News:

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

List of known MASM bugs

Started by jj2007, December 03, 2008, 10:19:10 PM

Previous topic - Next topic

jj2007

Japheth has already made an attempt to list the known MASM bugs. I think it would be extremely useful for beginners and seasoned programmers alike to find these bugs condensed in a list, maybe together with possible workarounds.

I start with three simple examples:

1. The programmer can pass more arguments to a macro than needed. ML 6.14 and ML 9.0 issue only a warning (A4006:too many arguments in macro call), although the MessageBox will look a bit odd. JWasm recognises this as an error.

include \masm32\include\masm32rt.inc

MBox MACRO text:REQ, title:REQ, style:REQ ; 3 arguments received
  invoke MessageBox, 0, text, title, style
ENDM

.code
MyTitle db "Ciao", 0

start:
MBox 0, chr$("Message text, not title!"), addr MyTitle, MB_OK ; 4 arguments passed

exit

end start


2. Assembly gets slow, and ML may eventually freeze, for large buffers in the .data? section:

.data?
MySlowBuffer db 600000 dup(?) ; 0.6 mega: about 5 seconds


The workaround is a macro using the ORG directive (I owe this idea to drizz and MichaelW):

(EDIT: link to drizz' post added - thanks Michael)

include \masm32\include\masm32rt.inc

mkbuf MACRO var, BufLen
LOCAL lbl
.data?
align 4
  lbl LABEL byte
  ORG $+BufLen-1
  db ?
.data
var dd lbl ;; define it in the data section
.code
ENDM

.data?

; MySlowBuffer db 600000 dup(?) ; 0.6 mega: about 5 seconds

.code

start: mkbuf MyBuffer, 100000000 ; one-hundred mega
invoke MessageBox, 0, chr$("Done!"), chr$("Fat buffer:"), MB_OK
exit

end start


3. The offset problem: Both versions of this code work for ml 6.14 and JWasm but ml 9.0 says error A2070:invalid instruction operands

.data
MyAccels ACCEL <FCONTROL or FVIRTKEY, VK_S, IdMenuSave>
LastAccel ACCEL <FVIRTKEY, VK_ESCAPE, IdEscape>
...
.code
invoke CreateAcceleratorTable, addr MyAccels,
1+(offset LastAccel-MyAccels)/SIZEOF ACCEL

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


No workaround found yet, except sacrificing a register...

KeepingRealBusy



MichaelW

JJ,

The workaround for big buffers in the .data? section was from drizz, I just tested it.

http://www.masm32.com/board/index.php?topic=8602.msg62638#msg62638
eschew obfuscation

jj2007

Quote from: KeepingRealBusy on December 04, 2008, 03:18:50 AM
JJ,

Here is another bug in MASM 8.0 AND still in MASM 9.0. I reported this to MS:
http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=356393

Dave.

Calc PROTO,dPercent:DWORD
...
Calc PROC,
     dPercent:DWORD

     ret
Calc ENDP

So what are you asking poor ml to do, Dave? What is the meaning of an "empty argument"?

EDIT: Strangely enough, the empty argument is not the culprit - the commas after PROTO and PROC are being ignored.
Since REC_PTRS EQU 12:

    INVOKE Calc, [esi+12] ; works like a charm
    ; INVOKE Calc,OFFSET [esi+12] ; does not work


What is the purpose of INVOKE Calc, OFFSET [esi+12] ? How does it differ from INVOKE Calc, [esi+12] ?

jj2007

#5
Quote from: KeepingRealBusy on December 04, 2008, 03:18:50 AM
JJ,

Here is another bug in MASM 8.0 AND still in MASM 9.0. I reported this to MS:
http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=356393

Dave.

Here is a minimalist demo of this behaviour:

include \masm32\include\masm32rt.inc

.code
MyWords dw 5678h, 1234h

start:
mov esi, offset MyWords
; mov eax, OFFSET [esi] ; throws an error even in JWasm
; mov eax, OFFSET [esi+0] ; works with JWasm but ml 6+9 produce fatal error A1016: Internal Assembler Error
mov eax, [esi+0] ; works with all versions, same result as JWasm

MsgBox 0, hex$(eax), chr$("Bug report:"), MB_OK
exit

end start



MSDN is, as usual, incredibly verbose about the exact meaning of "offset":

Microsoft Macro Assembler Reference
operator OFFSET

Returns the offset of expression.


Rockoon

The Masm workaround I use for the large BSS data is:

.data?
COMM MyBigBuffer:dword:12345678

Which creates a buffer of 12345678 dwords. No messy macros, but probably doesnt work in other assemblers.

As for other bugs... I don't even know where to begin in regards to all the quirks of the macro language that have become 'features'
When C++ compilers can be coerced to emit rcl and rcr, I *might* consider using one.

japheth

Quote from: jj2007 on December 04, 2008, 10:41:46 AM
MSDN is, as usual, incredibly verbose about the exact meaning of "offset":

The problem with OFFSET is that this operator has become ambiguous.

The - original - purpose of the OFFSET operator is to return the offset part of a label. For Masm, a label consists of segment, offset and type information. From this point of view, it's illegal to feed OFFSET with an indirect memory operand ( and JWasm is wrong to accept [esi+0], this will be fixed).

However, OFFSET in Masm additionally accepts numbers, structure names and structure fields, which aren't labels. The "offset" of a structure field is a useful information, but "offset" of numbers/structure names are useless. Also, IMO, since structure fields are accepted as operands, there's no good reason why stack variables are NOT accepted?


jj2007

Quote from: Rockoon on December 04, 2008, 12:05:57 PM
The Masm workaround I use for the large BSS data is:

.data?
COMM MyBigBuffer:dword:12345678

Which creates a buffer of 12345678 dwords. No messy macros, but probably doesnt work in other assemblers.
A word of caution:
Communal Data Is Not Included in the LIB Listing

Communal data declarations generate no PUBLIC definitions. Therefore, although they can be placed in a library, they are not placed in the library dictionary and will not be a part of the library listing generated by the LIB utility.

Communal variables are supported only by QuickC, Microsoft C versions 5.0 and later, and MASM. They are, however, similar to common blocks in FORTRAN. In C, communal variables are the uninitialized global data items. In MASM, they are data items declared with the COMM qualifier.

The linker will assume the communal variables refer to an external defining declaration elsewhere. If there is no external definition, the linker allocates storage and initializes it to 0 (zero). If there is more than one declaration, storage is allocated for the largest data item declared. For example, if I is declared int I; in one module and char I; in another module, the linker will allocate 2 bytes for I because the int is 2 bytes but the char is only 1 byte. Because memory for communal variables may not be assigned until load time, their use may reduce the size of your executable file.

When a communal variable is declared in a library and defined in one of the object modules, references to that variable will be resolved with the defined variable. For this reason, communal variable declarations are not recommended for any file that might be placed in a library. If a variable defined in a .OBJ file accidentally had the same name as a communal variable in a library that it is being linked with, its value would unexplainably change every time you called a library function that used that communal variable! The linker does not issue a warning because the variable was defined only once, in the OBJ file.

Quote
As for other bugs... I don't even know where to begin in regards to all the quirks of the macro language that have become 'features'

Every language has its known prob... pardon: features. The ones that 'count' are those that lead to endless unnecessary bug searches. In this context, there should be a Beginner's Guide to Masm Quirks. This should include serious Masm bugs, but also simple things like the ABI ("why does the beast destroy my precious eax?"), and hints to common errors such as ".if eax<-3" - I spent a lot of time chasing this "non-bug" simply because I didn't know that Masm was stupid enough to treat eax as unsigned. Since then I happily use

signed   equ sdword ptr
.if signed eax<-3


drizz

The two most serious bugs that are present in ml versions prior to 9.00.30729.01 are:
1) pushing of non dword variables/registers in invoke (also the zero/sign extension is silly)
2) dup with initialized structs

here's a link to more links :)
http://www.masm32.com/board/index.php?topic=8758.msg63746#msg63746

the workaround is to use the JWASM  :U. Or the latest version of ml
The truth cannot be learned ... it can only be recognized.

jj2007

Just found another cute "bug":

      mov eax, [esi+ecx+ebp-14]

gets without warning encoded as

      mov eax, [ecx+ebp-14]

I urgently needed that three-register address mode, but no luck :bg

jj2007

Quote from: jj2007 on December 03, 2008, 10:19:10 PM
...
3. The offset problem: Both versions of this code work for ml 6.14 and JWasm but ml 9.0 says error A2070:invalid instruction operands

.data
MyAccels ACCEL <FCONTROL or FVIRTKEY, VK_S, IdMenuSave>
LastAccel ACCEL <FVIRTKEY, VK_ESCAPE, IdEscape>
...
.code
invoke CreateAcceleratorTable, addr MyAccels,
1+(offset LastAccel-MyAccels)/SIZEOF ACCEL

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


No workaround found yet, except sacrificing a register...


Problem solved:
.data
MyAccels ACCEL <FCONTROL or FVIRTKEY, VK_S, IdMenuSave>
ACCEL <FVIRTKEY, VK_F5, IdButton1>
ACCEL <FCONTROL or FVIRTKEY, VK_N, IdMenuNew>
LastAccel ACCEL <FVIRTKEY, VK_ESCAPE, IdEscape>
...
.code
...
CASE WM_CREATE
; -------------------- create keyboard shortcuts --------------------
if 0
push dword ptr 1+(LastAccel-MyAccels)/SIZEOF ACCEL
push offset MyAccels
call CreateAcceleratorTable ; OPT_Assembler JWasm ; does not work with invoke, but pushing helps
else
@CatStr(<invoke CreateAcceleratorTable, offset MyAccels, >, %dword ptr 1+(LastAccel-MyAccels)/SIZEOF ACCEL)
endif


Both versions work with ml 6.14, 6.15, 9.0 and JWasm.