匯編指令-位置無關碼(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