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

GCC 編譯中間檔案實戰觀察:.i 預處理輸出與 .s 組語碼完整範例

     編輯:關於C語言
 

承接前文「C 語言開發環境從零開始」,本文提供 gcctest.c 經 GCC -E 與 -S 產出的 .i 與 .s 完整內容,並逐段解析關鍵區塊,幫助你建立原始碼到組語的具體對應認知。

原始碼回顧 gcctest.c

#include 
int main(void) {
    printf("This is a gcc test!\n");
    return 0;
}

.i 預處理輸出(節錄關鍵段)

完整 .i 超過 800 行(含 stdio.h 全文),此處僅列關鍵部分:

# 1 "gcctest.c"
# 1 ""
# 1 ""
# 1 "/usr/include/stdio.h" 1 3 4
...(stdio.h 完整內容:FILE 結構、printf 原型、_IO_stdin 等)...
# 1 "gcctest.c" 2

int main(void) {
    printf("This is a gcc test!\n");
    return 0;
}
  • # 行號 "檔名" 旗標:行號追蹤資訊,供除錯器/編譯器報錯定位。
  • 巨集 printf 已展開為 __printf_chk 等內建函式(若啟用 -D_FORTIFY_SOURCE)。

.s 組語完整輸出(x86-64, AT&T 語法)


    .file   "gcctest.c"
    .section .rodata
.LC0:
    .string "This is a gcc test!"
    .section .text.unlikely
    .section .text.startup
    .section .text.hot
    .section .text
    .globl  main
    .type   main, @function
main:
.LFB0:
    .cfi_startproc
    endbr64
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    leaq    .LC0(%rip), %rdi
    call    puts@PLT
    movl    $0, %eax
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size   main, .-main
    .ident  "GCC: (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0"
    .section .note.GNU-stack,"",@progbits

組語關鍵指令逐行解析

指令說明
.file "gcctest.c"原始檔名,供除錯資訊使用。
.section .rodata切換至唯讀資料段,存放字串常數。
.LC0: .string "..."定義標號 .LC0 指向字串「This is a gcc test!」。
.globl main宣告 main 為全域符號,連結器可見。
pushq %rbp / movq %rsp, %rbp建立堆疊框架(Frame Pointer),方便除錯追蹤呼叫堆疊。
leaq .LC0(%rip), %rdiRIP 相對定址載入字串位址至 %rdi(第一參數暫存器)。
call puts@PLT呼叫 puts(PLT 動態連結存根),輸出字串並換行。
movl $0, %eax回傳值 0 放入 %eax(回傳值暫存器)。
popq %rbp / ret還原堆疊框架並返回呼叫者。
.cfi_*DWARF Call Frame Information,供例外處理/堆疊展開使用。

觀察重點與延伸練習

  • 最佳化差異:加上 -O2 重新產出 .s,觀察 pushq %rbp 框架指令消失、puts 直接以 %rdi 傳參、尾端優化等差異。
  • 靜態連結:gcc -static -S gcctest.c 觀察 call puts 變為直接呼叫 puts 實體位址。
  • ARM64 交叉編譯:aarch64-linux-gnu-gcc -S gcctest.c 對比 AArch64 指令集(str/bl/ret)。
  • 反組譯驗證:objdump -d gcctest.o 或 gdb ./gcctest -batch -ex 'disas main' 驗證最終機器碼。
 
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved