现在的位置: 首页 > 综合 > 正文

关于 __declspec(naked) 编写干净函数

2013年08月15日 ⁄ 综合 ⁄ 共 2328字 ⁄ 字号 评论关闭
对于用 __declspec(naked) 编写干净函数

Copy code

VOID __declspec(naked) MyNakedFunction()
{
strcmp(...);
// __cdecl 函数是调用者清除参数堆栈,对于非内联汇编调用这类函数,编译器将自动平衡堆栈,加入 ADD ESP, 8
}

Copy code

VOID __declspec(naked) MyNakedFunction()
{
//...
__asm CALL strcmp;
__asm ADD ESP, 8; // 内联汇编需要自己平衡堆栈
}

__declspec(naked) 是且仅是不产生 prolog 和 epilog 代码 {保存并恢复使用过的寄存器和分配局部变量、平衡堆栈、返回值}。

附上刚翻译的一些 MSDN 可能对 naked 函数有点用的资料(我英语很烂,希望没翻译错误)

Microsoft Specific
All arguments are widened to 32 bits when they are passed. Return values are also widened to 32 bits and returned in the EAX register, except for 8-byte structures, which are returned in the EDX:EAX register pair. Larger structures are returned in the EAX register as pointers to hidden return structures. Parameters are pushed onto the stack from right to left. Structures that are not PODs will not be returned in registers.
The compiler generates prolog and epilog code to save and restore the ESI, EDI, EBX, and EBP registers, if they are used in the function.
Note 
When a struct, union, or class is returned from a function by value, all definitions of the type need to be the same, else the program may fail at runtime.

For information on how to define your own function prolog and epilog code, see Naked Function Calls.
The following calling conventions are supported by the Visual C/C++ compiler.
Keyword  Stack cleanup  Parameter passing 
__cdecl    Caller              Pushes parameters on the stack, in reverse order (right to left)
__clrcall    n/a                  Load parameters onto CLR expression stack in order (left to right).
__stdcall  Callee              Pushes parameters on the stack, in reverse order (right to left)
__fastcall Callee              Stored in registers, then pushed on stack
__thiscall Callee              Pushed on stack; this pointer stored in ECX

微软细节
所有参数在传递时都被扩展为 32 位。除了 8 字节结构体返回在 EDX:EAX 寄存器一对中,其它返回值同样被扩展为 32 位并返回在 EAX 寄存器中。大的结构体返回在 EAX 寄存器中的是指针来间接返回结构体。参数是自右向左压入堆栈。结构体是非 POD(Plain Old Data)类型将不会返回在寄存器中。
如果 ESI、EDI、EBX 和 EBP 寄存器在函数中使用,编译器将产生 prolog 和 epilog 代码保存并恢复它们。
注释
当一个函数用值返回结构体(struct)、联合体(union)或者类(class)时,所有类型的定义必须相同,否则程序可能在运行过程中失败。
关于如何定义你自身函数 prolog 和 epilog 代码的更多信息,请查阅 Naked Function Calls。
Visual C/C++ 编译器支持以下调用转换:
关键字   堆栈清除 参数传递
__cdecl  调用者  将参数倒序压入堆栈(自右向左)
__clrcall 不适用  将参数顺序加载到 CLR expression 堆栈中(自左向右)
__stdcall 被调用者 将参数倒序压入堆栈(自右向左)
__fastcall 被调用者 保存在寄存器然后压入堆栈
__thiscall 被调用者 压入堆栈,指针保存在 ECX 寄存器中

※ __fastcall:两个以内不大于 4 字节(DWORD)的参数将自左向右分别保存在 ECX、EDX 寄存器内,由于没有将参数压入堆栈,函数返回前无需将参数出栈(这就是它FASTCALL由来);其它参数仍按自右向左压入堆栈,函数返回时需要把这些参数出栈。

-----------------------------------------------------------------------------------------

呵,之前发帖提问的那位哥哥,不好意思呀,那时回答错了,幸亏你发信息提问下,要不然我要没验证下还真以为得还是得自己平衡堆栈呢。谢谢你的提问,让我又学了一点。

抱歉!评论已关闭.