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++ 裸属性有啥作用?的主要内容,如果未能解决你的问题,请参考以下文章