dlmopen()无法解析已创建名称空间中的已定义函数符号

问题描述 投票:1回答:1

我正在C中使用dlmopen将共享库加载到隔离的名称空间中。我的目标是使该命名空间中的符号全部属于已加载的库。因此他们无法访问我的主程序中的符号。流动是显示过程的主要功能的伪代码。

// 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

似乎第二个库未成功加载到名称空间中。但是正如我所展示的,第二次加载成功,并且返回了非null的handle2。那么为什么会发生这种情况,我的加载过程有什么问题呢?我只希望所有已加载的库都可以在该特定名称空间中共享符号,以避免在主程序中使用符号。

编辑:附录

如@CharlieBurns所建议。我在下面发布了最小的程序来显示我的问题。

#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 linux namespaces shared-libraries dlopen
1个回答
0
投票

Manaul并未明确指出名称空间问题(或者我不太清楚)使用dlmopen()新加载的共享库默认处于RTLD_LOCAL状态。也就是说,最新加载的函数无法调用函数或使用先前加载的变量。有关更多信息,请参见此post

© www.soinside.com 2019 - 2024. All rights reserved.