News:

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

Main Menu

Aligning memory for later instructions.

Started by hutch--, August 25, 2016, 10:28:20 PM

Previous topic - Next topic

jj2007

See e.g. j@VariantTimeToSystemTime equ 8777/89:s39
oleaut32.inc: VariantTimeToSystemTime PROTO :REAL8,:PTR SYSTEMTIME

Most args are DWORD in 32-bit code (even those that should be REAL4, see GdiPlus.inc). DWORDs can become SIZE_P for dual 64/32-bit assembly - the stack is organised in DWORD resp. QWORD slots, so even if (in 64-bit code) the arg should be "only" DWORD according to the C header file, it will do no harm to declare it a QWORD.

The conversion code starts in line 43ff of \Masm32\MasmBasic\Res\GetPT.asm


hutch--

Interestingly enough, this works OK.

    PPROTO TYPEDEF PTR PROC

    MessageBox MACRO args:VARARG
      externdef __imp_MessageBoxA:PPROTO
      IF argcount(args) NE 4
        echo *********************************************
        echo MessageBox MACRO arg count error, 4 expected
        echo *********************************************
        .err
      ENDIF
      invoke __imp_MessageBoxA,args
    ENDM

Its just that I could not be bothered, I have enjoyed working without prototypes.

jj2007

Erol and Paul had an alternative approach, as you may remember:

EXTERNDEF MessageBox@16:PROC
MessageBox EQU <invoke pr4 PTR MessageBox@16>


My version would be
jinvoke MessageBox, 0, Str$(rax), Chr$("Title"), MB_OK

based on
jd@130 equ user32
...
j@MessageBoxA equ 12837/130:s1111


where 12837 is a global counter, 130 is the ID of the DLL, and s1111 means stdcall, 4*DWORD (or QWORD in 64-bit)

hutch--

This will build but will not start and does not recognise an extra argument. It is old left over code that worked on 32 bit ML using a macro I designed a long time ago that is still in the 32 bit windows.inc file.

EXTERNDEF MessageBox@16:PROC
MessageBox EQU <invoke pr4 PTR MessageBox@16>

This method of prototyping does not work in ML64.

hutch--

In the C++ header file this is the prototype.

WINOLEAUTAPI_(INT) VariantTimeToSystemTime(__in DOUBLE vtime, __out LPSYSTEMTIME lpSystemTime);
vtime is a DOUBLE
lpSystemTime is a QWORD pointer to a structure

Both are 64 bit values.

jj2007

Quote from: hutch-- on September 18, 2016, 08:27:38 PM
In the C++ header file this is the prototype.

WINOLEAUTAPI_(INT) VariantTimeToSystemTime(__in DOUBLE vtime, __out LPSYSTEMTIME lpSystemTime);
vtime is a DOUBLE
lpSystemTime is a QWORD pointer to a structure

Both are 64 bit values.

Indeed. Little test:

include \Masm32\MasmBasic\Res\JBasic.inc            ; OPT_64 1      ; put 0 for 32 bit, 1 for 64 bit assembly
.data?
MyR8      REAL8 ?
MyST      SYSTEMTIME <>

Init
  PrintLine Chr$("This code was assembled with ", @AsmUsed$(1), " in ", jbit$, "-bit format")
  jinvoke SetLastError, 0
  jinvoke GetLocalTime, addr MyST
  jinvoke SystemTimeToVariantTime, addr MyST, addr MyR8
  jinvoke VariantTimeToSystemTime, MyR8, addr MyST
  deb 4, "Result", eax, MyR8, MyST.wDay, MyST.wMonth, MyST.wYear
  Inkey Err$()
EndOfCode


Output:
This code was assembled with ml64 in 64-bit format
Result
eax     1
MyR8    42631.545960648
MyST.wDay       18
MyST.wMonth     9
MyST.wYear      2016

Operazione completata.

hutch--

Beware of being trapped in the past, long mode /LARGEADDRESSAWARE is the future and the native data size for Win64 is 64 bit.

jj2007

Quote from: hutch-- on September 18, 2016, 10:13:50 PM
Beware of being trapped in the past, long mode /LARGEADDRESSAWARE is the future and the native data size for Win64 is 64 bit.

Can you please elaborate the relevance of your statement for the VariantTimeToSystemTime example? Or for any other 64-bit example I ever posted here?

hutch--

Quote
Most args are DWORD in 32-bit code (even those that should be REAL4, see GdiPlus.inc). DWORDs can become SIZE_P for dual 64/32-bit assembly - the stack is organised in DWORD resp. QWORD slots, so even if (in 64-bit code) the arg should be "only" DWORD according to the C header file, it will do no harm to declare it a QWORD.
According to the C++ header file, both values are 64 bit. If you want to write reliable code you will get the data sizes right. You may get away with 2 x 32 bit values but you are at risk with the future. The other test is if your code builds successfully with the linker option /LARGEADDRESSAWARE. If not you are tied to the past using 32 bit values.

jj2007

All my 64-bit code builds fine with /large.

int 3
jinvoke VariantTimeToSystemTime, MyR8, addr MyST
nop


translates to:CC                         | int3                                          |
48 8D 15 8C 21 00 00       | lea rdx, qword ptr ds:[140003268]             | pointer to SYSTEMTIME
48 8B 0D 7D 21 00 00       | mov rcx, qword ptr ds:[140003260]             | 40E4D0F6612F684C, double 42631.701273148
FF 15 9F 24 00 00          | call qword ptr ds:[<&VariantTimeToSystemTime> |
90                         | nop                                           |


Of course, with OPT_64 0,  i.e. 32-bit assembly, there will be two DWORD pushes for the REAL8:
CC                  int3
68 107BD400         push offset MyST
FF35 0C7BD400       push dword ptr [0D47B0C]
FF35 087BD400       push dword ptr [MyR8]
FF15 887CD400       call near [0D47C88]
90                  nop

hutch--

The 64 bit code looks simple enough as its only 3 register args but there is no gain in using the wrong data size in the register when the spec is 64 bit. I don't know what the value is in the ml64 subforum for the 32 bit code, its been around since the middle 1990s.

jj2007

Where am I "using the wrong data size in the register when the spec is 64 bit"??? ::)

MichaelW

Why not use the aligned malloc family of functions ? The attachment contains a demo done in C and GAS assembly.
Well Microsoft, here's another nice mess you've gotten us into.

hutch--

Michael,

You will probably like this.

  ; --------------------------------------------------------
  ; alignment must be an immediate operand and a power of 2
  ; when no longer required the original address must be
  ; freed with either GlobalFree() or the macro "mfree".
  ; --------------------------------------------------------
    aalloc MACRO pmem:REQ,bcnt:REQ,alignment:REQ
      mov rdx, bcnt
      add rdx, alignment
      mov rcx, GMEM_FIXED or GMEM_ZEROINIT
      call GlobalAlloc
      mov pmem, rax
      add rax, alignment - 1
      and rax, -alignment
      EXITM <rax>
    ENDM

Your suggestion is a good idea though, I have seen the function but have not had the time to try it out yet.

I have a longer version as well that will take memory operands for the alignment.

jj2007

Since HeapAlloc returns align 8, and align 16 is what you need for SIMD, a thin wrapper around HeapAlloc and HeapFree is another option. 8 bytes extra per call, obviously.