在特定情况下创建替换 memset 如何触发重复符号错误?
Posted
技术标签:
【中文标题】在特定情况下创建替换 memset 如何触发重复符号错误?【英文标题】:How does creating a replacement memset trigger duplicate symbol errors in specific circumstances? 【发布时间】:2013-07-07 22:22:13 【问题描述】:我最近写了一些字符串例程的替代品(memcpy、memset 和 memmove)。我的理解是,如果在编译/链接行中指定了包含这些例程的库,这些将优先于同名的系统标准库例程。如果我已经错了,请告诉我!
这在我所做的所有测试中都能正常工作(通过反汇编验证存在正确的例程而 glibc 例程不存在),但进一步的测试发现了一个由此引起的奇怪中断:
1) 使用 -g 在同一个库中构建另一个文件(我一直在构建 -O2)
2) 该文件对 memset 有显式调用
3a) 如果编译时选项的工作方式是这个 memset 被 gcc 内联,那么一切正常
3b) 但是,如果这些选项禁用了 memset 调用的内联否则会被内联,该库将构建,但使用该库静态链接应用程序会导致重复的符号链接器错误 - 符号的另一个实例是系统库的 memset。
基本上我可以构建我的库的两个版本(100 个源文件),并且通过将一个目录中的 make CFLAGS 从 -O1 -g 更改为仅 -g 我可以在使用此库时触发链接器错误。
我可以使用工作版本,通过 nm 运行它,并看到它有许多未定义的 memset 引用,包括链接到我的测试用例的例程 - 所以我知道它应该尝试在工作用例中解析 memset .当我将此与损坏库的 nm 输出进行比较时,我看到的只是一些额外的未定义的 memcpy 和 memset 引用。如果 memset 在第一种情况下(对我的例程)解决,它应该在第二种情况下。
我还查看了详细的编译器输出并验证了这两种情况下的链接行完全相同,除了这个库的路径。
这里有两件超级令人费解的事情(在无数其他问题中):
1) 为什么构建的库中的文件 -O1 -g 链接与 -g 不同
2) 为什么用户库中的替换 memset 会与系统 memset 冲突
而对于大奖,1)如何导致2)
【问题讨论】:
【参考方案1】:想出这个解决方案花了很长时间,但现在很有意义:
1) 更高的优化使 gcc 能够内联 bzero,它在链接时没有其他引用。 memset 称它是内联/不是内联是红鲱鱼。
2) bzero 与 libc.a 中的 memset 位于同一文件中:memset.o。当 ld 试图拉入 memset.o 以满足 bzero 请求时,它得到了重复的 memset 符号。
(1) 导致 (2)。
解决方案是在我的库中提供我自己的 bzero 例程,从而停止需要 libc 的 memset.o。
【讨论】:
【参考方案2】:GCC 提供了大量标准库函数的内置版本。这些是为了优化目的而提供的。
其中许多功能仅在某些情况下进行了优化。如果他们 在某些情况下没有优化,对库函数的调用是 发射。
因此,构建的库 -O1 -g 与 -g 的链接方式不同。
【讨论】:
我知道不断变化的优化可能会改变内联的内容,但我不知道的是那些额外的调用如何改变符号在链接时的解析方式。它们不是新符号,只是对现有符号的额外引用。以上是关于在特定情况下创建替换 memset 如何触发重复符号错误?的主要内容,如果未能解决你的问题,请参考以下文章
如何在特定创建的文件上用 `inotifywait` 替换 `until.. sleep`?