06. 函数栈
函数设计原则:高内聚,低耦合
内聚:所需资源自给自足,不依赖其他资源,重用性强,维护容易
责任清晰,容易移植到其他工程所需模块中
耦合:资源相互依赖,单一模块无法完成单一功能,重用性差,维护困难
责任不清晰,难以移植到其他工程所需模块中
函数调用时:
1.需要维护一个栈结构用于记录函数调用依赖关系
2.按调用约定传参
调用者caller
被调用者callee
调用约定主要约以下内容:
参数的传递顺序
参数的存储媒介(栈或寄存器)
谁负责释放参数空间(有且仅有一方实施)
返回值的存储媒介(栈或寄存器)
__cdecl:
函数参数从右往左传递
使用栈传递参数
caller负责释放参数空间
返回值在寄存器
__stdcall:
函数参数从右往左传递
使用栈传递参数
callee负责释放参数空间
返回值在寄存器
__fastcall:
左数前2个参数用寄存器传递,其余参数使用栈从右往左传递
callee释放参数空间
返回值在寄存器
3.保存返回地址
4.保存caller的栈底
5.更新当前栈底到callee的栈位置
6.为局部变量分配空间
7.保存其他受影响的寄存器(3个)
*8.编译选项/ZI /Zi会把局部变量的空间初始化为0xcccccccc(烫烫)
9.执行函数体
10.恢复保存的寄存器
11.释放局部变量占的空间
12.还原caller的栈底
13A. 如果是__fastcall或__stdcall,取出返回地址并按此更新流程。则由callee释放占空间
13B. 如果是__cdelc,取出返回地址并按此更新流程,这时流程回到caller
14.如果是__cdelc,则由caller释放栈空间
一个函数栈大概样子:
保存的寄存器
局部变量
Caller的栈底
返回地址
参数