当共享库依赖于其他共享库时,为什么动态链接器无法解析引用?

当共享库依赖于其他共享库时,为什么动态链接器无法解析引用?

代码:

//a.c   I don't use header files as this is just for demo purpose.
extern void function_b(int num);
void function_a(int num) {
   function_b(num)
}
//b.c
void function_b(int num) {
   ...
}
//dll.c 
#include <dlfcn.h>
int main() {
   void *handle_a;
   void *handle_b;
   void (*pfunc_a)(int);
   ...
   handle_a = dlopen("./a.so", RTLD_LAZY);
   ...
   pfunc_a = dlsym(handle_a, "function_a");
   ...
   handle_b = dlopen("./b.so", RTLD_GLOBAL);
   ...
   pfunc_a(2020);
   ...
   return 0;
}

我们可以看到,dll.c尝试在运行时加载共享库,并且 modulea有 的引用function_b,并且 moduleb有 的定义function_b。假设我们已经创建了共享库a.sob.so因此这些共享库在程序运行之前就存在于磁盘上,但是当我运行程序时,它会抛出符号查找错误:

./a.so:undefined symbol: function_b

handle_a = dlopen("./a.so", RTLD_LAZY); 但是对于我在这里使用的这行代码RTLD_LAZY,运行时链接器不会尝试解析符号function_b,并且我有机会dlopen("b.so", RTLD_GLOBAL)在调用之前调用function_a。这样,动态链接器将使用b.so 中a.so的定义修改引用。function_b

我的问题是:

  • 我的理解是否正确,动态链接器应该修改.gotor.got.plt部分,a.so以便它可以链接/重定位到.text部分中 function_b 的指令地址b.so

  • function_b如果我的理解是正确的,那么为什么动态链接器在这种情况下仍然无法解析?

答案1

问题不是动态链接器无法解析function_b,而是您的第二次调用dlopen不正确:需要包括RTLD_LAZYRTLD_NOW,其他标志与这两个标志是互补的。

必须包含以下两个值之一旗帜:

b.so将您的负载更改为

handle_b = dlopen("./b.so", RTLD_NOW | RTLD_GLOBAL);

产生一个工作程序。

每次调用都dlopen必须在RTLD_LAZY和之间进行选择RTLD_NOW;因为b.so是最后一个加载的库,我NOW在上面指定了(我们不会通过延迟加载获得任何东西),但LAZY在这种情况下效果同样好。除此之外,还可以添加其他标志;这里我们需要,RTLD_GLOBAL因为我们需要b.so全局可用的符号,以便在它运行时function_a可以找到。function_b

中的例子dlopen(3)有关您需要执行的错误处理的详细信息dlopen等,这揭示了问题。

相关内容