本文内容摘自《windows内核编程》
在一个编写高级语言的程序员的观念中,函数(或者没有返回值的过程)是必不可少的基础单元。C语言的程序完全由函数构成,所有的代码都在某一个函数中。Pascal区分函数和过程,但是本质依然是类似的。对计算机硬件而言,这种区分毫无必要,因为CPU只关心一条一条的指令,并不关心它们是以怎样的结构组织的。
Call指令和ret指令只是为了调用的方便而已,绝不是函数存在的绝对证据。即使我们仅仅使用jmp并自己操作堆栈,也一样可以实现函数的功能。因此,一种高级语言如何实现函数调用,并没有法律的约束,所以出现了各种不同的函数调用规则。
但是,毫无疑问,如果一个第三方提供的函数要能被使用,那么必须有约定的函数调用规则。
函数调用规则指的是调用者和被调用函数间传递参数及返回参数的方法,在Windows上,常用的有Pascal方式、WINAPI方式(_stdcall)、C方式(_cdecl)。
_cdecl C调用规则:
(1) 参数从右到左进入堆栈;
(2) 函数返回后,调用者要负责清楚堆栈,所以这种调用常会生成较大的可执行程序。
_stdcall 又称为WINAPI,其调用规则:
(1) 参数从右到左进入堆栈;
(2) 被调用的函数在返回前自行清理堆栈,所以生成的代码比_cdecl小。
Pascal 调用规则:
Pascal调用规则主要用在Win16函数库中,现在基本不用。
(1) 参数从左到右进入堆栈;
(2) 被调用的函数在返回前自行清理堆栈;
(3) 不支持可变参数的函数调用。
此外,在Windows内核中还常见有快速调用方式(_fastcall);在C++编译的代码中有this call方式(_thiscall)。