/* asm_demo.s */
.section .rodata
msg: .asciz "value = %d\n"
.section .data
arr: .fill 10, 4, 0 /* 10 個 int,初始 0 */
.section .text
.global main
main:
/* 初始化 arr[i] = i */
mov $0, %ecx # i = 0
init_loop:
mov %ecx, arr(,%ecx,4) # arr[i] = i (基址 + 索引*4)
inc %ecx
cmp $10, %ecx
jne init_loop
/* 列印陣列 */
mov $0, %ecx # i = 0
print_loop:
mov arr(,%ecx,4), %eax # eax = arr[i]
push %ecx # 保存 ecx (printf 會破壞)
push %eax # 參數 2: value
push $msg # 參數 1: format string
call printf
add $8, %rsp # 清理參數 (2 個 64-bit = 16 bytes? 實際 8+8=16)
pop %ecx # 還原 ecx
inc %ecx
cmp $10, %ecx
jne print_loop
ret
語法:`位移(基址, 索引, 比例)` → 有效位址 = `位移 + 基址 + 索引 * 比例`
| 類別 | 暫存器 | 責任 |
|---|---|---|
| 呼叫者保存 | RAX, RCX, RDX, RSI, RDI, R8-R11 | 呼叫前若需保留須自行 push |
| 被呼叫者保存 | RBX, RBP, R12-R15 | 被呼叫者若使用須 push/pop 還原 |
| 特殊 | RSP, RIP | 堆疊指標、指令指標 |
| 現象 | 組合語言線索 | 根因 |
|---|---|---|
| 區域變數值亂碼 | `sub $N, %rsp` 分配空間,但未初始化 | C 變數未初始化 |
| 函數返回後呼叫者暫存器變了 | 呼叫者保存暫存器未 push | 違反 ABI 慣例 |
| 參數傳遞錯誤 | 第 7 參數未壓堆疊 / 浮點參數用整數暫存器 | 呼叫慣例不符 |
| 堆疊損壞 | `add $N, %rsp` 數量與 `push` 不匹配 | 內聯組合語言/手寫組合錯誤 |
組合語言是 C 語言**執行實相**的直接投影。掌握定址模式、堆疊幀佈局、暫存器慣例、參數/返回值傳遞、呼叫者/被呼叫者保存分工,能在最底層驗證 C 代碼行為、優化熱點路徑、解決極難複現的 UB 崩潰。建議配合《CSAPP 第 3 章》、《System V AMD64 ABI 文件》、GDB `layout asm` 日常練習。