(Linux Uasm 2.46.7) Ubiquitous prologue/epilogue sequence sub/add rsp,8

Started by Quicksort, May 02, 2018, 06:08:13 PM

Previous topic - Next topic

Quicksort

Unlike Windows Uasm, Linux Uasm generates consistently (unless OPTION PROLOGUE/EPILOGUE : NONE is specified) a pseudo prologue/epilogue sequence sub/add rsp,8. It seems pointless and causes a crash if a jump is taken (following sub rsp,8) to a function expecting the return address at [rsp].

In my code, procedures are defined in the simplest possible way, by means of the PROC/ENDP directives, without FRAME/USES keywords or PROTO/INVOKE usage.

Did I miss something or is this indeed a bug ?
Linux Mint: from freedom came elegance.

johnsa

Hi,

Can you post an example proc + disasm ?

In theory there should be a SUB/ADD to align RSP to 16 which is required.. so if there is just a simple call, all parameters in registers and no locals the add/sub would be present.

Quicksort

Hi,

(Neither Windows Uasm nor Linux/Windows JWasm generate this sub/add rsp,8 sequence but Linux Uasm does, unless option prologue/epilogue:none is specified)

The test program of the library I have developed runs smoothly if the latter is assembled with Windows Uasm or Linux/Windows JWasm.

When it crashed, I (wrongly) suspected that a problem with Linux JWasm's address fixups I had notified to Japheth in 2012, and which he quickly solved, might have resurfaced. I therefore used Agner Fog's 'objconv' to disassemble a module of my library and noticed at once these sub/add rsp,8 sequences everywhere in the code.

Some tiny functions of my library, such as the two below, return a status code. There are countless (possible) jumps to them from various error checking preambles. Once executed, they would transfer control to the procedure which called the code containing the jump. If rsp does not point to the right location (namely after sub rsp,8) when the jump is taken, a crash occurs upon return. For example, the 'Lib_Setup' procedure's error checking code (whose four first lines are shown) could jump to E_null_pointer, E_structure_misalignment, etc.

This is objconv's output (Linux Uasm), the source code is identical.

(I had already understood the sub/add rsp,8 sequence served a stack alignment purpose, but in these small functions it is clearly useless)

E_normal_processing PROC
        sub     rsp, 8                                  ; 9106 _ 48: 83. EC, 08
        xor     eax, eax                                ; 910A _ 33. C0
        add     rsp, 8                                  ; 910C _ 48: 83. C4, 08
        ret                                             ; 9110 _ C3
E_normal_processing ENDP

E_lib_setup_not_performed PROC
        sub     rsp, 8                                  ; 9111 _ 48: 83. EC, 08
        mov     rax, -1                                 ; 9115 _ 48: C7. C0, FFFFFFFF
        add     rsp, 8                                  ; 911C _ 48: 83. C4, 08
        ret                                             ; 9120 _ C3
E_lib_setup_not_performed ENDP

        ...

Lib_Setup PROC
        sub     rsp, 8                                  ; 0000 _ 48: 83. EC, 08 ------------------ rsp does not point to return address anymore.
        test    rdi, rdi                                ; 0004 _ 48: 85. FF
        je      E_null_pointer                          ; 0007 _ 0F 84, 00009124 ----------------- and crashes.
        test    rdi, 7H                                 ; 000D _ 48: F7. C7, 00000007
        jne     E_structure_misalignment                ; 0014 _ 0F 85, 00009396 ----------------- and crashes.
        ...



Note that if a global label declared in a function were called from some other function, this would also cause a crash (and did right away in the case of my test program).

Function_A PROC
        sub     rsp, 8              ; rsp now points to an undefined value.
        ...
        call    some_global_label
A_next_instruction_address:       
        ...
Function_A ENDP

Function_B PROC
        ...
some_global_label::                ; Following the call, [rsp] holds 'A_next_instruction_address'.
        ...
        add     rsp, 8              ; Not anymore.
        ret                         ; [rsp] invalid value before the call is popped into rip.
Function_B ENDP
Linux Mint: from freedom came elegance.

aw27

I have not been playing with UASM under Linux lately, but a large work has been done not too long ago and a huge amount of bugs traced back to Japheth have been fixed.
On the other hand I don't find a normal behaviour to jump to global labels inside other functions. WTF!

johnsa

The assembler has no way of knowing what you're planning on doing, so for it to remove the sub/add rsp would be very problematic as under normal conditions that would definitely be required if the proc referenced any stack location/parameter, or made further calls.

I would think if you're trying to make some sort of jump table like this it would be better to avoid procs alltogether then and use some raw setup like:

Handler1:
  . . .
ret

Handler2:
...
ret

etc.. ?

Quicksort

I was not thinking it would be appropriate to remove the sub/add rsp,8 sequence (all the more so as "option prologue/epilogue: none" can be used to that purpose) but that this pseudo issue should be brought to Linux programmers' attention. My Window/Linux library's code does not rely on (or care about) stack alignment by 16, because all system calls are handled by cover functions which carry out the required stack setup (including shadow space allocation and additional stack parameters processing).

As for the jumps to global labels, or calls thereof, there are only a handful in my code and they are all performed to skip some functions' default setup instruction sequence.

Thanks for your feedback, johnsa.
Linux Mint: from freedom came elegance.