News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

A DWORD is a DWORD is a ... oh f***!

Started by jj2007, July 28, 2016, 06:35:57 PM

Previous topic - Next topic

jj2007

testme proc pText, pTitle
  invoke MessageBox, 0, pText, pTitle, MB_OK
  ret
testme endp


So simple, isn't it? But it won't work in 64-bit assembly: Both ML64 and the Watcom family insist that pText and pTitle are DWORDs, not QWORDs. Absolutely silly to use DWORD as default size for "unsized" arguments, but it's like that.

qWord

Quote from: jj2007 on July 28, 2016, 06:35:57 PMAbsolutely silly to use DWORD as default size for "unsized" arguments
It's silly to not specify the type. Even the default operand size is still 32 bit for x86-64.
MREAL macros - when you need floating point arithmetic while assembling!

jj2007

Quote from: qWord on July 29, 2016, 12:25:15 AMEven the default operand size is still 32 bit for x86-64.

Show me one x64 WinApi call that organises its stack as DWORDs...

qWord

CreateWindow,
SendMessage,
the WindowProc,
... and thousand others

BTW, this sentence was related to the ISA and not an OS.
MREAL macros - when you need floating point arithmetic while assembling!

jj2007

GCC-64, CreateWindowEx:
  CreateWindowEx, Gcc-64:
48 C7 44 24 58 00 00 00 00     | mov qword ptr ss:[rsp+58], 0                |+8....
48 C7 44 24 50 00 00 00 00     | mov qword ptr ss:[rsp+50], 0                |+8
48 C7 44 24 48 00 00 00 00     | mov qword ptr ss:[rsp+48], 0                |+8
48 C7 44 24 40 00 00 00 00     | mov qword ptr ss:[rsp+40], 0                |+8
C7 44 24 38 00 00 00 00        | mov dword ptr ss:[rsp+38], 0                |+8
C7 44 24 30 00 00 00 00        | mov dword ptr ss:[rsp+30], 0                |+8
C7 44 24 28 00 00 00 00        | mov dword ptr ss:[rsp+28], 0                |+8
C7 44 24 20 00 00 00 00        | mov dword ptr ss:[rsp+20], 0                |+0
41 B9 00 00 00 10              | mov r9d, 10000000                           |
4C 8D 05 6D 2A 00 00           | lea r8, qword ptr ds:[404000]               | 404000:"myTitle"
48 8D 15 6E 2A 00 00           | lea rdx, qword ptr ds:[404008]              | 404008:"myClass"
B9 00 02 00 00                 | mov ecx, 200                                |
FF 15 23 6E 00 00              | call qword ptr ds:[<&CreateWindowExA>]


Quote from: qWord on July 29, 2016, 12:36:16 AM
CreateWindow,
SendMessage,
the WindowProc,

CreateWindow, - see above
SendMessage, - HANDLE, WPARAM, LPARAM
the WindowProc, HANDLE, WPARAM, LPARAM

MSDN:
Quote9. The LPARAM, WPARAM, and LRESULT types change size with the platform.
When compiling 64-bit code, these types expand to 64 bits

qWord

jj, you are an cardsharper. You question was: show me one WinAPI call that takes a DWORD argument!

Regardless that, it does not change the fact the default operand size is 32 bit.
Just write out the types - thats it.
MREAL macros - when you need floating point arithmetic while assembling!

jj2007

Parameter Passing
QuoteThe first four integer arguments are passed in registers. Integer values are passed (in order left to right) in RCX, RDX, R8, and R9. Arguments five and higher are passed on the stack (JJ: at QWORD offsets). All arguments are right-justified in registers. This is done so the callee can ignore the upper bits of the register if need be and can access only the portion of the register necessary.

"the callee can ignore the upper bits of the register" - that is the only place where non-QWORD args come into play. Not often enough, though, to justify calling it a "default" 8)

But formally speaking, you may be right. Do you have a link to the "default operand size" definition?

qWord

It can be found in AMDs Manuals

Quote from: AMD Manuals, Application Programming64-Bit Addresses and Operands. In 64-bit mode, the default virtual-address size is 64 bits
(implementations can have fewer). The default operand size for most instructions is 32 bits. For most
instructions, these defaults can be overridden on an instruction-by-instruction basis using instruction
prefixes. REX prefixes specify the 64-bit operand size and register extensions.
MREAL macros - when you need floating point arithmetic while assembling!

nidud

#8
deleted

jj2007

Thanks for the helping hands ;-)

However, my post was about default arg sizes, not instruction sizes. As far as I can see, the stack (i.e. the args) is organised in QWORD, not DWORD, steps, and FASTCALL arguments are passed as QWORD, not DWORD, registers.

Anyway, this x64 ABI is one of the messiest exercises I've ever done in programming :(

nidud

#10
deleted

jj2007

Quote from: nidud on July 29, 2016, 03:05:36 AMthe stack-size is fixed but not the argument size.

Yes indeed. The problem at hand here is that 99% of all PROTOs in \Masm32\include\*.inc are DWORD size. To reuse them in X64 (that's what I do with my "no libraries" jinvoke macro), the only workable solution is to assume they are QWORDs now. This will cause headaches for C/C++ programmers, of course, but it works for API calls, simply because you can always fill the complete QWORD slot (or the four regs for the first 4 args).

What doesn't work so nicely is the "unsized" declaration in selfmade procedures. The assembler complains if you write mov rax, myarg. Not a big problem, though.

nidud

#12
deleted

hutch--

I think its fair to say that Win64 is a hotchpotch of Win32 left overs where all addressing is done in QWORD sizes and arguments sizes are all over the place. Combine this with a horrible ABI with its QWORD alignment and you have the formula for the scruffy mess that it is. If your pursuit of Win64 is driven by /LARGEADDRESSAWARE and very large available memory then the MS-DOS mentality of saving a few bytes here and there makes little sense, keep it simple, keep it consistent and spare yourself the complexity of endlessly chasing minor byte savings.

rrr314159

By the way, it's interesting to note that every problem you're having with 64-bit has to do with API calling conventions and include files. You don't have to deal with the Invoke / PROC / PROTO paradigm anywhere else. My approach: simply don't use these for your own work. It's an awful lot easier to go back to the good old days, and just "call" (or even "jmp"), and pass arguments any convenient way. C++ programmers will be horrified, but remember, they're not smart enough for assembler. You still have to deal with ABI to access API functions, but that's always going to involve stupid MS obfuscations anyway.

Looking at it like that, why not just let habran worry about this stuff? HJWasm takes care of the MS BS, and you can concentrate on assembler.
I am NaN ;)