You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用--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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 21:35:16