News:

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

Offset bug in Masm V9, ok in ml 6.14

Started by jj2007, November 06, 2008, 09:33:51 PM

Previous topic - Next topic

jj2007

I had experienced some weird behaviour with print str$(offset LabelA-LabelB) and was finally able to nail it down. Try to (console) assemble this simple snippet with Masm v6.14 - it should work smoothly. Try again with ml 9.0, and it will throw errors at you (the same for versions A+B):

tmp_file.asm(30) : error A2070:invalid instruction operands
str$(6): Macro Called From
  print(1): Macro Called From
   tmp_file.asm(30): Main Line Code

.nolist
include \masm32\include\masm32rt.inc

smul MACRO accu:REQ, mult:REQ
  ifdifi <accu>, <eax>
mov eax, accu ;; avoids a mov eax, eax
  endif
  if opattr mult eq 36 ;; doesn't work with JWasm
mov edx, mult
imul edx
  else
imul mult
  endif
  EXITM <eax>
ENDM

.code
start:
  print chr$(13, 10, "edx=")
  mov edx, 10000h
  mov eax, 12345678h
inLabel:
  mov edi, smul(eax, edx) ; reg32 * reg32
outLabel:
  print hex$(edx), 13, 10, 10 ; high dword of edx:eax
  print "edi="
  print hex$(edi) ; low dword of edx:eax

  print chr$(13, 10, 10, "Size=")
  print str$(offset outLabel - offset inLabel), 13, 10 ; version A, 2*offset

  print chr$(13, 10, "Size=")
  print str$(offset outLabel - inLabel), 13, 10, 10 ; version B, 1*offset

  inkey "Hit any key to get outta here", 13, 10
exit

end start



Two batch files for quick testing:

MakeV6.bat
copy mlv614.exe ml.exe
copy linkv614.exe link.exe


MakeV9.bat
copy mlv9.exe ml.exe
copy linkv9.exe link.exe

BlackVortex



MazeGen

I wouldn't say it is a bug. Since version 8 (IIRC) ML does more type-checking. If you assemble:


.386
.MODEL FLAT

.code
_start:
nop
_end:

push _end-_start
end _start


Works for 6.14, does not work for 9.00.

It is a bit similar situation to:


mov [eax], _end-_start


Where ML doesn't know what size of operand you want to MOVe. Typecasting helps:


mov [eax], dword ptr (_end-_start)


And the same apply for the PUSH (and therefore INVOKE) (you can PUSH word or dword):


push dword ptr (_end-_start)


japheth


It's a bug in Masm v8, nothing else. That's just a matter of course ...  :green


jj2007

I'm afraid it's not a simple bug. Masm versions behave differently, and JWasm issues only a warning where both ml versions throw an error. Here is a testbed. Note that I had to modify the str$ macro to make it work for immediates and non-dword values.

.nolist
include \masm32\include\masm32rt.inc

str$ MACRO value
LOCAL rvstring, ArgSize, ArgType
ArgType = (opattr(value)) AND 127
tmp$ CATSTR <aty=>, %ArgType, < for >, <value>
% 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
else
ArgSize = SIZEOF value
endif
.data?
rvstring dd 5 dup (?)
.code
if ArgSize eq 4
if ArgType eq 36 ;; only mlv9 needs this workaround
mov eax, value
invoke dwtoa, eax, offset rvstring
else
invoke dwtoa, value, offset rvstring
endif
else
movzx eax, value
invoke dwtoa, eax, offset rvstring
endif
EXITM <offset rvstring>
ENDM

.data?
varB db ?
varW dw ?
varD dd ?

.code

start:
l1:
nop ; one byte
l2:
; ----------- indirect via offset -----------------
mov eax, offset varB
mov byte ptr [eax], offset l2-l1
mov eax, offset varW
mov word ptr [eax], offset l2-l1
mov eax, offset varD
mov dword ptr [eax], offset l2-l1
; omitting the dword ptr leads to:
; JWasm warning W096: Size not specified -- BYTE PTR is assumed
; mlv6 and mlv9 error A2070: invalid instruction operands

print str$(varD), 9, "double",13,10
print str$(varW), 9, "word",13,10
print str$(varB), 9, "byte",13,10,10

; ----------- direct assign -----------------
mov varB, offset l2-l1
mov varW, offset l2-l1 ; e.g. mov word ptr [402191], 1
mov varD, offset l2-l1

print str$(varD), 9, "double",13,10
print str$(varW), 9, "word",13,10
print str$(varB), 9, "byte",13,10

; ----------- direct assign to eax -----------------
mov eax, offset l2-l1
print str$(eax), 9, "eax",13,10

; ----------- direct use in heavily modified str$ -----------------
print str$(offset l2-l1), 9, "str$",13,10

getkey
exit
end start

MazeGen

Quote from: jj2007 on November 25, 2008, 10:23:05 PM

.code
if ArgSize eq 4
if ArgType eq 36 ;; only mlv9 needs this workaround
mov eax, value
invoke dwtoa, eax, offset rvstring
else
invoke dwtoa, value, offset rvstring
endif
else
movzx eax, value
invoke dwtoa, eax, offset rvstring
endif


Why not dword ptr (value), as I suggested above, instead of this huge conditional? It does work, doesn't it?


invoke dwtoa, dword ptr (value), offset rvstring

japheth

Quote from: MazeGen on November 26, 2008, 08:57:27 AM
Why not dword ptr (value), as I suggested above, instead of this huge conditional? It does work, doesn't it?

"Of course" it does work, but that's not the point. The point is that the difference of two labels - which are internal to the module and also are in the same segment/section - is a numeric constant without "size" and must be treated as such by the assembler. Since "push 1" is valid without using "dword ptr", "push offset l2 - offset l1" must be valid as well.

MazeGen

Japheth, I agree that it is more likely a bug rather that a feature, because push 2-1 works fine as well.

I was just pointing out that we can get rid of that complex conditional using single line with that dword ptr () workaround.

jj2007

Quote from: MazeGen on November 26, 2008, 10:02:52 AM
I was just pointing out that we can get rid of that complex conditional using single line with that dword ptr () workaround.

The complex conditional enables str$ to deal with non-dword values (including ax, al etc):


.data?
varB db ?
varW dw ?
varD dd ?

.code
...
print str$(varD), 9, "double",13,10
print str$(varW), 9, "word",13,10
print str$(varB), 9, "byte",13,10,10

With invoke dwtoa, dword ptr (value), offset rvstring, you get
1       double
65537   word
16777473        byte

With the conditional, the output looks more correct:
1       double
1       word
1       byte


jj2007

Quote from: MazeGen on November 20, 2008, 03:34:37 PM
Where ML doesn't know what size of operand you want to MOVe. Typecasting helps:

Any solution for this one? Works for ml614 and JWasm but not for ml9...

      invoke CreateAcceleratorTable, addr MyAccels,
         1+(offset LastAccel-MyAccels)/SIZEOF ACCEL

jj2007

I found a solution:

.data
MyAccels ACCEL <FCONTROL or FVIRTKEY, VK_O, IdMenuOpen>
ACCEL <FCONTROL or FVIRTKEY, VK_S, IdMenuSaveAs>
LastAccel ACCEL <FVIRTKEY, VK_ESCAPE, IdEscape>
.code
JWasm = 0
V614 = 0
if JWasm or V614
; ml 9.0: error A2070:invalid instruction operands
if 0 ; both versions work, the dword ptr is not needed
  invoke CreateAcceleratorTable, addr MyAccels,
  dword ptr ((LastAccel-MyAccels)/(SIZEOF ACCEL)+1) ; with dword ptr
else
  invoke CreateAcceleratorTable, addr MyAccels, ; without dword ptr
  ((LastAccel-MyAccels)/(SIZEOF ACCEL)+1)
endif
else
if 0
  ; this looks OK but it simply won't work in Masm 9.0:
  invoke CreateAcceleratorTable, offset MyAccels,
dword ptr ((LastAccel-MyAccels)/(SIZEOF ACCEL)+1)
else
  ; but we can use a dirty trick: bye bye to invoke, push by hand...!
  push dword ptr ((LastAccel-MyAccels)/(SIZEOF ACCEL)+1)
  push offset MyAccels
  call CreateAcceleratorTable
endif
endif


As MazeGen noted earlier, this is not a bug, it's by design. Fortunately, Microsoft "designers" will never stop adding new "features" - we might get terribly bored otherwise :green

KeepingRealBusy

I reported this to Microsoft last September. They agreed that it was an error, they would fix it, but would still be in MASM 9.0 and the next update.

    http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=362492

Dave