這篇文章是自己疑惑究竟地址無關性是如何實現,然後查看匯編和CPU指令手冊,最後分析解除自己疑惑的,高手不要鄙視,哈哈。
編譯C代碼時候需要制定--acps/ropi選項,如下例子:
C-example
編譯:
armcc -c --cpu Cortex-M3 -O0 --apcs=interwork --apcs /ropi/rwpi -o main.o main.c
使用fromelf查看匯編代碼
fromelf.exe -s -c main.o
text段生成的匯編代碼如下:
匯編指令
查看關鍵的一句調用函數fun_for_sub的匯編代碼:
0x00000006: f7fffffe .... BL fun_for_sub ; 0x2 Section
查找arm的官方DDI0403D_arm_architecture_v7m_reference_manual_errata_markup_1_0.pdf關於BL指令的解釋如下:
Branch with Link (immediate) calls a subroutine at a PC-relative address.
得知BL是一條PC相關的指令。
具體看BL指令的構成:
根據我們產生的指令f7fffffe,
對應如下:
f7ff : 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1
fffe : 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0
符號位S=1,J1=1,J2=1,imm10 = 11 1111 1111,imm11 = 111 1111 1110
所以I1 = !(J1~S) = 1, I2 = !(J2~S) = 1,
imm32 = SignExtend(S:I1:I2:imm10:imm11:’0’,32) = SignExtend(1:1:1:11 1111 1111:111 1111 1110:’0’,32) = 1111 1111 1111 1111 1111 1111 1111 1100 = 0xfffffffc。
0xfffffffc是-4的補碼,另外當前PC是0x00000006,
再根據上面的Operation最後一步BranchWritePC( PC + imm32)
最終跳轉到0x6 + (-4) = 0x2的地址出,即函數fun_for_sub的地址,因此實現根據當前PC實現了地址無關性的代碼。
在X86平台下面也是差不多的原理,使用的也是基於PC相關的跳轉指令。《程序員的自我修養—鏈接、裝載和庫》講得很好。