位置無關碼
即該段代碼無論放在記憶體的哪個位址,都能正确運作。究其原因,是因為代碼裡沒有使用絕對位址,都是相對位址。
位置相關碼
即它的位址與代碼處于的位置相關,是絕對位址
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條指令取值的地方。
人間有真情,人間有真愛。
如果您喜歡這裡,感覺對你有幫助,并且有多餘的軟妹币的話,不妨投個食吧,贊賞的時候,留下美句和你的部落格位址哦~ 戳這裡看誰投食了