【问题标题】:Visibility of symbols among sibling .so files同级 .so 文件中符号的可见性
【发布时间】:2013-08-02 23:40:02
【问题描述】:

我正在尝试让这个 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!

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

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 的答案也是朝着正确方向迈出的一步。

【问题讨论】:

    标签: c linux shared-libraries elf dlopen


    【解决方案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!
    

    【讨论】:

    • 谢谢! :D(我已经编辑了您的评论以包含可剪切和粘贴的代码。)
    【解决方案2】:

    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() 搜索目录 按列出的顺序在环境变量中指定。

    【讨论】:

    • 对不起,这个答案是错误的。考虑将其删除,以免将来的访问者感到不必要的困惑。
    猜你喜欢
    • 1970-01-01
    • 2012-09-24
    • 1970-01-01
    • 2020-06-14
    • 2010-09-07
    • 2014-02-07
    • 1970-01-01
    • 2011-06-27
    • 2014-01-31
    相关资源
    最近更新 更多