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

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:利用动态链接的间接符号(兼容性有限)

通过编译选项让函数符号通过可写的间接指针引用,不过该方法依赖链接器行为,版本兼容性较差:

  1. 编译时添加链接选项:
gcc -o func_redirect func_redirect.c -flat_namespace -undefined suppress
  1. 修改代码如下:
#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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 17:40:31