VC/C++ 裸属性有啥作用?

Posted

技术标签:

【中文标题】VC/C++ 裸属性有啥作用?【英文标题】:What does VC/C++ naked attribute do?VC/C++ 裸属性有什么作用? 【发布时间】:2011-02-17 15:30:34 【问题描述】:

From msdn

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

 __declspec(naked) declarator

什么是“序言和结语代码”。我看到一个用 C 代码编写的库,只使用 libc 在设备或固件上运行。它调用函数没有问题,裸关键字有什么作用,为什么需要它?

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

【问题讨论】:

msdn.microsoft.com/en-us/library/tawsa7cb(v=vs.80).aspx 请注意,它不是 C 或 C++ 关键字:它是 Visual C++ 提供的语言扩展(它也不是 Visual C++ 中的关键字,它是一个属性)。 @Daniel 提供的链接对序言和尾声提供了不错的解释。可以在here 找到该页面的最新版本(至少乍一看是相同的)。 【参考方案1】:

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

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

【讨论】:

【参考方案2】:

Prolog 和 Epilog 代码是设置调用堆栈的第一条/最后几条指令。当您实现类似中断例程的东西时,您会使用裸机,您需要严格控制该函数中出现的确切指令。

【讨论】:

【参考方案3】:

__declspec(naked) 指令删除自动生成的序言/结语。

函数的序言/结语是保存和恢复寄存器并适当移动堆栈指针的样板代码。

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

void __fastcall DoFoo(int first, int second);

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

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

然而,不同的调用约定会产生不同的序言/结语代码。

Wiki

【讨论】:

【参考方案4】:

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

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

【讨论】:

【参考方案5】:

如果没有 __declspec(naked),您的编译器将负责正确的调用约定处理(将输入参数推入堆栈,为局部变量“保留”空间等)。在某些情况下,您可以自己完成。

例如 - 如果没有 __declspec(naked) 以下前 3(prolog) 和后 3(epilog) 指令,您的编译器将提供以下指令(假设使用了 cdecl 调用约定)。

__declspec(naked) void func(int a, int b, int c, int d)

    _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

顺便说一句 - args 以相反的顺序推送(与调用 func 时发现的顺序相比)以允许可变长度函数工作

【讨论】:

以上是关于VC/C++ 裸属性有啥作用?的主要内容,如果未能解决你的问题,请参考以下文章

sklearn 的 DecisionTreeClassifier 中的“拆分器”属性有啥作用?

enable-background 属性到底有啥作用?

C# CoClass 属性有啥作用?

C# CoClass 属性有啥作用?

Python - “为字段添加属性”有啥作用?

缩小以适应视口元属性有啥作用?