c - 为什么 gcc 中 '-l' 选项的顺序很重要?

标签 c gcc linker ld

<分区>

我正在尝试编译一个使用 udis86 的程序图书馆。实际上我正在使用 user-manual 中给出的示例程序图书馆的。但是编译的时候报错。我得到的错误是:

example.c:(.text+0x7): undefined reference to 'ud_init'
example.c:(.text+0x7): undefined reference to 'ud_set_input_file'
.
.
example.c:(.text+0x7): undefined reference to 'ud_insn_asm'

我使用的命令是:

$ gcc -ludis86 example.c -o example 

按照用户手册中的说明。

显然,链接器无法链接 libudis 库。但是,如果我将命令更改为:

$ gcc example.c -ludis86 -o example 

它开始工作了。那么请有人解释一下第一个命令有什么问题吗?

最佳答案

因为这就是 GNU 链接器使用的链接算法的工作方式(至少在链接静态库时)。链接器是单 channel 链接器,一旦看到它们就不会重新访问库。

库是目标文件的集合(存档)。当您使用 -l 选项添加库时,链接器不会无条件地从库中获取所有 目标文件。它只需要那些当前需要的目标文件,即解析一些当前未解析(待定)符号的文件。之后,链接器就完全忘记了那个库。

当链接器从左到右一个接一个地处理输入目标文件时,链接器会持续维护挂起符号列表。当它处理每个目标文件时,一些符号被解析并从列表中删除,其他新发现的未解析符号被添加到列表中。

因此,如果您使用 -l 包含某个库,链接器将使用该库来解析尽可能多的当前未决符号,然后完全忘记该库。如果它稍后突然发现它现在需要该库中的一些附加目标文件,则链接器将不会“返回”该库以检索这些附加目标文件。已经太迟了。

出于这个原因,在链接器的命令行中使用 -l 选项 late 总是一个好主意,这样当链接器到达那个 -l 它可以可靠地确定它需要哪些目标文件,不需要哪些。将 -l 选项作为链接器的第一个参数通常毫无意义:在最开始,挂起符号列表是空的(或者更准确地说,由单个符号 main),这意味着链接器根本不会从库中获取任何内容。

在您的情况下,您的目标文件 example.o 包含对符号 ud_initud_set_input_file 等的引用。链接器应该接收该目标文件第一的。它会将这些符号添加到挂起符号列表中。之后,您可以使用 -l 选项添加您的库:-ludis86。链接器将搜索您的库并从中获取解析那些未决符号的所有内容。

如果您将 -ludis86 选项放在命令行的最前面,链接器将有效地忽略您的库,因为一开始它并不知道它需要ud_init, ud_set_input_file 等。之后在处理example.o时会发现这些符号,并将它们添加到pending symbol列表中。但这些符号将一直未解析到最后,因为 -ludis86 已被处理(并被有效地忽略)。

有时,当两个(或更多)库以循环方式相互引用时,甚至可能需要对同一个库使用 -l 选项两次,以便给链接器两次检索的机会该库中的必要目标文件。

关于c - 为什么 gcc 中 '-l' 选项的顺序很重要?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38700597/

相关文章:

c - 单元测试 UDP 套接字处理代码

c - memcpy 与 C 中的赋值——应该是 memmove?

c - ... 的多个定义(链接器错误?)

c++ - 未解析的外部符号

c - wxDev-C++ 的 64 位编译器

C代码不起作用

c - 对写入特定目录中文件的 c 代码进行单元测试

c - 彩色的 printf 语句

gdb可以自动在SIGSEGV上附加一个进程吗

在一个程序中编译多个C文件