c++動態庫多層動態加載的問題

問題描述:
今有第三方庫曰xplico,將xplico.c中的main函數改寫成xplico_main然後修改makefile,將之由可執行程序改造成動態庫libxplico.so
然後編寫測試程序test.cpp(與libxplico.so放到同一路徑下),其內容如下:

//test.cpp
#include <iostream>
#include <thread>

extern "C"{
	int xplico_main(int, char *[]);
}

int main(int argc, char *argv[])
{
    std::thread t(xplico_main, argc, argv);
    t.join();
    return 0;
}

g++編譯之:# g++ test.cpp -o test -L. -lxplico -lpthread -Wl,-rpath=.
執行test:#./test -m -pcap -f /home/cyz/wahaha.pcap
上述操作能夠正常運行

然而
今有一可執行程序曰a.out,動態加載(dlopen)的方式調用一個庫liblib.so(c++動態庫),在lib中使用test.cpp程序中的std::thread兩句程序加載xplico。發現程序報錯,提示/opt/in-sec/taa/bin/a.out: symbol lookup error: /opt/in-sec/taa/bin/modules/dis_pcapf.so: undefined symbol: ProtName。打印信息提示a.out能夠調用xplico_main,但是當需要加載動態庫dis_pcapf.so時程序提示前述錯誤。
遂做如下檢查:
0. nm dis_pcapf.so | grep ProtName //提示ProtName未定義
1. ldd liblib.so //libxplico.so已鏈接
2. 查看運行時庫路徑是否正確
3. nm libxplico.so | grep ProtName //提示’0000000000012ed7 T ProtName’,表示已定義!
4. 查看xplico源碼中ProtName是否被static修飾
上述五步得出的結論是ProtName在dis_pcapf.so中未定義,定義發生在libxplico.so中,乃是全局共享函數。

於是在主程序a.out主程序中直接通過thread調用xplico_main. 此時發現能夠正常啓動,於是問題變得不可理喻,爲何主程序直接調用xplico_main可以,而通過中間庫liblib.so卻無能爲力?
那麼是不是liblib.so中鏈接的libxplico中的符號對主程序a.out是不可見的呢?遂做如下嘗試
將主程序編譯時鏈接上libxplico.so, 程序執行依然遇到同樣的問題,然後ldd a.out發現a.out未能鏈接上libxplicos.so. 原因是雖然我在a.out鏈接階段指定了鏈接libxplico.so,但是未真正使用libxplico.so庫中的函數,導致鏈接器智能的跳過了鏈接libxplico.so
於是在xplico.c中添加一個調試函數

void xplico_print()
{
	printf("測試\n");
}

a.out源文件中添加

extern "C"{
	void xplico_print();
}

重新編譯a.out, ldd查看之則libxplico.so被正常鏈接,然後執行a.out發現問題解決!
那麼問題來了,爲什麼會出現這種可執行程序直接加載沒有問題,而dlopen的庫中加載會導致這種符號未定義的錯誤呢?
查看源碼看到上述錯誤提示中dis_pcapf.so和liblib.so一樣,也是通過dlopen動態加載的,那麼,是不是dlopen加載的庫中間再次dlopen加載另一個庫會導致二次加載庫中的符號對主程序不可見呢?等有時間求證吧

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章