News:

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

Main Menu

Help understanding 64 bit MASM

Started by ddalgleish, March 01, 2015, 06:02:39 AM

Previous topic - Next topic

ddalgleish

I'm somewhat new to assembly language so bear with me here.  The following is my attempt to write a simple "Hello World" program.

GetStdHandle PROTO STDCALL :DWORD
WriteFile    PROTO STDCALL :DWORD, :DWORD, :DWORD, :DWORD, :DWORD
.DATA
hOut DQ ?
hIn DQ ?
charwritten DD ?
string DB "Hello World!"
numchars DQ 12D
.CODE
main PROC
   ;
   ; Get standard input handle
   mov rcx, -10D
   sub rsp, 4*8
   Call GetStdHandle
   add rsp, 4*8
   mov hIn, rax
   mov rcx, 0
   ;
   ; Get standard output handle
   mov rcx, -11D
   sub rsp, 4*8
   Call GetStdHandle
   add rsp, 4*8
   mov hOut, rax
   ;
   ;
   ;PUSH 0
   ;PUSH 0
   ;PUSH numchars
   ;LEA RAX, string
   ;PUSH RAX
   ;PUSH hOut
   PUSH 0
   mov r9, 0
   mov r8, numchars
   LEA rax, string
   mov rdx, rax
   mov rcx,hOut
   sub rsp, 5*8
   Call WriteFile
   add rsp, 1*8
   XOR RAX, RAX
   mov rcx, 0
   RET
main ENDP
END


The program does not exit and just stands by.  If I reorder the two blocks of code where I am getting my standard input and output handle, the program will continuously output Hello World for what appears to be forever.

Could someone please advise on whether I am properly making function calls?

qWord

You must take care of stack alignment, which must be 16 when calling a function. Its a common practice to setup the stack only once on function entry where allocating stack-space that is sufficient for all further calls.
Also, even if doesn't matter here, the prototypes are wrong.

GetStdHandle PROTO :DWORD
WriteFile    PROTO :QWORD, :QWORD, :DWORD, :QWORD, :QWORD
ExitProcess  PROTO :DWORD

.DATA
    hOut        QWORD   ?
    ; hIn         QWORD   ?
    charwritten DWORD   ?
    string      BYTE    "Hello World!",0    ; <- termination zero
    numchars    DWORD   12                  ; decimal is default!!
.CODE
main PROC               ; stack is misaligned by 8 on entry
   
   sub rsp, 5*8         ; setup stack
   
   ; mov ecx, -10
   ; Call GetStdHandle
   ; mov hIn, rax

   mov ecx, -11
   Call GetStdHandle
   mov hOut, rax

   xor r9, r9           ; zero 4th argument
   mov [rsp+4*8],r9     ; zero 5th argument
   mov r8d, numchars
   lea rdx, string
   mov rcx,rax          ; rax already contains hOut

   Call WriteFile

   xor ecx,ecx
   call ExitProcess     ; preferred way to exit program
   
   ; add rsp,5*8
   ; xor eax,eax
   ; ret
   
main ENDP
END
MREAL macros - when you need floating point arithmetic while assembling!

ddalgleish

Okay this makes sense now.

So just to confirm.  Basically you say "In my program, the program with the most inputs has 5 inputs (WriteFile).  I have my return address on the stack (8 bytes) already so 5*8 bytes will reserve enough memory on my stack while at the same time making it 16 byte algined (48 bytes total).  Correct?

qWord

Quote from: ddalgleish on March 01, 2015, 08:52:05 AMBasically you say "In my program, the program with the most inputs has 5 inputs (WriteFile).  I have my return address on the stack (8 bytes) already so 5*8 bytes will reserve enough memory on my stack while at the same time making it 16 byte algined (48 bytes total).  Correct?
yes.
MREAL macros - when you need floating point arithmetic while assembling!

ddalgleish

New question:

What would be the difference between using say:
GetStdHandle PROTO :DWORD
and
EXTERN GetStdHAndle:PROC

The reason I am asking is because I don't think I can use PROTO with sprintf.  So I am assuming I have to use EXTERN for that.

dedndave

extern tells the assembler there is an external symbol with that name
it allows it to resolve the name during assembly for a symbol that is otherwise undefined

proto also tells the assembler how many and what size the arguments are
these values are used for type checking when using INVOKE
it may define an otherwise undefined symbol, as extern does

by the way, welcome to the forum   :t
i know someone with that name and initial, her name is Denise   :P

ddalgleish

One more clarification:

All pointers to memory and windows handles are all qwords in 64 bit correct?

And to dave, yes there a few Dalgleish's on the internet.  Either my uncle David or your Denise must be stealing my usernames because sometimes its already taken on certain websites  :lol:

dedndave

Quote from: ddalgleish on March 02, 2015, 04:33:29 AM
All pointers to memory and windows handles are all qwords in 64 bit correct?

i believe both are true - the addresses for sure

rrr314159

Not completely sure what's being referred to, but if I understand correctly: no, u can have DWORD addresses if linker option /LARGEADDRESSAWARE:NO is used. For instance here's a perfectly legal statement I just typed a moment ago:

mov [esp-8], rax

As for handles, the word is used by OS in many different contexts but it's always typedef ptr or (equivalently, re # bytes) typedef QWORD. Which is funny since often a handle has a value such as 1ch ... fits in 8 bits, never mind 8 bytes!

BTW here's a quote from hutch, circa 2012
QuoteThe NO HOMEWORK Rule.
9. The forum is a technical help forum for assembler language programmers, it will not be used as a location for grovelling to get someone to do your homework. Members who are learning assembler programming at school or similar are welcome but they must do their own work. In this context they will receive assistance if they need it but any dumping of problems in the forum will be removed.
As a former teacher I care about students who play by the rules, work hard to understand, but get C's because of grading on a curve against other students who don't.

Finally, that's a great gamma prog u just posted on another thread, thanks for the lesson ...


I am NaN ;)

ddalgleish

rrr, thanks for the calrification on the typedef.

As for the quote on homework and philosophy on C students.  You lost me.  I'm just an engineer who wants to learn assembly on their free time.

Also, what gamma function? :lol:

dedndave

i haven't had the chance to play with 64-bit code, much
so - i prefer to leave it to those who have
i just noticed your questions were going unanswered (slow day in here)
so i tried to help - seems to me that addesses and handles should be 64-bits   :P
you could probably look at some of the other 64-bit code in the forum and figure it out

the gamma program he's talking about is from another thread...

http://masm32.com/board/index.php?topic=4052.msg42784#msg42784

ddalgleish

Well I appreciate the help from the both of you.

I feel like the more assembly programming I try to understand, the better I understand C.  So I think I will continue to ask questions in the future.  :biggrin:

qWord

Quote from: rrr314159 on March 02, 2015, 02:14:47 PM
Not completely sure what's being referred to, but if I understand correctly: no, u can have DWORD addresses if linker option /LARGEADDRESSAWARE:NO is used. For instance here's a perfectly legal statement I just typed a moment ago:

mov [esp-8], rax
I guess your explanation is a bit misdirecting, because IMU the main usage for that option is to allow 32bit immediate values for SIB addressing (so the base address is 32bit, absolute). Otherwise the default is RIP-relative addressing.
Also, above instruction requires an address size overwrite prefix.
MREAL macros - when you need floating point arithmetic while assembling!

rrr314159

Hello ddalgleish,

Sorry, sounded like homework to me, being 3 rather disconnected q's; but that's alright, forget I said anything about it.

Now, the reason I use LARGEADDRESSAWARE:NO is to allow 32-bit addresses, in various contexts. If I don't I get a linker error such as " LNK2017: 'ADDR32′ relocation to '.rdata' invalid without /LARGEADDRESSAWARE:NO ". There are other ways to deal with this (you can learn about them by googling that link error), but since I'm not accessing data above 2 gig (or even 1 gig) this seems fine. For example, I recently posted a tokenizing algo in the Laboratory which stores the addresses of each line of a text file, into a table. Those addresses could be qwords but instead I use dwords (saves space; the number of lines could be many millions). I *think* this works only with that linker option. To store RIP-relative addresses in such a situation must be possible but very clumsy; you could also store offsets from the base of the in-memory text, and add the offset to the base when using the address; but my solution seems simpler. I haven't researched the issue much, am no expert (like, for instance, qWord); but I know - from daily experience - that you can use 32-bit (absolute, not relative) pointers to memory with 64-bit MASM or JWasm. And this is clearly relevant to the Original Question:

QuoteAll pointers to memory and windows handles are all qwords in 64 bit correct?

- Prima facie, the answer is no for pointers (yes for handles).

qWord:
QuoteAlso, above instruction requires an address size overwrite prefix.

That's true, and a (minor, I *think*) negative. I often use 64-bit addresses also, BTW. But in two situations, both very common for me, it seems worth it. One, converting 32-bit code: when convenient I just leave the 32-bit addresses as they are. Two, large lookup tables: you save half the space.

Sorry ddalgeish, u probably weren't interested in these arcane details. And, I didn't mean to imply I know all about this issue; could well be my approach is not the best. But, to answer your question with complete accuracy, this issue does arise.
I am NaN ;)

qWord

Quote from: rrr314159 on March 03, 2015, 06:57:08 AMThose addresses could be qwords but instead I use dwords (saves space; the number of lines could be many millions). I *think* this works only with that linker option
I think so.

Quote from: rrr314159 on March 03, 2015, 06:57:08 AM
- Prima facie, the answer is no for pointers (yes for handles).
In context to the WinAPI pointers are 64 bit width. You picked out a special case, which is effectively (AFAICS) only available to Assembler programmers.
MREAL macros - when you need floating point arithmetic while assembling!