VC / C ++裸属性做什么?

来自msdn

对于使用naked属性声明的函数,编译器生成没有prolog和epilog代码的代码。 您可以使用此function使用内联汇编程序代码编写自己的prolog / epilog代码序列。 裸函数在编写虚拟设备驱动程序时特别有用。

__declspec(naked) declarator 

什么是“prolog和epilog代码”。 我看到用C语言编写的库只在libc上运行在设备或固件上。 它调用函数没有问题,naked关键字做了什么以及为什么需要它?

注意:我不确定函数在这些库中使用的调用约定。

Prolog和epilog代码是设置调用堆栈的第一个/最后几个指令。 当您实现类似中断例程的事情时,您可以使用裸体,在那里您需要严格控制该函数中出现的指令。

Prolog:在函数体之前运行的代码,通常是处理函数入口和参数处理的代码。 Epilog:在函数体之后运行的代码,通常是处理函数返回和返回值的代码。

有了“裸体”,你必须/有机会自己写这些东西。

__declspec(naked)指令删除自动生成的prolog / epilog。

函数的prolog / epilog是样板代码,用于保存和恢复寄存器并适当地移动堆栈指针。

__fastcall调用约定为例。 它指定前两个参数位于寄存器(ECX和EDX)中,其余参数位于堆栈的右侧 – >左侧。 所以对于一个function:

void __fastcall DoFoo(int first, int second);

我的汇编程序有点生疏,但序幕可能看起来像:

 mov %ecx, first mov %edx, second pushl %ebp mov %esp, %ebp sub bytes, %esp 

然而,不同的调用约定将生成不同的序言/ epilog代码。

维基

prolog和epilog代码通常会处理堆栈,在堆栈上经常传递和返回参数。 要求编译器不生成这意味着您必须自己实现访问参数的正确方法。

不确定它是否还涉及为函数自己的参数分配堆栈空间,这通常在函数的最开始时完成(然后在函数退出之前完成),所以看起来很可能。

如果没有__declspec(裸),你的编译器负责正确的调用对象处理(将输入args推送到堆栈,’为局部变量保留’空间等)。 在某些情况下,您可以自己做。

例如 – 没有__declspec(裸)前3(prolog)和后3(epilog)指令将由您的编译器提供(假设使用了cdecl调用对流)。

 __declspec(naked) void func(inta, intb, int c, intd) { _asm{ push ebp mov ebp, esp sub esp, 8 // for 2 local int(32bit) variables - if you need it of course mov dword ptr[ebp-4], 3 // set one local var to 3 mov dword ptr[ebp-8], 4 // set one local var to 4 mov eax, dword ptr [ebp+8] // a mov ebx, dword ptr [ebp+12] // b mov ecx, dword ptr [ebp+16] // c mov edx, dword ptr [ebp+20] // d add esp, 8 // remove space for local vars mov esp, ebp pop ebp ret } } 

您现在可以从C / C ++代码中调用此例程,如下所示:

 func(0xAA, 0xBB, 0xCC, 0xDD); 

这将成为:

 push 0DDh push 0CCh push 0BBh push 0AAh call func 

BTW – 以相反的顺序推动args(与callinf func时发现的顺序相比),以允许可变长度的funcs工作