MacOS Ventura下如何让符号表中的函数名指向另一函数
MacOS Ventura下通过dlopen修改函数符号指向的问题
在MacOS Ventura系统中,使用dlopen(NULL, 0)获取的动态加载器句柄包含整个可执行文件的符号表。通过该句柄可以获取全局变量的指针,修改后会在全程序生效,但对函数指针执行类似操作时却无法达到预期效果。
全局变量修改的有效示例
以下代码通过dlopen和dlsym修改全局变量my_var的值,最终输出5而非初始的0:
#include <dlfcn.h> #include <stdio.h> #include <stdlib.h> int my_var = 0; int main() { void *handle = dlopen(NULL, 0); int *a = dlsym(handle, "my_var"); *a = 5; printf("%d", my_var); return 0; }
函数指针修改的失败示例
尝试对函数执行类似操作时,调用fun1()仍输出a而非预期的b;若将f1ptr改为ftype *并执行*f1ptr = fun2,还会触发总线错误:
#include <dlfcn.h> #include <stdio.h> #include <stdlib.h> typedef void (*ftype)(void); void fun1() { printf("a"); } void fun2() { printf("b"); } int main() { void *handle = dlopen(NULL, 0); ftype f1ptr; *(void **)(&f1ptr) = dlsym(handle, "fun1"); f1ptr = fun2; fun1(); return 0; }
问题原因
MacOS的Mach-O可执行文件中,函数符号默认绑定到只读__TEXT段的代码地址,无法直接修改;而全局变量位于可写的__DATA段,因此可以通过dlsym获取指针后修改。
可行的解决方案
方法1:用全局函数指针替代原函数
将原函数包装为全局指针变量,使其位于可写段,即可像修改普通变量一样修改指向:
#include <dlfcn.h> #include <stdio.h> #include <stdlib.h> typedef void (*ftype)(void); // 原函数的实际实现 void fun1_impl() { printf("a"); } // 全局函数指针,初始指向原实现 ftype fun1 = fun1_impl; void fun2() { printf("b"); } int main() { void *handle = dlopen(NULL, 0); ftype *f1ptr = (ftype *)dlsym(handle, "fun1"); if (f1ptr == NULL) { fprintf(stderr, "%s\n", dlerror()); exit(1); } // 修改指针指向fun2 *f1ptr = fun2; // 调用fun1将执行fun2的代码 fun1(); return 0; }
方法2:利用动态链接的间接符号(兼容性有限)
通过编译选项让函数符号通过可写的间接指针引用,不过该方法依赖链接器行为,版本兼容性较差:
- 编译时添加链接选项:
gcc -o func_redirect func_redirect.c -flat_namespace -undefined suppress
- 修改代码如下:
#include <dlfcn.h> #include <stdio.h> #include <stdlib.h> typedef void (*ftype)(void); void fun1() { printf("a"); } void fun2() { printf("b"); } int main() { void *handle = dlopen(NULL, RTLD_NOW | RTLD_GLOBAL); void **f1ptr = (void **)dlsym(handle, "fun1"); if (f1ptr == NULL) { fprintf(stderr, "%s\n", dlerror()); exit(1); } *f1ptr = fun2; fun1(); return 0; }
内容的提问来源于stack exchange,提问作者jungon
相关产品推荐
相关产品推荐

