News:

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

Main Menu

h2incx

Started by hutch--, September 09, 2016, 04:26:45 PM

Previous topic - Next topic

jj2007

#30
It is important to understand that Windows couldn't care less what your assembler or C++ compiler decides.
The structures that you are passing to a Windows function are being used in a DLL, and in front of that DLL is a sign saying "compilers, stay outta here!".

So if you pass a structure with your favourite alignment, and Windows expects another one, you are doomed.

Unfortunately, the MSDN documentation is either old and false (VS 6.0: the default for Win32 is 8 bytes, VS2003: "The default for this switch is /Zp8"), or new and misleading (VS 2015: "Visual C++ generally aligns data on natural boundaries based on the target processor and the size of the data, up to 4-byte boundaries on 32-bit processors, and 8-byte boundaries on 64-bit processors.")

More recently, Under "Using the Windows Headers", MSDN states:
QuoteThe header files for the Windows API enable you to create 32- and 64-bit applications.
...
Controlling Structure Packing
Projects should be compiled to use the default structure packing, which is currently 8 bytes

OKAY.... that was 8 bytes in 2003, 4 bytes "on 32-bit processors" in VS2015, and 8 bytes again for Win 8.1 ::)

So if you are a little bit uncertain, go the empirical route! Here is a test (32-bit and 64-bit executables attached) with a nasty structure:SHQUERYRBINFO STRUCT
cbSize         dd ?
i64Size        qword ?
i64NumItems    qword ?
SHQUERYRBINFO ENDS


include \Masm32\MasmBasic\Res\JBasic.inc      ; ## OPT_64 0 ; put 0 for 32 bit, 1 for 64 bit assembly ##
.data
qrb SHQUERYRBINFO <SHQUERYRBINFO, 0, 0>
Init
  PrintLine Chr$("This code was assembled with ", @AsmUsed$(1), " in ", jbit$, "-bit format")
  lea rax, qrb.i64Size
  lea rdx, qrb.cbSize
  sub rax, rdx
  deb 4, "offset i64Size - cbSize", rax
  .if rv(SHQueryRecycleBin, Chr$("C:"), addr qrb)
      Inkey Err$()
  .else
      Print Str$(" \nThere are %i elements in the recycle", dword ptr qrb.i64NumItems)
      Inkey Str$(" bin, and their total size is %i bytes\n\n", dword ptr qrb.i64Size)
  .endif
EndOfCode


Output:This code was assembled with HJWasm32 in 64-bit format
offset i64Size - cbSize rax     8

There are 2 elements in the recycle bin, and their total size is 4640 bytes

This code was assembled with HJWasm32 in 32-bit format
offset i64Size - cbSize rax     4

There are 2 elements in the recycle bin, and their total size is 4640 bytes


So it turns out that the correct alignment for 32-bit code on my 64-bit processor is 4 bytes, not 8. You can test it with -Zp8 for 32-bit code: SHQueryRecycleBin does not report an error, but you'll get 0 elements with 0 bytes.

Now the good news: By sheer coincidence, all other 17 or so structures in Windows.inc+WinExtra.inc that contain QWORDs have an even number of DWORDs before the QWORDs, so it doesn't matter whether you use -Zp4 or Zp8. Isn't that cute?

P.S.: One more good advice from Redmond, in /Zp (Struct Member Alignment), Visual Studio 2015:  "You should not use this option" :greensml:

hutch--

> Now the good news: By sheer coincidence, all other 17 or so structures in Windows.inc+WinExtra.inc that contain QWORDs have an even number of DWORDs before the QWORDs, so it doesn't matter whether you use -Zp4 or Zp8. Isn't that cute?

If you have a look at a WNDCLASSEX structure in Win64, you will see its done the same way, 8 byte aligned and doubled DWORD values to keep it that way.

PS: I should have added, the code generator is written in that "CrippleWare[tm]" Microsoft assembler as well. It really terrible to be crippled to only being able to build 64 bit EXE, DLL, OBJ in either console or UI applications.  :biggrin:

jj2007

Quote from: hutch-- on September 13, 2016, 08:44:23 AMPS: I should have added, the code generator is written in that "CrippleWare[tm]" Microsoft assembler as well. It really terrible to be crippled to only being able to build 64 bit EXE, DLL, OBJ in either console or UI applications.  :biggrin:

I didn't expect you to write in HJWasm, Hutch. You are an excellent programmer, you are able to code without proper HLL elements and without a valid invoke (one that validates parameters). The question is whether it's a solution for the not-so-brilliant coder who is tempted by going X64. By the way, will you port \Masm32\examples\exampl07\slickhuh\slickhuh.asm to \Masm32\examples64?

Quote from: hutch-- on September 13, 2016, 08:44:23 AMIf you have a look at a WNDCLASSEX structure in Win64, you will see its done the same way, 8 byte aligned and doubled DWORD values to keep it that way.

\Masm32\MasmBasic\Res\DualWin.inc:
WNDCLASSA STRUCT
  style             DWORD       ?   ; oops, Redmond forgot the dwReserved ;-)
  lpfnWndProc       SIZE_P      ?
  cbClsExtra        DWORD       ?
  cbWndExtra        DWORD       ?
  hInstance         SIZE_P      ?
  hIcon             SIZE_P      ?
  hCursor           SIZE_P      ?
  hbrBackground     SIZE_P      ?
  lpszMenuName      SIZE_P      ?
  lpszClassName     SIZE_P      ?
WNDCLASSA ENDS


Fails with an exception in Win64 - unless you use option -Zp8, of course (which RichMasm kindly takes care of :biggrin:).

hutch--

Thi should work as it is in 64 bit.

  WNDCLASSEXA STRUCT QWORD
    cbSize dd ?
    style dd ?
    lpfnWndProc dq ?
    cbClsExtra dd ?
    cbWndExtra dd ?
    hInstance dq ?
    hIcon dq ?
    hCursor dq ?
    hbrBackground dq ?
    lpszMenuName dq ?
    lpszClassName dq ?
    hIconSm dq ?
  WNDCLASSEXA ENDS

jj2007

Quote from: hutch-- on September 13, 2016, 08:17:26 PM
Thi should work as it is in 64 bit.

Sure it does. This version works in 64- and 32-bit code (\Masm32\MasmBasic\Res\DualWin.inc):WNDCLASSEXA STRUCT
  cbSize            DWORD      ?
  style             DWORD      ?
  lpfnWndProc       SIZE_P      ?
  cbClsExtra        DWORD      ?
  cbWndExtra        DWORD      ?
  hInstance         SIZE_P      ?
  hIcon             SIZE_P      ?
  hCursor           SIZE_P      ?
  hbrBackground     SIZE_P      ?
  lpszMenuName      SIZE_P      ?
  lpszClassName     SIZE_P      ?
  hIconSm           SIZE_P      ?
WNDCLASSEXA ENDS


But the point was a different one: In the example attached above, I used the older WNDCLASS (no EX) structure, which doesn't have the even number of DWORDs:WNDCLASSA STRUCT
  style             DWORD      ?
  lpfnWndProc       SIZE_P      ?
..
WNDCLASSA ENDS


And that one works fine if you build it with Zp4 for 32-bit and Zp8 for 64-bit code, but it crashes for X64 and Zp4.

Which means that the default structure alignment of the Windows API is DWORD in 32-bit code and QWORD in 64-bit code. Both on a 64-bit processor, of course (see Reply #30); Redmond should take their documentation a bit more seriously 8)

hutch--

The humour here is the old WNDCLASS is just a macro for the WNDCLASSEX for folks who want to use the old Win3.? format, it has not been a valid structure since the end of the 16 bit Windows days. Be thankful if you never had to write 16 bit Windows.  :biggrin:

jj2007

Quote from: hutch-- on September 13, 2016, 11:24:59 PM
The humour here is the old WNDCLASS is just a macro for the WNDCLASSEX for folks who want to use the old Win3.? format, it has not been a valid structure since the end of the 16 bit Windows days.

Interesting that it still works on Win7-64, see Reply #32.

Btw: "macro"? See \masm32\include\Windows.inc:
IFDEF __UNICODE__
    WNDCLASS  equ  <WNDCLASSW>
ELSE
    WNDCLASS  equ  <WNDCLASSA>
ENDIF


WNDCLASSA STRUCT
  style             DWORD      ?
  lpfnWndProc       DWORD      ?
..
WNDCLASSA ENDS