先决条件
第三方提供了使用共享对象( C++ libfoo.so )的fooapp可执行文件.库还附带了头部foo.hpp,以便开发人员可以构建其他应用程序:
/* foo.hpp */
namespace foo {
void bar(int a, int b);
// More code below here <--- NOTE!!!
}成功范例
这是一个标准的LD_PRELOAD-based函数插入工作流。
首先,我编写了自己版本的库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 fooappFailure! ld_debug.log没有显示fooapp符号与libmyfoo.so的绑定。
(PS -如果您好奇的话,sym.map包含一个映射,该映射在foq::bar的破损名称和损坏的foo::bar名称之间。如果从-C命令中删除nm,您可以看到这些内容。参见man objcopy以获得更多详细信息。)
为什么?
总结如下:
objcopy正在正确地重命名符号。这里有什么故事?
发布于 2019-01-29 14:16:17
为什么?这里有什么故事?
objcopy -redefine-syms只会在.symtab和.strtab符号表中重新定义调试符号,而不会重新定义用于动态加载的.dynsym和.dynstr符号表中的符号。
如果检查用objcopy使用nm -D或readelf -s创建的库,就会发现动态加载程序使用的名称仍然是_ZN3foq3barEii,或者是nm -DC,foq::bar(int, int)。
所以,这就是发生的事。
我能找到的表明objcopy不能用于更新动态符号的最正式的引用是2010年未分配的bugzilla条目:
Bug 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.https://stackoverflow.com/questions/54332797
复制相似问题