News:

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

masm and its complex bugs

Started by frogbender, March 12, 2005, 10:39:05 AM

Previous topic - Next topic

frogbender

Hi,

iam working as an professional assembler programmer on large and difficult projects and i must say that, masm has
some very ugly bugs. for most of them, there are workarounds available (like offset variables which must be shifted/added
and u want to write in one line; u have to split it over some lines/ or the line to long errors/or the org directive in structures/
or the union structure which initializes the first var only and fills every next one with zeros independent of what i give; the
manual is satisfied with that behaviour/ or macros that will not work on past defined memvars / or the ret 0 directive which
should prevent a pascal proc from cleaning given parameters but results in 2 ret instructions like "ret x" directly
followed by "ret 0"/ or strucs that must be manually aligned to 2 before given to a pascal proc, cause only the proc knows
that the struc must be divisible by 2 but the calling proc does not).

but for some no workarround seems to  exist.

e.g. i encountered one in a macro where a jump label was succesfully addressed by 2 "goto" but the third "goto"
that addressed the same label was not accepted by the assemlber.
e.g. the type directive. used in macros on the second parameter, it sometimes gives u nonsense sizes (129, 26) in the
case the parameter is of byte type (happens only sometimes). All other types like words, dwords, fwords.. are working properly.

yesterday i had defined a dup operator within a structure. i  included that structure in a second and the second in a third one.
then i have reinited the first structure from top level with a new dup var like {{{'x'}}}. the assembler accepted (in some other
variations i got a1016-internal errors) but the result was disastrous. the procedure bhind the structure was half
overwritten with zeros. as  i tried to change the position of the dup member the assembler compiled code which jumped
to randimzed locations within the procedure behind the struc. as i tried to initialize the struc as follows {{'xxxxxx'}} the code
generation was succesfull again.
i was completely unable to isolate the error and iam shocked now. (really wonder how microsoft was able to develop
its operating systems)
i was looking in the past for a new and better assembler but it seems that no other assembelr exist that support such powerfull
programming like masm and  microsoft is no longer supporting/updating masm in version 6. (i got 6.14; for dos). Iam confused now.

thank you for reading my text



hutch--

frogbender,

Welcome on board, sounds like you are having fun with the project. I am surprised that anyone is still working on large DOS projects but I don't see a reason to change from ML 6.11d if in fact its only 16 bit code that you are writing. The patches after 611 were PE files and they tended to shift emphasis to 32 bit PE files and I don't know how good the DOS support was using it. Patches 6.12 and 6.13 had problems but 6.14 has been very good in 32 bit PE files.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

sluggy

frogbender,
maybe if you post some code then we can assist.


frogbender

#3


well, here it comes.

; the following file is filled with some obscure behaviours or bugs i have encountered with masm
; this file is ready for use and should compiled with masm (6.14) and link (5.63)
; (the 2 warnings can be ignored)
; no rights reserved by markus weinhold

.model small
.386p
;option prologue:usePrologue
option epilogue:useEpilogue
.code

stringcomp macro string1, string2, verifylength
local foundstring, sizestring1, sizestring2
foundstring = 0
exitm <foundstring>
endm

Move macro Dest:req, Source:req, useReg ; unable to reference past defined memvars
local typesource, typedest, destofs, sz1, sz2, code, codetext,\
sourcelinecount, sourcelinetext, fillzero, errorlbl, segments

typesource = 1 ; in the case of byte regs u get sometimes big values here (thus i set 1 as default)
typedest = 1
for sz1, <2, 4, 6, 8, 10>
if sz1 eq type(source)
  typesource = type(Source)
endif
if sz1 eq type(Dest)
  typedest = type(Dest)
endif
endm

if (opattr(Dest)) and (1 shl 1)
if (opattr(Source)) and (1 shl 1)
  if typedest lt typesource
   typesource = typedest
   sourcelinecount = @Line
   sourcelinetext textequ %sourcelinecount
   %echo   warning: -move- ("Dest" is lower than "Source"): @FileCur Line: sourcelinetext
  endif
  destofs = 0
  while (typesource-destofs) ne 0
   if (typesource-destofs-4) ge 0

    destofs = destofs+4
    elseif (typesource-destofs-2) ge 0

     destofs = destofs+2
     elseif (typesource-destofs-1) ge 0
  ifnb <useReg>
   mov useReg, byte ptr [Source+destofs]
       mov byte ptr [Dest+destofs], useReg
       destofs = destofs+1
  else
   echo need a 8bit helpreg
;bug_one    goto errorlbl ; will not work and thus..
   .err ; ..this line
  endif
   endif
  endm
  goto fillzero
elseif (opattr(Source)) and (1 shl 2)
  if typedest eq 1

   elseif typedest eq 2

elseif typedest ge 4

     destofs = 4
goto fillzero
else
  goto errorlbl
  endif
elseif (opattr(Source)) and (1 shl 4)
  if typedest ge typesource
   if typesource eq 4

destofs = 4
    elseif typesource eq 2

destofs = 2
     elseif typesource eq 1

  destofs = 1
  else
   goto errorlbl
   endif
   goto fillzero
  else
   goto errorlbl
  endif
endif
else
segments = 0
; for sz1, <cs, ds, es, ss, fs, gs>
;   if (stringcomp(<sz1>, Source) eq 1) and (segments lt 2) ; same as ifidni (no bugs here! commented only)
;    segments = segments+1
;    for sz2, <cs, ds, es, ss, fs, gs>
;     if (stringcomp(<sz2>, Dest) eq 1) and (segments lt 2) ; same as ifidni (no bugs here! commented only)
; segments = segments+1
;     endif
;    endm
;   endif
; endm
if segments lt 2
  mov Dest, Source
else
  push Source
  pop Dest
endif
endif
exitm
:fillzero
while (typedest-destofs) ne 0

endm
exitm
:errorlbl
sourcelinecount = @Line
sourcelinetext textequ %sourcelinecount
%echo   error: -move- ()@FileCur Line: sourcelinetext
.err
endm

useEpilogue macro procname, flag, parambytes, localbytes, regs, macroargs
local saveparambytes, saveparambytestext, sourcelinecount, sourcelinetext, forout
saveparambytes = 0
saveparambytestext textequ <>
ifnb <macroargs>
for mac, <macroargs>
; is there a difference between the next 17 (uncommented) and the next following (commented) 12 lines?
; yes! one block is working and the other not.
  ifidni <mac>, <SaveRegs16>
   popa
   goto forout
  elseifidni <mac>, <SaveRegs32>
   popad
   goto forout
  endif
  if (stringcomp(<mac>, !Save)) eq 1
   saveparambytestext substr <mac>, 5
   saveparambytes = saveparambytestext
   goto forout
  endif
  sourcelinecount = @Line
  sourcelinetext textequ %sourcelinecount
  %echo warning: -useEpilogue- (parameter "&mac" is not defined): @FileCur Line: sourcelinetext
:forout
;   ifidni <mac>, <SaveRegs16>
;    popa
;   elseifidni <mac>, <SaveRegs32>
;    popad
;   elseif (stringcomp(<mac>, !Save)) eq 1
;    saveparambytestext substr <mac>, 5
;    saveparambytes = saveparambytestext
;   else
;    sourcelinecount = @Line
;    sourcelinetext textequ %sourcelinecount
;    %echo warning: -useEpilogue- (parameter "&mac" is not defined): @FileCur Line: sourcelinetext
;   endif

endm
endif
ifnb <regs>
for r, regs
  pop r
endm
endif
if not ((localbytes eq 0) and (parambytes eq 0))
if localbytes ne 0
  mov sp, bp
endif
pop bp
endif
if (flag and (1 shl 8))
iret
else
if (flag and (1 shl 4))
  ret
else
  ret parambytes-saveparambytes
endif
endif
endm

_mbz      SEGMENT
assume ds:_mbz
jmp st1



strucab1 struc
db 4 dup (' ')
strucab1 ends

strucAb2 struc
Index strucab1 {}
db ']'
strucAb2 ends

struczz1 struc
struc Direct
tz strucAb2 {{{('1')}},}
ends
struczz1 ends

struczz2 struc
struc Direct
tz strucAb2 {{{'2'}},}
ends
struczz2 ends

struczz3 struc
struc Direct
tz strucAb2 {{'3456'},}
ends
struczz3 ends

strucnoteven struc
db 3 dup (?)
strucnoteven ends

strucForm struc
db ?
org 4 ; reserve me the last 3 bytes (for future use)
db ?
org 12 ; reserve 7 bytes
db ?
org 30 ; reserve 17 bytes
db ?
strucForm ends

unionForm union
first db 'hi folks!'
second db 40 dup (' ') ; format the rest of the string with spaces (but, it wont work!)
unionForm ends
uform unionform {}

;  the following line shows the a2159 error (structure cannot be instanced)
; form strucform {}

; the following struc have to set 4 bytes with the ascii char '1' the behaviour is, it will set only the first byte. the clamp ']' is lost and set to zero
gg1 struczz1 {}
; the following struc have to set the first byte only the behaviour is correct but clamp ']' is lost
gg2 struczz2 {}
; the following struc is set correct if u take consideraton for the dup size (why i must take into consideration the size?)
;   the clamp is in too (unbelievable) but the overall clamping seems illogical to me. if u take less characters (e.g. '345') u get a1016 internal error.
gg3 struczz3 {}


; ??? the assembelr will not warn me that "defconstant1" is not defined (plz do not tell me i have to manual set this). option that exist?
; defconstant1 equ 9
defconstant2 equ defconstant1

var1 db ?
var2 db ?
; the following text is correct compiled
defbillytext1 textequ <'IT',027h,'S ENOUGH BILL! '> ; same as "IT'S ENOUGH BILL!"
defbillytext2 textequ <'IAM SICK OF BILLWARE '>
billytext1 db defbillytext1
billytext2 db defbillytext2

strucBill struc
db 30 dup (' ')
strucBill ends
bill2 strucbill {defbillytext2}
; the next one will be rejected (yeah, that is logic i love!). as a workaround, i must write a macro that can convert text to db's
; bill1 strucbill {defbillytext1}


st1: Move var1, var2, al ; our move macro with the "goto" bug
; next line will not work (if someone wants to argue that it is senseless to divide a simple offset by 2 then
;   i must say, the assembler simple has to ignore that cause it's not his task!)
; mov ax, ((offset billytext2) shr 1)

; the next lines will work. this was a simple example. u have more to do if u want to calculate pagesizes, alignments or other things.
; (iam getting tired of that shit!)
thisoffset1 equ (offset billytext1)-0 ; dont forget the zero at end or it will not work!!
thisoffset2 equ thisoffset1 shr 1
mov ax, thisoffset2
;
push ax
push ax
call ded1 ; example for ret/ret 0
push ax
call ded3 ; example for useepilogue


ded1 proc far pascal,
var3 : word, ; if u got 10 vars here and u commented them u get with certainty line command errors (512 chars r max and this is quite to few)
var4 : word ; as waorkarround u must set it to struc
; sometimes i define constants here too, cause i need them here only
local\
blahblah : word
sub sp, sizeof strucnoteven ; reserve 3 bytes on stack
call ded2
; next line tells the assembler to get not rid of given params but he first codes "retf 4" followed by "retf"
ret 0 ; big ouch!
ded1 endp

ded2 proc far pascal,
noteven : strucnoteven
xor ax, ax
; cause the struc is not aligned by 2 and uneven the ret size should be 3 but is 4 (ok, but the assembler should really warn me for such behaviour!) 
ret
ded2 endp

ded3 proc far pascal <Save2>,
var5 : word
xor cx, cx 
ret
ded3 endp

_mbz      ends
end

frogbender

;i could reproduce some new. the type operator seems to work incorrect (in dependence on defined vars)
;with masm 6.14 in some cases. the following file shows it (the size for the register AL is not 1)
;it will work perfectly with masm 6.11d
;there is no need to link it!
.model small
.386p


; (un)comment next line
            defPCI_AddressIO                  equ            0CF8h
; (un)comment this struc
struca3            struc
struca3            ends

; (un)comment this struc
struca2            struc
struca2            ends

strucUserBootUp      struc
; (un)comment next line
            Choice         db            0
strucUserBootUp      ends

struca1            struc
; (un)comment this line
            UserBootUp      strucUserBootUp   {}
struca1            ends



.code
_mbz      SEGMENT
assume ds:_mbz
      jmp      st1


gettype   macro Par:vararg
LOCAL      counta, arg, ab1, ab2
            counta         = 0
            for arg, <Par>
               ab1 = type(arg)
               ab2   textequ % ab1
            %   echo ab2
               push      ab1
             counta         = counta+1
            endm
endm

st1:
   gettype    al, dl, eax, cs

_mbz      ends
end

MazeGen

Quote from: frogbender on March 21, 2005, 02:43:24 PM
;i could reproduce some new. the type operator seems to work incorrect (in dependence on defined vars)
;with masm 6.14 in some cases. the following file shows it (the size for the register AL is not 1)

Yeah, that's well known bug. I use the following macro instead of TYPE, originally written by Four-F:

$IsByte MACRO op:REQ
LOCAL r, f
f = 0

IF (TYPE (op)) EQ TYPE BYTE
   EXITM <1>
ELSE ;; MASM 6.14 bug: TYPE reg8 returns 0 instead of 1
   FOR r, <al,ah,bl,bh,cl,ch,dl,dh,>
%    IFIDNI <op>, <r> ;; op may need to be expanded!
       f = 1
       EXITM ;; done, terminate FOR block
     ENDIF
   ENDM
ENDIF

EXITM %f
ENDM