自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

原來編譯鏈接還有這么多套路

開發(fā) 前端
不知道大家平時(shí)編程過程中使用動(dòng)態(tài)鏈接庫(kù)的情況多不多,如果一個(gè)程序引用了無數(shù)個(gè)動(dòng)態(tài)鏈接庫(kù),那就有可能引入符號(hào)沖突的問題。

[[375749]]

本文轉(zhuǎn)載自微信公眾號(hào)「程序喵大人」,作者程序喵大人 。轉(zhuǎn)載本文請(qǐng)聯(lián)系程序喵大人公眾號(hào)。

大家好,我是程序喵。

不知道大家平時(shí)編程過程中使用動(dòng)態(tài)鏈接庫(kù)的情況多不多,如果一個(gè)程序引用了無數(shù)個(gè)動(dòng)態(tài)鏈接庫(kù),那就有可能引入符號(hào)沖突的問題,問題如下:

想象中

實(shí)際上

下面我們嘗試解決它:

最開始介紹下g++基本命令參數(shù):

  1. g++ 
  2. -c <file> 編譯源文件,但是不進(jìn)行鏈接 
  3. -o <file> 指定輸出文件的名字 
  4. -s        strip,移除符號(hào)信息 
  5. -L <dir>  指令搜索鏈接庫(kù)的路徑 
  6. -l <lib>  指定要鏈接的鏈接庫(kù) 
  7. -shared   產(chǎn)生動(dòng)態(tài)目標(biāo)文件 

先來看一段代碼:

  1. #include <stdio.h> 
  2.  
  3. void DoThing() { printf("work \n"); } 

再定義一個(gè)簡(jiǎn)單的main.cc程序:

  1. #include <stdio.h> 
  2.  
  3. void DoThing(); 
  4.  
  5. int main() { 
  6.     printf("start \n"); 
  7.     DoThing(); 
  8.     printf("finished \n"); 
  9.     return 0; 

編譯這兩個(gè)文件,并分別打包成靜態(tài)庫(kù):

  1. g++ -c work.cc -o work.o 
  2. ar rc libwork.a work.o 
  3. g++ -c main.cc -o main.o 
  4. ar rc libmain.a main.o 

現(xiàn)在將這兩個(gè)靜態(tài)庫(kù)鏈接成一個(gè)可執(zhí)行文件,注意鏈接器如果發(fā)現(xiàn)當(dāng)前庫(kù)中使用了沒有被定義的符號(hào),它只會(huì)向后查找,因此,最低級(jí)別沒有其它依賴的庫(kù)應(yīng)該放在最右邊,如果出現(xiàn)了符號(hào)沖突問題,鏈接器會(huì)使用最左邊的符號(hào)。

如果這樣進(jìn)行鏈接:

  1. $ g++ -s -L. -o main.exe -lwork -lmain 
  2. ./libmain.a(main.o): In function `main': 
  3. main.cc:(.text+0x11): undefined reference to `DoThing()' 
  4. collect2: error: ld returned 1 exit status 

鏈接失敗,因?yàn)閙ain庫(kù)里的DoThing符號(hào)沒有被定義,鏈接器向后查找,沒有找到對(duì)應(yīng)的符號(hào)定義,這里更改下鏈接庫(kù)的順序:

  1. g++ -s -L. -o main.exe -lmain -lwork 
  2. $ ./main.exe 
  3. start 
  4. work 
  5. finished 

鏈接成功。

現(xiàn)在寫一個(gè)簡(jiǎn)單的容易產(chǎn)生符號(hào)沖突的文件conflict.cc:

  1. #include <stdio.h> 
  2.  
  3. void DoThing() { printf("conflict \n"); } 

編譯并打包成靜態(tài)庫(kù):

  1. g++ -c conflict.cc -o conflict.o 
  2. ar rc libconflict.a conflict.o 

如果按這樣的順序鏈接成一個(gè)可執(zhí)行程序:

  1. $ g++ -s -L. -o main.exe -lmain -lwork -lconflict 
  2. $ ./main.exe 
  3. start 
  4. work 
  5. finished 

如果稍微更改一下鏈接的順序:

  1. $ g++ -s -L. -o main.exe -lmain -lconflict -lwork 
  2. $ ./main.exe 
  3. start 
  4. conflict 
  5. finished 

這里發(fā)現(xiàn)順序的不同導(dǎo)致了程序輸出內(nèi)容不同,究其原因就是那潛在的符號(hào)沖突。

現(xiàn)在再試試動(dòng)態(tài)庫(kù),先介紹如何使用動(dòng)態(tài)庫(kù):

  1. $ rm libconflict.a 
  2. $ g++ -shared conflict.o -o libconflict.so 
  3. $ g++ -s -L. -o main.exe -lmain -lconflict 
  4. $ LD_LIBRARY_PATH=. ./main.exe 
  5. start 
  6. conflict 
  7. finished 

現(xiàn)在再引用一個(gè)中間層在動(dòng)態(tài)鏈接庫(kù)中調(diào)用conflict的文件layer.cc

  1. #include <stdio.h> 
  2. void DoThing(); 
  3. void DoLayer() { 
  4.     printf("layer \n"); 
  5.     DoThing(); 

并把layer和conflict打包成一個(gè)動(dòng)態(tài)鏈接庫(kù):

  1. $ g++ -c layer.cc -o layer.o 
  2. $ g++ -shared layer.o conflict.o -o libconflict.so 

然后更新main.c程序,main里面調(diào)用layer,layer里調(diào)用conflict:

  1. #include <stdio.h> 
  2. void DoLayer(); 
  3. int main() { 
  4.     printf("start \n"); 
  5.     DoLayer(); 
  6.     printf("finished \n"); 
  7.     return 0; 

編譯鏈接執(zhí)行:

  1. $ g++ -c main.cc -o main.o 
  2. $ ar rc libmain.a main.o 
  3. $ g++ -s -L. -o main.exe -lmain -lconflict 
  4. $ LD_LIBRARY_PATH=. ./main.exe 
  5. start 
  6. layer 
  7. conflict 
  8. finished 

正常輸出,沒啥問題,現(xiàn)在再把之前的work.cc也塞到main.cc中,觀察下沖突:

  1. #include <stdio.h> 
  2. void DoThing(); 
  3. void DoLayer(); 
  4. int main() { 
  5.     printf("start \n"); 
  6.     DoThing(); 
  7.     DoLayer(); 
  8.     printf("finished \n"); 
  9.     return 0; 

把work.o和main.o打包成一個(gè)庫(kù),之后和conflict鏈接成一個(gè)可執(zhí)行程序,運(yùn)行:

  1. $ g++ -c main.cc -o main.o 
  2. $ ar rc libmain.a main.o work.o 
  3. $ g++ -s -L. -o main.exe -lmain -lconflict 
  4. $ LD_LIBRARY_PATH=. ./main.exe 
  5. start 
  6. work 
  7. layer 
  8. work 
  9. finished 

這里輸出了兩個(gè)work,正常情況下第二個(gè)work應(yīng)該輸出conflict,怎么解決呢?可以考慮使用-fvisibility=hidden來隱藏內(nèi)部的符號(hào),鏈接庫(kù)內(nèi)部使用的符號(hào)把它隱藏掉,不讓它被導(dǎo)出,外部也不會(huì)改變它的調(diào)用路徑。

先使用nm看一下libconflict.so里面的符號(hào):

  1. $ nm -CD libconflict.so 
  2.                  w _ITM_deregisterTMCloneTable 
  3.                  w _ITM_registerTMCloneTable 
  4. 000000000000065a T DoLayer() 
  5. 0000000000000672 T DoThing() 
  6. 0000000000201030 B __bss_start 
  7.                  w __cxa_finalize 
  8.                  w __gmon_start__ 
  9. 0000000000201030 D _edata 
  10. 0000000000201038 B _end 
  11. 0000000000000688 T _fini 
  12. 0000000000000528 T _init 
  13.                  U puts 

如果把符號(hào)隱藏掉,

  1. $ g++ -fvisibility=hidden -c layer.cc -o layer.o 
  2. $ g++ -fvisibility=hidden -c conflict.cc -o conflict.o 
  3. $ g++ -shared layer.o conflict.o -o libconflict.so 
  4. 再使用nm看一下libconflict.so里面的符號(hào): 
  5. $ nm -CD libconflict.so 
  6.                  w _ITM_deregisterTMCloneTable 
  7.                  w _ITM_registerTMCloneTable 
  8. 0000000000201028 B __bss_start 
  9.                  w __cxa_finalize 
  10.                  w __gmon_start__ 
  11. 0000000000201028 D _edata 
  12. 0000000000201030 B _end 
  13. 0000000000000618 T _fini 
  14. 00000000000004c0 T _init 
  15.                  U puts 

這樣的話main函數(shù)肯定不能調(diào)用DoLayer啦,因?yàn)镈oLayer符號(hào)沒有暴露出來:

  1. $ g++ -s -L. -o main.exe -lmain -lconflict 
  2. ./libmain.a(main.o): In function `main': 
  3. main.cc:(.text+0x16): undefined reference to `DoLayer()' 
  4. collect2: error: ld returned 1 exit statu 

那怎么暴露出來特定符號(hào)呢,直接看代碼,改動(dòng)了layer.cc:

  1. #include <stdio.h> 
  2. void DoThing(); 
  3. __attribute__ ((visibility ("default"))) void DoLayer() { 
  4.     printf("layer \n"); 
  5.     DoThing(); 

再編譯鏈接運(yùn)行看看結(jié)果:

  1. $ g++ -fvisibility=hidden -c layer.cxx -o layer.o 
  2. $ g++ -shared layer.o conflict.o -o libconflict.so 
  3. $ g++ -s -L. -o main.exe -lmain -lconflict 
  4. $ LD_LIBRARY_PATH=. ./main.exe 
  5. start 
  6. work 
  7. layer 
  8. conflict 
  9. finished 

發(fā)現(xiàn)已經(jīng)是我們期待的結(jié)果啦,符號(hào)沖突的問題因此被解決。

是不是感覺很麻煩,難道每個(gè)要暴露的符號(hào)都要加上__attribute__這種修飾嗎,這里其實(shí)可以寫一個(gè)export文件,告訴編譯器要導(dǎo)出的所有符號(hào)有哪些。

  1. export.txt 
  2.  
  3.  global: *DoLayer*; 
  4.  local: *; 
  5. }; 
  6. g++ -Wl,--version-script=export.txt -s -shared layer.o conflict.o -o libconflict.so 

但是這種方式只有在gcc中才可以被使用,我在clang中嘗試使用但是失敗啦,所以為了兼容性不建議使用這種方式,還是消停的使用__attribute__來解決符號(hào)沖突問題吧。

 

責(zé)任編輯:武曉燕 來源: 程序喵大人
相關(guān)推薦

2017-07-04 14:01:40

機(jī)房機(jī)柜

2018-06-26 15:00:24

Docker安全風(fēng)險(xiǎn)

2024-01-31 12:34:16

panic錯(cuò)誤檢測(cè)recover

2018-01-31 16:12:47

筆記本輕薄本游戲本

2024-05-13 16:22:25

固態(tài)硬盤接口硬盤

2017-07-12 08:20:32

閃存用途企業(yè)

2024-02-20 08:09:51

Java 8DateUtilsDate工具類

2023-11-13 08:49:54

2017-06-16 16:16:36

庫(kù)存扣減查詢

2018-12-05 15:39:24

2018-05-29 14:57:59

HashMap容量初始化

2021-05-03 23:41:42

微信功能知識(shí)

2023-07-26 00:32:33

注解抽象spring

2024-03-11 10:15:29

2022-01-12 20:04:09

網(wǎng)絡(luò)故障斷網(wǎng)事件網(wǎng)絡(luò)安全

2022-05-29 08:54:44

Edge瀏覽器

2024-01-02 12:48:49

2017-12-21 19:38:50

潤(rùn)乾中間表

2022-07-26 23:43:29

編程語(yǔ)言開發(fā)Java

2021-05-31 22:26:20

5G技術(shù)通信
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)