2013-08-02 130 views
0

我试图使这个OSX代码(golfed为便于讨论)在Ubuntu Linux上工作。兄弟之间的.so文件中的符号的可见性

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到即使整个“链”编译为-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 
0见 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的答案也是朝正确方向迈出的一步。

回答

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! 
+0

谢谢! :D(我已编辑您的评论以包含剪切和粘贴的代码。) – Quuxplusone

-1

dlopen调用失败在运行时,所以它不能找到或打开provider.so。这是man dlopen在OS X和可能帮助:

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

+0

对不起,这个答案是错的。考虑删除它,以便未来的访问者不会不必要地困惑。 – Quuxplusone