首页 > 解决方案 > Linux中gcc链接期间的多个定义错误

问题描述

最近开始在 Linux 上进行 C 编码并遇到“多重定义”错误(以下来源AcBc

gcc -Wall 傲波 -o C

/usr/bin/ld: Bo: in function "Hello":
Bc:(.text+0x0): 'Hello'的多重定义;Ao:Ac:(.text+0x0): 首先在这里定义

通过 SO 搜索,建议使用此链接器命令行选项

--allow-multiple-definition (-z muldefs)
通常当一个符号被定义多次时,链接器会报告一个致命错误。
这些选项允许多个定义,并且将使用第一个定义。

运行此命令绕过了错误消息

gcc -Wall -Wl,--allow-multiple-definition 傲博 -o C

似乎恢复了和平,但是,它输出

。/C

你好 A
你好 A
世界 B

我期待下面的输出并“假设”链接器会顺利解决任何符号冲突,但至少保留现有的代码功能

你好 A
你好 B
世界 B

但是,通过检查来自objdump -S -M intel C的程序集输出,生成的C ELF 二进制文件被修改如下

问题

  1. 重命名符号 Hello() 是唯一正确的解决方案吗?
  2. 使用--allow-multiple-definition选项是不好的做法吗?
  3. 如果可能的话,链接器是否应该通过限制函数的可见性来对预期的代码功能更加敏感,即理解 Hello() 是 Bo 中的重复符号,并且从 World() 调用它应该仅限于Bo而不是查看Ao



gcc -Wall -c Ac

#include <stdio.h>

void Hello(void)
{
    printf("Hello A\n");
}

int main()
{
    Hello();
    World();

    return 0;
}

gcc -Wall -c Bc

#include <stdio.h>

void Hello(void)
{
    printf("Hello B\n");
}

void World(void)
{
    Hello();
    printf("World B\n");
}

已编辑

根据评论/答案,添加静态关键字效果很好

static void Hello(void)
{
    printf("Hello B\n");
}

现在无需使用该命令行选项

gcc -Wall 傲波 -o C

你好 A
你好 B
世界 B

这个问题的真正推动力是我们构建了一个 UASM 程序集对象文件,并且给出了有关 C 静态关键字的提示,至少我现在可以研究 UASM 中可用的内容以使这些函数对对象私有。

更新

对于 UASM,能够通过添加将功能范围限制在目标文件中

PROC PRIVATE FRAME

谢谢!

标签: clinuxgcc

解决方案


  1. 更改名称是最好的,但您也可以将它们设为静态(以限制对它们所在文件的访问)或稍微更改签名。

  2. 是的。难以置信的糟糕!在现实世界中,您期望 Hello() 做某事,但现在您让编译器决定使用哪个版本的 Hello() - 可能是正确的。可能是错的。甚至有这个选项(恕我直言)都是疯狂的。

  3. 您可以通过使它们成为静态来做到这一点。

这有点学术。为什么您认为Hello()首先调用 2 个全局范围函数是个好主意?


推荐阅读