gpt4 book ai didi

c - 当目标文件和静态库中存在相同的符号时,链接器不会发出多个定义错误

转载 作者:太空狗 更新时间:2023-10-29 15:21:33 24 4
gpt4 key购买 nike

给定一个带有签名的编译函数 void some_func()在一个静态库中,另一个具有相同的 void some_func()目标文件中的签名期望当您将它们链接在一起时应该发生“多重定义”错误。

但这种情况并非如此。据我观察,链接器(使用 GCC 和 MSVC 工具链测试)选择驻留在目标文件中的实现而不会发出任何错误或警告。

鉴于以下 POC:

somelib.h

#ifndef _SOMELIB_H_
#define _SOMELIB_H_

void some_func();

#endif /* _SOMELIB_H_ */

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

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

麻烦头.h
#ifndef _TROUBLING_HEADER_H_
#define _TROUBLING_HEADER_H_

void some_func();

#endif /* _TROUBLING_HEADER_H_ */

麻烦源.c
#include "troublingheader.h"
#include <stdio.h>

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

主文件
#include <stdio.h>
#include "somelib.h"

int main()
{
some_func();
}

还有一个简单的 Makefile 来帮助构建(首先创建 tmp 文件夹):
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”的内容如上所示。

有人能解释一下为什么会发生这种情况吗?

最佳答案

GNU linker ld 的情况下,
由 GCC 调用,您所观察到的内容由以下几点解释。

  • 链接序列中的目标文件无条件地添加到链接中,
    它是否包含程序需要的符号。
  • 静态库是目标文件的存档以及“目录”
    链接器可以检查。
  • 默认情况下,不添加链接序列中静态库中的目标文件
    无条件连接。链接器只搜索静态库
    找到它观察到的被引用的符号的定义,
    但未定义,由已添加到链接中的目标文件定义。提取目标文件
    仅当它提供此类符号的定义时才从库中添加到链接中。仅当链接器
    已经需要它提供的一些定义。

  • 为避免混淆,我们将更改输出消息:
    "some_func in library\n"

    到:
    "some_func in somelib.o"

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

    案例1

    友情链接 troublingsource.o本身和 somelib.o来自静态库。

    联动序列: main.o , troublingsource.o , libsomelib.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发现定义于 main.o
  • 符号 some_func发现引用但未在 main.o 中定义
  • troublingsource.o已无条件添加到链接
  • 符号 some_func ,以前引用但未定义,在 troublingsource.o 中定义.
  • 没有 Unresolved reference 文献。 libsomelib.a甚至没有被搜查。

  • 案例2

    友情链接 someblib.o本身和 troublingsource.o来自静态库。

    联动序列: main.o , somelib.o , libtroublingsource.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发现定义于 main.o
  • 符号 some_func发现引用但未在 main.o 中定义
  • someblib.o已无条件添加到链接
  • 符号 some_func ,以前引用但未定义,在 somelib.o 中定义.
  • 没有 Unresolved reference 文献。 libtroublingsource.a甚至没有被搜查。

  • 案例3

    友情链接 someblib.otroublingsource.o来自单独的静态库。

    联动序列: main.o , libsomelib.a , libtroublingsource.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发现定义于 main.o
  • 符号 some_func发现引用但未在 main.o 中定义
  • libsomeblib.a已搜索提供 some_func 定义的目标文件
  • some_func的定义在成员 somelib.o 中找到的 libsomelib.a
  • somelib.o提取自 libsomelib.a并添加到链接中。
  • 没有 Unresolved reference 文献。 libtroublingsource.a甚至没有被搜查。

  • 案例4

    友情链接 someblib.o本身和 troublingsource.o本身。

    联动序列: main.o , somelib.o , troublingsource.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发现定义于 main.o
  • 符号 some_func发现引用但未在 main.o 中定义
  • someblib.o已无条件添加到链接
  • 符号 some_func ,以前引用但未定义,在 somelib.o 中定义
  • troublingsource.o已无条件添加到链接
  • 符号 some_func , 已在 somelib.o 中定义, 发现在 troublingbsource.o 中再次定义. 错误 .

  • 案例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甚至没有被搜索,
  • main.o被无条件地添加到链接中。
  • 符号 main发现定义于 main.o
  • 符号 some_func发现引用但未在 main.o 中定义
  • 没有要链接的其他目标文件或库。 some_func最后是一个 undefined reference 。 错误 .
  • 关于c - 当目标文件和静态库中存在相同的符号时,链接器不会发出多个定义错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37490157/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com