News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

SIZE OF PAINTSTRUCT in x64

Started by jorgon, October 19, 2006, 10:35:54 AM

Previous topic - Next topic

jorgon

When running XP Professional x64 edition the system wrote an extra 4 bytes to PAINTSTRUCT than the number expected.
This happened upon WM_PAINT after the API GetOpenFileNameW returned (user having chosen a file).

I had assumed that the 64-bit version of PAINTSTRUCT was as follows:-

PAINTSTRUCT STRUCT
            DQ 0      ;+0 hDC
            DD 0      ;+8 fErase
      left  DD 0      ;+C  left   )
       top  DD 0      ;+10 top    ) RECT
     right  DD 0      ;+14 right  )
    bottom  DD 0      ;+18 bottom )
            DD 0      ;+1C fRestore
            DD 0      ;+20 fIncUpdate
            DB 32 DUP 0   ;+24 rgbReserved
ENDS

This would give a size of 68 bytes.
However the system wrote into 72 bytes.
I discovered this when I found that the next dword in data was being written over.

I just wondered if anyone else had encountered this. 
I have not yet installed Vista and I wondered if this was a querk in x64.

If an extra 4 bytes is required in this structure, I'm not too sure exactly where it is.  I am sure the RECT structure is correctly positioned at +0Ch (this tests ok in Hello64World2 which is part of GoAsm).  So it may be just before the rgbReserved field to align that field on a qword boundary, or maybe that field has been extended to 36 bytes and we haven't been told about it.
Author of the "Go" tools (GoAsm, GoLink, GoRC, GoBug)

Relvinian

Quote from: jorgon on October 19, 2006, 10:35:54 AM

I had assumed that the 64-bit version of PAINTSTRUCT was as follows:-

PAINTSTRUCT STRUCT
            DQ 0      ;+0 hDC
            DD 0      ;+8 fErase
      left  DD 0      ;+C  left   )
       top  DD 0      ;+10 top    ) RECT
     right  DD 0      ;+14 right  )
    bottom  DD 0      ;+18 bottom )
            DD 0      ;+1C fRestore
            DD 0      ;+20 fIncUpdate
            DB 32 DUP 0   ;+24 rgbReserved
ENDS



I show the following for PAINTSTRUCT from the Visual Studio 2005 .NET developer's Edition:

typedef struct tagPAINTSTRUCT {
    HDC         hdc;    ; 4-bytes in Win32  and 8-bytes in Win64
    BOOL        fErase;
    RECT        rcPaint;  ; 16-bytes in both Win32/Win64
    BOOL        fRestore;
    BOOL        fIncUpdate;
    BYTE        rgbReserved[32];
} PAINTSTRUCT, *PPAINTSTRUCT, *NPPAINTSTRUCT, *LPPAINTSTRUCT;


Size of the structure is 64-byte in length (for a Win32 system) and 68-bytes in length (for a Win64) system. But one thing you have to remember about Windows is that all their structures are divisible by 4 (for Win32) or divisible by 8 (for Win64).  So make sure you pad your structures in ASM to that amount.

The only time you don't have do to somthing like is this if the first member variable of the structure is the size of the structure.

Relvinian

P1

Align 8 in the data section would fix a move by eight problem.  Provided is a OS thing.  And is this observable with other structures?

But I read somewhere, that 64bit and/or (???) Vista would need paragraph alignment of 16 for data and code.

Regards,  P1  :8)

EduardoS

The calling convention in Vista says stack should always be 16 bytes aligned, for SSE code, and pointers returned by allocs are always 16 bytes aligned too... But i never heard about others...

jorgon

Thanks everyone for your answers.

Relvinian, your answer caused me to look again at the Microsoft document SWConventions.doc (my copy is 1 May 2005) which sets out the x64 spec.
You are quite right and I quote from the document:-
QuoteStructure size must be an integral multiple of its alignment, which may require padding after the last member. Since structures and unions can be grouped in arrays, each array element of a structure or union must begin and end at the proper alignment previously determined.

an example is given:-

Example 2
struct S2 { // size = 24 bytes, alignment = 8 bytes
int a;
double b;
short c;
};

which is shown graphically as having 4 bytes of padding after the dword at "a" (for correct alignment of the qword at "b") and 6 bytes of padding after the word at "c" (to bring the total size of the structure up to 24 bytes ie. divisible by 8 being the natural alignment of the whole structure).

It seems clear from what happened to me that x64 was using the padding as a expected data area, and writing to it.

I shall need to ensure that structures used in GoAsm (64-bit) are always automatically padded to the correct size.  I'll work on it.

QuoteThe calling convention in Vista says stack should always be 16 bytes aligned, for SSE code

This is another thing, and when INVOKE is used, GoAsm automatically aligns the stack properly ready for the call.  This is a significant feature because it frees the assembler programmer from any concerns about stack alignment.  It means that you can call APIs from anywhere in your code without having to worry whether the call is from a "frame" or a "leaf" function.
Author of the "Go" tools (GoAsm, GoLink, GoRC, GoBug)

P1

Quote from: jorgon on October 21, 2006, 09:28:46 AMwhich is shown graphically as having 4 bytes of padding after the dword at "a" (for correct alignment of the qword at "b") and 6 bytes of padding after the word at "c" (to bring the total size of the structure up to 24 bytes ie. divisible by 8 being the natural alignment of the whole structure).
But your problem above, does not show this behavior for structure elements, but for the structure as a whole.

Regards,  P1  :8)

jorgon

QuoteBut your problem above, does not show this behavior for structure elements, but for the structure as a whole.

Yes, I know.  That's what surprised me. 
I was aware of the need to align the structure members on their natural boundary, just as you would need to do with any data in Win64.  That is achieved by aligning the structure itself (when used) to the appropriate boundary (ie. the natural boundary of the largest member), and by inserting padding in the structure itself (when declared) just before the structure member if necessary.

What I didn't expect was that the system would use any subsequent padding for its own purposes.  This means that the structure when declared must include such padding.  Otherwise the user might be tempted as I was to use the space after the structure to hold an old fashioned dword which could be overwritten by the system.

So in Win64 the MSG structure should now be 48 bytes:-

MSG      DQ 0         ;+0h hWnd
         DD 0         ;+8h message
         DD 0         ;padding for next
         DQ 0         ;+10h wParam
         DQ 0         ;+18h lParam
         DD 0         ;+20h time
         DD 0         ;+24h 1st part of point structure
         DD 0         ;+28h 2nd part of point structure
         DD 0         ;+2Ch padding to bring the overall size to 48 bytes



Author of the "Go" tools (GoAsm, GoLink, GoRC, GoBug)

jorgon

QuoteI shall need to ensure that structures used in GoAsm (64-bit) are always automatically padded to the correct size.  I'll work on it.

This has now been added to the very latest version of GoAsm (0.56 beta) which is now available from here.

This version:-

  • Corrects various things.
  • Allows multi-line macros to be declared using MACRO...ENDM (instead of using the continuation character which was unpopular).
  • Introduces #localdef (or LOCALEQU if you prefer), which permits you to have a definition (#define, macro or equate) which is limited in scope to its own stack frame.
  • Shows an error if you try to jump into or out of stack frames.
  • And of importance for those using GoAsm for 64-bit programming, it now (a) automatically aligns structures on the correct boundary in data at the beginning of the structure (b) automatically aligns each structure member to suit its natural boundary and (c) pads the structure at the end so that it ends on its natural boundary.

Since there was some delving into GoAsm's depths involved in the above changes, I thought it prudent to make this a beta for the moment.

Author of the "Go" tools (GoAsm, GoLink, GoRC, GoBug)