靜態鏈接

最近在閱讀《程序員的自我修養》,在閱讀到靜態鏈接一章發現其中的闡述過於的雜亂,導致本人在看完之後還是一頭霧水,在反覆的看了幾遍後,整理了一些的要點,其中有理解偏差的地方希望閱讀者能夠通知本人。
首先是兩個示例程序(主要示例,不具有任何功能)

a.c
extern int shared;

int main()
{
    int a = 10;
    swap(&a, &shared);
}
b.c

int shared = 9;

int swap( int *pa, int *pb )
{
    *pa ^=*pb ^=*pa ^=*pb;
}

上述的兩個源文件編譯生成目標文件,並鏈接生成可執行文件ab

gcc -c a.c b.c
gcc -o ab -e main a.o b.o

其中上面生成的可執行文件包括了一下的三個步驟:

  1. 相似段合併:
    a.o的.text與b.o的.text合併,即:main函數相對的偏移量爲0,swap函數相對的偏移量:00000027
    a.o的.data與b.o的.data合併,即:全局變量shared相對於.data的偏移量爲0
  2. 確定符號的虛擬地址
    如可執行文件的.text段虛擬地址開始於:08048094,則計算出的main的地址爲08048094,swap的地址爲:80480BB(08048094+00000027),地址對齊則變成:80480BC
    可執行文件的.data段虛擬地址開始於:08049154,則計算出的全局變量shared的虛擬地址爲:08049154
  3. 指令地址修正
    命令:readelf -r a.o查看需要修正的地址類型,其中
    shared絕對地址修正:R_386_32,
    swap爲相對地址修正:R_386_PC32
    絕對地址修正:S+A,
    相對地址修正:S+A-P

S爲可執行文件中的實際虛擬地址,
A爲被修正的位置值(反彙編 objdump -d a.o可查看),
P爲被修正的位置(指令的開始處)

shared的修正地址爲:S+A=08049154+00000000=08049154
swap的修正地址爲:S+A-P=80480BC+(-4)-(08048094+00000021)=80480B8-80480B5=3(其中的21在查看是何種修正方式的重定位表的偏移量,相對於最開始指令的偏移量)
可以通過查看ab的反彙編知道是否正確:這裏需要說明的是:swap是相對於下一條指令的偏移地址。

上述的地址值可以通過下面的一些命令進行查看

  1. 查看符號在段中的偏移量:readelf -s a.o value爲偏移量(查看符號表)
  2. 查看輸入的目標文件的段大小:objdump -h a.o的size(查看section)
  3. 查看實際的段的虛擬地址:objdump -h ab
  4. 查看地址的修正方式和相對於指令的偏移量:readelf -r a.o其中的Type和Offset(查看重定位表)
  5. 查看修正的值A,可通過反彙編的方式查看到:objdump -d a.o

接下來還會陸續更新本人的一些學習所得。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章