The MASM Forum

General => The Laboratory => Topic started by: hutch-- on August 14, 2014, 05:25:47 PM

Title: Simple algo to add DWORD size data together
Post by: hutch-- on August 14, 2014, 05:25:47 PM
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

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
Title: Re: Simple algo to add DWORD size data together
Post by: qWord on August 14, 2014, 07:14:34 PM
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
Title: Re: Simple algo to add DWORD size data together
Post by: hutch-- on August 14, 2014, 07:25:03 PM
 :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
Title: Re: Simple algo to add DWORD size data together
Post by: jj2007 on August 16, 2014, 01:30:57 AM
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
Title: Re: Simple algo to add DWORD size data together
Post by: hutch-- on August 16, 2014, 08:45:55 AM
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.
Title: Re: Simple algo to add DWORD size data together
Post by: jj2007 on August 16, 2014, 09:25:48 AM
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.
Title: Re: Simple algo to add DWORD size data together
Post by: hutch-- on August 16, 2014, 10:22:31 AM
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.
Title: Re: Simple algo to add DWORD size data together
Post by: hutch-- on August 16, 2014, 06:13:56 PM
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