Just wondering, has anyone more experienced in FASM macros created a set of PROC/ENDP macros that uses ESP to access the registers rather than EBP? I switched over from NASM recently but I am unable to bring some of my macros over with me. The following are for NASM (but the latest versions are breaking my macros to pieces).
%imacro Proc 1.nolist
%push Procedure$$
%assign %$Proc.ParamOffset 4
%assign %$Proc.LocalOffset 0
%assign %$Proc.StackOffset 0
%assign %$Proc.RegsOffset 0
%assign %$Proc.RegsAlloced 0
%1:
%endmacro
%imacro EndProc 1.nolist
%ifndef %$Proc.StackOffset
%error "'EndProc' used without a preceding Proc!"
%else
%pop
%endif
align 4
%endmacro
%imacro Param 1-*.nolist
%ifndef %$Proc.ParamOffset
%error "'Param' is not in a Procedure Context!"
%else
%assign %$Proc.LocalSave %$Proc.LocalOffset
%undef %$Proc.LocalOffset
%rep %0
%ifnnum %1
%assign %$Proc.StackSave %$Proc.StackOffset
%undef %$Proc.StackOffset
%xdefine %$%1 esp+%$Proc.LocalOffset+%$Proc.ParamOffset+%$Proc.StackOffset
%define %1 %$%1
%assign %$Proc.StackOffset %$Proc.StackSave
%ifnum %2
%assign %$Proc.ParamOffset %$Proc.ParamOffset+%2
%else
%assign %$Proc.ParamOffset (%$Proc.ParamOffset+7)&0FFFFFFFCh
%endif
%endif
%rotate 1
%endrep
%assign %$Proc.LocalOffset %$Proc.LocalSave
%endif
%endmacro
%imacro Local 1-*.nolist
%ifndef %$Proc.ParamOffset
%error "'Local' is not in a Procedure Context!"
%else
%rep %0
%ifnnum %1
%assign %$Proc.StackSave %$Proc.StackOffset
%undef %$Proc.StackOffset
%xdefine %$%1 esp+%$Proc.LocalOffset+%$Proc.StackOffset
%define %1 %$%1
%assign %$Proc.StackOffset %$Proc.StackSave
%ifnum %2
%assign %$Proc.LocalOffset %$Proc.LocalOffset+%2
%else
%assign %$Proc.LocalOffset (%$Proc.LocalOffset+7)&0FFFFFFFCh
%endif
%endif
%rotate 1
%endrep
%endif
%endmacro
%define ParamSpace$$ %$Proc.ParamOffset-4
%define LocalSpace$$ %$Proc.LocalOffset
%define EDI$$ [esp+%$Proc.StackOffset-%$Proc.RegsOffset+0]
%define ESI$$ [esp+%$Proc.StackOffset-%$Proc.RegsOffset+4]
%define EBP$$ [esp+%$Proc.StackOffset-%$Proc.RegsOffset+8]
%define ESP$$ [esp+%$Proc.StackOffset-%$Proc.RegsOffset+12]
%define EBX$$ [esp+%$Proc.StackOffset-%$Proc.RegsOffset+16]
%define EDX$$ [esp+%$Proc.StackOffset-%$Proc.RegsOffset+20]
%define ECX$$ [esp+%$Proc.StackOffset-%$Proc.RegsOffset+24]
%define EAX$$ [esp+%$Proc.StackOffset-%$Proc.RegsOffset+28]
;--------------------------------------------------------------------------
%macro push 0-*.nolist
%rep %0
%ifidn %1,all
pushad
%ifdef %$Proc.StackOffset
%assign %$Proc.StackOffset %$Proc.StackOffset+32
%if (%$Proc.RegsAlloced == 0)
%assign %$Proc.RegsOffset %$Proc.StackOffset
%assign %$Proc.RegsAlloced 1
%endif
%endif
%elifidn %1,flags
pushfd
%ifdef %$Proc.StackOffset
%assign %$Proc.StackOffset %$Proc.StackOffset+4
%endif
%else
push %1
%ifdef %$Proc.StackOffset
%assign %$Proc.StackOffset %$Proc.StackOffset+4
%endif
%endif
%rotate 1
%endrep
%endmacro
%macro pop 0-*.nolist
%rep %0
%ifidn %1,all
popad
%ifdef %$Proc.StackOffset
%assign %$Proc.StackOffset %$Proc.StackOffset-32
%endif
%elifidn %1,flags
popfd
%ifdef %$Proc.StackOffset
%assign %$Proc.StackOffset %$Proc.StackOffset-4
%endif
%else
pop %1
%ifdef %$Proc.StackOffset
%assign %$Proc.StackOffset %$Proc.StackOffset-4
%endif
%endif
%rotate 1
%endrep
%endmacro
The way you would use this is like this:
Proc TestProc
Param Param1, Param2, 8, Param3
Local Local1, Local2, 16
sub esp,LocalSpace$$
push all
; ... <-- do what you want here
mov eax,[Param3] ;<-- like this
mov [EAX$$],eax ; stores eax onto the stack for returning to caller
mov [EDX$$],edx ; stores edx onto the stack for returning to caller
pop all
add esp,LocalSpace$$
ret ParamCount$$
EndProc
Param and Local defaults to 4 bytes data size unless the size follows the variable being declared
LocalSpace$$ is the size of the space allocated for local variables, while ParamCount$$ is the number of bytes to pop off the stack when returning to the caller.
I tend to use all registers as much as possible, so I save all the registers upon entry and restore them all upon exit. EAX$$ and other macros are simply placeholders on the stack, so that when one does a pop all prior to returning to the caller, the return variables will be popped into their respective registers.
Sorry if this seems like a bit much, I have been working on FASM now for the past four months and have a lot of my code ported over but at this time being they use the EBP-based proc macro. I've tried many different ways to write the Proc macro for FASM but to no avail, so I am asking ya'll for help.
Thanks!
