News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Crashes in UASM 2.46.6

Started by mabdelouahab, January 08, 2018, 06:30:31 PM

Previous topic - Next topic

mabdelouahab

I got an error while trying to compile with the UASM64 V2.46.6 a code previously compiled with previous version of UASM64 with success.
p2 proc ar:qword
invoke MessageBoxW,0,0,0,0 ;<================== Crashe
ret
p2 endp
entry_point proc
invoke p2,0

With Uasm64 V2.46.6 (uasm64.EXE -c -win64 test.asm)
Quote
; --------------------------------------------------------------------------
; sub_140001d7c
; --------------------------------------------------------------------------
sub_140001d7c   proc
main:0000000140001d7c push rbp
main:0000000140001d7d mov rbp, rsp
main:0000000140001d80 sub rsp, 0x20
main:0000000140001d84 xor r9d, r9d
main:0000000140001d87 xor r8d, r8d
main:0000000140001d8a xor edx, edx
main:0000000140001d8c xor ecx, ecx
main:0000000140001d8e call _MessageBoxW
main:0000000140001d93 add rsp, 0x20
main:0000000140001d97 leave
main:0000000140001d98 ret
sub_140001d7c   endp

main:0000000140001d99 sub rsp, 0x20
main:0000000140001d9d xor ecx, ecx
main:0000000140001d9f call sub_140001d7c
With Uasm64 2.42 (success)
Quote
; --------------------------------------------------------------------------
; sub_140001dce
; --------------------------------------------------------------------------
sub_140001dce   proc
main:0000000140001dce sub rsp, 8
main:0000000140001dd2 sub rsp, 0x20
main:0000000140001dd6 xor r9d, r9d
main:0000000140001dd9 xor r8d, r8d
main:0000000140001ddc xor edx, edx
main:0000000140001dde xor ecx, ecx
main:0000000140001de0 call _MessageBoxW
main:0000000140001de5 add rsp, 0x20
main:0000000140001de9 add rsp, 8
main:0000000140001ded ret
sub_140001dce   endp

main:0000000140001dee sub rsp, 8
main:0000000140001df2 sub rsp, 0x20
main:0000000140001df6 xor ecx, ecx
main:0000000140001df8 call sub_140001dce
this is work whit UASM64 V2.46.6 :
   p2 proc ar:qword
      sub rsp,8
      invoke MessageBoxW,0,0,0,0
      ret
   p2 endp
   entry_point proc
      invoke p2,0

aw27

Let me put this in another angle:


includelib \masm32\lib64\msvcrt.lib
printf proto :ptr, :vararg
includelib \masm32\lib64\kernel32.lib
ExitProcess PROTO :DWORD

.data

_str0 db "Hello from UASM!",10,0

.code

main proc
invoke printf, addr _str0, 12
invoke ExitProcess,0
main endp

end


If we build with OPTION WIN64:3, UASM aligns the stack in main by doing sub rsp, 28h
If we don't use OPTION the stack in main stays not aligned, UASM simply does sub rsp, 20h.

As I mentioned somewhere, there was a time where things worked well, probably in "2.42 (success)"  :t

The problem is not what mabdelouahab mentions, the problem is that the stack came not aligned from the caller, the red note ammendement simply should not be needed.

johnsa


Ok... here is where I keep running into this issue..what works for one person/source doesn't work for another.. somewhere something has to give:

The sub rsp,8 was removed as we have a source with no proc frame, no win64 options set.

If I put it back in, this source works as one would expect and the automatic prologue accounts for the lack of push rbp / alignment and adds the sub rsp,8. But if I do that then another example from aw27 (which is now part of the regression tests no longer works or assembles the same as ML64) from the manual SEH test we then have this scenario:



; Case 8- Exception in a Leaf procedure, there is no Catch Block in caller,
; the exception will be passed to caller's parent, which in this case
; is main and the program will terminate normally.
proc8_1 PROC
hlt ; Prileged instruction.
ret
proc8_1 ENDP



This proc now includes a matched sub rsp,8 add rsp,8 logically as the stack would be unaligned, and it too is a non-frame, default proc no win64 option.. but with the add/sub rsp on this proc the example crashes.

Now one could argue the case that this proc shouldn't touch rsp at all because it's a leaf proc with no locals or parameters.. but how do we know this as the code inside the proc may not only use invokes..
1) Option A: this example should be wrapped in a prologue:none arrangement..
2) Option B: we need to come up with some really clever way to know we have a leaf proc.. so no invoke, no call..(possibly even no sneaky store return and jmp combination?)

aw27

I don't think we are talking about the same thing, in my example above, "main proc" is not a leaf function (also in the mabdelouahab example "entry_point proc" is not a leaf function) .
Note, however, that UASM does not have to align the stack, MASM does not align the stack, so UASM can proceed the same way. UASM, simply made us believe that it will handle it, when sometimes it does and other times it does not.

Now, about the leaf function. As mentioned, MASM does not align the stack, it expects us to do it, if we want (better we do when it is necessary :badgrin:). In the "proc8_1 PROC" example, I did not align the stack, because it would not make any difference, and if there was an exception it would unroll the same.

johnsa

The problem is, if you have the sub rsp,8 / add rsp,8 on your proc8_1 example it crashes.. so it must not generate the sub/add (why it crashes I don't know.. the sub/add shouldn't affect it but it does).
So in keeping with ML64, if we don't generate the sub/add there.. we also would not generate the sub/add on the main / entry_point examples either because technically the procedures are defined in an identical manner.

The only discriminating factor between them is the leaf/non leaf state given by whether the proc makes any further calls.
So my suggestion was whether we should put some logic in to identify the leafiness(tm) of the proc , perhaps just based on invoke.. then both cases can work..
proc8_1 would get no add/sub as it's a leaf
main/entry point example would as it's not a leaf

johnsa

Ok.. I've done it.. (added leaf tracking) based on just invokes for now.. if you're going to use lower level constructs I'll assume you know what you're doing and align the stack yourself.

So proc8_1 creates no sub/add rsp as it's a leaf.
the other examples like the main entry point are marked as not leaf and thus correct the alignment.

This did incur a change in one of the existing regression tests, but I personally feel the change is a good one (although it's different from jwasm and asmc output) :

SOURCE:


;--- invoke in 64-bit - ML64 will reject!

ifdef __JWASM__
.x64
.model flat, fastcall
endif

.data

rd real4 1.0
rq real8 1.0

.code

proc0 proc
ret
proc0 endp

proc1 proc p1:dword
ret
proc1 endp

proc2 proc p1:dword, p2:qword
ret
proc2 endp

proc3 proc p1:word, p2:qword, p3:qword
ret
proc3 endp

proc4 proc p1:byte, p2:word, p3:dword, p4:qword
ret
proc4 endp

proc5 proc p1:word, p2:word, p3:word, p4:word, p5:qword
ret
proc5 endp

proc6 proc p1:word, p2:word, p3:word, p4:word, p5:dword, p6:qword
ret
proc6 endp

proc7 proc p1:dword, p2:qword, p3:dword, p4:qword, p5:qword, p6:dword, p7:word
ret
proc7 endp

proc8 proc p1:dword, p2:real4, p3:real8, p4:byte
ret
proc8 endp


main proc
invoke proc0
invoke proc1, 1
invoke proc2, 1, 2
invoke proc3, 1, 2, 3
invoke proc4, 1, 2, 3, 4
invoke proc5, 1, 2, 3, 4, 5
invoke proc6, 1, 2, 3, 4, 5, 6
invoke proc7, 1, 2, 3, 4, 5, 6, 7
invoke proc8, 1, rd, rq, 4
invoke proc1, eax
;--- ecx is overwritten. This is checked since v2.04
; invoke proc2, 1, ecx
main endp

    END


BEFORE LEAF TRACKING:

Disassembly:
0:  c3                      ret
1:  55                      push   rbp
2:  48 8b ec                mov    rbp,rsp
5:  c9                      leave
6:  c3                      ret
7:  55                      push   rbp
8:  48 8b ec                mov    rbp,rsp
b:  c9                      leave
c:  c3                      ret
d:  55                      push   rbp
e:  48 8b ec                mov    rbp,rsp
11: c9                      leave
12: c3                      ret
13: 55                      push   rbp
14: 48 8b ec                mov    rbp,rsp
17: c9                      leave
18: c3                      ret
19: 55                      push   rbp
1a: 48 8b ec                mov    rbp,rsp
1d: c9                      leave
1e: c3                      ret
1f: 55                      push   rbp
20: 48 8b ec                mov    rbp,rsp
23: c9                      leave
24: c3                      ret
25: 55                      push   rbp
26: 48 8b ec                mov    rbp,rsp
29: c9                      leave
2a: c3                      ret
2b: 55                      push   rbp
2c: 48 8b ec                mov    rbp,rsp
2f: c9                      leave
30: c3                      ret
31: 48 83 ec 20             sub    rsp,0x20
35: e8 c6 ff ff ff          call   0x0
3a: 48 83 c4 20             add    rsp,0x20
3e: 48 83 ec 20             sub    rsp,0x20
42: b9 01 00 00 00          mov    ecx,0x1
47: e8 b5 ff ff ff          call   0x1
4c: 48 83 c4 20             add    rsp,0x20
50: 48 83 ec 20             sub    rsp,0x20
54: b9 01 00 00 00          mov    ecx,0x1
59: 48 c7 c2 02 00 00 00    mov    rdx,0x2
60: e8 a2 ff ff ff          call   0x7
65: 48 83 c4 20             add    rsp,0x20
69: 48 83 ec 20             sub    rsp,0x20
6d: 66 b9 01 00             mov    cx,0x1
71: 48 c7 c2 02 00 00 00    mov    rdx,0x2
78: 49 c7 c0 03 00 00 00    mov    r8,0x3
7f: e8 89 ff ff ff          call   0xd
84: 48 83 c4 20             add    rsp,0x20
88: 48 83 ec 20             sub    rsp,0x20
8c: b1 01                   mov    cl,0x1
8e: 66 ba 02 00             mov    dx,0x2
92: 41 b8 03 00 00 00       mov    r8d,0x3
98: 49 c7 c1 04 00 00 00    mov    r9,0x4
9f: e8 6f ff ff ff          call   0x13
a4: 48 83 c4 20             add    rsp,0x20
a8: 48 83 ec 30             sub    rsp,0x30
ac: 66 b9 01 00             mov    cx,0x1
b0: 66 ba 02 00             mov    dx,0x2
b4: 66 41 b8 03 00          mov    r8w,0x3
b9: 66 41 b9 04 00          mov    r9w,0x4
be: 48 c7 44 24 20 05 00    mov    QWORD PTR [rsp+0x20],0x5
c5: 00 00
c7: e8 4d ff ff ff          call   0x19
cc: 48 83 c4 30             add    rsp,0x30
d0: 48 83 ec 30             sub    rsp,0x30
d4: 66 b9 01 00             mov    cx,0x1
d8: 66 ba 02 00             mov    dx,0x2
dc: 66 41 b8 03 00          mov    r8w,0x3
e1: 66 41 b9 04 00          mov    r9w,0x4
e6: c7 44 24 20 05 00 00    mov    DWORD PTR [rsp+0x20],0x5
ed: 00
ee: 48 c7 44 24 28 06 00    mov    QWORD PTR [rsp+0x28],0x6
f5: 00 00
f7: e8 23 ff ff ff          call   0x1f
fc: 48 83 c4 30             add    rsp,0x30
100:    48 83 ec 40             sub    rsp,0x40
104:    b9 01 00 00 00          mov    ecx,0x1
109:    48 c7 c2 02 00 00 00    mov    rdx,0x2
110:    41 b8 03 00 00 00       mov    r8d,0x3
116:    49 c7 c1 04 00 00 00    mov    r9,0x4
11d:    48 c7 44 24 20 05 00    mov    QWORD PTR [rsp+0x20],0x5
124:    00 00
126:    c7 44 24 28 06 00 00    mov    DWORD PTR [rsp+0x28],0x6
12d:    00
12e:    66 c7 44 24 30 07 00    mov    WORD PTR [rsp+0x30],0x7
135:    e8 eb fe ff ff          call   0x25
13a:    48 83 c4 40             add    rsp,0x40
13e:    48 83 ec 20             sub    rsp,0x20
142:    b9 01 00 00 00          mov    ecx,0x1
147:    66 0f 6e 0d 31 00 00    movd   xmm1,DWORD PTR [rip+0x31]        # 0x180
14e:    00
14f:    f3 0f 7e 15 2d 00 00    movq   xmm2,QWORD PTR [rip+0x2d]        # 0x184
156:    00
157:    41 b1 04                mov    r9b,0x4
15a:    e8 cc fe ff ff          call   0x2b
15f:    48 83 c4 20             add    rsp,0x20
163:    48 83 ec 20             sub    rsp,0x20
167:    8b c8                   mov    ecx,eax
169:    e8 93 fe ff ff          call   0x1
16e:    48 83 c4 20             add    rsp,0x20


NOW:

Disassembly:
0:  c3                      ret
1:  55                      push   rbp
2:  48 8b ec                mov    rbp,rsp
5:  c9                      leave
6:  c3                      ret
7:  55                      push   rbp
8:  48 8b ec                mov    rbp,rsp
b:  c9                      leave
c:  c3                      ret
d:  55                      push   rbp
e:  48 8b ec                mov    rbp,rsp
11: c9                      leave
12: c3                      ret
13: 55                      push   rbp
14: 48 8b ec                mov    rbp,rsp
17: c9                      leave
18: c3                      ret
19: 55                      push   rbp
1a: 48 8b ec                mov    rbp,rsp
1d: c9                      leave
1e: c3                      ret
1f: 55                      push   rbp
20: 48 8b ec                mov    rbp,rsp
23: c9                      leave
24: c3                      ret
25: 55                      push   rbp
26: 48 8b ec                mov    rbp,rsp
29: c9                      leave
2a: c3                      ret
2b: 55                      push   rbp
2c: 48 8b ec                mov    rbp,rsp
2f: c9                      leave
30: c3                      ret
31: 48 83 ec 08             sub    rsp,0x8
35: 48 83 ec 20             sub    rsp,0x20
39: e8 c2 ff ff ff          call   0x0
3e: 48 83 c4 20             add    rsp,0x20
42: 48 83 ec 20             sub    rsp,0x20
46: b9 01 00 00 00          mov    ecx,0x1
4b: e8 b1 ff ff ff          call   0x1
50: 48 83 c4 20             add    rsp,0x20
54: 48 83 ec 20             sub    rsp,0x20
58: b9 01 00 00 00          mov    ecx,0x1
5d: 48 c7 c2 02 00 00 00    mov    rdx,0x2
64: e8 9e ff ff ff          call   0x7
69: 48 83 c4 20             add    rsp,0x20
6d: 48 83 ec 20             sub    rsp,0x20
71: 66 b9 01 00             mov    cx,0x1
75: 48 c7 c2 02 00 00 00    mov    rdx,0x2
7c: 49 c7 c0 03 00 00 00    mov    r8,0x3
83: e8 85 ff ff ff          call   0xd
88: 48 83 c4 20             add    rsp,0x20
8c: 48 83 ec 20             sub    rsp,0x20
90: b1 01                   mov    cl,0x1
92: 66 ba 02 00             mov    dx,0x2
96: 41 b8 03 00 00 00       mov    r8d,0x3
9c: 49 c7 c1 04 00 00 00    mov    r9,0x4
a3: e8 6b ff ff ff          call   0x13
a8: 48 83 c4 20             add    rsp,0x20
ac: 48 83 ec 30             sub    rsp,0x30
b0: 66 b9 01 00             mov    cx,0x1
b4: 66 ba 02 00             mov    dx,0x2
b8: 66 41 b8 03 00          mov    r8w,0x3
bd: 66 41 b9 04 00          mov    r9w,0x4
c2: 48 c7 44 24 20 05 00    mov    QWORD PTR [rsp+0x20],0x5
c9: 00 00
cb: e8 49 ff ff ff          call   0x19
d0: 48 83 c4 30             add    rsp,0x30
d4: 48 83 ec 30             sub    rsp,0x30
d8: 66 b9 01 00             mov    cx,0x1
dc: 66 ba 02 00             mov    dx,0x2
e0: 66 41 b8 03 00          mov    r8w,0x3
e5: 66 41 b9 04 00          mov    r9w,0x4
ea: c7 44 24 20 05 00 00    mov    DWORD PTR [rsp+0x20],0x5
f1: 00
f2: 48 c7 44 24 28 06 00    mov    QWORD PTR [rsp+0x28],0x6
f9: 00 00
fb: e8 1f ff ff ff          call   0x1f
100:    48 83 c4 30             add    rsp,0x30
104:    48 83 ec 40             sub    rsp,0x40
108:    b9 01 00 00 00          mov    ecx,0x1
10d:    48 c7 c2 02 00 00 00    mov    rdx,0x2
114:    41 b8 03 00 00 00       mov    r8d,0x3
11a:    49 c7 c1 04 00 00 00    mov    r9,0x4
121:    48 c7 44 24 20 05 00    mov    QWORD PTR [rsp+0x20],0x5
128:    00 00
12a:    c7 44 24 28 06 00 00    mov    DWORD PTR [rsp+0x28],0x6
131:    00
132:    66 c7 44 24 30 07 00    mov    WORD PTR [rsp+0x30],0x7
139:    e8 e7 fe ff ff          call   0x25
13e:    48 83 c4 40             add    rsp,0x40
142:    48 83 ec 20             sub    rsp,0x20
146:    b9 01 00 00 00          mov    ecx,0x1
14b:    66 0f 6e 0d 2d 00 00    movd   xmm1,DWORD PTR [rip+0x2d]        # 0x180
152:    00
153:    f3 0f 7e 15 29 00 00    movq   xmm2,QWORD PTR [rip+0x29]        # 0x184
15a:    00
15b:    41 b1 04                mov    r9b,0x4
15e:    e8 c8 fe ff ff          call   0x2b
163:    48 83 c4 20             add    rsp,0x20
167:    48 83 ec 20             sub    rsp,0x20
16b:    8b c8                   mov    ecx,eax
16d:    e8 8f fe ff ff          call   0x1
172:    48 83 c4 20             add    rsp,0x20


So now the main procedure aligns the stack properly.

aw27

Quote from: johnsa on January 08, 2018, 10:25:08 PM
The problem is, if you have the sub rsp,8 / add rsp,8 on your proc8_1 example it crashes.. so it must not generate the sub/add (why it crashes I don't know.. the sub/add shouldn't affect it but it does).
So in keeping with ML64, if we don't generate the sub/add there.. we also would not generate the sub/add on the main / entry_point examples either because technically the procedures are defined in an identical manner.

The only discriminating factor between them is the leaf/non leaf state given by whether the proc makes any further calls.

I have just tested the proc8_0 PROC/proc8_1 PROC and does not make any difference either for MASM or for UASM adding the sub rsp, 8 on the leaf. The exception is catched the same way.

BUT, when you use
OPTION FRAME:AUTO
OPTION WIN64:3

there is a sub rsp,8 added automatically to the leaf. It is stupid, but you can add another sub rsp,8 and again it will not make any difference as far as the exception is concerned-it will be catched the same way.

Quote
So my suggestion was whether we should put some logic in to identify the leafiness(tm) of the proc , perhaps just based on invoke.. then both cases can work..
proc8_1 would get no add/sub as it's a leaf
main/entry point example would as it's not a leaf

It does not hurt to always align a leaf (you already do it when OPTION WIN64:3 is selected), but you can as well check for calls, local variables and uses clauses to decide if it is a leaf.

aw27

The RULE is that a function MUST have the stack aligned at the point it calls another function independently of the callee being a leaf or not.
You were not complying with this RULE.

mabdelouahab

it crashes at proc1 (When we call MessageBoxA )

ifdef __JWASM__
.x64
.model flat, fastcall
endif
includelib kernel32
includelib user32
ExitProcess proto :vararg
MessageBoxA proto :vararg
.data

rd real4 1.0
rq real8 1.0

.code

proc0 proc
invoke MessageBoxA,0,0,0,0
ret
proc0 endp

proc1 proc p1:dword
invoke MessageBoxA,0,0,0,0
ret
proc1 endp

proc2 proc p1:dword, p2:qword
ret
proc2 endp

proc3 proc p1:word, p2:qword, p3:qword
ret
proc3 endp

proc4 proc p1:byte, p2:word, p3:dword, p4:qword
ret
proc4 endp

proc5 proc p1:word, p2:word, p3:word, p4:word, p5:qword
ret
proc5 endp

proc6 proc p1:word, p2:word, p3:word, p4:word, p5:dword, p6:qword
ret
proc6 endp

proc7 proc p1:dword, p2:qword, p3:dword, p4:qword, p5:qword, p6:dword, p7:word
ret
proc7 endp

proc8 proc p1:dword, p2:real4, p3:real8, p4:byte
ret
proc8 endp


entry_point proc
invoke proc0
invoke proc1, 1
invoke proc2, 1, 2
invoke proc3, 1, 2, 3
invoke proc4, 1, 2, 3, 4
invoke proc5, 1, 2, 3, 4, 5
invoke proc6, 1, 2, 3, 4, 5, 6
invoke proc7, 1, 2, 3, 4, 5, 6, 7
invoke proc8, 1, rd, rq, 4
invoke proc1, eax
invoke ExitProcess,0
;--- ecx is overwritten. This is checked since v2.04
; invoke proc2, 1, ecx
entry_point endp

    END

end 


Disassembly : proc0 and proc1

sub_140001000   proc
main:0000000140001000 sub rsp, 0x20
main:0000000140001004 xor r9d, r9d
main:0000000140001007 xor r8d, r8d
main:000000014000100a xor edx, edx
main:000000014000100c xor ecx, ecx
main:000000014000100e call _MessageBoxA
main:0000000140001013 add rsp, 0x20
main:0000000140001017 ret
sub_140001000   endp

; --------------------------------------------------------------------------
; sub_140001018
; --------------------------------------------------------------------------
sub_140001018   proc
main:0000000140001018 push rbp
main:0000000140001019 mov rbp, rsp
main:000000014000101c sub rsp, 0x20
main:0000000140001020 xor r9d, r9d
main:0000000140001023 xor r8d, r8d
main:0000000140001026 xor edx, edx
main:0000000140001028 xor ecx, ecx
main:000000014000102a call _MessageBoxA
main:000000014000102f add rsp, 0x20
main:0000000140001033 leave
main:0000000140001034 ret
sub_140001018   endp


Disassembly : entry_point


main:000000014000105f sub rsp, 0x20
main:0000000140001063 call sub_140001000
main:0000000140001068 add rsp, 0x20
main:000000014000106c sub rsp, 0x20
main:0000000140001070 mov ecx, 0x1
main:0000000140001075 call sub_140001018
main:000000014000107a add rsp, 0x20
main:000000014000107e sub rsp, 0x20
main:0000000140001082 mov ecx, 0x1
main:0000000140001087 mov rdx, 2
main:000000014000108e call sub_140001035


but it work with V2.42:

Disassembly : proc0 and proc1


sub_140001000   proc
main:0000000140001000 sub rsp, 8
main:0000000140001004 sub rsp, 0x20
main:0000000140001008 xor r9d, r9d
main:000000014000100b xor r8d, r8d
main:000000014000100e xor edx, edx
main:0000000140001010 xor ecx, ecx
main:0000000140001012 call _MessageBoxA
main:0000000140001017 add rsp, 0x20
main:000000014000101b add rsp, 8
main:000000014000101f ret
sub_140001000   endp

; --------------------------------------------------------------------------
; sub_140001020
; --------------------------------------------------------------------------
sub_140001020   proc
main:0000000140001020 sub rsp, 8
main:0000000140001024 sub rsp, 0x20
main:0000000140001028 xor r9d, r9d
main:000000014000102b xor r8d, r8d
main:000000014000102e xor edx, edx
main:0000000140001030 xor ecx, ecx
main:0000000140001032 call _MessageBoxA
main:0000000140001037 add rsp, 0x20
main:000000014000103b add rsp, 8
main:000000014000103f ret
sub_140001020   endp


Disassembly : entry_point


main:000000014000107f sub rsp, 8
main:0000000140001083 sub rsp, 0x20
main:0000000140001087 call sub_140001000
main:000000014000108c add rsp, 0x20
main:0000000140001090 sub rsp, 0x20
main:0000000140001094 mov ecx, 0x1
main:0000000140001099 call sub_140001020
main:000000014000109e add rsp, 0x20

johnsa

2.46.7 packages are updated now. Includes the new logic to test for and handle leaf procedures vs regular ones. It fixes this issue listed here while maintaining the compatibility and function of the regression tests and seh tests.

johnsa

The last post works now too with this build following the same alignment rules.

mabdelouahab


jj2007