Hello Andrey, there is a way but not much elegant and I had to omit MASM directives for SEH (Structured Exception Handling) which are not supported by €ASM:
;-------------------------------------------------------------------------
; Description: The following macro generates code that creates a stack
; frame for x86-64 functions.
; Macro Parameters: %1 Prefix Macro symbolic name prefix
; %2 StkSizeLocal1 Size in bytes for local1 vars
; %3 StkSizeLocal2 Size in bytes for XMM reg save area
; %4..%10 Rnv1 - Rnv7 Non-volatile registers to save
_CreateFrame %MACRO Prefix,StkSizeLocal1,StkSizeLocal2,Rnv1,Rnv2,Rnv3,Rnv4,Rnv5,Rnv6,Rnv7
%IF %StkSizeLocal1 \ 16 ; Make sure stack sizes are valid
%ERROR Macro parameter %StkSizeLocal1 must be evenly divisible by 16.
%ENDIF
%IF %StkSizeLocal2 \ 16
%ERROR Macro parameter %StkSizeLocal2 must be evenly divisible by 16.
%ENDIF
%IF %StkSizeLocal2 > 240
%ERROR Macro parameter %StkSizeLocal2 must be less than or equal to 240.
%ENDIF
PUSH RBP ; Push previous frame pointer.
%GPRtoPush %SET ; Make the list of GPR-to-save empty.
%GPRtoPop %SET ; Make the list of GPR-to-restore empty.
ArgNr %FOR 4..10 ; FOR-loop thru 4-th and further macro argument.
%GPR %SET2 %%Rnv%ArgNr
%IF %GPR ; If ArgNr-th argument is specified.
%GPRtoPush %SET %GPRtoPush,%GPR ; Populate the list of registers to save.
%GPRtoPop %SET %GPR,%GPRtoPop ; Populate the list in inversed order.
%ENDIF
%ENDFOR ArgNr
%NumPushReg %SETL %GPRtoPop
%NumPushReg %SETA %NumPushReg + 1 ; Increment because RBP was already pushed.
%IF %NumPushReg > 1
PUSH %GPRtoPush ; Push all specified non-volatile registers specified on the list.
%ENDIF
%StackPad %SETA ((%NumPushReg & 1) ^ 1) * 8 ; Zero when there are no other GPR than RBP.
%StackSizeTotal %SETA %StkSizeLocal1+%StkSizeLocal2+%StackPad
SUB RSP,%StackSizeTotal
%IF %StkSizeLocal2 > 0
LEA RBP,[RSP+%StkSizeLocal2]
%ELSE
MOV RBP,RSP
%ENDIF
; Create the symbols for current function
%Prefix{}StackSizeTotal EQU %StackSizeTotal
%Prefix{}StackSizeLocal1 EQU %StkSizeLocal1
%Prefix{}StackSizeLocal2 EQU %StkSizeLocal2
%Prefix{}OffsetHomeRCX EQU %StkSizeLocal1+%NumPushReg*8+%StackPad+8
%Prefix{}OffsetHomeRDX EQU %StkSizeLocal1+%NumPushReg*8+%StackPad+16
%Prefix{}OffsetHomeR8 EQU %StkSizeLocal1+%NumPushReg*8+%StackPad+24
%Prefix{}OffsetHomeR9 EQU %StkSizeLocal1+%NumPushReg*8+%StackPad+32
%Prefix{}OffsetStaclArgs EQU %StkSizeLocal1+%NumPushReg*8+%StackPad+40
%ValNameOffsetSaveXmmRegs %SET %Prefix{}OffsetSaveXmmRegs
%Prefix{}OffsetSaveXmmRegs EQU %StkSizeLocal2
%ValNameOffsetDeleteFrame %SET %Prefix{}OffsetDeleteFrame
%Prefix{}OffsetDeleteFrame EQU %StkSizeLocal1+%StackPad
%ENDMACRO _CreateFrame
;-------------------------------------------------------------------------
; Description: The following macro generates code that de-allocate a
; stack frame previously created using _CreateFrame.
; Macro Parameters: Rnv1 - Rnv7 Non-volatile registers to restore
_DeleteFrame %MACRO Rnv1,Rnv2,,,
%IF (%ValNameOffsetDeleteFrame > 0)
LEA RSP,[RBP+%ValNameOffsetDeleteFrame]
%ELSE
MOV RSP,RBP
%ENDIF
%IF %GPRtoPop ; List of Rnv7..Rnv1, if any.
POP %GPRtoPop ; Restore all pushed registers at once.
%ENDIF
POP RBP
%ENDMACRO _DeleteFrame
;-------------------------------------------------------------------------
; Description: The following macro generates code that saves the
; specified non-volatile registers to the local save area.
; Macro Parameters: Rnv1 - Rnv7 Non-volatile XMM registers to save.
_SaveXmmRegs %MACRO Rnv0,Rnv1,Rnv2,Rnv3,Rnv4,Rnv5,Rnv6,Rnv7,Rnv8,Rnv9
%position %SETA 0 ; Position of XMM register stored in Local2 (0,16,32..)
reg %FOR %* ; Repeat the %FOR block with all arguments.
VMOVDQA [RBP-%ValNameOffsetSaveXmmRegs+%position],%reg
%position %SETA %position+16
%ENDFOR reg
%ENDMACRO _SaveXmmRegs
;-------------------------------------------------------------------------
; Description: The following macro generates code that restores the
; specified non-volatile registers from the local save area.
; Macro Parameters: Rnv1 - Rnv7 Non-volatile XMM registers to restore.
;-------------------------------------------------------------------------
_RestoreXmmRegs %MACRO Rnv0,Rnv1,Rnv2,Rnv3,Rnv4,Rnv5,Rnv6,Rnv7,Rnv8,Rnv9
%position %SETA 0 ; Position of XMM register stored in Local2 (0,8,16,24..)
reg %FOR %* ; Repeat the %FOR block with all arguments.
VMOVDQA %reg,[RBP-%ValNameOffsetSaveXmmRegs+%position]
%position %SETA %position+16
%ENDFOR reg
%ENDMACRO _RestoreXmmRegs
;-------------------------------------------------------------------------
; A simple program to test the macros defined above.
EUROASM CPU=X64,SIMD=AVX, NoWarn=2101
; EUROASM ListRepeat=yes,ListMacro=yes,ListVar=yes ; Only if you want to debug the listing.
Andrey PROGRAM Format=DLL,Width=64
EXPORT ConvertImgU8ToF32_
ConvertImgU8ToF32_ PROC
_CreateFrame U2F_,0,160
_SaveXmmRegs xmm6,xmm7,xmm8,xmm9,xmm10,xmm11,xmm12,xmm13,xmm14,xmm15
NOP ; Here should be inserted instructions from the procedure ConvertImgU8ToF32_
NOP ; https://github.com/Apress/modern-x86-as ... 07_06_.asm
Done: _RestoreXmmRegs xmm6,xmm7,xmm8,xmm9,xmm10,xmm11,xmm12,xmm13,xmm14,xmm15
_DeleteFrame
RET
ENDP ConvertImgU8ToF32_
; %Display UserVariables, Symbols ; Only if you want to debug the listing.
ENDPROGRAM
If you want it more elegant, use macros from
https://euroassembler.eu/maclib/fastcall.htm
Uses saves and restores the enumerated GPR and XMM registers (unfortunately only the low half of XMM)
However, you can reserve space on stack for save/restore XMMs with
LocalVar and you won't need the complex MASM frame machinery. Something like
EUROASM CPU=X64,SIMD=AVX, NoWarn=2101
; EUROASM ListRepeat=yes,ListMacro=yes,ListVar=yes ; Only if you want to debug the listing.
Elegant PROGRAM Format=DLL,Width=64
INCLUDE "fastcall.htm"
EXPORT ConvertImgU8ToF32_
ConvertImgU8ToF32_ Procedure des, src, num_pixels
Uses RSI,RDI ; GPR which shouldn't be clobbered in the procedure.
; The number of enumerated GPRs should be even to keep 16byte alignment of the following local stack variables.
SavedXMM10 LocalVar Size=16
SavedXMM11 LocalVar Size=16
SavedXMM12 LocalVar Size=16 ; etc.
VMOVDQA [%SavedXMM10],XMM10 ; Manually store XMMs which should't be clobbered.
VMOVDQA [%SavedXMM11],XMM11
VMOVDQA [%SavedXMM12],XMM12 ; etc.
; Make sure num_pixels is valid and pixel buffers are properly aligned
xor eax,eax ;set error return code
; Here should be instructions from the original procedure ConvertImgU8ToF32_
mov eax,1 ;set success return code
Done:
VMOVDQA XMM12,[%SavedXMM12] ; Manually restore XMMs which should't be clobbered.
VMOVDQA XMM11,[%SavedXMM11]
VMOVDQA XMM10,[%SavedXMM10] ; etc.
EndProcedure ConvertImgU8ToF32_
ENDPROGRAM