News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

str$, hex$ etc macros: use offset, not addr

Started by jj2007, July 03, 2008, 12:10:53 PM

Previous topic - Next topic

jj2007

I stumbled over a little problem:

mov edi, HEX$(SelDW)         ; hex$ creates its own buffer, and should pass the pointer

Actually, it does pass the pointer, but as follows:

    hex$ MACRO DDvalue
      LOCAL rvstring
      .data
        rvstring db 12 dup (0)
        align 4
      .code
      invoke dw2hex,DDvalue,ADDR rvstring
      EXITM <ADDR rvstring>
    ENDM


ml.exe chokes on mov edi, ADDR rvstring but not on mov edi, OFFSET rvstring. Codewise the two versions are identical, since rvstring sits in the .data (why not .data?) section.

The macros following hex$ in macros.asm, e.g. ubyte$, already have the offset notation.

Jimg

This is a problem throughout macros.asm, starting with the very first macro, reparg.

Is there any reason to use ADDR at any time other than to refer to a variable declared in the locals of a PROC???

And then, only when used in an invoke?

reparg
SADD
CADD
Str$
hex$



hutch--

This sounds reasonable, as long as it does not break existing code I don't see why OFFSET should not be used. Whizz up a list and I will see what I can do.

Jim, reparg has 3 versions, reparg, repargv and repargof.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

Jimg

Quote from: hutch-- on July 03, 2008, 02:15:48 PM
This sounds reasonable, as long as it does not break existing code I don't see why OFFSET should not be used. Whizz up a list and I will see what I can do.

Jim, reparg has 3 versions, reparg, repargv and repargof.
Right.  Which is what we are talking about. Obviously all three macros must be kept since there must be code using all of them somewhere, but reparg and repargof should be identical and return the offset since there is no reason to return an ADDR, and then could just always use reparg without having to go look up the name of the other one-

mov eax,reparg("test")    ; this would always work

something like-
    reparg MACRO arg
      LOCAL nustr
        quot SUBSTR <arg>,1,1
      IFIDN quot,<">            ;; if 1st char = "
        .data
          nustr db arg,0        ;; write arg to .DATA section
        .code
        EXITM <offset nustr>      ;; append name to ADDR operator
      ELSE
        EXITM <arg>             ;; else return arg
      ENDIF
    ENDM
  ; -------------------------------------
  ; variation returns address in register eax
  ; so it can be assigned to a variable.
  ; -------------------------------------
    repargv MACRO arg
      mov eax,reparg(arg)
      exitm <eax>
    ENDM
  ; -----------------------------------------------------------
  ; replace a quoted string with its OFFSET in the data section
  ; -----------------------------------------------------------
    repargof MACRO arg
      exitm <reparg(arg)>
    ENDM


Although it is probably more efficient to have each macro fully expanded, I don't know.

MichaelW

I'm not sure if this is actually a useful solution, but it does appear to work.

    tooff MACRO arg
      IFIDN @SubStr(<arg>,1,4), <ADDR>
        EXITM @CatStr(<OFFSET>, @SubStr(<arg>,5))
      ENDIF
    ENDM

    mov eax, 12345678h
    mov edx, tooff(hex$(eax))
    print edx,13,10
    mov edx, tooff(hex$(12345678h))
    print edx,13,10

eschew obfuscation

jj2007

Quote from: MichaelW on August 11, 2008, 10:55:05 PM
I'm not sure if this is actually a useful solution, but it does appear to work.
It works, and is the only workaround without changing the original macros. However, if there is the option to change the originals, then opattr might be the way to go: check whether the arg is a local or global var, and use addr only for the local vars.

EDIT: Obviously, as shown in my initial post, opattr is not needed when the variable is created in the .data? section by the macro itself:

    hex$ MACRO DDvalue
      LOCAL rvstring
      .data?
        rvstring db 12 dup (?)
        align 4
      .code
      invoke dw2hex,DDvalue,ADDR rvstring
      EXITM <ADDR offset rvstring>  ;; always correct
    ENDM

jj2007

Masm32's str$ macro does not work with sizes other than dword. While this is documented, it may put newbies in trouble (a bug that is difficult to trace), and it is not necessary. Here is a fix that will not break or change any existing code, except that
a) it saves a few bytes by putting the buffer into the uninitialised section,
b) it allows the mov esi, str$(123) variant, which chokes with the current version of str$.


include \masm32\include\masm32rt.inc

str$ MACRO value
LOCAL rvstring, ArgSize, ArgType
ArgType = (opattr(value)) AND 127
tmp$ catstr <at=>, %ArgType ;;, <, as=>, %ArgSize
% echo tmp$
if ArgType eq 48
ArgSize = @SizeStr(value)+1 ;; register: size ax, al etc 3, eax etc 4
elseif ArgType eq 36
ArgSize = 4 ;; immediate
else
ArgSize = SIZEOF value
endif
.data?
rvstring dd 5 dup (?)
.code
if ArgSize eq 4
invoke dwtoa, value, offset rvstring
else
movzx eax, value
invoke dwtoa, eax, offset rvstring
endif
EXITM <offset rvstring>
ENDM

.data
   var_byte db 123
   var_word dw 12345
   var_dword dd 123456789

.code
start:
mov ebx, 123456789
mov esi, str$(987654)
MsgBox 0, esi, "The buffer:", MB_OK
MsgBox 0, str$(ebx), "ebx:", MB_OK
MsgBox 0, str$(bx), "bx:", MB_OK
MsgBox 0, str$(bl), "bl:", MB_OK
MsgBox 0, str$(var_byte), "var_byte:", MB_OK
MsgBox 0, str$(var_word), "var_word:", MB_OK
MsgBox 0, str$(var_dword), "var_dword:", MB_OK
    exit

end start


The same logic can be applied to hex$ etc.