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

是否存在编译器标志允许共享库调用打开它的共享库的函数?

问题:无需显式传递函数指针,让a.so调用b.so中的b_util函数

我需要实现从a()函数中调用b_util(),但不想通过显式传递b_util()的函数指针给a.c的方式来实现。我尝试使用-rdynamic编译标志(类似让共享库调用主可执行文件函数的场景),但编译a.c或b.c时添加该标志后,依然出现相同的运行时错误,想了解正确使用该标志的方法。

当前使用的编译命令:

gcc c.c -o c.out && gcc b.c -o b.so -shared -fPIC && gcc a.c -o a.so -shared && ./c.out

运行后输出错误:

dlopen: ./a.so: undefined symbol: b_util


相关代码

a.c

void b_util(void);
void a(void) {
    b_util();
}

b.c

#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
void assert_dl(void *p, char *fn_name) {
    if (!p) {
        fprintf(stderr, "%s: %s\n", fn_name, dlerror());
        exit(EXIT_FAILURE);
    }
}
void b(void) {
    void *dll = dlopen("./a.so", RTLD_NOW);
    assert_dl(dll, "dlopen");
    void (*a)(void) = dlsym(dll, "a");
    assert_dl(a, "dlsym");
    a();
}
void b_util(void) {
    printf("b_util\n");
}

c.c

#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
void assert_dl(void *p, char *fn_name) {
    if (!p) {
        fprintf(stderr, "%s: %s\n", fn_name, dlerror());
        exit(EXIT_FAILURE);
    }
}
int main(void) {
    void *dll = dlopen("./b.so", RTLD_NOW);
    assert_dl(dll, "dlopen");
    void (*b)(void) = dlsym(dll, "b");
    assert_dl(b, "dlsym");
    b();
}

解决方案

问题核心是:加载a.so时,b.so中的b_util符号未被暴露给a.so解析。需要调整编译选项和动态加载标志实现符号共享:

  1. 修改b.c的编译命令:添加-rdynamic,让b.so的符号导出到动态符号表,允许后续加载的库访问
  2. 修改b.c中的dlopen调用:添加RTLD_GLOBAL标志,让a.so加载时能访问已加载的全局符号(即b.so中的b_util)

修改后的代码和命令

修改后的b.c(仅改动dlopen行)
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
void assert_dl(void *p, char *fn_name) {
    if (!p) {
        fprintf(stderr, "%s: %s\n", fn_name, dlerror());
        exit(EXIT_FAILURE);
    }
}
void b(void) {
    // 添加RTLD_GLOBAL标志
    void *dll = dlopen("./a.so", RTLD_NOW | RTLD_GLOBAL);
    assert_dl(dll, "dlopen");
    void (*a)(void) = dlsym(dll, "a");
    assert_dl(a, "dlsym");
    a();
}
void b_util(void) {
    printf("b_util\n");
}
正确的编译运行命令
gcc c.c -o c.out && gcc b.c -o b.so -shared -fPIC -rdynamic && gcc a.c -o a.so -shared && ./c.out

原理说明

  • -rdynamic:让编译器将b.so中的全局符号(如b_util)加入动态符号表,使得这些符号可以被后续动态加载的共享库访问
  • RTLD_GLOBAL:加载a.so时,将其符号加入全局符号表,同时允许a.so从已加载的全局符号中解析自身未定义的符号(这里就是b_util)

运行修改后的代码,会输出b_util,实现预期的调用。


内容的提问来源于stack exchange,提问作者MyNameIsTrez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 16:13:15