This is just an attempt :biggrin:
My Invoke macro with best performence
.invoke CreateFont,16,8,0,0,600,0,0,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,PROOF_QUALITY,FF_DONTCARE,"fixedsys"
.text:00000000004014e0 sub rsp, 0x70
.text:00000000004014e4 mov rcx, 0x10
.text:00000000004014eb mov rdx, 8
.text:00000000004014f2 xor r8, r8
.text:00000000004014f5 xor r9, r9
.text:00000000004014f8 mov qword ptr [rsp+0x20], 0x258
.text:0000000000401501 mov qword ptr [rsp+0x28], r8
.text:0000000000401506 mov qword ptr [rsp+0x30], r8
.text:000000000040150b mov qword ptr [rsp+0x38], 0x1
.text:0000000000401514 mov qword ptr [rsp+0x40], r8
.text:0000000000401519 mov qword ptr [rsp+0x48], r8
.text:000000000040151e mov qword ptr [rsp+0x50], 2
.text:0000000000401527 mov qword ptr [rsp+0x58], r8
.text:000000000040152c lea rax, [0x004032ef]
.text:0000000000401533 mov qword ptr [rsp+0x60], rax
.text:0000000000401538 call qword ptr [CreateFontA]
.text:000000000040153e add rsp, 0x70
.invoke MessageBox,0,"This is a test",0,RCX
.text:0000000000401542 sub rsp, 0x20
.text:0000000000401546 lea rdx, [0x004032f8]
.text:000000000040154d xor r8, r8
.text:0000000000401550 mov r9, rcx
.text:0000000000401553 xor rcx, rcx
.text:0000000000401556 call qword ptr [MessageBoxA]
.text:000000000040155c add rsp, 0x20
.invoke MessageBox,R9,"This is a test",0,edx
.text:0000000000401560 sub rsp, 0x20
.text:0000000000401564 mov rcx, r9
.text:0000000000401567 lea rax, [0x00403307]
.text:000000000040156e mov qword ptr [rsp+0x8], rax
.text:0000000000401573 xor r8, r8
.text:0000000000401576 mov r9d, edx
.text:0000000000401579 mov rdx, qword ptr [rsp+0x8]
.text:000000000040157e call qword ptr [MessageBoxA]
.text:0000000000401584 add rsp, 0x20
OPTION DOTNAME
.Putstr macro sstr
LOCAL dstr,?Len,cur_Pos,ch_unq,tmpStr
IFDEF __UNICODE__
?Len = @SizeStr(<sstr>)
?Len = ?Len - 2
cur_Pos = 1
tmpStr CATSTR <>
repeat ?Len
cur_Pos=cur_Pos+1
ch_unq SubStr <sstr>,cur_Pos,1
tmpStr CATSTR tmpStr,<!">,ch_unq,<!",>
endm
.data
dstr dw tmpStr 0
.code
ELSE
.data
dstr db sstr,0
.code
ENDIF
EXITM< dstr >
endm
.RAX macro __val
LOCAL n
n equ type( __val)
IF n eq 1
MOV AL,__val
ELSEIF n eq 2
MOV AX,__val
ELSEIF n eq 4
MOV EAX,__val
ELSE
MOV RAX,__val
ENDIF
endm
.RCX macro __val
LOCAL n
n equ type( __val)
IF n eq 1
MOV CL,__val
ELSEIF n eq 2
MOV CX,__val
ELSEIF n eq 4
MOV ECX,__val
ELSE
MOV RCX,__val
ENDIF
endm
.RDX macro __val
LOCAL n
n equ type( __val)
IF n eq 1
MOV DL,__val
ELSEIF n eq 2
MOV DX,__val
ELSEIF n eq 4
MOV EDX,__val
ELSE
MOV RDX,__val
ENDIF
endm
.R8 macro __val
LOCAL n
n equ type( __val)
IF n eq 1
MOV R8B,__val
ELSEIF n eq 2
MOV R8W,__val
ELSEIF n eq 4
MOV R8D,__val
ELSE
MOV R8,__val
ENDIF
endm
.R9 macro __val
LOCAL n
n equ type( __val)
IF n eq 1
MOV R9B,__val
ELSEIF n eq 2
MOV R9W,__val
ELSEIF n eq 4
MOV R9D,__val
ELSE
MOV R9,__val
ENDIF
endm
.MEM macro __val,__ad
LOCAL n
n equ type( __val)
IF n eq 1
MOV BYTE PTR [RSP+__ad],__val
ELSEIF n eq 2
MOV WORD PTR [RSP+__ad],__val
ELSEIF n eq 4
MOV DWORD PTR [RSP+__ad],__val
ELSE
MOV QWORD PTR [RSP+__ad],__val
ENDIF
endm
.SetMEM macro addit_,argN
IF IsNullv eq 1
IF hNullReg
MOV QWORD PTR [RSP+addit_],rNullReg
ELSE
IF nRAX
MOV QWORD PTR [RSP+addit_],RAX
ELSE
nRAX =1 ;rax=0
XOR RAX,RAX
MOV QWORD PTR [RSP+addit_],RAX
ENDIF
ENDIF
ELSEIF IsAddr eq 1
nRAX =2 ;rax=??
LEA RAX,@SubStr(<argN>,2)
MOV QWORD PTR [RSP+addit_],RAX
ELSEIF IsString eq 1
nRAX =2 ;rax=??
LEA RAX,.Putstr(argN)
MOV QWORD PTR [RSP+addit_],RAX
ELSE
IF (instrRAX and uRAX)
IF nRAX ne 3
nRAX =3 ;rax=rax
MOV RAX,QWORD PTR [RSP-8] ; pop rax
ENDIF
.MEM argN, addit_
ELSEIF uIMM eq 1
nRAX =2 ;rax=??
.RAX argN
MOV QWORD PTR [RSP+addit_],RAX
ELSE
.MEM argN, addit_
ENDIF
ENDIF
endm
.invoke macro ProcName,ProcArg:vararg
nbProcArg = 0
uRCX = 0
uRDX = 0
uR8 = 0
uR9 = 0
uRAX = 0
nRCX = 0
nRDX = 0
nR8 = 0
nR9 = 0
nRAX = 0
uIMM = 0
instrInterface INSTR 1,<ProcName>,<.>
IF instrInterface
nbProcArg = nbProcArg + 1
ENDIF
FOR argN,<ProcArg>
nbProcArg=nbProcArg+1
upArg CatStr <__UpStr(&argN)>
% instrRCX INSTR 1,<-RCX-ECX-CX-CH-CL->,<-&upArg&->
% instrRDX INSTR 1,<-RDX-EDX-DX-DH-DL->,<-&upArg&->
% instrR8 INSTR 1,<-R8-R8D-R8W-R8B->,<-&upArg&->;
% instrR9 INSTR 1,<-R9-R9D-R9W-R9B->,<-&upArg&->
% instrRAX INSTR 1,<-RAX-EAX-AX-AH-AL->,<-&upArg&->
instrAddr SubStr <argN>,1,1
IsNullArg = 0
IFDIF instrAddr,<&>
IFDIF instrAddr,<">
??oparg = OPATTR(argN)
IF (??oparg eq 024h)
?v = argN
IF ?v eq 0
IF nbProcArg eq 1
nRCX = 1
ELSEIF nbProcArg eq 2
nRDX = 1
ELSEIF nbProcArg eq 3
nR8 = 1
ELSEIF nbProcArg eq 4
nR9 = 1
ENDIF
IsNullArg = 1
ENDIF
ENDIF
ENDIF
ENDIF
IF (( uRCX eq 0 ) and ( nbProcArg ne 1 ) )
IF instrRCX
uRCX = 1
ENDIF
ENDIF
IF (( uRDX eq 0 ) and ( nbProcArg gt 1 ) )
IF instrRDX
uRDX = 1
ENDIF
ENDIF
IF (( uR8 eq 0 ) and ( nbProcArg gt 2 ) )
IF instrR8
uR8 = 1
ENDIF
ENDIF
IF (( uR9 eq 0 ) and ( nbProcArg gt 3 ) )
IF instrR9
uR9 = 1
ENDIF
ENDIF
IF (( uRAX eq 0 ) and ( nbProcArg gt 4 ) )
IF instrRAX
uRAX = 1
ENDIF
ENDIF
IF IsNullArg eq 0
IF ((uIMM eq 0) and ( nbProcArg gt 4) );and (IsNullArg eq 0)
IFIDN instrAddr,<&>
uIMM = 1
ENDIF
IFDIF instrAddr,<&>
IFIDN instrAddr,<">
uIMM = 1
ENDIF
IFDIF instrAddr,<">
??oparg = OPATTR(argN)
IF ((??oparg eq 024h) OR (??oparg eq 026h) OR (??oparg eq 030h) OR (??oparg eq 062h)) eq 0;Reg or Imm
uIMM = 1
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDM
adj??=nbProcArg-((nbProcArg/2)*2)
alnbProcArg=nbProcArg+adj?? ; align to 16
IF alnbProcArg lt 4
alnbProcArg=4
ENDIF
alnbProcArg=(alnbProcArg*8)
hNullReg = 1
IF (nRCX and (uRCX eq 0))
rNullReg equ <RCX>
ELSEIF (nRDX and (uRDX eq 0))
rNullReg equ <RDX>
ELSEIF (nR8 and (uR8 eq 0))
rNullReg equ <R8>
ELSEIF (nR9 and (uR9 eq 0))
rNullReg equ <R9>
ELSE
uIMM = 1
hNullReg = 0
ENDIF
SUB RSP,alnbProcArg
; If rax is in args and and there are an other mem arg that we must use rax to pass it
IF ((uRAX eq 1) and (uIMM eq 1))
MOV QWORD PTR [RSP-8],RAX ; PUSH RAX
ELSE
uRAX = 0
ENDIF
nbProcArg=0
IF instrInterface
nbProcArg=nbProcArg+1
ENDIF
FOR argN,<ProcArg>
IsNullv = 0
upArg CatStr <__UpStr(&argN)>
% instrRCX INSTR 1,<-RCX-ECX-CX-CH-CL->,<-&upArg&->
% instrRDX INSTR 1,<-RDX-EDX-DX-DH-DL->,<-&upArg&->
% instrR8 INSTR 1,<-R8-R8D-R8W-R8B->,<-&upArg&->;
% instrR9 INSTR 1,<-R9-R9D-R9W-R9B->,<-&upArg&->
% instrRAX INSTR 1,<-RAX-EAX-AX-AH-AL->,<-&upArg&->
instrAddr SubStr <argN>,1,1
uIMM = 0
IsAddr = 0
IsString = 0
IFIDN instrAddr,<&>
IsAddr = 1
ENDIF
IF IsAddr ne 1
IFIDN instrAddr,<">
IsString = 1
ENDIF
IF IsString ne 1
??oparg = OPATTR(argN)
IF (??oparg eq 024h)
?v = argN
IF ?v eq 0
IsNullv = 1
ENDIF
ENDIF
ENDIF
ENDIF
uIMM = 0
IF ((IsNullv eq 0) and ( IsString eq 0)and ( IsAddr eq 0) )
??oparg = OPATTR(argN)
IF ((??oparg eq 024h) OR (??oparg eq 026h) OR (??oparg eq 030h) OR (??oparg eq 062h))
uIMM = 1
ENDIF
ENDIF
IF nbProcArg eq 0
IF uRCX eq 1 ;If RCX is used in other arg => push in home
IF nRCX eq 0
.SetMEM 0,argN
ENDIF
ELSE
IF IsNullv eq 1 ; if arg =0
XOR RCX,RCX
ELSEIF IsAddr eq 1
LEA RCX,@SubStr(<argN>,2)
ELSEIF IsString eq 1
% LEA RCX,.Putstr(argN)
ELSE
IF instrRCX eq 0 ; if not rcx in 1st arg
.RCX argN
ENDIF
ENDIF
ENDIF
ELSEIF nbProcArg eq 1
IF uRDX eq 1
IF nRDX eq 0
.SetMEM 8,argN
ENDIF
ELSE
IF IsNullv eq 1
XOR RDX,RDX
ELSEIF IsAddr eq 1
LEA RDX,@SubStr(<argN>,2)
ELSEIF IsString eq 1
LEA RDX,.Putstr(argN)
ELSE
IF instrRDX eq 0 ; if not rcx in 1st arg
.RDX argN
ENDIF
ENDIF
ENDIF
ELSEIF nbProcArg eq 2
IF uR8 eq 1
IF nR8 eq 0
.SetMEM 16,argN
ENDIF
ELSE
IF IsNullv eq 1
XOR R8,R8
ELSEIF IsAddr eq 1
LEA R8,@SubStr(<argN>,2)
ELSEIF IsString eq 1
LEA R8,.Putstr(argN)
ELSE
IF instrR8 eq 0
.R8 argN
ENDIF
ENDIF
ENDIF
ELSEIF nbProcArg eq 3
IF uR9 eq 1
IF nR9 eq 0
.SetMEM 24,argN
ENDIF
ELSE
IF IsNullv eq 1
XOR R9,R9
ELSEIF IsAddr eq 1
LEA R9,@SubStr(<argN>,2)
ELSEIF IsString eq 1
LEA R9,.Putstr(argN)
ELSE
IF instrR9 eq 0
.R9 argN
ENDIF
ENDIF
ENDIF
ELSE
.SetMEM <(nbProcArg*8)>,argN
ENDIF
nbProcArg=nbProcArg+1
ENDM
IF uRCX eq 1
IF nRCX ne 0
XOR RCX,RCX
ELSE
MOV RCX,QWORD PTR [RSP]
ENDIF
ENDIF
IF uRDX eq 1
IF nRDX ne 0
XOR RDX,RDX
ELSE
MOV RDX,QWORD PTR [RSP+8]
ENDIF
ENDIF
IF uR8 eq 1
IF nR8 ne 0
XOR R8,R8
ELSE
MOV R8,QWORD PTR [RSP+16]
ENDIF
ENDIF
IF uR9 eq 1
IF nR9 ne 0
XOR R9,R9
ELSE
MOV R9,QWORD PTR [RSP+24]
ENDIF
ENDIF
IF instrInterface
sChrs SizeStr <ProcName>
MOV RCX,@SubStr(ProcName,1,instrInterface-1)
MOV RAX,[RCX]
IF sChrs gt instrInterface
fChr SubStr <ProcName>,instrInterface+1,1
instrNum INSTR 1,<0123456789>,fChr
Indexf SubStr <ProcName>,instrInterface+1
IF instrNum
ADD RAX,Indexf * ( SizeOf rWord)
CALL QWORD PTR [RAX]
ELSE
% CALL [RAX]. &Indexf&
ENDIF
ELSE
CALL QWORD PTR [RAX]
ENDIF
ELSE
call ProcName
ENDIF
ADD RSP,alnbProcArg
endm
Interesting approach, and it works fine :t
Compliments, the output is well done. The next trick is to handle different sized data apart from QWORD sizes. Sad to say the input from some structures is in DWORD rather than QWORD so you need to use OPATTR to determine the data SIZE and write it to the appropriate sized register (al, ax, eax etc ...) then write the full 64 bit register to the memory locations you are using.
I just had a look at the source you have posted and it does the correct sizes. Compliments again. :t
Quote from: hutch-- on August 07, 2016, 08:12:09 PMThe next trick is to handle different sized data apart from QWORD sizes
...
I just had a look at the source you have posted and it does the correct sizes. Compliments again. :t
Nice indeed:
.RCX macro __val
LOCAL n
n equ type( __val)
IF n eq 1
MOV CL,__val
ELSEIF n eq 2
MOV CX,__val
ELSEIF n eq 4
MOV ECX,__val
ELSE
MOV RCX,__val
ENDIF
endm
mabdelouahab,
I have a question for you, have you written your own prologue/epilogue or are you using an existing one, the default or Vasily's pair ? I ask this for a reason as so far I have found this effects "invoke" style macros wityh how accurately the data is passed to the called process.
Indeed, prolog macros are fun :t
You can smuggle in things like this check for stack alignment:
if usedeb
j4Save ; save 4 args in global vars
test sp, 15
je alignOK
Print " Stack misaligned in &procname: "
mov rax, rsp
PrintLine Hex$(rax)
jmp alignBad
alignOK:
if jbVerbosePE
PrintLine " stack ok"
endif
alignBad:
j4Restore
endif
Applied to a commented out sub rsp, 8:
j@start
; sub rsp, 8 ; v v v fall through to winmain requires this correction
WinMain proc arg
Results in WndProc:
Message=f
Message=14
Message=7f
Message=7f
Message=7f
Stack misaligned in WndProc: 12fbf8
Message=c0d6
Message=86
Message=d
Message=6
The odd thing here is that over 90% of all messages are aligned. And you can run the proggie without ever seeing a problem - the ideal situation for spending some nights in bug chasing mode :P
Quote from: hutch-- on August 08, 2016, 05:16:48 PM
mabdelouahab,
I have a question for you, have you written your own prologue/epilogue or are you using an existing one, the default or Vasily's pair ? I ask this for a reason as so far I have found this effects "invoke" style macros wityh how accurately the data is passed to the called process.
Sir hutch,
I don't use my own prologue/epilogue, I use what you use in masm64rt.inc
Off-topic, but jj's "test sp, 15" caught my eye.
An interesting use of a 16+ bit register - accessing the low byte of the stack pointer.
.flat:0000000000401000 48 F7 C4 0F 00 00 00 test rsp, 0Fh
.flat:0000000000401007 F7 C4 0F 00 00 00 test esp, 0Fh
.flat:000000000040100D 66 F7 C4 0F 00 test sp, 0Fh
.flat:0000000000401012 40 F6 C4 0F test spl, 0Fh
There is no corresponding sph because the encoding for the high byte (and AH,BH etc) is used in 64-bit mode as a prefix (usually REX ?).
Nice find, John :t
Will test if all assemblers understand spl ;)
Now you can call Interface methods:
.invoke ppvInterface.index ,.......
ppvInterface:variable = interface pointer
index : is const number 0=first function,1=second function, ...
or .invoke ppvInterface.IvTable.Method ,.......
or .invoke ppvInterface. ,....... ; to call the first method
Word Application Example:
STIUnknown STRUCT
Queryinterface DQ 0 ; index=0
AddRef DQ 0 ; index=1
Release DQ 0 ; index=2
STIUnknown ends
.data
IID_IUnknown GUID <000000000h,00000h,00000h,<0C0h,000h,000h,000h,000h,000h,000h,046h>>
CLSID_Word_Application GUID <0000209FFh,00000h,00000h,<0C0h,000h,000h,000h,000h,000h,000h,046h>>
IID_Word__Application GUID <000020970h,00000h,00000h,<0C0h,000h,000h,000h,000h,000h,000h,046h>>
.code
.invoke CoInitializeEx,0,0
.invoke CoCreateInstance,&CLSID_Word_Application,0,CLSCTX_LOCAL_SERVER,&IID_IUnknown,&_ppv_IUnknown
.if rax == S_OK
.invoke MessageBoxW,0,"CoCreateInstance Word Application ok",0,0
.invoke _ppv_IUnknown.STIUnknown.Queryinterface,&IID_Word__Application,&WordApplication
; Also you can use:
;.invoke _ppv_IUnknown.,&IID_Word__Application,&WordApplication
.if rax == S_OK
.invoke MessageBoxW,0,"IUnknown.Queryinterface ok",0,0
;------------------------------------ WordApplication.Visible = TRUE
.invoke WordApplication.34,TRUE
;------------------------------- pause
.invoke MessageBoxW,0,"push OK to quit Winword ",0,0
.data
NulloptionalArg dw VT_ERROR,0,0,0 ;Null Optional Arg
dq DISP_E_PARAMNOTFOUND,0
.code
; WordApplication.Quit ([in,optional] SaveChanges:Ptr Variant,[in,optional] OriginalFormat:Ptr Variant,...)
.invoke WordApplication.120,&NulloptionalArg,&NulloptionalArg,&NulloptionalArg
;WordApplication.Release
.invoke WordApplication.2
.endif
.endif