Author Topic: Assembler mistake: CALL vs INVOKE  (Read 1341 times)

NoCforMe

  • Member
  • *****
  • Posts: 1124
Assembler mistake: CALL vs INVOKE
« on: September 12, 2022, 06:47:54 AM »
And by assembler mistake, I mean a mistake on the part of MASM, the macro assembler, not me. I think.

In my editor program I kept losing the "Goodies" dialog; sometimes it just wouldn't come up at all. Traced the problem to my custom mcListbox control in that dialog. It wasn't getting initialized, therefore Windows sent destroy messages to the dialog even before it got created.

Long story short: it wasn't getting initialized because I wasn't calling my initialization function correctly. It's defined as

Code: [Select]
InitmcLB PROC hInst:HINSTANCE

and yet I was able to do this:

Code: [Select]
CALL InitmcLB
(because at some earlier point it had no parameter)

Shouldn't this have generated an assembler error? Like INVOKing with too many or too few arguments? It just said "fine, whatever".

BAD assembler. Bad boy.
(The weird thing is, it worked most of the time, even though the instance handle wasn't getting set correctly in RegisterClassEx(). ????)


zedd151

  • Member
  • *****
  • Posts: 1968
Re: Assembler mistake: CALL vs INVOKE
« Reply #1 on: September 12, 2022, 06:59:47 AM »
Masm only checks arg count for "invoke". That is one of its main purposes, along with type checking for the arguments. If you use "call" instead, no argument count or argument type checking is done - that is left up to the coder in that instance.  call != invoke, unless argument count and type are correct.
Regards, zedd.
:tongue:

jj2007

  • Member
  • *****
  • Posts: 13957
  • Assembly is fun ;-)
    • MasmBasic
Re: Assembler mistake: CALL vs INVOKE
« Reply #2 on: September 12, 2022, 07:54:37 AM »
Swordfish is correct. How should the assembler even know how many parameters you pushed before the call, e.g. in the simple example below?

NoCforMe

  • Member
  • *****
  • Posts: 1124
Re: Assembler mistake: CALL vs INVOKE
« Reply #3 on: September 12, 2022, 08:13:27 AM »
Right. Although still, if you think about it: when you do push-push-call, you're generally not calling a procedure name; you're calling either through a DWORD variable or register. (Until I saw your example I didn't even know that you could call a function by name this way.)

If I were the one writing the assembler, I think I'd at least flag it as a warning of someone made the mistake I did here. Because clearly my subroutine takes an argument, which I'm not (explicitly) providing.

Or maybe they should give us an option to flag such warnings or not.

But then, MASM isn't "strongly typed" like C is, so it gives us programmers more, and more interesting, ways to get into trouble.

jj2007

  • Member
  • *****
  • Posts: 13957
  • Assembly is fun ;-)
    • MasmBasic
Re: Assembler mistake: CALL vs INVOKE
« Reply #4 on: September 12, 2022, 08:58:32 AM »
when you do push-push-call, you're generally not calling a procedure name; you're calling either through a DWORD variable or register.

In my code, 95% of the push-push-calls concern procedure names, only a handful call registers or memory. However, I rarely use push-push-call, mostly to save some bytes as in the example above. The invoke macro is a lot safer, handier and more transparent.

hutch--

  • Administrator
  • Member
  • ******
  • Posts: 10583
  • Mnemonic Driven API Grinder
    • The MASM32 SDK
Re: Assembler mistake: CALL vs INVOKE
« Reply #5 on: September 12, 2022, 11:50:59 AM »
Its an interesting case where the traditional "invoke" notation in 32 bit MASM had arg count checking which helped a lot of people catch errors in their code. Traditionally, assemblers never needed such things (real men[tm] etc ....) and while it was introduced about 1990 to make MASM a bit more usable, it only lingered on as it was too much hassle to change it.

Come 64 bit which is mainly new code (apart from the pre-processor) and "bye bye" high level constructions. The old (read ancient) pre-processor in part compensated for this shortfall with enough macros but 64 bit MASM was pointed at people who actually know how to write code of that type.

Now this comes down to using the documentation to get the argument count and type right. Hardware is never gracious, it expects the right data to be pointed at it and will do horrible things if you get it wrong. While the old "Blue Screen Of Death" had a reputation, a real[tm] phukup was the instant "black screen of death", even in protected mode 32 and 64 bit code. At least you knew something was wrong when it happened.

The old rule still applies here, RTFM, understand it and pass the correct data/arguments to the CPU.  :rolleyes:
hutch at movsd dot com
http://www.masm32.com    :biggrin:  :skrewy:

NoCforMe

  • Member
  • *****
  • Posts: 1124
Re: Assembler mistake: CALL vs INVOKE
« Reply #6 on: September 12, 2022, 01:05:19 PM »
The old rule still applies here, RTFM, understand it and pass the correct data/arguments to the CPU.  :rolleyes:

Yes, agree 1003% (especially the RTFM part*). Just one quibble, though: we're miles (kilometers) away from the actual CPU here, what with HAL** and all (unless you do something really gross to the FPU and it pukes all over you) ...

* In a previous life I was a tech writer who wrote computer manuals. Good ones, I was told by my customers, unlike the other shit out there.
** "Hardware abstraction layer" (whatever the hell that is)

jj2007

  • Member
  • *****
  • Posts: 13957
  • Assembly is fun ;-)
    • MasmBasic
Re: Assembler mistake: CALL vs INVOKE
« Reply #7 on: September 12, 2022, 06:39:55 PM »
the traditional "invoke" notation in 32 bit MASM had arg count checking which helped a lot of people catch errors in their code. Traditionally, assemblers never needed such things (real men[tm] etc ....)

Real Men[tm] know how to write macros that are understood even by ML64:

Code: [Select]
mov hEdit, rv(CreateWindowEx, 0, Chr$("RichEdit20A"), NULL, reStyle, 0, 0, 1, 1, hWnd, ID_EDIT, wcx.hInstance) ; one less
mov hEdit, rv(CreateWindowEx, 0, Chr$("RichEdit20A"), NULL, reStyle, 0, 0, 1, 1, hWnd, ID_EDIT, wcx.hInstance, NULL)
mov hEdit, rv(CreateWindowEx, 0, Chr$("RichEdit20A"), NULL, reStyle, 0, 0, 1, 1, hWnd, ID_EDIT, wcx.hInstance, NULL, 123) ; one more

Code: [Select]
*** Assemble using ml64  ***
 Assembling: tmp_file.asm
** 64-bit assembly **
## line 32: not enough arguments for CreateWindowExA ##
## line 34: too many arguments for CreateWindowExA ##

daydreamer

  • Member
  • *****
  • Posts: 2399
  • my kind of REAL10 Blonde
Re: Assembler mistake: CALL vs INVOKE
« Reply #8 on: September 12, 2022, 06:46:16 PM »
the advantage of call vs invoke when no arguments proc is invoke sometimes need you define proto procname to work,but call doesnt

my none asm creations
http://masm32.com/board/index.php?topic=6937.msg74303#msg74303
I am an Invoker
"An Invoker is a mage who specializes in the manipulation of raw and elemental energies."
Like SIMD coding

NoCforMe

  • Member
  • *****
  • Posts: 1124
Re: Assembler mistake: CALL vs INVOKE
« Reply #9 on: September 12, 2022, 07:46:17 PM »
The disadvantage of call vs. invoke is that although you don't need to define a prototype, your chances of screwing up the number or order of arguments using push-push-call are much higher (and won't be caught by the assembler but will cause mysterious run-time errors).

But Real Men™...

daydreamer

  • Member
  • *****
  • Posts: 2399
  • my kind of REAL10 Blonde
Re: Assembler mistake: CALL vs INVOKE
« Reply #10 on: September 12, 2022, 08:01:53 PM »
the advantage of call vs invoke when no arguments proc is invoke sometimes need you define proto procname to work,but call doesnt
makes me wonder if this will work?
Code: [Select]
proc number1
LOCAL x,y,z:DWORD
mov x,100
mov y,200
mov z,65
call procthatneeds3argument
ret ;???? maybe need some adjustment to not crash after the above trick?
endp number1
;locals are placed on stack in 32bit assembly,will the called proc use x,y,z instead of 3 pushed arguments?
would be useful if called proc uses local array?
my none asm creations
http://masm32.com/board/index.php?topic=6937.msg74303#msg74303
I am an Invoker
"An Invoker is a mage who specializes in the manipulation of raw and elemental energies."
Like SIMD coding

hutch--

  • Administrator
  • Member
  • ******
  • Posts: 10583
  • Mnemonic Driven API Grinder
    • The MASM32 SDK
Re: Assembler mistake: CALL vs INVOKE
« Reply #11 on: September 12, 2022, 08:48:10 PM »
 :biggrin:

> Real Men[tm] know how to write macros that are understood even by ML64:

Yeah yeah, but at the cost of massive overhead when at last count, there are over 15 thousand API functions. The old rule applies, get the argument count right and pass the correct data.
hutch at movsd dot com
http://www.masm32.com    :biggrin:  :skrewy:

jj2007

  • Member
  • *****
  • Posts: 13957
  • Assembly is fun ;-)
    • MasmBasic
Re: Assembler mistake: CALL vs INVOKE
« Reply #12 on: September 12, 2022, 08:52:26 PM »
at the cost of massive overhead when at last count, there are over 15 thousand API functions

Slightly less massive than Windows.inc

hutch--

  • Administrator
  • Member
  • ******
  • Posts: 10583
  • Mnemonic Driven API Grinder
    • The MASM32 SDK
Re: Assembler mistake: CALL vs INVOKE
« Reply #13 on: September 12, 2022, 09:16:42 PM »
 :biggrin:

I think you know this response, REAL MEN[tm] don't need someone to hold their hot little hand when if they stuff it up, they generally know why.  :tongue:
hutch at movsd dot com
http://www.masm32.com    :biggrin:  :skrewy:

jj2007

  • Member
  • *****
  • Posts: 13957
  • Assembly is fun ;-)
    • MasmBasic
Re: Assembler mistake: CALL vs INVOKE
« Reply #14 on: September 13, 2022, 12:43:57 AM »
The jinvoke (the one that teaches ML64 to count and check arguments) is 458 lines long (and that's only a small part of the JBasic 64-/32-bit dual assembly framework). Guess what? Nobody held my hot little hand when I coded it.