当目标文件和静态库中同时存在相同符号时,链接器不会发出多个定义错误 [英] Linker does not emit multiple definition error when same symbol coexists in object file and static library

查看:113
本文介绍了当目标文件和静态库中同时存在相同符号时,链接器不会发出多个定义错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给出一个在静态库中具有签名void some_func()的已编译函数,而在目标文件中另一个具有相同void some_func()签名的函数希望将它们链接在一起时会出现多个定义"错误.

Given a compiled function with signature void some_func() in a static library, and another one with the same void some_func() signature in a object file one expects that when you link them together a "multiple definition" error should have occured.

但事实并非如此.据我观察,链接器(已通过GCC和MSVC工具链进行了测试)选择了驻留在目标文件中的实现,而不会发出任何错误或警告.

But this is not the case. As far as i've observed the linkers (tested with GCC and MSVC toolchains) choose the implementation residing in the object file without emitting any error or warning.

给出以下POC:

somelib.h

somelib.h

#ifndef _SOMELIB_H_
#define _SOMELIB_H_

void some_func();

#endif /* _SOMELIB_H_ */

somelib.c

somelib.c

#include "somelib.h"
#include <stdio.h>

void some_func()
{
    printf("some_func in library\n");
}

troublingheader.h

troublingheader.h

#ifndef _TROUBLING_HEADER_H_
#define _TROUBLING_HEADER_H_

void some_func();

#endif /* _TROUBLING_HEADER_H_ */

troublingsource.c

troublingsource.c

#include "troublingheader.h"
#include <stdio.h>

void some_func()
{
    printf("Troubling func\n");
}

main.c

#include <stdio.h>
#include "somelib.h"

int main()
{
    some_func();
}

还有一个简单的Makefile来帮助构建(首先创建tmp文件夹):

And a simple Makefile to assist building (create tmp folder first):

tmp/wat.exe: tmp/libsomelib.a tmp/main.c.o tmp/troublingsource.c.o
    gcc -static -static-libgcc -Ltmp -otmp/wat.exe tmp/main.c.o tmp/troublingsource.c.o -lsomelib

tmp/main.c.o:
    gcc -Wall -Wextra -c -g -O0 src/main.c -o tmp/main.c.o

tmp/troublingsource.c.o:
    gcc -Wall -Wextra -c -g -O0 src/troublingsource.c -o tmp/troublingsource.c.o

tmp/somelib.o:
    gcc -Wall -Wextra -c -g -O0 src/somelib.c -o tmp/somelib.c.o

tmp/libsomelib.a: tmp/somelib.o
    ar rcs tmp/libsomelib.a tmp/somelib.c.o

运行最终可执行文件时,内容"Troubling func"如上所示.

When running the final executable, the contents "Troubling func" are shown as above described.

有人可以向我解释为什么会这样吗?

Can someone explain me why this happens?

推荐答案

对于

In the case of the GNU linker ld, invoked by GCC, what you have observed is explained by the following points.

  • 链接序列中的目标文件被无条件地添加到链接中, 是否包含程序需要的符号.

  • An object file in the linkage sequence is added to the linkage unconditionally, whether it contains symbols that the program needs or not.

静态库是目标文件和目录"的档案 链接器可以检查的.

A static library is an archive of object files together with a "table of contents" that the linker can inspect.

默认情况下,在链接序列中添加静态库中的目标文件 无条件地链接.链接器仅在静态库中搜索 查找已观察到要引用的符号的定义, 但尚未定义,通过已将对象文件 添加到链接中.提取目标文件 仅从库中添加并添加到链接中,前提是它提供了此类符号的定义.仅当链接器添加时 已经需要它提供的一些定义.

By default, an object file within a static library in the linkage sequence is not added to the linkage unconditionally. The linker searches a static library only to find definitions of symbols that it has observed to be referenced, but not defined, by object files already added to the linkage. An object file is extracted from the library and added to the linkage only if it provides definitions of such symbols. It is added only if the linker already needs some of the definitions that it provides.

为避免混淆,我们将更改输出消息:

For the avoidance of confusion, we'll change the output message:

"some_func in library\n"

收件人:

"some_func in somelib.o"

然后对这些要点进行演示,以解释您所看到的内容:

Then a demonstration of these points that explains what you've seen:

案例1

从静态库链接troublingsource.o本身和somelib.o.

链接顺序:main.otroublingsource.olibsomelib.a

gcc -I. -c -o troublingsource.o troublingsource.c
gcc -I. -c -o somelib.o somelib.c
gcc -I. -c -o main.o main.c
ar rcs libsomelib.a somelib.o
gcc -o test main.o troublingsource.o -L. -lsomelib
./test
Troubling func

这里:

  • main.o被无条件添加到链接中.
  • 发现在main.o 中定义了
  • 符号main 找到
  • 符号some_func,但未在main.o
  • 中定义
  • troublingsource.o被无条件添加到链接中
  • troublingsource.o中发现了
  • 先前引用过但未定义的符号some_func.
  • 没有未解决的参考文献.甚至没有搜索到libsomelib.a.
  • main.o was added unconditionally to the linkage.
  • Symbol main was found defined in main.o
  • Symbol some_func was found referenced but not defined in main.o
  • troublingsource.o was added unconditionally to the linkage
  • Symbol some_func, previously referenced but not defined, was found defined in troublingsource.o.
  • No unresolved references remained. libsomelib.a was not even searched.

案例2

从静态库链接someblib.o本身和troublingsource.o.

链接顺序:main.osomelib.olibtroublingsource.a

gcc -I. -c -o somelib.o somelib.c
gcc -I. -c -o troublingsource.o troublingsource.c
gcc -I. -c -o main.o main.c
ar rcs libtroublingsource.a troublingsource.o
gcc -o test main.o somelib.o -L. -ltroublingsource
./test
some_func in somelib.o

这里:

  • main.o被无条件添加到链接中.
  • 发现在main.o 中定义了
  • 符号main 找到
  • 符号some_func,但未在main.o
  • 中定义
  • someblib.o被无条件添加到链接中
  • somelib.o中找到了
  • 以前引用过但未定义的符号some_func.
  • 没有未解决的参考文献.甚至没有搜索到libtroublingsource.a.
  • main.o was added unconditionally to the linkage.
  • Symbol main was found defined in main.o
  • Symbol some_func was found referenced but not defined in main.o
  • someblib.o was added unconditionally to the linkage
  • Symbol some_func, previously referenced but not defined, was found defined in somelib.o.
  • No unresolved references remained. libtroublingsource.a was not even searched.

案例3

从单独的静态库链接someblib.otroublingsource.o.

Link someblib.o and troublingsource.o from separate static libraries.

链接顺序:main.olibsomelib.alibtroublingsource.a

gcc -I. -c -o somelib.o somelib.c
gcc -I. -c -o troublingsource.o troublingsource.c
gcc -I. -c -o main.o main.c
ar rcs libsomelib.a somelib.o
ar rcs libtroublingsource.a troublingsource.o
gcc -o test main.o -L. -lsomelib -ltroublingsource
./test
some_func in somelib.o

这里:

  • main.o被无条件添加到链接中.
  • 发现在main.o 中定义了
  • 符号main 找到
  • 符号some_func,但未在main.o
  • 中定义 在
  • libsomeblib.a中搜索了提供some_func
  • 定义的目标文件.
  • libsomelib.a的成员somelib.o中找到some_func的定义
  • libsomelib.a中提取
  • somelib.o并将其添加到链接中.
  • 没有未解决的参考文献.甚至没有搜索到libtroublingsource.a.
  • main.o was added unconditionally to the linkage.
  • Symbol main was found defined in main.o
  • Symbol some_func was found referenced but not defined in main.o
  • libsomeblib.a was searched for an object file providing a definition of some_func
  • A definition of some_func was found in member somelib.o of libsomelib.a
  • somelib.o was extracted from libsomelib.a and added to the linkage.
  • No unresolved references remained. libtroublingsource.a was not even searched.

案例4

链接someblib.o本身和troublingsource.o本身.

链接顺序:main.osomelib.otroublingsource.o

gcc -I. -c -o somelib.o somelib.c
gcc -I. -c -o troublingsource.o troublingsource.c
gcc -I. -c -o main.o main.c
gcc -o test main.o somelib.o troublingsource.o
troublingsource.o: In function `some_func':
troublingsource.c:(.text+0x0): multiple definition of `some_func'
somelib.o:somelib.c:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status

这里:

  • main.o被无条件添加到链接中.
  • 发现在main.o 中定义了
  • 符号main 找到
  • 符号some_func,但未在main.o
  • 中定义
  • someblib.o被无条件添加到链接中
  • 发现在somelib.o 中定义的
  • 符号some_func先前已引用但未定义.
  • troublingsource.o被无条件添加到链接中
  • troublingbsource.o中再次定义的
  • 符号some_func已全部定义在somelib.o中. 错误.
  • main.o was added unconditionally to the linkage.
  • Symbol main was found defined in main.o
  • Symbol some_func was found referenced but not defined in main.o
  • someblib.o was added unconditionally to the linkage
  • Symbol some_func, previously referenced but not defined, was found defined in somelib.o
  • troublingsource.o was added unconditionally to the linkage
  • Symbol some_func, allready defined in somelib.o, was found defined again in troublingbsource.o. Error.

案例5

从静态库链接someblib.o.

链接顺序:libsomelib.a main.o

gcc -I. -c -o somelib.o somelib.c
gcc -I. -c -o main.o main.c
ar rcs libsomelib.a somelib.o
gcc -o test -L. -lsomelib main.o
main.o: In function `main':
main.c:(.text+0xa): undefined reference to `some_func'
collect2: error: ld returned 1 exit status

这里:

    在将任何目标文件添加到
  • libsomelib.a之前,遇到了
  • libsomelib.a 连锁.那时没有引用任何符号,但未定义任何符号,因此libsomelib.a 甚至没有被搜索到,
  • main.o被无条件添加到链接中.
  • 发现在main.o 中定义了
  • 符号main 找到
  • 符号some_func,但未在main.o
  • 中定义
  • 没有其他要链接的目标文件或库. some_func 最终是一个未定义的引用. 错误.
  • libsomelib.a was encountered before any object files were added to the linkage. At that point no symbols were referenced but undefined, so libsomelib.a was not even searched,
  • main.o was added unconditionally to the linkage.
  • Symbol main was found defined in main.o
  • Symbol some_func was found referenced but not defined in main.o
  • There were no further object files or libraries to link. some_func was finally an undefined reference. Error.

这篇关于当目标文件和静态库中同时存在相同符号时,链接器不会发出多个定义错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆