News:

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

Main Menu

Quick play with UASM

Started by hutch--, July 21, 2019, 07:04:08 PM

Previous topic - Next topic

johnsa

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

hutch--

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.

hutch--

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.

johnsa

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.

hutch--

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.

johnsa

I'll have a think more about it, as long as whatever we do prevents ambiguity between "abcd"(CONSTANT NUMERIC) and "abcd"(STRING)

aw27

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, 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.


hutch--

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.

nidud

#53
deleted

hutch--

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)

nidud

#55
deleted

johnsa

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.

hutch--

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.

jj2007

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.

johnsa

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.