從匯編角度觀察 C 指針與陣列操作,能建立「代碼→指令→硬體」的立體認知。本文分析一段 x86 AT&T 語法匯編:在 .data 區定義 10 整數陣列,迴圈初始化 0~9,再迴圈呼叫 printf 列印,展示指標算術、棧幀保存/恢復、呼叫約定細節。
.section .rodata // 唯讀資料段
output:
.asciz "the number is %d\n" // 格式字串(以 \0 結尾)
.section .data // 已初始化可讀寫資料段
value:
.int 0,0,0,0,0,0,0,0,0,0 // 10 個 int,佔 40 位元組
.section .text // 代碼段
.globl main
main:
movl $0, %ecx // ecx = 0 (迴圈計數器)
loopset: // 初始化迴圈
// 基址寻址:value(基址, %ecx索引, 4比例因子) → value + ecx*4
movl %ecx, value(, %ecx, 4) // value[ecx] = ecx
inc %ecx // ecx++
cmpl $10, %ecx // ecx == 10 ?
jne loopset // 不等則跳回
movl $0, %ecx // 重置 ecx = 0
loopprint: // 列印迴圈
movl value(, %ecx, 4), %eax // eax = value[ecx] (參數1)
pushl %ecx // 保存 ecx (printf 可能破壞)
pushl %eax // 參數2:要列印的整數
pushl $output // 參數1:格式字串地址
call printf // 呼叫 C 庫函數
addl $8, %esp // 清理參數:pop 2 個 push (eax, output),各 4 位元組
popl %ecx // 恢復 ecx
inc %ecx
cmpl $10, %ecx
jne loopprint // 迴圈 10 次
// 隱式返回 0 (eax=0)
value(, %ecx, 4) 對應 Intel 語法 [value + ecx*4]。
value 陣列起始地址。%ecx (0~9)。4 (int 大小)。value[ecx],無需手動乘法指令。pushl %ecx / popl %ecxprintf 遵循 **cdecl 呼叫約定**:%eax, %ecx, %edx 為調用者保存暫存器。%ecx 必須在 call 前保存,返回後恢復,否則迴圈邏輯錯亂。push format, push value。call 後由**調用者**清理棧:addl $8, %esp (2參數 × 4字節)。%eax。esp/ebppush → esp -= 4;pop → esp += 4。ebp 幀指標(葉子函數、優化),直接用 esp 相對寻址。
$ gcc -o test1 test1.s
$ ./test1
the number is 0
the number is 1
...
the number is 9
#include
int main() {
int value[10];
for (int i = 0; i < 10; i++) value[i] = i;
for (int i = 0; i < 10; i++) printf("the number is %d\n", value[i]);
return 0;
}
這段匯編展示了 C 陣列下標如何編譯為 **基址+索引×比例** 寻址、迴圈計數器如何跨函數呼叫保存、cdecl 參數右進左出與調用者清棧。理解這些機制,是掌握指針算術、調試崩潰棧幀、編寫高效內聯匯編的基石。