位置無關代碼,即該段代碼無論放在內存的哪個地址,都能正確運行。究其原因,是因為代碼裡
沒有使用絕對地址,都是相對地址。
位置無關的寫法:
(1) B指令
B指令接受一個相對地址,因此在匯編裡用B跳轉到一個標號時,實際編譯的結果是一個相對跳轉。
相對地址有個范圍限制,即目標不能太遠,一般目標放在同一個文件裡是肯定可以的。
_start:
b _reset
_reset:
...
(2) BL
BL用於調用函數,也是一個相對跳轉
(3) ADR
獲取標號的地址,在編譯時會使用PC+偏移的方式得到該位置的地址。例如,當TEXT_BASE是0時
SMRDATA可能被放在0x100的位置,當TEXT_BASE為0x30000000時放在0x30000100的位置。使用ADR
總能獲取正確的位置,與程序的加載地址無關。
ADR R0, SMRDATA
SMRDATA:
.word 0x22111120
.word 0x00002F50
.word 0x00000700
(相應的, LDR Rn, =LABEL是位置相關的)
(4) LDR
當加標號時,LDR可以用於偽指令,也可以真指令。
真指令: (標號前不加=號,表示取標號處的值)
LDR R0, SDRDATA
實際被編譯為LDR R0, [PC, #NN],其中NN是目標的相對距離
偽指令: (標號前加=號,取標號的地址)
LDR R0, = SDRDATA
實際編譯的時候的時候,會在某位置存處SDRDATA的值,然後用一個LDR取出來。
顯然,用LDR時,加不加=號有很大區別。
無=號:取該標號處的值,位置無關
有=號:取該標號的地址,位置相關
舉例分析
例1:中斷向量跳轉
_start:
b reset
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq
_undefined_instruction: .word undefined_instruction
_software_interrupt: .word software_interrupt
_prefetch_abort: .word prefetch_abort
_data_abort: .word data_abort
_not_used: .word not_used
_irq: .word irq
_fiq: .word fiq
其中,
ldr pc, _irq,由於沒加=號,表示取值_irq處的值放在pc裡 (位置無關)
_irq: .word irq ,表示_irq存放的值是irq的絕對地址(位置有關)