一个多年的老隐患---ARM BL指令的分析

前两天在俺们的EVB上加了点东西,增加了一下的BL语句进行初始化:

        BL       C2g_GsmStartZac
        LDR     pc, =INT_Initialize                  ;goto main in RAM

接着就出了一个奇怪的问题,使用RVDS,将PC置于代码烧录的其实地址0x40004,然后F5开跑,可以正常开跑。但是如果使用板子自带的boot进行启动,则跑不起来。

使用RVDS从boot开始跟踪,发现原来boot跳到主程序的过程中,跳入的地址为0x40040004,之所以这么做主要是为了和操作flash的代码进行统一,因为0-32K的Flash空间在系统运行的过程中被映射为内部IRAM,如果要操作这段Flash,则需要从0x4000000开始,通过地址绕转来巧妙的绕过这个问题。系统用了多年没出问题,其实是没在这个地方调用过IRAM里的函数。

本来,如果BL跳转的地址C2g_GsmStartZac,如果也是在Flash中,则不会有任何问题,反正地址都是绕转。另外,如果跳转到地址如果超出了BL的能力范围32M,编译器(链接器)本来也会想办法解决这个问题的,即将C2g_GsmStartZac的地址保存在Flash中的某个位置,然后通过LDR把地址加载到寄存器,再通过寄存器跳转。

出现前面说的问题的关键在于,这个地址正好位于0-32k的空间内,而且由于scatter loader文件中的链接地址又是0x40000开始的,导致编译器认为正好在BL跳转的32M范围内,直接编译成了通过偏移条状,即BL跳转是在当前PC的基础上加上偏移量来跳转的,因此就有了问题。

通过反汇编知道,使用0x40000进行链接,生成的代码如下:

 

        0x00040060:    fbff0269    i...    BLX      C2g_GsmStartZac  ; 0xa0e

 

根据文档《ARM Instruction》对BLX的介绍如下:

 

 其中的0-23位为有符号的偏移,指令fbff0269中对应的为0-22位为0x7f0269, 第23为1,表示负数,即负的0xFD97, 在左移两位为负的0x3F65c,加上H<<1, H为1, 运算结果为负的0x3F65A. 用PC值0x40060-3f65a=0xA06.和0xa0e差8,正好符合BLX指令下面的注释。但是当链接地址为0x40000开始,boot跳转却是到0x4000000时,此处的PC变成了0x4000060了,运算结果变成了0x4000060-3f65a=3FC0A06,访问的是绕转的Flash的内容,当然就有问题了。

 

实际上如果scatter loader写为0x4000000则,链接器处理的结果是这样的,使用了临时变量。

 

    0x40000060:    eb02bc1c    ....    BL       $Ven$AT$L$$C2g_GsmStartZac  ; 0x400af0d8
...........................
    $Ven$AT$L$$C2g_GsmStartZac
    $a
        0x400af0d8:    e59fc000    ....    LDR      r12,0x400af0e0
        0x400af0dc:    e12fff1c    ../.    BX       r12
    $d
    $f
        0x400af0e0:    00000a0f    ....    DCD    2575 ;即0xA0F, thumb

 

 但是由于系统已经做好了,改变scatter loader的地址还要牵扯到MMU的配置,Flash的写入cache等诸多问题,最后的解决方法就是使用不会产生歧义的调用方法,即直接使用pc跳转

 

        mov     lr, pc
        LDR     pc, =C2g_GsmStartZac
        LDR     pc, =INT_Initialize                  ;goto main in RAM


这样在什么位置跳转都没有问题了,不过先得把pc保存到lr中(上面的第一句),不然调用后就回不来了。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值