ISSUE NUMBER ONE:
Let's consider the following code:
option casemap:none
;option frame:auto ; no AUTO
includelib \masm32\lib64\kernel32.lib
ExitProcess proto :dword
.code
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
proc2 proc FRAME par1:qword, par2:qword
db 048h
push rbp
.pushreg rbp
mov rbp, rsp
.setframe rbp, 0
sub rsp, 60h
.allocstack 60h
.endprolog
mov par1, rcx
mov par2, rdx
leave
ret
proc2 endp
OPTION PROLOGUE:PROLOGUEDEF
OPTION EPILOGUE:EPILOGUEDEF
proc1 proc FRAME par1:qword, par2:qword
db 048h
push rbp
.pushreg rbp
mov rbp, rsp
.setframe rbp, 0
sub rsp, 60h
.allocstack 60h
.endprolog
mov par1, rcx
mov par2, rdx
leave
ret
proc1 endp
main proc
sub rsp, 8
int 3
sub rsp, 20h
call proc1
call proc2
add rsp, 20h
add rsp, 8
mov ecx, 0
call ExitProcess
main endp
end
UASM
proc2
00000001`40001000 4855 push rbp
00000001`40001002 488bec mov rbp,rsp
00000001`40001005 4883ec60 sub rsp,60h
00000001`40001009 48894c2410 mov qword ptr [rsp+10h],rcx
00000001`4000100e 4889542418 mov qword ptr [rsp+18h],rdx
00000001`40001013 c9 leave
00000001`40001014 c3 ret
proc1
00000001`40001015 4855 push rbp
00000001`40001017 488bec mov rbp,rsp
00000001`4000101a 55 push rbp
00000001`4000101b 488bec mov rbp,rsp
00000001`4000101e 4883ec60 sub rsp,60h
00000001`40001022 48894d10 mov qword ptr [rbp+10h],rcx
00000001`40001026 48895518 mov qword ptr [rbp+18h],rdx
00000001`4000102a c9 leave
00000001`4000102b 5d pop rbp
00000001`4000102c c3 ret
MASM
proc2
00000001`40001000 4855 push rbp
00000001`40001002 488bec mov rbp,rsp
00000001`40001005 4883ec60 sub rsp,60h
00000001`40001009 48894d10 mov qword ptr [rbp+10h],rcx
00000001`4000100d 48895518 mov qword ptr [rbp+18h],rdx
00000001`40001011 c9 leave
proc1
00000001`40001012 4855 push rbp
00000001`40001014 488bec mov rbp,rsp
00000001`40001017 4883ec60 sub rsp,60h
00000001`4000101b 48894d10 mov qword ptr [rbp+10h],rcx
00000001`4000101f 48895518 mov qword ptr [rbp+18h],rdx
00000001`40001023 c9 leave
JWASM
proc2
00000001`40001000 4855 push rbp
00000001`40001002 488bec mov rbp,rsp
00000001`40001005 4883ec60 sub rsp,60h
00000001`40001009 48894d10 mov qword ptr [rbp+10h],rcx
00000001`4000100d 48895518 mov qword ptr [rbp+18h],rdx
00000001`40001011 c9 leave
00000001`40001012 c3 ret
proc1
00000001`40001013 4855 push rbp
00000001`40001015 488bec mov rbp,rsp
00000001`40001018 4883ec60 sub rsp,60h
00000001`4000101c 48894d10 mov qword ptr [rbp+10h],rcx
00000001`40001020 48895518 mov qword ptr [rbp+18h],rdx
00000001`40001024 c9 leave
00000001`40001025 c3 ret
In main proc UASM also unexpectedly adds sub rsp,8 but does not add rsp, 8 in the epilog.
As a side note, appears that MASM is also buggy because the RET after the LEAVE disappear.
ISSUE NUMBER TWO:
OPTION LITERALS:ON does not work when FRAME is not AUTO
Hi,
I'll check the literals with frame stuff shortly.
With regards to the example you've posted there are a couple of notes:
the add rsp,8 is missing because there is no RET after the exitprocess, RET is what triggers epilogue generation.
You can't mix custom prologue with a normal FRAME proc in uasm as you'll get duplicated prologue. If you're putting in custom prologue you need to use either option proc:none (which is shorthand for option prologue:none and option epilogue:none) or use a custom macro. FRAME in ML doesn't generate prologue which is why it has only the one copy.
Quote from: johnsa on October 16, 2017, 08:45:12 PM
You can't mix custom prologue with a normal FRAME proc in uasm as you'll get duplicated prologue. If you're putting in custom prologue you need to use either option proc:none (which is shorthand for option prologue:none and option epilogue:none) or use a custom macro. FRAME in ML doesn't generate prologue which is why it has only the one copy.
Things are becoming a bit confusing, particularly because FRAME without FRAME:AUTO should not work like that. It contradicts both MASM and JWASM, which deals very well with all this.
And how to fill the HOME Shadow space with the registers values if UASM keeps using the ESP as frame pointer after I set EBP as frame pointer? I don't see any way.
That first one was a bug in 2.42 which is now already fixed, it shouldn't have reverted to rsp in that case.
We forced all procs in 64bit to frame auto to simplify the number of options and to also remove the need to even use the frame keyword, so all procs are FRAME+FRAME:AUTO, unless you switch off prologue/epilogue to write your own "raw" proc. I always thought the whole FRAME thing was pretty pointless having to use it in combination with FRAME:AUTO etc. Why would you want anything but a frame proc or a raw proc ?
I'm happy to look at changing this behaviour if someone has a convincing argument :) I don't care about ML64 compatibility.
Do you have an example with the literals not working ? I've tried it this side without frame:auto and it's working.
Quote from: johnsa on October 16, 2017, 09:25:53 PM
I always thought the whole FRAME thing was pretty pointless
It is not pointless, don't despise the intelligence of people that have thought about that before you :(.
It is fundamental for the Exception Handling, something I am working at the moment. FRAME:AUTO is pointless for anything useful concerning Exception Handling. If you can't fix it, leave it but I can't use UASM as it is for that.
Good idea to dump something that is useless and confusing. What you are proposing is what I already do in 64 bit MASM, the choice of with or without a stack frame. It is useful to control the alignment as a user defined variable as it makes larger that 64 bit LOCAL variables viable by placing them at the top of the procedure. To simplify the usage, I have 2 basic wrapper types of macros,
STACKFRAME
NOSTACKFRAME
Quote from: aw27 on October 16, 2017, 09:34:42 PM
Quote from: johnsa on October 16, 2017, 09:25:53 PM
I always thought the whole FRAME thing was pretty pointless
It is not pointless, don't despise the intelligence of people that have thought about that before you :(.
It is fundamental for the Exception Handling, something I am working at the moment. FRAME:AUTO is pointless for anything useful concerning Exception Handling. If you can't fix it, leave it but I can't use UASM as it is for that.
FRAME will add the .pdata record, which is the default now even if you don't specify frame.. you can still use frame:<handler> if you need a custom one.
So what I'm saying is that you have full exception handling support built-in the prologue with all the pseudo-ops already, no need to add them manually.. unless you write a raw proc and have a specific requirement ?
Quote from: johnsa on October 16, 2017, 09:47:31 PM
Quote from: aw27 on October 16, 2017, 09:34:42 PM
Quote from: johnsa on October 16, 2017, 09:25:53 PM
I always thought the whole FRAME thing was pretty pointless
It is not pointless, don't despise the intelligence of people that have thought about that before you :(.
It is fundamental for the Exception Handling, something I am working at the moment. FRAME:AUTO is pointless for anything useful concerning Exception Handling. If you can't fix it, leave it but I can't use UASM as it is for that.
FRAME will add the .pdata record, which is the default now even if you don't specify frame.. you can still use frame:<handler> if you need a custom one.
So what I'm saying is that you have full exception handling support built-in the prologue with all the pseudo-ops already, no need to add them manually.. unless you write a raw proc and have a specific requirement ?
I need a handler, there is no default handler, so I need FRAME:<handler>. Simply embedding the .pdarta and .xdata does not solve anything because the exception should be handled somewhere and it is not without a handler.
exchdl proc FRAME pRecord:ptr EXCEPTION_RECORD64, ulframe:qword, pContext:ptr, x4:ptr
add qword ptr [r8].CONTEXT.Rip_, 1 ;1=size of "in EAX, DX" opcode
invoke printf, CStr("exception code: %X",10), [rcx].EXCEPTION_RECORD64.ExceptionCode
mov eax, 0 ;0=continue execution?
ret
exchdl endp
MyProc PROC FRAME:exchdl
.
; normal code
in eax, dx
.
MyProc ENDP
should work fine ? (without the need for pseudo ops)
deleted
Quote from: johnsa on October 16, 2017, 10:00:58 PM
should work fine ? (without the need for pseudo ops)
I just wonder why something that was working fine in JWASM does not now, I mean the pseudocodes. I have not fully tested the FRAME:AUTO for Exception Handling, however if I need to produce code that works both in MASM and UASM with minor changes, it is much more difficult using the FRAME:AUTO. And everybody knows that UASM is MASM compatible, it does not remove features only adds features.
Anyway, the major problem is indeed "if UASM keeps using the ESP as frame pointer after I set EBP as frame pointer", the others may be worked around.
I've updated the packages on the site dated today with all the fixes thus far, please test that out.
This works perfectly now for me:
option casemap:none
includelib c:\jwasm\wininc\lib64\kernel32.lib
ExitProcess proto :dword
.code
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
proc2 proc FRAME par1:qword, par2:qword
db 048h
push rbp
.pushreg rbp
mov rbp, rsp
.setframe rbp, 0
sub rsp, 60h
.allocstack 60h
.endprolog
mov par1, rcx
mov par2, rdx
leave
ret
proc2 endp
OPTION PROLOGUE:PROLOGUEDEF
OPTION EPILOGUE:EPILOGUEDEF
proc1 proc FRAME par1:qword, par2:qword
mov par1,rcx
mov par2,rdx
ret
proc1 endp
main proc
sub rsp,20h
call mainE
call proc1
call proc2
add rsp,20h
mov ecx,0
call ExitProcess
ret
main endp
ExceptionHandler proc
ret
ExceptionHandler endp
mainE proc frame:ExceptionHandler
ret
mainE endp
end
deleted
That last one works for me:
D:\HJWasm\Tests>c:\jwasm\uasm64 -c -win64 -Zp8 exc.asm
UASM v2.42, Oct 16 2017, Masm-compatible assembler.
Portions Copyright (c) 1992-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
exc.asm(2) : Warning A4095: Multiple .MODEL directives, .MODEL ignored
exc.asm: 28 lines, 3 passes, 1 ms, 1 warnings, 0 errors
D:\HJWasm\Tests>link /machine:x64 /subsystem:console exc.obj c:\jwasm\wininc\lib64\msvcrt.lib
Microsoft (R) Incremental Linker Version 14.10.25017.0
Copyright (C) Microsoft Corporation. All rights reserved.
D:\HJWasm\Tests>exc
ExceptionHandler called
D:\HJWasm\Tests>
I've removed the need for frame:auto to generate the .endprolog
as long as the proc is a frame proc, it will be automatically inserted, which is why the first example warns about the manually added one.
I feel sorry, but a few things are not getting better, actually on the contrary.
option frame:NOAUTO
......
; Error A2256: .ENDPROLOG found before EH directives
proc1 proc FRAME
db 048h
push rbp
.pushreg rbp
mov rbp, rsp
.setframe rbp, 0
.endprolog
ret
proc1 endp
www.terraspace.co.uk/uasm64.zip (http://www.terraspace.co.uk/uasm64.zip)
Try this one now.
The follow examples all work perfectly:
option casemap:none
option frame:NOAUTO
includelib c:\jwasm\wininc\lib64\kernel32.lib
ExitProcess proto :dword
.code
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
proc2 proc FRAME par1:qword, par2:qword
db 048h
push rbp
.pushreg rbp
mov rbp, rsp
.setframe rbp, 0
sub rsp, 60h
.allocstack 60h
.endprolog
mov par1, rcx
mov par2, rdx
leave
ret
proc2 endp
OPTION PROLOGUE:PROLOGUEDEF
OPTION EPILOGUE:EPILOGUEDEF
proc1 proc FRAME par1:qword, par2:qword
.endprolog
mov par1,rcx
mov par2,rdx
ret
proc1 endp
proc3 proc FRAME
db 048h
push rbp
.pushreg rbp
mov rbp, rsp
.setframe rbp, 0
.endprolog
ret
proc3 endp
main proc
sub rsp,20h
call mainE
call proc1
call proc2
add rsp,20h
mov ecx,0
call ExitProcess
ret
main endp
ExceptionHandler proc
ret
ExceptionHandler endp
mainE proc frame:ExceptionHandler
.endprolog
ret
mainE endp
end
and
.x64
.model flat, fastcall
option frame:auto
option dllimport:<msvcrt>
printf proto :ptr, :vararg
exit proto :dword
option dllimport:none
.data
string db "ExceptionHandler called",10,0
.code
ExceptionHandler PROC
invoke printf, addr string
invoke exit,0
ret
ExceptionHandler ENDP
main proc frame:ExceptionHandler
xor rax,rax
mov [rax],al
ret
main endp
end main
and
.x64
.model flat, fastcall
option dllimport:<msvcrt>
printf proto :ptr, :vararg
exit proto :dword
option dllimport:none
.data
string db "ExceptionHandler called",10,0
.code
ExceptionHandler PROC
invoke printf, addr string
invoke exit,0
ret
ExceptionHandler ENDP
main proc frame:ExceptionHandler
.endprolog
xor rax,rax
mov [rax],al
ret
main endp
end main
results:
D:\HJWasm\Tests>build
D:\HJWasm\Tests>uasm64 -c -nologo -less -Zi -Zd -win64 -Zp8 nid_frame.asm
nid_frame.asm(2) : Warning A4095: Multiple .MODEL directives, .MODEL ignored
nid_frame.asm: 1 warnings, 0 errors
D:\HJWasm\Tests>uasm64 -c -nologo -less -Zi -Zd -win64 -Zp8 nid_frame2.asm
nid_frame2.asm(2) : Warning A4095: Multiple .MODEL directives, .MODEL ignored
nid_frame2.asm: 1 warnings, 0 errors
D:\HJWasm\Tests>uasm64 -c -nologo -less -Zi -Zd -win64 -Zp8 aw27_frame.asm
aw27_frame.asm: ok
D:\HJWasm\Tests>"C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.10.25017\bin\HostX86\x64\link.exe" /subsystem:console /machine:x64 /Libpath:"d:\winsdk\v7.1\Lib\x64" nid_frame.obj msvcrt.lib
Microsoft (R) Incremental Linker Version 14.10.25017.0
Copyright (C) Microsoft Corporation. All rights reserved.
D:\HJWasm\Tests>"C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.10.25017\bin\HostX86\x64\link.exe" /subsystem:console /machine:x64 /Libpath:"d:\winsdk\v7.1\Lib\x64" nid_frame2.obj msvcrt.lib
Microsoft (R) Incremental Linker Version 14.10.25017.0
Copyright (C) Microsoft Corporation. All rights reserved.
D:\HJWasm\Tests>"C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.10.25017\bin\HostX86\x64\link.exe" /subsystem:console /machine:x64 /Libpath:"d:\winsdk\v7.1\Lib\x64" /entry:main aw27_frame.obj
Microsoft (R) Incremental Linker Version 14.10.25017.0
Copyright (C) Microsoft Corporation. All rights reserved.
D:\HJWasm\Tests>nid_frame
ExceptionHandler called
D:\HJWasm\Tests>nid_frame2
ExceptionHandler called
Did you have a chance to try that updated version yet?
John
Quote from: johnsa on October 20, 2017, 07:29:04 PM
Did you have a chance to try that updated version yet?
John
I had a look now at the first case you sport above.
I don't think it is what is needed, when FRAME is NOAUTO the function should be completely dumb and you make it a little smart. JWASM makes it dumb as well as MASM.
For example, for proc1 the listing of UASM is:
00000013 proc1 proc FRAME par1:qword, par2:qword
.endprolog
00000013 55 * push rbp
00000014 488BEC * mov rbp, rsp
00000017 48894D10 mov par1,rcx
0000001B 48895518 mov par2,rdx
0000001F ret
0000001F 5D * pop rbp
00000020 C3 * retn
JWASM does:
00000013 proc1 proc FRAME par1:qword, par2:qword
.endprolog
00000013 48894D10 mov par1,rcx
00000017 48895518 mov par2,rdx
0000001B ret
0000001B C3 * retn
You are pushing rbp after the prolog and this causes problems, for the unwinding in case of exception.
This is different from what would happen if you had not put FRAME.
Here MASM would put push rbp at least to align the stack. I did not check JWASM here, but I expect it to do the same.
Ok,
So I've set it so it won't attempt to add any prologue unless frame auto. in the case of this proc1 it obviously crashes, as par1/2 are not setup in terms of a stack frame. but the disasm is:
proc1 proc FRAME par1:qword, par2:qword
.endprolog
mov par1,rcx
00007FF71A1D1063 mov qword ptr [par1],rcx
mov par2,rdx
00007FF71A1D1067 mov qword ptr [par2],rdx
ret
00007FF71A1D106B ret
proc1 endp
Are you ok with that and the assumption that the crash is expected?
Quote from: johnsa on October 20, 2017, 09:30:57 PM
Are you ok with that and the assumption that the crash is expected?
With NOAUTO we need to handle the epilog. This is what JWASM does and it works well on this.
If you follow JWASM you will be good.
It must work without default Epilog and Prolog even if you don't set both to none.
This must not crash:
OPTION PROLOGUE:PROLOGUEDEF
OPTION EPILOGUE:EPILOGUEDEF
proc1 proc FRAME par1:qword, par2:qword
db 048h
push rbp
.pushreg rbp
mov rbp, rsp
.setframe rbp, 0
.endprolog
int 3
mov par1,rcx
mov par2,rdx
; epilog
leave
; or
;pop rbp
;mov rsp, rbp
ret
proc1 endp
This is how JWASM assembles it:
00000001`40001013 4855 push rbp
00000001`40001015 488bec mov rbp,rsp
;00000001`40001018 cc int 3
00000001`40001019 48894d10 mov qword ptr [rbp+10h],rcx
00000001`4000101d 48895518 mov qword ptr [rbp+18h],rdx
00000001`40001021 c9 leave
00000001`40001022 c3 ret
Test piece:
option casemap:none
option frame:NOAUTO
includelib c:\jwasm\wininc\lib64\kernel32.lib
ExitProcess proto :dword
.code
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
proc2 proc FRAME par1:qword, par2:qword
db 048h
push rbp
.pushreg rbp
mov rbp, rsp
.setframe rbp, 0
sub rsp, 60h
.allocstack 60h
.endprolog
mov par1, rcx
mov par2, rdx
leave
ret
proc2 endp
OPTION PROLOGUE:PROLOGUEDEF
OPTION EPILOGUE:EPILOGUEDEF
proc1 proc FRAME par1:qword, par2:qword
.endprolog
mov par1,rcx
mov par2,rdx
ret
proc1 endp
proc3 proc FRAME
db 048h
push rbp
.pushreg rbp
mov rbp, rsp
.setframe rbp, 0
.endprolog
ret
proc3 endp
proc4 proc FRAME par1:qword, par2:qword
db 048h
push rbp
.pushreg rbp
mov rbp, rsp
.setframe rbp, 0
sub rsp, 60h
.allocstack 60h
.endprolog
mov par1, rcx
mov par2, rdx
leave
ret
proc4 endp
main proc
sub rsp,20h
call mainE
;call proc1
call proc2
;call proc3
call proc4
add rsp,20h
mov ecx,0
call ExitProcess
ret
main endp
ExceptionHandler proc
ret
ExceptionHandler endp
mainE proc frame:ExceptionHandler
.endprolog
ret
mainE endp
end
From this..
1) proc1 will crash as no stack frame is setup. (I believe that should be the expected result)
2) proc2, mainE and proc4 work perfectly.
3) proc3 is a problem now however. As it has no locals and no arguments the assumption is that it should use FPO, therefor there is an extra sub rsp,8 and add rsp,8 in the proc.. which is meant to account for the lack of push rbp, which has been manually added. Given there is also no corresponding leave or pop rbp it crashes.
If we add the pop rbp everything works, however the stack is unaligned due to the sub and push combined.
I don't think there is anything I can do about that apart from having an option to disable FPO (like forceframe) or as the programmer you'd be expected to know that particular proc should be coded as FPO.
As mentioned earlier, if you compare what you get with UASM with what JWASM gets you will end fixing everything. In my opinion JWASM handles even better than MASM this stuff - MASM becomes confused when you use parameters in a procedure with FRAME (it should give error but does not and simply garbles things).
I don't thing you should add anything for Proc 3, the developer should do it in the prolog (i.e. sub rsp,8 followed by .allocstack 8 ), because if there is an exception, the exception handler will know it must unwind those bytes . The developer must also add manually the add rsp, 8 in the epilog.
Done :) 2.43 will be out shortly with this fix plus:
1) console colouring (just because it's funky)
2) new operators ARGIDX(arg) and ARGSIZE(arg) which tell you the size in bytes of a PROC parameter and it's ordinal (1.. n including varargs).
3) Using 2 a new macro in the library for use with SYSTEM V ABI to map a parameter (which is either in register or stack) to a local or equate referring to the stack as SYSTEMV ABI has no notion of shadow space.
4) Some new features and support for inline 128 records to and from memory or xmm regs.
Quote from: johnsa on October 21, 2017, 02:04:41 AM
4) Some new features and support for inline 128 records to and from memory or xmm regs.
What you have now is loading records, which is good.
But as records are becoming bigger and bigger, what about an internal macro to retrieve its fields? ;)
Will do. I believe the mask operator should be extended to support 128bits ... so next will be some macro or operator to extract a specified field. :)