小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

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ù)的作用是:將指示連接器把所有符號(hào)(而不僅僅只是程序已使用到的外部符號(hào),但不包括靜態(tài)符號(hào),比如被static修飾的函數(shù))都添加到動(dòng)態(tài)符號(hào)表(即.dynsym表)里,以便那些通過dlopen()或backtrace()(這一系列函數(shù)使用.dynsym表內(nèi)符號(hào))這樣的函數(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í)會(huì)自動(dòng)調(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,也會(huì)有錯(cuò)誤:undefined symbol: print


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

使用readelf -s libso.so | grep fun來查看libso.so的符號(hào)表里是否有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鏡像中符號(hào)的可見性為隱藏。使用這個(gè)特性可以非常充分的提高連接和加載共享庫的性能,生成更加優(yōu)化的代碼,提供近乎完美的API輸出和防止符號(hào)碰撞。我們強(qiáng)烈建議你在編譯任何共享庫的時(shí)候使用該選項(xiàng)。

-fvisibility-inlines-hidden

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


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

總結(jié):

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

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

b: -rdynamic

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

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

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

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

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


在編譯nodejs第三方模塊時(shí)都會(huì)碰到這樣的問題,第三方模塊依賴與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è)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多