都是学习过程中做的笔记。
在编程的过程中,函数是必不可少的基础之一。c语言的程序完全由函数构成,所有的代码都在某一个函数中;pascal区分函数和过程,但是本质是类似的。而对计算机硬件而言CPU只关心一条条的指令,而不是它们是什么样的结构组织。call和ret只是为了函数调用的方便而已,并不是函数存在的证据。最简单的例子就是在木马免杀过程中call+ret和jmp是等价的。因此一种高级语言如何实现函数调用并不受约束,故出现了不同的函数调用规则。
在windows平台上常用的函数调用方式有pascal方式(psscal调用约定),WINAPI方式(StdCall调用约定),c方式(Cdedel调用约定)。
假设有一高级语言函数Message(p1,p2,p3)
c方式(Cdedel调用约定):
1.参数从右到左进入堆栈;
2.在函数返回后,调用者要负责清除堆栈,所以这种调用会生成较大的可执行程序。
push p3
push p2
push p1
call Message
add esp,0ch ;之前压入了3个四字节的参数
WINAPI方式(StdCall调用约定):
1.函数从右到左进入堆栈;
2.被调用的函数在返回之前自行清理堆栈,所以生成的代码较小。
push p3
push p2
push p1
call Message
pascal方式(psscal调用约定):主要用于win16函数库中,现在基本不用
1.参数从左到右进入堆栈
2.被调用的函数在返回前自行清理堆栈
3.不支持可变参数的函数调用。
push p1
push p2
push p3
call Message
此外在windows内核中还有快速调用方式(_fastcall);在C++编译的代码中有this call方式(_thiscall)。