如何查找.so动态库文件中符号(如函数名)的绝对地址
动态库.so符号地址获取方法
你看到的地址为0的符号都标记了UND属性,属于该动态库依赖的外部符号(比如glibc、libstdc++提供的库函数),本身并不在当前.so中实现,因此没有对应地址。你输出中第66行的_ZN4test13overwriteFuncEiml是当前.so自身实现的函数,第一列的0xfe0就是该函数在.so文件内的相对偏移地址。
静态获取符号相对偏移
如果仅需要获取符号在.so文件中的相对偏移,可使用以下方法:
- 优先使用
readelf命令读取符号表,结果更准确:readelf -s myLib.so | grep 目标符号名
输出结果的Value字段即为符号的相对偏移。 - 也可使用
nm命令,若要查看C++脱修饰后的函数名,添加-C参数:nm -gDC myLib.so | grep 目标函数名
非UND条目的第一列就是符号相对偏移。
注意:如果.so文件已经被strip过,符号表会被删除,静态工具无法查询到符号信息。
运行时获取符号绝对地址
动态库默认编译为位置无关代码(PIC),加载到进程虚拟地址空间的基址是运行时动态分配的,因此绝对地址 = 动态库加载基址 + 符号相对偏移,可通过两种方式获取:
方法1:程序内通过dlsym直接获取
调用dlopen系列函数可直接拿到符号的绝对地址,示例代码如下:
#include <dlfcn.h> #include <stdio.h> int main() { // 加载目标动态库 void* handle = dlopen("./myLib.so", RTLD_LAZY); if (!handle) { printf("加载动态库失败: %s\n", dlerror()); return 1; } // 查找目标符号地址,C++符号需要传入修饰后的名称,或加extern "C"修饰函数 void* sym_addr = dlsym(handle, "目标符号名"); if (!sym_addr) { printf("查找符号失败: %s\n", dlerror()); dlclose(handle); return 1; } printf("符号绝对地址为: %p\n", sym_addr); dlclose(handle); return 0; }
编译时添加-ldl参数链接动态加载库即可运行。
方法2:通过进程maps文件计算
如果目标动态库已经被加载到某进程中,可通过进程的maps文件计算地址:
- 先查询目标进程的PID,执行
cat /proc/<PID>/maps | grep myLib.so,输出第一列的起始地址就是该动态库的加载基址。 - 将加载基址加上之前静态查询到的符号相对偏移,得到的结果就是该符号在当前进程中的绝对地址。
额外注意事项
C++函数默认会开启名字修饰,直接用原函数名无法查找到符号,有两种解决方案:
- 函数定义时添加
extern "C"修饰,关闭名字修饰。 - 查询符号时使用修饰后的名称,可通过
nm -DC命令先查询到修饰名和原函数的对应关系。
内容的提问来源于stack exchange,提问作者Qiyang Li
相关产品推荐
相关产品推荐

