Archived

This topic is now archived and is closed to further replies.

meZmo

Naked functions..

Recommended Posts

Hi. I''ve been reading around, but I haven''t found any conclusive answer to this.. When creating naked functions (fastcalled), which registers do I have to restore before returning? I''ve gotten the impression that I''m free to mess up eax, ecx and edx. Can anyone confirm this? Are there any others I can mess up? -meZ

Share this post


Link to post
Share on other sites
You can mess up all the registers. If it''s a naked - there''s no calling convention specified (i.e. it''s NOT a fastcall - it''s naked). It''s kinda like an inline function, but at the register level.

If you need/use local variables, you need to make room on the stack for them!

Share this post


Link to post
Share on other sites
The only special rules for naked __fastcall functions are (from the VC++7 docs):
quote:
For __fastcall naked functions, whenever there is a reference in C/C++ code to one of the register arguments, the prolog code should store the values of that register into the stack location for that variable. For example:

  
// nkdfastcl.cpp

__declspec(naked) int __fastcall power(int i, int j)
{
/* calculates i^j, assumes that j >= 0 */

/* prolog */
__asm {
push ebp
mov ebp, esp
sub esp, __LOCAL_SIZE
// store ECX and EDX into stack locations allocated for i and j
mov i, ecx
mov j, edx
}

{
int k=1; // return value
while (j-- > 0) k *= i;
__asm { mov eax, k };
}

/* epilog */

__asm
{
mov esp, ebp
pop ebp
ret
}
}



In conjunction with the general register preservation requirements:
quote:
In general, you should not assume that a register will have a given value when an __asm block begins. Register values are not guaranteed to be preserved across separate __asm blocks. If you end a block of inline code and begin another, you cannot rely on the registers in the second block to retain their values from the first block. An __asm block inherits whatever register values result from the normal flow of control.

If you use the __fastcall calling convention, the compiler passes function arguments in registers instead of on the stack. This can create problems in functions with __asm blocks because a function has no way to tell which parameter is in which register. If the function happens to receive a parameter in EAX and immediately stores something else in EAX, the original parameter is lost. In addition, you must preserve the ECX register in any function declared with __fastcall.

To avoid such register conflicts, don''t use the __fastcall convention for functions that contain an __asm block. If you specify the __fastcall convention globally with the /Gr compiler option, declare every function containing an __asm block with __cdecl or __stdcall. (The __cdecl attribute tells the compiler to use the C calling convention for that function.) If you are not compiling with /Gr, avoid declaring the function with the __fastcall attribute.

When using __asm to write assembly language in C/C++ functions, you don''t need to preserve the EAX, EBX, ECX, EDX, ESI, or EDI registers. For example, in the POWER2.C example in Writing Functions with Inline Assembly, the power2 function doesn''t preserve the value in the EAX register. However, using these registers will affect code quality because the register allocator cannot use them to store values across __asm blocks. In addition, by using EBX, ESI or EDI in inline assembly code, you force the compiler to save and restore those registers in the function prologue and epilogue.

You should preserve other registers you use (such as DS, SS, SP, BP, and flags registers) for the scope of the __asm block. You should preserve the ESP and EBP registers unless you have some reason to change them (to switch stacks, for example). Also see Optimizing Inline Assembly.

Note If your inline assembly code changes the direction flag using the STD or CLD instructions, you must restore the flag to its original value.

Share this post


Link to post
Share on other sites
quote:
Original post by Magmai Kai Holmlor
You can mess up all the registers. If it''s a naked - there''s no calling convention specified (i.e. it''s NOT a fastcall - it''s naked). It''s kinda like an inline function, but at the register level.

If you need/use local variables, you need to make room on the stack for them!


No!

Naked is not a calling convention.

Naked means that the compiler won''t insert its prologue/epilogue code for you.

A naked function can still be __fastcall, __cdecl, or __stdcall (I dunno if you can write thiscall naked functions). This tells the *calling* code how to pass its arguments, and determines whether the caller or the callee cleans up the stack.

Share this post


Link to post
Share on other sites
Dr. Pizza in your prolog code, whats with the:


// store ECX and EDX into stack locations allocated for i and j
mov i, ecx
mov j, edx

???

EDIT-
quote:
originally posted by Dr.Pizza
A naked function can still be __fastcall, __cdecl, or __stdcall (I dunno if you can write thiscall naked functions). This tells the *calling* code how to pass its arguments, and determines whether the caller or the callee cleans up the stack.


oh, is that how u tell the compiler that u want 'i' in ECX and 'j' in EDX? And how do you get the compiler to have the callee clean up the stack?

-potential energy is easily made kinetic-


Edited by - Infinisearch on February 7, 2002 9:50:52 PM

Share this post


Link to post
Share on other sites
doh - explains alot of the problem's I've been having with naked calls.

I guess __forceinline is like have no calling convention?

So if it's naked and __stdcall, you have to clean up the stack in your epilog? but if it's __cdecl the callee will?

It what situation would you need control of the just the called functions stack manipulation code? It seems like you would need to write code to handle both the caller and the callee to be useful...


Edited by - Magmai Kai Holmlor on February 7, 2002 12:47:00 AM

Share this post


Link to post
Share on other sites