【发布时间】:2020-12-09 07:05:01
【问题描述】:
是否有任何实用程序可以修补 ELF 符号表中的任意符号,以便定义的符号变为未定义的?例如,这里是 readelf --syms 用于我要处理的文件
Symbol table '.symtab' contains 8 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
...
5: 0000000000000000 13 FUNC WEAK DEFAULT 3 my_message
6: 0000000000000000 19 FUNC GLOBAL DEFAULT 5 print_msg
7: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND puts
这是未定义 my_message 的同一二进制文件的预期输出:
Symbol table '.symtab' contains 8 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
...
5: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND my_message
6: 0000000000000000 19 FUNC GLOBAL DEFAULT 5 print_msg
7: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND puts
ELF 文件本身是可重定位的。修改应该只改变符号表。包含原始符号定义的实际部分应保持不变。
我已经检查了 GNU Binutils,objcopy 可能是我正在寻找的东西,但到目前为止,我还没有想出任何可以给我上述行为的选项(或组合)。
事实上,这样的工具应该很容易实现(即使没有像 BFD 这样的额外库),但我想知道是否有一些我可能会错过的现有东西。
【问题讨论】:
-
你希望通过取消定义符号来实现什么?因此,内部呼叫可能不会被重定向。
-
@FlorianWeimer 我计划强制链接器忽略一个目标文件中的某些定义,以便从其他地方解析它们。正如您所说,这可能不适用于非
GLOBAL符号,因为编译器可能会发出这样的重定位,这些重定位以后无法通过链接器转换为跳转槽或 GOT 条目(因此无法重定向到外部 DSO)。但另一方面 gABI 将GLOBAL符号定义为可抢占的,这意味着它们最终会通过专用跳转槽或 GOT 条目来引用。所以应该可以“取消定义”它们并从其他动态库中获取另一个定义。 -
编译器可能已经创建了本地别名,然后链接编辑器将在本地解析。 LTO 会发生这种情况,
-fno-semantic-interposition也会发生这种情况。 -
对,
*.localalias.0都是LOCAL,所以我提到的方法在这里行不通。无论如何,如果可以创建或不创建本地别名,这是用户控制的行为。所以这对我的项目来说应该是可以管理的。而且看起来只有 GCC 支持-fno-semantic-interposition而我的目标编译器是 Clang,它对此一无所知。 -
顺便说一句,
-fno-semantic-interposition看起来有些多余,因为STV_PROTECTED以与工具链无关的方式提供了完全相同的语义。此外,IMO-fno-semantic-interposition违反了 gABI,因为它硬连线GLOBAL在二进制文件中导出,而不让用户抢占它,更重要的是,与STV_PROTECTED不同,它无法通过检查剥离的可加载二进制文件来猜测这一点。