This file can be included to 64bit programs written in EuroAssembler.
The library contains macroinstructions Procedure, EndProcedure, Invoke
which extend generic (pseudo)instructions PROC, ENDPROC, CALL
in calling convention defined by
System V Application Binary Interface in AMD64 architecture
[SystemV]
, where the arguments are transferred to the function in registers. If there is no enough registers,
the remaining arguments are pushed on stack, starting with the last, and the stack is restored by the caller after return.
Machine stack is OWORD aligned before the CALL is performed.
The first 6 arguments are provided in registers RDI,RSI,RDX,RCX,R8,R9 (or in XMM0..XMM7
when they are floating-point numbers). Callee-save registers are RBX,RBP,RSP,R12..R15.
All other registers may be destroyed by the invoked function.
Such calling convention is used in Linux and Unix based operation systems.
This library implements simplified subset of System V convention, where the invoked procedure
has not more than 6 integer and 8 floating-point arguments (no argument is transferred via machine stack),
only one (scalar) FP value is transferred in the lower 32 or 64 bits of XMM.
Macros from this library cannot be used for functions which have more than 6 integer arguments,
more than 8 floating-point arguments, which require transfer in YMM or ZMM register,
which require stack alignment better than 16.
The block of code defined between macros Procedure .. EndProcedure can be called by macro Invoke or as a callback procedure from library functions.
Macro Invoke can be also used to call functions from third-party static or dynamically linked libraries. For invocation of Linux kernel functions it's necessary to use specialized macro LinABI because of differences in the register used for transfer of 4th argument and because LinABI uses SYSCALL instead of CALL.
Macro Invoke takes care of stack alignment to OWORD just before execution of instruction
CALL Function
.
The following diagram shows the stack frame created by invoking MyProc defined in the example above.
Macros of sysvcall convention will create and update the following "global" %variables at asm-time:%ArgC_MyProc %SETA 5
(number of arguments),%Uses_MyProc %SET R12,RBX
(list of used callee-saved registers),%LvSize_MyProc %SETA 8+16
(total size of local stack-variables),%LocV1 %SET RBP-24
(1st local stack variable),%LocV2 %SET RBP-40
(2nd local stack variable),
sysvcall HEAD
This macro Procedure declares simplified 64bit System V procedure prologue.
Using of the macro Procedure requires the corresponding EndProcedure
be used in the same program.
Move Procedure
in the previous example will assign
%ArgC_Move %SET 3 ; This %variable propagates to the corresponding macro EndProcedure Move
.
%Uses_Move %SET ; This %variable propagates to the macro Uses and EndProcedure.
%LvSize_Move %SETA 0 ; This %variable propagates to the macro LocalVar and EndProcedure.
Invoke Move, RSI, OutBuffer, SIZE# OutBuffer ; Example of procedure invocation.
Procedure %MACRO FormalName1, FormalName2,,,,
LblCheck %IF "%:" === ""
%ERROR ID=5921, 'Macro "Procedure" requires a label.'
%EXITMACRO Procedure
%ENDIF LblCheck
%%ArgC_%: %SETX %# ; Initialize with number of arguments.
%%Uses_%: %SETX ; Initialize as empty list.
%%LvSize_%: %SETX 0 ; Initialize as zero.
%::: PROC %=*, NESTINGCHECK=OFF ; Open the namespace and define entry symbol from macro label %:
as GLOBAL.
PUSH RBP
MOV RBP,RSP ; Initialize the frame pointer.
%ENDMACRO Procedure
Macro Uses specifies which callee-save registers does the Procedure use, so they are pushed on stack here (and they will be restored in EndProcedure epilogue).
Calling convention macros in 16bit and 32bit mode could save/restore all eight GPR with a single PUSHA/POPA. This instruction is not available in 64bit mode, so we will use this macro instead.
Macro Uses can be used in 64bit mode only, right after the statement Procedure and before local stack variables are defined with LocalVar.
Callee-save registers RBX,,R12..R15 should be enumerated here
if they are actually used in Procedure..EndProcedure block.
Callee-save registers RBP,RSP should not be mentioned here, they are always saved automatically in Procedure prologue.
It is useless to enumerate all other registers here,
because the caller of our Procedure cannot expect them to be preserved.
Registers which return the result may not be enumerated here, because they wouldn't return the expected value after their restoration.
%Uses_ProcedureName
in reversed order. This %variable will be used by EndProcedure for restoration of callee-save registers.Uses %MACRO Register1,Register2,... InProcCheck %IF "%^PROC" === "" %ERROR ID=5926,'Macro "%0" is unexpected here.' %ENDIF InProcCheck %Uses %SET2 %%Uses_%^PROC reg %FOR %* %IF REGTYPE#(%reg) = 'Q' ; General-purpose 64bit register. PUSHQ %reg %Uses %SET %reg,%Uses ; Accumulate register names in reversed order. %ELSE %ERROR ID=5927,'Macro "Uses" does not support operand "%reg".' %ENDIF %ENDFOR reg %%Uses_%^PROC %SETX %Uses %ENDMACRO Uses
Procedure..EndProcedure
block.SUB RSP,%Size
to reserve room on the machine stack.
%LvSize_ProcedureName
which was initialized in macro Procedure
and which will be used for zeroing local variables in
ClearLocalVar and for discarding local variables in
EndProcedure.RBP-8
.
BlockSize LocalVar ; %BlockSize
is now assigned with RBP-16
(8+8).
Block LocalVar Size=1024 ; %Block
is now assigned with RBP-1040
(8+8+1024).
ClearLocalVar ; Fill %Block and %BlockSize with 0.
MOV [%BlockSize],1K, DATA=QWORD
LEA RBX,[%Block]
; more instructions...
EndProcedure ProcNameLocalVar %MACRO Size=8 InProcCheck %IF "%^PROC" === "" %ERROR ID=5926,'Macro "%0" is unexpected here.' %EXITMACRO LocalVar %ENDIF InProcCheck LblCheck %IF "%:" === "" %ERROR ID=5922, 'Macro "%0" requires a label.' %EXITMACRO LocalVar %ENDIF OrdCheck %IF %# %ERROR ID=5923, 'Macro "%0" does not expect ordinal parameters.' %ENDIF %: %COMMENT ; This empty comment block makes the label of macro void, %ENDCOMMENT %: ; so it does not declare a symbol. %ThisLvSize %SETA (%Size + 7) & ~7 ; Round up to the nearest multiple of 8. %GlbLvSize %SET2 %%LvSize_%^PROC+%ThisLvSize ; Increase the total size of previously defined local variables. %%LvSize_%^PROC %SETX %GlbLvSize ; Update the "global" %variable. SUB RSP, %ThisLvSize ; Stack memory allocation. %ThisUses %SET2 %%Uses_%^PROC ; Retrieve the list of used registers. %ThisLen %SETL %ThisUses ; Number of registers pushed by macro Uses. %%%: %SETX RBP-8*%ThisLen-(%GlbLvSize) ; Assign formal %name to the id %: specified as LocalVar label. %ENDMACRO LocalVar
We could as well decide to initialize each local variable individually, e.g.
MOVQ [%MyLocalVar],0
,
and in this case the macro ClearLocalVar will not be used in the Procedure body at all.
RSP
,
its size is specified with "global" variable
%LvSize_ProcedureName
.ClearLocalVar %MACRO InProcCheck %IF "%^PROC" === "" %ERROR ID=5926,'Macro "%0" is unexpected here.' %EXITMACRO ClearLocalVar %ENDIF %GlbLvSize %SET2 %%LvSize_%^PROC %IF %GlbLvSize ; Do nothing if no LocalVar was used in this Procedure (%GlbLvSize=0). PUSH RCX,RDI LEA RDI,[RSP+2*8] ; Skip pushed RCX,RDI. MOV ECX,%GlbLvSize / 8 XOR EAX,EAX REP STOSQ POP RDI,RCX %ENDIF %ENDMACRO ClearLocalVar
Macro EndProcedure terminates context of the previously opened Procedure . This epilogue of System V convention will
MOV RSP,RBP
,POP registers
,POP RBP
and thenRET
to the parent code
which the Procedure was invoked from.Programmer should never use explicit machine instructionRET
to return from the block defined withProcedure .. EndProcedure
.
If premature return is required, jump to the label ofEndProcedure
statement instead.
Procedure
statement.Invoke
statement.EndProcedure %MACRO ProcName OpCheck %IF %# <> 1 %ERROR ID=5924, 'Macro "EndProcedure" requires one operand.' %EXITMACRO EndProcedure %ENDIF %NameStrip %SET %ProcName Decolonize %WHILE "%NameStrip[%&]" === ":" ; Get rid of trailing colon(s), if used. %NameStrip %SET %NameStrip[1..%&-1] %ENDWHILE Decolonize NestCheck %IF "%NameStrip" !=== "%^PROC" %ERROR ID=5925, 'Nesting mismatch, "%ProcName Procedure" missing.' %EXITMACRO EndProcedure %ENDIF NestCheck %GlbLvSize %SET2 %%LvSize_%^PROC %IF %GlbLvSize ADD RSP,%GlbLvSize ; Discard local variables. %ENDIF %ThisUses %SET2 %%Uses_%^PROC %IF "%ThisUses" <> "" POP %ThisUses ; Callee-save registers saved by macro Uses. %ENDIF POP RBP ; Restore caller's frame pointer. RET ; Return below Invoke which called %ProcName. ENDP %ProcName, NESTINGCHECK=OFF %ENDMACRO EndProcedure
Macro Invoke is a replacement of standard CALL instruction which can pass parameters to the Procedure in simplified System V convention .
Invoke walks through the list of arguments, starting with the first, and loads them either to
RDI,RSI,RDX,RCX,R8,R9 when they are integer, or to XMM0..XMM7 when they are floating-point.
Argument is treated as floating point when it is SIMD register or when it ends with suffix
#SS or #SD.
Stack pointer will be OWORD aligned before the CALL instruction is performed.
Epilogue of macro Invoke restores RSP to its original value.
XMM15
,RCX
,0
or -11
,GMEM_FIXED
,="Hello, world!"
or MyCallback:
.[RBP+32]
or [MyTable+RSI]
or [=Q 22.5]#SD
.#SS
or #SD
(case insensitive),
which signalizes that it represents floating-point value in Scalar Single or
Scalar Double precision format, and that it should be therefore passed to the Function in XMM register instead of GPR.
Invoke %MACRO Function, Arg1, Arg2,,, Fastmode=Yes PUSH RSP ; Store original stack pointer value (equilibrum). TEST SPL,1000b ; Test stack OWORD alignment at run-time. FaEv %IF %# & 1b ; If the number of Function arguments is 0,2,4,6,8,10,,(even), JZ .Invoke%.: ; store 2nd copy of equilibrum when RSP is OWORD-unaligned. %ELSE FaEv ; If the number of arguments is 1,3,5,7,9,11,,, (odd), JNZ .Invoke%.: ; store 2nd copy of equilibrum when RSP is OWORD-aligned. %ENDIF FaEv PUSH RSP ; Store and update 2nd copy of original RSP (equilibrum). ADDQ [RSP],8 ; Those two instructions aren't executed if RSP was properly aligned. .Invoke%.: %GPR %SET RDI,RSI,RDX,RCX,R8,R9 ; Enumerate registers for transfer of integer|pointer values. %SIMD %SET XMM0,XMM1,XMM2,XMM3, \ ; Enumerate registers for transfer of floating-point values. XMM4,XMM5,XMM6,XMM7 %ArgNr %SETA 2 ; Start with the 2nd operand, i.e. the 1st Function argument. Arg %WHILE %ArgNr <= %# %Arg %SET %*{%ArgNr} ; Transfer all Function arguments, start with the first one. %suffix %SET Q ; %suffix of MOV will be Q, SS or SD (MOVQ, MOVSS or MOVSD). %IF '%Arg[%&-2..%&-1]'=='#S' ; If suffix #SS or #SD is present in argument notation, %suffix %SET %Arg[%&-1..%&] ; let %suffix be SS or SD %Arg %SET %Arg[1..%&-3] ; and remove it from the argument. %ENDIF ; %Arg may be GPR,SIMD,imm@abs,ptr@rel,[mem@abs],[mem@rel]. FaSc %IF TYPE#(SEGMENT#(%Arg)) = 'N' ; %Arg is not relocatable (scalar). It can be GPR,SIMD,imm@abs,[mem@abs]. FaScRg %IF TYPE#(%Arg) = 'R' ; %Arg is a GP or SIMD register. FaScRgXm %IF REGTYPE#(%Arg) = 'X' %IF "%SIMD{1}" !== "%Arg" ; %Arg is XMM. Skip when it's already there. MOV%suffix %SIMD{1},%Arg ; Copy SIMD %Arg to the first available SIMD (XMM0..XMM7). %SIMD %SET %SIMD{2..} ; Remove the used register from the list. %ENDIF %ELSE FaScRgXm ; %Arg is GPR. %IF "%GPR{1}" !== "%Arg" ; Skip when it's already there. MOV %GPR{1},%Arg ; Copy GPR to the first available GPR from the list RDI,RSI,RDX,RCX,R8,R9. %GPR %SET %GPR{2..} ; Remove the used register from the list. %ENDIF %ENDIF FaScRgXm %ELSE FaScRg ; %Arg is scalar immediate or [mem], e.g. 1 or [RBP+16]. FaScIm %IF '%suffix' === 'Q' MOV %GPR{1},%Arg ; %Arg is integer value. %GPR %SET %GPR{2..} ; Remove the used register from the list. %ELSE FaScIm MOV%suffix %SIMD{1},%Arg ; %Arg is FP value, e g. [RSI]. %SIMD %SET %SIMD{2..} ; Remove the used register from the list. %ENDIF FaScIm %ENDIF FaScRg %ELSE FaSc ; %Arg is relocatable (vector), e.g. Symbol or [Symbol+RSI]. FaVeM %IF '%Arg[1]' === '[' ; Argument is passed by value, via this GPR. LEA %GPR{1},%Arg MOV %GPR{1},[%GPR{1}] ; Dereference the argument value, transfer the value. %GPR %SET %GPR{2..} ; Remove the used register from the list. %ELSE FaVeM ; Argument is passed by reference, e.g. Symbol. LEA %GPR{1},[%Arg] ; Transfer the pointer. %GPR %SET %GPR{2..} ; Remove the used register from the list. %ENDIF FaVeM %ENDIF FaSc %ArgNr %SETA %ArgNr + 1 ; The next argument. %ENDWHILE Arg CALL %Function ; Call the function. POP RSP ; Restore RSP to equilibrum from 1st or 2nd copy. %ENDMACRO Invoke
ENDHEAD sysvcall