The MASM Forum Archive 2004 to 2012

Specialised Projects => Pelle's Macro Assembler Development => Topic started by: ramguru on June 07, 2009, 08:08:26 PM

Title: the simplest 64bit app won't start
Post by: ramguru on June 07, 2009, 08:08:26 PM
hey everyone, I want to make a new start in asm programming.
Decided to write only 64bit applications from now on.
So as I can see masm won't be a tool of my choice.
Now poasm seems to have some support, or maybe I'm wrong...


    includelib \POASM\lib64\user32.lib

MessageBoxA PROTO :QWORD,:QWORD,:QWORD,:DWORD
       
    .data
ALIGN 8
dlgname db "TESTWIN",0
    .code

start:
ALIGN 8
invoke MessageBoxA, 0, ADDR dlgname, ADDR dlgname, 5

end start


compiler/linker parameters:

C:\POASM\bin\poasm /AAMD64 "%1.asm"
C:\POASM\bin\polink /MACHINE:AMD64 /SUBSYSTEM:WINDOWS "%1.obj"


The code compiles fine w/o a single warning, but once I start the app it crashes. Could anyone help with that ? Maybe I'm doing impossible ?..
Title: Re: the simplest 64bit app won't start
Post by: GregL on June 07, 2009, 10:38:58 PM
ramguru,

You can use MASM for x64, the assembler is called ml64.exe.  There is some info about using it here (http://www.masm32.com/board/index.php?topic=10880.0).  In your code, you should set up the Parameter Stack Area, which requires that you allocate at least 4 QWORDS on the stack, C compilers allocate at least 5 QWORDS.  I haven't used POASM for x64 yet, so I'm only speaking from MASM experience.  One thing I found really helpful is to look at the dissassembly of an x64 executable from a C compiler.

Here is the dissassembly from a simple 'Hello World' C program:

#include <stdio.h>

int main(void)
{
000000013F081000  sub         rsp,28h
    printf("Hello x64 world!\n");
000000013F081004  lea         rcx,[__native_dllmain_reason-3Ch (13F083000h)]
000000013F08100B  call        qword ptr [__imp_printf (13F0820F8h)]
    return 0;
000000013F081016  xor         eax,eax
}
000000013F081018  add         rsp,28h
000000013F08101C  ret           



The rules: Calling Convention for x64 64-Bit Environments (http://msdn.microsoft.com/en-us/library/ms794533.aspx)


Title: Re: the simplest 64bit app won't start
Post by: drizz on June 07, 2009, 11:05:45 PM
ramguru,
Read about the stack in x64. It must be aligned at 16 at all times.
You can put "and rsp,-16" on start since it's the entrypoint but you're going to be calling functions read about param area like Greg said.

Greg,
Poasm is better than ml64, It has a very useful PARMAREA command, invoke WORKS, does not have "proc stack alignment bug" like masm etc.

the fifth qword makes the stack aligned at 16 bytes.

Here is how it works:
Upon entrypoint stack is misaligned because "call" puts return address on the stack which is 8bytes.
Your/Compiler duty is to make stack aligned after the prologue to be aligned at 16 again, taking into consideraction local variables and preserved registers. Do not push a single register before calling a proc because that will make the stack mislaigned again. Stack must be aligned at 16 at all times. If you use poasm and follow this rules you wont have any problems
Title: Re: the simplest 64bit app won't start
Post by: GregL on June 07, 2009, 11:30:46 PM
drizz,

Thanks for the good info.  :U

I'll have to give POASM a try with x64.

Title: Re: the simplest 64bit app won't start
Post by: BlackVortex on June 07, 2009, 11:35:00 PM
What about goasm ? Its 64bit support seems complete. I've never used it though.
Title: Re: the simplest 64bit app won't start
Post by: mitchi on June 08, 2009, 12:03:41 AM
And there is Sol_Asm too ! 64 bit worked perfectly last time I tried  :green
I'm really grateful to have good tools like this available to me.
Title: Re: the simplest 64bit app won't start
Post by: dedndave on June 08, 2009, 12:06:34 AM
i bet instructions like....
mov rax,7
or
mov al,7
must cause actual physical pain in 64-bit - lol

my eye twitches as it is, in 32-bit
Title: Re: the simplest 64bit app won't start
Post by: drizz on June 08, 2009, 12:08:53 AM
Heres a hello world for ramguru:
MessageBoxA PROTO :QWORD,:QWORD,:QWORD,:DWORD
MessageBox EQU <MessageBoxA>
ExitProcess PROTO :QWORD
       
.data
ALIGN 8
dlgname db "TESTWIN",0
.code

;; mainCRTStartup proc public; SUBSYSTEM:CONSOLE
;; WinMainCRTStartup proc public; SUBSYSTEM:WINDOWS

WinMainCRTStartup proc PARMAREA=4*QWORD;; MAX 4 arguments Are used in this proc
;push rax;;  DO NOT DO THIS, push 16 bytes or use locals
invoke MessageBox,0,ADDR dlgname,ADDR dlgname,5
;pop rax
invoke ExitProcess,rax
WinMainCRTStartup endp

end
Title: Re: the simplest 64bit app won't start
Post by: mitchi on June 08, 2009, 12:23:35 AM
I'm wondering when we'll get an x64 compiler from Intel  :bg
Title: Re: the simplest 64bit app won't start
Post by: Mark Jones on June 08, 2009, 01:27:28 AM
Welcome back Ramguru! :bg
Title: Re: the simplest 64bit app won't start
Post by: ramguru on June 08, 2009, 05:24:49 AM
Thank you  :U
Title: Re: the simplest 64bit app won't start
Post by: Vortex on June 08, 2009, 04:55:13 PM
Quote from: BlackVortex on June 07, 2009, 11:35:00 PM
What about goasm ? Its 64bit support seems complete. I've never used it though.

Jeremy's website (http://www.jorgon.freeserve.co.uk) has a tutorial on 64-bit programming.

The subtitle is : 64-bit programming using the "Go" tools
Title: Re: the simplest 64bit app won't start
Post by: ramguru on June 09, 2009, 01:07:49 PM
I'm kinda heaving a hard start :}
polink will complain about every global variable that is declared in .data section
f.e.

    .data
num1 dq 0FF00FF00FF00FF00h
    .code

WinMainCRTStartup proc PARMAREA=4*QWORD
LOCAL buf1[32]:BYTE

invoke dqtoa, num1, ADDR buf1

invoke MessageBoxA, 0, ADDR buf1, ADDR buf1, 0

WinMainCRTStartup endp

; main idea is nothing new:
; 1) divide by 10
; 2) append (remainder + '0') to string
; 3) shift string (because we appended from the end)
dqtoa proc num:QWORD, buf:QWORD

mov    rsi, 20 ; let's assume that our string cannot exceed 20 chars
mov    rdi, buf
mov    rax, num
mov    rcx, 10

@convert:
xor    rdx, rdx
test   rax, rax
jz     @done_convert
div    rcx
add    dl, '0'
mov    BYTE PTR [rdi+rsi], dl
dec    rsi
jmp    @convert
@done_convert:
mov    BYTE PTR [rdi+rsi], 0

mov    rcx, 20 
sub    rcx, rsi ; rcx - length of the string
inc    rsi      ; rsi - value by which we need to shift the string
@shift:
mov    al, BYTE PTR [rdi+rsi]
mov    BYTE PTR [rdi], al
test   al, al
jz     @done_shift
inc    rdi
jmp    @shift
@done_shift:
mov    rax, rcx
ret
dqtoa endp

produce the following error report:

POLINK: error: Relocation type ADDR32 is invalid without /LARGEADDRESSAWARE:NO, for symbol 'num1'.


But putting /LARGEADDRESSAWARE:NO means executable file cannot handle addresses above 2 GB which doesn't correspond to 64bit programming logic IMO (even though it compiles fine then :} )
Title: Re: the simplest 64bit app won't start
Post by: drizz on June 10, 2009, 12:54:01 PM
Hi ramguru

You should also read about "RIP-relative addressing"  :wink

change:
invoke dqtoa, num1, ADDR buf1
to
invoke dqtoa, num1[rip], ADDR buf1
Title: Re: the simplest 64bit app won't start
Post by: ecube on June 10, 2009, 07:12:52 PM
GoAsm 64bit support is beautiful, you can compile the same source for 32bit/64bit easily, example are here http://www.masm32.com/board/index.php?topic=11180.0, MASM64 is a joke btw, on so many levels. PoASM the author doesn't really care about Assembler, he's more C focused, GoASM is your best bet, I translated most my masm 32bit/64bit sources to GoASM and I couldn't be happier. Here's an example from the sdk

#DEFINE LINKFILES

;#Define WIN64 ;uncomment to enable for 64bit building
#include "\GoAsm\include\windows.h"

CODE SECTION

START:
#ifndef WIN64
    invoke MessageBox,0,"i'm running in 32bit!","i'm running in 32bit!",MB_ICONINFORMATION
#else
    invoke MessageBox,0,"i'm running in 64bit!","i'm running in 64bit!",MB_ICONINFORMATION
#endif
invoke ExitProcess,0
Title: Re: the simplest 64bit app won't start
Post by: ramguru on June 10, 2009, 07:31:42 PM
ha-ha actually I was focusing on goasm starting yesterday. Indeed it has the most complete & user friendly 64bit support. Though I have to say documentation could be neater :} .. and lack of examples (just invoke MessageBox), but that's allright..
BTW I've found another bad poasm (x64) feature that was the last drop :}
let's assume we have the following code:

foo proc bla1:QWORD, bla2:QWORD
   LOCAL hamster:QWORD

    ; bla1, bla2 are valid here
    invoke MessageBox,...
    ; bla1, bla2 become invalid here
    mov r10, bla1 ; --> mov r10, rcx
foo endp


It's simple really - poasm doesn't write any parameter to stack .. so they are lost if not preserved manually
Title: Re: the simplest 64bit app won't start
Post by: drizz on June 10, 2009, 07:39:51 PM
That's what param area is for....
Title: Re: the simplest 64bit app won't start
Post by: ramguru on June 10, 2009, 07:52:19 PM
So this is the actual code:

foo proc bla1:QWORD, bla2:QWORD PARMAREA=4*QWORD
LOCAL hamster:QWORD

mov    rcx, bla1
invoke MessageBox, 0, 0, 0, 0
mov    rcx, bla1

ret
foo endp

And this is it's disassembly

sub_140001028   proc near               ; CODE XREF: start+12
                sub     rsp, 38h
                mov     rcx, rcx
                mov     r9, 0           ; uType
                mov     r8, 0           ; lpCaption
                mov     rdx, 0          ; lpText
                mov     rcx, 0          ; hWnd
                call    MessageBoxA
                mov     rcx, rcx
                add     rsp, 38h
                retn
sub_140001028   endp



It's not like I haven't checked before stating my opinion..
Title: Re: the simplest 64bit app won't start
Post by: drizz on June 10, 2009, 10:07:44 PM
In ML64 arguments evaluate to stack and in poasm to Registers, so in ML64 you can save them with "mov bla1,rcx"
I don't know if there is an easy way to access param stack area with poasm, it's probably a good idea to ask Pelle about that.