With thanks to both "sinsi" and "HSE", I have got a system that is clean and easy to use for preserving 64 bit registers (rax to r15) in a stackframe procedure. It tests OK, it is easy to use and it is thread safe. I have used the name "USING" for the macro that allocates the stack space as it has at least some familiarity with the USES notation but is free of the RSP alteration that PUSH and POP mnemonics produce.
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
include \masm32\include64\masm64rt.inc
MLOCAL equ LOCAL ; the word LOCAL is ambiguous in a MACRO
; -------------------------------------------------------
; Register preservation macros for stack frame procedures
; -------------------------------------------------------
USING MACRO arglist:VARARG ;; Must be placed before dynamic code
MLOCAL r64@@_@@[argcount(arglist)] :QWORD
reg_64_bit_list_@@@@ equ arglist
ENDM
SaveRegs MACRO ;; must be placed AFTER LOCALs
cntr = 0
%FOR arg,<reg_64_bit_list_@@@@>
;; %echo arg
mov r64@@_@@[cntr], arg
cntr = cntr + 8
ENDM
ENDM
RestoreRegs MACRO ;; must be placed BEFORE "ret"
cntr = 0
%FOR arg,<reg_64_bit_list_@@@@>
;; %echo arg
mov arg, r64@@_@@[cntr]
cntr = cntr + 8
ENDM
ENDM
; -------------------------------------------------------
.code
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
entry_point proc
USING r12,r13,r14,r15 ; allocate local space for registers
SaveRegs ; save register list
call tstproc
waitkey
RestoreRegs ; restore register list
.exit
entry_point endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
tstproc proc
USING rax,rbx,rcx,rdx
SaveRegs
nop
nop
nop
nop
RestoreRegs
ret
tstproc endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
end