打印

彻底倒塌了~~~keil的CARM编译器好象不能设置生成相对跳转代码

[复制链接]
12921|58
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
computer00|  楼主 | 2007-4-11 10:33 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
最近在弄44B0,要通过串口下载程序到FLASH中,需要擦除flash。所以要先把代码复制到RAM中运行,
这样就需要产生相对跳转的代码,不然一跳转就到FLASH里面去,死翘翘了。虽然CARM有__ram,
但是弄起来太麻烦了。在选项里面找了半天,也没找到在哪设置?晕菜了.....



看来是该换换口味~~~换用RealView来搞了………………

相关帖子

沙发
ayb_ice| | 2007-4-11 10:55 | 只看该作者

原来是不会用啊...

使用特权

评论回复
板凳
djyos| | 2007-4-11 11:59 | 只看该作者

哈哈,遇到同道了

我用gcc做44b0,效果还可以,也是要copy代码到ram中.
这种用法中,你要的应该是长跳转吧,b和bl只能跳32M,而44b0的sdram区与flash(cs0)区距离不止32M哟,如果你用c语言拷贝代码,那应该用函数指针,编译器会处理的.
keil不是可以用gcc编译吗?

使用特权

评论回复
地板
computer00|  楼主 | 2007-4-11 16:17 | 只看该作者

回ayb_ice:是不会用,不然我也不会来这里发帖了

请问ayb_ice该如何在CARM里面设置,才让它生成的代码不是绝对地址跳转的指令呢?


回djyos:GCC我电脑上没装,也更加不熟悉,所以就不打算用它了。用realview算了。
我的问题不是长跳转的问题,而是用C写代码,让编译器产生代码的时候,不要产生使用绝对
地址的指令。这样我复制到RAM里面再去运行,跳转到绝对地址就错了。长跳转的话,可以通过
PC=PC+offset的办法来实现,这个编译器应该可以搞定的。

使用特权

评论回复
5
djyos| | 2007-4-11 16:45 | 只看该作者

那不叫相对跳转,叫位置无关.

这样执行效率会低不少的.因为不但代码位置无关,而且变亮也要位置无关,所有全局变亮都要使用基址+变址方式寻址.

难道你不能把代码copy到固定的地址去吗?这样就可以不使用"位置无关"技术了.把你copy的目标地址作为函数指针调用就可以了,这个目标地址你总是知道的.

我的做法是:
用C语言写一个load_program,函数,返回main函数指针.再调用这个指针.注意main函数的地址不一定就是copy的目标地址,要使main函数是目标地址,就只有改连接配置文件了,但这好像没什么意义.

使用特权

评论回复
6
computer00|  楼主 | 2007-4-11 17:20 | 只看该作者

我的全局变量要固定地址,否则就乱套了。

局部变量是压在栈里面的,这个我不用担心。


代码是可以复制到固定的RAM地址,并且我也知道如何去调用。

问题是,如果在这个函数中(总之是在RAM里运行的程序了),有一个跳转指令是绝对地址跳转,
它就会跳到原来的FLASH地址中去,这样就错了。必须要地址无关的跳转才可以。我就是在
CARM里找不到如何设置,但在RealView里是有可以选的,代码和变量无关都可以选。


不知道CARM是不是默认就是产生相对跳转的指令,昨天弄了一阵,开始是在它的启动
代码里又回到了FLASH,那个是因为keil提供的启动代码使用的是LDR PC,xx的方式,
我将其修改了,然后继续往下运行,到RAM初始化时,又跳到FLASH里面去了,这里
的代码我就没办法控制了,因为是编译器自动产生的。我不清楚之后的代码是否还
会有绝对地址跳转?去找相关设置,找不到。只好考虑换成RealView来搞了。hotpower大叔
早就建议我换了,趁这个机会,赶紧换了~~~~~~~

使用特权

评论回复
7
djyos| | 2007-4-11 17:56 | 只看该作者

看我的做法

//以下是由编译链接器定义的常数,gcc下可以通过链接脚本得到.
//carm应该也有类似的常数吧,没用过,不了解.
//调用load_program函数后,就可以直接执行该函数的返回值了.
extern ucpu_t text_load_start[];
extern ucpu_t text_run_start[];
extern ucpu_t text_run_limit[];
extern ucpu_t rodata_load_start[];
extern ucpu_t rodata_run_start[];
extern ucpu_t rodata_run_limit[];
extern ucpu_t rw_load_start[];
extern ucpu_t rw_run_start[];
extern ucpu_t rw_run_limit[];
extern ucpu_t zi_start[];
extern ucpu_t zi_limit[];

void main(void);

void (*load_program(void))(void)
{
    uint8_t *src,*des;
    //在44b0x中,初始化段无需拷贝

    if(text_run_start != text_load_start)       //拷贝代码段
        for(src=text_load_start,des=text_run_start;des<text_run_limit;src++,des++)
            *des=*src;
    if(rodata_run_start != rodata_load_start)   //拷贝只读数据段
        for(src=rodata_load_start,des=rodata_run_start;des<rodata_run_limit;src++,des++)
            *des=*src;
    if(rw_run_start != rw_load_start)           //拷贝初始化数据段
        for(src=rw_load_start,des=rw_run_start;des<rw_run_limit;src++,des++)
            *des=*src;
    for(src=zi_start;src<zi_limit;src++)
        *src=0;
    return main;
}

使用特权

评论回复
8
computer00|  楼主 | 2007-4-11 23:22 | 只看该作者

晕菜了~~~看来你还是没理解我要表达的

复制这个过程我已经完成了,并且去RAM里面运行了,但是在RAM里面运行一些指令后,它又自己跑到FLASH里面去运行了,因为有绝对跳转的指令。


例如FLASH地址从0开始,RAM地址从0x0C000000开始,那么我把FLASH的内容复制到0x0C000000开始处,
并跳转到0x0C000000开始运行,运行一些指令后,遇到了一个绝对跳转指令,假设它要跳转到地址0x30,
那么这个地址是在FLASH中的,然后程序又回到FLASH中去了,并没有继续在RAM中运行。我现在就
是要它不要生成这样的指令,而用相对跳转.因为我要把程序搬到RAM中,然后擦除FLASH,这个过程
程序不能继续去FLASH里面去取指令了,否则肯定乱套.

使用特权

评论回复
9
high| | 2007-4-12 00:07 | 只看该作者

相当于ads1.2里面的ropi, rwpi。

//position impendence
position imdependence

木有用过keil for arm. 查查看编译器手册.应该会支持吧,不然,application中动态加载程序就没法实现了?

---
我们写完一个程序for os with file system,事先也不可能知道会被加载到什么地址.所以编译器应该支持的,我想.
---
或者是通过mmu等的地址映射,使得总是加载到地址0.这也是可能的,windows的每个进程就总以为自己占有0~4g地址空间.

使用特权

评论回复
10
hotpower| | 2007-4-12 01:06 | 只看该作者

我没搞过此活动,估计应该实现

关键以前在FLASH生成的函数必须是相对寻址的.绝对寻址可能要跳回FLASH.
再者中断向量表也要重定位即映射到RAM去.

我不太喜欢在RAM中运行,DSP时是这样玩的.

使用特权

评论回复
11
iC921| | 2007-4-12 01:11 | 只看该作者

难得00发自己的问题

使用特权

评论回复
12
computer00|  楼主 | 2007-4-12 01:15 | 只看该作者

谢谢大家的讨论,晚上又试了一下,OK了,

不用去哪里设置,默认生成的代码应该就是Read-Only Position Independent的,
以前跳到FLASH中运行,是因为keil自动生成启动代码里面有绝对跳转的指令,并且
我没有修改到它. 现在改成相对跳转的指令,就OK了。把所有的代码复制到RAM中,
然后跳转过去运行,再也没有回到FLASH中去了~~~~~~~高兴~~~~~接下来就是做这个
FLASH的编程程序了,找到几份关于这个的源代码,拿来修修改改应该就可以了,
哈哈~~~~~~原来是错怪CARM了.........

使用特权

评论回复
13
computer00|  楼主 | 2007-4-12 01:50 | 只看该作者

这回是彻底倒塌了......结果还是有些地方跑到flash里去了....

还以为搞定了,晕死.........


0x0C3042D4  E1A03004  MOV       R3,R4
0x0C3042D8  E3A0000C  MOV       R0,#0x0000000C
0x0C3042DC  E0030390  MUL       R3,R0,R3
0x0C3042E0  E59F0028  LDR       R0,[PC,#0x0028]
0x0C3042E4  E7902003  LDR       R2,[R0,R3]
0x0C3042E8  E1A00002  MOV       R0,R2
0x0C3042EC  E3500000  CMP       R0,#0x00000000
0x0C3042F0  0A000003  BEQ       0x0C304304
0x0C3042F4  E59D0000  LDR       R0,[R13]
0x0C3042F8  E28D1004  ADD       R1,R13,#0x00000004
0x0C3042FC  E1A0E00F  MOV       R14,PC
0x0C304300  E12FFF12  BX        R2

本来运行在RAM好好的,就是这个BX R2(这里R2=0x000039d4了,是FLASH中的地址),
一跳就跳到FLASH里去了,晕菜,不知道如何控制它好......不搞了,倒塌,睡觉去........

使用特权

评论回复
14
hotpower| | 2007-4-12 01:54 | 只看该作者

应该有编译选项吧.

使用特权

评论回复
15
djyos| | 2007-4-12 09:06 | 只看该作者

注意看清楚了

    下面的常数中,load表示存放代码的起始地址,limit表示存放代码的结束地址,run表示运行地址.
    初始化代码则run和load地址相同且在flash里面,无须拷贝,load_program代码就在初始化段里面,所以可以在flash中运行.
    其他代码的load地址在flash中,run地址在ram中,所以只能在ram中运行的,如果把它放在flash中,反而不能运行了,因为代码里面用的也是绝对跳转地址.
    这些常数中,你还可以看到,zi段只有run地址而没有load地址.
    在ads中,是可以用scat文件完成这些功能的,而且,连接定位是开发系统的基本功能,keil也应该有这种功能吧,没用过,说说而已,错了不要砸砖.
    你这个问题当时我也是花了很多时间去解决,只是我是先看到了这个问题的存在,动手写程序之前先解决了,而不是等出了问题再抓狂.
    其实"位置无关"只是在动态加载中才会用到,这时运行地址是用malloc得到的,编译时不知道运行地址,只能编译成"位置无关"的,但嵌入式开发中不多见.
extern ucpu_t text_load_start[];
extern ucpu_t text_run_start[];
extern ucpu_t text_run_limit[];
extern ucpu_t rodata_load_start[];
extern ucpu_t rodata_run_start[];
extern ucpu_t rodata_run_limit[];
extern ucpu_t rw_load_start[];
extern ucpu_t rw_run_start[];
extern ucpu_t rw_run_limit[];
extern ucpu_t zi_start[];
extern ucpu_t zi_limit[];

使用特权

评论回复
16
computer00|  楼主 | 2007-4-12 10:43 | 只看该作者

晕了~~~还是不明白djyos所说的方法.

我不能把代码区间设置到RAM区间,因为这样就没办法下载到FLASH里面去.设置在FLASH区间,
生成的跳转指令又是跳到FLASH中去,复制到RAM里去运行就不行了。所以我需要地址无关的
代码.但是我在KEIL CARM中找不到它在哪儿设置,帮助手册看了,都没提到.我的是keil UV3 2.5A版,
不知道新版本是否有这些选项? 还是先换用RealView试试吧.如果那个再不行,那我只能给
每个需要用到的函数加上__ram了......并且还不能调用库函数(例如整数除法,浮点运算等),
因为里面有这些运算的话,__ram并不负责搬运代码,而是简单的调用FLASH里面的内容......

使用特权

评论回复
17
djyos| | 2007-4-12 11:09 | 只看该作者

我的程序确实是下载到flash中运行的

过程:
1.编译连接后产生一个bin文件,
2.下载到flash.
3.复位板子
4.从flash开始运行,执行初始化代码
5.copy大部分代码(除初始化和load_program本身以外的代码)到sdram中.copy的代码包括了所有库函数.
6.执行main函数,即load_program返回的指针,此时已经在sdram中了.

是不是跟你的需求一样?

使用特权

评论回复
18
computer00|  楼主 | 2007-4-12 13:16 | 只看该作者

基本上差不多,只是我的不是一上电就copy,而是由我通过串口

也许我们的编译器不同,你的编译器产生的代码是相对跳转的,所以在跳转的时候不会跳到绝对地址,
因而一直在RAM里面运行,不会再回到FLASH去.

但是我这个编译出来的结果有绝对跳转的指令,所以到RAM里面去运行遇到绝对地址跳转时,就回
跳回到FLASH中.

例如一个函数,由于代码是写在FLASH中的,假设它的地址是0x200,当前PC是在0x100处,
这两个地址都是在FLASH中.现在要调用这个函数,编译器生成了一条绝对跳转指令,
jump 0x200,OK,这个指令是没问题的,运行正常.

   然后我把代码复制到RAM中,又运行到了这里,而这时的PC值已经变为0xC000100了,
而这个函数的地址也就变成0xC000200了.但是里面的代码还是一个绝对地址跳转指令,
它要jump到0x200处,这样就又回到FLASH去了.我要编译器帮我生成一个基于PC跳转的
指令,跳转到0xC000200处才正确。而我现在不知道如何去告诉编译器,产生这样的代码.

使用特权

评论回复
19
djyos| | 2007-4-12 13:29 | 只看该作者

不是这样的

    我的代码也是绝对跳转的,它只能copy到0xc000000,别的地址是不行的。我前面的帖子里已经说过,真正使用相对跳转的“位置无关”代码只有在动态加载到用malloc创建的内存中运行才需要。
    至于用串口命令,这个不是问题,只要在load_program函数中加入接收串口命令的代码就可以了。
    莫非你要求代码既要能在flash中运行,又要可以在ram中运行?收到命令前在flash中运行,同一份代码,收到命令后copy到ram中运行?要是这样,可就只有用“位置无关”了。可这样有什么实际意义吗?

使用特权

评论回复
20
mybao| | 2007-4-12 13:31 | 只看该作者

难得圈圈问问题,我也顶一个

ModeMask         EQU    0x1F
SVC32Mode        EQU    0x13
IRQ32Mode        EQU    0x12
FIQ32Mode        EQU    0x11
User32Mode        EQU    0x10
Abort32Mode        EQU    0x17
Undef32Mode        EQU    0x1B
IRQ_BIT            EQU    0x80
FIQ_BIT            EQU    0x40

    GBLS    MainEntry
MainEntry    SETS    "main"
    IMPORT    $MainEntry
;******************************************************
    AREA    SelfBoot,    CODE,    READONLY
    
    IMPORT    UDF_INS_VECTOR
    IMPORT    SWI_SVC_VECTOR
    IMPORT    INS_ABT_VECTOR
    IMPORT    DAT_ABT_VECTOR
    IMPORT    IRQ_SVC_VECTOR
    IMPORT    FIQ_SVC_VECTOR                
    
    ENTRY    
    IF :DEF: |ads$version|
    ELSE
    EXPORT    __main
__main
    ENDIF        
ResetEntry
    b    SYS_RST_HANDLER
    b    UDF_INS_HANDLER
    b    SWI_SVC_HANDLER
    b    INS_ABT_HANDLER
    b    DAT_ABT_HANDLER
    b    .
    b    IRQ_SVC_HANDLER
    b    FIQ_SVC_HANDLER

;******************************************************
    MACRO    
$Label    HANDLER    $Vector
$Label
    sub    lr, lr, #4            
    stmfd    sp!, {r0-r3, lr}     
    ldr    r0, =$Vector
    ldr    pc, [r0]
    ldmfd    sp!, {r0-r3, pc}^        
    MEND
    
UDF_INS_HANDLER
    stmfd    sp!, {r0-r3, lr}
    ldr    r0, =UDF_INS_VECTOR
    mov    lr, pc
    ldr    pc, [r0]
    ldmfd    sp!, {r0-r3, pc}^
SWI_SVC_HANDLER
    stmfd    sp!, {r0-r3, lr}
    ldr    r0, =SWI_SVC_VECTOR
    mov    lr, pc
    ldr    pc, [r0]
    ldmfd    sp!, {r0-r3, pc}^
INS_ABT_HANDLER
    sub    lr, lr, #4
    stmfd    sp!, {r0-r3, lr}
    ldr    r0, =INS_ABT_VECTOR
    mov    lr, pc
    ldr    pc, [r0]
    ldmfd    sp!, {r0-r3, pc}^
DAT_ABT_HANDLER
    sub    lr, lr, #4
    stmfd    sp!, {r0-r3, lr}
    ldr    r0, =DAT_ABT_VECTOR
    mov    lr, pc
    ldr    pc, [r0]
    ldmfd    sp!, {r0-r3, pc}^
IRQ_SVC_HANDLER
    sub    lr, lr, #4
    stmfd    sp!, {r0-r12, lr}    
    mrs    r0, spsr
    stmfd    sp!, {r0}
    ldr    r0, =IRQ_SVC_VECTOR
    ldr    pc, [r0]    
FIQ_SVC_HANDLER
    sub    lr, lr, #4
    stmfd    sp!, {r0-r12, lr}    
    mrs    r0, spsr
    stmfd    sp!, {r0}
    ldr    r0, =IRQ_SVC_VECTOR
    ldr    pc, [r0]
                
;*******************************************************
SYS_RST_HANDLER
    mrs    r0, cpsr                ;enter svc mode and disable irq,fiq
    bic    r0, r0, #ModeMask
    orr    r0, r0, #(SVC32Mode :OR: IRQ_BIT :OR: FIQ_BIT)
    msr    cpsr_c, r0
    
    IMPORT    InitSystem
    bl    InitSystem    
    
    adr    r0, ResetEntry
    ldr    r1,    BaseOfROM
    cmp    r0,    r1
    ldreq    r0, TopOfROM
    beq    InitRamData
            
    ldr    r2,    =CopyProcBeg
    sub    r1, r2, r1
    add    r0, r0, r1    
    ldr    r3,    =CopyProcEnd    
0    
    ldmia    r0!, {r4-r7}
    stmia    r2!, {r4-r7}
    cmp    r2, r3
    bcc    %B0    
    
    ldr    r3, TopOfROM        
    ldr    pc, =CopyProcBeg
    
;***********************************************
CopyProcBeg    
0    
    ldmia    r0!, {r4-r11}
    stmia    r2!, {r4-r11}
    cmp    r2, r3
    bcc    %B0    
CopyProcEnd
    
    sub    r1, r2, r3
    sub    r0, r0, r1        
    
InitRamData    
    ldr    r2, BaseOfBSS
    ldr    r3, BaseOfZero    
0
    cmp    r2, r3
    ldrcc    r1, [r0], #4
    strcc    r1, [r2], #4
    bcc    %B0    

    mov    r0,    #0
    ldr    r3,    EndOfBSS
1    
    cmp    r2,    r3
    strcc    r0, [r2], #4
    bcc    %B1            
                          
    ldr    pc,    GotoMain    

GotoMain    DCD    $MainEntry

;***********************************************
    IMPORT    |Image$$RO$$Base|    ; ROM code start    
    IMPORT    |Image$$RO$$Limit|    ; RAM data starts after ROM program
    IMPORT    |Image$$RW$$Base|    ; Pre-initialised variables
    IMPORT    |Image$$ZI$$Base|    ; uninitialised variables
    IMPORT    |Image$$ZI$$Limit|    ; End of variable RAM space


BaseOfROM    DCD    |Image$$RO$$Base|
TopOfROM    DCD    |Image$$RO$$Limit|
BaseOfBSS    DCD    |Image$$RW$$Base|
BaseOfZero    DCD    |Image$$ZI$$Base|
EndOfBSS    DCD    |Image$$ZI$$Limit|

    EXPORT    GetBaseOfROM
    EXPORT    GetEndOfROM
    EXPORT    GetBaseOfBSS
    EXPORT    GetBaseOfZero
    EXPORT    GetEndOfBSS
    
GetBaseOfROM
    ldr    r0, BaseOfROM
    mov    pc, lr    
GetEndOfROM
    ldr    r0, TopOfROM
    mov    pc,    lr
GetBaseOfBSS
    ldr    r0,    BaseOfBSS
    mov    pc,    lr
GetBaseOfZero
    ldr    r0,    BaseOfZero
    mov    pc,    lr
GetEndOfBSS
    ldr    r0,    EndOfBSS
    mov    pc,    lr
    
;***********************************************    
    
    END        
        


直接把工程所有的空间都设置到RAM区,生成的BIN文件烧FLASH就可以。
CopyProcBeg    
0    
    ldmia    r0!, {r4-r11}
    stmia    r2!, {r4-r11}
    cmp    r2, r3
    bcc    %B0    
CopyProcEnd

上面这段负责从FLASH搬移代码

    adr    r0, ResetEntry
    ldr    r1,    BaseOfROM
    cmp    r0,    r1
    ldreq    r0, TopOfROM
    beq    InitRamData
上面这段,简单的说,就是判断代码从FLASH执行还是从RAM执行。

Image$$RO$$Base 这些是ADS连接器预定意的,KEIL也有吧,
有了这段启动代码,存储器空间怎么设置都为所谓。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

246

主题

14693

帖子

210

粉丝