位置無關碼取值 是通過指令間相對位址取值,而有關碼是通過絕對位址來定址。在arm中最開始的幾句**都是位置無關**,採用bl或者b進行跳轉,而有關碼通過ldr pc,=lable 進行跳轉,其中lable為鏈結位址。位置有關碼保證鏈結位址與執行位址一致程式才能正常執行。
adr r0 , _start ;載入執行位址到r0當中
ldr r1, _start ;載入鏈結位址到r1當中
在spv210**重定位實驗當中,指定鏈結位址為 0xd0024000
以上兩句都是偽指令,反彙編內容如下:
adr r0, _start
d0024020:e24f0028 subr0, pc, #40; 0x28
最左邊為鏈結位址,其次為機器碼,反彙編**,注釋。
執行位址推斷: 根據鏈結位址0xd0024020得出偏移量為0x20,則pc位址為0xd0020010+0x20+8(流水線) = 0xd0020038,pc--0x28 正好等於0xd0020010,也就是執行位址的起始位址。注意:8級流水線。
ldr r1, _start
d0024024:e59f1048 ldrr1, [pc, #72]; d0024074
根據偏移量,這句執行的位址為0xd0020034, 此處的pc為鏈結位址,也就是0xd0024024+8,則[pc,#72]中的內容為位址0xd0024024+8+72內容,及備註中的d0024074,在反彙編**中檢視0xd0020074中存放的資料正好是0xd0024000,相當於把鏈結位址賦值r1.
d0024074: d0024000 andler4, r2, r0
整體過程分析;
程式在執行之前先編譯鏈結,鏈結完成之後,每句程式對應乙個鏈結位址,如同反彙編那樣,而鏈結位址的起始位址往往是ddr的起始位址。
但是一開始程式是在sram中執行的,執行位址的起始位置往往是sram的起始位置,那麼一開始執行的**他的鏈結位址和執行位址不同,但是**本身不知道這件事,程式設計師明白,所以這段**只能是位置無關碼,主要負責一些初始化和重定位。知道搬運完成,pc的值還是執行時位址的值,也就是說pc不等於[pc].
通過絕對跳轉修改pc的值為當前鏈結位址的值:如果用相對跳轉就是當前執行位址加上乙個偏移量,此時pc執行還是執行位址,這樣就無法到ddr上執行程式。執行完ldr pc,=on_sdram 後 pc=[pc].
參考:
鏈結位址與執行位址
32位的處理器,它的每一條指令是4個位元組順序儲存,cpu是順序執行的,只要沒發生什麼跳轉,它會順序進行執行這些指令,編譯器對 中的變數名 函式名等東西進行乙個位址的編排,賦予這些抽象的東西乙個位址,然後在程式中訪問這些變數名 函式名就是在訪問一些位址,這些位址我們稱之為編譯位址。是指程式指令真正執...
關於鏈結位址
回過頭來看我們的helloworld程式,在makefile中 ttext 0x7c00,鏈結位址為0x7c00,code標號的偏移位址為0x15,則鏈結後其位址為0x7c15,其他函式呼叫此函式時,也就會呼叫位址0x7c15,這時jmpl 0,code語句反彙編後為 假如我們在makefile中改...
鏈結位址和執行位址
位置無關 和位置有關 位置無關 要好一些,適應強,放在 都可以執行 位置有關 就必須。三星推薦的啟動方式 bootloader必須大於16kb並小於96kb,假定bootloader為80kb,啟動過程是這個樣子 先開機上電後bl0執行,bl0會載入外部啟動裝置中的bootloader的前16kb ...