Linux

當共享庫依賴於其他共享庫時,為什麼動態連結器無法解析引用?

  • December 27, 2020

程式碼:

//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並且 modulebfunction_b. 假設我們已經創建了共享庫a.sob.so所以這些共享庫在程序執行之前就存在於磁碟上,但是當我執行程序時,它會拋出一個符號查找錯誤:

./a.so:undefined symbol: function_b

handle_a = dlopen("./a.so", RTLD_LAZY); 但是對於我在這裡使用的這行程式碼RTLD_LAZY,執行時連結器不會嘗試解析 symbol function_b,並且我有機會在呼叫dlopen("b.so", RTLD_GLOBAL)之前先呼叫function_a. 這樣,動態連結器將使用b.so中a.so的定義修改 in 的引用。function_b

我的問題是:

  • 我的理解是否正確,動態連結器應該修改.gotor.got.plt部分,a.so以便它可以連結/重定位.textb.so.
  • 如果我的理解是正確的,那麼為什麼動態連結器function_b在這種情況下仍然無法解析?

問題不在於動態連結器無法解析function_b,而是您的第二次呼叫dlopen不正確:需要包含RTLD_LAZYorRTLD_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,這揭示了問題。

引用自:https://unix.stackexchange.com/questions/607652