BL :带连接分支跳转指令,也是位置无关码(相对位置),一般用于带返回的子程序跳转,B指令是用于无返回的跳转。
LDR:通常都是作加载指令的,但是它也可以作伪指令,通常有两种不同的表示:
1)LDR pc, =MyHandleIRQ 表示将MyHandleIRQ地址放入pc寄存器中,相当于PC=MyHandleIRQ 。
2)LDR PC,MyHandleIRQ 表示将 MyHandleIRQ地址中的值放入pc寄存器中,类似于C语言中的指针形式,相当于PC=*(MyHandleIRQ )。
实例:
1 Reset: 2 ldr sp, =4096 @ 设置栈指针,以下都是C函数,调用前需要设好栈 3 bl disable_watch_dog @ 关闭WATCHDOG,否则CPU会不断重启 4 // bl是位置无关码,相当于:PCnew = PC + 偏移 5 // PCnew = (4+8) + 0x28 = 0x34 6 7 //ldr pc, =disable_watch_dog /* 这样写将出错 */ 8 9 bl clock_init @ 设置MPLL,改变FCLK、HCLK、PCLK 10 bl memsetup @ 设置存储控制器以使用SDRAM 11 bl copy_steppingstone_to_sdram @ 复制代码到SDRAM中 12 ldr pc, =on_sdram @ 跳到SDRAM中继续执行 13 on_sdram: 14 ldr sp, =0x34000000 @ 设置栈指针 15 ldr lr, =halt_loop @ 设置返回地址 16 ldr pc, =main @ 调用main函数 17 halt_loop: 18 b halt_loop
链接脚本如下,链接地址在0X30000000:
1 SECTIONS { 2 . = 0x30000000; 3 .text : { *(.text) } 4 .rodata ALIGN(4) : {*(.rodata)} 5 .data ALIGN(4) : { *(.data) } 6 .bss ALIGN(4) : { *(.bss) *(COMMON) } 7 }
反汇编如下:
1 30000000 <_start>: 2 30000000: e3a0da01 mov sp, #4096 ; 0x1000 3 30000004: eb00000a bl 30000034 <disable_watch_dog> 4 30000008: eb00000d bl 30000044 <clock_init> 5 3000000c: eb000026 bl 300000ac <memsetup> 6 30000010: eb000040 bl 30000118 <copy_steppingstone_to_sdram> 7 30000014: e59ff00c ldr pc, [pc, #12] ; 30000028 <.text+0x28> 8 9 30000018 <on_sdram>: 10 30000018: e3a0d30d mov sp, #872415232 ; 0x34000000 11 3000001c: e59fe008 ldr lr, [pc, #8] ; 3000002c <.text+0x2c> 12 30000020: e59ff008 ldr pc, [pc, #8] ; 30000030 <.text+0x30> 13 14 30000024 <halt_loop>: 15 30000024: eafffffe b 30000024 <halt_loop> 16 30000028: 30000018 andcc r0, r0, r8, lsl r0 17 3000002c: 30000024 andcc r0, r0, r4, lsr #32 18 30000030: 30000200 andcc r0, r0, r0, lsl #4 19 20 30000034 <disable_watch_dog>: ... ...
从反汇编中可以看出当执行ldr pc, =on_sdram 时的反汇编是 ldr pc, [pc, #12] ; 相当于pc=*(pc+12)=30000018,此时的*(pc+12)是指的pc+12地址所指的地址,所以无论pc怎么变都是指的30000018这个常量来执行on_sdram,属于绝对转移。
执行 bl disable_watch_dog 时,地址0X30000004跳转到0X30000034.这里的0X30000034是通过机器码算出来的,机器码格式如下图所示:
其中[31:28]位是条件码;[27:24]位为“1010”(0xeaffffff)时,表示B跳转指令,为“1011”时,表示BL跳转指令;[23:0]表示偏移地址。
从反汇编中可以看到 bl disable_watch_dog 的机器码是eb00000a ,二进制为1110 1011 000000000000000000001010。
其中1110表示无条件执行,接下的1011就是BL指令,如L==0则就表示B指令,剩下的Offset就是链接位。
BL指令的跳转地址计算:
1.如上图所示,先将24位Offset补码左移两位,得到000000000000000000001010 00 =0X28
2.由于ARM流水线,当前PC永远等于PC+8,所以PC=PC+0X28+8=0X30000004+0X28+8=0X30000034。
若这里的PC值为其它值,算出来的转移地址也会随之改变,所以BL指令为地址无关码,跳转地址与位置无关。
注:ARM9是3级流水线,也就是PC处理时正在执行第1条指令的同时对第2条指令进行译码,并将第3条指令从存储器中取出,如下图所示,PC总是指向第3条指令取值的地方。