int add(int a, int b) {int c = a + b;return c;
}int main() {int result = add(1, 2);return 0;
}
生成匯編代碼:g++ -S Cplus.cpp -o Cplus.s
.file "Cplus.cpp".text.globl _Z3addii.def _Z3addii; .scl 2; .type 32; .endef.seh_proc _Z3addii
_Z3addii:pushq %rbp.seh_pushreg %rbpmovq %rsp, %rbp.seh_setframe %rbp, 0subq $16, %rsp.seh_stackalloc 16.seh_endprologuemovl %ecx, 16(%rbp)movl %edx, 24(%rbp)movl 16(%rbp), %edxmovl 24(%rbp), %eaxaddl %edx, %eaxmovl %eax, -4(%rbp)movl -4(%rbp), %eaxaddq $16, %rsppopq %rbpret.seh_endproc.def __main; .scl 2; .type 32; .endef.globl main.def main; .scl 2; .type 32; .endef.seh_proc main
main:pushq %rbp # 將寄存器的值壓入棧中.seh_pushreg %rbp # 上一個棧幀的基址movq %rsp, %rbp # 當前棧幀的基址.seh_setframe %rbp, 0subq $48, %rsp # 預留空間.seh_stackalloc 48.seh_endprologuecall __mainmovl $2, %edxmovl $1, %ecxcall _Z3addii # 調用函數movl %eax, -4(%rbp)movl $0, %eaxaddq $48, %rsppopq %rbpret.seh_endproc.ident "GCC: (x86_64-win32-sjlj-rev0, Built by MinGW-W64 project) 8.1.0"
- 函數調用過程:
初始狀態:rbp = rsp = 0x1000
地址 | 棧中的內容 | 執行的操作 | 指令 |
---|---|---|---|
0x0ff8 | 上一個函數的棧幀基址(rbp=0x1000) | rsp-=8 0x0ff8->rsp | pushq %rbp |
rbp=rsp=0x0ff8,表示當前函數棧幀的基址 | movq %rsp, %rbp | ||
0x0ff0 | eax值(0x0ff8,0x0ff4) | ||
0x0fe8 | |||
0x0fe0 | |||
0x0fd8 | |||
0x0fd0 | |||
0x0fc8 | rsp-=48 0x0fc8->rsp | subq $48, %rsp | |
0x0fc0 | 返回地址 | rsp-=8 0x0fc0->rsp | call __main |
0x0fb8 | 返回地址 | rsp-=8 0x0fb8->rsp | call _Z3addii |
0x0fb0 | main函數的棧幀基址(rbp=0x0ff8) | rsp-=8 0x0fb0->rsp | pushq %rbp |
0x0fa8 | eax值 (0x0fb0,0x0fa4) | rbp=rsp=0x0fb0,表示當前函數棧幀的基址 | movq %rsp, %rbp |
0x0fa0 | rsp-=16 0x0fa0->rsp | subq $16, %rsp | |
0x0f98 |
注意:
- 參數傳遞規則??
??前 4 個整數參數??:通過寄存器傳遞(順序:rcx, rdx, r8, r9)。
??多余參數??:通過棧傳遞(從右向左壓棧)。
這是反匯編或編譯器生成的代碼,可能是調試版本或未優化的結果。實際參數應直接從寄存器讀取: movl %ecx, 16(%rbp)
的問題
雖然 subq $48, %rsp 預留了 48 字節棧空間,但:
實際只用了 4 字節(保存返回值);
剩下的是 對齊 + 編譯器保守行為 + SEH支持 的結果;
并不是異常,是很正常且常見的行為。
- 函數返回過程:
movl %ecx, 16(%rbp)
movl %edx, 24(%rbp)
movl 16(%rbp), %edx
movl 24(%rbp), %eax
addl %edx, %eax
movl %eax, -4(%rbp)
movl -4(%rbp), %eaxaddq $16, %rsp # 釋放空間
popq %rbp # rbp = *(rsp), rsp+=8
ret # 讀取rsp獲得返回地址,rsp+=8
- 返回到主函數后:
movl %eax, -4(%rbp) #
movl $0, %eax # 寄存器置于0
addq $48, %rsp # 釋放空間
popq %rbp # rbp = *(rsp), rsp+=8
ret # 讀取rsp獲得返回地址,rsp+=8,最終rsp=0x1000(初始值)