News:

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

Really evil macros

Started by jj2007, May 05, 2008, 02:17:22 PM

Previous topic - Next topic

jj2007

I hope somebody can enlighten me with the following MACRO problem:

Here is a call to a multicat implementation:

MulCat Tmp$, FileHasNow$, STR1$(CurSize), fSize$, AtLoop$, STR2$(LoopCounter)

A MsgBox will then say, "Hi, your file testbed.exe has now 1234 bytes at loop 1000"

Knowing that Masm and macros have their limits, I use two different STR$ macros, with individual dwtoa buffers...

MulCat MACRO dest:REQ, strings:VARARG
push edi
push esi
xor edi, edi ;; first call: allocate tmp string
FOR macstr, <strings>
mov ecx, macstr ;; load src, i.e. the pointer to various strings, and the retval from STR$
xor eax, eax ;; flag "not yet cleanup", if ecx==0 it means a Null$
call AddString ;; little proggie adding one string to tmp string with rep stosd etc
ENDM
xor ecx, ecx ;; flag "not a source", cleanup
lea edx, dest ;; put address of destination$ in edx
lea eax, SAT ;; SysAllocTable for cleanup FreeStrings
call AddString ;; copy to dest and free the tmp string
pop esi
pop edi
ENDM


Cute, ain't it? And it works perfectly, except for one little problem: The STR$ eax that I pass over to the macro gets lost in translation:

STR$ MACRO DDvalue
mov eax, DDvalue
xor ecx, ecx ;; slot 0
call GfaSTR$ ;; returns a valid address to dwtoa buffer No. 0
... *** HERE THE REALLY EVIL THINGS HAPPEN! ***...
EXITM <eax> ;; but the eax gets lost during macro passes...!
ENDM


Since I don't give up so easily, I investigated and found a clumsy workaround:

STR1$ MACRO DDvalue
mov eax, DDvalue
xor ecx, ecx
inc ecx ;; mov ecx, 1 - use dwtoa buffer No. 1
call GfaSTR$
mov sptr1, eax ;; sptr1 is a local var, and this works
EXITM <sptr1>
ENDM

STR2$ MACRO DDvalue
mov eax, DDvalue
mov ecx, 2
call GfaSTR$
mov sptr2, eax ;; sptr2 is a local var, and this works
EXITM <sptr2>
ENDM


This works like a charm, but it is definitely a bit clumsy. Another working solution is...

call GfaSTR$
mov esi, eax
EXITM <esi>

... but using esi in this context is kind of dangerous.

Questions:
- are there clearly defined rules what happens in MACRO passes 1..n, and which registers might get lost?
- are there other workarounds?
Thanxalot, jj

qWord

Hi jj2007,

Try it with the expansion-operator "%":

           MulCat Tmp$, FileHasNow$, %STR$(CurSize), fSize$, AtLoop$, %STR$(LoopCounter)
or:   
    %    MulCat Tmp$, FileHasNow$, STR$(CurSize), fSize$, AtLoop$, STR$(LoopCounter)


qWord
FPU in a trice: SmplMath
It's that simple!

jj2007

Quote from: qWord on May 05, 2008, 06:26:47 PM
Try it with the expansion-operator "%":

           MulCat Tmp$, FileHasNow$, %STR$(CurSize), fSize$, AtLoop$, %STR$(LoopCounter)
or:   
    %    MulCat Tmp$, FileHasNow$, STR$(CurSize), fSize$, AtLoop$, STR$(LoopCounter)

Thanks, qWord - I'm afraid neither option works. Apparently, passing a fn() to a macro implies that the usual suspects, eAx, eCx, eDx, get lost during expansion.
In the meantime, I found a workaround using a global variable in exitm <globvar>

qWord

what do you mean with "get lost" => blank?

You could post more code or/and show the error-message by ml

regards, qWord
FPU in a trice: SmplMath
It's that simple!

jj2007

#4
Quote from: qWord on May 05, 2008, 08:39:35 PM
what do you mean with "get lost" => blank?
No, instead of my expected pointer to a variable in eax (as returned through EXITM <eax>) I get garbage values. If I use esi for the same purpose, it works - but that is not a good solution...

Quote
You could post more code or/

If you don't fear for your mental health... see attachment. Source is tmp_file.asm, the workaround can be enabled/disabled in the first line through the workaround EQU 0 or 1; the workaround is used in Gfa2Masm.inc

For workaround EQU 0, the MsgBox shows "Testbed.exe has now  bytes at loop 456"
For workaround EQU 1, the MsgBox shows "Testbed.exe has now 123 bytes at loop 456"

If you are really curious, activate the .if ecx<99 in the MulCat macro

Quote
and show the error-message by ml

No error messages, the code assembles fine (but I have to discard the garbage to avoid exceptions).

[attachment deleted by admin]

u

masm macros are tricky when doing literal stuff with them. Search here or the asmcommunity for a link to the full macro documentation (it was one big html page iirc). I didn't have that page while developing some complex macros, so a lot of trial and error was involved. But ultimately, there's always a way to solve the probs. Look into using @CatStr to generate lines of literals, and  using global macro-literals instead of local ones ("local" in the macro definition). Also, reusing a local variable one time for literals, then for integer is sometimes a no-no.
Please use a smaller graphic in your signature.


jj2007

Quote from: Ultrano on May 05, 2008, 10:11:43 PM
http://doc.ddart.net/asm/Microsoft_MASM_Programmers_Guide_v6.1/Chap_09.htm

http://webster.cs.ucr.edu/Page_TechDocs/MASMDoc/ReferenceGuide/Chap_03.htm

Thanks, I've consulted them already. But there is no easy way out, eax will simply be "lost in translation". Same for ecx and edx; but as I said, I have a workaround. Now the following para assembles and works fine:

   OPEN "I", #1, "TestBed.exe"
   MulCat Tmp$, FileHasNow$, STR$(LOF(#1)), fSize$, " at loop ", STR1$(MyCt)
   CLOSE 1
   MsgBox Tmp$, "Isn't it great?", MB_OK

Doesn't really look like assembler, I know ;-)

qWord

so...

its not a macro problem, its a logical problem:

this works:  MulCat Tmp$, FileHasNow$, <STR1$(123)>, fSize$, AtLoop$, STR2$(456)

STR1$(123) must be expand in the FOR-loop (MACRO-LOOP!!!), otherwise eax will be overridden by prior procedure-calls  ( AddString(Tmp$) and AddString(FileHasNow$) )



MulCat MACRO dest:REQ, strings:VARARG
push edi
push esi
xor edi, edi
FOR macstr, <strings>
mov ecx, macstr ; <= here is the problem! : if macstr == mem-operants => no problem
                                                ;if macstr == eax  => eax is undefined => look@debuger
xor eax, eax
call AddString
ENDM
xor ecx, ecx
lea edx, dest
lea eax, SAT
call AddString
pop esi
pop edi
ENDM
FPU in a trice: SmplMath
It's that simple!

jj2007

Quote from: qWord on May 05, 2008, 10:54:33 PM
this works:  MulCat Tmp$, FileHasNow$, <STR1$(123)>, fSize$, AtLoop$, STR2$(456)

Very helpful, thanxalot! It is even some bytes shorter... the exe is at 3584 bytes, not bad for a string management and basic file I/O library ;-)

   OPEN "I", #1, "TestBed.exe"
   invoke GetTickCount
   mov tc, eax
   MulCat Tmp$, FileHasNow$, <STR$(LOF(#1))>, " bytes at ", <STR$(tc)>, " ticks in loop ", <STR$(MyCt)>, " - FANTASTIC!!"
   MsgBox Tmp$, "Write to Tmp.txt?", MB_YESNOCANCEL
   .if eax==IDYES
      OPEN "O", #2, "Tmp.txt"
      PRINT #2, Tmp$
   .endif
   CLOSE

Attachment still has some switches for continued testing.

[attachment deleted by admin]