The MASM Forum

64 bit assembler => UASM Assembler Development => Topic started by: Biterider on March 22, 2019, 05:36:44 AM

Title: Passing a structure
Post by: Biterider on March 22, 2019, 05:36:44 AM
Hi
Today I found a difference in the behavior of UASM in 32 bit and 64 bit. Using the invoke directive and a structure as argument, in 32 bit (stdcall) all members of the structure are passed in sequence. Using exactly the same syntax, but in 64 bit (fastcall), only a pointer to the structure is passed as argument. I checked all settings I know and I can't find the reason why UASM acts that way. Maybe has it something to do with the calling convention, but I have not found any clues on this particular topic.

Maybe the UASM team can shed some light on this matter.  :biggrin:

.code
TestProc proc Arg1:RECT
  ret
TestProc endp


start proc
  local Rct:RECT

  invoke TestProc, Rct
  invoke ExitProcess, 0
start endp



In 32 bit mode (stdcall)
  invoke TestProc, Rct
01361059 FF 75 FC             push        dword ptr [ebp-4]
0136105C FF 75 F8             push        dword ptr [ebp-8]
0136105F FF 75 F4             push        dword ptr [ebp-0Ch]
01361062 FF 75 F0             push        dword ptr [Rct]
01361065 E8 96 FF FF FF       call        TestProc (01361000h)


In 64 bit mode (fastcall)
  invoke TestProc, Rct
000000013F3A1075 48 8D 4D F0          lea         rcx,[Rct]
000000013F3A1079 E8 82 FF FF FF       call        TestProc (013F3A1000h)


Biterider
Title: Re: Passing a structure
Post by: habran on March 22, 2019, 03:58:38 PM
Hi Biterider :biggrin:
IMHO it actually behaves the same, it sends  a reference.
The difference is in allocating the structure. Here is one example how 64 bit allocates the local data:

WinMain proc FRAME hInst : HINSTANCE, hPrevInst : HINSTANCE, CmdLine : LPSTR, CmdShow : UINT

local wc : WNDCLASSEXA
local msg : MSG
local hwnd : HWND
local Rct : RECT
push  rbp
.pushreg rbp
mov   rbp, rsp
.setframe rbp, 0
sub   rsp, sizeof WNDCLASSEXA + sizeof MSG + sizeof HWND + 13 * 8; make sure rsp is 16 - byte aligned
.allocstack sizeof WNDCLASSEXA + sizeof MSG + sizeof RECT + sizeof HWND + 13 * 8
.endprolog
.....
.....
Title: Re: Passing a structure
Post by: aw27 on March 22, 2019, 04:27:30 PM
STDCALL always pushes everything unless you expressly tell to pass by reference - the default is to pass by value. Arrays are an exception but in ASM there is no direct concept of array. In 64-bit Windows ABI (why call it fastcall?)  everything over 8 bytes is passed by reference.
Title: Re: Passing a structure
Post by: Biterider on March 23, 2019, 02:12:13 AM
Hi
Thanks for the answers. I have found the corresponding passage in the Microsoft x64 ABI.
https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=vs-2017 (https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=vs-2017)
"Any argument that does not fit in 8 bytes, or is not 1, 2, 4, or 8 bytes, must be passed by reference."

This is interesting. I tested what happens with a 3 byte structure

MyStruct struct
  a1  BYTE  ?
  a2  BYTE  ?
  a3  BYTE  ?
MyStruct ends

.code
TestProc proc Arg1:MyStruct
  ret
TestProc endp

start proc
  local Argument:MyStruct

  invoke TestProc, Argument
  invoke ExitProcess, 0
start endp

  invoke TestProc, Argument
000000013F9E1015 48 8B 4D FD          mov         rcx,qword ptr [Argument]



This does not seem to fulfill the ABI. OTOH, following the link "Parameter passing" from the previous paper
https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=vs-2017#parameter-passing (https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=vs-2017#parameter-passing)
it says that:
"All arguments are right-justified in registers, so the callee can ignore the upper bits of the register and access only the portion of the register necessary."

That can also be applied to the 3 byte structure, but this is not what the calling convention specifies.
BTW, the same happens to a 5, 6, 7 byte structure.

Thanks, Biterider
Title: Re: Passing a structure
Post by: aw27 on March 23, 2019, 03:06:01 AM
rcx will be filled with 5 random bytes that don't belong to the structure. It is probably a bug.
Title: Re: Passing a structure
Post by: johnsa on March 25, 2019, 08:36:55 PM
That definitely seems like a bug to me. Will add it to the log for 2.49
Title: Re: Passing a structure
Post by: Biterider on March 25, 2019, 08:39:18 PM
Thank you johnsa!


Biterider
Title: Re: Passing a structure
Post by: johnsa on March 26, 2019, 08:05:47 PM
I think the best option, rather than anything automated would be to perform a check

when you use invoke myProc, myStruct

if myStruct is not 1/2/4/8 an error will be emitted ("Structure parameter not 1/2/4/8 bytes, please pass by reference") so that it's clear what the situation is and force the programmer to then use ADDR.

Sound ok ?
Title: Re: Passing a structure
Post by: Biterider on March 26, 2019, 08:51:45 PM
Hi
It's OK for me.  :t
Please add to the error conditions sizes bigger than 8 bytes.

Thanks!!

Biterider
Title: Re: Passing a structure
Post by: nidud on March 26, 2019, 10:23:52 PM
deleted
Title: Re: Passing a structure
Post by: aw27 on March 27, 2019, 12:23:37 AM
Quote from: nidud on March 26, 2019, 10:23:52 PM
For the RECT struct:

msvc x86 will pass rc as a reference in eax
msvc x64 will pass rc as a reference in rcx
masm x86 will push rc
masm x64 will return error (no invoke)
uasm x86 will push rc
uasm x64 will pass rc as a reference in rcx

For the 3 byte struct:

msvc x86 will push ms (8 bytes)
msvc x64 will pass ms as a reference in rcx
masm x86 will push ms - push ax + push word ptr ms
masm x64 will return error (no invoke)
usmc x86 will return error A2070: invalid instruction operands - push ms
uasm x64 will pass ms in rcx - mov rcx, qword ptr [rbp-5H]
asmc x64 will pass ms in cx - mov cx, word ptr [rbp-5H]
I may be wrong but I don't think so on this:
msvc x86 will push ms (8 bytes):
   mov   BYTE PTR _somethree$[ebp], 11      ; 0000000bH
   mov   BYTE PTR _somethree$[ebp+1], 22      ; 00000016H
   mov   BYTE PTR _somethree$[ebp+2], 33      ; 00000021H

   mov   eax, esp
   mov   cx, WORD PTR _somethree$[ebp]
   mov   WORD PTR [eax], cx
   mov   dl, BYTE PTR _somethree$[ebp+2]
   mov   BYTE PTR [eax+2], dl
   call   _threeByteFunction@4


Title: Re: Passing a structure
Post by: nidud on March 27, 2019, 01:15:35 AM
deleted
Title: Re: Passing a structure
Post by: aw27 on March 27, 2019, 01:25:11 AM
Quote from: nidud on March 27, 2019, 01:15:35 AM
Quotemsvc x86 will pass rc as a reference in eax
It does actually push the arguments there...
Cool, we are talking about stdcall.

Quote
Note that the default calling convention for VC x86 is C, not STDCALL.
We are talking about stdcall since the beginning.

Quote
The result will be the same thought.
:biggrin:
Title: Re: Passing a structure
Post by: nidud on March 27, 2019, 03:50:21 AM
deleted
Title: Re: Passing a structure
Post by: aw27 on March 28, 2019, 07:05:10 AM
I have checked MASM and MSVC for the 32-bit case and 3 byte strutures.
There is indeed a bug in MASM when using invoke with the 3 byte structure.
On the other hand MSVC handles well the situation, it does not makes 2 pushes totaling 8 bytes, it reserves 4 bytes in the stack through "sub esp" and puts the structure there by moving 1 byte more 1 word. The receiving end knows how to pick it correctly.
Title: Re: Passing a structure
Post by: nidud on March 28, 2019, 08:33:32 AM
deleted
Title: Re: Passing a structure
Post by: LiaoMi on March 28, 2019, 08:40:55 AM
Quote from: AW on March 28, 2019, 07:05:10 AM
I have checked MASM and MSVC for the 32-bit case and 3 byte strutures.
There is indeed a bug in MASM when using invoke with the 3 byte structure.
On the other hand MSVC handles well the situation, it does not makes 2 pushes totaling 8 bytes, it reserves 4 bytes in the stack through "sub esp" and puts the structure there by moving 1 byte more 1 word. The receiving end knows how to pick it correctly.

Not a bug but a feature :biggrin: we can create a good support request  :eusa_boohoo:
Title: Re: Passing a structure
Post by: aw27 on March 28, 2019, 04:33:16 PM
I made a report to Microsoft and am ready to wait 5 years for the fix.  ::)

https://developercommunity.visualstudio.com/content/problem/508122/masm-invoke-with-a-3-byte-struct.html
Title: Re: Passing a structure
Post by: jj2007 on March 28, 2019, 05:58:25 PM
Personally, I would never use a 3-byte structure; add one padding byte, and everything works fine. Anyway, here's a testbed for 32-bit Masm:
include \masm32\include\masm32rt.inc

S3 STRUCT
x0 db ?
x1 db ?
x2 db ?
; x3 db ?    ; uncomment, and it will work just fine
S3 ENDS

.data
s3b S3 <1, 2, 3>

.code
s3Test proc s3passed:S3
  lea edx, s3passed
  print hex$(edx), " is the address", 13, 10
  movzx eax, s3passed.x0
  print str$(eax), " = x0", 13, 10
  movzx eax, s3passed.x1
  print str$(eax), " = x1", 13, 10
  movzx eax, s3passed.x2
  print str$(eax), " = x2", 13, 10
  ret
s3Test endp

start:
;   int 3
  invoke s3Test, s3b ; UAsm: Error A2049: Invalid instruction operands
  inkey "buggy indeed"
  exit

end start

OPT_Assembler mlv14 ; no complaints but there is a FAT BUG

0040102B      ³.  A0 02204000       mov al, [402002] ; the S3 starts at 402000
00401030      ³.  66:50             push ax
00401032      ³.  66:FF35 02204000  push word ptr [402002]
00401039      ³.  E8 C2FFFFFF       call 00401000
Title: Re: Passing a structure
Post by: aw27 on March 29, 2019, 06:04:26 PM
I got a reply from an MSFT (Microsoft Fuzzy Technician):
"Need More Info" and added a comment.Thank you for your feedback! For us to investigate this further, could you please provide more details like reproducing steps about this issue and example issue code.we don't know how to reproduce this issue on my side as current description. We look forward to hearing from you!

They never understand on a first approach, we need to be patient.  :biggrin:
Title: Re: Passing a structure
Post by: jj2007 on March 29, 2019, 07:18:00 PM
Give him my testbed, it shows the issue crystal clear. Of course, Fuzzy himself has never touched Masm, but there must be somebody at M$ who has coded some lines in assembly. I hope so, at least. There are rumours that compiler developers use assemblers.
Title: Re: Passing a structure
Post by: Biterider on March 29, 2019, 09:20:15 PM
Hi
Point them to this topic. At least our forum can gain some attention on Redmond.
Biterider
Title: Re: Passing a structure
Post by: aw27 on March 29, 2019, 09:59:53 PM
Quote from: jj2007 on March 29, 2019, 07:18:00 PM
Give him my testbed, it shows the issue crystal clear.
You can post your testbed but you will need to explain to them what the macros do with examples and documentation.

Quote from: Biterider on March 29, 2019, 09:20:15 PM
Point them to this topic.
:badgrin:
Title: Re: Passing a structure
Post by: LiaoMi on March 30, 2019, 01:14:44 AM
Quote from: AW on March 29, 2019, 06:04:26 PM
I got a reply from an MSFT (Microsoft Fuzzy Technician):
"Need More Info" and added a comment.Thank you for your feedback! For us to investigate this further, could you please provide more details like reproducing steps about this issue and example issue code.we don't know how to reproduce this issue on my side as current description. We look forward to hearing from you!

They never understand on a first approach, we need to be patient.  :biggrin:

They want a ready-made binary file to keep their heads off, so that in their free time they can play Sony PlayStation, in previous topics it was all the same  :eusa_clap:
Title: Re: Passing a structure
Post by: aw27 on March 30, 2019, 05:06:26 AM
Quote from: LiaoMi on March 30, 2019, 01:14:44 AM
They want a ready-made binary file to keep their heads off, so that in their free time they can play Sony PlayStation, in previous topics it was all the same  :eusa_clap:
Everything works like in a big hospital.
They have a Triage at the entrance that establish priorities and forward the complaints to Areas.
Each Area has a receptionist, like the Fuzzy guy that replied to me. He knows nothing about the problem or how o solve it, but must write a summary of the symptoms  and address the file to the specialist doctor.
Title: Re: Passing a structure
Post by: TimoVJL on March 30, 2019, 05:22:40 AM
Person or PC, at least makes same mistakes ;)
compare to this (https://developercommunity.visualstudio.com/content/problem/388581/event-log-contains-crash-reports-of-cc-compiler-cl.html)

So next reply is
QuoteThank you for your feedback! Unfortunately, right now we don't have enough information to investigate this issue and find a solution. If this is still an issue for you, please update to our latest version. If you are still able to repro it, please provide us with more info!

BTW:Lin Gao [MSFT]
Reputation 27
Posts 142
Following 0
Followers 0
Joined 11/18
Title: Re: Passing a structure
Post by: aw27 on April 01, 2019, 11:16:33 PM
Let's see what come next,  8):
Thanks for taking the time to report this issue to us. We've filed a bug for this issue on the C++ team here. The status on this Developer Community item will be updated as that bug is looked at. Thanks again for reporting this to us.
Title: Re: Passing a structure
Post by: LiaoMi on April 02, 2019, 06:58:10 AM
Quote from: AW on April 01, 2019, 11:16:33 PM
Let's see what come next,  8):
Thanks for taking the time to report this issue to us. We've filed a bug for this issue on the C++ team here. The status on this Developer Community item will be updated as that bug is looked at. Thanks again for reporting this to us.

Great news! Thank you AW! Artificial intelligence could talk to us, suddenly asked where to get this little-known msvcrt.lib library :biggrin:.
Title: Re: Passing a structure
Post by: aw27 on April 02, 2019, 04:28:25 PM
Quote from: LiaoMi on April 02, 2019, 06:58:10 AM
Great news! Thank you AW! Artificial intelligence could talk to us, suddenly asked where to get this little-known msvcrt.lib library :biggrin:.

Hi LiaoMi,
msvcrt.lib is a problem these days. "Weird, my msvcrt.lib doesn't export printf... " (https://twitter.com/aionescu/status/960304224255885312)
But I could not tell the MickeySoft representative to download the MASM32 SDK and have a msvcrt.lib with printf, they wouldn't use 3rd party generated libraries.
So, I built a VS 2017 project and put there as input the 3 libs required nowadays (since VS 2015) to produce a printf. Apparently it worked.  :biggrin:
Title: Re: Passing a structure
Post by: TimoVJL on April 02, 2019, 06:16:45 PM
But they can create one:; lib.exe -DEF:msvcrt-os.def -OUT:msvcrt-os.lib
; link.exe -lib -DEF:msvcrt-os.def -OUT:msvcrt-os.lib
LIBRARY msvcrt.dll
EXPORTS
printf
Title: Re: Passing a structure
Post by: Vortex on April 03, 2019, 05:24:46 AM
Reading that Twitter message, one can write a simplified version of printf. No need of other dependencies.
Title: Re: Passing a structure
Post by: aw27 on April 03, 2019, 02:30:49 PM
msvcrt.dll continues to be available in everyone's system32 folder, only for backwards compatibility.
We expect this to happen for a few more years.  :biggrin:
There are a few simplified alternatives to printf, but they are not as comprehensive by definition, which is desirable some times.

Title: Re: Passing a structure
Post by: TimoVJL on April 03, 2019, 05:42:34 PM
msvcrt.dll is a Windows NT CRT DLL.
So system programs and dlls use it too.
Like about 1400 in Windows 7 and 1800  in Windows 10 in system32 folder.
Title: Re: Passing a structure
Post by: jj2007 on April 03, 2019, 05:59:37 PM
Quote from: TimoVJL on April 03, 2019, 05:42:34 PM
msvcrt.dll is a Windows NT CRT DLL.
So system programs and dlls use it too.
Like about 1400 in Windows 7 and 1800  in Windows 10 in system32 folder.

But of course, M$ wants us to use the latest and most exotic flavour of the CRT. To make sure our programs don't run on obsolete Windows versions :icon_mrgreen:
Title: Re: Passing a structure
Post by: aw27 on April 03, 2019, 06:09:45 PM
We can replace "includelib \masm32\lib\msvcrt.lib" with:

includelib "C:\Program Files (x86)\Windows Kits\10\Lib\10.0.17763.0\ucrt\x86\ucrt.lib"
includelib "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.20.27508\lib\x86\legacy_stdio_definitions.lib"
includelib "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.20.27508\lib\x86\legacy_stdio_wide_specifiers.lib"

it works but we receive a warning in the end (instead of a warming congratulation for our great success):
warning LNK4210: .CRT section exists; there may be unhandled static initializers or terminators
Title: Re: Passing a structure
Post by: jj2007 on April 03, 2019, 07:38:50 PM
Quote from: AW on April 03, 2019, 06:09:45 PMincludelib "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.20.27508\lib\x86\legacy_stdio_wide_specifiers.lib"

Yes, that's what they want. But you can get practically the same service from a LoadLibrary("msvcrt"). Works on all Windows versions, from XP to 10.
Title: Re: Passing a structure
Post by: aw27 on April 03, 2019, 07:48:32 PM
Quote from: jj2007 on April 03, 2019, 07:38:50 PM
Quote from: AW on April 03, 2019, 06:09:45 PMincludelib "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.20.27508\lib\x86\legacy_stdio_wide_specifiers.lib"
Yes, that's what they want. But you can get practically the same service from a LoadLibrary("msvcrt"). Works on all Windows versions, from XP to 10.
I was talking about True MasmTM not High Level Languages or macro boosted variations.
Title: Re: Passing a structure
Post by: jj2007 on April 03, 2019, 08:39:09 PM
Me too.
Title: Re: Passing a structure
Post by: TimoVJL on April 03, 2019, 09:32:23 PM
As jj2007 mentioned, the dynamic way:
.386
.model flat, stdcall
includelib kernel32.lib

.data
sDll db 'msvcrt',0
sFunc db 'printf',0
sMsg db 'Hello ASM',13,10,0

.code
_mainCRTStartup:
push ebp
mov ebp, esp
sub esp, 4h ; function pointer
push offset sDll
call LoadLibraryA@4
push offset sFunc
push eax
call GetProcAddress@8
mov dword ptr [ebp-4h], eax
push offset sMsg
call dword ptr [ebp-4h]
add esp, 4h
mov eax, 0h
mov esp, ebp
pop ebp
ret
end _mainCRTStartup
Title: Re: Passing a structure
Post by: aw27 on April 03, 2019, 11:30:07 PM
LoadLibrary("msvcrt") is not MASM or any assembly language in this World. Can be considered pseudo-code, so that people can figure out the idea. incidentally can even be an instruction of MASM BASIC, which is not MASM just because it contains the word MASM.  JJ may even change the name to UASM BASIC it will not make any difference at all. It will not be UASM as well  just because it uses the UASM assembler :(
Title: Re: Passing a structure
Post by: jj2007 on April 04, 2019, 12:01:30 AM
I hope you had a good lunch, José - I won't feed you :P
Title: Re: Passing a structure
Post by: Vortex on April 04, 2019, 04:55:35 AM
Code assembled with nidud's asmc :

include windows.inc

.data?

hModule     dd ?

.data

string      db 'This is a test.',0

.code

main PROC

    LoadLibrary("msvcrt")
    mov     hModule,eax
   
    GetProcAddress(eax,"printf")

    push    OFFSET string
    call    eax
    add     esp,4

    FreeLibrary(hModule)
    ExitProcess(0)

main ENDP

END main
Title: Re: Passing a structure
Post by: aw27 on April 04, 2019, 05:08:55 AM
Quote from: Vortex on April 04, 2019, 04:55:35 AM
Code assembled with nidud's asmc :

include windows.inc

    LoadLibrary("msvcrt")
    GetProcAddress(eax,"printf")
    FreeLibrary(hModule)
    ExitProcess(0)

main ENDP

END main

Yeap, ASMC has lots of internal macros, or whatever I can call that, replicating Windows API and CRT functions. It is a great work indeed for people that want to maintain a comfortable distance from machine code.   :t
Title: Re: Passing a structure
Post by: johnsa on April 08, 2019, 05:25:01 AM
LoadLibrary is a std. win32 function, not related to asmc or uasm, masm etc. So that should be 100% generic and safe to use on any Windows always.
Title: Re: Passing a structure
Post by: hutch-- on April 08, 2019, 11:57:56 AM
LoadLibrary() and GetProcAddress() are standard API functions which should be used with the normal testing on both the library handle and the procedure address. Without this it can go BANG if either are incorrect.

call LoadLibrary
If return value != 0
call GetProcAddress
If return value != 0
....
call function address.
Title: Re: Passing a structure
Post by: aw27 on April 08, 2019, 11:58:09 AM
In x86/x64, there are 2 major syntax branches for Assemblers, the GAS and the Intel syntax.  However, most assemblers contain high-level features.
LoadLibrary("msvcrt") is a high-level feature.
If we integrate too many high-level features into the Assembler it may become a compiler, though. That is nice but there are so many compilers out there, why another one?
Title: Re: Passing a structure
Post by: hutch-- on April 08, 2019, 04:03:25 PM
As I understand, nidud has a different design criterion which is demonstrated in his project's name, ASMC and from the bits and pieces of it I have seen it intends to use a hybrid of C and assembler. This is different of course from what I understand of UASM or in fact MASM which intend to remain assemblers only. If an assembler is a MACRO assembler, then it will have multiple ways of constructing macros in its pre-processor to automate a whole range of things but as they must be constructed (written) by assembler programmers, they are in fact assembler code.
Title: Re: Passing a structure
Post by: jj2007 on April 08, 2019, 06:04:29 PM
Quote from: hutch-- on April 08, 2019, 04:03:25 PM... they are in fact assembler code.

Thanks for the clarification :icon_mrgreen:
Title: Re: Passing a structure
Post by: johnsa on April 16, 2019, 03:15:23 AM
LoadLibrary("xyz") is indeed not "pure" assembler syntax in the traditional sense. ASMC and UASM support this C-Style of calling.

One could argue, what is pure assembler syntax? INVOKE certainly isn't.. it hides implementation details, can obscure register usage etc.. but I for one wouldn't like to go back to an x86 assembler without it.

So for me, adding a small sprinkling of a high level features where it makes coding in asm easier/more enjoyable or more maintainable for larger projects is probably a good thing.