I am reading the macro include files and help files in masm32 directory, but if there is something I don't understand well, it's macros. I seldom use them. It was under DOS that I went into it for the first time, but like I said I seldom use it under masm32. Sometimes I use the macros that comes with masm32 and sometimes I create simple macros for plotting pixels and that sort of stuff.
Can anyone produce (5-6-7-8-9 or 10) small examples, very tiny examples with different usage of macros. How to insert literal text, how to insert values to registers, how to differentiate between text, numbers and so forth. Can you produce a few small samples, they must be very very tiny samples so that I can grasp it with ease. I appreciate wide variety of usage, so the more examples the better. The less complex the better.
Many small, but wide variety that covers most in as little text as possible. Be very accurate, keep text clean, use proper naming convention, organize your work, keep it clean above everything.
(Btw, I understand the definition of macros, they are pseudo instructions for the assembler, I need only to learn how to use them properly)
EDIT: I realized it may be better to ask for specific type of examples. I can give a few suggestions..
1: Macro to insert text into the .asm file, let's say I need to replace an argument inside an INVOKE, how can I use a macro to replace parameters?
2: How to create variables in a macro and perform some calculations (perhaps)
....
i have gotten a little better with them :P
watching jj2007 and qWord helps a lot - so you might use advanced search, the term "macro", and limit the results to either of those ID's
of course, other members are good at macros, as well - those two just come to mind :P
also - the masm programmers guide is a must-read - it has a pretty good section on macros
http://www.4shared.com/zip/39MdNf_v/MASMProgGuide.html
this is a good example of how to replace a parm in INVOKE
len MACRO lpString
invoke szLen,reparg(lpString)
EXITM <eax>
ENDM
notice the EXITM <eax> line
also important to understand that both the macro and the function preserve all other registers, including ECX and EDX
that way, if...
INVOKE SomeFunction,ecx,len(offset szString)
the contents of ECX are not destroyed by the macro before it is pushed onto the stack by INVOKE
Thanks, I am now a certified macro professional.
You will understand about half of it (my success quote with qWord's macros :bg), but don't worry, that's more than enough for the certificate.
Theory: Masm Programmer's Guide (search the forum, e.g. this post (http://www.masm32.com/board/index.php?topic=5433.msg70110#msg70110))
Usage: \masm32\MasmBasic\MbGuide.rtf (>100 macros explained)
Macros: \masm32\MasmBasic\MasmBasic.inc
The MasmBasic package is at http://www.masm32.com/board/index.php?topic=12460
Example:
Err$()
Err$(1) ; call GetLastError, and show a MessageBox with a formatted string if there was an error
Err$(0) ; call GetLastError, and show a MessageBox even if there was no error
PrintLine "Result=", Err$() ; print the formatted string
void Err$() ; no arg: returns <eax> plus the zero flag
.if !Zero? ; for use with .if, .Break etc
MsgBox 0, eax, "Hey coder, there is an error:", MB_OK
.else
deb 4, "Loop C", $eax ; will write The operation completed successfully to the console
.endif
Rem the blank argument version returns a pointer to the formatted error desription in eax
The macro from MasmBasic.inc:
Err$ MACRO dummy ; 0: show always, 1: show if error, (): .if e$()
push ecx
push ebx
invoke GetLastError
xchg eax, ebx
mov edx, offset MbDebugBuffer+512 ; 1024/2
push edx ; make a copy for the retval
xor ecx, ecx
push ecx ; no args
push 512 ; size
push edx ; pBuffer
push ecx ; default language
push ebx ; the error #
push ecx ; no source, GetItFromSystem
push FORMAT_MESSAGE_FROM_SYSTEM
call FormatMessage
ifnb <dummy>
mov eax, [esp] ; MbGpBuffer
ifidn <dummy>, <0>
.if ebx
invoke MessageBox, 0, eax, 0, MB_OK
.endif
else
invoke MessageBox, 0, eax, 0, MB_OK
endif
endif
pop eax ; offset MbGpBuffer
test ebx, ebx ; allows void Err$(), .if !Zero?
pop ebx
pop ecx
ifnb <dummy>
EXITM <>
else
EXITM <eax>
endif
ENDM
i see you've taken up one of my favorite tricks :bg
xchg eax, ebx
ok, i have a question...
void Err$() ; no arg: returns <eax> plus the zero flag
wouldn't that just be
Err$() ; no arg: returns <eax> plus the zero flag
if you changed the end to this ?
ifnb <dummy>
EXITM
else
EXITM <eax>
endif
ENDM
actually, i guess it would be this ?
ifb <dummy>
EXITM <eax>
endif
ENDM
dedndave,
that not possible: if your macro return something, it must be done for all paths. However, you have the option to return nothing: EXITM <>.
What exactly does EXITM do, I have forgotten, lol, all I remember is that it stands for exit macro? Also, can anyone explain or give an example of how to add two numbers in a macro and have the macro output the result as text into the source code.
EXITM returns a string. This is e.g. the case for mov ecx, rv(GetTickCount).
The "standalone" macros such as print do not return anything, therefore no EXITM.
You can use a function macro in "standalone mode", e.g. for starting in MasmBasic the QueryPerformanceCounter:
NanoTimer()
... do stuff ...
Print Str$("%i ms needed", NanoTimer(ms))
The first call returns EXITM <>, the second one EXITM <eax>.
Here is a macro that adds two numbers and displays the result.
include \masm32\include\masm32rt.inc
Add2 MACRO arg1, arg2
LOCAL oa
push arg1
oa = opattr arg2
if (oa eq 36) or (oa eq 48) ; immediate or register
add dword ptr [esp], arg2
else
mov eax, arg2
add [esp], eax
endif
pop eax
print str$(eax), 13, 10
ENDM
.code
v1 dd 111
AppName db "Masm32:", 0
start: Add2 v1, 222
Add2 222, v1
mov eax, v1
Add2 eax, 222
inkey "bye"
exit
end start
This is a proper example :U
EXITM allows you to return data to the caller of the macro, either inline in the source code text or called from another macro.
EXITM <eax>
This allows you to place the data in EAX inline with the code that calls the macro that EXITM is contained in.
hutch, can you give an example of calling another macro and returning in that way. Something simple is preferrable.
This should make sense.
IF 0 ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
Build this template with "CONSOLE ASSEMBLE AND LINK"
ENDIF ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
include \masm32\include\masm32rt.inc
addem MACRO int1,int2 ;; function style macro that returns a value
mov eax, int1
add eax, int2
EXITM <eax> ;; return data in EAX to caller
endm
.code
start:
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
call main
inkey
exit
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
main proc
LOCAL retval1 :DWORD
cls
mov retval1, addem(1234,5678)
print ustr$(retval1),13,10
ret
main endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
end start
Nested like this.
IF 0 ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
Build this template with "CONSOLE ASSEMBLE AND LINK"
ENDIF ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
include \masm32\include\masm32rt.inc
addem MACRO int1,int2 ;; function style macro that returns a value
mov eax, int1
add eax, int2
EXITM <eax> ;; return data in EAX to caller
endm
.code
start:
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
call main
inkey
exit
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
main proc
LOCAL retval1 :DWORD
LOCAL retval2 :DWORD
cls
mov retval1, addem(1234,addem(1111,addem(9876,5432)))
mov retval2, addem(retval1,retval1)
print ustr$(retval2),13,10
ret
main endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
end start
Same as before but in function form. Actually, Hutch' solution
mov eax, arg1
add eax, arg2
is simpler and works fine, too.
include \masm32\include\masm32rt.inc
Add2 MACRO arg1, arg2
LOCAL oa, is, leftarg, rightarg
is INSTR <arg1>, <+>
if is
leftarg SUBSTR <arg1>, 1, is-1
rightarg SUBSTR <arg1>, is+1
push leftarg
oa = opattr rightarg
if (oa eq 36) or (oa eq 48) ; immediate or register
add dword ptr [esp], rightarg
else
mov eax, rightarg
add [esp], eax
endif
pop eax
EXITM <eax>
else
push arg1
oa = opattr arg2
if (oa eq 36) or (oa eq 48) ; immediate or register
add dword ptr [esp], arg2
else
mov eax, arg2
add [esp], eax
endif
pop eax
print str$(eax), 13, 10
EXITM <>
endif
ENDM
.code
v1 dd 111
AppName db "Masm32:", 0
start: Add2(v1, 222) ; standalone usage
Add2(222, v1)
mov eax, v1
Add2(eax, 222)
mov ecx, 111
print str$(Add2(ecx+222)), 13, 10 ; used as function
inkey "bye"
exit
end start
Thanks, nice and simple. I can live with this. :lol
Another example please.
I am aware of the rv macro, but how would you go ahead and do it if you wanted to
1: The macro should check if the returned value is NULL, if it is null the macro should jump to a label
2: The label should be passed as an argument to the macro.
Very often I use API function that could return NULL and then I usually need to jump somewhere. Can you make an example of this, the macro should jump to n1 on not null and n0 on null. Or at least jump to n0 on null and perhaps stay neutral otherwise. (no jump)
Example: RVZ FunctionName Parameter1 Parameter2 n0
n0: INVOKE ExitProcess, eax
Quote from: zemtex on April 15, 2012, 07:59:46 AM
Thanks, nice and simple. I can live with this. :lol
ML.exe (and JWasm) has a really powerful macro engine, in contrast to other assemblers. Try this...
include \masm32\MasmBasic\MasmBasic.inc ; download (http://www.masm32.com/board/index.php?topic=12460)
Init
movlps xmm1, FP8(123.45678)
mov eax, 100
Inkey Str$("Xmm1*eax/ecx+PI=%f", f:xmm1*eax/1.2345678+PI)
Exit
end start
Xmm1*eax/ecx+PI=10003.14
I have a feeling you have been working hard on this masmbasic :bg
Quote from: zemtex on April 15, 2012, 08:15:19 AM
Example: RVZ FunctionName Parameter1 Parameter2 n0
To have some flexibility, I would use a design that allows for variable arguments:
include \masm32\include\masm32rt.inc
rvz MACRO jmparg, API:REQ, args:VARARG
is INSTR <jmparg>, <z:>
invoke API, args
test eax, eax
if is eq 2
jne @SubStr(<jmparg>, is+2)
else
je @SubStr(<jmparg>, is+2)
endif
EXITM <eax>
ENDM
.code
start:
print str$(rvz(z:Complain, GetSystemMetrics, 123 or SM_CMOUSEBUTTONS)), 13, 10
@@: inkey "bye"
exit
Complain:
print "There was an error!", 13, 10
jmp @B
end start
here is my unfinished work on fluxusmacros that is limited to handle cubes(8 coordinates)
I was aiming at inlining that 3d tree fluxus example I found on the web
PUSHSTATE MACRO
FXSAVE [ebx]
add ebx,512
ENDM
POPSTATE MACRO
sub ebx,512
FXRSTOR [ebx]
ENDM
TRANSLATE MACRO vectconst
addps XMM0,vectconst
addps XMM1,vectconst
addps XMM2,vectconst
addps XMM3,vectconst
addps XMM4,vectconst
addps XMM5,vectconst
addps XMM6,vectconst
addps XMM7,vectconst
ENDM
SCALE MACRO vectconst
mulps XMM0,vectconst
mulps XMM1,vectconst
mulps XMM2,vectconst
mulps XMM3,vectconst
mulps XMM4,vectconst
mulps XMM5,vectconst
mulps XMM6,vectconst
mulps XMM7,vectconst
ENDM
;usage for example ROTATE vectconst1,X,Y,Z
;where first two is rotation axisconstants, last it the third axis not used
ROTATE MACRO vectconst,coord1,coord2,coord3 ;not finished
fld1
fst tmpf1
fst tmpf1+4
fst tmpf1+8
fst tmpf1+12
fst tmpf2
fst fmpf2+4
fst tmpf2+8
fstp tmpf2+12 ;mul coordinates not affected with 1.0
fld vectconst
fsincos
fst tmpf1+coord1
fstp tmpf1+coord2
fst tmpf2+coord1
fxch
fstp tmpf2+coord2 ;generate cos,-sin and cos,sin
fldz
movaps xmm0tmp,XMM0 ;copy XMM0
mulps XMM0,tmpf1 ;one mul XY
movaps tmpf3,XMM0
fstp tmpf3+coord3
;add zero to coordinates not effected
mov eax,tmpf3+coord1
xchg eax,tmpf3+coord2
mov tmpf3+coord1,eax
movaps tmpf2,XMM0
mulps XMM0,xmm0tmp ;second mul XY
addps XMM0,tmpf3 ;add xcos,-ysin with xsin,ycos
ENDM
New one:
How to define data in code section using macros, so that they are auto moved to data section or data? section.
Something like this:
DefineData MACRO Name:REQ, SomeText:REQ
db Name "SomeText"
ENDM
Also..
When I have data defined in the data section, like this
SomeData db "Some text here"
and I have a textequ at the top like this:
Digit TEXTEQU %(32*2+1)
How can I add Digit in between Some and text as "65" and not as ascii character 'A'
DefineData macro lbl:req,txt:VARARG
.data
lbl db txt
.code
endm
DefineData xyz,"Some ",65," text here",0
DefineData xyz,"Some ",Digit," text here",0
Quote from: zemtex on April 15, 2012, 04:10:03 PM
How to define data in code section using macros, so that they are auto moved to data section or data? section.
That's exactly what print
"hello world", 13, 10 or print
chr$("Hello World", 13, 10) do - see macros.asm...