使用 objcopy --redefine-syms 的绑定失败
Binding failure with objcopy --redefine-syms
前提条件
第三方提供了使用共享对象libfoo.so
的C++可执行文件fooapp
。该库还附带了一个标头foo.hpp
以便开发人员可以构建其他应用程序:
/* foo.hpp */
namespace foo {
void bar(int a, int b);
// More code below here <--- NOTE!!!
}
成功案例
这是一个标准的基于LD_PRELOAD
的函数干预工作流。
首先,我编写自己的库版本,myfoo.cpp
完全反映了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
按预期显示绑定,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
显示没有将fooapp
符号绑定到libmyfoo.so
。
(PS - 如果你好奇,sym.map
包含foq::bar
的损坏名称和foo::bar
的损坏名称之间的映射。如果从nm
命令中删除-C
,则可以看到这些内容。有关更多详细信息,请参阅man objcopy
。
为什么?
总结:
objcopy
正确重命名符号。- 符号名称未更改大小。
- 但是加载程序在加载时忽略了它。
这是什么故事?
为什么?这是什么故事?
objcopy -redefine-syms
只会重新定义.symtab
和.strtab
符号表中的调试符号,而不会重新定义用于动态加载的.dynsym
和.dynstr
符号表中的符号。
如果您检查使用nm -D
或readelf -s
objcopy
创建的库,您将看到动态加载程序使用的名称仍然是_ZN3foq3barEii
,或者带有nm -DC
、foq::bar(int, int)
。
所以,这就是正在发生的事情。
我能找到的最官方的参考资料表明objcopy
不能用于更新动态符号是 2010 年的这个未分配的 bugzilla 条目:
错误 11386 - objcopy 应该能够更新动态符号可见性
以及我自己在官方binutils
邮件列表中的查询:
重新定义动态符号
作为旁注,我认为没有可用于重新定义动态符号的工具(正确),但我可能是错的。
2015年的劫机者/精灵项目似乎在尝试。我尝试过,它似乎实际上重命名了动态符号名称 - 但之后加载.so
失败,而是使用原始的 libs 符号。
% 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.
- 结构化绑定初始值设定项表单 { 赋值表达式 } 对于 clang 上的数组类型失败
- Qt - QUdpSocket 绑定不断失败
- std::tie 在从函数调用传递值时失败,并显示"无法绑定非常量左值引用"
- 当Boost ::绑定模板函数时,模板参数扣除/替换失败
- QUdp套接字绑定失败
- 在 Mac 上C++编译代码时处理“dyld:惰性符号绑定失败:找不到符号”错误
- C++ 由于无法解决过载功能而导致绑定失败
- dyld:惰性符号绑定失败:找不到符号:_yylex
- 从返回绑定中获取函数失败
- dyld:惰性符号绑定失败:找不到符号.预期在:平面命名空间
- 为线程构造函数传递引用以将其绑定到函数失败
- 为什么结构化绑定在 GCC 上失败
- 使用 objcopy --redefine-syms 的绑定失败
- 为什么这个std::绑定失败
- 惰性符号绑定失败:找不到符号
- sc_start警告 W571 表示信号/端口绑定失败
- C++套接字编程:sendto()和recvfrom()错误代码10038和in 'server'绑定失败,10038
- 使用ShareAddress进行多播的QUdpSocket绑定失败
- 运行时使用MVVM绑定失败
- OSX 10.7.5 上的 node-gyp -- dyld:惰性符号绑定失败:找不到符号