The MASM Forum

General => The Workshop => Topic started by: _japheth on March 16, 2025, 07:36:53 PM

Title: Is this AI response (GitHub Copilot) regarding the Win64 ABI correct?
Post by: _japheth on March 16, 2025, 07:36:53 PM
My question, inspired by https://masm32.com/board/index.php?topic=12621.0 (https://masm32.com/board/index.php?topic=12621.0), was:

In a Win64 leaf function, is it allowed to define stack variables and still be SEH compliant?

and was answered with:

------------------------------------------------------------------------------------------------------
In a Win64 leaf function, it is allowed to define stack variables and still be SEH (Structured Exception Handling) compliant. However, you must adhere to certain constraints to ensure compliance with SEH. Specifically, you need to ensure that the function's prologue and epilogue follow the conventions expected by the SEH system.

Here are some key points to consider:

By following these guidelines, you can define stack variables in a Win64 leaf function while remaining compliant with SEH requirements.[/i]
------------------------------------------------------------------------------------------------------

My knowledge so far was:

As a consequence of those restrictions, I did assume that in a leaf function local variables, if possible at all, had to be addressed with RSP and a negative displacement.
Title: Re: Is this AI response (GitHub Copilot) regarding the Win64 ABI correct?
Post by: zedd151 on March 16, 2025, 09:44:35 PM
I wouldn't trust AI with any type of answers to code related questions. You must check and verify.  :smiley:

I have done my fair share of experimentation with asking several AI models for both assembly code and C code. During my experiments, I found only around 25% of the code generated produced code that would compile/assemble without errors, run without errors, and importantly produced accurate results.

Just some food for thought about AI. I don't think that Github Copilot would be much different. You must verify for accuracy.  :smiley:  The AI models I have used clearly state as a disclaimer, a sentence to the affect of "Results may contain errors, or mistake, etc." something of that nature.

The above are my opinions about AI, after having tried several AI models.
More specific to your question, I don't know of anyone here that even uses SEH in their code.
Title: Re: Is this AI response (GitHub Copilot) regarding the Win64 ABI correct?
Post by: six_L on March 17, 2025, 01:51:42 AM
Q:
QuoteIn a Win64 leaf function, is it allowed to define stack variables and still be SEH compliant?
A:(from DeepSeek)
QuoteYes, in a Win64 leaf function (a function that does not call other functions), it is allowed to define stack variables and still be SEH-compliant (Structured Exception Handling compliant). However, there are specific requirements to ensure SEH compatibility. Here's a detailed explanation:
1. What is a Leaf Function?
A leaf function is a function that does not call any other functions. Because it does not call other functions, it typically does not need to:
    Save non-volatile registers (e.g., rbx, rsi, rdi).
    Allocate a call stack frame (e.g., shadow space for function calls).
2. Requirements for SEH Compliance in Win64
To support SEH in Win64, a function must meet the following requirements:
    Stack Alignment: The stack pointer (rsp) must remain 16-byte aligned at all times.
    Stack Frame Chain: If the function might trigger an exception, it must establish a stack frame chain (via mechanisms like RtlUnwind or RtlLookupFunctionEntry).
3. Defining Stack Variables in a Leaf Function
Defining stack variables in a leaf function is allowed, but you must ensure:
    Stack Alignment: When allocating stack space, ensure rsp remains 16-byte aligned.
    Stack Frame Chain: If the function might trigger an exception, you must explicitly establish a stack frame chain (even if it does not call other functions).
4. Example Code
Here's an example of a leaf function that defines stack variables while remaining SEH-compliant:
leaf_function PROC
    ; Save non-volatile registers (optional)
    push    rbx
    push    rsi
    push    rdi

    ; Allocate stack space (maintain 16-byte alignment)
    sub     rsp, 32  ; Allocate 32 bytes of stack space (16-byte aligned)

    ; Define stack variables
    mov     DWORD PTR [rsp + 16], 1234  ; Example variable

    ; Free stack space
    add     rsp, 32

    ; Restore non-volatile registers
    pop     rdi
    pop     rsi
    pop     rbx
    ; Return
    ret
leaf_function ENDP
5. Ensuring SEH Compliance
To ensure SEH compliance:
    Establish a Stack Frame Chain: If the function might trigger an exception, use .seh_prolog and .seh_epilog directives to establish a stack frame chain.
    Maintain Stack Alignment: Ensure rsp remains 16-byte aligned at all times.
6. Key Points
    Defining stack variables in a Win64 leaf function is allowed.
    To be SEH-compliant, ensure stack alignment and establish a stack frame chain if necessary.
    If the function does not involve exception handling, you can omit the stack frame chain setup.
Title: Re: Is this AI response (GitHub Copilot) regarding the Win64 ABI correct?
Post by: _japheth on March 17, 2025, 02:55:52 AM
Quote from: six_L on March 17, 2025, 01:51:42 AM1. What is a Leaf Function?
A leaf function is a function that does not call any other functions.

That's probably the crucial point. It's somewhat intuitive to agree to the definition supplied by the AI, but according to MS the definition is as follows:

Leaf functions are functions that don't change any non-volatile registers.

And only in the context of this latter definition the problem touched by my original question becomes clear (because RSP is a non-volatile register).
Title: Re: Is this AI response (GitHub Copilot) regarding the Win64 ABI correct?
Post by: jj2007 on March 17, 2025, 09:05:11 AM
Quote from: _japheth on March 17, 2025, 02:55:52 AMLeaf functions are functions that don't change any non-volatile registers.

Raymond Chen: (https://devblogs.microsoft.com/oldnewthing/20150730-00/?p=90791) But those rules are relaxed for leaf functions (functions which call no other functions).
Title: Re: Is this AI response (GitHub Copilot) regarding the Win64 ABI correct?
Post by: tenkey on March 17, 2025, 02:47:34 PM
That article is about the Itanium, which is not an x86 CPU. It is possible that a call (whatever mnemonic it uses) instruction stores the return address in a register. There would not be any change to a stack pointer.

AFAIK there is no red zone defined by the Win64 ABI. So I would not store anything below RSP.

What I do know is that RSP must not be changed by the leaf function. The leaf function must NOT align RSP to a 16-byte boundary.
Title: Re: Is this AI response (GitHub Copilot) regarding the Win64 ABI correct?
Post by: _japheth on March 17, 2025, 06:17:52 PM
Quote from: jj2007 on March 17, 2025, 09:05:11 AMRaymond Chen: (https://devblogs.microsoft.com/oldnewthing/20150730-00/?p=90791) But those rules are relaxed for leaf functions (functions which call no other functions).

Raymond Chen is definitely your Guru  :biggrin: Well, why not, he's very knowledgeable - but even he might sometimes simplify things not to overstrain his readers.

If you'd bother to make yourself familiar with Win64 SEH, you'll realize that the SEH code has a lot to do if an exception occurs (may forget some details, my Windows knowledge has become a bit rusty ):


That's why, if I may quote myself, wrote:

in a leaf function, the return address to the caller must be at [rsp+0]. So no rbp stack frame is possible
Title: Re: Is this AI response (GitHub Copilot) regarding the Win64 ABI correct?
Post by: _japheth on March 18, 2025, 02:53:06 AM

This YASM (https://www.tortall.net/projects/yasm/manual/html/objfmt-win64-exception.html) site gives a rather good overview about the differences between "leaf" and "frame" functions.
Also, it describes in detail what's required if you want to dynamically alloc stack space ( _alloca() in C ) in a SEH-safe way.
Title: Re: Is this AI response (GitHub Copilot) regarding the Win64 ABI correct?
Post by: tenkey on March 18, 2025, 08:03:20 AM
The YASM document is much better. It is consistent with the parts I have figured out.
This includes:

* The position of saved nonvolatile registers.
    I'm displeased with UASM's auto-placement of "used" 64-bit registers
    in the stack.
    In its current implementation (ver. 2.57), it can unalign the stack.
* The difference between presence and absence of alloca() behavior.
    This is an indicator that a frame pointer (separate from RSP)
    is needed or not.
* The stack alignment of leaf functions.
    My definition of leaf functions (or procedures) depends on context.
    If I'm talking about MS function implementation, it means one thing.
    If I'm talking about call structure, it means something else.
Title: Re: Is this AI response (GitHub Copilot) regarding the Win64 ABI correct?
Post by: tenkey on March 20, 2025, 09:19:24 AM
After my statements mentioning two meanings of leaf functions, it occurred to me that the AI might be referring to my second meaning. I spell it out now.

If leaf function refers to a function in a call structure (info is who calls whom) then a leaf function is a function that doesn't call another function. If that is the case, an MS "leaf function" is really an optimized leaf function (call structure meaning). That is an implementation detail.

The confusion is a term originally defining a concept (a function that doesn't call other functions) being used to define an implementation (a function with implementation restrictions).

The "restrictions" are conditions that compilers can detect to optimize leaf functions (by removing or not generating stack realignment code), because the exception handler system can handle the specific code change.
Title: Re: Is this AI response (GitHub Copilot) regarding the Win64 ABI correct?
Post by: sinsi on March 26, 2025, 08:09:19 AM
I was looking through the SDK/DDK files and found this little snippet in MACAMD64.INC
; LEAF_ENTRY_ALIGNED <Name>, <Section>, <Alignment>, <NoPad>
;
; Macro Description:
;
;  This macro indicates the beginning of a leaf function with custom alignment.
;
;  A leaf function is one that DOES NOT:
;
;  - manipulate non-volatile registers
;  - manipulate the stack pointer
;  - call other functions
;  - reference an exception handler
;  - contain a prologue
;  - have any unwind data associated with it