VC / C ++裸属性有什么作用?

时间:2011-02-17 15:30:34

标签: c++ c visual-c++

From msdn

  

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

 __declspec(naked) declarator

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

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

5 个答案:

答案 0 :(得分:7)

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

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

答案 1 :(得分:4)

Prolog和epilog代码是设置调用堆栈的第一个/最后几个指令。当你实现像中断例程这样的东西时,你需要使用裸体,在那里你需要严格控制该函数中出现的指令。

答案 2 :(得分:2)

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

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

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

void __fastcall DoFoo(int first, int second);

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

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

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

Wiki

答案 3 :(得分:0)

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

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

答案 4 :(得分:0)

如果没有 __ 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工作