News:

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

Main Menu

Difference between jwasm and uasm

Started by tastewar, August 28, 2019, 05:12:27 AM

Previous topic - Next topic

tastewar

I've tried to upload my source file, but wasn't allowed, so it's included below. I should note this isn't really a source file; rather, it's the output file from our own proprietary compiler. We are seeing differences between what jwasm produces and uasm, given the same command line. So, assembling with the following command line:

jwasm -elf64 -Zp8 -Sg -nologo -c -Sa -FlHelloWorld64.lst -FoHelloWorld64.o Main64.asm

Produces a few differences (if you substitute uasm in the call). The first seems minor; in the header jw produces an 'assume' line that includes gs:error whereas uasm specifies gs:nothing. But then what I believe is the source of our problem is that the jw version starts the PROC off with:

push rbp
mov rbp, rsp

where these lines are not to be found in the uasm output, and also a

leave

So it looks like jwasm sets up a normal stack frame under these conditions where uasm does not? Is this expected? Are there different arguments we should be passing to uasm to make it compatible with how jwasm worked? The external manifestation of this is that the program works as expected when assembled with jwasm, and seg faults immediately with uasm. Below is the text of the file Main64.asm:


;; ***************************************
;; *** @main argc,argv                 ***
;; *** Source: Main64.txt      Line: 1 ***
;; ***************************************

.DATA
                ALIGN           1
                DynamicString_Main64_1 BYTE "Hello World",0
.CODE

;; MST generated alignment code.

IFDEF MST_PROCALIGN

                ALIGN           MST_PROCALIGN

ENDIF

main PROC SYSCALL_ argc:QWORD,argv:QWORD
                SUB             RSP,16
                PUSH            RBX
                PUSH            R12
                PUSH            R13
                PUSH            R14
                PUSH            R15
                MOV             R15,[RBP]
                MOV             [RBP-16],R15
                MOV             R15,[RBP+8]
                MOV             [RBP-16+8],R15
                SUB             RBP,16
                mov             [rbp+16],rdi
                mov             [rbp+24],rsi

                ;; ***Code: (2) @C.printf{"Hello World"}

                printf          PROTO SYSCALL_:QWORD
                PUSH            RSI
                PUSH            RDI
                MOV             R12,RSI
                MOV             R13,RDI
                PUSH            RSP
                PUSH            QWORD PTR [RSP]
                AND             SPL,0F0h
                LEA             RDI,DynamicString_Main64_1
                XOR             RAX,RAX
                CALL            printf
                ADD             RSP,8
                POP             RSP
                POP             RDI
                POP             RSI
                POP             R15
                POP             R14
                POP             R13
                POP             R12
                POP             RBX
                ret             16
main ENDP

END


Thanks!

hutch--

In 64 bit JWASM was not properly Win64 ABI compliant, push / call is the correct method in Win32 but Win64 does not use this technique, it uses the first 4 registers then writes any further arguments to 64 bit aligned stack locations. UASM is properly Win64 ABI compliant and works correctly in 64 bit Windows. I do not use Linux so I am not familiar with how both work in any Linux distro.

KradMoonRa

UASM defaults for SYSVCALL on 64bits linux mac unix etc, so most of the stack is pre aligned.
For my test I still aint figured out why linker do not like the output produced by uasm wen using -fPIC and -shared, most of my code fails with seg fault wen linking uasm output with this new unix/linux GCC/clang  thing's, but some sussed wen removed from linking time, some run's others fails for miss stack alignment prediction.
The uasmlib

tastewar

I'm trying to understand why there's a difference between JWasm and UASM (Linux 64 bit). In my example, JWasm produces code that works, and UASM produces code that seg faults before calling printf. I'm trying to understand why there's a difference, whether it's intentional. If it's unintentional, is UASM "correct" where JWasm was wrong? If so, we may have to make modifications to our compiler that produces the .ASM file. But if not, perhaps there's a bug in UASM.

It seems much more likely that we're doing something incorrect here. Or it could be that there's a command line argument that I could assert to get the "old" (working!) behavior. hutch-- mentioned a difference in how calls are done, but the two assemblers produce identical code around the call to printf. It's the setup and teardown of the traditional x86 stack frame that is present in the JWasm output and missing from the UASM output that appears to me to be the main difference.

I'm going to try attaching a ZIP file (seems to be the only allowed format?) with the source file, and the two listing files.

Arguments passed to the assembler are in both cases;

-elf64 -Zp8 -Sg -nologo -c -Sa -FlHelloWorld64.lst -FoHelloWorld64.o Main64.asm

(I had just renamed the listing files for the purpose of zipping them up together)

LiaoMi

Quote from: tastewar on August 28, 2019, 10:51:48 PM
I'm trying to understand why there's a difference between JWasm and UASM (Linux 64 bit). In my example, JWasm produces code that works, and UASM produces code that seg faults before calling printf. I'm trying to understand why there's a difference, whether it's intentional. If it's unintentional, is UASM "correct" where JWasm was wrong? If so, we may have to make modifications to our compiler that produces the .ASM file. But if not, perhaps there's a bug in UASM.

It seems much more likely that we're doing something incorrect here. Or it could be that there's a command line argument that I could assert to get the "old" (working!) behavior. hutch-- mentioned a difference in how calls are done, but the two assemblers produce identical code around the call to printf. It's the setup and teardown of the traditional x86 stack frame that is present in the JWasm output and missing from the UASM output that appears to me to be the main difference.

I'm going to try attaching a ZIP file (seems to be the only allowed format?) with the source file, and the two listing files.

Arguments passed to the assembler are in both cases;

-elf64 -Zp8 -Sg -nologo -c -Sa -FlHelloWorld64.lst -FoHelloWorld64.o Main64.asm

(I had just renamed the listing files for the purpose of zipping them up together)

Hi tastewar,

the code differs only in the frame, the differences are shown in red .. there is no frame in UASM.


tastewar

Indeed, that's what I've already pointed out. I'm trying to understand if it's intentional, given that UASM started from the same code base. And assuming for the moment that it is intentional, is there a flag we could assert on the command line to get the old (jwasm/masm) behavior?

tastewar

Doing more searching on the web & forum, this thread seems relevant:

http://masm32.com/board/index.php?topic=6617.0

But I've tried OPTION FRAME:AUTO with no change in output.

fearless

What if you combine it with OPTION WIN64:11 (or OPTION WIN64:15) and/or also specify FRAME keyword after the PROC?

KradMoonRa

Probably this changes something, but the leave as truncated by pop rbp.



OPTION PROC:DEFAULT

;;;; Default Actually this ain't changing nothing because already the default with uasm 64bit mach unix linux
OPTION FRAME:AUTO
OPTION STACKBASE:RBP        ; RSP or RBP are supported options for the stackbase, RBP for SYSV linux frame auto.
OPTION WIN64:7              ; 11-15 for RSP and 1-7 for RBP.
OPTION LANGUAGE:SYSTEMV      ;;; this supposed to force call for entire file procedure, only if no one call already declared
;;;; DEFAULT END

;; ***************************************
;; *** @main argc,argv                 ***
;; *** Source: Main64.txt      Line: 1 ***
;; ***************************************

.DATA
                ALIGN           1
                DynamicString_Main64_1 BYTE "Hello World",0
.CODE

;; MST generated alignment code.

IFDEF MST_PROCALIGN

                ALIGN           MST_PROCALIGN

ENDIF

main PROC SYSTEMV argc:QWORD,argv:QWORD ;; here not specifiing the call later can be change above or force the call including SYSTEMV
                SUB             RSP,16
                PUSH            RBX
                PUSH            R12
                PUSH            R13
                PUSH            R14
                PUSH            R15
                MOV             R15,[RBP]
                MOV             [RBP-16],R15
                MOV             R15,[RBP+8]
                MOV             [RBP-16+8],R15
                SUB             RBP,16
                mov             [rbp+16],rdi
                mov             [rbp+24],rsi

                ;; ***Code: (2) @C.printf{"Hello World"}

                printf          PROTO SYSTEMV :PTR, :VARARG ;; were force the correct call
                PUSH            RSI
                PUSH            RDI
                MOV             R12,RSI
                MOV             R13,RDI
                PUSH            RSP
                PUSH            QWORD PTR [RSP]
                AND             SPL,0F0h
                LEA             RDI,DynamicString_Main64_1
                XOR             RAX,RAX
                CALL            printf
                ADD             RSP,8
                POP             RSP
                POP             RDI
                POP             RSI
                POP             R15
                POP             R14
                POP             R13
                POP             R12
                POP             RBX
                ADD             RSP,16 ;; restore stack alignment
                ret             16
main ENDP

END
The uasmlib

aw27

UASM defaults to RSP stack frame under Linux (simply look and you will see).
So, you must force RBP stack frame with OPTION STACKBASE:RBP if you want an RBP stack frame that should work like in Jwasm

DON'T EVER USE OPTION FRAME: AUTO, it has nothing to do with frame stack pointers, it has to do with exception handling. (Or use it, if you love to use things you don't understand).

KradMoonRa

Has I said, (64bits), linux, unix, machos, defaults to SYSTEMV or the 64bits syscall wai. (cdecl or c call or syscall or fastcall) ignored in 64 bits (windows, unix, linux, machos).
UASM defaults to generic rsp thing, wen using other convention than systemv. The thing breaks with miss stack convention.

So this is the same as using systemv with proc proto thing.

OPTION PROC:DEFAULT

;; ***************************************
;; *** @main argc,argv                 ***
;; *** Source: Main64.txt      Line: 1 ***
;; ***************************************

.DATA
                ALIGN           1
                DynamicString_Main64_1 BYTE "Hello World",0
.CODE

;; MST generated alignment code.

IFDEF MST_PROCALIGN

                ALIGN           MST_PROCALIGN

ENDIF

main PROC argc:QWORD,argv:QWORD ;; here not specifiing the call later can be change above or force the call including SYSTEMV
                SUB             RSP,16
                PUSH            RBX
                PUSH            R12
                PUSH            R13
                PUSH            R14
                PUSH            R15
                MOV             R15,[RBP]
                MOV             [RBP-16],R15
                MOV             R15,[RBP+8]
                MOV             [RBP-16+8],R15
                SUB             RBP,16
                mov             [rbp+16],rdi
                mov             [rbp+24],rsi

                ;; ***Code: (2) @C.printf{"Hello World"}

                printf          PROTO :PTR, :VARARG ;; were force the correct call
                PUSH            RSI
                PUSH            RDI
                MOV             R12,RSI
                MOV             R13,RDI
                PUSH            RSP
                PUSH            QWORD PTR [RSP]
                AND             SPL,0F0h
                LEA             RDI,DynamicString_Main64_1
                XOR             RAX,RAX
                CALL            printf
                ADD             RSP,8
                POP             RSP
                POP             RDI
                POP             RSI
                POP             R15
                POP             R14
                POP             R13
                POP             R12
                POP             RBX
                ADD             RSP,16 ;; restore stack alignment
                ret             16
main ENDP

END


And with all this, o got it all my code cleaned-up, systemv de facto a standard for all 64bits unix distros.
The uasmlib

tastewar

I've tried all these suggestions, but I don't get the stack frame generation like we do with jwasm with any of them. Perhaps I've misunderstood someone's suggestion. If you have a modification of my source that does produce the equivalent listing as jwasm (included in my .ZIP file), please post it! Apologies if I've misunderstood, and someone has solved this. For instance, I tried both WIN64 OPTIONs that fearless suggested, but din't know exactly what was meant by the FRAME part of the suggestion. Everything I tried resulted in a syntax error.

I *do* appreciate the suggestions!

hutch--

tastewar,

Find Agner Fog's data on calling conventions and see how a stack frame (if used) works in Linux. It is a bit different to Win64 and you need to understand the details but this will help you with the compiler you mentioned. You can soldier on with JWASM but its old and did not do 64 bit correctly.

aw27

Actually RBP based stackframe is the default, I thought not.

So this will build and run properly in UASM (but stack alignment was not done in this example).


;--- "hello world" for 64-bit Linux, using SYSCALL.
;--- assemble: UASM -elf64 -Fo=Lin64_1.o Lin64_1.asm
;--- link:     gcc Lin64_1.o -o Lin64_1

stdout    equ 1
SYS_WRITE equ 1
SYS_EXIT  equ 60

    .data

string  db 10,"Hello, world!",10

    .code

main proc
LOCAL myVar : dword
    mov myVar, 12
    mov edx, sizeof string
    mov rsi, offset string
    mov edi, stdout
    mov eax, SYS_WRITE
    syscall
    mov eax, SYS_EXIT
    syscall
main endp

    end main



00000000004004e0 <main>:
  4004e0:   55                      push   %rbp
  4004e1:   48 8b ec                mov    %rsp,%rbp
  4004e4:   48 83 ec 08             sub    $0x8,%rsp
  4004e8:   c7 45 fc 0c 00 00 00    movl   $0xc,-0x4(%rbp)
  4004ef:   ba 0f 00 00 00          mov    $0xf,%edx
  4004f4:   48 be 30 10 60 00 00    movabs $0x601030,%rsi
  4004fb:   00 00 00
  4004fe:   bf 01 00 00 00          mov    $0x1,%edi
  400503:   b8 01 00 00 00          mov    $0x1,%eax
  400508:   0f 05                   syscall
  40050a:   b8 3c 00 00 00          mov    $0x3c,%eax
  40050f:   0f 05                   syscall

or

00000000004004e0 <main>:
  4004e0:   55                      push   rbp
  4004e1:   48 8b ec                mov    rbp,rsp
  4004e4:   48 83 ec 08             sub    rsp,0x8
  4004e8:   c7 45 fc 0c 00 00 00    mov    DWORD PTR [rbp-0x4],0xc
  4004ef:   ba 0f 00 00 00          mov    edx,0xf
  4004f4:   48 be 30 10 60 00 00    movabs rsi,0x601030
  4004fb:   00 00 00
  4004fe:   bf 01 00 00 00          mov    edi,0x1
  400503:   b8 01 00 00 00          mov    eax,0x1
  400508:   0f 05                   syscall
  40050a:   b8 3c 00 00 00          mov    eax,0x3c
  40050f:   0f 05                   syscall

KradMoonRa

#14
Gonna test force removing the frame for the proc. And see if it removes the rbp thing.
Interesting the
OPTION FRAME:NOAUTO
OPTION STACKBASE:RSP

Error A2258: Missing FRAME in PROC, no unwind code will be generated

https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI

reading and researching the code....

Quote
The conventional use of %rbp as a frame pointer for the stack frame may be avoided by using
The 128-byte area beyond the location pointed to by %rsp is considered to
be reserved and shall not be modified by signal or interrupt handlers.10 Therefore,
functions may use this area for temporary data that is not needed across function
calls. In particular, leaf functions may use this area for their entire stack frame,
rather than adjusting the stack pointer in the prologue and epilogue. This area is
known as the red zone.

has syscall instruction leaves in kernel, were kernel (The Linux kernel does not honor the red zone and therefore this
area is not allowed to be used by kernel code
)

I also don't like frame with proc, but if not required, the best thing is calling the necessary code outside the main or not, depends programmer heaven, if has I with linux, we can directly use syscal instruction, and remove the extra stack save/push for the printf. Has with windows don't allow use the kernel directly.

@tastewar Dono wath version's  You are using, so with uasm if some of the options fails with syntax error, remove it and retry.
The uasmlib