The MASM Forum Archive 2004 to 2012

Project Support Forums => The GeneSys Development System => User Contributed Code => Topic started by: Vortex on October 24, 2006, 07:50:29 PM

Title: invoke macro simulator - updated
Post by: Vortex on October 24, 2006, 07:50:29 PM
Here is an example of simulating the invoke statement, it demonstrates the power of MASM's macro engine.

.386
.model flat, stdcall
option casemap :none

include \GeneSys\include\windows.inc
include \GeneSys\include\kernel32.inc
include \GeneSys\include\msvcrt.inc
include invoke.inc

includelib \GeneSys\lib\kernel32.lib
includelib \GeneSys\lib\msvcrt.lib

.data
message db "Hello world!",0
template db "%s",0

.code

start:

cinvoke _strupr,ADDR message
cinvoke printf,ADDR template,eax
_invoke ExitProcess,0

END start


invoke.inc :


_invoke MACRO funcname:REQ,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20
LOCAL pos

    FOR arg,<p20,p19,p18,p17,p16,p15,p14,p13,p12,p11,p10,p9,p8,p7,p6,p5,p4,p3,p2,p1>

        IFNB <arg>

             pos=@InStr(1,arg,<ADDR>) OR @InStr(1,arg,<addr>) OR @InStr(1,arg,<Addr>)

             IF pos

                IF (OPATTR(@SubStr(arg,%pos+5))) EQ 98
                        lea eax,@SubStr(<arg>,%pos+5)
                        push eax
                ELSE
                        push OFFSET @SubStr(<arg>,%pos+5)
                ENDIF

             ELSE
                        push arg
             ENDIF
        ENDIF
    ENDM
call funcname
ENDM

cinvoke MACRO funcname:REQ,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20
LOCAL pos,counter
counter=0

    FOR arg,<p20,p19,p18,p17,p16,p15,p14,p13,p12,p11,p10,p9,p8,p7,p6,p5,p4,p3,p2,p1>

        IFNB <arg>

             counter=counter+4
             pos=@InStr(1,arg,<ADDR>) OR @InStr(1,arg,<addr>) OR @InStr(1,arg,<Addr>)

             IF pos

                IF (OPATTR(@SubStr(arg,%pos+5))) EQ 98
                        lea eax,@SubStr(<arg>,%pos+5)
                        push eax
                ELSE
                        push OFFSET @SubStr(<arg>,%pos+5)
                ENDIF

             ELSE
                        push arg
             ENDIF
        ENDIF
    ENDM
call funcname

IF counter NE 0
    add esp,counter
ENDIF

ENDM

[attachment deleted by admin]
Title: Re: invoke macro simulator - updated
Post by: PBrennick on October 24, 2006, 08:30:18 PM
Here is another one, this one allows the user to use the exact same format as invoke, we have included this in our macro set.


.386
.model flat, stdcall
option casemap :none

include \GeneSys\include\windows.inc
include \GeneSys\include\kernel32.inc
include \GeneSys\include\msvcrt.inc

include \GeneSys\macros\macros.asm

includelib \GeneSys\lib\kernel32.lib
includelib \GeneSys\lib\msvcrt.lib

.data
message db "Hello world!",0

.code

start:

CallIt  printf, offset message, eax
Add     esp, 8
CallIt  ExitProcess, 0

END start



CallIt MACRO procedure, parameters:VARARG
  Local param, reversed

  reversed TEXTEQU <>
  %For param, <parameters>
    reversed CATSTR <param>, <!,>, reversed
  EndM
  %For param, <reversed>
    push param
  EndM
  call procedure
ENDM




[attachment deleted by admin]
Title: Re: invoke macro simulator - updated
Post by: Vortex on October 25, 2006, 04:47:34 AM
Now, the functionalities of both macros are united into one :

.code

start:

_invoke _strupr,ADDR message
_invoke printf,ADDR template,eax
_invoke ExitProcess,0

END start


invoke.inc :

_invoke MACRO funcname:REQ,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20
LOCAL pos,counter
counter=0

    FOR arg,<p20,p19,p18,p17,p16,p15,p14,p13,p12,p11,p10,p9,p8,p7,p6,p5,p4,p3,p2,p1>

        IFNB <arg>

             counter=counter+4
             pos=@InStr(1,arg,<ADDR>) OR @InStr(1,arg,<addr>) OR @InStr(1,arg,<Addr>)

             IF pos

                IF (OPATTR(@SubStr(arg,%pos+5))) EQ 98
                        lea eax,@SubStr(<arg>,%pos+5)
                        push eax
                ELSE
                        push OFFSET @SubStr(<arg>,%pos+5)
                ENDIF

             ELSE
                        push arg
             ENDIF
        ENDIF
    ENDM
call funcname

IF (OPATTR(funcname)) EQ 421
   IF counter NE 0
      add esp,counter
   ENDIF
ENDIF

ENDM

[attachment deleted by admin]
Title: Re: invoke macro simulator - updated
Post by: Vortex on October 29, 2006, 10:05:46 AM
Hi Paul,

printf is a C function, so your line :

CallIt  printf, offset message, eax

requires a manual stack balancing :

add esp,8
Title: Re: invoke macro simulator - updated
Post by: PBrennick on October 29, 2006, 01:37:04 PM
Thanks,
I hate that stack balancing requirement required by C functions. I am not a wizard at using C stuff like you are so if this is a silly question, please understand. How come these C functions do not balance the stack themselves. I cannot ever remember creating anything that did not do its own clean up when done. I have not coded in C in over 20 years so I cannot remember if this was always an issue. I know that printf, for example comes from C and was first created in the '80s.

Paul
Title: Re: invoke macro simulator - updated
Post by: hutch-- on October 30, 2006, 12:02:59 PM
Paul,

It is because the C calling convention handles a variable number of parameters which cannot be determined within the proc so it is designed for the caller to balance the stack rather than automatically doing it like STDCALL where the stack arg size is known.
Title: Re: invoke macro simulator - updated
Post by: PBrennick on October 30, 2006, 04:30:21 PM
Hutch,
Thank you for that reply, it is helpful but also leads into my next question. Do you think I could count parameters. If so, perhaps I could modify CallIt to count parameters, multipy by 4 and do a add esp,eax. How does that look to you? I know that you are a macro guru so I definitely value your input. The only bottleneck is the macro would have to know if the call is to a C function. That might not be possible.  :'(

Actually, perhaps it is better for me to write my own preprocessor for any C function that I happen to use, but I would rather know if there is some way of knowing from the macro. It would be the perfect solution.

Paul
Title: Re: invoke macro simulator - updated
Post by: Vortex on October 30, 2006, 06:10:20 PM
Hi Paul,

Check my latest version of invoke macro simulator above. ( invk_simul2.zip )

These two lines are keeping track of the number of parameters passed to the macro :

IFNB <arg>

             counter=counter+4
.
.


The code portion to detect C functions :

IF (OPATTR(funcname)) EQ 421
   IF counter NE 0
      add esp,counter
   ENDIF
ENDIF
Title: Re: invoke macro simulator - updated
Post by: zooba on October 31, 2006, 11:11:11 PM
Quote from: Vortex on October 30, 2006, 06:10:20 PM
The code portion to detect C functions :

IF (OPATTR(funcname)) EQ 421
   IF counter NE 0
      add esp,counter
   ENDIF
ENDIF


The IF (OPATTR(funcname)) EQ 421 should, I believe, use the AND operator (or a combination of AND and EQ), since OPATTR may return other details which will cause an equality check to fail. Though I haven't checked your 421 value, it looks like quite a few bits are set.

Cheers,

Zooba :U
Title: Re: invoke macro simulator - updated
Post by: MichaelW on November 01, 2006, 01:00:00 AM
Quote from: zooba on October 31, 2006, 11:11:11 PM
The IF (OPATTR(funcname)) EQ 421 should, I believe, use the AND operator (or a combination of AND and EQ), since OPATTR may return other details which will cause an equality check to fail. Though I haven't checked your 421 value, it looks like quite a few bits are set.

The set bits are:

0 – references a code label
2 – is immediate expression
5 – references no undefined symbols and is without error
7 – references an external label
8 – language type C

For an invoke I can't see how these bits could be set:

1 – is a memory expression or has a relocatable data label
3 – uses direct memory addressing
4 – is a register expression
6 – is SS relative memory expression

But what about bit 7 for a local C procedure (however unlikely that might be)?

Title: Re: invoke macro simulator - updated
Post by: Vortex on November 01, 2006, 11:10:48 AM
The set bits are:

0 – references a code label
2 – is immediate expression
5 – references no undefined symbols and is without error
7 – references an external label
8 – language type C


MichaelW is right, these are the bits. The trick to obtain the 421 value is to play with the OPATTR statement :

.386
.model flat,stdcall
option casemap:none

include \masm32\include\user32.inc
includelib \masm32\lib\user32.lib

temp    TEXTEQU %(OPATTR(wsprintf))

.code

start:

% echo temp

ret

END start


You get 421 as the result.
Title: Re: invoke macro simulator - updated
Post by: Vortex on November 01, 2006, 12:07:08 PM
This one is a sight modification :

IF ((OPATTR(funcname)) AND 11100000000y) EQ 00100000000y
   IF counter NE 0
      add esp,counter
   ENDIF
ENDIF

[attachment deleted by admin]
Title: Re: invoke macro simulator - updated
Post by: Vortex on April 19, 2007, 05:58:30 PM
Here is a new version. Thanks to E^cube to report the bugs in the macro.

_invoke MACRO funcname:REQ,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20
LOCAL pos,counter
counter=0

    FOR arg,<p20,p19,p18,p17,p16,p15,p14,p13,p12,p11,p10,p9,p8,p7,p6,p5,p4,p3,p2,p1>

        IFNB <arg>

counter=counter+4
pos=@InStr(1,arg,<ADDR >) OR @InStr(1,arg,<addr >) OR @InStr(1,arg,<Addr >)  OR \
                @InStr(1,arg,<ADDR >) OR @InStr(1,arg,<addr >) OR @InStr(1,arg,<Addr >)

             IF pos

                IF ((OPATTR(@SubStr(arg,%pos+5))) EQ 98) OR ((OPATTR(@SubStr(arg,%pos+5))) EQ 34)

                        lea eax,@SubStr(<arg>,%pos+5)
                        push eax
                ELSE
                        push OFFSET @SubStr(<arg>,%pos+5)
                ENDIF

             ELSE
                        push arg
             ENDIF
        ENDIF
    ENDM
call funcname

IF ((OPATTR(funcname)) AND 11100000000y) EQ 00100000000y ; Handle C functions
    IF counter NE 0
        add esp,counter ; correct the stack
    ENDIF
ENDIF

ENDM

[attachment deleted by admin]
Title: Re: invoke macro simulator - updated
Post by: gfalen on April 19, 2007, 07:05:08 PM
This functionality is already provided by invoke.  A more usefull implementation would allow
for immediate strings such as - invok SomeFunction, "Literal String".

[Edit]

$str MACRO _STR
local L
    if @InStr(1, <_STR>, <!">)
        .data
        ifdif <_STR>, <"">
            L db _STR
        endif
        db 0
        .code
        exitm <offset L>
    else
        exitm <_STR>
    endif
endm

invok MACRO _FUNC, _ARGS:VARARG
    $ARGS equ <>
    irp $V, <_ARGS>
        $ARGS catstr $ARGS, <,>, $str($V)
    endm
    % invoke _FUNC $ARGS
endm
Title: Re: invoke macro simulator - updated
Post by: ecube on April 20, 2007, 05:45:13 AM
Alright great!, thanks Vortex, i'll test it out  :bg
Title: Re: invoke macro simulator - updated
Post by: PBrennick on April 21, 2007, 09:41:08 PM
Thanks Vortex, it will be in the next update of the GeneSys SDK.

Paul
Title: Re: invoke macro simulator - updated
Post by: Vortex on December 16, 2008, 04:54:17 PM
This new version creates the functions prototypes :


_invoke MACRO FuncName:REQ,args:VARARG

LOCAL counter,params,StringSize
params TEXTEQU <>
counter = 0

    FOR param,<args>

        counter=counter+1

    ENDM

;   IFNDEF FuncName

        IF counter

            REPEAT counter
                params CATSTR params,<:DWORD,>
            ENDM

            params SUBSTR params,1,@SizeStr(%params)-1

        ENDIF

        FuncName PROTO STDCALL params

;   ENDIF

    IF counter
        invoke  FuncName,args
    ELSE
        invoke  FuncName
    ENDIF

ENDM

cinvoke MACRO FuncName:REQ,args:VARARG

LOCAL counter
counter = 0

    FOR param,<args>

        counter=counter+1

    ENDM

;   IFNDEF FuncName

        FuncName PROTO C :VARARG

;   ENDIF

    IF counter
        invoke  FuncName,args
    ELSE
        invoke  FuncName
    ENDIF

ENDM



[attachment deleted by admin]