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工作