首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

深入理解 Linux 動態鏈接:PLT 與 GOT 表機制詳解

     編輯:關於C語言

前言

近期在學習 Linux 高級調試技術時,針對動態庫鏈接機制進行了一系列實驗。本文將詳細記錄 PLT(Procedure Linkage Table,過程鏈接表)與 GOT(Global Offset Table,全局偏移表)的交互過程,並通過 GDB 反匯編分析動態鏈接的延遲綁定特性。

基礎概念

  • PLT:存放函數入口地址,用於引導動態鏈接器解析符號。
  • GOT:存放外部符號的實際運行時地址,首次調用前指向 PLT 中的解析代碼,解析後更新為真實函數地址。

實驗環境與代碼

測試程式碼簡單調用 puts 函數:

#include <stdio.h>

int fun() {
    printf("hello world\n");
}

int main() {
    while(1) {
        fun();
    }
    return 1;
}

在 fun 函數入口設置斷點,啟動 GDB 進行動態分析。

反匯編分析:首次調用流程

1. fun 函數調用點

(gdb) disassemble fun
Dump of assembler code for function fun:
0x080483d4 <+0>: push %ebp
0x080483d5 <+1>: mov %esp,%ebp
0x080483d7 <+3>: sub $0x18,%esp
0x080483da <+6>: movl $0x80484d0,(%esp)
0x080483e1 <+13>: call 0x80482f0 <puts@plt>
0x080483e6 <+18>: leave
0x080483e7 <+19>: ret
End of assembler dump.

偏移量 +13 處的 call 0x80482f0 即為對 puts@plt 的調用。

2. PLT 存根代碼

(gdb) disassemble 0x80482f0
Dump of assembler code for function puts@plt:
0x080482f0 <+0>: jmp *0x804a000
0x080482f6 <+6>: push $0x0
0x080482fb <+11>: jmp 0x80482e0
End of assembler dump.

PLT 條目包含三條指令:

  1. 間接跳轉到 GOT 項 0x804a000(即 puts@got.plt)
  2. 壓入重定位索引(此處為 0)
  3. 跳轉到 PLT0(0x80482e0),進入動態鏈接器解析流程

3. GOT 初始狀態

(gdb) x/x 0x804a000
0x804a000 <puts@got.plt>: 0x080482f6

初始時 GOT 項指向 PLT 條目中的下一條指令(push $0x0),而非真實函數地址。

4. PLT0 解析入口

(gdb) x/10i 0x80482e0
0x80482e0: pushl 0x8049ff8
=> 0x80482e6: jmp *0x8049ffc

查看 0x8049ffc(_GLOBAL_OFFSET_TABLE_+8):

(gdb) x/x 0x8049ffc
0x8049ffc <_GLOBAL_OFFSET_TABLE_+8>: 0xb7ff2690

該地址指向動態鏈接器 ld-linux.so.2 內部的 _dl_runtime_resolve 函數,負責符號解析與重定位。

5. 解析後的 GOT 更新

首次調用結束後,再次檢視 GOT 項:

(gdb) x/x 0x804a000
0x804a000 <puts@got.plt>: 0xb7e866a0

地址已更新為 puts 在 libc 中的真實實現地址。後續調用將直接跳轉至此,無需再經動態鏈接器。

總結

動態鏈接採用延遲綁定策略:

  • 首次調用:PLT → GOT(指向 PLT 解析代碼) → PLT0 → 動態鏈接器解析符號 → 更新 GOT 為真實地址 → 跳轉執行。
  • 再次調用:PLT → GOT(已為真實地址) → 直接跳轉執行,效率等同於靜態鏈接。

此機制平衡了程式啟動速度(避免解析所有符號)與運行效率(熱點函數僅解析一次)。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved