This file can be included to 32bit programs written in EuroAssembler.
The library contains OS-independent macroinstructions Procedure, EndProcedure, Invoke
which extend generic pseudoinstruction PROC, ENDPROC, CALL.
Macroinstructions Procedure and EndProcedure hide the prologue and epilogue of
standard call calling convention
, where the arguments are pushed backwards and they are removed by the called procedure.
All GP registers are calee-saved by the Procedure. Result value of the invokation can be returned
from procedure by copying the value to stack-variables such as %ReturnEAX, which is defined by
%StdCall32 as EBP+28.
Macroinstructions in this library comunicate at assembly time through the preprocessing %variables
%LvSize_ProcName (total size of all local stack-variables) and
%ArgC_ProcName (number of procedure parameters).
Individualization of global %variable names allows to nest procedure definitions in one another.
stdcal32 HEAD
Implementation of standard call convention in €ASM uses formal %names for accessing Procedure parameters, local stack-memory variables and all eight general-purpose registers saved on stack.
The following example shows stack-frame created by invoking Procedure with the name
MyFn which has three parameters and uses two local stack variables
named LocV1 and LocV2 with sizes 4 and 8. Prologue of MyFn Procedure Param1, Param2, Param3
will assign "global" %variables
%ArgC_MyFn %SETA 3 and %LvSize_MyFn %SETA 4+8
, they can be used in macros LocalVar,
ClearLocalVar and by epilogue in
EndProcedure MyFn during Invoke MyFn, Param1, Param2, Param3.
; Formal names assignment: %Param8 %SET EBP+64 %Param7 %SET EBP+60 %Param6 %SET EBP+56 %Param5 %SET EBP+52 %Param4 %SET EBP+48 %Param3 %SET EBP+44 %Param2 %SET EBP+40 %Param1 %SET EBP+36 %ReturnEAX %SET EBP+28 %ReturnECX %SET EBP+24 %ReturnEDX %SET EBP+20 %ReturnEBX %SET EBP+16 %ReturnESP %SET EBP+12 %ReturnEBP %SET EBP+08 %ReturnESI %SET EBP+04 %ReturnEDI %SET EBP+00
PUSHAD and
MOV EBP,ESP as the procedure prolog.
Procedure %MACRO Operands ; Prologue of standard calling convention procedure.
LblCheck %IF "%:" === ""
%ERROR ID=5921, 'Macro "Procedure" requires a label.'
%EXITMACRO Procedure
%ENDIF LblCheck
%%ArgC_%: %SETX %#
%%LvSize_%: %SETX 0
ArgNr %FOR 1..%#, STEP= +1
%%%*{%ArgNr} %SETX EBP+(32+%ArgNr*4)
%ENDFOR ArgNr
%::: PROC %=*, NESTINGCHECK=OFF
PUSHAD
MOV EBP,ESP
%ENDMACRO Procedure
EBP-4
Block LocalVar Size=1K ; %Block is now EBP-1028.
ClearLocalVar ; Fill Block and BlockSize with 0.
MOV [%BlockSize],1K, DATA=DWORD
LEA EDI,[%Block]
...
EndProcedure ProcNameSUB ESP,%Size
to reserve room on the machine stack.
%LvSize_ProcedureName which was initialized in macro Procedure.
LocalVar %MACRO Size=4
LblCheck %IF "%:" === ""
%ERROR ID=5922, 'Macro "LocalVar" requires a label.'
%EXITMACRO LocalVar
%ENDIF LblCheck
SizeCheck %IF %#
%ERROR ID=5923, 'Macro "LocalVar" does not expect ordinal parameters.'
%EXITMACRO LocalVar
%ENDIF SizeCheck
%: %COMMENT ; This makes the label of macro invocation void,
%ENDCOMMENT %: ; so it does not declare a symbol.
%ThisLvSize %SETA (%Size + 3) & ~3 ; Round up the required size to DWORD.
%GlbLvSize %SET2 %%LvSize_%^PROC+%ThisLvSize ; Accumulate total size of all LocalVar.
%%LvSize_%^PROC %SETX %GlbLvSize ; Update the "global" variable.
SUB ESP, %ThisLvSize ; Allocate room on stack.
%%%: %SETX EBP-(%GlbLvSize) ; Assign formal %name to the id specified with LocalVar label.
%ENDMACRO LocalVar
We could as well decide to initialize each local variable individually, in this case the macro ClearLocalVar will not be used in the Procedure body at all.
ESP, cleared size is specified with "global" variable
%LvSize_CurrentProcName.
ClearLocalVar %MACRO
%GlbLvSize %SET2 %%LvSize_%^PROC
%IF %GlbLvSize
MOV EDI,ESP
MOV ECX,(%GlbLvSize) / 4
XOR EAX,EAX
REP STOSD
%ENDIF
%ENDMACRO ClearLocalVar
Macro EndProcedure terminates context of the previously opened
Procedure
. This epilogue of StdCall convention will discard local variables defined with
LocalVar (using machine instruction
MOV ESP,EBP), restore all GP registers (using
POPAD) and then return to the parent code
which the Procedure was Invoked from (using RET 4*%ArgC_ProcName).
Operands pushed on stack in the Invoke statement
will be discarded here by this EndProcedure macro.
All registers are preserved throughout the procedure invocation
unless the procedure changed their stored value
on the stack frame (writing to [%ReturnEAX] for instance).
CPU flags are not preserved, EndProcedure returns
with the same flag values which were set at the
EndProcedure entry.
Programmer should never use explicit machine instructionRETto return from the block defined withProcedure .. EndProcedure. If premature return is required, jump to the label ofEndProcedurestatement instead.
Procedure statement.Invoke statement.
EndProcedure %MACRO ProcName
OpCheck %IF "%ProcName" === ""
%ERROR ID=5924, 'Macro "EndProcedure" requires one operand.'
%EXITMACRO EndProcedure
%ENDIF OpCheck
%NameStrip %SET %ProcName
%WHILE "%NameStrip[%&]" === ":"
%NameStrip %SET %NameStrip[1..%&-1] ; Get rid of trailing colons.
%ENDWHILE
%ArgC %SET2 %%ArgC_%NameStrip
NestCheck %IF "%ArgC" === ""
%ERROR ID=5925, '"%ProcName Procedure" statement missing.'
%EXITMACRO EndProcedure
%ENDIF NestCheck
MOV ESP,EBP
POPAD
RET 4 * (%ArgC)
ENDP %ProcName, NESTINGCHECK=OFF ; Terminate the namespace.
%ENDMACRO EndProcedure
Invoke %MACRO ProcName, Arguments
ArgCheck %IF "%ProcName" === ""
%ERROR ID=5926, 'Macro "Invoke" requires the name of called Procedure.'
%EXITMACRO Invoke
%ENDIF ArgCheck
ArgNr %FOR %#..2, STEP= -1
PUSHD %*{%ArgNr}
%ENDFOR ArgNr
CALL %ProcName
%ENDMACRO Invoke
ENDHEAD stdcal32