From 3fc23c6cbcf41762c02799aa4d212a208e18e75c Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Thu, 23 Jun 2022 05:59:57 -0700 Subject: [PATCH] Add getcontext() and setcontext() Fixes #413 --- libc/calls/getcontext.S | 79 +++++++++++++++++++++++++++++++ libc/calls/setcontext.S | 73 ++++++++++++++++++++++++++++ libc/calls/ucontext.h | 3 ++ test/libc/calls/getcontext_test.c | 49 +++++++++++++++++++ 4 files changed, 204 insertions(+) create mode 100644 libc/calls/getcontext.S create mode 100644 libc/calls/setcontext.S create mode 100644 test/libc/calls/getcontext_test.c diff --git a/libc/calls/getcontext.S b/libc/calls/getcontext.S new file mode 100644 index 000000000..b14199b58 --- /dev/null +++ b/libc/calls/getcontext.S @@ -0,0 +1,79 @@ +/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ +│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/macros.internal.h" + +// Gets machine state. +// +// @note please use longerjmp() and setlongerjmp() for fibers +// @note currently only gets general registers +// @see setcontext() +getcontext: + mov %r8,40(%rdi) + mov %r9,48(%rdi) + mov %r10,56(%rdi) + mov %r11,64(%rdi) + mov %r12,72(%rdi) + mov %r13,80(%rdi) + mov %r14,88(%rdi) + mov %r15,96(%rdi) + mov %rdi,104(%rdi) + mov %rsi,112(%rdi) + mov %rbp,120(%rdi) + mov %rbx,128(%rdi) + mov %rdx,136(%rdi) + mov %rax,144(%rdi) + mov %rcx,152(%rdi) + lea 8(%rsp),%rax + mov %rax,160(%rdi) + mov (%rsp),%rax + mov %rax,168(%rdi) + xor %eax,%eax + ret + .endfn getcontext,globl + + .end +//////////////////////////////////////////////////////////////////////////////// +noasan noubsan noinstrument int getcontext(ucontext_t *uc) { + asm volatile("mov\t%%r8,%0" : "=m"(uc->uc_mcontext.r8)); + asm volatile("mov\t%%r9,%0" : "=m"(uc->uc_mcontext.r9)); + asm volatile("mov\t%%r10,%0" : "=m"(uc->uc_mcontext.r10)); + asm volatile("mov\t%%r11,%0" : "=m"(uc->uc_mcontext.r11)); + asm volatile("mov\t%%r12,%0" : "=m"(uc->uc_mcontext.r12)); + asm volatile("mov\t%%r13,%0" : "=m"(uc->uc_mcontext.r13)); + asm volatile("mov\t%%r14,%0" : "=m"(uc->uc_mcontext.r14)); + asm volatile("mov\t%%r15,%0" : "=m"(uc->uc_mcontext.r15)); + asm volatile("mov\t%%rdi,%0" : "=m"(uc->uc_mcontext.rdi)); + asm volatile("mov\t%%rsi,%0" : "=m"(uc->uc_mcontext.rsi)); + asm volatile("mov\t%%rbp,%0" : "=m"(uc->uc_mcontext.rbp)); + asm volatile("mov\t%%rbx,%0" : "=m"(uc->uc_mcontext.rbx)); + asm volatile("mov\t%%rdx,%0" : "=m"(uc->uc_mcontext.rdx)); + asm volatile("mov\t%%rax,%0" : "=m"(uc->uc_mcontext.rax)); + asm volatile("mov\t%%rcx,%0" : "=m"(uc->uc_mcontext.rcx)); + asm volatile("lea\t8(%%rsp),%%rax\n\t" + "mov\t%%rax,%0" + : "=m"(uc->uc_mcontext.rsp) + : /* no inputs */ + : "rax"); + asm volatile("mov\t(%%rsp),%%rax\n\t" + "mov\t%%rax,%0" + : "=m"(uc->uc_mcontext.rip) + : /* no inputs */ + : "rax"); + return 0; +} diff --git a/libc/calls/setcontext.S b/libc/calls/setcontext.S new file mode 100644 index 000000000..958e8b1eb --- /dev/null +++ b/libc/calls/setcontext.S @@ -0,0 +1,73 @@ +/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ +│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/macros.internal.h" + +// Sets machine state. +// +// @note please use longerjmp() and setlongerjmp() for fibers +// @note currently only sets general registers +// @see getcontext() +setcontext: + mov 40(%rdi),%r8 + mov 48(%rdi),%r9 + mov 56(%rdi),%r10 + mov 64(%rdi),%r11 + mov 72(%rdi),%r12 + mov 80(%rdi),%r13 + mov 88(%rdi),%r14 + mov 96(%rdi),%r15 + mov 112(%rdi),%rsi + mov 120(%rdi),%rbp + mov 128(%rdi),%rbx + mov 136(%rdi),%rdx + mov 144(%rdi),%rax + mov 152(%rdi),%rcx + mov 160(%rdi),%rsp + xor %rax,%rax + push 168(%rdi) + mov 104(%rdi),%rdi + ret + .endfn setcontext,globl + + .end +//////////////////////////////////////////////////////////////////////////////// +noasan noubsan int setcontext(const ucontext_t *uc) { + asm volatile("mov\t%0,%%r8" : /* no outputs */ : "m"(uc->uc_mcontext.r8)); + asm volatile("mov\t%0,%%r9" : /* no outputs */ : "m"(uc->uc_mcontext.r9)); + asm volatile("mov\t%0,%%r10" : /* no outputs */ : "m"(uc->uc_mcontext.r10)); + asm volatile("mov\t%0,%%r11" : /* no outputs */ : "m"(uc->uc_mcontext.r11)); + asm volatile("mov\t%0,%%r12" : /* no outputs */ : "m"(uc->uc_mcontext.r12)); + asm volatile("mov\t%0,%%r13" : /* no outputs */ : "m"(uc->uc_mcontext.r13)); + asm volatile("mov\t%0,%%r14" : /* no outputs */ : "m"(uc->uc_mcontext.r14)); + asm volatile("mov\t%0,%%r15" : /* no outputs */ : "m"(uc->uc_mcontext.r15)); + asm volatile("mov\t%0,%%rsi" : /* no outputs */ : "m"(uc->uc_mcontext.rsi)); + asm volatile("mov\t%0,%%rbp" : /* no outputs */ : "m"(uc->uc_mcontext.rbp)); + asm volatile("mov\t%0,%%rbx" : /* no outputs */ : "m"(uc->uc_mcontext.rbx)); + asm volatile("mov\t%0,%%rdx" : /* no outputs */ : "m"(uc->uc_mcontext.rdx)); + asm volatile("mov\t%0,%%rax" : /* no outputs */ : "m"(uc->uc_mcontext.rax)); + asm volatile("mov\t%0,%%rcx" : /* no outputs */ : "m"(uc->uc_mcontext.rcx)); + asm volatile("mov\t%0,%%rsp" : /* no outputs */ : "m"(uc->uc_mcontext.rsp)); + asm volatile("xor\t%%rax,%%rax\n\t" + "push\t%0\n\t" + "mov\t%1,%%rdi\n\t" + "ret" + : /* no outputs */ + : "m"(uc->uc_mcontext.rip), "m"(uc->uc_mcontext.rdi)); + unreachable; +} diff --git a/libc/calls/ucontext.h b/libc/calls/ucontext.h index 24450230b..493275043 100644 --- a/libc/calls/ucontext.h +++ b/libc/calls/ucontext.h @@ -82,6 +82,9 @@ struct ucontext { typedef struct ucontext ucontext_t; +int getcontext(ucontext_t *); +int setcontext(const ucontext_t *); + COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* COSMOPOLITAN_LIBC_CALLS_UCONTEXT_H_ */ diff --git a/test/libc/calls/getcontext_test.c b/test/libc/calls/getcontext_test.c new file mode 100644 index 000000000..3a5faad0e --- /dev/null +++ b/test/libc/calls/getcontext_test.c @@ -0,0 +1,49 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" +#include "libc/calls/ucontext.h" +#include "libc/runtime/runtime.h" +#include "libc/testlib/testlib.h" + +int x; +bool ok1; +bool ok2; +ucontext_t context; + +void func(void) { + x++; + setcontext(&context); + abort(); +} + +void test(void) { + getcontext(&context); + if (!x) { + ok1 = true; + func(); + } else { + ok2 = true; + } +} + +TEST(getcontext, test) { + test(); + ASSERT_TRUE(ok1); + ASSERT_TRUE(ok2); +}