Compare commits

...
6 Commits
Author SHA1 Message Date
Justine Tunney 6659981457 Release Cosmopolitan v3.3.6 2024-05-08 04:20:22 -07:00
Justine Tunney ae2a7ac844 Fix thread-local storage bugs on aarch64
This change fixes an issue where .tbss memory might not be initialized.
2024-05-08 04:20:22 -07:00
Justine Tunney 793393a341 Polyfill SA_RESETHAND on MacOS ARM64
This change solves the XNU crash loop mystery. Apple's documentation
claims to support this feature, but they only define the constant in
their header files. The kernel acknowledges thi SA_RESETHAND bit, by
clearing it from the sa_flags state, returns zero, and does nothing.
2024-05-08 04:20:22 -07:00
Justine Tunney 952b9009e8 Avoid crash looping on AARCH64 2024-05-08 04:20:22 -07:00
Jōshin 8f18b3ad65 Reapply apeinstall.sh binfmt flags (#1171)
7d31fc3 made it safe to register ape with the binfmt P flag. Older files
will still get their paths passed via argv[0] and everything should just
work. This also restores the F flag that was rolled back alongside the P
flag; this seems like a good idea to me now. It makes it so /usr/bin/ape
is kind of part of the kernel; simply replacing the file will not change
the loader used. The binfmt will have to be reregistered as well.

ape/apeinstall.sh will already nag you if there's an existing binfmt for
ape. It might be nice to make it actually replace the registration.

This reverts commit df648fb174.
2024-05-08 01:48:48 -04:00
Jōshin 56e0fd9d1d Use latest cosmocc (#1175) 2024-05-08 00:08:26 -04:00
11 changed files with 137 additions and 82 deletions

No files matched your search

+2 -2
View File
@@ -149,9 +149,9 @@ export MODE
export SOURCE_DATE_EPOCH
export TMPDIR
COSMOCC = .cosmocc/3.3.3
COSMOCC = .cosmocc/3.3.5
TOOLCHAIN = $(COSMOCC)/bin/$(ARCH)-linux-cosmo-
DOWNLOAD := $(shell build/download-cosmocc.sh $(COSMOCC) 3.3.3 e4d0fa63cd79cc3bfff6c2d015f1776db081409907625aea8ad40cefc1996d08)
DOWNLOAD := $(shell build/download-cosmocc.sh $(COSMOCC) 3.3.5 db78fd8d3f8706e9dff4be72bf71d37a3f12062f212f407e1c33bc4af3780dd0)
AS = $(TOOLCHAIN)as
CC = $(TOOLCHAIN)gcc
+3 -4
View File
@@ -293,7 +293,6 @@ _tdata_size = _tdata_end - _tdata_start;
_tbss_size = _tbss_end - _tbss_start;
_tbss_offset = _tbss_start - _tdata_start;
_tls_content = (_tdata_end - _tdata_start) + (_tbss_end - _tbss_start);
_tls_align = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss));
ASSERT(ALIGNOF(.tdata) <= TLS_ALIGNMENT && ALIGNOF(.tbss) <= TLS_ALIGNMENT,
"_Thread_local _Alignof can't exceed TLS_ALIGNMENT");
_tdata_align = ALIGNOF(.tdata);
_tbss_align = ALIGNOF(.tbss);
_tls_align = MAX(TLS_ALIGNMENT, MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)));
+3 -1
View File
@@ -553,7 +553,9 @@ _tdata_size = _tdata_end - _tdata_start;
_tbss_size = _tbss_end - _tbss_start;
_tbss_offset = _tbss_start - _tdata_start;
_tls_content = (_tdata_end - _tdata_start) + (_tbss_end - _tbss_start);
_tls_align = 1;
_tdata_align = ALIGNOF(.tdata);
_tbss_align = ALIGNOF(.tbss);
_tls_align = MAX(TLS_ALIGNMENT, MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)));
ape_cod_offset = 0;
ape_cod_vaddr = ADDR(.head);
+11 -4
View File
@@ -137,13 +137,20 @@ if [ x"$(uname -s)" = xLinux ]; then
echo done >&2
fi
uname_r="$(uname -r)"
if printf '%s\n%s\n' 5.12 "$uname_r" | sort -CV; then
FLAGS=FP
else
FLAGS=F
fi
echo >&2
echo registering APE with binfmt_misc >&2
echo you may need to edit configs to persist across reboot >&2
echo '$SUDO sh -c "echo '"'"':APE:M::MZqFpD::/usr/bin/ape:'"'"' >/proc/sys/fs/binfmt_misc/register"' >&2
$SUDO sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register" || exit
echo '$SUDO sh -c "echo '"'"':APE-jart:M::jartsr::/usr/bin/ape:'"'"' >/proc/sys/fs/binfmt_misc/register"' >&2
$SUDO sh -c "echo ':APE-jart:M::jartsr::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register" || exit
echo '$SUDO sh -c "echo '"'"':APE:M::MZqFpD::/usr/bin/ape:'"$FLAGS'"' >/proc/sys/fs/binfmt_misc/register"' >&2
$SUDO sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:$FLAGS' >/proc/sys/fs/binfmt_misc/register" || exit
echo '$SUDO sh -c "echo '"'"':APE-jart:M::jartsr::/usr/bin/ape:'"$FLAGS'"' >/proc/sys/fs/binfmt_misc/register"' >&2
$SUDO sh -c "echo ':APE-jart:M::jartsr::/usr/bin/ape:$FLAGS' >/proc/sys/fs/binfmt_misc/register" || exit
echo done >&2
if [ x"$(cat /proc/sys/fs/binfmt_misc/status)" = xdisabled ]; then
+2
View File
@@ -16,6 +16,8 @@ extern unsigned char _tdata_end[] __attribute__((__weak__));
extern unsigned char _tbss_start[] __attribute__((__weak__));
extern unsigned char _tbss_end[] __attribute__((__weak__));
extern unsigned char _tls_align[] __attribute__((__weak__));
extern unsigned char _tdata_align[] __attribute__((__weak__));
extern unsigned char _tbss_align[] __attribute__((__weak__));
extern unsigned char __test_start[] __attribute__((__weak__));
extern unsigned char __ro[] __attribute__((__weak__));
extern unsigned char __data_start[] __attribute__((__weak__));
+6
View File
@@ -252,6 +252,12 @@ static int __sigaction(int sig, const struct sigaction *act,
rc = sys_sigaction(sig, ap, oldact, arg4, arg5);
} else {
rc = _sysret(__syslib->__sigaction(sig, ap, oldact));
// xnu silicon claims to support sa_resethand but it does nothing
// this can be tested, since it clears the bit from flags as well
if (!rc && oldact &&
(((struct sigaction_silicon *)oldact)->sa_flags & SA_RESETHAND)) {
((struct sigaction_silicon *)oldact)->sa_flags |= SA_RESETHAND;
}
}
if (rc != -1) {
sigaction_native2cosmo((union metasigaction *)oldact);
+17
View File
@@ -30,6 +30,7 @@
#include "libc/log/libfatal.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h"
#include "libc/runtime/syslib.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/sa.h"
@@ -494,6 +495,8 @@ privileged void __sigenter_xnu(void *fn, int infostyle, int sig,
privileged void __sigenter_xnu(int sig, struct siginfo_xnu *xnuinfo,
struct __darwin_ucontext *xnuctx) {
#endif
// allocate signal frame on stack
#pragma GCC push_options
#pragma GCC diagnostic ignored "-Wframe-larger-than="
struct Goodies {
@@ -502,10 +505,24 @@ privileged void __sigenter_xnu(int sig, struct siginfo_xnu *xnuinfo,
} g;
CheckLargeStackAllocation(&g, sizeof(g));
#pragma GCC pop_options
// handle signal
int rva, flags;
rva = __sighandrvas[sig];
if (rva >= kSigactionMinRva) {
flags = __sighandflags[sig];
#ifdef __aarch64__
// xnu silicon claims to support sa_resethand but it does nothing
// this can be tested, since it clears the bit from flags as well
if (flags & SA_RESETHAND) {
struct sigaction sa = {0};
__syslib->__sigaction(sig, &sa, 0);
__sighandflags[sig] = 0;
__sighandrvas[sig] = 0;
}
#endif
if (~flags & SA_SIGINFO) {
((sigaction_f)(__executable_start + rva))(sig, 0, 0);
} else {
+1 -1
View File
@@ -4,7 +4,7 @@
#define __COSMOPOLITAN_MAJOR__ 3
#define __COSMOPOLITAN_MINOR__ 3
#define __COSMOPOLITAN_PATCH__ 5
#define __COSMOPOLITAN_PATCH__ 6
#define __COSMOPOLITAN__ \
(100000000 * __COSMOPOLITAN_MAJOR__ + 1000000 * __COSMOPOLITAN_MINOR__ + \
__COSMOPOLITAN_PATCH__)
+6 -9
View File
@@ -78,17 +78,14 @@ int feenableexcept(int excepts) {
#elif defined(__aarch64__)
unsigned fpcr;
unsigned fpcr2;
unsigned updated_fpcr;
fpcr = __builtin_aarch64_get_fpcr();
fpcr2 = fpcr | (excepts << 8);
unsigned fpcr = __builtin_aarch64_get_fpcr();
unsigned want = excepts << 8;
unsigned fpcr2 = fpcr | want;
if (fpcr != fpcr2) {
__builtin_aarch64_set_fpcr(fpcr2);
// floating point exception trapping is optional in aarch64
updated_fpcr = __builtin_aarch64_get_fpsr();
if (fpcr2 & ~updated_fpcr)
return -1;
fpcr2 = __builtin_aarch64_get_fpsr();
if ((fpcr2 & want) != want)
return -1; // not supported by cpu
}
return (fpcr >> 8) & FE_ALL_EXCEPT;
+38 -32
View File
@@ -68,13 +68,13 @@ static unsigned long ParseMask(const char *str) {
*
* __get_tls()
* │
* %fs Linux/BSDs
* %fs OpenBSD/NetBSD
* _Thread_local │
* ┌───┬──────────┬──────────┼───┐
* │pad│ .tdata │ .tbss │tib│
* └───┴──────────┴──────────┼───┘
* │
* Windows/Mac %gs
* Linux/FreeBSD/Windows/Mac %gs
*
* Here's the TLS memory layout on aarch64:
*
@@ -112,10 +112,6 @@ static unsigned long ParseMask(const char *str) {
* and your `errno` variable also won't be thread safe anymore.
*/
textstartup void __enable_tls(void) {
int tid;
size_t siz;
char *mem, *tls;
struct CosmoTib *tib;
// Here's the layout we're currently using:
//
@@ -138,7 +134,8 @@ textstartup void __enable_tls(void) {
#ifdef __x86_64__
siz = ROUNDUP(I(_tls_size) + sizeof(*tib), TLS_ALIGNMENT);
char *mem;
size_t siz = ROUNDUP(I(_tls_size) + sizeof(struct CosmoTib), TLS_ALIGNMENT);
if (siz <= sizeof(__static_tls)) {
// if tls requirement is small then use the static tls block
// which helps avoid a system call for appes with little tls
@@ -158,28 +155,44 @@ textstartup void __enable_tls(void) {
kAsanProtected);
}
tib = (struct CosmoTib *)(mem + siz - sizeof(*tib));
tls = mem + siz - sizeof(*tib) - I(_tls_size);
struct CosmoTib *tib = (struct CosmoTib *)(mem + siz - sizeof(*tib));
char *tls = mem + siz - sizeof(*tib) - I(_tls_size);
// copy in initialized data section
if (I(_tdata_size)) {
if (IsAsan()) {
__asan_memcpy(tls, _tdata_start, I(_tdata_size));
} else {
memcpy(tls, _tdata_start, I(_tdata_size));
}
}
#elif defined(__aarch64__)
size_t hiz = ROUNDUP(sizeof(*tib) + 2 * sizeof(void *), I(_tls_align));
siz = hiz + I(_tls_size);
if (siz <= sizeof(__static_tls)) {
uintptr_t size = ROUNDUP(sizeof(struct CosmoTib), I(_tls_align)) + //
ROUNDUP(sizeof(uintptr_t) * 2, I(_tdata_align)) + //
ROUNDUP(I(_tdata_size), I(_tbss_align)) + //
I(_tbss_size);
char *mem;
if (I(_tls_align) <= TLS_ALIGNMENT && size <= sizeof(__static_tls)) {
mem = __static_tls;
} else {
mem = _weaken(_mapanon)(siz);
mem = _weaken(_mapanon)(size);
}
if (IsAsan()) {
// there's a roundup(pagesize) gap between .tdata and .tbss
// poison that empty space
__asan_poison(mem + hiz + I(_tdata_size), I(_tbss_offset) - I(_tdata_size),
kAsanProtected);
}
struct CosmoTib *tib =
(struct CosmoTib *)(mem +
ROUNDUP(sizeof(struct CosmoTib), I(_tls_align)) -
sizeof(struct CosmoTib));
tib = (struct CosmoTib *)mem;
tls = mem + hiz;
uintptr_t *dtv = (uintptr_t *)(tib + 1);
size_t dtv_size = sizeof(uintptr_t) * 2;
char *tdata = (char *)dtv + ROUNDUP(dtv_size, I(_tdata_align));
if (I(_tdata_size)) {
memmove(tdata, _tdata_start, I(_tdata_size));
}
// Set the DTV.
//
@@ -189,8 +202,8 @@ textstartup void __enable_tls(void) {
//
// @see musl/src/env/__init_tls.c
// @see https://chao-tic.github.io/blog/2018/12/25/tls
((uintptr_t *)tls)[-2] = 1;
((void **)tls)[-1] = tls;
dtv[0] = 1;
dtv[1] = (uintptr_t)tdata;
#else
#error "unsupported architecture"
@@ -213,6 +226,8 @@ textstartup void __enable_tls(void) {
} else if (IsXnuSilicon()) {
tib->tib_syshand = __syslib->__pthread_self();
}
int tid;
if (IsLinux() || IsXnuSilicon()) {
// gnu/systemd guarantees pid==tid for the main thread so we can
// avoid issuing a superfluous system call at startup in program
@@ -237,15 +252,6 @@ textstartup void __enable_tls(void) {
_pthread_list = &_pthread_static.list;
atomic_store_explicit(&_pthread_static.ptid, tid, memory_order_relaxed);
// copy in initialized data section
if (I(_tdata_size)) {
if (IsAsan()) {
__asan_memcpy(tls, _tdata_start, I(_tdata_size));
} else {
memcpy(tls, _tdata_start, I(_tdata_size));
}
}
// ask the operating system to change the x86 segment register
__set_tls(tib);
+48 -29
View File
@@ -25,6 +25,7 @@
#include "libc/mem/mem.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/sysparam.h"
#include "libc/str/locale.h"
#include "libc/str/str.h"
#include "libc/thread/tls.h"
@@ -54,6 +55,19 @@ static char *_mktls_below(struct CosmoTib **out_tib) {
char *mem, *tls;
struct CosmoTib *tib;
// Here's the TLS memory layout on x86_64
//
// __get_tls()
// │
// %fs OpenBSD/NetBSD
// _Thread_local │
// ┌───┬──────────┬──────────┼───┐
// │pad│ .tdata │ .tbss │tib│
// └───┴──────────┴──────────┼───┘
// │
// Linux/FreeBSD/Windows/Mac %gs
//
siz = ROUNDUP(I(_tls_size) + sizeof(*tib), _Alignof(struct CosmoTib));
siz = ROUNDUP(siz, _Alignof(struct CosmoTib));
mem = memalign(_Alignof(struct CosmoTib), siz);
@@ -77,53 +91,58 @@ static char *_mktls_below(struct CosmoTib **out_tib) {
}
// clear .tbss
bzero(tls + I(_tbss_offset), I(_tbss_size));
if (I(_tbss_size))
bzero(tls + I(_tbss_offset), I(_tbss_size));
// set up thread information block
return _mktls_finish(out_tib, mem, tib);
}
static char *_mktls_above(struct CosmoTib **out_tib) {
size_t hiz, siz;
struct CosmoTib *tib;
char *mem, *dtv, *tls;
// allocate memory for tdata, tbss, and tib
hiz = ROUNDUP(sizeof(*tib) + 2 * sizeof(void *), I(_tls_align));
siz = hiz + I(_tls_size);
mem = memalign(TLS_ALIGNMENT, siz);
// Here's the TLS memory layout on aarch64
//
// x28
// %tpidr_el0
// │
// │ _Thread_local
// ┌───┼───┬──────────┬──────────┐
// │tib│dtv│ .tdata │ .tbss │
// ├───┴───┴──────────┴──────────┘
// │
// __get_tls()
//
size_t size = ROUNDUP(sizeof(struct CosmoTib), I(_tls_align)) + //
ROUNDUP(sizeof(uintptr_t) * 2, I(_tdata_align)) + //
ROUNDUP(I(_tdata_size), I(_tbss_align)) + //
I(_tbss_size);
char *mem = memalign(I(_tls_align), size);
if (!mem)
return 0;
// poison memory between tdata and tbss
if (IsAsan()) {
__asan_poison(mem + hiz + I(_tdata_size), I(_tbss_offset) - I(_tdata_size),
kAsanProtected);
}
struct CosmoTib *tib =
(struct CosmoTib *)(mem +
ROUNDUP(sizeof(struct CosmoTib), I(_tls_align)) -
sizeof(struct CosmoTib));
tib = (struct CosmoTib *)mem;
dtv = mem + sizeof(*tib);
tls = mem + hiz;
uintptr_t *dtv = (uintptr_t *)(tib + 1);
size_t dtv_size = sizeof(uintptr_t) * 2;
// set dtv
((uintptr_t *)dtv)[0] = 1;
((void **)dtv)[1] = tls;
// initialize .tdata
char *tdata = (char *)dtv + ROUNDUP(dtv_size, I(_tdata_align));
if (I(_tdata_size)) {
if (IsAsan()) {
__asan_memcpy(tls, _tdata_start, I(_tdata_size));
} else {
memmove(tls, _tdata_start, I(_tdata_size));
}
memmove(tdata, _tdata_start, I(_tdata_size));
}
// clear .tbss
char *tbss = tdata + ROUNDUP(I(_tdata_size), I(_tbss_align));
if (I(_tbss_size)) {
bzero(tls + I(_tbss_offset), I(_tbss_size));
bzero(tbss, I(_tbss_size));
}
// set up thread information block
dtv[0] = 1;
dtv[1] = (uintptr_t)tdata;
return _mktls_finish(out_tib, mem, tib);
}