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 \
-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_SRCS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_SRCS))
LIBC_CALLS_HDRS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_HDRS))

View file

@ -22,6 +22,8 @@
//
// @see setcontext()
getcontext:
#ifdef __x86_64__
pushf
pop 176(%rdi)
movaps %xmm0,480(%rdi)
@ -61,12 +63,39 @@ getcontext:
mov %rax,160(%rdi)
mov (%rsp),%rax
mov %rax,168(%rdi)
xor %eax,%eax
ret
jmp __getcontext
#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
.end
////////////////////////////////////////////////////////////////////////////////
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%%xmm1,%0" : /* no outputs */ : "m"(uc->__fpustate.xmm[1]));
@ -112,3 +141,11 @@ noasan noubsan dontinstrument int getcontext(ucontext_t *uc) {
: "rax");
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"
// Sets machine state.
//
// @see getcontext()
setcontext:
// tailed called by setcontext() implementation
__setcontext:
#ifdef __x86_64__
mov 224(%rdi),%rax
test %rax,%rax
je 1f
@ -43,6 +43,7 @@ setcontext:
movaps 400(%rax),%xmm15
1: push 176(%rdi)
popf
mov %rsi,%rsp
mov 40(%rdi),%r8
mov 48(%rdi),%r9
mov 56(%rdi),%r10
@ -57,16 +58,41 @@ setcontext:
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
#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
////////////////////////////////////////////////////////////////////////////////
noasan noubsan int setcontext(const ucontext_t *uc) {
noasan noubsan int __setcontext(const ucontext_t *uc) {
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,%%xmm1" : /* no outputs */ : "m"(uc->uc_mcontext.fpregs->xmm[1]));

View file

@ -5,6 +5,14 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
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 _ntlinux2context(struct NtContext *, const ucontext_t *) _Hide;

View file

@ -17,13 +17,13 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/struct/sigset.h"
#include "libc/calls/ucontext.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/sig.h"
#include "libc/testlib/ezbench.h"
#include "libc/testlib/testlib.h"
#ifdef __x86_64__
int x;
bool ok1;
bool ok2;
@ -51,6 +51,25 @@ TEST(getcontext, test) {
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) {
static int a;
a = 0;
@ -64,5 +83,3 @@ void SetGetContext(void) {
BENCH(getcontext, bench) {
EZBENCH2("get/setcontext", donothing, SetGetContext());
}
#endif /* __x86_64__ */