0

What is .noframe in delphi 64-bit assembly?

I have seen x64 assembly code like this.

procedure test;
{$IFDEF CPUX64}
asm
  .noframe
..
..

What is the meaning of .noframe and why should I care?

justyy
  • 5,831
  • 4
  • 40
  • 73
  • Is this SO question any help? Comments discuss `.noframe` and provide further links. Found immediately on searching. http://stackoverflow.com/questions/10695264/delphi-asm-code-incompatible-with-64bit – Weather Vane Nov 07 '15 at 17:09

3 Answers3

2

From the documentation:

Forcibly disables the generation of a stack frame as long as there are no local variables declared and the parameter count <= 4. Use only for leaf functions.

A leaf function is one that does not call another function. That is one that is always at the bottom of the call tree.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • These restrictions line up somewhat with MS x64's definition of a Leaf Function: https://learn.microsoft.com/en-us/cpp/build/stack-usage?view=vs-2019#function-types. Parameter count <= 4 means the args are all in registers, and don't need to be accessed from the stack. So apparently Delphi doesn't know how to use `[rsp+40]` to access a stack arg. No local vars means nothing might need to be spilled to stack memory (even though you have 32 bytes of shadow space above the return address without needing to move RSP). – Peter Cordes May 06 '19 at 22:16
  • 1
    As Ross commented, "leaf" has implications for stack unwinding: a "leaf" function can't modify any non-volatile (call preserved) register including RSP. So with a combination of that restriction + Delphi's apparent inability to use the stack at all without a frame pointer, we get this restriction of no locals + only register args. – Peter Cordes May 06 '19 at 22:18
1

From http://blogs.embarcadero.com/abauer/2011/10/10/38940

.NOFRAME

Some functions never make calls to other functions. These are called “leaf” functions because the don’t do any further “branching” out to other functions, so like a tree, they represent the “leaf” For functions such as this, having a full stack frame may be extra overhead you want eliminate. While the compiler does try and eliminate the stack frame if it can, there are times that it simply cannot automatically figure this out. If you are certain a frame is unnecessary, you can use this directive as a hint to the compiler.

justyy
  • 5,831
  • 4
  • 40
  • 73
  • 1
    While this is the ordinary definition of a leaf function, the Microsoft x64 calling convention defines a leaf function differently. Basically a leaf function is one that doesn't modify any non-volatile register including RSP, so that the return address is at the top of the stack. https://learn.microsoft.com/en-us/cpp/build/stack-usage?view=vs-2019#function-types – Ross Ridge May 06 '19 at 16:31
0

As far as I know the correct answer wouldn’t imply the “leaf function” condition. You can use the .noframe when you are sure that

  1. the parameter count is ≤ 4, as stated above;
  2. you don’t need to create a frame for local variables,
  3. the (1), (2) and (3) are also true for all the functions you want to call from this routine.

If the “leaf function” statement was true it would mean that you wouldn’t use the stack at all in such functions.

Zoltán Bíró
  • 346
  • 1
  • 12
  • 1
    The real requirement for a leaf function, according to the Microsoft x64 calling convention, is that the function can't modify non-volatile registers, including RSP. The return value must be at the top of the stack. This means that you can't call another function that follows the x64 calling convention, even a leaf function, because caller must allocate 32 bytes for the outgoing parameters. You can however call a function that doesn't assume these 32 bytes have been allocated on the stack and doesn't modify volatile registers, including RSP. – Ross Ridge May 06 '19 at 16:27
  • If my routine can call functions which don’t need frame even for return value I cannot see why the callee wouldn’t be able to do the same in turn. A `push rax` `pop rax` instruction pair doesn’t differ essentially from calling a simple function with no frame and no buffer for return value. – Zoltán Bíró May 07 '19 at 08:51
  • The unwinder can't unwind a function that uses `push rax` `pop rax` without the unwind information created by the .PUSHNV directive that only frame functions can use. – Ross Ridge May 07 '19 at 15:37