While working on an old program, this bug took a long time to run down.
I think we have discussed before, but I couldn't find the thread.
When running the following program, masm correctly displays 1 in the messagebox, uasm display 2.
.686
include masm32rt.inc
.data
buff db 100 dup (?)
fmt db "return=%lu",0
.code
test1 proc x,y
mov edx,x
ret
test1 endp
test2 proc x,y
mov edx,y
ret
test2 endp
want1=1
ifdef want1
testroutine = test1
else
testroutine = test2
endif
.code
Program:
invoke testroutine,1,2
invoke wsprintf,addr buff,addr fmt,edx
invoke MessageBox,0,addr buff,0,0
; uasm print out 2, masm prints out 1
invoke ExitProcess,0
end Program
In the Masm programmers reference, it states-
QuoteThe directives EQU and = have slightly different purposes. Integers defined with the = directive can be
redefined with another value in your source code, but those defined with EQU cannot. Once you've
defined a symbolic constant with the EQU directive, attempting to redefine it generates an error. The
syntax is:
symbol EQU expression
The symbol is a unique name of your choice, except for words reserved by MASM. The expression can
be an integer, a constant expression, a one- or two-character string constant (four-character on the
80386/486), or an expression that evaluates to an address.
In this context, it seems to me that testroutine is " an expression that evaluates to an address".
Before someone immediately jumps in with "It will work if you use .....", yes, I know several ways to make it work, but I feel it should work like masm in this instance.
Similarly, if you change the code to the following, masm works properly but uasm goes off into never-never land and crashes.
Quoteifdef want1
testroutine = test1
else
testroutine = test2
endif
the reference text you are looking at refers to numbers, strictly speaking
i don't know if the assembler resolves "test1" and "test2" to addresses
you might try it with "offset test1"
it may be that it is essentially a TEXTEQU, which is not quite the same as EQU or =
either way, it should work correctly :P
Quote from: dedndave on May 10, 2018, 01:58:46 AMyou might try it with "offset test1"
Masm throws an error. Btw Masm shows "1" for this code:
want1=2
ifdef want1
testroutine = test1
else
testroutine = test2
endif
.data
BranchTable dd test1,test2
.code
mov ebx,4 ;or 0
call dword ptr BranchTable[ebx]
you can use invoke if you do the EQU's and TYPEDEF's :biggrin:
This is indeed a bug, inherited from jwasm - so I feel a bit responsible for it.
The test case can be simplified to
.686
.model flat, stdcall
.code
test1 proc x,y
mov edx,x
ret
test1 endp
testroutine = test1
.code
Program:
invoke test1,1,2
invoke testroutine,1,2
end Program
and, after compiling it with options -Fl and -Sg, see the listing file:
.686
.model flat, stdcall
00000000 * _TEXT segment PARA FLAT PUBLIC 'CODE'
* _TEXT ends
00000000 * _DATA segment PARA FLAT PUBLIC 'DATA'
* _DATA ends
* assume cs:flat,ds:flat,ss:flat,es:flat,fs:ERROR,gs:ERROR
.code
00000000 * _TEXT segment
* assume cs:FLAT
00000000 test1 proc x,y
00000000 55 * push ebp
00000001 8BEC * mov ebp, esp
00000003 8B5508 mov edx,x
00000006 ret
00000006 5D * pop ebp
00000007 C20800 * retn 8
0000000A test1 endp
0000000A = 0 C testroutine = test1
00000000 .code
0000000A * _TEXT ends
0000000A * _TEXT segment
* assume cs:FLAT
0000000A Program:
0000000A invoke test1,1,2
0000000A 6A02 * push 2
0000000C 6A01 * push 1
0000000E E8EDFFFFFF * call test1
00000013 invoke testroutine,1,2
00000013 6A01 * push 1
00000015 6A02 * push 2
00000017 E8FBFFFFFF * call testroutine
end Program
0000001C * _TEXT ends
Macros:
N a m e Type
@CatStr . . . . . . . . . . . . Func
@Environ . . . . . . . . . . . . Func
@InStr . . . . . . . . . . . . . Func
@SizeStr . . . . . . . . . . . . Func
@SubStr . . . . . . . . . . . . Func
Segments and Groups:
N a m e Size Length Align Combine Class
FLAT . . . . . . . . . . . . . . GROUP
_DATA . . . . . . . . . . . . . 32 Bit 00000000 Para Public 'DATA'
_TEXT . . . . . . . . . . . . . 32 Bit 0000001C Para Public 'CODE'
Procedures, parameters and locals:
N a m e Type Value Segment Length
test1 . . . . . . . . . . . . . P Near 00000000 _TEXT 0000000A Public STDCALL
x . . . . . . . . . . . . . . DWord ebp + 0008
y . . . . . . . . . . . . . . DWord ebp + 000C
testroutine . . . . . . . . . . P Near 00000000 _TEXT 00000000 Private
y . . . . . . . . . . . . . . DWord ebp + 000C
x . . . . . . . . . . . . . . DWord ebp + 0008
Symbols:
N a m e Type Value Attr
@CodeSize . . . . . . . . . . . Number 0h
@DataSize . . . . . . . . . . . Number 0h
@Interface . . . . . . . . . . . Number 3h
@Model . . . . . . . . . . . . . Number 7h
@code . . . . . . . . . . . . . Text _TEXT
@data . . . . . . . . . . . . . Text FLAT
@stack . . . . . . . . . . . . . Text FLAT
Program . . . . . . . . . . . . L Near Ah _TEXT STDCALL
The assembler has "lost" the language information for the procedure equate "testroutine" and hence doesn't know in which order to push the arguments. The default which it chooses is obviously wrong.
Quote from: _japheth on May 10, 2018, 05:44:34 AM
This is indeed a bug
Hi Japheth,
You can call it a bug, and it should indeed be fixed if UAsm claims to be a 100% compatible MASM clone. But I would give it a low priority, because (and I hope Jim will agree) it's not exactly the best use of the "=" operator.
Below a version that performs the intended action, and behaves identical for ML and UAsm. What is different?
Instead of ...
want1=1
ifdef want1
... it uses an assignment that can be used as a switch, and is thus a lot more flexible:
wantX=2
if wantX eq 1
testroutine equ <test1>
elseif wantX eq 2
testroutine equ <test2>
else
.err <please make up your mind, your instructions are confusing...>
endif
Why is that better? Because using ifdef is a good recipe for hard to recognise bugs:
want1=2
ifdef want1
testroutine equ <test1>
else
testroutine equ <test2>
endif
Crystal clear, isn't it? Furthermore, instead of hoping that the assembler somehow guesses that we want to assign a proc's start address when writing
testroutine = test1, a simple text equate is being used:
testroutine equ <test1>.686
include masm32rt.inc
.data
buff db 100 dup (?)
fmt db "return=%lu",0
.code
test1 proc x,y
mov edx,x
ret
test1 endp
test2 proc x,y
mov edx,y
ret
test2 endp
wantX=1
if wantX eq 1
testroutine equ <test1>
else
testroutine equ <test2>
endif
.code
Program:
tmp$ CATSTR <My routine is >, <testroutine>
% echo tmp$
invoke testroutine,1,2
invoke wsprintf,addr buff,addr fmt,edx
print addr buff, 13, 10
testroutine equ test2
tmp$ CATSTR <My routine is >, <testroutine>
% echo tmp$
invoke testroutine,1,2
invoke wsprintf,addr buff,addr fmt,edx
print addr buff, 13, 10
; both uasm and masm print exactly the same
invoke ExitProcess,0
end Program
Without whining, justifying, or obfuscating it further, I feel this is a significant problem and should be corrected.
So it seems then as if there are 3 separate issues here:
1) There is a case that causes UASM to crash
2) There is the fact that the language type is not transferred from the proc to the equate causing invoke to incorrectly generate the argument order
3) the ifdef doesn't seem to be picking up the want1=1
I will add these to my todo list for 2.47 :)