Bl指令与LDR PC,=函数名指令 一些区别

#转载内容

Ldr和bl在启动程序中,都是可以负责pc跳转的指令。

1)bl是地址无关指令,和当前的运行地址无关,链接器脚本中标明了一个运行地址,但是arm中的代码实际是从地址0开始运行的。这个时候实际的地址和运行地址不相符,如果想让程序正常的运行,就必须使用地址无关指令。比如在完成将程序复制到内存之前想要跳转到一个函数里,就必须使用bl,因为bl跳转依靠的是相对地址,和运行地址无关,所以能完成跳转。

2)Ldr是地址有关指令,如果这个时候使用“ldr  pc,=函数名”来跳转,实际上是跳转到这个函数在链接器脚本中标明的地址上了。所以使用地址相关指令之前,要把代码复制到链接器脚本中指明的那个地址上,否则程序就跑飞了。复制完成之后再使用ldr跳转到内存中,使程序继续运行。

#转载结束

测试代码出现的问题:

/*load program to SDRAM and clear bss */
    bl copy_sdram
    bl clean_bss
/*init uart port 0 and test*/
    ldr pc , =test_uart

/*LED Flush indicate code error*/    
halt:
    bl led
    b halt
程序说明:代码重定位到SDRAM后,跳转到SDRAM中的test_uart空函数位置执行,然后返回执行led函数点亮LED,运行后LED不亮,查看反汇编代码如下:

30000050:    e59ff010     ldr    pc, [pc, #16]    ; 30000068 <.text+0x68>
30000068:    30000664     andcc    r0, r0, r4, ror #12

30000664 :
30000664:    e1a0c00d     mov    ip, sp
30000668:    e92dd800     stmdb    sp!, {fp, ip, lr, pc}
3000066c:    e24cb004     sub    fp, ip, #4    ; 0x4
30000670:    e89da800     ldmia    sp, {fp, sp, pc}

test_uart执行后lr寄存器存入栈中,程序结束lr赋值给pc,但是lr的值并不是下一条指令地址,ldr指令不是bl指令,没有保存pc到lr的操作,所以程序跑飞了。

   以后编程需要注意,LDR PC,=函数名的函数内部需要设置死循环,否则返回指令后会跑飞。或者按如下代码,强行给lr寄存器赋值下一条指令地址:

    mov lr ,pc
    add lr ,lr, #10

   ldr pc , =test_uart

因为arm流水线,下一条指令是pc+8,再根据ldr pc , =test_uart是mov lr ,pc执行后的第二个指令,lr=lr+(8+2),就能正常返回。

或者:

    ldr lr ,=halt  //halt是跳转地址
    ldr pc , =test_uart

 

 

 

 

 

你可能感兴趣的:(Bl指令与LDR PC,=函数名指令 一些区别)