多个弱符号的后果(C链接器)

时间:2018-11-12 02:44:29

标签: c linker

我只是有一个关于多个弱符号的潜在问题的问题,这个问题来自我的教科书:

一个模块A:

int x;
int y;
p1() {...}

另一个模块B:

double x;
p2() {...}

我的课本说 '在p2中写入x可能会覆盖y' 我可以有点教科书的想法(双倍x是int x大小的两倍,并且int y紧接在int x后面放置int,这是问题所在),但仍然遗漏了细节,我知道何时有多个弱点符号,链接器将随机选择一个,所以我的问题是,链接器选择的模块的哪个x将导致写入p2中的x会覆盖y。

这是我的理解:如果链接器选择模块A的 int x ,将导致结果,因为那样,x,y都是4个字节,而p2(编译后的图像在那里是一个汇编代码movq与p1中的movl比较)将更改8个字节,因此覆盖y。

但是我的讲师说,如果仅链接程序选择模块B的 double x ,这将导致覆盖y,这是怎么回事,我是正确的还是我的讲师是正确的?

1 个答案:

答案 0 :(得分:0)

根据ISO C,程序将调用未定义的行为。所使用的外部名称必须在程序中的某个位置完全具有一个定义。 *

“弱符号”是某些动态库系统(例如GNU / Linux上的ELF)的概念。该术语在这里不适用。允许对外部符号进行多个定义的链接器据说正在实现“松弛的ref / def”模型。该术语来自ANSI C rationale的6.1.2.2节。

如果我们将宽松的ref / def模型视为文档化的语言扩展,则名称的多个定义将成为本地定义的行为。但是,如果输入不一致,该怎么办?这种情况类似于不良的类型别名的理由几乎可以肯定地未定义。如果一个模块具有int x; int y;,而另一个模块具有double x,则通过double x别名进行的写操作将破坏y。这不是您可以依赖的东西。这是故意获得锯齿效果的非常差的方法。您想在两个结构之间使用union或类似的结构。

现在有关“弱符号”的问题:那些是共享库中的外部名称,可以用替代定义覆盖。例如,GNU / Linux系统上GNU C库中的大多数功能都是弱符号。例如,程序可以定义自己的read函数来替换POSIX函数。无论如何重新定义read,库本身都不会中断;当需要调用read时,它不使用弱符号read,而是使用一些内部别名,例如__libc_read。 这个机制很重要;它允许库符合ISOC。允许严格符合ISO C的程序使用read作为外部名称。


*在ISO C99标准中,这是在 6.9外部定义中给出的:“如果在表达式中使用了用外部链接声明的标识符(不是作为操作数的一部分)一个sizeof运算符,其结果是一个整数常量),在整个程序中的某个位置,标识符应恰好是一个外部定义;否则,标识符应不超过一个。”