以 32 位 x86 cdecl 為例:
EAX (64 位用 EDX:EAX,浮點用 ST0)EBX, ESI, EDI, EBP, ESP (非易失性);調用者保存:EAX, ECX, EDX (易失性)fun(p0, p1, p2) 為例); 假設參數為立即數 movl $p2, 8(%esp) movl $p1, 4(%esp) movl $p0, (%esp) ; 棧頂 (ESP) 指向 p0
call fun ; 硬體自動:push EIP (返回位址) ; ESP -= 4 ; 跳轉到 fun 入口
fun:
pushl %ebp ; 保存調用者 EBP
movl %esp, %ebp ; 建立新基址
; 此時棧布局 (高位址→低位址):
; [舊 EBP] ← EBP
; [返回位址]
; [p0] ← 8(%EBP)
; [p1] ← 12(%EBP)
; [p2] ← 16(%EBP)
; 方式 1:手動恢復 addl $24, %esp ; 釋放區域變數空間 popl %ebp ; 恢復舊 EBP ret ; 彈出返回位址跳轉 ; 方式 2:leave 指令 (等價於 movl %ebp,%esp; popl %ebp) leave ret
#include <stdio.h>
#include <stdlib.h>
void fun(int a, int b) {
int local = 12;
unsigned int ebp_val, esp_val;
long ret_addr;
int p0, p1;
// 讀取 EBP, ESP
asm volatile ("movl %%ebp, %%eax\n\t"
"movl %%esp, %%ebx\n\t"
: "=a"(ebp_val), "=b"(esp_val));
printf("EBP=%p, ESP=%p, 局部變數空間=%d\n", ebp_val, esp_val, ebp_val - esp_val);
// 讀取參數與返回位址
asm volatile ("movl 8(%%ebp), %%eax\n\t" // p0
"movl 12(%%ebp), %%ebx\n\t" // p1
"movl 4(%%ebp), %%ecx\n\t" // 返回位址
: "=a"(p0), "=b"(p1), "=c"(ret_addr));
printf("p0=%d, p1=%d, 返回位址=%p\n", p0, p1, ret_addr);
}
int main() { fun(1, 2); return 0; }
leave/popl %ebp 瞬間棧幀消失,區域變數內存失效subl $N, %esp 的 N 由符號表決定,非動態printf)——首個參數固定偏移,可解析格式串確定後續參數call、清理棧EAX)extern "C" 禁用