为何无法在可执行文件内部通过dlopen/dlsym动态调用自身函数?
可执行文件内部动态调用同文件函数失败的解决方法
问题描述
尝试在可执行文件内部通过dlopen+dlsym动态调用同源码文件中的test_func函数,示例代码如下:
#include <stdio.h> #include <dlfcn.h> // or with some tricks // void __attribute__((visibility("default"))) void test_func(void) { printf("test_func in %s\n",__FILE__); } int main() { void *handle = dlopen(0, RTLD_LAZY); // or RTLD_GLOBAL printf("dlopen return %p\n", handle); void (*func)() = dlsym(handle, "test_func"); printf("dlsym return %p\n", func); if (func) (*func)(); return 0; }
编译后运行失败,输出:
$ ./a.out dlopen return 0xe29dfbec1c7bc0d dlsym return 0x0
但通过readelf能看到该符号存在:
$ readelf -s a.out | grep test_func 40: 00000000000017c8 36 FUNC GLOBAL DEFAULT 13 test_func
问题原因与解决方法
核心问题
readelf查看的是静态符号表,而dlsym查找的是动态符号表。GCC默认编译可执行文件时,不会将全局符号加入动态符号表,因此即使符号存在,动态链接器也无法找到。
解决方式一:添加编译选项-rdynamic
编译时加上-rdynamic选项,它会将所有全局符号导出到动态符号表中,让dlsym可以找到目标函数:
gcc test.c -o a.out -ldl -rdynamic
解决方式二:显式设置函数可见性
修改test_func的定义,添加visibility("default")属性,单独将该符号导出到动态符号表,无需全局导出所有符号:
#include <stdio.h> #include <dlfcn.h> void __attribute__((visibility("default"))) test_func(void) { printf("test_func in %s\n",__FILE__); } int main() { void *handle = dlopen(0, RTLD_LAZY); printf("dlopen return %p\n", handle); void (*func)() = dlsym(handle, "test_func"); printf("dlsym return %p\n", func); if (func) (*func)(); return 0; }
编译时只需链接动态链接库:
gcc test.c -o a.out -ldl
验证效果
两种方式编译后运行,都会输出:
dlopen return 0xXXXXXX dlsym return 0xXXXXXX test_func in test.c
内容的提问来源于stack exchange,提问作者uscq
相关产品推荐
相关产品推荐

