News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Simple algo to add DWORD size data together

Started by hutch--, August 14, 2014, 05:25:47 PM

Previous topic - Next topic

hutch--

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

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

qWord

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
MREAL macros - when you need floating point arithmetic while assembling!

hutch--

 :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

jj2007

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

hutch--

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.

jj2007

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.

hutch--

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.

hutch--

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