C++中获取函数真实入口地址并还原名称需结合多种方法:一、用&func取址转uintptr_t;二、objdump+addr2line解析符号;三、运行时调用__cxa_demangle;四、用libbfd/libdwarf读DWARF调试信息;五、GDB Python API动态查询。

如果您在调试或逆向分析 C++ 程序时,需要获取函数在内存中的真实入口地址并还原其原始可读名称,则可能遇到符号被编译器修饰(mangled)且地址受优化、内联、链接方式影响的问题。以下是实现该目标的多种方法:
一、使用 & 操作符获取函数指针并强制转换为 uintptr_t
对于非内联、非虚、非模板的普通函数,取地址操作符 & 可直接获得其代码段起始地址,该地址即为运行时实际入口。需注意函数必须已定义且未被编译器完全优化掉。
1、声明一个普通全局函数,确保未加 inline、static 或被 LTO 优化删除。
2、在代码中使用 reinterpret_cast
立即学习“C++免费学习笔记(深入)”;
3、验证该地址是否在 .text 段范围内,可通过 /proc/self/maps(Linux)或 VirtualQuery(Windows)比对。
二、通过 objdump + addr2line 定位符号地址并解析
当函数已被编译进可执行文件或共享库,但源码不可控时,可借助工具链从二进制中提取地址信息,并结合调试信息还原符号。
1、执行 objdump -tT ./binary | grep func_name 查找符号表中对应条目(含地址和绑定类型)。
2、若符号为动态导出,使用 readelf -Ws ./lib.so | grep func_name 检查其 STB_GLOBAL 绑定与 STT_FUNC 类型。
3、对得到的地址(如 0x4012a0),运行 addr2line -e ./binary -C -f 0x4012a0 输出反混淆后的函数名及源码位置。
三、调用 __cxa_demangle 进行运行时 Demangle
GNU libstdc++ 提供的 __cxa_demangle 是标准 C++ ABI 规定的运行时反混淆接口,适用于从 typeid.name() 或异常信息中提取的 mangled 名称。
1、包含头文件
2、调用 abi::__cxa_demangle(mangled_name, nullptr, nullptr, &status),其中 status 为 int 输出参数,仅当值为 0 时表示成功。
3、检查返回指针是否非空,若成功则为堆分配的 C 字符串,需手动 free()。
四、利用 libbfd 或 libdwarf 解析调试段中的 DWARF 信息
当程序带有 DWARF 调试信息(-g 编译),可绕过符号表,直接从 .debug_info 段定位函数的 low_pc 属性,该值即为其机器码起始地址,且 DIE 中包含未修饰的 DW_AT_name。
1、使用 bfd_init() 和 bfd_openr() 打开目标文件。
2、调用 bfd_check_format() 确认格式为 bfd_object,并启用调试信息解析。
3、遍历所有编译单元,对每个 DW_TAG_subprogram DIE 调用 dwarf_get_die_addr() 获取 low_pc 值,并读取 DW_AT_name 属性字符串。
五、通过 GDB Python API 在运行时提取符号地址与名称
当程序正在 GDB 中运行,且已加载调试符号,可利用 GDB 内置的 Python 扩展直接查询函数的真实地址和 demangled 名称,无需修改源码或重新编译。
1、在 GDB 中执行 python import gdb; f = gdb.lookup_global_symbol("func_name"); print(hex(int(f.value().address))) 获取地址。
2、对符号对象调用 f.symbol.linkage_name 获取 mangled 名,再调用 gdb.demangle(f.symbol.linkage_name) 得到可读名。
3、若函数为成员函数或模板实例,需确保 GDB 版本 ≥ 8.2 且启用了 set print demangle on。


















