天天看點

彙編指令-位置無關碼(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是通過機器碼算出來的,機器碼格式如下圖所示:

彙編指令-位置無關碼(BL)與絕對位置碼(LDR)(2)

其中[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條指令取值的地方。

彙編指令-位置無關碼(BL)與絕對位置碼(LDR)(2)

人間有真情,人間有真愛。

彙編指令-位置無關碼(BL)與絕對位置碼(LDR)(2)

如果您喜歡這裡,感覺對你有幫助,并且有多餘的軟妹币的話,不妨投個食吧,贊賞的時候,留下美句和你的部落格位址哦~   戳這裡看誰投食了