The align value of 4 isn't so good. :) It's already aligned by four. Also, there was an error in the align macro above - I hope you got the fix. :tongue: I'll play with it when I get home - I already have a working set-up for my code, but there is too much stuff mixed in to post.
Posted on 2002-06-21 14:18:22 by bitRAKE
@align MACRO val:REQ, sz:REQ

EXITM %((val*(sz))/sz)
ENDM
I removed the -1 because it's causing some graphical problems(see image below). Now fixed :) Thanks for the alignment macro!!!
Posted on 2002-06-21 14:19:59 by stryker
Really should be:
@align MACRO val:REQ, sz:REQ

EXITM %((val+sz-1)/sz)*sz)
ENDM
Sorry, I'm a little busy ATM - going in a million directions and all... :)
Posted on 2002-06-21 14:43:50 by bitRAKE
I'll post the final version to avoid confusion. :grin:

[size=9];by bitRAKE


@align MACRO val:REQ, sz:REQ
EXITM %(((val+sz-1)/sz)*sz)
ENDM

;by gfalen

@str MACRO _str:VARARG
LOCAL @@1
IF @InStr(1, <_str>, <!"> )
.DATA
@@1 DB _str, 0
.CODE
EXITM <OFFSET @@1>
ELSE
EXITM <_str>
ENDIF
ENDM

;by stryker

xcall MACRO function:REQ, parameters:VARARG
LOCAL psize, paddr, plen
IFNB <parameters>
psize = 0
FOR param, <parameters>
psize = psize + 4
ENDM
psize = @align((psize+4), [color=#3366FF][b]4[/b][/color]) [color=#3366FF][b];change alignment[/b][/color]
psize = psize - 4
sub esp, psize
psize = 0
FOR param, <parameters>
IF @SizeStr(<param> ) GT 4
paddr SUBSTR <param>, 1, 5
IFIDNI paddr, <ADDR >
paddr SUBSTR <param>, 6, @SizeStr(<param>) - 5
lea eax, paddr
mov DWORD PTR [esp+psize*4], eax
ELSE
mov DWORD PTR [esp+psize*4], @str(<param>)
ENDIF
ELSE
mov DWORD PTR [esp+psize*4], @str(<param> )
ENDIF
psize = psize + 1
ENDM
ENDIF
call function
ENDM[/size]
Thanks to all those who've contributed!!! :alright:
Posted on 2002-06-21 14:49:26 by stryker
stryker, there is no such thing as a final version. ;)
Posted on 2002-06-21 14:56:21 by bitRAKE
Yep, if I can just access the variable declarations on the data and data? sections plus the local variables, the macro could be tweaked more, plus determining the size of the variables(byte, word, qword, tbyte) would add functionality and flexibility to the macro. :)
Posted on 2002-06-21 14:59:57 by stryker
Ok, now I've listened to the conversations (unfortunately I've been lacking any really (advanced) macro training) and I've come to one conclusion: That I need to reread this whole thread one more time.

What benefits does this (xcall) have over (invoke)?
What does "@align" and "@str" do?
If a tree falls in a forest does anyone really care if it makes a sound?

I need instant gratification :) So a line by line commenting of the whole procedure is what you have to give me :alright:

Well, maybe you can just start with the first 2 questions and work on the rest later :)

Sliver
Posted on 2002-06-22 11:18:14 by Sliver
this thread might help you more!!! :) I designed it to accomplished this for example:


sub esp, 16
mov DWORD PTR [esp], NULL
mov DWORD PTR [esp+4], OFFSET MsgCaption
mov DWORD PTR [esp+8], OFFSET MsgTitle
mov DWORD PTR [esp+12], MB_OK
call MessageBox
which is "faster" than:


push MB_OK
push OFFSET MsgTitle
push OFFSET MsgTitle
push NULL
call MessageBox
these pushes are create by invoke.

As for @align bitRAKE might explain this much better.

As for @str this is a macro created by gfalen so it'll be easy to create text data for example:
xcall MessageBox, 0, "MsgCaption", "MsgTitle", MB_YESNO
You don't need to go to the data section and create or edit the contents of a text data. Nice Isn't it!! :)


Just remember when you use the xcall macro it only supports DWORD sizes(Most API calls are DWORD in size)...I'll see what I can do to improve it, so it can support any size.
Posted on 2002-06-22 11:30:46 by stryker
For some processors:
sub esp,X

mov [esp+4*i], Ni
mov [esp+4*(i-1)], N(i-1)
mov [esp+4*(i-2)], N(i-2)
...
mov [esp+4*0], N0
Is faster than:
push Ni

push N(i-1)
push N(i-2)
...
push N0
Also, if you were to hand code it, you could do the moves in any order that fit with the calculations you were doing, helping to eliminate dependancies and making maximum use of the registers.

@str - checks if a parameter is a constant string and creates the string if it is - returning the offset. Otherwise it just returns the parameter.

@align - returns the smallest interger multiple of the alignment size, that is equal or greaterthan the value passed. @align(24,16) would return 32. @align(8,4) would return 8 - it is already aligned.

I like to test macros using the ECHO keyword. Macros that return values always return text.
% ECHO @align(24,16)
Note the % forces MASM to evaluate the line, rather then just echoing it. Cool, huh!
Posted on 2002-06-22 11:35:07 by bitRAKE
Hi!
Compliments for clever macro, but i should say, that using it is not so good as it seems at first glance.

Let's compile this code-snippet:
(_call is macro i use instead of invoke. It puts params on stack in a general way)



xcall MessageBox, 0, "MsgCaption", "MsgTitle", MB_YESNO
_call MessageBox, 0, "MsgCaption", "MsgTitle", MB_YESNO


and take a look at disassembly from IDA:



:00401000 ; xcall MessageBox, 0, "MsgCaption", "MsgTitle", MB_YESNO
:00401000
:00401000 sub esp, 1Ch ; hWnd
:00401003 [COLOR=red]C7 04 24 00 00 00 00[/COLOR] mov [esp+1Ch+var_1C], 0
:0040100A [COLOR=red]C7 44 24 04 00 30 40 00[/COLOR] mov [esp+1Ch+var_18], offset szMsgcaption ; "MsgCaption"
:00401012 [COLOR=red]C7 44 24 08 0B 30 40 00[/COLOR] mov [esp+1Ch+var_14], offset szMsgtitle ; "MsgTitle"
:0040101A [COLOR=red]C7 44 24 0C 04 00 00 00[/COLOR] mov [esp+1Ch+var_10], 4
:00401022 E8 43 00 00 00 call MessageBoxA
:00401027
:00401027 ; _call MessageBox, 0, "MsgCaption", "MsgTitle", MB_YESNO
:00401027
:00401027 [COLOR=red]6A 04[/COLOR] push 4 ; uType
:00401029 [COLOR=red]68 14 30 40 00[/COLOR] push offset szMsgtitle_0 ; lpCaption
:0040102E [COLOR=red]68 1D 30 40 00[/COLOR] push offset szMsgcaption_0 ; lpText
:00401033 [COLOR=red]6A 00[/COLOR] push 0 ; hWnd
:00401035 E8 30 00 00 00 call MessageBoxA


You can see that xcall needs 31 bytes to pass 4 params to MessageBox.
But _call only 14 bytes.
31 - 14 = 17.
17 extra bytes for calling simple MessageBox!
If params are in registers the difference is yet more:
push reg - 1 byte
mov - 8 bytes

7 extra bytes for every reg-param.

Is it faster or slower does not matter at all if you call system function,
because system function basically are bad optimized.
Is it important for you, how many cpu circles does it take to call some func from kernel or user - 5000 or 5005?
It makes sense to use xcall only if you call your own func many times.
But in this instance it will be better, IMHO, to pass params through registers.

BUT BE CAREFULL! Things will get much worse if you use aligment option.
You get Stack Overflow or GPF error in very short order.

Suppose 32-byte alignment and let see what will happen in this code:


xcall GetModuleHandle, "Kernel32.dll" ; hInstance of Kernel32.dll
push eax ; save it for future use
xcall GetProcAddress, eax, "LoadLibraryA" ; addr of LoadLibraryA
pop eax ; restore hInstance of Kernel32.dll




:00401004 sub esp, 1Ch ; say esp = 0063FE3C
:00401007 mov [esp+1Ch+var_1C], offset aKernel32_dll ; esp = 0063FE20
:0040100E call GetModuleHandleA ; esp = 0063FE20
:00401013 push eax ; esp = 0063FE24
:00401014 sub esp, 1Ch ; esp = 0063FE20
:00401017 mov [esp+38h+var_38], eax ; esp = 0063FE04
:0040101A mov [esp+38h+var_34], offset aLoadlibrarya ; esp = 0063FE04
:00401022 call GetProcAddress ; esp = 0063FE04
:00401027 pop eax ; esp = 0063FE0C [COLOR=red]<-!!! it's not hInstance[/COLOR]
:00401028 ; esp = 0063FE10 [COLOR=red]<-!!! should be 0063FE3C[/COLOR]


GetModuleHandleA and GetProcAddress and all other know nothing about your aligment,
and according to stdcall conversion remove from stack 4 and 8 bytes accordingly.
And at address 00401027 you have garbage in eax instead of hInstance of Kernel32.dll!!!
In order to use xcall properly you should balance stack manually - nightmare, i think.

The macro i use:


_call MACRO arglist:VARARG

local n, a, sz, q, arg

n TEXTEQU @ArgCount( <arglist> )
% FOR arg, @ArgRev( <arglist> )
n TEXTEQU %(n - 1)
IF n EQ 0
call arg
IF (OPATTR ( arg )) AND 10000000y
;; References an external label
IF ((OPATTR ( arg )) AND 11100000000y) EQ 00100000000y
;; Uses C calling convention (_cdecl)
n TEXTEQU @ArgCount( <arglist> )
add esp, (n - 1) * sizeof DWORD
ENDIF
ENDIF
ELSE
IF @InStr(1, <arg>, <addr >) OR @InStr(1, <arg>, <ADDR >)
a SUBSTR <arg>, 6
IF $IsStack(a) ;; Is relative to SS
lea eax, a
push eax
ELSE
push offset a
ENDIF
ELSEIF @InStr(1, @SubStr(<arg>, 1 , 1), <!">)
push $TO(,<arg>,)
ELSEIF @InStr(1, @SubStr(<arg>, 1 , 1), <&>)
a SUBSTR <arg>, 2
IF $IsStack(a) ;; Is relative to SS
lea eax, a
push eax
ELSE
push offset a
ENDIF
ELSE
IF $IsImm(arg)
push arg
ENDIF
ENDIF
ENDIF
ENDM
ENDM

$call MACRO arglist:VARARG
_call arglist
EXITM <eax>
ENDM

If possible _call tries to use push offset, if not - lea eax, param/push eax.
To pass addresses you can use addr or ADDR but not aDDr, Addr etc... or you can use c-like &.
What @ArgCount, $IsStack and other macros do see in attachment.
Hope this will be interesting for all of you.
Posted on 2002-06-23 05:50:22 by Four-F
Great work, guys. Our apps will at least run 0,1 micro seconds faster (but possibly load 0,2 microseconds slower because of larger file size :) ).

what Four-F said about alignment seems to be a severe bug. I think in Win32 esp should be always dword-aligned. So instead of adjusting esp it may be better to display a warning if esp is "wrong" (if anything at all).

About speed: I doubt that manuelly "pushing" parms is faster than push if it is a call with just one parameter. So the macro should be adjusted to handle this special case.

To Four-F: could you please explain me what is the advantage of your macro compared with the standard "invoke"?

japheth
Posted on 2002-06-23 11:18:58 by japheth
Four-F, you have stated some very good points. I think the alignment should be left out - it really requires the stack to be aligned all the time.

japheth, there are many features that can be added to the macros to automate providing better performance, but the best optimizer is always going to be manually coding the instructions.

Here is the fix for the stack alignment:
__STACK_ALIGNMENT__ EQU 16


@align MACRO val:REQ, sz:REQ
EXITM %(((val+sz-1)/sz)*sz)
ENDM

;by gfalen

@str MACRO _str:VARARG
LOCAL @@1
IF @InStr(1, <_str>, <!"> )
.DATA
@@1 DB _str, 0
.CODE
EXITM <OFFSET @@1>
ELSE
EXITM <_str>
ENDIF
ENDM

;by stryker

xcall MACRO function:REQ, parameters:VARARG
LOCAL psize, paddr, plen, palign

IFNB <parameters>
psize = 0
FOR param, <parameters>
psize = psize + 4
ENDM
palign = @align((psize+4), __STACK_ALIGNMENT__) - 4 - psize
sub esp, psize + palign
psize = 0
FOR param, <parameters>
IF @SizeStr(<param> ) GT 4
paddr SUBSTR <param>, 1, 5
IFIDNI paddr, <ADDR >
paddr SUBSTR <param>, 6, @SizeStr(<param> ) - 5
lea eax, paddr
mov DWORD PTR [esp+psize*4], eax
ELSE
mov DWORD PTR [esp+psize*4], @str(<param> )
ENDIF
ELSE
mov DWORD PTR [esp+psize*4], @str(<param> )
ENDIF
psize = psize + 1
ENDM
ENDIF
call function
IF palign NE 0
add esp,palign
ENDIF
ENDM
Posted on 2002-06-23 11:50:03 by bitRAKE
If you don't want to use alignment at all(Which was the original version), use this macro added with what japheth said about only 1 parameter. By the way, the ADDR is not limited to ADDR or addr but to any uppercase-lowercase combo .eg. aDdR ...
;by gfalen


@str MACRO _str:VARARG
LOCAL @@1
IF @InStr(1, <_str>, <!"> )
.DATA
@@1 DB _str, 0
.CODE
EXITM <OFFSET @@1>
ELSE
EXITM <_str>
ENDIF
ENDM

;by stryker

xcall MACRO function:REQ, parameters:VARARG
LOCAL psize, paddr, plen
IFNB <parameters>
psize = 0
FOR param, <parameters>
psize = psize + 4
ENDM
IF psize EQ 4
push parameters
ELSE
sub esp, psize
psize = 0
FOR param, <parameters>
IF @SizeStr(<param> ) GT 4
paddr SUBSTR <param>, 1, 5
IFIDNI paddr, <ADDR >
paddr SUBSTR <param>, 6, @SizeStr(<param> ) - 5
lea eax, paddr
mov DWORD PTR [esp+psize*4], eax
ELSE
mov DWORD PTR [esp+psize*4], @str(<param> )
ENDIF
ELSE
mov DWORD PTR [esp+psize*4], @str(<param> )
ENDIF
psize = psize + 1
ENDM
ENDIF
ENDIF
call function
ENDM
Haven't tested bitRAKE's modified version yet. And remember folks, this only supports DWORD parameters. I'll test with QWORD(2 pushes) later.
Posted on 2002-06-23 22:48:23 by stryker
Stryker,
What program is that a screen shot from?

Sliver
Posted on 2002-06-24 00:26:06 by Sliver
IDA Pro :)
Posted on 2002-06-24 00:50:55 by stryker

what Four-F said about alignment seems to be a severe bug. I think in Win32 esp should be always dword-aligned. So instead of adjusting esp it may be better to display a warning if esp is "wrong" (if anything at all).


Right. I meant alignment other then DWORD.


To Four-F: could you please explain me what is the advantage of your macro compared with the standard "invoke"?


None ;-) Except for:


mov var, $call(SomeFunc1,,,,,$call(SomeFunc2,,,))

and


_call SomeFuncWithTextParam,,,,"SomeText",,


But main disadvantage is no param type/number checking.


If you don't want to use alignment at all(Which was the original version), use this macro added with what japheth said about only 1 parameter. By the way, the ADDR is not limited to ADDR or addr but to any uppercase-lowercase combo .eg. aDdR ...


If 0,0001% of speed increasing is more important than 1% larger size use it.
Sorry, but personally i can't see any advantage of using it.
Posted on 2002-06-24 02:26:24 by Four-F