【问题标题】:Why symbols of a shared library are not resolved at link time?为什么在链接时不解析共享库的符号?
【发布时间】:2010-07-01 15:45:14
【问题描述】:

这是我在此站点上的第二篇文章,旨在了解 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'

所以我的问题是为什么在链接共享库时符号没有解析。当我将使用这个库来制作可执行文件时,需要完成这项工作(解析其下游的符号),但这意味着我们需要知道在使用这个库时这个库依赖于什么,但这不是不可取的吗?

谢谢, 贾格拉蒂

【问题讨论】:

    标签: c++ c linux gcc linker


    【解决方案1】:

    在构建库时添加-z defs 是否符合您的要求?如果没有,请查看 ld 手册页,关于未定义符号的处理有很多选项。

    【讨论】:

      【解决方案2】:

      由于您没有提供 -c(仅编译)选项,因此您请求 gcc 编译这两个源文件并将它们与标准库 (libc) 和 c 运行时启动(通常为 crt0)链接到产生一个运行程序。 crt0 尝试通过调用 main() 来进入您的程序,这是链接器找不到的未定义符号。它找不到它,因为您的任何一个 .c 文件中都没有 main(),对吧?

      那么,关于您的实际问题,“为什么共享库的符号在链接时没有被解析?”答案是,“链接时间”是什么意思?根据定义,动态链接程序在启动之前不会“链接”(或者甚至可能不会,具体取决于您的系统。)

      在 Linux 系统上,您可以使用 ldd 命令查看程序依赖的动态库(在 Mac OS 上使用“otool -L”)。 ldd 的输出会告诉你程序依赖哪些动态库,在库搜索路径中找到哪些动态库,哪些找不到(如果有的话)。

      当您启动动态程序时,链接到其中的动态链接器会定位并加载程序所依赖的动态库,并“修复”对外部符号的引用。如果其中任何一个失败,您的程序将无法启动。所有以前未解析的符号之一已被解析,动态链接器返回,C 运行时将调用您的 main() 函数。 (在 Mac OS 上有些不同,但效果相似,链接发生在您的程序启动之后。)

      【讨论】:

        【解决方案3】:

        我认为链接器选项 -Bsymbolic 是您正在寻找的。​​p>

        【讨论】:

        • 本身还不够。我这里有一个 -Bsymbolic 共享库,它在运行时会出错。
        【解决方案4】:

        至少在 ELF 中,链接无法知道符号在哪里(即在哪个库中)。另一方面,在 OS X 中,您需要按照您描述的方式链接库。最后,这是一个设计问题。一种更灵活,另一种更严格。

        【讨论】:

        • 为什么这被否决了?请注意,在 OSX 上,您可以使用 -flat_namespace 选项使其行为类似于其他操作系统,例如。 Linux。
        【解决方案5】:

        即使你构建了一个共享库,它也必须解决所有的依赖关系。

        因此,当一个共享库在编译时加载时,它知道在运行时要加载哪些其他共享库,以便它可以解析其他依赖项。

        1) 使用 look()
        构建一个共享 (look.) 库 2) 使用 hello() bye() 链接构建一个共享 (hg.) 库,针对look.
        3) 使用链接到 hg.

        的 main() 构建应用程序

        在运行时,应用程序将加载 hg.,这将加载共享库的外观。

        【讨论】:

          【解决方案6】:

          可执行文件需要entry point。但是可以在没有入口点的情况下构建共享库,然后可以使用此共享库编译可执行文件。

          【讨论】:

            猜你喜欢
            • 2013-12-27
            • 2014-03-06
            • 1970-01-01
            • 2013-10-16
            • 2016-03-19
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-12-17
            相关资源
            最近更新 更多