Hey bitRAKE your a MACRO master, can you tell me what the hell is happening with the following code.

It compiles fine, but crashes when run. OllyDbg shows the code has turned to custard!

The problem is with the .ASSERT macro or more likely the .TEXT macro. OllyDbg shows that ESI is NOT being pushed but IS being popped, and the code after the first .IF has turned to jelly. There should be two .IF tests but the second one has vanished. Now the interesting part is if you use the .ASSERT2 macro everything works fine????

I've just changed from simple code segments to defining them manually - have I stuffed something up there? If not I'm completly confused

I'm using XP professional and MASM 6.15.8803




.686P

OPTION CASEMAP:NONE
OPTION LANGUAGE:STDCALL
OPTION DOTNAME

;====================================

_TEXT SEGMENT READONLY DWORD PUBLIC USE32 'CODE'
_TEXT ENDS

CONST SEGMENT READONLY DWORD PUBLIC USE32 'CONST'
CONST ENDS

_DATA SEGMENT DWORD PUBLIC USE32 'DATA'
_DATA ENDS

_BSS SEGMENT DWORD PUBLIC USE32 'BSS'
_BSS ENDS

ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:FLAT

;====================================

ExitProcess PROTO :DWORD

INCLUDELIB kernel32.lib

;====================================

.ASSERT MACRO x, y
LOCAL n1
IFB <y>
n1 TEXTEQU .TEXT( "ASSERT" )
ELSE
n1 TEXTEQU .TEXT( y )
ENDIF
.IF x == 0
; do somthing with n1
.ENDIF
ENDM

.ASSERT2 MACRO x, y
LOCAL n1
.IF x == 0
IFB <y>
n1 TEXTEQU .TEXT( "ASSERT" )
ELSE
n1 TEXTEQU .TEXT( y )
ENDIF
; do somthing with n1
.ENDIF
ENDM

.TEXT MACRO n:VARARG
LOCAL n1
CONST SEGMENT
n1 db n, 0
CONST ENDS
EXITM <OFFSET n1>
ENDM

;====================================

_TEXT SEGMENT

TestMain PROC USES ebx ecx edx edi esi

.ASSERT eax, "bugger"
.ASSERT eax, "bugger"

; .ASSERT2 eax, "bugger"
; .ASSERT2 eax, "bugger"

mov eax, 1
mov ebx, 2
mov ecx, 3
mov edx, 4

ret

TestMain ENDP

_TEXT ENDS

;====================================

_TEXT SEGMENT

@@_start:

invoke TestMain

invoke ExitProcess, 0

ret

_TEXT ENDS

;====================================

END @@_start



And on a slightly unrelated issue does XP have a minimum EXE file size as this code compiles to 16K

EDIT: I must have screwed up big time somewhere, even if I use the .ASSERT2 macro I've still got custard in my EXE

:stupid:

Maelstrom
Posted on 2002-09-07 23:26:19 by Maelstrom
Just use the linker from MASM32 which is out of the win98ddk and you will get smaller.

Regards,

hutch@movsd.com
Posted on 2002-09-07 23:51:33 by hutch--
Cheers Hutch :alright:

Thats fixed the compile size prob, only the MACRO prob remains

Maelstrom
Posted on 2002-09-08 02:29:47 by Maelstrom
I would guess that the ASSERT2 Macro works because X = eax, not 0 therefore the Macro actually does nothing. Don't know why the first works though.
Posted on 2002-09-08 07:55:38 by Eóin
no reason to use an old linker, just add "/filealign:512" or "/opt:nowin98" to the linker switches. Know your tools.
Posted on 2002-09-08 13:17:37 by f0dder
OK I've played around some more and found that the problem ( for the code above anyway ) was
the following line in the .ASSERT macro



n1 TEXTEQU .TEXT( ... )


if I replace the TEXTEQU with EQU everything works fine, but the problem still remains in a program that
I'm currently working on, could it be a compiler bug? i've tried compiling with 6.14 but the problem remains.

Its probably something so simple :rolleyes:

Thanks f0dder :alright:

Maelstrom
Posted on 2002-09-08 22:22:14 by Maelstrom
I had similar problem once. After playing around some time i've found that very first line in the code can't be a macro call. Place nop (or something) as very first command and all will work fine. I think it's a kind of compiler bug. Simply some internal variable is in undefined state if macro call appears in very first line.
Posted on 2002-09-09 02:51:44 by Four-F
Maelstrom, I have returned from a little break. Four-F is certainly correct - this is how MASM supports the LOCAL keyword and custom PROLOGUE macros. Important Note: MASM doesn't really execute the PROLOGUE macro until before the first instruction is assembled. This allows several LOCAL lines and custom macros to execute prior to the PROLOGUE macro - this is a feature, imho. I don't know why MASM backs up a byte in the output stream - this does not happen if you stay in the same segment - this is the root of the error.

Alternative method:
	.ASSERT MACRO x, y:=<"ASSERT">

LOCAL n1
n1 TEXTEQU .TEXT <y>
.IF x == 0
; do somthing with n1
.ENDIF
ENDM
Most likely the LOCAL symbol is not needed.
Posted on 2002-09-10 01:37:08 by bitRAKE
Thanks Four-F, bitRAKE :alright:

bitRAKE

So if I understand you correctly it was because of the macro appearing before the first code instruction.
Does the first instruction have to be before the macro or can it be in the macro?

What I mean is, would this be ok if was the first line in a proc or would it cause the same probs



blah MACRO
mov eax, something
ENDM


What about the following macro, would it work without introducing this 'feature'?
I want to use macros to hide some name mangling in my object framework ( under construction ).



.PROC MACRO name, args
IFB <args>
name PROC
ELSE
name PROC args
ENDIF
ENDM


P.S Hope you had a nice break

Maelstrom
Posted on 2002-09-10 17:56:47 by Maelstrom
My experience shows there has to be an actual instruction to force PROLOGUE macro code generation. For example, put this macro in place of one above:
	.TEXT MACRO n:VARARG

LOCAL n1
;CONST SEGMENT
n1 db n, 0
;CONST ENDS
EXITM <OFFSET n1>
ENDM
Now in a debugger you will see the text passed to .ASSERT before the PUSH instructions - now the first string start address is the PROC address! Also, note DB directive does not force PROLOGUE generation - must be an instruction or HLL syntax that creates an instruction (ie .IF). This kind of thing really makes a programmer want to rewrite MASM correctly. Maelstrom, by your comments, you surely understand the power that could exist without these flaws. The segment switch bug has prevented my further work on some profiling macros. I am investing more time into my assembler (FASM doesn't fully support my needs because code & data is harder to combine and use together, non-linear positioning of code in object file is cumbersome, and mostly I need to try out some of my own ideas for an assembler that have been cooking for a long time.)
Posted on 2002-09-10 22:20:55 by bitRAKE
The fog in my brain has cleared - cheers bitRAKE :alright:

It also explains why the .ASSERT2 macro worked since it encountered the .IF statement before the .TEXT macro.

I await the bitRAKE assembler with great anticipation.

Maelstrom
Posted on 2002-09-11 00:33:12 by Maelstrom
nop
ORG $-1

...could solve the problem, but I really don't want to add this to every macro that could be after PROC. :(
Posted on 2002-09-11 06:41:13 by bitRAKE
Hey bitRAKE

I was fooling around with the idea of trying to determine if any code exists in the proc before changing segments using $ and macros. My idea didn't work but the $ does seem to force the PROLOGUE to execute. So using the above example I modified the .TEXT macro as shown below and it seems to work.



.TEXT MACRO n:VARARG
LOCAL n1, n2
n2 EQU $ ; <------- added this
CONST SEGMENT
n1 db n, 0
CONST ENDS
EXITM <OFFSET n1>
ENDM


A fairly simple solution, if it indeed works properly !!!

Maelstrom
Posted on 2002-09-12 05:11:46 by Maelstrom
Bravo! Very logical solution - obviously the PROLOGUE macro would have to execute to give a valid address for $. Thank you, works well on both problems!
Posted on 2002-09-12 10:40:21 by bitRAKE