blog 文章

2021年4月2日 星期五

gcc link 順序

大家可能都有遇過 link 時, 檔案的順序會影響 link 是不是成功, 我也一直搞不懂是怎麼回事, 這次來搞懂他。

m2.c
1 #include "a1.h"
2 
3 int main(int argc, char *argv[])
4 {
5   a1();
6   return 0;
7 }


a1.c
1 #include <stdio.h>
2 
3 #include "b1.h"
4 
5 void a1()
6 {
7   printf("a1\n");
8   b1();
9 }


b1.c
1 #include <stdio.h>
2 
3 void b1()
4 {
5   printf("b1\n");
6 }


a1() 有呼叫 b1(), 如果 link 順序會會影響錯誤 link 的話, 應該是怎麼樣呢?

會出錯的情形是使用 lib, 我們來把 a1.c, b1.c 做成 static library。
gcc  -c a1.c 
ar rcs liba1.a a1.o
gcc  -c b1.c 
ar rcs libb1.a b1.o
gcc -o m2 m2.o libb1.a liba1.a # link error
liba1.a(a1.o): In function `a1':
a1.c:(.text+0x14): undefined reference to `b1'
collect2: error: ld returned 1 exit status

gcc -o m2 m2.o liba1.a libb1.a # link ok

加入 --start-group, --end-group 也可以正確解決
gcc -o m2 m2.o -Wl,--start-group libb1.a liba1.a -Wl,--end-group


如果直接 link .o 沒有順序問題, 以下2個順序都可以成功

gcc -o m2 m2.o a1.o b1.o
gcc -o m2 m2.o b1.o a1.o


有點納悶, 是吧!

我推測是這樣:

gcc -o m2 m2.o libb1.a liba1.a # link error

處理到 libb1.a 時, 沒有把 b1.o 複製到最終執行檔, 因為從 m2.o 得不到這個資訊,

readelf -a m2.o
1 Relocation section '.rela.text' at offset 0x1c8 contains 1 entries:
2   Offset          Info           Type           Sym. Value    Sym. Name + Addend
3 000000000015  000900000002 R_X86_64_PC32     0000000000000000 a1 - 4
4
5 Relocation section '.rela.eh_frame' at offset 0x1e0 contains 1 entries:
6   Offset          Info           Type           Sym. Value    Sym. Name + Addend
7 000000000020  000200000002 R_X86_64_PC32     0000000000000000 .text + 0
8
9 The decoding of unwind sections for machine type Advanced Micro Devices X86-64 is not currently supported.


relocation symbol 只有 a1, 所以在這個時間點, linker 不會去複製 b1.o 到最終執行檔, 等到處理 a1.o 時, 才發現 b1 不存在。

readelf -a a1.o
 1
 2 Relocation section '.rela.text' at offset 0x1f8 contains 3 entries:
 3   Offset          Info           Type           Sym. Value    Sym. Name + Addend
 4 000000000005  00050000000a R_X86_64_32       0000000000000000 .rodata + 0
 5 00000000000a  000a00000002 R_X86_64_PC32     0000000000000000 puts - 4
 6 000000000014  000b00000002 R_X86_64_PC32     0000000000000000 b1 - 4
 7
 8 Relocation section '.rela.eh_frame' at offset 0x240 contains 1 entries:
 9   Offset          Info           Type           Sym. Value    Sym. Name + Addend
10 000000000020  000200000002 R_X86_64_PC32     0000000000000000 .text + 0
a1.o 有一個 relocation symbol b1, 但之後已經不會再去搜尋 libb1.a 了, 而 --start-group, --end-group 會在回頭找 libb1.a, 所以就找到 b1() 了。

ref:
gcc/g++鏈接時.o文件以及庫的順序問題

沒有留言:

張貼留言

使用 google 的 reCAPTCHA 驗證碼, 總算可以輕鬆留言了。

我實在受不了 spam 了, 又不想讓大家的眼睛花掉, 只好放棄匿名留言。這是沒辦法中的辦法了。留言的朋友需要有 google 帳號。