汇编笔记:函数调用详细过程

问题一:sum函数执行完毕,计算机怎么知道继续执行哪条指令?

函数运行时要在栈帧上开辟空间,esp寄存器存储的是当前函数栈顶的位置,ebp寄存器存储的是当前函数栈底的位置

首先main函数调用sum函数,第一件事是将下一条指令的地址压栈

栈帧开辟详细细节

第二件事是开辟sum函数的栈帧空间

1、push ebp 保存调用方函数的栈底地址

2、执行 mov ebp, esp 将esp赋值给ebp,此时ebp指向sum函数栈帧的栈底

栈是从高地址向低地址增长的。也就是说,当你向栈中压入新的数据时,栈顶的地址实际上是在减小。

3、执行 sub esp, 为sum函数开辟的栈帧大小 来为sum函数开辟栈帧空间

4、(可选)对栈帧初始化,比如有的vs编译器会均初始化为0xCCCCCCCC,结果是打印未初始化的int值为-858993460

栈帧回退细节

执行 mov esp, ebp

pop ebp

CPU的PC寄存器存放的是下一条指令的地址,从栈顶弹出下一条指令的地址放到CPU的PC寄存器

示例

main函数中调用sum函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
using namespace std;

int sum(int a, int b)
{
return a + b;
}

int main()
{
int a = 8;
int b = 18;

int ret = sum(a, b);
cout << "ret is: " << ret << endl;
return 0;
}

执行 g++ -S calldetail.cpp

对应的汇编代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
	.file	"calldetail.cpp"
.text
.section .rdata,"dr"
_ZStL19piecewise_construct:
.space 1
.lcomm _ZStL8__ioinit,1,1
.text
.globl _Z3sumii
.def _Z3sumii; .scl 2; .type 32; .endef
.seh_proc _Z3sumii
_Z3sumii:
.LFB1573:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
.seh_endprologue
movl %ecx, 16(%rbp)
movl %edx, 24(%rbp)
movl 16(%rbp), %edx
movl 24(%rbp), %eax
addl %edx, %eax
popq %rbp
ret
.seh_endproc
.def __main; .scl 2; .type 32; .endef
.section .rdata,"dr"
.LC0:
.ascii "ret is: \0"
.text
.globl main
.def main; .scl 2; .type 32; .endef
.seh_proc main
main:
.LFB1574:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $48, %rsp
.seh_stackalloc 48
.seh_endprologue
call __main
movl $8, -4(%rbp)
movl $18, -8(%rbp)
movl -8(%rbp), %edx
movl -4(%rbp), %eax
movl %eax, %ecx
call _Z3sumii
movl %eax, -12(%rbp)
leaq .LC0(%rip), %rdx
movq .refptr._ZSt4cout(%rip), %rcx
call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
movq %rax, %rcx
movl -12(%rbp), %eax
movl %eax, %edx
call _ZNSolsEi
movq .refptr._ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_(%rip), %rdx
movq %rax, %rcx
call _ZNSolsEPFRSoS_E
movl $0, %eax
addq $48, %rsp
popq %rbp
ret
.seh_endproc
.def __tcf_0; .scl 3; .type 32; .endef
.seh_proc __tcf_0
__tcf_0:
.LFB2064:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $32, %rsp
.seh_stackalloc 32
.seh_endprologue
leaq _ZStL8__ioinit(%rip), %rcx
call _ZNSt8ios_base4InitD1Ev
nop
addq $32, %rsp
popq %rbp
ret
.seh_endproc
.def _Z41__static_initialization_and_destruction_0ii; .scl 3; .type 32; .endef
.seh_proc _Z41__static_initialization_and_destruction_0ii
_Z41__static_initialization_and_destruction_0ii:
.LFB2063:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $32, %rsp
.seh_stackalloc 32
.seh_endprologue
movl %ecx, 16(%rbp)
movl %edx, 24(%rbp)
cmpl $1, 16(%rbp)
jne .L8
cmpl $65535, 24(%rbp)
jne .L8
leaq _ZStL8__ioinit(%rip), %rcx
call _ZNSt8ios_base4InitC1Ev
leaq __tcf_0(%rip), %rcx
call atexit
.L8:
nop
addq $32, %rsp
popq %rbp
ret
.seh_endproc
.def _GLOBAL__sub_I__Z3sumii; .scl 3; .type 32; .endef
.seh_proc _GLOBAL__sub_I__Z3sumii
_GLOBAL__sub_I__Z3sumii:
.LFB2065:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $32, %rsp
.seh_stackalloc 32
.seh_endprologue
movl $65535, %edx
movl $1, %ecx
call _Z41__static_initialization_and_destruction_0ii
nop
addq $32, %rsp
popq %rbp
ret
.seh_endproc
.section .ctors,"w"
.align 8
.quad _GLOBAL__sub_I__Z3sumii
.ident "GCC: (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 8.1.0"
.def _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc; .scl 2; .type 32; .endef
.def _ZNSolsEi; .scl 2; .type 32; .endef
.def _ZNSolsEPFRSoS_E; .scl 2; .type 32; .endef
.def _ZNSt8ios_base4InitD1Ev; .scl 2; .type 32; .endef
.def _ZNSt8ios_base4InitC1Ev; .scl 2; .type 32; .endef
.def atexit; .scl 2; .type 32; .endef
.section .rdata$.refptr._ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, "dr"
.globl .refptr._ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
.linkonce discard
.refptr._ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_:
.quad _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
.section .rdata$.refptr._ZSt4cout, "dr"
.globl .refptr._ZSt4cout
.linkonce discard
.refptr._ZSt4cout:
.quad _ZSt4cout

作者:张泽中