日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

rdynamic和

 cupid 2015-10-31

遇到如下情況,主程序通過dlopen來打開.so文件,但是.so用到了主程序的log函數(shù)。

編譯so時(shí),通過引用主程序頭文件來編譯通過,頭文件有l(wèi)og函數(shù)聲明:

  extern "C" { 
   void print()
  }

在主程序的.c文件里有函數(shù)的具體實(shí)現(xiàn)。


但是dlopen后運(yùn)行so中函數(shù)時(shí),出現(xiàn)找不到相應(yīng)的symbol。

這時(shí)候就需要在編譯主程序ld時(shí)加上參數(shù)-rdynamic,該參數(shù)的作用是:將指示連接器把所有符號(而不僅僅只是程序已使用到的外部符號,但不包括靜態(tài)符號,比如被static修飾的函數(shù))都添加到動態(tài)符號表(即.dynsym表)里,以便那些通過dlopen()或backtrace()(這一系列函數(shù)使用.dynsym表內(nèi)符號)這樣的函數(shù)使用。


-rdynamic
Pass the flag ‘-export-dynamic’ to the ELF linker, on targets that support
it. This instructs the linker to add all symbols, not only used ones, to the
dynamic symbol table. This option is needed for some uses of dlopen or to
allow obtaining backtraces from within a program.


-g是編譯選項(xiàng),而-rdynamic是鏈接選項(xiàng)

參考:http://www./archives/2013/01/2190


小例子:


a.cc

  1. #include "stdio.h"  
  2. #include <dlfcn.h>  
  3.   
  4. extern "C" {  
  5. void print()  
  6. {  
  7.     printf("I am in so file!\n");  
  8. }  
  9.   
  10. void fun()  
  11. {  
  12.     void * err = dlopen("./libtmp.so", RTLD_LAZY);  
  13.     printf("dlopen = %p\n", err);  
  14.     if (err == NULL) {  
  15.         printf("err=%s\n", dlerror());  
  16.     }     
  17. }  
  18. }  

a.h

  1. extern "C" void print();  
  2. extern "C" void fun();  // 函數(shù)聲明和定義都要有extern “C”,或者都沒有,否則調(diào)用時(shí)出現(xiàn)undefined symbol fun  
  3.   
  4. #define NODE_MODULE \  
  5. extern "C" { \  
  6.    static void print_main() __attribute__((constructor)) // dlopen時(shí)會自動調(diào)用該contructor函數(shù)</span>  
  7.    static void print_main() { \  
  8.        print(); \  
  9.    } \  
  10. }   


so.cc

  1. #include "a.h"  
  2. #include "stdio.h"  
  3.   
  4. NODE_MODULE  


foo.h

  1. <span style="font-size:18px;">void foo();</span>  

foo.cc

  1. #include "stdio.h"  
  2.   
  3. void foo()  
  4. {  
  5.     printf("foo === \n");  
  6. }  


main.cc
  1. #include "a.h"  
  2.   
  3. int main(void)  
  4. {  
  5.     fun();  
  6.     return 0;  
  7. }  

Makefile

  1. all:dynamic  
  2.   
  3. libtmp.so:so.cc  
  4.     g++ -fPIC -shared -o $@ $^   
  5.   
  6. a.o:  
  7.     g++ -c a.cc -fPIC  
  8.   
  9. liba.a:a.o  
  10.     ar -r $@  $^   
  11.   
  12. libso.so: foo.cc liba.a  
  13.     g++ -fPIC -shared -o $@ $< -L./ -la -Wl,--whole-archive -la  -Wl,--no-whole-archive -ldl  
  14.   
  15. dynamic:libso.so libtmp.so  
  16.     g++ -o $@ main.cc -Wl,--rpath=. -L./ -lso rdynamic  
  17.   
  18. clean:  
  19.     rm dynamic liba.a a.o libtmp.so  


運(yùn)行dynamic后輸出為:

  1. I am in so file!  
  2. dlopen = 0xdeb030  
如果沒有-rdynamic,則輸出為:

  1. dlopen = (nil)  
  2. err=./libtmp.so: undefined symbol: print  
如果沒有-Wl,--whole-archive -la  -Wl,--no-whole-archive,也會有錯(cuò)誤:undefined symbol: print


--whole-archive 可以把 在其后面出現(xiàn)的靜態(tài)庫包含的函數(shù)和變量輸出到動態(tài)庫,--no-whole-archive 則關(guān)掉這個(gè)特性

使用readelf -s libso.so | grep fun來查看libso.so的符號表里是否有fun這個(gè)函數(shù)暴露出來。有--whole-archive的可以查到fun,而沒有--whole-archive的,則找不到fun


先理清一下code

可執(zhí)行文件dynamic依賴與libso.so,而libso.so有包含liba.a,在liba.a的函數(shù)fun調(diào)用dlopen來打開libtmp.so

主函數(shù)調(diào)用liba.a的函數(shù)來打開libtmp.so


-fvisibility=hidden

  設(shè)置默認(rèn)的ELF鏡像中符號的可見性為隱藏。使用這個(gè)特性可以非常充分的提高連接和加載共享庫的性能,生成更加優(yōu)化的代碼,提供近乎完美的API輸出和防止符號碰撞。我們強(qiáng)烈建議你在編譯任何共享庫的時(shí)候使用該選項(xiàng)。

-fvisibility-inlines-hidden

        默認(rèn)隱藏所有內(nèi)聯(lián)函數(shù),從而減小導(dǎo)出符號表的大小,既能縮減文件的大小,還能提高運(yùn)行性能,我們強(qiáng)烈建議你在編譯任何共享庫的時(shí)候使用該選項(xiàng)


所以編譯的時(shí)候也不能有-fvisibility=hidden和-fvisibility-inlines-hidden。如果有,也會在dlopen時(shí)造成錯(cuò)誤:undefined symbol

總結(jié):

本實(shí)例雖小,但用到了不少編譯選項(xiàng)

a: __attribute__((constructor))
主程序main函數(shù)之前被執(zhí)行或dlopen時(shí)被執(zhí)行

b: -rdynamic

ld時(shí)將動態(tài)庫的的所有符號都輸出到符號表,以便dlopen和backtrace也能調(diào)用

c: --whole-archive -la -Wl,--no-whole-archive

靜態(tài)庫的符號導(dǎo)入到動態(tài)庫的符號表中,默認(rèn)是hidden的

d: -fvisibility=hidden和-fvisibility-inlines-hidden

ELF鏡像中符號的可見性為隱藏(在實(shí)驗(yàn)過程中不太好用,待研究)


在編譯nodejs第三方模塊時(shí)都會碰到這樣的問題,第三方模塊依賴與nodejs進(jìn)行編譯,而第三方模塊又是通過dlopen來打開的,這就要求nodejs編譯時(shí)將一下第三方模塊需要的函數(shù)都暴露出來。


參考:

http://www./qa-225-106759.aspx

http://os./a2010/0112/1060/000001060902_3.shtml



版權(quán)聲明:本文為博主原創(chuàng)文章

    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多