From msdn
For functions declared with the naked attribute, the compiler generates code without prolog and epilog code. You can use this feature to write your own prolog/epilog code sequences using inline assembler code. Naked functions are particularly useful in writing virtual device drivers开发者_StackOverflow社区.
__declspec(naked) declarator
What is "prolog and epilog code". I seen a libraries written in C code running on device or firmware using only libc. It calls functions without a problem, what does the naked keyword do and why is it needed?
note: I'm unsure what calling convention the functions use in those libs.
Prolog: Code that runs before the function body, typically code that handles function entry and argument handling. Epilog: Code that runs after the function body, typically code that handles return of function and return value.
With "naked" you have to/get the opportunity to write this stuff yourself.
Prolog and epilog code is the first/last few instructions where it sets up the call stack. You use naked when you're implementing something like an interrupt routine, where you need strict control over exactly what instructions appear in that function.
The __declspec(naked)
directive removes the automatically generated prolog/epilog.
The prolog/epilog for a function is the boilerplate code that saves and restores registers and moves the stack pointer appropriately.
Take __fastcall
calling conventions for example. It specifies the first two arguments are in registers (ECX and EDX) and the rest are right->left on the stack. So for a function:
void __fastcall DoFoo(int first, int second);
My assembler is a bit rusty but the prologue might look like:
mov %ecx, first
mov %edx, second
pushl %ebp
mov %esp, %ebp
sub bytes, %esp
Different calling conventions however will generate different prologue/epilog code.
Wiki
The prolog and epilog code would typically be dealing with the stack, on which arguments are often passed and returned. Asking the compiler to not generate that means you will have to implement the proper way of accessing the arguments yourself.
Not sure if it also involves allocating stack space for the function's own arguments, that is often done at the very start of a function (and then un-done before the function exits) so it seems likely.
Without __declspec(naked) your compiler is responsible for proper calling convension handling (pushing input args to stack, 'reserving' space for local variables etc). In some cases you may do it by yourself.
For example - without __declspec(naked) first 3(prolog) and last 3(epilog) instructions below would be provided by your compiler (assuming cdecl calling convension used).
__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
}
}
you can now call this routine from C/C++ code like this:
func(0xAA, 0xBB, 0xCC, 0xDD);
which will become:
push 0DDh
push 0CCh
push 0BBh
push 0AAh
call func
BTW - args are pushed in reverse order (comparing to order found when calling func
) to allow variable length functions to work
精彩评论