Link


鏈接種類

  • 編譯時 靜態庫,整合到可執行文件中

  • 加載時 動態庫,在load時loader看到interp節,調用動態連接器

  • 運行時 由代碼決定加載那個,可以實現熱更新

GCC參數

  • -o outputfile
  • -O Optimize 優化
  • -fpic 位置無關
  • -shared 共享庫
  • -static 靜態鏈接,完全鏈接
  • -D ifdef的參數
  • -I include 路徑
  • -L 靜態庫路徑
  • -llib 靜態庫縮寫

鏈接工作

符號解析

代碼中引用的函數和變量

編譯的原則是每個源代碼文件形成一個目標文件,當需要跨文件或者跨文件夾訪問或調用時,即有多個文件,那么在編譯時,有些符號並沒有實際的地址,符號解析的作用就是讓每個符號綁定一個地址。

怎么做?

編譯成功的的目標文件是一個ELF格式,有頭部、節段、節頭部表組成。

其中.symtab 是符號表,模塊中所有出現的符號都會在里面。

.rel.text.rel.data 是重定位的信息,標記了.text.data 節段中鏈接后需要修改的部分的位置

.symtab 中的標志表示了這個符號是本地還是外部,是否需要解析。

三種符號

  • 全局符號,定義在本模塊中,所有的模塊都能看到,如全局變量,函數
  • 外部符號,定義在其他模塊中,本模塊引用,extern 定義的
  • 局部符號,帶有static屬性的全局變量和函數

鏈接的過程,為未定義的符號找到一個地址,可能多個模塊中有相同的符號,取哪一個取決於符號的強弱,是否定義了。連接器會把未解析的符號不斷地解析到定義的地方,在鏈接靜態庫時,其中引用的模塊必須排在定義的模塊前面

重定位(relocation)

重定位會把所有的模塊中相同的section聚合在一起,然后給每個section一個運行時的地址,然后根據重定位section中的記錄去修改二進制的內容。

typedef struct
{
    long offset;     /* Offset of the reference to relocate */
    long type : 32,  /* Relocation type */
        symbol : 32; /* Symbol table index */
    long addend;     /* Constant part of relocation expression */
} Elf64_Rela

位置無關代碼

gcc -shared -fpic -o a.so b.o c.o

專門為動態庫設計的,可以實現不管放在哪個地址都能正常的引用,動態庫在完成鏈接的時候,代碼並沒有進入可執行文件中,只是賦值了一些重定位和符號表的信息,包括動態庫的路徑信息。

動態庫在磁盤上只有一份,代碼段內存中也只有一份

位置無關代碼重定位時修改的是section前面的引用表GOTPLT 相當於抽象了一層,多了一次訪問,但是重定位時不需要修改代碼,只要改引用層就行。

打樁

打樁的目的就是在不改變源代碼的情況下,實現功能的轉移

  • 編譯時 通過宏替換標准庫的函數,這一步是在預處理時產生的,分離式編譯的模塊發生了改變

  • 鏈接時 通過gcc的參數,改變符號解析,來達到打樁的目的

    gcc -Wl,--wrap,malloc -Wl,--wrap,free a.o b.o
    

    會把對malloc的引用重定位到__wrap_malloc,把__real_malloc的引用重定位到malloc(這里就是標准庫)

  • 運行時 通過LD_PRELOAD 環境變量改變了動態庫的尋找路徑

    # bash 中
    LD_PRELOAD="./a.so" ./b.out
    

    能對malloc函數進行打樁是因為C語言的標准庫libc.so都是動態庫


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM