Linux
當共享庫依賴於其他共享庫時,為什麼動態連結器無法解析引用?
程式碼:
//a.c I don't use header files as this is just for demo purpose. extern void function_b(int num); void function_a(int num) { function_b(num) }
//b.c void function_b(int num) { ... }
//dll.c #include <dlfcn.h> int main() { void *handle_a; void *handle_b; void (*pfunc_a)(int); ... handle_a = dlopen("./a.so", RTLD_LAZY); ... pfunc_a = dlsym(handle_a, "function_a"); ... handle_b = dlopen("./b.so", RTLD_GLOBAL); ... pfunc_a(2020); ... return 0; }
我們可以看到
dll.c
嘗試在執行時載入共享庫,並且 modulea
有一個引用 onfunction_b
並且 moduleb
有function_b
. 假設我們已經創建了共享庫a.so
,b.so
所以這些共享庫在程序執行之前就存在於磁碟上,但是當我執行程序時,它會拋出一個符號查找錯誤:./a.so:undefined symbol: function_b
handle_a = dlopen("./a.so", RTLD_LAZY);
但是對於我在這裡使用的這行程式碼RTLD_LAZY
,執行時連結器不會嘗試解析 symbolfunction_b
,並且我有機會在呼叫dlopen("b.so", RTLD_GLOBAL)
之前先呼叫function_a
. 這樣,動態連結器將使用b.so中a.so
的定義修改 in 的引用。function_b
我的問題是:
- 我的理解是否正確,動態連結器應該修改
.got
or.got.plt
部分,a.so
以便它可以連結/重定位.text
到b.so
.- 如果我的理解是正確的,那麼為什麼動態連結器
function_b
在這種情況下仍然無法解析?
問題不在於動態連結器無法解析
function_b
,而是您的第二次呼叫dlopen
不正確:您需要包含RTLD_LAZY
orRTLD_NOW
,其他標誌與這兩個標誌互補。flags中必須包含以下兩個值之一:
b.so
將負載更改為handle_b = dlopen("./b.so", RTLD_NOW | RTLD_GLOBAL);
產生一個工作程序。
每次呼叫都
dlopen
必須在 和 之間RTLD_LAZY
進行選擇RTLD_NOW
;因為b.so
是最後一個載入的庫,我NOW
在上面指定(我們沒有通過延遲載入獲得任何東西),但LAZY
在這種情況下也能正常工作。最重要的是,可以添加其他標誌;在這裡我們需要RTLD_GLOBAL
,因為我們需要b.so
’s 符號在全球範圍內可用,以便在它執行時function_a
可以找到。function_b
有關您需要進行的錯誤處理等的詳細資訊,請參閱中的範例
dlopen(3)
dlopen
,這揭示了問題。