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

C語言靜態鏈接深度解析:段合併、符號解析、重定位全流程

     編輯:關於C語言

C語言靜態鏈接深度解析:段合併、符號解析、重定位全流程

靜態鏈接器如何將多個 .o 目標文件合併為單一可執行文件?本文以 GCC/Linux/ELF32 為例,拆解「空間分配 → 符號解析 → 重定位」三大核心階段,附 objdump 實證分析。

第一階段:空間與地址分配——相似段合併

鏈接器掃描所有輸入文件,收集段信息(長度、屬性、位置),**按名稱合併同類段**:

  • 所有 .text → 一個大 .text
  • 所有 .data → 一個大 .data
  • 所有 .bss → 一個大 .bss

優勢:段數量固定、消除內部碎片、利於內存映射。同時構建**全局符號表**,彙總所有文件的符號定義與引用。

第二階段:符號解析與重定位

合併段後,原符號地址失效,需完成:

  1. 符號解析:將每個未定義引用(如 extern int shared)綁定到唯一定義(b.c 中的 shared)
  2. 重定位:修正代碼中所有「待定地址」為最終虛擬地址

實證案例:a.c + b.c → ab

// b.c
int shared = 1;
void swap(int *a, int *b) { *a ^= *b ^= *a ^= *b; }

// a.c
extern int shared;
int main() { int a=100; swap(&a, &shared); return 0; }

編譯:gcc -c a.c b.c → a.o、b.o
鏈接:gcc a.o b.o -o ab

1. 目標文件基址均為 0,可執行文件基址 0x08048000

# objdump -h a.o b.o ab
a.o/.text: VMA=0x0
b.o/.text: VMA=0x0
ab/.text:  VMA=0x08048000  // Linux 32位默認加載地址

2. a.o 重定位表揭示待修正位置

# objdump -r a.o
RELOCATION RECORDS FOR .text:
OFFSET   TYPE              VALUE
00000011 R_386_32          shared   // 指令中 shared 地址佔位
00000020 R_386_PC32        swap     // call swap 相對偏移佔位

3. 反彙編定位具體指令

# objdump -d a.o
  11:  c7 44 24 04 00 00 00 00   movl $0x0, 0x4(%esp)  # shared 佔位 0
  20:  e8 fc ff ff ff            call 0x21               # swap 佔位 -4 (相對偏移)

# objdump -d ab (鏈接後)
  80480a5: c7 44 24 04 58 91 04 08  movl $0x8049158, 0x4(%esp)  # shared 真實地址
  80480b4: e8 07 00 00 00            call 0x80480c0              # swap 真實入口

4. 重定位計算公式驗證

  • 共享變量 shared:S + A = 0x08049158 + 0 = 0x08049158(小端存儲 58 91 04 08)
  • 函數 swap (PC32 相對重定位):S + A - P = 0x080480c0 + (-4) - 0x080480b5 = 0x7(小端 07 00 00 00)

完全匹配鏈接後機器碼!

關鍵結構:ELF 重定位表項

typedef struct {
    Elf32_Addr r_offset;  // 需修正位置在段內偏移
    Elf32_Word r_info;    // 符號表索引 + 重定位類型
} Elf32_Rel;

r_info 高 24 位 = 符號索引,低 8 位 = 類型(R_386_32 絕對、R_386_PC32 相對)。

總結:靜態鏈接三部曲

  1. 掃描合併:相似段合併,計算合併後 VMA,建立段映射
  2. 符號解析:構建全局符號表,解決所有引用→定義綁定
  3. 重定位修正:遍歷各段重定位表,按類型(絕對/相對)計算最終值,回填機器碼

理解此流程,是排查「未定義引用」「多重定義」「地址錯誤」等鏈接錯誤的理論基石。

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