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
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
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>
what do you mean with "get lost" => blank?
You could post more code or/and show the error-message by ml
regards, qWord
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]
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.
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
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 ;-)
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
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]