gpt4 book ai didi

c++ - objcopy --redefine-syms 绑定(bind)失败

转载 作者:可可西里 更新时间:2023-11-01 15:22:43 24 4
gpt4 key购买 nike

先决条件

第三方提供了使用共享对象 libfoo.so 的 C++ 可执行文件 fooapp。该库还带有一个 header foo.hpp,因此开发人员可以构建其他应用程序:

/* foo.hpp */
namespace foo {
void bar(int a, int b);
// More code below here <--- NOTE!!!
}

成功范例

这是一个标准的基于 LD_PRELOAD 的函数插入工作流程。

首先,我编写了我自己的库版本 myfoo.cpp,它完全反射(reflect)了部分 foo.hpp:

/* myfoo.hpp */
# include <ofstream>
namespace foo {
void bar(int a, int b) {
std::cout << a << "," << b << std::endl;
}
// NOTHING below here <-- NOTE!!!
}

然后我将我的库编译成 libmyfoo.so 并看到以下内容:

$ nm libfoo.so -C | fgrep bar
0000000000021fc0 T foo::bar(int, int)
$ nm libmyfoo.so -C | fgrep bar
0000000000010c30 T foo::bar(int, int)
$ LD_DEBUG=bindings LD_DEBUG_OUTPUT=ld_debug.log LD_PRELOAD=./libmyfoo.so fooapp

成功! ld_debug.log 按预期显示绑定(bind),并且 bar(...) 生成输出到控制台。

失败示例

对于失败示例,我将 (1) 更改 myfoo.hpp 中的一个字符,(2) 然后使用 objcopy 修复二进制文件中的该字符:

/* myfoo.hpp */
# include <ofstream>
namespace foq { // <-- NAME CHANGE!
void bar(int a, int b) {
std::cout << a << "," << b << std::endl;
}
// NOTHING below here <-- NOTE!!!
}

当我将我的库编译成 libmyfoq.so 时,我看到以下内容:

$ nm libfoo.so -C | fgrep bar
0000000000021fc0 T foo::bar(int, int) # <-- Sames as before
$ nm libmyfoq.so -C | fgrep bar
0000000000010c30 T foq::bar(int, int) # <-- New name as expected
$ objcopy --redefine-syms=sym.map libmyfoq.so libmyfoo.so # <-- NEW STEP!
$ nm libmyfoo.so -C | fgrep bar
0000000000010c30 T foo::bar(int, int) # <-- SUCCESSful name update
$ LD_DEBUG=bindings LD_DEBUG_OUTPUT=ld_debug.log LD_PRELOAD=./libmyfoo.so fooapp

失败! ld_debug.log 显示 NO fooapp 符号与 libmyfoo.so< 的绑定(bind).

(PS -- 如果你很好奇,sym.map 包含 foq::bar 的错位名称和 的错位名称之间的映射foo::bar。如果从 nm 命令中删除 -C,就可以看到这些。有关其他信息,请参见 man objcopy详情。)

为什么?

总结:

  • objcopy 正在正确重命名符号。
  • 符号名称没有改变大小。
  • 但是加载程序在加载时忽略了它。

这里有什么故事?

最佳答案

WHY? What's the story here?

objcopy -redefine-syms 只会重定义.symtab.strtab 符号表中的调试符号,不会重定义.dynsym.dynstr 用于动态加载的符号表。

如果您使用 nm -Dreadelf -s 检查您使用 objcopy 创建的库,您会看到动态加载器仍然是 _ZN3foq3barEii,或者使用 nm -DCfoq::bar(int, int)

所以,这就是正在发生的事情。

我能找到的表明 objcopy 不能用于更新动态符号的最官方引用资料是这个 2010 年未分配的 bugzilla 条目:

Bug 11386 - objcopy should be able to update dynamic symbols visibility

还有我自己在官方 binutils 邮件列表中的查询:

Redefining dynamic symbols


附带说明一下,我认为没有可用的工具来(正确地)重新定义动态符号,但我可能是错的。

cjacker/elfhash 2015年的project似乎在做尝试。我试过了,它似乎实际上重命名了动态符号名称 - 但之后加载 .so 失败,而是使用原始库符号。

% elfhash -f _ZN3foq3barEii -t _ZN3foo3barEii libmyfoq.so
% mv libmyfoq.so libmyfoo.so
% LD_DEBUG=bindings LD_DEBUG_OUTPUT=ld_debug.log LD_PRELOAD=./libmyfoo.so ./fooapp
ERROR: ld.so: object './libmyfoo.so' from LD_PRELOAD cannot be preloaded (cannot change memory protections): ignored.

关于c++ - objcopy --redefine-syms 绑定(bind)失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54332797/

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