Documentation is lousy by UASM seems to work OK. I could not find the reference for => OPTION PROC:NONE. I could not find a reason why it had to have "main" as its entry point. I just used an equate to get the name I wanted.
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
option casemap:none
includelib \masm32\lib64\kernel32.lib
includelib \masm32\lib64\user32.lib
MessageBoxA PROTO :QWORD,:QWORD,:QWORD,:QWORD
MessageBox equ <MessageBoxA>
ExitProcess PROTO :QWORD
MB_OK equ <0>
entry_point equ <main>
.data
caption db " The UASM Assembler", 0
text db "Bare Bones MessageBox", 0
.code
OPTION PROC:NONE
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
entry_point proc
add rsp, 8
invoke MessageBox,0,ADDR text,ADDR caption,MB_OK
invoke ExitProcess,0
entry_point endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
end
The build batch file.
@echo off
set appname=UASM1
del %appname%.obj
del %appname%.exe
\uasm\uasm64 -win64 %appname%.asm
\masm32\bin64\polink.exe /SUBSYSTEM:WINDOWS /entry:main /LARGEADDRESSAWARE %appname%.obj
dir %appname%.exe
pause
as link.exe and polink.exe understand those basic entry points mainCRTStartup, wmainCRTStartup, WinMainCRTStartup, wWinMainCRTStartup, why not use one of them ?
so only -subsystem is necessary for link.exe, but M$ must be a reason for that.
If you don't need them, why use them. Assemblers do not need to assume C technology.
Quote from: hutch-- on July 21, 2019, 08:49:28 PM
If you don't need them, why use them. Assemblers do not need to assume C technology.
You missed something, those don't depend of C
Even i know something about compilers, like C, it's a linker that i was talking about.
As i said, it's a M$ linker issue, not a C issue.
Your site, your rules, but try to be in truth :skrewy:
:biggrin:
mainCRTStartup, wmainCRTStartup, WinMainCRTStartup, wWinMainCRTStartup is not assembler technology, it is C technology. Assembler modules only need an entry point which you specify on the linker command line. I am not sure what you are trying to prove here.
Here is a slightly tweaked version.
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
option casemap:none
includelib \masm32\lib64\kernel32.lib
includelib \masm32\lib64\user32.lib
MessageBoxA PROTO :QWORD,:QWORD,:QWORD,:QWORD
MessageBox equ <MessageBoxA>
ExitProcess PROTO :QWORD
MB_OK equ <0>
entry_point equ <main>
NULL equ <0>
t MACRO quoted
LOCAL text
LOCAL ptxt
.data
text db quoted,0
ptxt dq text
.code
EXITM <ptxt>
ENDM
OPTION PROC:NONE
.code
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
entry_point proc
sub rsp, 8
invoke MessageBox,NULL,t("Bare Bones MessageBox"),t(" The UASM Assembler"),MB_OK
invoke ExitProcess,0
entry_point endp
OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
end
As i said, a linker issue, predefined names in linker, not a C issue.
https://docs.microsoft.com/en-us/cpp/build/reference/entry-entry-point-symbol
TimoVJL but why Masm32 don't need it? In masm I can write
.code
start:
...
nop
..
end start
Without any proc.
From the link above (provided by timo):
Quote
It is recommended that you let the linker set the entry point so that the C run-time library is initialized correctly, and C++ constructors for static objects are executed.
By default, the starting address is a function name from the C run-time library. The linker selects it according to the attributes of the program, as shown in the following table.
Function name Default for
mainCRTStartup (or wmainCRTStartup) An application that uses /SUBSYSTEM:CONSOLE; calls main (or wmain)
WinMainCRTStartup (or wWinMainCRTStartup) An application that uses /SUBSYSTEM:WINDOWS; calls WinMain (or wWinMain), which must be defined to use __stdcall
_DllMainCRTStartup A DLL; calls DllMain if it exists, which must be defined to use __stdcall
Looks a lot like a c related issue...
Polink and Link.exe will accept any entry point set in UASM with a correct syntax name, the same as in MASM. This includes the "entry_point" name. It will also accept labels as entry points but is not recommended for 64-bit when you want the OPTION for automatic stack alignment to work.
Timo,
I am not sure what you are getting at, what have you missed with *****CRT***** = C runtime. Now I have no doubt that you can start an app with a C runtime procedure but the obvious is that an assembler does not need it.
I confess it seems like a waste of time posting a simple experiment with UASM as it ends up in yet another nonsense argument over very old technology from the Petzold era that aped a technique where a WinMain had 4 arguments which followed from the format of a 16 bit Win3.0 era code design and YES it was in C.
I was looking for some of the UASM folks who knew more of the reference material that I have yet to find. All I have so far is some old stuff from the data that Japheth wrote.
Quote from: morgot on July 22, 2019, 03:56:17 AM
TimoVJL but why Masm32 don't need it? In masm I can write
.code
start:
...
nop
..
end start
Without any proc.
just look inside of .obj and find out why M$ link find that entry point, no magic.
I knew I had stuff this old somewhere. This is how you ape a 16 bit Windows WinMain in early 32 bit.
start:
invoke GetModuleHandle, NULL
mov hInstance, eax
invoke GetCommandLine
mov CommandLine, eax
invoke WinMain,hInstance,NULL,CommandLine,SW_SHOWDEFAULT
invoke ExitProcess,eax
; #########################################################################
WinMain proc hInst :DWORD,
hPrevInst :DWORD,
CmdLine :DWORD,
CmdShow :DWORD
Most of it is redundant in Win32 and certainly in Win64. You do not need hPrevInst and CmdShow. It was just a pseudo compatibility with 16 bit Windows while updating to Win32.
Linker don't care about language, only symbol names,just learn object file basics with wrj's PEView.exe.
It seems that i just waste my time here to teach some professionals to update their knowledge of some basic things.
I haven't been a professional programmer in my life, only a hobbyist, but some of my programs are still important part of production line in one factory.
My role was a IT support and a system expert person at that time.
I even created a C code to read Vertex Systems databases.
Quote from: TimoVJL on July 22, 2019, 04:53:49 AM
It seems that i just waste my time here to teach some professionals to update their knowledge of some basic things.
I haven't been a professional programmer in my life, only a hobbyist, but some of my programs are still important part of production line in one factory.
My role was a IT support and a system expert person at that time.
I even created a C code to read Vertex Systems databases.
:biggrin: And you have never learned assembly language?
Timo,
I think you have mixed up a couple of things, we all know that the entry point is set in the linker but the code for that entry point is in the source code that the assembler processes. Your original comment was a suggestion to use the CRT in the form mainCRTStartup, wmainCRTStartup, WinMainCRTStartup, wWinMainCRTStartup and I made you the comment that it is not needed in the source code of an assembler application.
Here is an example in another assembler, POASM.
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
ExitProcess PROTO :QWORD
MessageBoxA PROTO :QWORD,:QWORD,:QWORD,:QWORD
MessageBox equ <MessageBoxA>
MB_OK equ <0>
includelib \masm32\lib64\kernel32.lib
includelib \masm32\lib64\user32.lib
.data
msg db "A MessageBox in POASM",0
ttl db " About",0
.code
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
entry_point proc
add rsp, 8
invoke MessageBox,0,ADDR msg,ADDR ttl,MB_OK
invoke ExitProcess,0
entry_point endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
end
It is built with this batch file.
@echo off
set appname=app
if exist %appname%.obj del %appname%.obj
if exist %appname%.exe del %appname%.exe
\masm32\bin64\poasm.exe %appname%.asm
\masm32\bin64\polink.exe /SUBSYSTEM:WINDOWS /MACHINE:X64 /ENTRY:entry_point /nologo /LARGEADDRESSAWARE %appname%.obj
dir %appname%.*
pause
On one side people that has never used UASM in his life (but there is always a first time for everything) and on the other side people that has no clue at all about assembly language. Looks funny. :skrewy:
:biggrin:
Yes you are right and with the amount of crap I have had to listen to in this topic I may not ever get there. Here is a tweaked version done in POASM. I am not really up to date with POASM but its has always been a decent tool
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
MessageBoxA PROTO :QWORD,:QWORD,:QWORD,:QWORD
ExitProcess PROTO :QWORD
MessageBox equ <MessageBoxA>
MB_OK equ <0>
includelib \masm32\lib64\kernel32.lib
includelib \masm32\lib64\user32.lib
t MACRO quoted
LOCAL text
LOCAL ptxt
.data
text db quoted,0
.code
EXITM <ADDR text>
ENDM
.code
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
entry_point proc
sub rsp, 8
invoke MessageBox,0,t("A MessageBox in POASM"),t(" About"),MB_OK
invoke ExitProcess,0
entry_point endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
end
Note that it will build as well with UASM without modification. However to run properly you will need to add OPTION PROC:NONE (it is indeed mentioned in the documentation) or alternatively OPTION PROLOGUE:NONE
Quote from: hutch-- on July 22, 2019, 05:29:25 AM
Timo,
I think you have mixed up a couple of things, we all know that the entry point is set in the linker but the code for that entry point is in the source code that the assembler processes. Your original comment was a suggestion to use the CRT in the form mainCRTStartup, wmainCRTStartup, WinMainCRTStartup, wWinMainCRTStartup and I made you the comment that it is not needed in the source code of an assembler application.
Steve,
not me, you can read from Microsoft linker documents about those predefined symbols.
Quote from: felipe on July 22, 2019, 05:03:12 AM
Quote from: TimoVJL on July 22, 2019, 04:53:49 AM
It seems that i just waste my time here to teach some professionals to update their knowledge of some basic things.
I haven't been a professional programmer in my life, only a hobbyist, but some of my programs are still important part of production line in one factory.
My role was a IT support and a system expert person at that time.
I even created a C code to read Vertex Systems databases.
:biggrin: And you have never learned assembly language?
a joke?
after over 10 years making bug report to software company of bug finding with WinDBG, what you except ?
i think it need more than just assembly language, you must understand a whole system around it.
Quote from: hutch-- on July 22, 2019, 04:27:09 AM
I was looking for some of the UASM folks who knew more of the reference material that I have yet to find. All I have so far is some old stuff from the data that Japheth wrote.
There is a pdf in the releases that contains the new stuff: uasm248_ext.pdf or similarly named.
The option for string literals is a nice handy feature
OPTION LITERALS:ON
Then should be able to do this:
invoke MessageBox, NULL, "Bare Bones MessageBox", "The UASM Assembler", MB_OK
Instead of using a macro - for convenience really, but could be useful
invoke MessageBox, NULL, t("Bare Bones MessageBox"), t("The UASM Assembler"), MB_OK
It also supports wide string literals when prefixed with L
The pdf manual does have a lot of interesting new features, lots to explore, and I'm sure they will be useful to many.
fearless, Gratsie. :thumbsup:
I did try the option but got this result.
UASM v2.49, Jun 21 2019, Masm-compatible assembler.
Portions Copyright (c) 1992-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
UASM1.asm(44) : Error A2145: INVOKE argument type mismatch: argument 1
UASM1.asm(44) : Error A2145: INVOKE argument type mismatch: argument 2
UASM1.asm: 55 lines, 1 passes, 2 ms, 0 warnings, 2 errors
POLINK: fatal error: File not found: 'UASM1.obj'.
Volume in drive K is disk3_k
Volume Serial Number is 68C7-4DBB
Directory of K:\uasm\test1
File Not Found
Press any key to continue . . .
@Hutch
> For a string literal to be accepted as such, the corresponding procedure parameter must be defined as PTR.
MessageBoxA PROTO :qword,:ptr,:ptr,:dword
Right. That was introduced when somebody tried to pass "a" as the immediate value 97.
Works perfect, Gratsie.
I still have not got rid of the stack twiddle "sub rsp, 8". I have been scanning the PDF file but any FRAME attempt outputs an error.
In MASM I have automatic stack control so I can do this.
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
include \masm32\include64\masm64rt.inc
.code
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
entry_point proc
rcall MessageBox,0,"A MessageBox in 64 bit MASM", \
"MASM Pure And Simple",MB_OK
.exit
entry_point endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
end
try adding the following:
option win64 : 11
option frame : auto
option stackbase : rsp
and although I don't think it's required anymore (except for older versions of UASM) I put a FRAME keyword after the PROC (just for that backward compatibility)
entry_point proc frame
Thanks, that worked well.
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
OPTION CASEMAP:NONE
OPTION LITERALS:ON
OPTION FRAME:AUTO
OPTION WIN64:11
OPTION STACKBASE:RSP
includelib \masm32\lib64\kernel32.lib
includelib \masm32\lib64\user32.lib
MessageBoxA PROTO :QWORD,:PTR,:PTR,:QWORD
MessageBox equ <MessageBoxA>
ExitProcess PROTO :QWORD
close MACRO optvar:=<0>
invoke ExitProcess,optvar
ENDM
MB_OK equ <0>
NULL equ <0>
.code
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
entry_point proc
invoke MessageBox,NULL,"Bare Bones MessageBox"," The UASM Assembler",MB_OK
close
entry_point endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
end
The use of FRAME, which also exists in MASM, has never really been of interest to Assembly-Language-only programmers, although at a point in time everybody started using it with JWasm and successors, (including myself :badgrin:). In addition, it was broken in its 64-bit version (Japeth heritage). After a lengthy discussion with Johnsa, which started probably here (http://masm32.com/board/index.php?topic=6617.0) and continued in private I believe that UASM ended with a functional FRAME for people that wants to use it. As a spin-off of that discussion I ended up doing an article for CodeProject (https://www.codeproject.com/Articles/1212332/bit-Structured-Exception-Handling-SEH-in-ASM) which is centered in MASM, but which applies to UASM as well (although I intend to update it and be more specific about its use with UASM).
I went for a rat through my archives and found one of my own golden oldies, a template that I used for C code and it only has a "main" to start, no WinMain or CRT runtime module to start it. If you are old enough you will pick the K&R formatting. Its last build was with the VC 2003 toolkit.
/* ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««« */
#include <windows.h>
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
/* ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««« */
void main()
{
HANDLE hWnd; // local main window handle
HICON hIcon; // local icon handle
LPMSG pmsg; // pointer for MSG structure
WNDCLASSEX * pwc; // pointer to WNDCLASSEX structure
MSG msg; // local msg structure
WNDCLASSEX wc; // local structure for RegisterClassEx
char szTitle[] = "Small C";
char szWindowClass[] = "SC_Class";
/* ------------------------------------------
Copy structure addresses to pointer variables
------------------------------------------ */
pmsg = &msg;
pwc = &wc;
hIcon = LoadIcon(NULL,IDI_APPLICATION);
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_BYTEALIGNWINDOW | CS_BYTEALIGNCLIENT;
wc.lpfnWndProc = (WNDPROC)WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = (HINSTANCE)0x400000;
wc.hIcon = hIcon;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = szWindowClass;
wc.hIconSm = hIcon;
RegisterClassEx(pwc);
hWnd = CreateWindowEx(WS_EX_LEFT,
szWindowClass,
szTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,0,
CW_USEDEFAULT,0,
NULL,NULL,(HINSTANCE)0x400000,NULL);
ShowWindow(hWnd,SW_SHOW);
UpdateWindow(hWnd);
while (GetMessage(pmsg,NULL,0,0))
{
TranslateMessage(pmsg);
DispatchMessage(pmsg);
}
}
/* ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««« */
LRESULT CALLBACK WndProc(HWND hWin,UINT uMsg,
WPARAM wParam,LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY:
{
PostQuitMessage(0);
break;
}
}
return DefWindowProc(hWin,uMsg,wParam,lParam);
}
/* ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««« */
Built with,
@echo off
set lib=h:\vctoolkit\lib\
set include=h:\vctoolkit\include\
if exist project2.exe del project2.exe
if exist project2.obj del project2.obj
h:\vctoolkit\bin\cl /c /G7 /O2 /Ot /GA /TC /W3 /FA project2.c
h:\vctoolkit\bin\Link /SUBSYSTEM:WINDOWS /entry:main /libpath:h:\msc6\lib @project2.rsp
dir project2.*
pause
Hi Hutch,
Same C example built with Manos' pcc32 compiler. The executable is 2560 bytes.
Let me see if I get this right (for a Windows program):
1) If you don't use the /Entry switch in the linker, the entry point for a Windows program will be WinMainCRTStartup.
For this case, on a ASM program you must have a procedure called WinMainCRTStartup.
On a C program WinMainCRTStartup is part of the runtime (it is possible to override it and save a few KBs), it runs first and then calls WinMain which is what you see on a normal C program.
2) If you use the /Entry switch, this will be called first either in ASM or in C. For an ASM program the Microsoft Linker will not even require you to specify /SUBSYSTEM:WINDOWS. If you don't specify /SUBSYSTEM:WINDOWS, the POLINK guy will tell you that it is assuming CONSOLE but that does not really matter, it will swallow whatever comes after the entry point.
So Hutch's old Windows application complies. :biggrin:
I have found a funny effect prototyping API functions for UASM so far.
Change this,
SendMessageA PROTO :QWORD,:QWORD,:QWORD,:QWORD
IFNDEF __UNICODE__
SendMessage equ <SendMessageA>
ENDIF
To
SendMessageA PROTO :PTR,:PTR,:PTR,:PTR
IFNDEF __UNICODE__
SendMessage equ <SendMessageA>
ENDIF
And it seems to work fine with the OPTION LITERALS:ON as well as any other 64 bit argumernt.
.drectve section is useful for some linker options
OPTION DOTNAME
.drectve SEGMENT INFO
db '-subsystem:windows,5.2 -entry:start',0
.drectve ENDS
public start ; for ml64.exe
.code
start:
;WinMainCRTStartup proc
mov eax, 0
ret
;WinMainCRTStartup endp
end ;start ; ml64 don't accept entry point
Prototypes were invented to guide our hot little hands :thumbsup:. We can do without them but is painful and will never be a recommended practice.
One size fits all prototyping has caused the need for new Masm SDK 64-bit include files. Microsoft had been alerting for decades that people should not rely on pointers being dwords. Nobody listened.
:biggrin:
I guess it depends on if the programmer knows what the pointer size is for the OS being used. DOS was 16 bit, win32 was 32 bit and win64 is 64 bit. If a programmer does not know this, they should stick to server side scripting.
UASM seems to work well once you can get it up and going, full window app comes easy, about the only real complaint after using 64 bit MASM is all the hassle producing fixed prototypes, something I left behind in 32 bit. It could do with the OPTION DOTNAME as this solves many naming problems, the need to specify PTR for literal text is a pest and the work around was to make all include file data types PTR instead of QWORD which is nonsensical but it works OK. This needs to be ditched and leave open the base datatype, not some notion of strong typing.
Example built with MS VC Toolkit 2003 :
#include <stdio.h>
void __stdcall ExitProcess(unsigned int uExitCode);
__declspec(naked) void proc()
{
static char name[32];
printf("What's your name?\n");
scanf("%s",name);
printf("Nice to meet you %s\n",name);
ExitProcess(0);
}
Set vc2003=C:\MSVCTK2003
Set PATH=%vc2003%\bin;%PATH%
Set INCLUDE=%vc2003%\include;%INCLUDE%
Set LIB=%vc2003%\lib;%LIB%
cl /c /Zl Project.c
link /SUBSYSTEM:CONSOLE /ENTRY:proc Project.obj kernel32.lib H:\masm32\lib\msvcrt.lib
as msvcrt.dll was used, exit() is usable too.void __cdecl mainCRTStartup(void) {exit(main());}
A UASM window with no Microsoft components used in its build.
UASM assembler
POLINK linker
PORC resource compiler
The source is attached but it cannot be directly built as it assumes bits and pieces from all over my DEV drive but the exe runs correctly, it has an icon, manifest and version control block.
The "sauce".
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
include \uasm\include\uasm64rt.inc
button PROTO :PTR,:PTR,:PTR,:PTR,:PTR,:PTR,:PTR,:PTR
iMsgbox PROTO :PTR,:PTR,:PTR,:PTR,:PTR
.data?
hInstance dq ?
hWnd dq ?
hIcon dq ?
hCursor dq ?
sWid dq ?
sHgt dq ?
hBrush dq ?
butn1 dq ?
butn2 dq ?
.data
classname db "template_class",0
caption db "UASM Template",0
.code
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
entry_point proc
mov hInstance, rv(GetModuleHandle,0)
mov hIcon, rv(LoadIcon,hInstance,10)
mov hCursor, rv(LoadCursor,0,IDC_ARROW)
mov sWid, rv(GetSystemMetrics,SM_CXSCREEN)
mov sHgt, rv(GetSystemMetrics,SM_CYSCREEN)
mov hBrush, rv(CreateSolidBrush,00666666h)
call main
close
entry_point endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
main proc
LOCAL wc :WNDCLASSEX
LOCAL lft :QWORD
LOCAL top :QWORD
LOCAL wid :QWORD
LOCAL hgt :QWORD
mov wc.cbSize, SIZEOF WNDCLASSEX
mov wc.style, CS_BYTEALIGNCLIENT or CS_BYTEALIGNWINDOW
mov wc.lpfnWndProc, ptr$(WndProc)
mov wc.cbClsExtra, 0
mov wc.cbWndExtra, 0
mrm wc.hInstance, hInstance
mrm wc.hIcon, hIcon
mrm wc.hCursor, hCursor
mrm wc.hbrBackground, hBrush
mov wc.lpszMenuName, 0
mov wc.lpszClassName, ptr$(classname)
mrm wc.hIconSm, hIcon
invoke RegisterClassEx,ADDR wc
mov wid, 800
mov hgt, 450
mov rax, sWid ; calculate offset from left side
sub rax, wid
shr rax, 1
mov lft, rax
mov rax, sHgt ; calculate offset from top edge
sub rax, hgt
shr rax, 1
mov top, rax
invoke CreateWindowEx,WS_EX_LEFT or WS_EX_ACCEPTFILES, \
ADDR classname,ADDR caption, \
WS_OVERLAPPEDWINDOW or WS_VISIBLE,\
lft,top,wid,hgt,0,0,hInstance,0
mov hWnd, rax
call msgloop
ret
main endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
msgloop proc
LOCAL msg :MSG
LOCAL pmsg :QWORD
mov pmsg, ptr$(msg) ; get the msg structure address
jmp gmsg ; jump directly to GetMessage()
mloop:
invoke TranslateMessage,pmsg
invoke DispatchMessage,pmsg
gmsg:
test rax, rv(GetMessage,pmsg,0,0,0) ; loop until GetMessage returns zero
jnz mloop
ret
msgloop endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
WndProc proc hWin:PTR,uMsg:PTR,wParam:PTR,lParam:PTR
.if uMsg == WM_COMMAND
.if wParam == 100
invoke iMsgbox,hWin,"Button 1 was pressed","Information",MB_OK,10
.elseif wParam == 200
jmp bye
.elseif wParam == 300
Invoke iMsgbox,hWin,"UASM 64 Bit Template","About",MB_OK,10
.endif
.elseif uMsg == WM_CREATE
invoke LoadMenu,hInstance,100
invoke SetMenu,hWin,rax
mov butn1, rv(button,hInstance,hWin,"Button 1",50,40,100,20,100)
mov butn2, rv(button,hInstance,hWin,"Close",50,65,100,20,200)
xor rax, rax
ret
.elseif uMsg == WM_CLOSE
bye:
invoke SendMessage,hWin,WM_DESTROY,0,0
.elseif uMsg == WM_DESTROY
invoke PostQuitMessage,NULL
.endif
invoke DefWindowProc,hWin,uMsg,wParam,lParam
ret
WndProc endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
button proc instance:PTR,hparent:PTR,text:PTR,topx:PTR,topy:PTR,wid:PTR,hgt:PTR,idnum:PTR
invoke CreateWindowEx,0,"BUTTON",text, \
WS_CHILD or WS_VISIBLE,\
topx,topy,wid,hgt,hparent,idnum,instance,0
ret
button endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
iMsgbox proc hParent:PTR,pText:PTR,pTitle:PTR,mbStyle:PTR,IconID:PTR
LOCAL mbp :MSGBOXPARAMSxx
or mbStyle, MB_USERICON
mov mbp.cbSize, SIZEOF mbp
mrm mbp.hwndOwner, hParent
mov mbp.hInstance, rv(GetModuleHandle,0)
mrm mbp.lpszText, pText
mrm mbp.lpszCaption, pTitle
mov rax, mbStyle
mov mbp.dwStyle, eax
mrm mbp.lpszIcon, IconID
mov mbp.dwContextHelpId, NULL
mov mbp.lpfnMsgBoxCallback, NULL
mov mbp.dwLanguageId, NULL
invoke MessageBoxIndirect,ADDR mbp
ret
iMsgbox endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
end
button proc instance:PTR,hparent:PTR,text:PTR,topx:PTR,topy:PTR,wid:PTR,hgt:PTR,idnum:PTR
We all know how params are being passed in x64: rcx, rdx, r8, r9, then QWORDs on the stack. The receiving end will pick what it needs, mostly DWORDs in this case. So technically speaking, you can cheat the assembler in x64, passing only "pointers". But is it wise to do so?
:biggrin:
> But is it wise to do so?
No its not as it makes a fool of the pseudo strong typing. The alternative is to spend YEARS manually editing prototypes which no-one is willing to do. Auto formatting prototypes based on the actual data size is viable as a vast number of API functions use 64 bit arguments and even if they don't, the stack layout is done in 64 bit slots.
I would look for an option to turn it off while still being able to use the literal strings in invoke calls.
If you would abandon for a moment your ideological "hot little hands" position, you might reflect on mechanisms to extract the size from C headers. I had started such an exercise, it took me a few days to get it 90% right, but then I completely lost interest in 64-bit coding and abandoned the project. I could dig it out, but of course, it's MasmBasic.
Quote from: jj2007 on July 24, 2019, 04:09:02 PM
button proc instance:PTR,hparent:PTR,text:PTR,topx:PTR,topy:PTR,wid:PTR,hgt:PTR,idnum:PTR
We all know how params are being passed in x64: rcx, rdx, r8, r9, then QWORDs on the stack. The receiving end will pick what it needs, mostly DWORDs in this case. So technically speaking, you can cheat the assembler in x64, passing only "pointers". But is it wise to do so?
Hi jj2007,
Full SDK 10.0 translate for 64 and 32 bits - http://masm32.com/board/index.php?topic=563.0 (http://masm32.com/board/index.php?topic=563.0) - uses this PTR technique, on the forum it is discussed in the section of this sdk. I use it from 2016, during this time there were no problems.
Quote from: habran on December 24, 2014, 06:38:47 AM
I was unable to setup your SDK for use on my computer :(
I am curious if anybody else except you succeeded to set it up
I think that it requires to much work and I am wondering how someone new in programming can use it
I will stick to WinInc, it is simple to use and runs without flow :t
Why use XMASM
It is more clear like this in WinInc:
@DefProto WINOLEAPI, OleCreate, stdcall, ,<:REFCLSID,:REFIID,:DWORD,:LPFORMATETC,:LPOLECLIENTSITE,:LPSTORAGE,:ptr LPVOID>, 28
than this in SDK:
OleCreate PROTO :DWORD ,:DWORD ,:DWORD ,:XMASM ,:XMASM ,:XMASM ,:XMASM
XMASM = PTR
You can use regular :DWORD, :QWORD etc wherever you want on the prototypes.. the :PTR notation was purely to prevent conflicts between using an actual string literal and numeric constant string.
literalStringProc PROTO :PTR
constantProc PROTO :DWORD
invoke literalStringProc, "abcd"
invoke constantProc, "abcd"
What might be an option as I wouldn't want to remove this safety mechanism (we didn't have it originally and were bitten with unexpected results - bugs)
We "could" have an OPTION UNSAFE STRING or something like that, which would then lift the :PTR requirement... but then any use of INVOKE "...." would assume you meant a string literal and never a string constant -> number conversion
jj,
Have a look at this pile of crap.
WINBASEAPI
BOOL
WINAPI
InitOnceExecuteOnce (
__inout PINIT_ONCE InitOnce,
__in __callback PINIT_ONCE_FN InitFn,
__inout_opt PVOID Parameter,
__deref_opt_out_opt LPVOID *Context
);
I have cut this out manually but look at what you need to be able to identify the prototype. There are 3 equates that may be defined in the header file but may also be defined in another header file. Then for each argument you have a number of other externally defined equates as qualifying directives for the argument. You can determine the actual argument by it being followed by a trailing comma and you can determine the end of the prototype by the ";" character.
Then you have to track back to find the size of the qualifying directives and apply them to the arguments and again the equates for the qualifying directive may not be in the same H file.
There is in fact a trick to avoid most of this crap, load only the H file into CL and send the output to STDOUT and when redirected to a file you get most of the crap removed.
John,
Its the prototypes where its a problem, when you have large counts of API functions, without being able to automate the arguments, you are stuck with manually editing a massive number of prototypes which could take years to do. Defining all args as PTR works but its a crude way to get around this limitation.
Just had another idea... to prevent a conflict.. we could force the use of a different delimiter for literal strings.. so instead of " " in the invoke, perhaps ` ` ? like newer HLL template string literals.
I am used to that with alternate quotes in MASM but an OFF switch would be a better choice as double quotes are the normal notation across a large number of programming languages. If you can do large numbers of prototypes using the native QWORD, it makes include file a lot easier to generate. Having the option to use the alternate equates for assembler data types is easy enough to do for people who like that format.
I'll have a think more about it, as long as whatever we do prevents ambiguity between "abcd"(CONSTANT NUMERIC) and "abcd"(STRING)
On the function declarations theme, Microsoft never bothered to make life (relatively) easy for languages other than C/C++ (even for C#, everybody knows the complicative mess that is that Pinvoke thingy, and there are no ready-made include files).
I am remembering the Vulkan Registry (https://github.com/KhronosGroup/Vulkan-Docs/blob/master/xml/vk.xml), which is a long tabular XML document containing, within other things, every detail about each function and data type and has been used by other languages to produce Vulkan bindings with relative easiness.
Microsoft has never done anything similar because does not want.
John,
The way I did it in the macros for 64 bit masm was to scan the source that could either be a string literal or a string address for a leading double quote, if it is a double quote, it reads the quoted text into a data section ID and returns its address. This way you can handle both literal strings and string addresses in the same location.
invoke MessageBox,hWin,pMsg,"About",MB_OK
This would not be uncommon if the text body was too large to easily fit on a line of code so being able to handle both is a lot more flexible.
deleted
How do you do the return value ? All I do in MASM is use the function form and return RAX.
mov var, rv(MessageBox,hWin,"Text Message","Title",MB_OK)
deleted
hutch, the problem isn't string literal vs string pointer .. internally that amounts to the same thing.. it's when you want the string literal "abcd" to actually mean the number "60616263h" or whatever the ascii code is off hand :)
We've done a similar thing in uasm with the hll style calls and return types, the default is eax or rax unless you specify the return type explicitly on the PROTO. That way it can type check that the returned type fits into the register/variable you're putting it into.
John,
I probably have a touch of barbarian here but an assembler is a basic tool that lets you do things that really do not work and makes a mess of your app. Go down the path of hand holding and its a never ending disaster, it is really up to the user to know the difference between a number 1234 and 4 characters in quotes "1234". If a user makes a blunder like this, an error message should be what they get from making a mistake.
One of the things I like about 64 bit MASM is its crudity, it is one of the most terse tools I have ever used but you find mistakes (bugz) real fast when it crashes around your ears. You have the advantage of writing an assembler that can take the very rough edges off assembler programming but if you go the path of hand holding, you make your own cross very heavy to carry.
The rough distinction I am suggesting is to be able to turn off the requirement of type casting for string literals as it makes the include files much simpler and thus a lot easier to make reliable from the really messy Microsoft header files.
John,
My 2cts: Please leave it "as is", i.e. do the conversion to a string only if the routine explicitly asks for a pointer; that's what PROTO is good for. No coder will pass the immediate value "abcd" knowing that the routine needs a pointer - it must be chr$("abcd"), not "abcd" alias 64636261h.
It's not quite that simple unfortunately, the problem is the parser side of things.
It encounters INVOKE SOMEPROC , "ABCD"
Now, what does it do with "ABCD" ? In MASM, old JWASM etc that is simply converted to a numeric representation, if you tried more than 4 chars you'd get an error that the numeric value is too large, fair enough.
Now with string literals, if they're enabled.. what is that.. is it a 4 character string, which must be put in .const/.data and referenced with a pointer (like CSTR("") would) or must the immediate value be given.
That is where the ambiguity lies. It's easy enough to not require the argument type to be :PTR, but then that excludes one or the other ability. If we assume they are always string literals than you can never use "ABCD" as an immediate, which breaks existing code. Alternatively if we assume that they are always immediates, then you can't convert it to a literal. Either string literals must use a different delimiter other than " " or we have to use the argument type from the proto to clearly indicate the desired intention.
There is nothing stopping conversion/use of headers with basic types :DWORD, :QWORD etc it just means you can't use them as-is with string literals unless you modify them, wrap them or rely on an existing macro solution like CSTR.
JJ I agree, that was why this decision was taken.. it ensures that if and when you use a string literal in uasm, you have thought about the implication and the proto argument matches the intention of being a ptr.
I understand both parts arguments, however it appears that once we select OPTION LITERALS:ON anything enclosed between quotes will be considered a string, even if we don't have a PTR parameter, until we use OPTION LITERALS:OFF, as we do in the code below.
proc2 expects a qword but if we don't deactivate OPTION LITERALS:ON with OPTION LITERALS:OFF it will not even build.
option win64 : 11
includelib \masm32\lib64\kernel32.lib
includelib \masm32\lib64\user32.lib
MessageBoxA PROTO :QWORD,:PTR,:PTR,:DWORD
MessageBox equ <MessageBoxA>
ExitProcess PROTO :DWORD
proc2 proto :qword
.code
proc2 proc myValue : qword
ret
proc2 endp
main proc
OPTION LITERALS:ON
invoke MessageBox, 0, "Hello World", "Title", 0
OPTION LITERALS:OFF
invoke proc2, "abcd"
invoke ExitProcess,0
main endp
end
COMMENT ?
0007ff7`48d31006 33c9 xor ecx,ecx
00007ff7`48d31008 488d15f11f0000 lea rdx,[test6+0x3000 (00007ff7`48d33000)]
00007ff7`48d3100f 4c8d05f61f0000 lea r8,[test6+0x300c (00007ff7`48d3300c)]
00007ff7`48d31016 4533c9 xor r9d,r9d
00007ff7`48d31019 e819000000 call test6+0x1037 (00007ff7`48d31037)
00007ff7`48d3101e 48c7c164636261 mov rcx,61626364h
00007ff7`48d31025 e8d6ffffff call test6+0x1000 (00007ff7`48d31000)
00007ff7`48d3102a 33c9 xor ecx,ecx
00007ff7`48d3102c e800000000 call test6+0x1031 (00007ff7`48d31031)
?
This is what has me tossed, in MASM 64 bit with macros, I either get quoted text OR you put a number there, that can be an immediate or a variable and it is easy enough to parse, if the argument starts with a double quote, its a string, if its a number, its an immediate. If it can be done in the pre-processor in MASM it should not be a big deal when you are writing an assembler.
Now I have a work around, make all of the prototypes PTR and the string literals work and everything else is passed as a PTR in 64 bit Windows is 64 bit. Its just that its very untidy and misleading. If someone types "abcd" then it should generate an error.
Personally.. I would agree that using "abcd" as a numeric expectation/value isn't great in the first place.. but that's how MASM works and there is code out there expecting it to be that way.
I guess it has "a" place (pardon the quoted pun) :)
for example,
CompareDwordAsASCII PROC bufferPtr:PTR, dwordStringValue:DWORD
mov rdi,bufferPtr
mov eax,dwordStringValue
cmp [rdi],eax
....
and you'd call it with:
CompareDwordAsASCII ADDR myBuffer, "heap"
I imagine that most legacy uses are of this sort of style for 1/2/4 char strings.
AW that sounds like a bug to me in that case, the string should work as a literal string for message box and as a qword with value "abcd" after that.. i'll check that one.
I think I get what the problem John addressed happens to be. It is common to write mnemonics where you use quoted text for characters.
cmp eax, "x" ; and all other data sizes. "xx","xxxx","xxxxxxxx"
This is normal mnemonic coding practice but use it in a function call and it is ambiguous. It can be either quoted text "My Text" or a number "abcd". Rather than inflicting a form of strong typing to stop people from making an error, test if its a valid number "abcde" and generate an error if its not. It is just that quote text is just about universal across programming languages where quoted numbers "1234" are not.
If someone wants to put "abcd" in a function call, they are writing text "abcd". I would suggest that a data type "PTR" should only ever be an equate to the actual pointer size.
PTR equ <QWORD> ; in 64 bit
In Visual Studio C/C++, GCC, and others, we can pass multi-character constants within single-quotes. These are called multi-character literals and have type int (i,e 4 bytes). This behavior is considered implementation-defined, i.e, not part of the C/C++ standards.
For example, what C++14 (C is similar) says is:
"
An ordinary character literal that contains more than one c-char is a multicharacter literal. A multicharacter literal, or an ordinary character literal containing a single c-char not representable in the execution character set, is conditionally-supported, has type int, and has an implementation-defined value.
"
One conclusion we can take now is that the standards do not consider qword size (8 bytes) multi-character constants, they are limited to int (4 bytes).
Although is not absurd in Assembly Language to consider qword size multi-character constants, they are not a current practice. However, even if UASM restricts multi-character constants to dword size this will not make happy people that do not use prototypes, or consider them a girly thing - so, is a no-solution. In addition, for ASM is also a no solution to use single quotes specifically for that, since single quotes are an alternative to double quotes. I don't think the grave accent is an excellent solution, but is not bad at all, because not all keyboards have it (but people can always type ALT 96).
An example C implementation:
#include <stdlib.h>
#include <stdio.h>
void myFunction1(char *str)
{
printf("%s\n", str);
return;
}
void myFunction2(unsigned int myValue)
{
printf("0x%x\n", myValue);
return;
}
int main()
{
myFunction1("abcd");
myFunction2('abcd');
return 0;
}
Output:
abcd
0x61626364
I can do this in MASM easily.
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
include \masm32\include64\masm64rt.inc
.code
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
entry_point proc
mov rax, "abcdefgh" ; load immediate into register
conout "abcdefgh = ",str$(rax),lf ; display immediate src string + numeric result
waitkey
.exit
entry_point endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
end
Screen output,
abcdefgh = 7017280452245743464
Press any key to continue...
I know it required, and still requires, a lot of effort to produce brilliant macros to compensate for the MASM lack of features and shortcomings.
Macros will always have a significant place in all assemblers, whether they are called macro assemblers or not. Actually I never met an assembler that does not do macros and some have a much larger macro grammar than MASM.
This does not mean that we need to make a holy war against more advanced assemblers than MASM is, simply because they prefer to use internal code to replace some hand crafted macros. In my opinion - the perspective of a single user - the code becomes more clean when we don't abuse macros.