News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

error A2114: INVOKE argument type mismatch : argument : 0

Started by Vortex, February 01, 2024, 06:21:59 AM

Previous topic - Next topic

Vortex

Hello,

The latest versions of Asmc and Poasm can assemble the code below. Ml.exe coming with the Masm32 package reports :

printfProto.asm(51) : error A2114: INVOKE argument type mismatch : argument : 0
.386
.model flat,stdcall
option casemap:none

ExitProcess PROTO :DWORD
__p__iob PROTO C
vfprintf PROTO C :DWORD,:VARARG
printfx PROTO C :DWORD,:VARARG

includelib  \masm32\lib\kernel32.lib
includelib  \masm32\lib\msvcrt.lib

_iobuf STRUCT

    _ptr        DWORD ?
    _cnt        DWORD ?
    _base       DWORD ?
    _flag       DWORD ?
    _file       DWORD ?
    _charbuf    DWORD ?
    _bufsiz     DWORD ?
    _tmpfname   DWORD ?

_iobuf ENDS

FILE TYPEDEF _iobuf

.data

format  db 'Pi is nearly equal to %f',0
pi      real8 3.141592

.code

start:

    invoke  printfx,ADDR format,ADDR pi
           
    invoke  ExitProcess,0

printfx PROC C _format:DWORD,args:VARARG

    invoke  __p__iob

;  #define stdout (&__iob_func()[1])

    add     eax,SIZEOF(FILE)

dummy:

    invoke vfprintf,eax,_format,args
    ret

printfx ENDP

END start


Edit : Replacing the invoke macro here with my own invoke macro is solving the issue :

    _invoke  vfprintf,eax,_format,args

fearless

Would it work by replacing?:

vfprintf PROTO C :DWORD,:VARARG
printfx PROTO C :DWORD,:VARARG

with:

vfprintf PROTO C :VARARG
printfx PROTO C :VARARG

_japheth

Hm, calling a "vararg"-proc from another "vararg"-proc, and simply hand over the vararg "argument" - that's a pretty adventurous thing to do. I doubt that AsmC or Poasm can do that in a way as it is "expected" by the programmer.

So perhaps Masm is right by simply rejecting this.
Dummheit, gepaart mit Dreistigkeit - eine furchtbare Macht.

HSE

Quote from: _japheth on February 01, 2024, 06:57:47 PMSo perhaps Masm is right by simply rejecting this.

Probably is just luck that others assemblers work in this example.

Must be tested with more arguments.

Old ML work with a little modification:
printfx PROC C _format:DWORD,args:VARARG
    local arg1:dword

    push args
    pop arg1

    invoke  __p__iob

;  #define stdout (&__iob_func()[1])

    add    eax,SIZEOF(FILE)

dummy:

    invoke    vfprintf,eax,_format,arg1
    ret

printfx ENDP

That work because there is only 1 argument in VARARG, with more arguments probably fail, I don't know.
Equations in Assembly: SmplMath

jj2007

Quote from: Vortex on February 01, 2024, 06:21:59 AMThe latest versions of Asmc and Poasm can assemble the code below.

I've put together a testbed based on your code, see attachment.

I builds and runs fine with UAsm, AsmC and PoAsm.
It fails with all MASM versions I've tested (6.14, 6.15, 14.0).

There is no problem with passing on the varargs, as long as the assembler is able to do that. UAsm, AsmC and PoAsm are able to do it, at point "Dummy" they pass the two arguments on the stack that they received above on entry into the main proc.

MASM can't do that, so it chokes - bad luck. I suggest to dump MASM and work with the improved clones instead. PoAsm is a good option, too, unfortunately not for me because my macros are too complex.

_japheth

Quote from: jj2007 on February 01, 2024, 11:21:16 PMThere is no problem with passing on the varargs, as long as the assembler is able to do that. UAsm, AsmC and PoAsm are able to do it, at point "Dummy" they pass the two arguments on the stack that they received above on entry into the main proc.

Well, I expressed myself very carefully in my post above (so nobody's feelings are hurt  :bgrin: ), but actually it is impossible inside a "vararg" procedure to determine at assembly-time the size of the vararg argument.
 Since the size is unknown to the assembler, how is an INVOKE, placed inside the procedure and using the procedure's vararg-argument as argument for a call, supposed to emit the correct number of pushes?
Dummheit, gepaart mit Dreistigkeit - eine furchtbare Macht.

Vortex

Hi fearless,

Thanks for the suggestion. Wih the modified prototypes, I receive the same error message :

vfprintf PROTO C :VARARG
printfx PROTO C :VARARG

printfx PROC C args:VARARG

    invoke  __p__iob

;   #define stdout (&__iob_func()[1])

    add     eax,SIZEOF(FILE)

    invoke  vfprintf,eax,args
    ret

printfx ENDP

printfProto.asm(52) : error A2114: INVOKE argument type mismatch : argument : 0

Vortex

Hi Japhet,

QuoteHm, calling a "vararg"-proc from another "vararg"-proc, and simply hand over the vararg "argument" - that's a pretty adventurous thing to do. I doubt that AsmC or Poasm can do that in a way as it is "expected" by the programmer.

Starting with VC 2019 ( or maybe even before ), MS decided to inline the good old printf function. Here is the case :

.
.
extern __declspec(dllimport) FILE* __cdecl __acrt_iob_func(unsigned);
#define stdin  (__acrt_iob_func(0))
#define stdout (__acrt_iob_func(1))
#define stderr (__acrt_iob_func(2))

#pragma comment (lib, "ucrtbase.lib")

__declspec(dllimport)  int __cdecl __stdio_common_vfprintf(long long, FILE*, char const* , int, va_list);

int printf(const char * format, ...)
{
int ret;
va_list vl;
va_start(vl, format);
ret = __stdio_common_vfprintf(0, stdout, format, 0, vl);
va_end(vl);
return ret;
}

https://masm32.com/board/index.php?msg=104933

Quotebut actually it is impossible inside a "vararg" procedure to determine at assembly-time the size of the vararg argument.

For 32-bit coding : True but for practical reasons, one can assume that every argument is DWORD sized for most of the time.

_japheth

Quote
Quotebut actually it is impossible inside a "vararg" procedure to determine at assembly-time the size of the vararg argument.

For 32-bit coding : True but for practical reasons, one can assume that every argument is DWORD sized for most of the time.

That's not the point here. The reason why your code may work ( does it indeed? ) is not because "all arguments are DWORDs", but because you're using vfprintf(). This function does NOT have a variable number of arguments, but exactly 3. Insofar your prototype for vfprintf in the first post is incorrect.
Dummheit, gepaart mit Dreistigkeit - eine furchtbare Macht.

Vortex

Hi Japheth,

Thanks, correcting the prototype :

int vfprintf ( FILE * stream, const char * format, va_list arg );
vfprintf PROTO C :DWORD,:DWORD,:VARARG
The correct approach :

    lea    ecx,args
    invoke  vfprintf,eax,_format,ecx

.data

pi      real8 3.141592
format  db '%s is nearly equal to %f',0
str1    db 'Pi',0

.code

start:

    invoke  printfx,ADDR format,ADDR str1,pi
           
    invoke  ExitProcess,0

printfx PROC C _format:DWORD,args:VARARG

    invoke  __p__iob

;  #define stdout (&__iob_func()[1])

    add    eax,SIZEOF(FILE)

    lea    ecx,args
    invoke  vfprintf,eax,_format,ecx
    ret

printfx ENDP

Hi Jochen,

Thanks for the Poasm samples. Sorry for the confusing label Dummy, it should be removed. The vfprintf based printf function is a compact and small implenentation.



NoCforMe

If you'll pardon a naive question, what about wsprintf()? I've used this probably hundreds of times in my code with never a problem. (I use MASM.)

It's in our windows.inc as
wsprintfA PROTO C :VARARG

So what's the big problem here?
Assembly language programming should be fun. That's why I do it.

Vortex

Hi NoCforMe,

wsprintfA PROTO C :VARARG
This one is valid too with the condition that the coder is careful to type the correct parameters.

Reading the documentation of Microsoft :

int WINAPIV wsprintfA(
  [out] LPSTR  unnamedParam1,
  [in]  LPCSTR unnamedParam2,
        ...   
);

https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-wsprintfa

wsprintfA PROTO C :DWORD,:DWORD,:VARARG
This full prototype is enforcing the user to specify the buffer receiving the formatted output and the format-control specification. One could miss the first two parameters with the prototype found in windows.inc

NoCforMe

Yes, yes, I know all that: first parm is the output buffer, second is the format string, and the rest are variables to be formatted. I can use that function in my sleep (and often do).

My question is why there's so much angst here about using vararg functions like wsprintf(). As I said, I've never had any problems using this with MASM. i use INVOKE, so the assembler takes care of stack management for me.

Is this a 64-bit problem?
Assembly language programming should be fun. That's why I do it.

_japheth

Quote from: NoCforMe on February 02, 2024, 07:52:12 AMSo what's the big problem here?

Perhaps none. Not all threads must handle a big problem.

Btw., it's also not mandatory to participate in a thread. If you have difficulties understanding what's going on - or just don't want to bother reading a thread carefully - then you might consider not to post at all.
Dummheit, gepaart mit Dreistigkeit - eine furchtbare Macht.

NoCforMe

Assembly language programming should be fun. That's why I do it.