兄弟.so文件中符号的可见性

时间:2013-08-02 23:40:03

标签: c linux shared-libraries elf dlopen

我正在尝试将这个OSX代码(golfed以便于讨论)在Ubuntu Linux上运行。

cat >main.c <<EOF
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
void provided_by_main() { puts("Hello main!"); }
int main() {
  void *provider_so, *needer_so;
  (provider_so = dlopen("provider.so", RTLD_NOW)) || printf("Fail %s\n", dlerror()) && (exit(0),0);
  (needer_so = dlopen("needer.so", RTLD_NOW)) || printf("Fail %s\n", dlerror()) && (exit(0),0);
  void (*needer)() = dlsym(needer_so, "needer");
  needer();
}
EOF

cat >needer.c <<EOF
extern void provider();
void needer() { provider(); }
EOF

cat >provider.c <<EOF
#include <stdio.h>
void provider() { puts("Hello provider!"); }
EOF

gcc -shared -o provider.so provider.c
gcc -shared -o needer.so needer.c -dynamic -undefined dynamic_lookup
gcc -o main main.c -ldl
./main
Hello provider!

在Linux上,通过反复试验和StackOverflow,我确定needer无法引用main中定义的任何内容,除非main已与-rdynamic相关联:

gcc -shared -fpic -o provider.so provider.c
gcc -shared -fpic -o needer.so needer.c -Dprovider=provided_by_main
gcc -o main main.c -ldl -rdynamic
./main
Hello main!

但是,即使整个“链”使用needer进行编译,我也无法让provider看到-rdynamic提供的任何内容:

gcc -shared -fpic -o provider.so provider.c -rdynamic
gcc -shared -fpic -o needer.so needer.c
gcc -o main main.c -ldl -rdynamic
./main
Fail needer.so: undefined symbol: provider

那么,我该如何做到这一点?

或者,如果Linux在设计上不可能,那么为什么它被设计为不可能?

(OSX等效:Accessing main program global variables from a dlopen()ed dynamic library in C on OS X

真实的奖金复杂化:在我的实际程序中,provider.so是在运行时代码生成的,provider符号的名称直到之后才确定main已被关联。但是,即使是涉及修改main.c的答案也是朝着正确方向迈出的一步。

2 个答案:

答案 0 :(得分:1)

这在OS X上运行并且在Linux上失败的原因是RTLD_GLOBAL是前者的dlopen默认符号可见性,而后者默认为RTLD_LOCAL。使用(小心):

dlopen("provider.so", RTLD_NOW | RTLD_GLOBAL);
另一方面,

-rdynamic仅适用于可执行文件中定义的缺失库符号,但不适用于其他任何地方。


sed -i 's/RTLD_NOW/RTLD_NOW|RTLD_GLOBAL/' main.c
gcc -shared -fpic -o provider.so provider.c
gcc -shared -fpic -o needer.so needer.c
gcc -o main main.c -ldl
./main
Hello provider!

答案 1 :(得分:-1)

dlopen调用在运行时失败,因此无法找到或打开provider.so。这来自OS X上的man dlopen,可能有所帮助:

  

dlopen()在目录中搜索兼容的Mach-O文件   由一组环境变量和进程的当前指定   工作目录。设置时,环境变量必须包含   以冒号分隔的目录路径列表,可以是绝对路径或   相对于当前工作目录。环境变量   是LD_LIBRARY_PATH,DYLD_LIBRARY_PATH和   DYLD_FALLBACK_LIBRARY_PATH。前两个变量没有默认值   值。 DYLD_FALLBACK_LIBRARY_PATH的默认值是   $ HOME / lib目录;在/ usr / local / lib目录,/ usr / lib目录。 dlopen()搜索目录   按照列出的顺序在环境变量中指定。