Files

158 lines
4.9 KiB
NASM

; x64 POSIX vfork continuation. The parent enters the resume/wait syscall without
; a nested userspace return frame while the child owns the caller's stack.
INCLUDE syscall_nr.inc
VF_ReturnAddress EQU 0
VF_ParentRsp EQU 8
VF_Rbx EQU 16
VF_Rbp EQU 24
VF_Rsi EQU 32
VF_Rdi EQU 40
VF_R12 EQU 48
VF_R13 EQU 56
VF_R14 EQU 64
VF_R15 EQU 72
VF_Xmm6 EQU 80
VF_Xmm7 EQU 96
VF_Xmm8 EQU 112
VF_Xmm9 EQU 128
VF_Xmm10 EQU 144
VF_Xmm11 EQU 160
VF_Xmm12 EQU 176
VF_Xmm13 EQU 192
VF_Xmm14 EQU 208
VF_Xmm15 EQU 224
VF_Mxcsr EQU 240
VF_X87Control EQU 244
VF_ThreadHandle EQU 256
VF_PreviousSuspendCount EQU 264
VF_ContextSize EQU 280
VF_LocalSize EQU 312
EXTERN PosixVforkPrepare:PROC
EXTERN PosixVforkParentFinish:PROC
.CODE
PUBLIC vfork
vfork PROC EXPORT
sub rsp, VF_LocalSize
lea r10, [rsp + 32]
mov rax, [rsp + VF_LocalSize]
mov [r10 + VF_ReturnAddress], rax
lea rax, [rsp + VF_LocalSize + 8]
mov [r10 + VF_ParentRsp], rax
mov [r10 + VF_Rbx], rbx
mov [r10 + VF_Rbp], rbp
mov [r10 + VF_Rsi], rsi
mov [r10 + VF_Rdi], rdi
mov [r10 + VF_R12], r12
mov [r10 + VF_R13], r13
mov [r10 + VF_R14], r14
mov [r10 + VF_R15], r15
movdqu xmmword ptr [r10 + VF_Xmm6], xmm6
movdqu xmmword ptr [r10 + VF_Xmm7], xmm7
movdqu xmmword ptr [r10 + VF_Xmm8], xmm8
movdqu xmmword ptr [r10 + VF_Xmm9], xmm9
movdqu xmmword ptr [r10 + VF_Xmm10], xmm10
movdqu xmmword ptr [r10 + VF_Xmm11], xmm11
movdqu xmmword ptr [r10 + VF_Xmm12], xmm12
movdqu xmmword ptr [r10 + VF_Xmm13], xmm13
movdqu xmmword ptr [r10 + VF_Xmm14], xmm14
movdqu xmmword ptr [r10 + VF_Xmm15], xmm15
stmxcsr dword ptr [r10 + VF_Mxcsr]
fnstcw word ptr [r10 + VF_X87Control]
mov rcx, r10
call PosixVforkPrepare
test rax, rax
jnz vfork_wait
add rsp, VF_LocalSize
mov eax, -1
ret
vfork_wait:
; R12 deliberately holds the heap context across the kernel wait. The child
; restores the caller's original R12 in its independent native context.
mov r12, rax
mov ecx, dword ptr [r12 + VF_ThreadHandle]
lea rdx, [r12 + VF_PreviousSuspendCount]
mov eax, SYS_RESUME_THREAD_AND_WAIT
int 02Fh
mov r9d, eax
; The child may have overwritten every byte of the old vfork/helper frames.
; Rebuild only a synthetic return frame from the heap continuation.
mov r10, r12
mov r11, [r10 + VF_ParentRsp]
mov rax, [r10 + VF_ReturnAddress]
mov rsp, r11
sub rsp, 8
mov [rsp], rax
sub rsp, 40
ldmxcsr dword ptr [r10 + VF_Mxcsr]
fldcw word ptr [r10 + VF_X87Control]
movdqu xmm6, xmmword ptr [r10 + VF_Xmm6]
movdqu xmm7, xmmword ptr [r10 + VF_Xmm7]
movdqu xmm8, xmmword ptr [r10 + VF_Xmm8]
movdqu xmm9, xmmword ptr [r10 + VF_Xmm9]
movdqu xmm10, xmmword ptr [r10 + VF_Xmm10]
movdqu xmm11, xmmword ptr [r10 + VF_Xmm11]
movdqu xmm12, xmmword ptr [r10 + VF_Xmm12]
movdqu xmm13, xmmword ptr [r10 + VF_Xmm13]
movdqu xmm14, xmmword ptr [r10 + VF_Xmm14]
movdqu xmm15, xmmword ptr [r10 + VF_Xmm15]
mov rbx, [r10 + VF_Rbx]
mov rbp, [r10 + VF_Rbp]
mov rsi, [r10 + VF_Rsi]
mov rdi, [r10 + VF_Rdi]
mov r12, [r10 + VF_R12]
mov r13, [r10 + VF_R13]
mov r14, [r10 + VF_R14]
mov r15, [r10 + VF_R15]
mov rcx, r10
mov edx, r9d
call PosixVforkParentFinish
add rsp, 40
ret
vfork ENDP
PUBLIC PosixVforkEnterChild
PosixVforkEnterChild PROC
mov r10, rcx
mov r11, [r10 + VF_ParentRsp]
mov rax, [r10 + VF_ReturnAddress]
mov rsp, r11
sub rsp, 8
mov [rsp], rax
ldmxcsr dword ptr [r10 + VF_Mxcsr]
fldcw word ptr [r10 + VF_X87Control]
movdqu xmm6, xmmword ptr [r10 + VF_Xmm6]
movdqu xmm7, xmmword ptr [r10 + VF_Xmm7]
movdqu xmm8, xmmword ptr [r10 + VF_Xmm8]
movdqu xmm9, xmmword ptr [r10 + VF_Xmm9]
movdqu xmm10, xmmword ptr [r10 + VF_Xmm10]
movdqu xmm11, xmmword ptr [r10 + VF_Xmm11]
movdqu xmm12, xmmword ptr [r10 + VF_Xmm12]
movdqu xmm13, xmmword ptr [r10 + VF_Xmm13]
movdqu xmm14, xmmword ptr [r10 + VF_Xmm14]
movdqu xmm15, xmmword ptr [r10 + VF_Xmm15]
mov rbx, [r10 + VF_Rbx]
mov rbp, [r10 + VF_Rbp]
mov rsi, [r10 + VF_Rsi]
mov rdi, [r10 + VF_Rdi]
mov r12, [r10 + VF_R12]
mov r13, [r10 + VF_R13]
mov r14, [r10 + VF_R14]
mov r15, [r10 + VF_R15]
xor eax, eax
ret
PosixVforkEnterChild ENDP
END