2013-08-02 97 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