1. 例子1
C++代码:
int main()
{
func1(5);
}
对应的汇编代码为:
1 PUBLIC _main
2 _TEXT SEGMENT
3 _main PROC
4 push ebp
5 mov ebp, esp
6 push 5
7 call ?func1@@YAXH@Z
8 add esp, 4
9 xor eax, eax
10 pop ebp
11 ret 0
12 _main ENDP
13 _TEXT ENDS
解释:
L3-L12是main函数和procedure
L4, 5, 10是函数main的栈框架
ebp: base pointer,用于索引函数的参数和本地变量。先把之前的ebp入栈,再把main的ebp作为新的ebp。调用结束后恢复原函数的ebp。
L6:func1的函数入栈
L7:C++对函数名func1生成的符号,把函数的参数、参数类型都编码进去(因为有重载)
ESP:stack point
L8:退栈操作
L9:函数返回值清零,代表main函数返回0
L11:返回,但不对栈做额外的更改。不是main返回值为0的意思。
2. 例子2
void func1(int n)
{
int a = n + 1;
func2(a);
}
对应的汇编代码为:
1 _a{% math_inline %} = -4
2 _n{% endmath_inline %} = 8
3 ?func1@@YAXH@Z PROC
4 push ebp
5 mov ebs, esp
6 push ecx
7 mov eax, DWORD PTR _n{% math_inline %}[ebp]
8 add eax, 1
9 mov DWORD PTR _a{% endmath_inline %}[ebp], eax
10 mov ecx, DWORD PTR _a$[ebp]
11 push ecx
12 call ?func2@@YZXH@Z
13 add esp, 4
14 mov esp, ebp
15 pop ebp
16 ret 0
17 ?func1@@YZXH@Z ENDP
解释:
L4, 5, 14, 15为函数func1的栈框架
L6:腾出变量a在栈上的空间
L7:通过ebp+8得到入参n的值,并把值放入eax
L9:把eax存入ebp-4的位置入
L10-11:把ebp-4位置上的值读到ecx上并入栈,用于func1函数的参数入栈
L13:bar函数的参数退栈
3. 调用过程中的栈变化
栈空间的内容 | 说明 |
---|---|
main函数已经使用的空间 | |
func1的参数5 | main L6 |
“返回到main后的下一句指令”的地址 | main L7 |
寄存器保留的空间 | 从这里开始是func1的空间,对寄存器的push操作放到这里 |
a=5 | 参数的空间,L9 |
func2的参数5 | func1 L11 |
“返回到func1后的下一句指令”的地址 | L12 |
func2的可用空间 |