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

C 指標原理(87):從彙編視角看 C 程式執行流程與堆疊操作

     編輯:關於C

靜態資料區與堆疊區的區別

.LC0 標記的字串常數位於靜態分配區(.rodata),程式載入時即固定;堆疊則是執行期動態增長/縮減的區域,用於函數參數傳遞、區域變數、回傳位址暫存。

堆疊採用 LIFO(後進先出),若無基址偏址機制,只能順序存取。指令 pushl/popl 自動調整 %esp。

基本彙編運算指令回顧

  • movl:資料搬移
  • addl:加法
  • subl:減法

語法:指令 來源 目的(AT&T 風格)。

main 函數彙編完整流程追蹤

main:
    leal 4(%esp), %ecx      # 1. 暫存 argc 位址
    andl $-16, %esp         # 2. 堆疊 16-byte 對齊
    pushl -4(%ecx)          # 3. 壓入 argc (原始堆疊頂)
    pushl %ebp              # 4. 保存呼叫者 %ebp
    movl %esp, %ebp         # 5. 建立本幀 %ebp
    pushl %ecx              # 6. 保存 argc 位址到新幀
    subl $4, %esp           # 7. 分配/對齊區域空間
    movl $.LC0, (%esp)      # 8. 參數 "hello,world" 位址入棧
    call puts               # 9. 呼叫 puts (破壞寄存器)
    movl $0, %eax           # 10. 設定回傳值 0
    addl $4, %esp           # 11. 釋放區域空間
    popl %ecx               # 12. 還原 argc 位址
    popl %ebp               # 13. 還原呼叫者 %ebp
    leal -4(%ecx), %esp     # 14. 還原原始 %esp
    ret                     # 15. 返回

關鍵步驟圖解

  1. 呼叫前準備 (1-7):對齊堆疊、建立堆疊幀、保存必要寄存器。
  2. 參數佈置 (8):將字串位址放到棧頂,符合 cdecl 呼叫慣例。
  3. 函數呼叫 (9):call 隱含 pushl %eip(回傳位址)並跳轉。
  4. 清理與返回 (10-15):設定回傳值、拆除堆疊幀、恢復現場、ret 彈出回傳位址跳轉。

呼叫慣例細節:保存/恢復現場

呼叫 puts 可能修改 %eax, %ecx, %edx 等「呼叫者保存」寄存器。編譯器在呼叫前將需保留的值(如 %ebp, %ecx)壓入堆疊,呼叫後彈出還原,這就是「保存現場」與「恢復現場」。

進階觀察:優化等級影響

gcc -O2 -S hello.c   # 會省略堆疊幀、合併指令、使用寄存器傳參

開啟優化後,main 可能縮減為:

main:
    subl $12, %esp
    movl $.LC0, (%esp)
    call puts
    xorl %eax, %eax
    addl $12, %esp
    ret

總結

  • C 高階語句最終轉化為搬移、算術、堆疊、跳轉等原始指令序列。
  • 堆疊是函數呼叫的核心基礎設施,支援參數傳遞、區域儲存、控制流轉移。
  • 理解彙編有助於除錯、效能分析、逆向工程與嵌入式開發。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved