从技术上讲,就文件内容而言,gcc -fPIC -shared src.c
和gcc -fPIC src.c
的输出有什么区别?
假设int main(int, char**)
在src.c
中定义,以便两个编译都成功。但正如预期的那样执行a.out
生成的gcc -shared src.c
会出现以下错误:
-bash: ./a_shared.out: cannot execute binary file
即使有main
功能它。
另外,如何使用otool
或objdump
等工具检查输出文件的差异?
非常感谢。
共享库和可执行文件使用相同的格式:它们都是可加载的图像。然而,
main()
,因为main()
是一个函数,函数返回,但执行应该永远不会从入口点返回。现在,这并没有回答关于-shared
做什么的问题。您可以使用-v
标志询问GCC。以下是我的系统在没有和使用-shared
的调用之间的差异。
collect2
without -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
with -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或模型子选项)。
根据Difference between -shared and -Wl,-shared of the GCC options,传递-shared到GCC可以在链接时启用或禁用其他标志。
根据我的理解,如果可执行文件具有共享库,则可执行文件的大小非常小。在共享库存在并正确链接之前,可执行文件不会运行。使用共享库的好处是,如果我们有一个非常大的代码库,我们不需要每次都构建整个代码。我们只需要重建.so文件并将其链接到可执行文件。这节省了大量时间。
如果没有共享库的可执行文件,可执行文件的大小将非常大。对于每个代码更改,需要构建整个代码,这可能非常耗时。