0

我试图让这个 OSX 代码(为了便于讨论而打高尔夫球)在 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 等价物:从 OS X 上的 C 中的 dlopen()ed 动态库访问主程序全局变量

现实世界的额外复杂性:在我的实际程序中,provider.so是在运行时生成的代码,并且在链接provider之后才确定符号的名称。main但是,即使是涉及修改的答案也main.c将是朝着正确方向迈出的一步。

4

2 回答 2

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!
于 2013-08-03T00:52:48.483 回答
-1

调用在dlopen运行时失败,因此无法找到或打开provider.so。这是来自man dlopenOS 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() 按列出的顺序搜索环境变量中指定的目录。

于 2013-08-03T00:24:33.457 回答