mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-03-15 05:16:30 +00:00
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:
parent
8b62bff364
commit
7ec84655b4
7 changed files with 182 additions and 13 deletions
|
@ -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))
|
||||
|
|
|
@ -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
34
libc/calls/getcontext2.c
Normal 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
41
libc/calls/setcontext.c
Normal 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);
|
||||
}
|
|
@ -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]));
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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__ */
|
||||
|
|
Loading…
Add table
Reference in a new issue