Saving the volatile registers

Started by Vortex, May 01, 2025, 09:33:52 PM

Previous topic - Next topic

Vortex

Hello,

Here is a macro to save rcx,rdx,r8 and r9 to protect them across API function calls.

include SaveRegs.inc

SaveRegs MACRO

    LOCAL_rcx TEXTEQU <LOCAL _rcx:QWORD>
    LOCAL_rdx TEXTEQU <LOCAL _rdx:QWORD>
    LOCAL_r8  TEXTEQU <LOCAL _r8:QWORD>
    LOCAL_r9  TEXTEQU <LOCAL _r9:QWORD>

    LOCAL_rcx
    LOCAL_rdx
    LOCAL_r8
    LOCAL_r9

    mov _rcx,rcx
    mov _rdx,rdx
    mov _r8,r8
    mov _r9,r9

ENDM

.data

msg    db 'Hello!',0
msg2    db 'rcx,rdx,r8 and r9 are saved.',0
title  db 'MsgBox',0
title2  db 'Macro test',0

.code

start:

    sub    rsp,8+4*8
    invoke  main,ADDR msg2,ADDR title2

    invoke  ExitProcess,0

main PROC x:QWORD,y:QWORD PARMAREA=4*SIZEOF QWORD

    SaveRegs

    invoke  MessageBox,0,ADDR msg,ADDR title,0
   
;  The first call to MessageBox destroys rcx,rdx,r8 and r9

    invoke  MessageBox,0,_rcx,_rdx,0
   
    invoke  ExitProcess,0

main ENDP

END start
Code it... That's all...

Quin

Cool stuff, thanks Vortex! Works here with latest Poasm :)
Use the assembly, Luke.

Vortex

#2
Hi Quin,

Thanks for your test. This modified version where the non-volatile registers are preserved works as expected :

main PROC uses rsi rdi rbx x:QWORD,y:QWORD PARMAREA=4*SIZEOF QWORD

    SaveRegs

    xor    rsi,rsi
    mov    rdi,1
    mov    rbx,2

    invoke  MessageBox,0,ADDR msg,ADDR title,0
   
;  The first call to MessageBox destroys rcx,rdx,r8 and r9

    invoke  MessageBox,0,_rcx,_rdx,0
   
    ret

main ENDP
Code it... That's all...

Vortex

Here is another attempt :

include SaveRegs.inc

SaveRegs MACRO

    mov     QWORD PTR [rbx],rcx
    mov     QWORD PTR [rbx+8],rdx
    mov     QWORD PTR [rbx+16],r8
    mov     QWORD PTR [rbx+24],r9

ENDM

.data

msg     db 'Hello!',0
msg2    db 'rcx,rdx,r8 and r9 are saved.',0
title   db 'MsgBox',0
title2  db 'Macro test',0

.data?

mainRsp dq ?

.code

start:

    sub     rsp,8+4*8

    push    rsp
    pop     mainRsp

    invoke  main,ADDR msg2,ADDR title2,10,20

    invoke  ExitProcess,0

main PROC uses rsi rdi rbx x:QWORD,y:QWORD,w:QWORD,z:QWORD PARMAREA=4*SIZEOF QWORD

    LOCAL   temp1:QWORD

    mov     rbx,mainRsp
    SaveRegs

    xor     rsi,rsi
    mov     rdi,1

    invoke  MessageBox,0,ADDR msg,ADDR title,0
   
;   The first call to MessageBox destroys rcx,rdx,r8 and r9

    invoke  MessageBox,0,[rbx],[rbx+8],0
   
    ret

main ENDP

END start
Code it... That's all...

TimoVJL

May the source be with you

Vortex

Here is how to get the stack allocated by a Poasm procedure. The task is to get the allocation from the statement add rsp,X before ret :

include RegsToShadSpace.inc

.data

msg     db 'Hello!',0
msg2    db 'rcx,rdx,r8 and r9 are saved.',0
title   db 'MsgBox',0
title2  db 'Macro test',0

.data?

mainRsp dq ?

.code

start PROC PARMAREA=5*SIZEOF QWORD

    invoke  main,ADDR msg2,ADDR title2,10,20,30

    invoke  ExitProcess,0
    ret

start ENDP

main PROC a1:QWORD,a2:QWORD,a3:QWORD,a4:QWORD,a5:QWORD PARMAREA=4*SIZEOF QWORD

    LOCAL  temp1:QWORD
    LOCAL  temp2:QWORD
    LOCAL  temp3:QWORD

    mov    temp1,1
    mov    temp2,2

    mov     rax,-1

;   How     the stack release instructions are encoded?
;   Example :

;   add     rsp, 88   ; 48: 83. C4, 58
;   add     rsp, 136  ; 48: 81. C4, 00000088

    mov     r10,OFFSET StackReservation
    cmp     WORD PTR [r10],08348h
    jne     l1

    movzx   rax,BYTE PTR [r10+3]
    jmp     l3

l1:

    mov     eax,DWORD PTR [r10+3]

l3:
    lea     rax,[rsp+rax+8]
    mov     temp3,rax
    mov     QWORD PTR [rax],a1
    mov     QWORD PTR [rax+8],a2
    mov     QWORD PTR [rax+16],a3
    mov     QWORD PTR [rax+24],a4   

;   MessageBox destroying parameters a1,a2,a3 and a4

    invoke  MessageBox,0,ADDR msg,ADDR title,0

;   Retrieve the volatile registers from the shadow space

    mov     r10,temp3
    invoke  MessageBox,0,[r10],[r10+8],0

StackReservation:   

    ret

main ENDP

END start
Code it... That's all...