Last active
May 3, 2024 16:58
-
-
Save ookiineko/3b50874d1d783fcaa4a42a8f91d23f6e to your computer and use it in GitHub Desktop.
trying to implement vfork(2) for MinGW
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* DISCLAIMER | |
* This file has no copyright assigned and is placed in the Public Domain. | |
* This file is part of the mingw-w64 runtime package. | |
* | |
* The mingw-w64 runtime package and its code is distributed in the hope that it | |
* will be useful but WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESSED OR | |
* IMPLIED ARE HEREBY DISCLAIMED. This includes but is not limited to | |
* warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
*/ | |
#ifdef __i386__ | |
# define __vfork_longjmp __vfork_longjmp | |
#endif | |
.globl __vfork_longjmp | |
.def __vfork_longjmp; .scl 2; .type 32; .endef | |
__vfork_longjmp: | |
#ifdef __i386__ | |
movl 4(%esp), %ecx | |
movl 8(%esp), %eax /* retval */ | |
movl 0(%ecx), %ebp /* Ebp */ | |
movl 4(%ecx), %ebx /* Ebx */ | |
movl 8(%ecx), %edi /* Edi */ | |
movl 12(%ecx), %esi /* Esi */ | |
movl 16(%ecx), %esp /* Esp */ | |
addl $4, %esp /* get rid of return address */ | |
jmp *20(%ecx) /* Eip */ | |
#elif defined(__x86_64__) | |
movq %rdx, %rax /* retval */ | |
movq 0x8(%rcx), %rbx /* Rbx */ | |
movq 0x18(%rcx), %rbp /* Rbp */ | |
movq 0x20(%rcx), %rsi /* Rsi */ | |
movq 0x28(%rcx), %rdi /* Rdi */ | |
movq 0x30(%rcx), %r12 /* R12 */ | |
movq 0x38(%rcx), %r13 /* R13 */ | |
movq 0x40(%rcx), %r14 /* R14 */ | |
movq 0x48(%rcx), %r15 /* R15 */ | |
ldmxcsr 0x58(%rcx) /* MxCsr */ | |
fnclex | |
fldcw 0x5c(%rcx) /* FpCsr */ | |
movdqa 0x60(%rcx), %xmm6 /* Xmm6 */ | |
movdqa 0x70(%rcx), %xmm7 /* Xmm7 */ | |
movdqa 0x80(%rcx), %xmm8 /* Xmm8 */ | |
movdqa 0x90(%rcx), %xmm9 /* Xmm9 */ | |
movdqa 0xa0(%rcx), %xmm10 /* Xmm10 */ | |
movdqa 0xb0(%rcx), %xmm11 /* Xmm11 */ | |
movdqa 0xc0(%rcx), %xmm12 /* Xmm12 */ | |
movdqa 0xd0(%rcx), %xmm13 /* Xmm13 */ | |
movdqa 0xe0(%rcx), %xmm14 /* Xmm14 */ | |
movdqa 0xf0(%rcx), %xmm15 /* Xmm15 */ | |
movq 0x50(%rcx), %rdx /* Rip */ | |
movq 0x10(%rcx), %rsp /* Rsp */ | |
jmp *%rdx | |
#elif defined(__arm__) | |
ldr r4, [r0, #0x4] /* R4 */ | |
ldr r5, [r0, #0x8] /* R5 */ | |
ldr r6, [r0, #0xc] /* R6 */ | |
ldr r7, [r0, #0x10] /* R7 */ | |
ldr r8, [r0, #0x14] /* R8 */ | |
ldr r9, [r0, #0x18] /* R9 */ | |
ldr r10, [r0, #0x1c] /* R10 */ | |
ldr r11, [r0, #0x20] /* R11 */ | |
ldr sp, [r0, #0x24] /* Sp */ | |
ldr r2, [r0, #0x28] /* Pc */ | |
ldr r3, [r0, #0x2c] /* Fpscr */ | |
vmsr fpscr, r3 | |
vldr d8, [r0, #0x30] /* D[0] */ | |
vldr d9, [r0, #0x38] /* D[1] */ | |
vldr d10, [r0, #0x40] /* D[2] */ | |
vldr d11, [r0, #0x48] /* D[3] */ | |
vldr d12, [r0, #0x50] /* D[4] */ | |
vldr d13, [r0, #0x58] /* D[5] */ | |
vldr d14, [r0, #0x60] /* D[6] */ | |
vldr d15, [r0, #0x68] /* D[7] */ | |
mov r0, r1 /* retval */ | |
bx r2 | |
#elif defined(__aarch64__) | |
ldp x19, x20, [x0, #0x10] /* X19, X20 */ | |
ldp x21, x22, [x0, #0x20] /* X21, X22 */ | |
ldp x23, x24, [x0, #0x30] /* X23, X24 */ | |
ldp x25, x26, [x0, #0x40] /* X25, X26 */ | |
ldp x27, x28, [x0, #0x50] /* X27, X28 */ | |
ldp x29, x30, [x0, #0x60] /* Fp, Lr */ | |
ldr x2, [x0, #0x70] /* Sp */ | |
mov sp, x2 | |
ldr w2, [x0, #0x78] /* Fpcr */ | |
msr fpcr, x2 | |
ldr w2, [x0, #0x7c] /* Fpsr */ | |
msr fpsr, x2 | |
ldp d8, d9, [x0, #0x80] /* D[0-1] */ | |
ldp d10, d11, [x0, #0x90] /* D[2-3] */ | |
ldp d12, d13, [x0, #0xa0] /* D[4-5] */ | |
ldp d14, d15, [x0, #0xb0] /* D[6-7] */ | |
mov x0, x1 /* retval */ | |
ret | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* DISCLAIMER | |
* This file has no copyright assigned and is placed in the Public Domain. | |
* This file is part of the mingw-w64 runtime package. | |
* | |
* The mingw-w64 runtime package and its code is distributed in the hope that it | |
* will be useful but WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESSED OR | |
* IMPLIED ARE HEREBY DISCLAIMED. This includes but is not limited to | |
* warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
*/ | |
#ifndef __VFORK___SETJMP_H__ | |
#define __VFORK___SETJMP_H__ | |
typedef | |
#ifdef __i386__ | |
int | |
_vfork_jmp_buf[16]; | |
#elif defined(__x86_64__) | |
__attribute__((__aligned__(16))) unsigned long long | |
__vfork_jmp_buf[32]; | |
#elif defined(__arm__) | |
int | |
__vfork_jmp_buf[28]; | |
#elif defined(__aarch64__) | |
unsigned long long | |
__vfork_jmp_buf[24]; | |
#endif | |
int __cdecl __attribute__((__nothrow__,__returns_twice__)) | |
__vfork_setjmp (__vfork_jmp_buf buf); | |
void __attribute__((__nothrow__,__noreturn__)) | |
__vfork_longjmp (__vfork_jmp_buf buf, int ret); | |
#endif /* __VFORK___SETJMP_H__ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* DISCLAIMER | |
* This file has no copyright assigned and is placed in the Public Domain. | |
* This file is part of the mingw-w64 runtime package. | |
* | |
* The mingw-w64 runtime package and its code is distributed in the hope that it | |
* will be useful but WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESSED OR | |
* IMPLIED ARE HEREBY DISCLAIMED. This includes but is not limited to | |
* warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
*/ | |
#ifdef __i386__ | |
# define __vfork_setjmp __vfork_setjmp | |
#endif | |
.globl __vfork_setjmp | |
.def __vfork_setjmp; .scl 2; .type 32; .endef | |
__vfork_setjmp: | |
#ifdef __i386__ | |
movl 4(%esp), %ecx | |
movl %ebp, 0(%ecx) /* Ebp */ | |
movl %ebx, 4(%ecx) /* Ebx */ | |
movl %edi, 8(%ecx) /* Edi */ | |
movl %esi, 12(%ecx) /* Esi */ | |
movl %esp, 16(%ecx) /* Esp */ | |
movl 0(%esp), %eax | |
movl %eax, 20(%ecx) /* Eip */ | |
xorl %eax, %eax | |
retl | |
#elif defined(__x86_64__) | |
xorq %rdx, %rdx | |
movq %rdx, (%rcx) /* Frame */ | |
movq %rbx, 0x8(%rcx) /* Rbx */ | |
leaq 0x8(%rsp), %rax | |
movq %rax, 0x10(%rcx) /* Rsp */ | |
movq %rbp, 0x18(%rcx) /* Rbp */ | |
movq %rsi, 0x20(%rcx) /* Rsi */ | |
movq %rdi, 0x28(%rcx) /* Rdi */ | |
movq %r12, 0x30(%rcx) /* R12 */ | |
movq %r13, 0x38(%rcx) /* R13 */ | |
movq %r14, 0x40(%rcx) /* R14 */ | |
movq %r15, 0x48(%rcx) /* R15 */ | |
movq (%rsp), %rax | |
movq %rax, 0x50(%rcx) /* Rip */ | |
stmxcsr 0x58(%rcx) /* MxCsr */ | |
fnstcw 0x5c(%rcx) /* FpCsr */ | |
movdqa %xmm6, 0x60(%rcx) /* Xmm6 */ | |
movdqa %xmm7, 0x70(%rcx) /* Xmm7 */ | |
movdqa %xmm8, 0x80(%rcx) /* Xmm8 */ | |
movdqa %xmm9, 0x90(%rcx) /* Xmm9 */ | |
movdqa %xmm10, 0xa0(%rcx) /* Xmm10 */ | |
movdqa %xmm11, 0xb0(%rcx) /* Xmm11 */ | |
movdqa %xmm12, 0xc0(%rcx) /* Xmm12 */ | |
movdqa %xmm13, 0xd0(%rcx) /* Xmm13 */ | |
movdqa %xmm14, 0xe0(%rcx) /* Xmm14 */ | |
movdqa %xmm15, 0xf0(%rcx) /* Xmm15 */ | |
xorq %rax, %rax | |
retq | |
#elif defined(__arm__) | |
mov r1, #0 | |
str r1, [r0] /* Frame */ | |
str r4, [r0, #0x4] /* R4 */ | |
str r5, [r0, #0x8] /* R5 */ | |
str r6, [r0, #0xc] /* R6 */ | |
str r7, [r0, #0x10] /* R7 */ | |
str r8, [r0, #0x14] /* R8 */ | |
str r9, [r0, #0x18] /* R9 */ | |
str r10, [r0, #0x1c] /* R10 */ | |
str r11, [r0, #0x20] /* R11 */ | |
str sp, [r0, #0x24] /* Sp */ | |
str lr, [r0, #0x28] /* Pc */ | |
vmrs r2, fpscr | |
str r2, [r0, #0x2c] /* Fpscr */ | |
vstr d8, [r0, #0x30] /* D[0] */ | |
vstr d9, [r0, #0x38] /* D[1] */ | |
vstr d10, [r0, #0x40] /* D[2] */ | |
vstr d11, [r0, #0x48] /* D[3] */ | |
vstr d12, [r0, #0x50] /* D[4] */ | |
vstr d13, [r0, #0x58] /* D[5] */ | |
vstr d14, [r0, #0x60] /* D[6] */ | |
vstr d15, [r0, #0x68] /* D[7] */ | |
mov r0, #0 | |
bx lr | |
#elif defined(__aarch64__) | |
str xzr, [x0] /* Frame */ | |
stp x19, x20, [x0, #0x10] /* X19, X20 */ | |
stp x21, x22, [x0, #0x20] /* X21, X22 */ | |
stp x23, x24, [x0, #0x30] /* X23, X24 */ | |
stp x25, x26, [x0, #0x40] /* X25, X26 */ | |
stp x27, x28, [x0, #0x50] /* X27, X28 */ | |
stp x29, x30, [x0, #0x60] /* Fp, Lr */ | |
mov x2, sp | |
str x2, [x0, #0x70] /* Sp */ | |
mrs x2, fpcr | |
str w2, [x0, #0x78] /* Fpcr */ | |
mrs x2, fpsr | |
str w2, [x0, #0x7c] /* Fpsr */ | |
stp d8, d9, [x0, #0x80] /* D[0-1] */ | |
stp d10, d11, [x0, #0x90] /* D[2-3] */ | |
stp d12, d13, [x0, #0xa0] /* D[4-5] */ | |
stp d14, d15, [x0, #0xb0] /* D[6-7] */ | |
mov x0, #0 | |
ret | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <assert.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include "_vfork_setjmp.h" | |
#ifdef __x86_64__ | |
# define FUNCTION_PREAMBLE_SIZE (0x10) | |
#endif | |
static __thread struct | |
{ | |
__vfork_jmp_buf buf; | |
#define _vfork_buf _vfork_info.buf | |
int in_progress; | |
#define _is_vfork _vfork_info.in_progress | |
void *frame; | |
#define _vfork_frame _vfork_info.frame | |
char *sp; | |
#define _vfork_sp _vfork_info.sp | |
char *bp; | |
#define _vfork_bp _vfork_info.bp | |
#define _vfork_frame_size \ | |
(_vfork_bp - _vfork_sp + FUNCTION_PREAMBLE_SIZE) | |
} _vfork_info; | |
static inline int | |
_vfork_save_frame (void) | |
{ | |
if (!(_vfork_frame = malloc (_vfork_frame_size))) | |
return -1; | |
memcpy (_vfork_frame, _vfork_sp, _vfork_frame_size); | |
return 0; | |
} | |
__attribute__((__noinline__)) static void | |
_vfork_restore_frame (void) | |
{ | |
memcpy (_vfork_sp, _vfork_frame, _vfork_frame_size); | |
free (_vfork_frame); | |
} | |
__attribute__((__noinline__,__returns_twice__)) int | |
vfork (void) | |
{ | |
if (!__vfork_setjmp (_vfork_buf)) | |
{ | |
// initial call from parent; | |
// save current stack frame | |
#ifdef __x86_64__ | |
__asm__ volatile ("movq %%rsp, %0\n" : "=r"(_vfork_sp)); | |
#endif | |
_vfork_bp = __builtin_frame_address(0); | |
if (_vfork_save_frame () < 0) | |
return -1; | |
_is_vfork = 1; | |
// parent act as child | |
return 0; | |
} | |
else | |
{ | |
// child exited, or called exec(3) | |
_vfork_restore_frame (); | |
_is_vfork = 0; | |
// back to normal parent | |
return 1; // fake pid for demo | |
} | |
} | |
__attribute__((__noreturn__)) static inline void | |
_vfork_end (void) | |
{ | |
__vfork_longjmp (_vfork_buf, 1); | |
// unreachable | |
assert (0); | |
} | |
__attribute__((__noreturn__)) void | |
umixw32_exec_demo (void) | |
{ | |
if (_is_vfork) | |
{ | |
// our own exec(3) substitute | |
printf ("pretend to spawn a process\n"); | |
// exec should never return | |
// now we should be back to parent | |
_vfork_end (); | |
// unreachable | |
assert (0); | |
} | |
else | |
{ | |
// XXX: call the original mingw exec(3) here | |
// omitted for demo | |
for (;;); | |
} | |
} | |
int | |
main () | |
{ | |
int pid; | |
printf ("before vfork\n"); | |
pid = vfork (); | |
if (pid < 0) | |
{ | |
perror ("vfork"); | |
return 1; | |
} | |
else if (pid == 0) | |
{ | |
// in child | |
// Linux manpage say u can only either exec(3) or _exit(3) | |
umixw32_exec_demo (); | |
// unreachable | |
assert (0); | |
} | |
else | |
printf ("in parent\n"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment