Just occasionally I need something like this to simplify the index calculations of complex addressing. The algo is normal stack based so it will take registers, memory operands or immediates as arguments. Importantly you must match the arg count to the counter to ensure the stack is balanced.
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
; vaddc PROTO c :DWORD,:VARARG ;<<< prototype
align 4
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
vaddc proc c cnt:DWORD,argz:VARARG
; -----------------------------------------
; add a sequence of 32 bit numbers together
; arg count must match the 1st arg counter
; -----------------------------------------
xor eax, eax ; zero EAX
mov ecx, 8 ; use ECX as the index register
mov edx, [esp+4] ; put the counter in a register
@@:
add eax, [esp+ecx] ; add each arg to EAX
add ecx, 4 ; add 4 to get next arg
sub edx, 1 ; sub the loop counter by 1
jnz @B
; return value is already in EAX
ret
vaddc endp
OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
hutch,
isn't this task predestinated for a macro? :biggrin:
; EDX is the accumulator register, EAX is used for ADDR-operator
vadd macro args:VARARG
vadd_edx_initialized = 0
FOR arg,<&args>
vadd_has_addr_op = 0
IF @SizeStr(<&arg>) GT 5
vadd_pos1 INSTR <&arg>,<ADDR>
vadd_pos2 INSTR <&arg>,<Addr>
vadd_pos3 INSTR <&arg>,<addr>
IF vadd_pos1 EQ 1 OR vadd_pos2 EQ 1 OR vadd_pos3 EQ 1
IFB @SubStr(<&arg>,5,1)
vadd_has_addr_op = -1
ENDIF
ENDIF
ENDIF
IF vadd_has_addr_op
IF vadd_edx_initialized
lea eax,@SubStr(<&arg>,5,)
add edx,eax
ELSE
lea edx,@SubStr(<&arg>,5,)
ENDIF
ELSE
IF vadd_edx_initialized
add edx,arg
ELSE
mov edx,arg
ENDIF
ENDIF
vadd_edx_initialized = -1
ENDM
IFE vadd_edx_initialized
xor edx,edx
ENDIF
endm
e.g.:
LOCAL foo:DWORD
; ...
vadd ADDR foo, 123, ecx, foo
; result in edx
:biggrin:
Most probably but I did want it to be useful in a general purpose sense.
Slightly later. :P
This seems to work OK.
addup MACRO args:VARARG
LOCAL acnt
acnt = argcount(args) ;; macro to count args
invoke vaddc,acnt,args ;; make proc call with arg count and args
EXITM <eax> ;; return EAX in function position
ENDM
Here is a variant that keeps ecx intact:
mov edx, [esp+4] ; put the counter in a register
xor eax, eax ; zero EAX
lea edx, [esp+4*edx] ; put the counter in a register
@@:
sub edx, 4 ; sub the loop counter by 1
add eax, [edx+8] ; add each arg to EAX
cmp edx, esp
jg @B
I am not sure what your gain is in saving ECX but trashing EDX. They are both expendable as transient registers so I don't see that it matters as the algo needs 2 registers to work.
Quote from: hutch-- on August 16, 2014, 08:45:55 AM
I am not sure what your gain is in saving ECX but trashing EDX.
Your version is same speed & size but trashes ecx AND edx.
The problem is I conform to the Intel ABI which makes EAX ECX and EDX expendable. I don't impose extra conditions above and beyond the OS design on how I use registers.
Here is a basic macro design that makes the function call even simpler. It comes at the price that any value must occur in the right order but it allows you to use closer to high level notation without having to declare a LOCAL variable for the return value. The macro allocates a DWORD variable in the DATA? section and returns it in the EXITM operator. What it effectively is doing is allowing the DATA? section variable to be renamed to the convenience of the programmer.
The technique is not entirely compatible with conventional MASM code but it works fine and is a possible vehicle for a simplified language for performing specialised tasks.
It allows you to use notation like,
retnv = addup(123,ecx,ADDR buffer,esi)
The macro is as follows.
addup MACRO args:VARARG
LOCAL acnt
LOCAL rval
.data?
rval dd ?
.code
acnt = argcount(args) ;; macro to count args
invoke vaddc,acnt,args ;; make proc call with arg count and args
mov rval, eax ;; place the return value in a DATA? section variable
EXITM <rval> ;; return the variable in the function position
ENDM