开发者

What does VC/C++ naked attribute do?

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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜