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

C 指標原理(86):GCC 編譯輸出組合語言分析 — 寄存器與記憶體分配

     編輯:關於C

前言

透過 gcc -S 產生的組合語言,可窺探 C 程式的底層執行機制:變數如何映射到記憶體、函數呼叫慣例、堆疊幀建立與拆除等。本文以經典的 hello world 為例,逐步剖析 GCC (AT&T 語法) 輸出的組合語言。

一、IA-32 通用寄存器速查

寄存器慣用用途
%eax累加器、函數回傳值
%ebx基址暫存器
%ecx計數器
%edx資料暫存器
%esp堆疊指標
%ebp基址指標(堆疊幀指標)
%esi來源變址
%edi目的變址

AT&T 語法中寄存器前加 %,立即數前加 $。

二、C 變數在記憶體中的分布

靜態資料區

字串常數 "hello,world" 放在 .rodata 區,標記為 .LC0:

.section .rodata
.LC0:
    .string "hello,world"

程式啟動時已分配,位址固定。

堆疊區

區域變數、函數參數、回傳位址、暫存寄存器值皆放於堆疊。堆疊向低位址增長,%esp 永遠指向棧頂(下一個可用位置)。

常用指令:

  • pushl %reg / pushl $imm:壓入堆疊,%esp -= 4
  • popl %reg:彈出堆疊,%esp += 4

三、hello world 組合語言逐行解讀

.text
.p2align 4,,15
.globl main
.type main, @function
main:
    leal 4(%esp), %ecx      # 保存 argc 位址
    andl $-16, %esp         # 對齊堆疊到 16 位元組邊界
    pushl -4(%ecx)          # 壓入 argc
    pushl %ebp              # 保存舊基址指標
    movl %esp, %ebp         # 建立新堆疊幀
    pushl %ecx              # 保存 argc 位址
    subl $4, %esp           # 分配區域變數空間 (對齊用)
    movl $.LC0, (%esp)      # 將字串位址放到堆疊頂 (puts 參數)
    call puts               # 呼叫 puts
    movl $0, %eax           # 回傳值 0
    addl $4, %esp           # 釋放區域空間
    popl %ecx               # 還原 argc 位址
    popl %ebp               # 還原基址指標
    leal -4(%ecx), %esp     # 還原堆疊指標
    ret                     # 返回呼叫者

關鍵點解析

  1. 堆疊對齊:andl $-16, %esp 確保 SSE 指令所需的 16-byte 對齊。
  2. 參數傳遞:x86 呼叫慣例將參數壓入堆疊,最右參數最先壓入。此處 puts 只有一個參數,直接放在 (%esp)。
  3. 保存/還原現場:pushl %ebp/popl %ebp 維護堆疊幀鏈,便於除錯回溯。
  4. 回傳值:放在 %eax。

四、基本運算指令

  • movl src, dst:複製資料(注意 AT&T 語法來源在前)
  • addl src, dst:dst += src
  • subl src, dst:dst -= src

範例:將變數 myvalue 加 100 再減 20:

movl myvalue, %ebx
addl $100, %ebx
subl $20, %ebx
movl %ebx, myvalue

總結

  • 寄存器是 CPU 內部最高速儲存,編譯器盡量將熱門變數放入寄存器。
  • 靜態資料(全域/靜態變數、字串常數)置於 .data/.rodata。
  • 自動變數、呼叫鏈資訊置於堆疊,透過 %ebp/%esp 管理。
  • 函數呼叫遵循約定:參數壓棧、建立堆疊幀、呼叫、清理堆疊、返回。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved