我正在尝试编译一个使用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 它开始工作了。那么,请解释一下第一个命令的问题是什么?
发布于 2012-08-10 09:00:04
因为这就是GNU链接器使用的链接算法的工作方式(至少在链接静态库时是这样的)。链接器是一个单通道链接器,一旦看到库,它就不会重新访问它们。
库是目标文件的集合(存档)。使用-l选项添加库时,链接器不会无条件地从库中获取所有目标文件。它只接受当前需要的目标文件,即解析一些当前未解析(挂起)的符号的文件。在那之后,链接器完全忘记了这个库。
当链接器从左到右一个接一个地处理输入对象文件时,挂起的符号列表由链接器连续维护。当它处理每个对象文件时,一些符号被解析并从列表中删除,其他新发现的未解析的符号被添加到列表中。
因此,如果您使用-l包含了一些库,链接器将使用该库来解析尽可能多的当前挂起的符号,然后完全忘记该库。如果链接器后来突然发现它现在需要从该库中获取一些额外的目标文件,则链接器将不会“返回”到该库来检索这些额外的目标文件。现在已经太晚了。
出于这个原因,在链接器的命令行后期使用-l选项总是一个好主意,这样在链接器到达该-l时,它可以可靠地确定它需要哪些目标文件,哪些不需要。将-l选项作为链接器的第一个参数通常没有任何意义:一开始,挂起的符号列表是空的(或者,更准确地说,由单个符号main组成),这意味着链接器根本不会从库中获取任何东西。
在本例中,目标文件example.o包含对符号ud_init、ud_set_input_file等的引用。链接器应首先接收该目标文件。它会将这些符号添加到挂起的符号列表中。之后,您可以使用-l选项添加您的库:-ludis86。链接器将搜索您的库,并从中获取解析那些挂起的符号的所有内容。
如果您首先将-ludis86选项放在命令行中,链接器将有效地忽略您的库,因为在开始时它不知道它将需要ud_init、ud_set_input_file等。稍后,当处理example.o时,它会发现这些符号并将它们添加到挂起的符号列表中。但是这些符号将一直未解析到最后,因为-ludis86已经被处理(并且实际上被忽略了)。
有时,当两个(或更多)库以循环方式相互引用时,甚至可能需要对同一个库使用两次-l选项,以便链接器有两次机会从该库中检索必要的目标文件。
https://stackoverflow.com/questions/11893996
复制相似问题