訂閱
糾錯
加入自媒體

從0學ARM——什么是位置無關碼?

2021-01-13 16:01
一口Linux
關注

如果我們將生成的bin文件拷貝到內存0x40008000位置運行必然沒有問題,

bl func 和 ldr pc,=func 都能跳轉到func函數(shù),
而19行代碼,也能訪問到全局變量aaaa。
如果我們將該程序拷貝到其他地址是否能正常運行呢?

假定我們拷貝到0地址運行,那么程序的執(zhí)行地址需要從0開始重新編排,即_start對應0地址,main對應0x18。

拷貝到0地址后內存布局:

拷貝到0地址運行后,**內存中指令(機器碼)**的內容還和以前一樣,pc的值會根據實際運行地址重新修正。

首先看bl func

對應的匯編代碼是 第9行;該指令的機器碼是0xeb000001,我們在《4. 從0開始學ARM-ARM指令,移位、數(shù)據處理、BL、機器碼》講過該機器碼格式是從pc的位置向前偏移1條指令因為三級流水線,所以應該往下偏移3條指令,即func的位置,所以bl仍然可以正確找到func這個函數(shù)。

bl funcldr pc,=func對應的匯編代碼是 第10行;

我們可以看到是從pc值+4位置取出對應的內存的值,pc值+4是14,該位置對應15行,即將40008010寫入到pc,

而我們的bin文件只有44個字節(jié)大小,所以此時內存40008010并沒有我們編寫的任何代碼。所以ldr pc,=func 無法跳轉到func。

c訪問全局變量aaaa

對應的匯編代碼是 第19行;

c訪問全局變量aaaa

我們可以看到是從pc值+4位置取出對應的內存的值,pc值+4是28,該位置對應22行,即將4000802c寫入到r3,然后20行會將r2中值寫入到0x4000802c這個地址,而此時該地址并不是全局變量aaaa,所以此指令是無法找到bss段的aaaa變量的內存。

三、總結

1. 位置無關碼:

CPU取指時用相對地址取指令(比如pc +4),只要其相對地址沒有變,都能夠取指并運行。即該段代碼無論放在內存的哪個地址,都能正確運行。究其原因,是因為代碼里沒有使用絕對地址,都是相對地址。

2. 位置相關碼:

利用絕對地址取指并運行,這就需要你存放程序(鏈接過程中)需要按照連接腳本的要求那樣執(zhí)行(Makefile里面有 -Ttext xxx指定或連接腳本)。即它的地址與代碼處于的位置相關,是絕對地址,如:mov PC ,#0xff;ldr pc,=0xffff等。

3. 位置無關碼的應用:

1). 程序在運行期間動態(tài)加載到內存;
2). 程序在不同場合與不同程序組合后加載到內存(共享的動態(tài)鏈接庫);
3). 在運行期間不同地址相互之間的映射(如bootloader)

4. 結論使用「mov pc ,xxx ;  ldr pc ,xxx」等就是位置相關碼。這些使用絕對指令尋址。而使用「bl ,b ,adr,ldr」一般為位置無關碼。在使用「b, bl」調用C語言中的函數(shù)里「不要使用全局變量」,因為C中全局變量的地址「也是根據鏈接地址生成」的。使用=和不使用=號是有很大區(qū)別的!笩o=號:取該標號處的值,位置無關有=號:取該標號的地址,位置相關」

【考一考】考一考大家為什么uboot的異常向量表的reset異常,指令是b reset,而其他異常卻是我們本文所說的位置相關碼,ldr pc,XXXXXX?

arm對應的uboot異常向量表如下:

arch/arm/cpu/armv7/start.S


<上一頁  1  2  3  
聲明: 本文由入駐維科號的作者撰寫,觀點僅代表作者本人,不代表OFweek立場。如有侵權或其他問題,請聯(lián)系舉報。

發(fā)表評論

0條評論,0人參與

請輸入評論內容...

請輸入評論/評論長度6~500個字

您提交的評論過于頻繁,請輸入驗證碼繼續(xù)

暫無評論

暫無評論

人工智能 獵頭職位 更多
掃碼關注公眾號
OFweek人工智能網
獲取更多精彩內容
文章糾錯
x
*文字標題:
*糾錯內容:
聯(lián)系郵箱:
*驗 證 碼:

粵公網安備 44030502002758號