使用dlopen编译C程序,使用-fPIC编译dlsym

use*_*486 5 c linux gcc elf dlopen

我遇到了错误的符号解析问题.我的主程序用dlopen加载一个带dlopen的共享库和一个符号.程序和库都是用C语言库代码编写的

int a(int b)
{
  return b+1;
}

int c(int d)
{
  return a(d)+1;
}
Run Code Online (Sandbox Code Playgroud)

为了使它在64位机器上运行,-fPIC在编译时传递给gcc.

该计划是:

#include <dlfcn.h>
#include <stdio.h>

int (*a)(int b);
int (*c)(int d);

int main()
{
  void* lib=dlopen("./libtest.so",RTLD_LAZY);
  a=dlsym(lib,"a");
  c=dlsym(lib,"c");
  int d = c(6);
  int b = a(5);
  printf("b is %d d is %d\n",b,d);
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

如果程序未使用-fPIC编译,则一切运行正常,但在使用-fPIC编译程序时,它会因分段错误而崩溃.调查导致发现崩溃是由于符号a的错误解决.无论是从库还是主程序(后者是通过在主程序中注释掉调用c()的行获得的),都会在调用a时发生崩溃.

调用c()本身时没有问题,可能是因为c()不是由库本身在内部调用,而a()既是库内部使用的函数,也是库的API函数.

编译程序时,一个简单的解决方法是不使用-fPIC.但这并不总是可行的,例如当主程序的代码必须在共享库本身时.另一种解决方法是将指针重命名为其他功能.但我找不到任何真正的解决方案.

用RTLD_NOW替换RTLD_LAZY没有帮助.

zvr*_*rba 4

怀疑两个全球符号之间存在冲突。a一种解决方案是在主程序中声明为静态。或者,linux 手册页提到了RTLD_DEEPBINDflag,这是一个仅适用于 linux 的扩展,您可以传递给它dlopen,这将导致库更喜欢自己的符号而不是全局符号。

  • 两种方法都有效。关键字 static 并不是那么通用,因为它限制了对同一编译单元的可见性,但是如果需要函数指针不是静态的,则可以使用 __attribute__ ((visibility ("hidden")))。 (2认同)