首页 > 解决方案 > 为什么传递给`gcc`的参数顺序会影响构建共享库的`readelf -d`的输出?

问题描述

鉴于这些:

bar.cpp:

int foo();

int bar()
{
    return foo();
}

foo.cpp:

int foo()
{
    return 42;
}

由forlibfoo.so构建,即gccfoo.cppgcc -shared -o libfoo.so -fPIC foo.c

众所周知,它readelf -d可用于显示特定共享库的依赖关系。

$ gcc -shared -o libbar2.so -fPIC bar.c -lfoo -L. 
$ gcc -shared -o libbar.so -lfoo -L. -fPIC bar.c
$ readelf -d libbar2.so | grep -i needed
 0x0000000000000001 (NEEDED)             Shared library: [libfoo.so]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]

$ readelf -d libbar.so | grep -i needed
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]

为什么传递的参数顺序会gcc影响readelf -d构建共享库的输出?

所有这些测试都Ubuntu16.04gcc 5.4.0.

更新

$ ls -l libbar*
-rwxrwxr-x 1 joy joy 8000 Oct  4 23:16 libbar2.so
-rwxrwxr-x 1 joy joy 8000 Oct  4 23:16 libbar.so
$ sum -r libbar*
00265     8 libbar2.so
56181     8 libbar.so

标签: cgccdependenciesshared-librariesubuntu-16.04

解决方案


链接过程是连续的,您指定文件的顺序很重要。文件按给出的顺序处理。请参阅 ld 手册的摘录:

ld 的某些命令行选项可以在命令行中的任何位置指定。但是,相对于目标文件和其他文件选项,引用文件的选项(例如 -l 或 -T)会导致在命令行中出现该选项的位置读取文件。

当您尝试将共享库链接到另一个共享库时,链接器将查找是否存在任何未定义的引用,该引用需要在所有考虑到现在的文件中从库中获取某些内容(因此在您的第二个示例中,之前没有文件libfoo library ) ,如果没有,则将该库放在一边,并继续链接剩余的文件。

在这里,您还有一个可能令人惊讶的行为:可以(默认情况下)创建仍然具有未定义引用的共享库(这意味着它们不是自包含的)。这就是您的第二个示例(libbar.so)中发生的情况。如果您想避免这种行为以确保您不在这种情况下,您可以添加该-Wl,-no-undefined选项(请参阅https://stackoverflow.com/a/2356393/4871988)。

如果添加此选项,则第二种情况将在链接时引发错误。

编辑:我在 ld 手册中找到了解释这种行为的其他摘录:

链接器只会在命令行中指定的位置搜索存档一次。如果存档定义了在命令行上出现在存档之前的某个对象中未定义的符号,则链接器将包含存档中的适当文件。但是,稍后在命令行上出现的对象中的未定义符号不会导致链接器再次搜索存档。请参阅 -( 选项以了解强制链接器多次搜索档案的方法。

您可以在命令行上多次列出同一个存档。

这也适用于共享库


推荐阅读