[英]How does gcc `-shared` option affect the output?
從技術上講,就文件內容而言, gcc -fPIC -shared src.c
和gcc -fPIC src.c
的輸出有什么區別?
假設在src.c
定義了int main(int, char**)
以便兩個編譯都成功。 但是按預期執行由gcc -shared src.c
生成的a.out
會出現以下錯誤:
-bash: ./a_shared.out: cannot execute binary file
就算有一個main
函數吧。
另外,如何使用otool
或objdump
等工具檢查輸出文件中的差異?
非常感謝。
共享庫和可執行文件使用相同的格式:它們都是可加載的圖像。 然而,
共享庫通常與位置無關,可執行文件通常不是。 這會影響代碼生成:對於位置無關,您必須使用相對地址加載全局變量或跳轉到函數。
可執行文件有一個“入口點”,它是執行開始的地方。 這通常不是main()
,因為main()
是一個函數,函數返回,但執行永遠不應該從入口點返回。
現在,這並沒有回答關於-shared
做什么的問題。 您可以使用-v
標志詢問 GCC。 以下是我的系統上不帶和帶-shared
的調用之間的差異。
collect2
無-shared
:-dynamic-linker
/lib64/ld-linux-x86-64.so.2
/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/crt1.o
/usr/lib/gcc/x86_64-linux-gnu/4.7/crtbegin.o
/usr/lib/gcc/x86_64-linux-gnu/4.7/crtend.o
collect2
與-shared
:-shared
/usr/lib/gcc/x86_64-linux-gnu/4.7/crtbeginS.o
/usr/lib/gcc/x86_64-linux-gnu/4.7/crtendS.o
看起來代碼生成不受影響:您仍然必須使用-fpic
或-fPIC
。
您可以看到crt1.o
(“C 運行時”)僅在鏈接可執行文件時包含在內。 使用nm
,我們可以找出它包含的內容:
$ nm /usr/lib/x86_64-linux-gnu/crt1.o
0000000000000000 R _IO_stdin_used
0000000000000000 D __data_start
U __libc_csu_fini
U __libc_csu_init
U __libc_start_main
0000000000000000 T _start
0000000000000000 W data_start
U main
所以你可以看到它似乎定義了一些與stdin
以及_start
(它是入口點)有關的東西,並且它有一個對main
的未定義引用。
我不確定其余的文件是什么,但至少您知道如何找到它們,並且可以隨意瀏覽,或者如果您願意,可以查看源代碼。
根據https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html#Link-Options -shared選項執行以下操作
生成一個共享對象,然后可以將其與其他對象鏈接以形成可執行文件。
並非所有系統都支持此選項。
對於可預測的結果,您還必須在指定此鏈接器選項時指定用於編譯的相同選項集(-fpic、-fPIC 或模型子選項)。
按照-shared和輪候冊的區別,-shared的GCC選項傳遞到-shared GCC可以啟用或鏈接時禁止其他標志。
根據我的理解,如果可執行文件具有共享庫,則可執行文件的大小非常小。 在共享庫存在並正確鏈接之前,可執行文件不會運行。 使用共享庫的好處是如果我們有一個非常大的代碼庫,我們不需要每次都構建整個代碼。 我們只需要重建 .so 文件並將其鏈接到可執行文件。 這節省了大量時間。
對於沒有共享庫的可執行文件,可執行文件的大小將非常大。 對於每次代碼更改,都需要構建完整的代碼,這可能非常耗時。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.