我正在尝试将这个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
的答案也是朝着正确方向迈出的一步。
答案 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()搜索目录 按照列出的顺序在环境变量中指定。