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.
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$
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.
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.
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
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
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.