使用--wrap选项的链接器包装无法捕获jmp指令调用的符号
内存追踪系统中libstdc++的operator delete跳转指令问题
我正在通过链接器包装内存分配与释放函数构建内存追踪系统,采用C++11标准,已定义以下包装符号:
#define wrap(symbol) __wrap_ ## symbol extern "C" { void* wrap(malloc)(size_t size); void* wrap(realloc)(void* ptr, size_t new_size); void wrap(free)(void *ptr); void* wrap(calloc)(size_t num, size_t size); char* wrap(strdup)(const char *str1); // operator new(unsigned long) void* wrap(_Znwm)(std::size_t count); // operator new[](unsigned long) void* wrap(_Znam)(std::size_t count); // operator new(unsigned long, std::nothrow_t const&) void* wrap(_ZnwmRKSt9nothrow_t)(std::size_t count, const std::nothrow_t& tag); // operator new[](unsigned long, std::nothrow_t const&) void* wrap(_ZnamRKSt9nothrow_t)(std::size_t count, const std::nothrow_t& tag); // operator delete(void*) void wrap(_ZdlPv)(void *ptr); // operator delete[](void*) void wrap(_ZdaPv)(void *ptr); // operator delete(void*, std::nothrow_t const&) void wrap(_ZdlPvRKSt9nothrow_t)(void *ptr, std::nothrow_t const&); // operator delete[](void*, std::nothrow_t const&) void wrap(_ZdaPvRKSt9nothrow_t)(void *ptr, std::nothrow_t const&); // placement operator delete // operator delete(void*, unsigned long) void wrap(_ZdlPvm)(void* ptr, unsigned long); // operator delete[](void*, unsigned long) void wrap(_ZdaPvm)(void* ptr, unsigned long); } // extern "C"
问题现象
我发现libstdc++头文件中部分operator delete调用未使用call指令,而是通过jmp指令实现,比如std::string的析构逻辑:
(gdb) disas std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_destroy Dump of assembler code for function std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_destroy(unsigned long): 0x00007ffff56b3d90 <+0>: mov rdi,QWORD PTR [rdi] 0x00007ffff56b3d93 <+3>: jmp 0x7ffff560c7d0 <_ZdlPv@plt> End of assembler dump.
目前std::basic_string::_M_create中的new调用已被正常包装,但该jmp问题也出现在std::stringstream等场景。虽然可以通过传入自定义allocator解决,但此方案不可行。
核心疑问
我理解相关代码位于头文件并随项目编译,现存在两个问题:
- 如何将PLT中指向operator delete的jmp指令转为call指令?
- 或如何强制链接器包装通过jmp指令调用的符号?
当前环境
我使用的编译选项为:
-Wl,--wrap=malloc,--wrap=realloc,--wrap=free,--wrap=calloc,--wrap=strdup,--wrap=_Znwm,--wrap=_Znam,--wrap=_ZnwmRKSt9nothrow_t,--wrap=_ZnamRKSt9nothrow_t,--wrap=_ZdlPv,--wrap=_ZdaPv,--wrap=_ZdlPvRKSt9nothrow_t,--wrap=_ZdaPvRKSt9nothrow_t,--wrap=_ZdlPvm,--wrap=_ZdaPvm
我曾怀疑是尾调用优化导致,尝试添加-fno-optimize-sibling-calls编译选项,但未能解决问题。
内容的提问来源于stack exchange,提问作者Evgeny Ignatenko
相关产品推荐
相关产品推荐

