当在linux上链接一个共享库时,是否包括所有的模块?

问题描述 投票:1回答:1

我正在将一个应用程序系统从AIX移植到linux,所有这些应用程序都包含一个共享库。 我已经把共享库构建成了linux的.so文件--我在这里看到至少有一个帖子描述了如何指定从共享库中导出的内容(就像AIX通过一个.exp文件做的那样)。

只是有一个愚蠢的问题。 在AIX上,如果一个共享库中的模块没有被链接到它的应用程序中的任何东西引用,它就会被链接器忽略。 在linux上似乎不是这样,但我想确认一下。

在测试我的linux共享库时,我漏掉了一个我还没准备好处理的依赖性模块(或者更准确地说,我为那个模块的所有入口点提供了一个带有虚函数的替代模块,以为这样就能让它链接了)。 到目前为止,一切都很好。 但当我试图将那个共享库链接到一个琐碎的测试程序中时,链接器报告说,由以下代码引用的东西未解析符号 另一个 共享库模块,而它本身只在我用dummies替换的模块中被引用。 即,我将会消耗掉 模块被简单地忽略...

换句话说,这个模块被链接器认为是最终应用的一部分,尽管应用中没有任何东西引用它。 我在AIX上也做了同样的实验(用dummies替换相同的模块,并尝试在那里链接一个琐碎的应用程序)。 没有任何抱怨。

所以,AIX链接器只尝试解决共享库模块的依赖关系,如果这些模块是 自己 是由应用程序明确调用的。 但是,linux linker试图解决对 共享库模块,无论它们是否从应用程序中调用。

这是真的吗? 如果是的话,有什么方法可以覆盖这种行为吗? 最终,当我把所有东西都移植过来时,所有的依赖关系都会解决。 但现在,很难漏掉一些东西--即使它没有被引用......


这是一个最小的案例。

main.c contains function main(), which calls function one().
one.c contains function one(), which does nothing.
two.c contains function two(), which calls function three().

There is no function three(), but libshared.so is built from 
modules one.c and two.c.  Program main is built from main.c and
links in libshared.so. 

The linker needs to resolve function one(), which is in the shared
library.  But that's all main.c requires.  Still, function two() in
the library references function three(), which doesn't exist.
The linker will complain about the undefined symbol 'three', even
though program main doesn't need it.
On AIX the linker will not complain and everything will work.

main.c:

    #include <stdio.h>
    int     one();
    int main()
    {
            one();
    }

one.c:

    #include <stdio.h>
    int one()
    {
            return 1;
    }

two.c:

    #include <stdio.h>
    int three();
    int two()
    {
            return three();
    }

build libshared.so with modules one.c and two.c:

    gcc -fPIC -shared one.c two.c -o libshared.so

Attempt to build main from main.c and libshared.so:

    gcc main.c -o main -L. -lshared
    ./libshared.so: undefined reference to `three'
    collect2: error: ld returned 1 exit status

The linker reports an undefined reference to 'three',
which is referenced from two() - but main() doesn't ever call two().
linux linker aix
1个回答
0
投票

实际的答案。共享库 其实 共享对象。 它们被视为一个单一对象,而不是一个*.a库。

这表明Linux(指:glibcgccgoldld)和AIX对共享对象有不同的概念。

在Linux中,当你链接一个可执行文件时,ldgold也会检查所使用的共享对象的依赖关系--Aix链接器不会:它假定共享对象要按原样使用,它们的依赖关系不是当前链接的一部分。至少这是默认行为)。

下面是我的测试总结。

+----------------+--------------------+-------------------------------+
|                |    AIX             |    linux                      |
+----------------+--------------------+-------------------------------+
| libshared.so   |  only with option  |    yes                        |
| can be created |  -Wl,-berok        |                               |
+----------------+--------------------+-------------------------------+
| main           |    yes             |  only with option             |
| can be created |                    |  -Wl,--allow-shlib-undefined  |
+----------------+--------------------+-------------------------------+

注:我对AIX和链接的随机想法。http:/lzsiga.users.sourceforge.netaix-linking.html


0
投票

默认情况下 GNU binutils linker。ld onLinux需要一个符号 ref 在链接中由某个输入文件(即对象文件或共享库)定义,如果 ref 的定义所引用。def 在任何需要链接的输入文件中。不管是 def 是依次引用的。

您的程序链接需要 libshared.so. libshared.so 定义 two其中,指的是 three所以 three 必须被定义。

你可以通过以下方式反制这种默认行为,以容忍共享库中的未定义引用(但不包括对象文件)。

$ gcc main.c -o main -L. -lshared -Wl,--allow-shlib-undefined

--allow-shlib-undefinedld 手册

的概念。模块 在您的语言中,对应于 翻译组 在汇编层面和 对象文件 在链接层面上。欣赏一个输入到ELF程序或共享库的链接中的对象文件在程序或共享库中没有独特的存在,这可能是有帮助的。它被切成几块,散落在各处。因此,没有任何意义上的链接是可能的。

$ gcc main.c -o main -L. -lshared ...

忽略未引用的模块 two.(c|o)libshared.so. 根本不存在这种情况。如果这种联系不需要任何定义的话,那么就不存在这种情况。libshared.so 那么它就会完全忽略共享库。1. 如果它需要共享库,那么默认情况下它的引用必须被解析。


[1]也就是说,在Debian-clan系统中,如果需要共享库,那么默认情况下,它的引用必须被解析。gcc 是为了调用 ld 随着 --as-needed 选项。在Redhat-clan系统中,如果共享库是输入的,需要的,或者不需要的,GCC都会默认链接它们。
© www.soinside.com 2019 - 2024. All rights reserved.