Does a legitmate epilog need to include a dummy rsp adjustment even if not otherwise necessary?
Asked Answered
B

0

6

The x86-64 Windows ABI has the concept of a legitimate epilog, which is a special type of function epilog that can be simulated during exception handling in order to restore the callers context1 as described here:

If the RIP is within an epilog [when an exception occurs], then control is leaving the function, ... and the effects of the epilog must be continued to compute the context of the caller function. To determine if the RIP is within an epilog, the code stream from RIP on is examined. If that code stream can be matched to the trailing portion of a legitimate epilog, then it is in an epilog, and the remaining portion of the epilog is simulated, with the context record updated as each instruction is processed...

You can find a prose description of a legitimate epilog here, which includes the following example:

If no frame pointer is used in the function, then the epilog must first deallocate the fixed part of the stack, the nonvolatile registers are popped, and control is returned to the calling function. For example,

add      RSP, fixed-allocation-size  
pop      R13  
pop      R14  
pop      R15  
ret

It contains a similar example with lea to restore the stack when a frame pointer is used.

What if, however, there is no fixed size allocation at all within the function? It is not uncommon for functions not to use the stack. Does a dummy add rsp, 0 need to be inserted in this case to conform to the rules for a legitimate epilog, or may it be omitted?


1 For example, to restore the non-volatile registers that may have been clobbered by the callee.

Barranquilla answered 26/7, 2017 at 20:0 Comment(7)
you can have any form of prolog and epilog. but for unwind must be associated RUNTIME_FUNCTION table entry that describes the current function. in c/c++ we use for this __try/__except for example. in masm - PROC FRAME:ehandler - msdn.microsoft.com/en-us/library/ms235231.aspxHelenahelene
What you say seems to contradict the documentation. It's true you can have various prolog types, but that's because you have to document the byte-range of your prolog instructions, and create a list of UNWIND_INFO that documents exactly on an instruction-by-instruction basis what your prolog does. The mechanism for the epilog is very different (see my links). Note that your link talks about prolog, not epilog.Barranquilla
exception in epilog (when you only pop registers from stack) can occur only if rsp already point to invalid location. in this case anyway exception can not be handled (it even will be no passed to user mode, if rsp not point to valid memory location). so I personally think that what is your epilog form not matter . if exception will be inside your function - we got to Case c)Helenahelene
Well the documentation implies otherwise, since they have a detailed description of what happens if there is an exception in the epilog, and there is a complex mechanism to simulate the epilog instructions. You are right though that it seems quite unusual to get have an exception in the epilog. The only ways I could think of would be some type of permissions change on the stack pages, or perhaps some trickery with the segment register. Are all of the possible cases unrecoverable? I'm not sure.Barranquilla
what I wrote only my personally vision, but I not view way how exception can be on pop and ret instruction, if rsp point to valid memory (ok, we can image for example that while code executed, somebody change page protection of epilog code bytes, make it not executable, but this is ..think not real case). if rsp not valid - exception even will be not passed to user mode (kernel copy exception record and context to stack before call KiUserExceptionDispatcher). I think you need correct RUNTIME_FUNCTION for you function. epilog anyway will be not problemHelenahelene
Well some functions don't have any epilogue I.e. no callee saved registers, no alignment requirement, no homespace+return address because it doesn't call a function, no locals. In this case, there is no epilogue. I would think it can handle all types of epilogues. Prologue in this case is also nonexistent, and there's an implicit call instruction to unwindHidrosis
The doc also says: "Epilog code trims the stack to its fixed allocation size (if necessary)". It seems to me that an epilog can contain: an optional RSP adjustment (in one or two steps), an optional sequence of registers POP, a RET/JMP (not all forms). Also doesn't a function like this prooves there's no need for add rsp, xxx?Hebron

© 2022 - 2024 — McMap. All rights reserved.