首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用objcopy绑定失败-重新定义-syms

使用objcopy绑定失败-重新定义-syms
EN

Stack Overflow用户
提问于 2019-01-23 17:39:00
回答 1查看 2.4K关注 0票数 14

先决条件

第三方提供了使用共享对象( C++ libfoo.so )的fooapp可执行文件.库还附带了头部foo.hpp,以便开发人员可以构建其他应用程序:

代码语言:javascript
复制
/* foo.hpp */
namespace foo {
  void bar(int a, int b);
  // More code below here <--- NOTE!!!
}

成功范例

这是一个标准的LD_PRELOAD-based函数插入工作流。

首先,我编写了自己版本的库myfoo.cpp,它精确地反映了 foo.hpp部分。

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

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

代码语言:javascript
复制
$ 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修复二进制中的字符

代码语言:javascript
复制
/* 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中时,我会看到以下内容:

代码语言:javascript
复制
$ 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

Failure! ld_debug.log没有显示fooapp符号与libmyfoo.so的绑定。

(PS -如果您好奇的话,sym.map包含一个映射,该映射在foq::bar的破损名称和损坏的foo::bar名称之间。如果从-C命令中删除nm,您可以看到这些内容。参见man objcopy以获得更多详细信息。)

为什么?

总结如下:

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

这里有什么故事?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-01-29 14:16:17

为什么?这里有什么故事?

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

如果检查用objcopy使用nm -Dreadelf -s创建的库,就会发现动态加载程序使用的名称仍然是_ZN3foq3barEii,或者是nm -DCfoq::bar(int, int)

所以,这就是发生的事。

我能找到的表明objcopy不能用于更新动态符号的最正式的引用是2010年未分配的bugzilla条目:

Bug 11386 - objcopy应该能够更新动态符号可见性。

以及我自己对官方binutils邮件列表的查询:

重新定义动态符号

顺便提一句,我不认为有一个工具可以重新定义动态符号(正确),但我可能是错的。

2015年开始的夹子/散列项目似乎是一次尝试。我试过了,它似乎实际上重命名了动态符号名,但是加载.so之后失败了,取而代之的是原来的libs符号。

代码语言:javascript
复制
% 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.
票数 10
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54332797

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档