dlmopen() 无法解析创建的命名空间中定义的函数符号
dlmopen() can't resolve defined function symbol in created namespace
我在 C 中使用 dlmopen 将共享库加载到隔离的名称空间中。我的目标是使该名称空间中的符号都属于加载的库。所以他们无法访问我的主程序中的符号。 Flowing是main函数的伪·do·代码,用来展示过程。
// when first .so is loaded, load it into a new namespace and store that namespace
// function a() is defined in it
void* handle1 = dlmopen(LM_ID_NEWLM, new_so_name1, RTLD_NOW);
// store the namespace in lmid
dlinfo(handle1, RTLD_DI_LMID, &lmid);
// when second .so is loaded, load it in lmid
// function b() is defined in it
void* handle2 = dlmopen(lmid, new_so_name2, RTLD_NOW);
效果不错。而且似乎 a() 和 b() 都被加载到命名空间中。
但是当我加载第三个共享库时,发生了一些奇怪的事情:
// If I make a call a() in the third library
void* handle3 = dlmopen(lmid, new_so_name3, RTLD_NOW);
// call a() using dlsym()
加载成功,我可以调用那个函数a()。
但是,如果我在第三个库中调用 b() 并将其加载到相同的命名空间中:
void* handle3 = dlmopen(lmid, new_so_name3, RTLD_NOW);
printf("error:%s\n", dlerror());
它给出了以下错误:
erroe:undefined symbol: b
似乎第二个库没有成功加载到命名空间中。但正如我所展示的,第二次加载成功并返回了一个非空的 handle2。
那么为什么会发生这种情况,我的加载过程有什么问题?我只希望所有加载的库都可以在该特定命名空间中共享符号,以避免在我的主程序中使用符号。
编辑:附录
正如@CharlieBurns 所建议的。我post下面的最小程序来说明我的问题。
#define _GNU_SOURCE
#include <stdio.h>
#include <link.h>
#include <dlfcn.h>
void* handle1;
void* handle2;
void* handle3;
Lmid_t lmid;
int main() {
// handle1 contains: int a(){return 0;}
handle1 = dlmopen(LM_ID_NEWLM, "/tmp/lib-o1i6Yd.so", RTLD_NOW);
dlinfo(handle1, RTLD_DI_LMID, &lmid);
// handle2 contains: int b(){return 1;}
handle2 = dlmopen(lmid, "/tmp/lib-vSyM4y.so", RTLD_NOW);
#ifdef RUN_A
int (*A)(void);
handle3 = dlmopen(lmid, "/tmp/lib-lAGjb2.so", RTLD_NOW);
A = (int(*)(void))dlsym(handle3, "__wrapper_lAGjb2");
/*
int __wrapper_lAGjb2() {
return a();
}
*/
printf("%d\n", (*A)()); // output 0 as expected
return 0;
#endif
#ifdef RUN_B
int (*B)(void);
handle3 = dlmopen(lmid, "/tmp/lib-CO1YAD.so", RTLD_NOW);
// error: /tmp/lib-CO1YAD.so: undefined symbol: b
printf("error: %s\n", dlerror());
B = (int(*)(void))dlsym(handle3, "__wrapper_CO1YAD");
// error: ./a.out: undefined symbol: __wrapper_CO1YAD
printf("error: %s\n", dlerror()); //
/*
int __wrapper_CO1YAD() {
return b();
}
*/
printf("%d\n", (*B)()); // segmentation fault (core dumped)
return 0;
#endif
}
这是test.c
文件。我使用 gcc test.c -ldl -DRUN_A/B
编译,然后 ./a.out
到 运行 它。
编辑:/tmp/.so
个文件
它们是手动创建的。例如,要使用 gcc 创建 /tmp/lib-o1i6Yd.so
文件:
在 /tmp/lib-o1i6Yd.c
:
中编写代码
int a(){return 0;}
编译为 .o
目标文件:
gcc -c -fpic /tmp/lib-o1i6Yd.c -o /tmp/lib-o1i6Yd.o
然后创建 .so
文件:
gcc -shared -o /tmp/lib-o1i6Yd.so /tmp/lib-o1i6Yd.o
我在 C 中使用 dlmopen 将共享库加载到隔离的名称空间中。我的目标是使该名称空间中的符号都属于加载的库。所以他们无法访问我的主程序中的符号。 Flowing是main函数的伪·do·代码,用来展示过程。
// when first .so is loaded, load it into a new namespace and store that namespace
// function a() is defined in it
void* handle1 = dlmopen(LM_ID_NEWLM, new_so_name1, RTLD_NOW);
// store the namespace in lmid
dlinfo(handle1, RTLD_DI_LMID, &lmid);
// when second .so is loaded, load it in lmid
// function b() is defined in it
void* handle2 = dlmopen(lmid, new_so_name2, RTLD_NOW);
效果不错。而且似乎 a() 和 b() 都被加载到命名空间中。 但是当我加载第三个共享库时,发生了一些奇怪的事情:
// If I make a call a() in the third library
void* handle3 = dlmopen(lmid, new_so_name3, RTLD_NOW);
// call a() using dlsym()
加载成功,我可以调用那个函数a()。 但是,如果我在第三个库中调用 b() 并将其加载到相同的命名空间中:
void* handle3 = dlmopen(lmid, new_so_name3, RTLD_NOW);
printf("error:%s\n", dlerror());
它给出了以下错误:
erroe:undefined symbol: b
似乎第二个库没有成功加载到命名空间中。但正如我所展示的,第二次加载成功并返回了一个非空的 handle2。 那么为什么会发生这种情况,我的加载过程有什么问题?我只希望所有加载的库都可以在该特定命名空间中共享符号,以避免在我的主程序中使用符号。
编辑:附录
正如@CharlieBurns 所建议的。我post下面的最小程序来说明我的问题。
#define _GNU_SOURCE
#include <stdio.h>
#include <link.h>
#include <dlfcn.h>
void* handle1;
void* handle2;
void* handle3;
Lmid_t lmid;
int main() {
// handle1 contains: int a(){return 0;}
handle1 = dlmopen(LM_ID_NEWLM, "/tmp/lib-o1i6Yd.so", RTLD_NOW);
dlinfo(handle1, RTLD_DI_LMID, &lmid);
// handle2 contains: int b(){return 1;}
handle2 = dlmopen(lmid, "/tmp/lib-vSyM4y.so", RTLD_NOW);
#ifdef RUN_A
int (*A)(void);
handle3 = dlmopen(lmid, "/tmp/lib-lAGjb2.so", RTLD_NOW);
A = (int(*)(void))dlsym(handle3, "__wrapper_lAGjb2");
/*
int __wrapper_lAGjb2() {
return a();
}
*/
printf("%d\n", (*A)()); // output 0 as expected
return 0;
#endif
#ifdef RUN_B
int (*B)(void);
handle3 = dlmopen(lmid, "/tmp/lib-CO1YAD.so", RTLD_NOW);
// error: /tmp/lib-CO1YAD.so: undefined symbol: b
printf("error: %s\n", dlerror());
B = (int(*)(void))dlsym(handle3, "__wrapper_CO1YAD");
// error: ./a.out: undefined symbol: __wrapper_CO1YAD
printf("error: %s\n", dlerror()); //
/*
int __wrapper_CO1YAD() {
return b();
}
*/
printf("%d\n", (*B)()); // segmentation fault (core dumped)
return 0;
#endif
}
这是test.c
文件。我使用 gcc test.c -ldl -DRUN_A/B
编译,然后 ./a.out
到 运行 它。
编辑:/tmp/.so
个文件
它们是手动创建的。例如,要使用 gcc 创建 /tmp/lib-o1i6Yd.so
文件:
在 /tmp/lib-o1i6Yd.c
:
int a(){return 0;}
编译为 .o
目标文件:
gcc -c -fpic /tmp/lib-o1i6Yd.c -o /tmp/lib-o1i6Yd.o
然后创建 .so
文件:
gcc -shared -o /tmp/lib-o1i6Yd.so /tmp/lib-o1i6Yd.o