Get setcontext() and getcontext() working on Aarch64

This change also adds the missing code for getting and restoring the
thread's signal mask, since that's explicitly listed by the man page
This commit is contained in:
Justine Tunney 2023-07-01 22:42:58 -07:00
parent 8b62bff364
commit 7ec84655b4
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
7 changed files with 182 additions and 13 deletions

View file

@ -211,6 +211,12 @@ o/$(MODE)/libc/calls/pledge-linux.o: private \
-Os \ -Os \
-fPIC -fPIC
# these assembly files are safe to build on aarch64
o/$(MODE)/libc/calls/getcontext.o: libc/calls/getcontext.S
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
o/$(MODE)/libc/calls/setcontext2.o: libc/calls/setcontext2.S
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
LIBC_CALLS_LIBS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x))) LIBC_CALLS_LIBS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)))
LIBC_CALLS_SRCS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_SRCS)) LIBC_CALLS_SRCS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_SRCS))
LIBC_CALLS_HDRS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_HDRS)) LIBC_CALLS_HDRS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_HDRS))

View file

@ -22,6 +22,8 @@
// //
// @see setcontext() // @see setcontext()
getcontext: getcontext:
#ifdef __x86_64__
pushf pushf
pop 176(%rdi) pop 176(%rdi)
movaps %xmm0,480(%rdi) movaps %xmm0,480(%rdi)
@ -61,12 +63,39 @@ getcontext:
mov %rax,160(%rdi) mov %rax,160(%rdi)
mov (%rsp),%rax mov (%rsp),%rax
mov %rax,168(%rdi) mov %rax,168(%rdi)
xor %eax,%eax jmp __getcontext
ret
#elif defined(__aarch64__)
stp x0,x1,[x0,184]
stp x2,x3,[x0,200]
stp x4,x5,[x0,216]
stp x6,x7,[x0,232]
stp x8,x9,[x0,248]
stp x10,x11,[x0,264]
stp x12,x13,[x0,280]
stp x14,x15,[x0,296]
stp x16,x17,[x0,312]
stp x18,x19,[x0,328]
stp x20,x21,[x0,344]
stp x22,x23,[x0,360]
stp x24,x25,[x0,376]
stp x26,x27,[x0,392]
stp x28,x29,[x0,408]
str x30,[x0,424]
mov x1,sp
str x1,[x0,432] // sp = caller's sp
str x30,[x0,440] // pc = caller's pc
b __getcontext
#else
#error "unsupported architecture"
#endif
.endfn getcontext,globl .endfn getcontext,globl
.end .end
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
noasan noubsan dontinstrument int getcontext(ucontext_t *uc) { noasan noubsan dontinstrument int getcontext(ucontext_t *uc) {
asm volatile("movaps\t%%xmm0,%0" : /* no outputs */ : "m"(uc->__fpustate.xmm[0])); asm volatile("movaps\t%%xmm0,%0" : /* no outputs */ : "m"(uc->__fpustate.xmm[0]));
asm volatile("movaps\t%%xmm1,%0" : /* no outputs */ : "m"(uc->__fpustate.xmm[1])); asm volatile("movaps\t%%xmm1,%0" : /* no outputs */ : "m"(uc->__fpustate.xmm[1]));
@ -112,3 +141,11 @@ noasan noubsan dontinstrument int getcontext(ucontext_t *uc) {
: "rax"); : "rax");
return 0; return 0;
} }
noasan noubsan dontinstrument int getcontext(ucontext_t *uc) {
asm volatile("stp\tx0,x1,%0" : "=m"(uc->uc_mcontext.regs[0]));
asm volatile("stp\tx2,x3,%0" : "=m"(uc->uc_mcontext.regs[2]));
asm volatile("mov\tx1,sp\n\tstr\tx1,%0" : "=m"(uc->uc_mcontext.sp));
asm volatile("str\tx30,%0" : "=m"(uc->uc_mcontext.pc));
return 0;
}

34
libc/calls/getcontext2.c Normal file
View file

@ -0,0 +1,34 @@
/*-*- 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 2023 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/struct/sigset.h"
#include "libc/calls/struct/ucontext.internal.h"
#include "libc/calls/ucontext.h"
#include "libc/runtime/stack.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/consts/ss.h"
// this is tail called by the getcontext() implementation
int __getcontext(ucontext_t *uc) {
uc->uc_flags = 0;
uc->uc_link = 0;
uc->uc_stack.ss_sp = (void *)uc->uc_mcontext.SP;
uc->uc_stack.ss_flags = SS_ONSTACK;
uc->uc_stack.ss_size = uc->uc_mcontext.SP - GetStackAddr();
return sigprocmask(SIG_SETMASK, 0, &uc->uc_sigmask);
}

41
libc/calls/setcontext.c Normal file
View file

@ -0,0 +1,41 @@
/*-*- 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 2023 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/struct/sigset.h"
#include "libc/calls/struct/ucontext.internal.h"
#include "libc/calls/ucontext.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/consts/ss.h"
int __setcontext(const ucontext_t *, uintptr_t);
/**
* Sets machine context.
*
* @see getcontext()
*/
int setcontext(const ucontext_t *uc) {
uintptr_t sp;
if (sigprocmask(SIG_SETMASK, &uc->uc_sigmask, 0)) return -1;
if (uc->uc_stack.ss_flags & (SS_DISABLE | SS_ONSTACK)) {
sp = uc->uc_mcontext.SP;
} else {
sp = (uintptr_t)uc->uc_stack.ss_sp & -16;
}
return __setcontext(uc, sp);
}

View file

@ -18,10 +18,10 @@
*/ */
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
// Sets machine state. // tailed called by setcontext() implementation
// __setcontext:
// @see getcontext() #ifdef __x86_64__
setcontext:
mov 224(%rdi),%rax mov 224(%rdi),%rax
test %rax,%rax test %rax,%rax
je 1f je 1f
@ -43,6 +43,7 @@ setcontext:
movaps 400(%rax),%xmm15 movaps 400(%rax),%xmm15
1: push 176(%rdi) 1: push 176(%rdi)
popf popf
mov %rsi,%rsp
mov 40(%rdi),%r8 mov 40(%rdi),%r8
mov 48(%rdi),%r9 mov 48(%rdi),%r9
mov 56(%rdi),%r10 mov 56(%rdi),%r10
@ -57,16 +58,41 @@ setcontext:
mov 136(%rdi),%rdx mov 136(%rdi),%rdx
mov 144(%rdi),%rax mov 144(%rdi),%rax
mov 152(%rdi),%rcx mov 152(%rdi),%rcx
mov 160(%rdi),%rsp
xor %rax,%rax xor %rax,%rax
push 168(%rdi) push 168(%rdi)
mov 104(%rdi),%rdi mov 104(%rdi),%rdi
ret ret
.endfn setcontext,globl
#elif defined(__aarch64__)
mov sp,x1 // sp = second argument
ldr x30,[x0,440] // return address <- pc
ldp x28,x29,[x0,408] // x0 and x30 discarded
ldp x26,x27,[x0,392]
ldp x24,x25,[x0,376]
ldp x22,x23,[x0,360]
ldp x20,x21,[x0,344]
ldp x18,x19,[x0,328]
ldp x16,x17,[x0,312]
ldp x14,x15,[x0,296]
ldp x12,x13,[x0,280]
ldp x10,x11,[x0,264]
ldp x8,x9,[x0,248]
ldp x6,x7,[x0,232]
ldp x4,x5,[x0,216]
ldp x2,x3,[x0,200]
ldr x1,[x0,192]
mov w0,0
ret
#else
#error "unsupported architecture"
#endif
.endfn __setcontext,globl
.end .end
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
noasan noubsan int setcontext(const ucontext_t *uc) { noasan noubsan int __setcontext(const ucontext_t *uc) {
if (uc->uc_mcontext.fpregs) { if (uc->uc_mcontext.fpregs) {
asm volatile("movaps\t%0,%%xmm0" : /* no outputs */ : "m"(uc->uc_mcontext.fpregs->xmm[0])); asm volatile("movaps\t%0,%%xmm0" : /* no outputs */ : "m"(uc->uc_mcontext.fpregs->xmm[0]));
asm volatile("movaps\t%0,%%xmm1" : /* no outputs */ : "m"(uc->uc_mcontext.fpregs->xmm[1])); asm volatile("movaps\t%0,%%xmm1" : /* no outputs */ : "m"(uc->uc_mcontext.fpregs->xmm[1]));

View file

@ -5,6 +5,14 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
#ifdef __x86_64__
#define SP rsp
#elif defined(__aarch64__)
#define SP sp
#else
#error "unsupported architecture"
#endif
void _ntcontext2linux(struct ucontext *, const struct NtContext *) _Hide; void _ntcontext2linux(struct ucontext *, const struct NtContext *) _Hide;
void _ntlinux2context(struct NtContext *, const ucontext_t *) _Hide; void _ntlinux2context(struct NtContext *, const ucontext_t *) _Hide;

View file

@ -17,13 +17,13 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/struct/sigset.h"
#include "libc/calls/ucontext.h" #include "libc/calls/ucontext.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/sysv/consts/sig.h"
#include "libc/testlib/ezbench.h" #include "libc/testlib/ezbench.h"
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"
#ifdef __x86_64__
int x; int x;
bool ok1; bool ok1;
bool ok2; bool ok2;
@ -51,6 +51,25 @@ TEST(getcontext, test) {
ASSERT_TRUE(ok2); ASSERT_TRUE(ok2);
} }
TEST(getcontext, canReadAndWriteSignalMask) {
sigset_t ss, old;
volatile int n = 0;
sigemptyset(&ss);
sigaddset(&ss, SIGUSR1);
sigprocmask(SIG_SETMASK, &ss, &old);
ASSERT_EQ(0, getcontext(&context));
if (!n) {
n = 1;
ASSERT_TRUE(sigismember(&context.uc_sigmask, SIGUSR1));
sigaddset(&context.uc_sigmask, SIGUSR2);
setcontext(&context);
abort();
}
sigprocmask(SIG_SETMASK, 0, &ss);
ASSERT_TRUE(sigismember(&ss, SIGUSR2));
sigprocmask(SIG_SETMASK, &old, 0);
}
void SetGetContext(void) { void SetGetContext(void) {
static int a; static int a;
a = 0; a = 0;
@ -64,5 +83,3 @@ void SetGetContext(void) {
BENCH(getcontext, bench) { BENCH(getcontext, bench) {
EZBENCH2("get/setcontext", donothing, SetGetContext()); EZBENCH2("get/setcontext", donothing, SetGetContext());
} }
#endif /* __x86_64__ */