Here is a little exercise: Find a macro that saves 5 arguments to memory for later use. The macro should have no more than 20 lines, and their should be no restrictions regarding the 32-bit registers used as arguments. Global DWORD variables are also allowed. Hint: It is possible :bg
include \masm32\include\masm32rt.inc
Store5 Macro arg1, arg2, arg3, arg4, arg5
...
ENDM
.data?
MyDword dd ?
Store5Buffer dd 64 dup(?)
.code
start:
... ; 10 bytes overhead
Store5 eax, ecx, edx, esi, edi ; 12 plus one per reg32, 6 per global var
Store5 MyDword, ecx, edx, esi, edi ; 12+6+4=22 bytes
Store5 MyDword, ecx, edx, esi, MyDword ; 12+2*6+3=27
inkey "No crash so far"
exit
end start
:bg
push arg1
push arg2
push arg3
push arg4
push arg5
Later.
pop arg5
pop arg4
pop arg3
pop arg2
pop arg1
:P
i like the second one Hutch :P
Ok, I see that was too liberal, so let me introduce a constraint: You need the content of memory later on deep inside a proc, and you have no idea what happened to the stack in the meantime. Use Store5Buffer.
:green2
push arg5
pop Store5Buffer[16]
push arg4
pop Store5Buffer[12]
push arg3
pop Store5Buffer[8]
push arg2
pop Store5Buffer[4]
push arg1
pop Store5Buffer
with a little word-play, you can make it support a variable number of arguments
you could also add some verbage to use MOV if the argument is a register
you know me, Jochen - macro comes on a plate with cheesy sauce :bg
What ever the sense is ... look at this :bg
Store5 Macro arg1, arg2, arg3, arg4, arg5
IFNDEF s5_cntr
s5_cntr = 0
ENDIF
IF s5_cntr+5 GT ((SIZEOF Store5Buffer)/4)
%echo ERR: overflow ;)
EXITM
ENDIF
cntr = 0
REPEAT 5
% IF (OPATTR getarg(%(cntr+1),<arg1,arg2,arg3,arg4,arg5>)) AND 010000y
mov Store5Buffer[s5_cntr*4+cntr*4], getarg(%(cntr+1),<arg1,arg2,arg3,arg4,arg5>)
ELSE
push getarg(%(cntr+1),<arg1,arg2,arg3,arg4,arg5>)
pop Store5Buffer[s5_cntr*4+cntr*4]
ENDIF
cntr = cntr + 1
ENDM
s5_cntr = s5_cntr + 5
ENDM
Not bad, really not bad... :U
17 bytes for macJ
35 bytes for macD
29 bytes for macQ
Quote from: jj2007 on January 31, 2010, 06:05:50 PM
17 bytes for macJ
17 bytes ... :
Store5 Macro arg1, arg2, arg3, arg4, arg5
IFNDEF s5_cntr
s5_cntr = 0
.data
_esp dd OFFSET Store5Buffer + (sizeof Store5Buffer)
.code
ENDIF
IF s5_cntr+5 GT ((SIZEOF Store5Buffer)/4)
%echo ERR: overflow ;)
EXITM
ENDIF
cntr = 1
xchg _esp,esp
REPEAT 5
push getarg(%(cntr),<arg1,arg2,arg3,arg4,arg5>)
cntr = cntr + 1
ENDM
xchg esp,_esp
s5_cntr = s5_cntr + 5
ENDM
Thanks, Dave & qWord - you were pretty close :toothy
include \masm32\include\masm32rt.inc
Store5J Macro arg1, arg2, arg3, arg4, arg5
xchg esp, Store5Buffer[20]
push arg1
push arg2
push arg3
push arg4
push arg5
add esp, 20
xchg esp, [esp]
ENDM
Store5D Macro arg1, arg2, arg3, arg4, arg5
push arg5
pop Store5Buffer[16]
push arg4
pop Store5Buffer[12]
push arg3
pop Store5Buffer[8]
push arg2
pop Store5Buffer[4]
push arg1
pop Store5Buffer
ENDM
Store5Q Macro arg1, arg2, arg3, arg4, arg5
IFNDEF s5_cntr
s5_cntr = 0
.data
_esp dd OFFSET Store5Buffer + (sizeof Store5Buffer)
.code
ENDIF
IF s5_cntr+5 GT ((SIZEOF Store5Buffer)/4)
%echo ERR: overflow ;)
EXITM
ENDIF
cntr = 1
xchg _esp,esp
REPEAT 5
push getarg(%(cntr),<arg1,arg2,arg3,arg4,arg5>)
cntr = cntr + 1
ENDM
xchg esp,_esp
s5_cntr = s5_cntr + 5
ENDM
.data?
MyDword1 dd ?
MyDword2 dd ?
Store5Buffer dd 6 dup(?)
.code
start:
mov Store5Buffer[20], offset Store5Buffer+5*4 ; 10 bytes overhead for Store5J
mov ebx, esp ; just a little test whether the stack is still OK after the macros
mjs:
REPEAT 5
Store5J MyDword1, ecx, edx, esi, MyDword2 ; 12 plus one per reg32, 6 per global var: 12+2*6+3=27
Store5J eax, ecx, edx, esi, edi ; 12 plus one per reg32, 6 per global var: 12+5=17
ENDM
mje:
mds:
REPEAT 5
Store5D MyDword1, ecx, edx, esi, MyDword2
Store5D eax, ecx, edx, esi, edi
ENDM
mde:
mqs:
REPEAT 5
Store5Q MyDword1, ecx, edx, esi, MyDword2
Store5Q eax, ecx, edx, esi, edi
ENDM
mqe:
sub ebx, esp ; just a little test whether the stack is still OK after the macros
je @F
print "Somebody just crashed the stack, shame on you!", 13, 10
@@:
mov eax, mje
sub eax, mjs
print str$(eax), " bytes for 10*macJ", 13, 10
mov eax, mde
sub eax, mds
print str$(eax), " bytes for 10*macD", 13, 10
mov eax, mqe
sub eax, mqs
print str$(eax), " bytes for 10*macQ, qWord cheats!!!", 13, 10, 10
inkey "No crash so far, thanks"
exit
end start
Quote from: jj2007 on January 31, 2010, 10:00:06 PM
xchg esp, Store5Buffer[20]
...
add esp, 20
xchg esp, [esp]
tricky one :clap:
qWord
Quote from: qWord on January 31, 2010, 10:20:31 PM
tricky one :clap:
qWord
Thanks :bg
Here is the general form for any number of arguments:
Store2Mem MACRO TheArgs:VARARG
LOCAL argct, arg
argct = 0
FOR arg, <TheArgs>
argct = argct + 1
ENDM
MyBuf CATSTR <Store2MemBuffer>, %argct ; we check if the buffer has been created
% ifndef MyBuf
.data?
MyBuf dd argct+1 dup(?)
.code
mov MyBuf[argct*4], offset MyBuf+argct*4 ; 10 bytes overhead per argct
endif
xchg esp, MyBuf[argct*4]
FOR arg, <TheArgs>
push arg
ENDM
add esp, argct*4
xchg esp, [esp]
ENDM
Usage:
REPEAT 5 ; per argct 10 bytes overhead; then x per macro call: 10+5*(27+17)=230
Store2Mem MyDword1, ecx, edx, esi, MyDword2 ; 12 plus one per reg32, 6 per global var: 12+2*6+3=27
Store2Mem eax, ecx, edx, esi, edi ; 12 plus one per reg32, 6 per global var: 12+5=17
ENDM
REPEAT 5 ; per argct 10 bytes overhead; then x per macro call: 10+5*(19+14)=175
Store2Mem MyDword1, ecx ; 12 plus one per reg32, 6 per global var: 12+6+1=19
Store2Mem eax, ecx ; 12 plus one per reg32, 6 per global var: 12+2=14
ENDM
230 bytes for 10*Store2Mem, 5 args
175 bytes for 10*Store2Mem, 2 args
Full code attached. Its practical usage might be in writing prologues for 64-bit Masm etc...(?)
I got inspired to write this because it's difficult to have macros that accept regs and globals but don't trash any regs. And push/pop are the only mem to mem instructions that require only one register (the others being movsxx).