2010-07-01 30 views
7

這是我在本網站的第二篇文章,旨在瞭解使用gcc編譯/鏈接過程。當我嘗試創建可執行文件時,需要在鏈接時解析符號,但是當我嘗試創建共享庫時,符號在鏈接時不會解析。當我嘗試使用這個共享庫製作可執行文件時,它們可能會被解決。動手:爲什麼共享庫的符號在鏈接時沒有解決?

bash$ cat printhello.c 
#include <stdio.h> 
//#include "look.h" 

void PrintHello() 
{ 
look(); 
printf("Hello World\n"); 
} 

bash$ cat printbye.c 
#include <stdio.h> 
//#include "look.h" 

void PrintBye() 
{ 
look(); 
printf("Bye bye\n"); 
} 

bash$ cat look.h 
void look(); 

bash$ cat look.c 
#include <stdio.h> 

void look() 
{ 
printf("Looking\n"); 
} 

bash$ gcc printhello.c printbye.c 
/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crt1.o: In function `_start': 
(.text+0x18): undefined reference to `main' 
/tmp/cck21S0u.o: In function `PrintHello': 
printhello.c:(.text+0x7): undefined reference to `look' 
/tmp/ccNWbCnd.o: In function `PrintBye': 
printbye.c:(.text+0x7): undefined reference to `look' 
collect2: ld returned 1 exit status 

bash$ gcc -Wall -shared -o libgreet printhello.c printbye.c 
printhello.c: In function 'PrintHello': 
printhello.c:6: warning: implicit declaration of function 'look' 
printbye.c: In function 'PrintBye': 
printbye.c:5: warning: implicit declaration of function 'look' 

所以我的問題是爲什麼當我鏈接共享庫時符號未解決。當我使用這個庫來創建一個可執行文件時,需要完成這項工作(解析下游的符號),但這意味着我們需要知道這個庫在使用這個庫時依賴於什麼,但這不是不可取的嗎?

謝謝, Jagrati

回答

6

添加-z defs當建立圖書館做你想要的?如果沒有,請檢查ld手冊頁,處理未定義符號的選項有很多。

0

鏈接的沒有辦法知道,在ELF,其中所述符號是至少(即,其中庫)。另一方面,在OS X中,您需要按照您所描述的方式鏈接庫。最後,這是一個設計問題。一個更靈活,另一個更嚴格。

+0

爲什麼這會降低投票率?請注意,在OSX上,您可以使用'-flat_namespace'選項使其像其他操作系統一樣運行。 Linux操作系統。 – Troubadour 2010-07-01 16:19:55

0

即使構建共享庫,它也必須解決所有的依賴關係。

因此,當編譯時加載共享庫時,它知道在運行時加載哪些其他共享庫,以便它可以解決其他依賴關係。

1)建立一個共享(外觀。< sharedLib>)庫與外觀()
2)建立一個共享(HG。< sharedLib>)用針對外表你好()再見()鏈接庫。 < sharedLib>
3)用main()構建應用程序,該應用程序與hg鏈接。 < sharedlib>

在運行時,應用程序將加載hg。 < sharedlib>這將實習生加載共享庫的外觀。 < sharedlib>

2

我認爲鏈接選項-Bsymbolic是你在找什麼。

+0

本身不夠。我在這裏有一個-Bsymbolic共享庫,用於在運行時訪問barfs。 – Kaz 2016-11-23 23:25:33

0

可執行文件需要entry point。但是可以在沒有入口點的情況下構建共享庫,然後可以使用此共享庫編譯可執行文件。

3

您似乎並不瞭解您在第一個命令中要求編譯器驅動程序(gcc)執行的操作。由於您沒有提供-c(僅編譯)選項,因此您要求gcc編譯這兩個源文件並將它們與標準庫(libc)和c運行時啓動(通常爲crt0)進行鏈接以生成運行程序。 crt0試圖通過調用main()來進入你的程序,這是鏈接器找不到的未定義符號。它找不到它,因爲你的任何一個.c文件中都沒有main(),對吧?

因此,關於您的實際問題,「爲什麼共享庫的符號在鏈接時沒有解決?」答案是,「鏈接時間」是什麼意思?通過定義,一個動態鏈接的程序在啓動之前不會「鏈接」(或者甚至可能還沒有,這取決於您的系統。)

在Linux系統上,您可以看到程序依賴於ldd命令(Mac OS使用'otool -L')所依賴的動態庫。 ldd的輸出會告訴你程序依賴哪些動態庫,哪些在庫搜索路徑中找到,哪些不能找到(如果有的話)。

當動態程序啓動時,鏈接到它的動態鏈接器定位並加載程序依賴的動態庫,並「修復」對外部符號的引用。如果其中任何一個失敗,您的程序將無法啓動。一個所有以前未解決的符號已經解決,動態鏈接器返回並且C運行庫將調用您的main()函數。 (在Mac OS上它有些不同,但效果相似,鏈接發生在您的程序啓動後。)