汇编指令-位置无关码(BL)与绝对位置码(LDR)(2)


位置无关码

即该段代码无论放在内存的哪个地址,都能正确运行。究其原因,是因为代码里没有使用绝对地址,都是相对地址。 

位置相关码

即它的地址与代码处于的位置相关,是绝对地址


 

BL :带链接分支跳转指令,也是位置无关码(相对位置),用于调用函数用的。

B:分支跳转指令,指目标不能太远,一般用于同一个文件下的目标地址跳转。

LDR:通常都是作加载指令的,但是它也可以作伪指令,通常有两种不同的表示: 


1)LDR pc, =MyHandleIRQ 表示将MyHandleIRQ地址放入pc寄存器中,相当于PC=MyHandleIRQ 。

例如:

1. LDR r0,=label    //用于加载立即数或一个地址值到指定寄存器中

              //如果label是立即数: LDR r0,=0X123 ;将0X123存入r0中

              //如果name是个标识符: LDR r0,=label_1 ;将label_1所指向的地址值存入r0中

2)LDR PC,MyHandleIRQ 表示将 MyHandleIRQ地址中的值放入pc寄存器中,类似于C语言中的指针形式,相当于PC=*(MyHandleIRQ )。

例如:

  •  LDR r0,[r1]        //将R1中的值存到r0中
  •  LDR r1,[r2,#16]     //将(r2+16)地址中的内容存到r1中
  •  LDR r1,[r2],#4      //将r2地址中的内容存到r1中,同时r2=r2+4

 


 

实例:
 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条指令取值的地方。

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM