Initial import

This commit is contained in:
Justine Tunney 2020-06-15 07:18:57 -07:00
commit c91b3c5006
14915 changed files with 590219 additions and 0 deletions

52
libc/runtime/_exit.S Normal file
View file

@ -0,0 +1,52 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/dce.h"
#include "libc/runtime/internal.h"
#include "libc/macros.h"
.privileged
.yoink __FILE__
/ Terminates process, ignoring destructors and atexit() handlers.
/
/ Normally exit() or quick_exit() is better. This won't even flush
/ stdio streams. Sometimes that makes sense, like after fork().
/
/ @param edi is exit code ∈ [0,256)
/ @note _exit() is same thing
/ @asyncsignalsafe
_Exit: orl $RUNSTATE_TERMINATE,g_runstate(%rip)
#if SupportsWindows()
testb IsWindows()
jz 1f
movzbl %dil,%ecx # %ERRORLEVEL% is limitless
4: call *__imp_ExitProcess(%rip)
jmp 4b
0: int3 # @see setjmp() in WinMain()
#endif
1: mov __NR_exit(%rip),%eax
syscall
cli
lidt 3f
2: hlt
jmp 2b
3: .quad 0
.endfn _Exit,globl,protected
.hidden __NR_exit
.hidden g_runstate

64
libc/runtime/abort.S Normal file
View file

@ -0,0 +1,64 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/dce.h"
#include "libc/runtime/internal.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/consts/nr.h"
#include "libc/macros.h"
.real
.yoink __FILE__
/ Terminates program abnormally.
/
/ This function first tries to trigger your SIGABRT handler. If
/ there isn't one or execution resumes, then abort() terminates
/ the program using an escalating variety methods of increasing
/ brutality.
/
/ @forcealignargpointer
/ @asyncsignalsafe
/ @noreturn
abort: push %rbp
mov %rsp,%rbp
and $-16,%rsp
sub $16,%rsp
orl $RUNSTATE_BROKEN,g_runstate(%rip)
testb IsWindows()
jnz 2f
mov SIG_SETMASK,%edi
mov %rsp,%rsi
push $0xffffffffffffffdf # all bits blocked but SIGABRT
push $0xffffffffffffffff # assumes von neum. arithmetic
pop 8(%rsi)
pop (%rsi)
xor %edx,%edx # don't care about old sigmask
pushpop 4*4,%r10 # sizeof(sigset_t) for systemd
mov __NR_sigprocmask,%eax # sigprocmask$sysv is hookable
syscall
mov __NR_getpid,%eax
syscall
mov %eax,%edi
mov SIGABRT,%esi
mov __NR_kill,%eax
syscall # avoid hook and less bt noise
2: mov $134,%edi # exit(128+SIGABRT) [bash-ism]
call _Exit
.endfn abort,globl,protected
.hidden g_runstate

184
libc/runtime/arch_prctl.c Normal file
View file

@ -0,0 +1,184 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "ape/lib/pc.h"
#include "libc/bits/bits.h"
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/nexgen32e/msr.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/runtime/interruptiblecall.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h"
/**
* @fileoverview Memory segmentation system calls.
*
* This whole file basically does:
*
* mov foo,%fs
* mov foo,%gs
* mov %fs,foo
* mov %gs,foo
*
* Which is nontrivial due to the limitless authoritarianism of
* operating systems.
*/
int arch_prctl$sysv(int, int64_t) hidden;
static inline int arch_prctl$fsgsbase(int code, int64_t addr) {
switch (code) {
case ARCH_SET_GS:
asm volatile("wrgsbase\t%0" : /* no outputs */ : "r"(addr));
return 0;
case ARCH_SET_FS:
asm volatile("wrfsbase\t%0" : /* no outputs */ : "r"(addr));
return 0;
case ARCH_GET_GS:
asm volatile("rdgsbase\t%0" : "=r"(*(int64_t *)addr));
return 0;
case ARCH_GET_FS:
asm volatile("rdfsbase\t%0" : "=r"(*(int64_t *)addr));
return 0;
default:
return einval();
}
}
static int arch_prctl$msr(int code, int64_t addr) {
switch (code) {
case ARCH_SET_GS:
wrmsr(MSR_IA32_GS_BASE, addr);
return 0;
case ARCH_SET_FS:
wrmsr(MSR_IA32_FS_BASE, addr);
return 0;
case ARCH_GET_GS:
*(int64_t *)addr = rdmsr(MSR_IA32_GS_BASE);
return 0;
case ARCH_GET_FS:
*(int64_t *)addr = rdmsr(MSR_IA32_FS_BASE);
return 0;
default:
return einval();
}
}
static int arch_prctl$freebsd(int code, int64_t addr) {
switch (code) {
case ARCH_GET_FS:
return arch_prctl$sysv(128, addr);
case ARCH_SET_FS:
return arch_prctl$sysv(129, addr);
case ARCH_GET_GS:
return arch_prctl$sysv(130, addr);
case ARCH_SET_GS:
return arch_prctl$sysv(131, addr);
default:
return einval();
}
}
static int arch_prctl$xnu(int code, int64_t addr) {
int ax;
switch (code) {
case ARCH_SET_GS:
asm volatile("syscall"
: "=a"(ax)
: "0"(0x3000003), "D"(addr - 0x8a0 /* wat */)
: "rcx", "r11", "memory", "cc");
return ax;
case ARCH_GET_FS:
case ARCH_SET_FS:
case ARCH_GET_GS:
return enosys();
default:
return einval();
}
}
static int arch_prctl$openbsd(int code, int64_t addr) {
int64_t rax;
switch (code) {
case ARCH_GET_FS:
asm volatile("syscall"
: "=a"(rax)
: "0"(0x014a /* __get_tcb */)
: "rcx", "r11", "cc", "memory");
*(int64_t *)addr = rax;
return 0;
case ARCH_SET_FS:
asm volatile("syscall"
: "=a"(rax)
: "0"(0x0149 /* __set_tcb */), "D"(addr)
: "rcx", "r11", "cc", "memory");
return 0;
case ARCH_GET_GS:
case ARCH_SET_GS:
return enosys();
default:
return einval();
}
}
static char g_fsgs_once;
static struct InterruptibleCall g_fsgs_icall;
/**
* Don't bother.
*/
int arch_prctl(int code, int64_t addr) {
void *fn = arch_prctl$fsgsbase;
if (!g_fsgs_once) {
g_fsgs_once = true;
if (X86_HAVE(FSGSBASE)) {
g_fsgs_icall.sig = SIGILL;
if (interruptiblecall(&g_fsgs_icall, fn, code, addr, 0, 0) != -1 &&
g_fsgs_icall.returnval != -1) {
/* ivybridge+ (2012) lets us change segment registers without
needing a 700ns system call. cpuid and /proc/cpuinfo will both
report it's available; unfortunately, operating systems have an
added ability to restrict this feature in %cr4, which we're not
even allowed to read lool */
g_fsgs_once = 2;
return 0;
}
}
}
if (g_fsgs_once == 2) {
return arch_prctl$fsgsbase(code, addr);
}
switch (hostos) {
case METAL:
return arch_prctl$msr(code, addr);
case FREEBSD:
/* claims support but it appears not */
return arch_prctl$freebsd(code, addr);
case OPENBSD:
return arch_prctl$openbsd(code, addr);
case LINUX:
return arch_prctl$sysv(code, addr);
case XNU:
/* probably won't work */
return arch_prctl$xnu(code, addr);
default:
return enosys();
}
}

75
libc/runtime/asan.greg.c Normal file
View file

@ -0,0 +1,75 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/calls.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/fileno.h"
privileged void __asan_init(void) {
}
privileged void __asan_register_globals(uintptr_t a, uintptr_t b) {
}
privileged void __asan_unregister_globals(uintptr_t a, uintptr_t b) {
}
privileged void __asan_loadN(uintptr_t ptr, size_t size) {
dprintf(STDERR_FILENO, "load %p %zu");
}
privileged void __asan_storeN(uintptr_t ptr, size_t size) {
dprintf(STDERR_FILENO, "store %p %zu");
}
privileged void __asan_report_load_n(uintptr_t ptr, size_t size) {
dprintf(STDERR_FILENO, "%s%zu%s%#p", "asan: load ", size, " bytes at ", ptr);
}
privileged void __asan_report_store_n(uintptr_t ptr, size_t size) {
dprintf(STDERR_FILENO, "%s%zu%s%#p", "asan: store ", size, " bytes at ", ptr);
}
privileged uintptr_t __asan_stack_malloc(size_t size, int classid) {
return 0;
}
privileged void __asan_stack_free(uintptr_t ptr, size_t size, int classid) {
}
privileged void __asan_handle_no_return(void) {
}
privileged void __asan_version_mismatch_check_v8(void) {
}
privileged void __asan_alloca_poison(uintptr_t addr, uintptr_t size) {
}
privileged void __asan_allocas_unpoison(uintptr_t top, uintptr_t bottom) {
}
privileged void *__asan_addr_is_in_fake_stack(void *fakestack, void *addr,
void **beg, void **end) {
return NULL;
}
privileged void *__asan_get_current_fake_stack(void) {
return NULL;
}

55
libc/runtime/assertfail.c Normal file
View file

@ -0,0 +1,55 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/calls/calls.h"
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/mem/alloca.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/fileno.h"
/**
* Handles failure of assert() macro.
*/
relegated void __assert_fail(const char *expr, const char *file, int line) {
static bool once;
char *msg, *p, linebuf[16];
unsigned i, exprlen, filelen;
if (!once) {
once = true;
exprlen = expr ? strlen(expr) : 0;
filelen = file ? strlen(file) : 0;
p = msg = alloca(MIN(512, exprlen + filelen + 64));
p = mempcpy(p, file, filelen);
p = stpcpy(p, ":");
if (line < 1) line = 1;
for (i = 0; line; line /= 10) linebuf[i++] = '0' + line % 10;
while (i) *p++ = linebuf[--i];
p = stpcpy(p, ":");
p = mempcpy(p, expr, exprlen);
p = stpcpy(p, "\r\n");
write(STDERR_FILENO, msg, p - msg);
if (weaken(die)) weaken(die)();
}
abort();
unreachable;
}

90
libc/runtime/balloc.c Normal file
View file

@ -0,0 +1,90 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/bits/safemacros.h"
#include "libc/calls/calls.h"
#include "libc/runtime/buffer.h"
#include "libc/runtime/mappings.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/prot.h"
#define kGuard PAGESIZE
#define kGrain FRAMESIZE
/**
* Allocates page-guarded buffer.
*
* sigsegv
* 𝑣..𝑣 𝑣..𝑣
* sigsegv
*
* @param b is metadata object owned by caller, initialized to zero for
* first call; subsequent calls will resize
* @param a is alignment requirement in bytes, e.g. 1,2,4,8,16,...
* @param n is buffer size in bytes
* @return b->p
* @see ralloc()
*/
void *balloc(struct GuardedBuffer *b, unsigned a, size_t n) {
int rc;
char *p;
size_t mi, need;
struct AddrSize az;
struct MemoryCoord mc;
assert(a >= 1);
assert(a <= kGuard);
assert(kGuard < kGrain);
assert(popcount(a) == 1);
assert(popcount(kGuard) == 1);
assert(popcount(kGrain) == 1);
assert(n < 0x800000000000ul - kGrain - kGuard);
if (n) {
az.addr = 0;
az.size = 0;
n = roundup(n, a);
need = roundup(n + kGuard, kGrain);
if (b->p) {
mc = ADDRSIZE_TO_COORD(b->p, 1);
mi = findmapping(mc.y);
if (mi && ISOVERLAPPING(mc, _mm.p[mi - 1])) {
az = COORD_TO_ADDRSIZE(_mm.p[mi - 1]);
if (az.size < need) {
rc = munmap(az.addr, az.size);
assert(rc != -1);
az.addr = NULL;
az.size = 0;
}
}
}
if (!az.size) {
if ((p = mapanon(need)) == MAP_FAILED) abort();
if (mprotect(p + need - kGuard, kGuard, PROT_NONE) == -1) abort();
} else {
p = az.addr;
}
b->p = p + need - kGuard - n;
}
return b->p;
}

40
libc/runtime/bfree.c Normal file
View file

@ -0,0 +1,40 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/runtime/buffer.h"
#include "libc/runtime/mappings.h"
void bfree(struct GuardedBuffer *b) {
int mr;
size_t mi;
struct AddrSize az;
struct MemoryCoord mc;
if (b->p) {
mc = ADDRSIZE_TO_COORD(b->p, 1);
mi = findmapping(mc.y);
assert(mi > 0);
assert(ISOVERLAPPING(mc, _mm.p[mi - 1]));
az = COORD_TO_ADDRSIZE(_mm.p[mi - 1]);
mr = munmap(az.addr, az.size);
assert(mr != -1);
b->p = NULL;
}
}

15
libc/runtime/buffer.h Normal file
View file

@ -0,0 +1,15 @@
#ifndef COSMOPOLITAN_LIBC_RUNTIME_BUFFER_H_
#define COSMOPOLITAN_LIBC_RUNTIME_BUFFER_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct GuardedBuffer {
void *p;
};
void *balloc(struct GuardedBuffer *, unsigned, size_t);
void bfree(struct GuardedBuffer *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_RUNTIME_BUFFER_H_ */

28
libc/runtime/clearenv.c Normal file
View file

@ -0,0 +1,28 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/runtime/runtime.h"
/**
* Removes all environment variables.
*/
int clearenv(void) {
environ = NULL;
return 0;
}

36
libc/runtime/close_s.c Normal file
View file

@ -0,0 +1,36 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
#include "libc/calls/calls.h"
#include "libc/runtime/mappings.h"
#include "libc/runtime/runtime.h"
/**
* Closes file descriptor.
*
* The caller's variable is made -1. Note that close(-1) is a no-op.
*
* @return 0 on success, or -1 w/ errno
* @asyncsignalsafe
*/
int close_s(int *fdp) {
int fd = -1;
return close(lockxchg(fdp, &fd));
}

View file

@ -0,0 +1,37 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/runtime/ezmap.h"
#include "libc/runtime/symbols.h"
#include "libc/calls/calls.h"
/**
* Frees symbol table.
* @return 0 on success or -1 on system error
*/
int closesymboltable(struct SymbolTable **table) {
int rc = 0;
if (*table && (intptr_t)*table != (intptr_t)-1) {
struct SymbolTable *t = *table;
*table = NULL;
if (unmapfile(&t->mf) == -1) rc = -1;
if (munmap(t, t->scratch) == -1) rc = -1;
}
return rc;
}

181
libc/runtime/cxaatexit.S Normal file
View file

@ -0,0 +1,181 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 sw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "ape/relocations.h"
#include "libc/macros.h"
.section .text.exit,"ax",@progbits
.yoink __FILE__
/ Delegates to __cxa_atexit().
/
/ @param rdi callback typed void(*)(void) (nullable)
/ @return 0 on success or nonzero if out of space
atexit: xor %esi,%esi
xor %edx,%edx
/ 𝑠𝑙𝑖𝑑𝑒
/ Registers destructor to be called upon exit().
/
/ Destructors are called in reverse order. They won't be called
/ if the program aborts or _exit() is called. Invocations of this
/ function are usually generated by the C++ compiler.
/
/ @param rdi callback typed void(*)(T) (nullable)
/ @param rsi callback arg typed T (nullable)
/ @param rdx dso handle (nullable)
/ @return 0 on success or nonzero if out of space
/ @note folks have forked libc in past just to unbloat atexit()
/ @see news.ycombinator.com/item?id=20228082
/ @preinitsafe
__cxa_atexit:
push %rbp
mov %rsp,%rbp
.profilable
push %r15
ezlea g_cxa,cx
mov %rcx,%r15
mov (%r15),%rax # get state->block
mov 8(%r15),%rcx # get state->offset
test %rcx,%rcx
jz 2f
0: sub $24,%rcx
mov %rdx,(%rax,%rcx) # set cb->dso
mov %rsi,8(%rax,%rcx) # set cb->arg
mov %rdi,16(%rax,%rcx) # set cb->fn
mov %rcx,8(%r15) # set state->offset
xor %eax,%eax # success
1: pop %r15
pop %rbp
ret
2: .weak calloc
ezlea calloc,cx
test %rcx,%rcx
jz 1b # fail (no malloc)
push %rax
push %rdi
push %rsi
pushpop ATEXIT_MAX+1,%rdi
pushpop 16,%rsi
call *%rcx
pop %rsi
pop %rdi
pop %rcx # rax=new rcx=old
test %rax,%rax
jz 1b # fail (no memory)
mov $ATEXIT_MAX*8*3,%r8
mov %rax,(%r15) # set state->block
mov %rcx,(%rax,%r8) # set block->next
mov %r8,%rcx
jmp 0b
.endfn __cxa_atexit,globl
.endfn atexit,globl
/ Triggers destructors.
/
/ This implementation supports DSO handles, but is optimized for
/ cases when it's called only once by exit().
/
/ @param rdi is dso predicate or null to destroy all
/ @see libc/exit.c
__cxa_finalize:
push %rbp
mov %rsp,%rbp
.profilable
push %r14
push %r13
push %r12
mov g_cxa(%rip),%rsi
mov %rdi,%r14
0: mov %rsi,%r12 # loop through blocks
pushpop ATEXIT_MAX,%rcx
1: lodsq # dso # loop through callbacks
xchg %rax,%rdx
lodsq # arg
xchg %rax,%rdi
lodsq # fn
test %rax,%rax
jz 2f # ignore empty slots
test %r14,%r14
jmp 5f # null predicate match all
cmp %r14,%rdx
jne 2f # predicate mismatch
5: push %rsi
push %rcx
push %rcx
call *%rax
pop %rcx
pop %rcx
pop %rsi
xor %eax,%eax # clear slot (never reused)
mov %rax,-8(%rsi)
2: loop 1b
lodsq # get next block ptr
test %rax,%rax # don't free static block no. 1
jz 3f # which always has next == NULL
test %r14,%r14
jz 1f # don't free anything if just one dso
push %rax
mov %r12,%rdi
.weak free
call free # can't panic due to earlier test
1: pop %rsi
jmp 0b
3: pop %r12 # align stack for next call
test %r14,%r14 # no static dtor for dso exit
jnz 9f
ezlea __fini_array_end,ax # static dtors in reverse order
.weak __fini_array_end # could be called multiple times
ezlea __fini_array_start,cx # idempotency recommended
.weak __fini_array_start # or consider atexit()
8: sub $8,%rax # @see ape/ape.lds
cmp %rcx,%rax
jl 9f
push %rax
push %rcx
call *(%rax)
pop %rcx
pop %rax
jmp 8b
9: pop %r13
pop %r14
pop %rbp
ret
.endfn __cxa_finalize,globl,hidden
.bss
.align 16 # static/dynamic hybrid linked list
g_cxa: .quad 0 # last block ptr: (long (*)[32][3])
.quad 0 # block byte offset moves backwards
.endobj g_cxa
g_cxa_static:
.rept ATEXIT_MAX
.quad 0 # dso
.quad 0 # arg
.quad 0 # fn (or NULL for empty)
.endr
.quad 0 # next (always NULL in static block)
.endobj g_cxa_static
.previous
.init.start 300,_init_g_cxa
ezlea g_cxa,cx
lea g_cxa_static-g_cxa(%rcx),%rax
mov %rax,(%rcx)
movl $ATEXIT_MAX*8*3,8(%rcx)
.init.end 300,_init_g_cxa

63
libc/runtime/defer.greg.c Normal file
View file

@ -0,0 +1,63 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/alg/arraylist.h"
#include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/calls/calls.h"
#include "libc/mem/mem.h"
#include "libc/nexgen32e/gc.h"
#include "libc/runtime/gc.h"
#include "libc/runtime/runtime.h"
forceinline bool PointerNotOwnedByParentStackFrame(struct StackFrame *frame,
struct StackFrame *parent,
void *ptr) {
return !(((intptr_t)ptr > (intptr_t)frame) &&
((intptr_t)ptr < (intptr_t)parent));
}
/**
* Adds destructor to garbage shadow stack.
*
* @param frame is passed automatically by wrapper macro
* @param fn takes one argument
* @param arg is passed to fn(arg)
* @return arg
*/
void __defer(struct StackFrame *frame, void *fn, void *arg) {
struct StackFrame *frame2;
/*
* To avoid an API requiring dlmalloc dependency, say:
* defer(free_s, &ptr_not_owned_by_current_frame)
* Rather than:
* defer(weak(free), ptr)
*/
if (!arg) return;
frame2 = __builtin_frame_address(0);
assert(frame2->next == frame);
assert(PointerNotOwnedByParentStackFrame(frame2, frame, arg));
if (append(&__garbage,
(&(const struct Garbage){frame->next, (intptr_t)fn, (intptr_t)arg,
frame->addr})) != -1) {
atomic_store(&frame->addr, (intptr_t)&__gc);
} else {
abort();
}
}

39
libc/runtime/describeos.c Normal file
View file

@ -0,0 +1,39 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
char *describeos(char *buf, size_t size) {
const char *s;
if (IsLinux()) {
s = "gnu/systemd";
} else if (IsXnu()) {
s = "xnu's not unix";
} else if (IsFreebsd()) {
s = "freebesiyatadishmaya";
} else if (IsOpenbsd()) {
s = "openbsd";
} else if (IsWindows()) {
s = "the new technology";
} else {
s = "wut";
}
return memccpy(buf, s, '\0', size);
}

27
libc/runtime/dsohandle.S Normal file
View file

@ -0,0 +1,27 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
#include "libc/notice.inc"
.yoink __FILE__
/ Uniquely identifies each artifact linked in an address space.
__dso_handle:
.quad __dso_handle
.endobj __dso_handle,globl,hidden

View file

@ -0,0 +1,71 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "ape/lib/pc.h"
#include "libc/dce.h"
#include "libc/nexgen32e/nexgen32e.h"
#include "libc/nt/struct/context.h"
#include "libc/nt/thunk/msabi.h"
#define kNtContextXstate 0x00100040
#define kNtXstateAvx 2
#define kNtXstateMaskAvx (1ull << kNtXstateAvx)
static void EnableAvx(void) {
asm volatile("mov\t%%cr4,%%rax\n\t"
"or\t%0,%%rax\n\t"
"mov\t%%rax,%%cr4\n\t"
"xor\t%%ecx,%%ecx\n\t"
"xgetbv\n\t"
"or\t%1,%%eax\n\t"
"xsetbv"
: /* no outputs */
: "i"(CR4_OSXSAVE), "i"(XCR0_X87 | XCR0_SSE | XCR0_AVX)
: "rax", "rcx", "rdx", "memory", "cc");
}
static void EnableAvxOnWindows(void) {
/* typedef uint64_t (*getenabledxstatefeatures_f)(void) __msabi; */
/* typedef bool32 (*initializecontext_f)(void *buffer, uint32_t flags, */
/* struct NtContext **out_context, */
/* uint32_t *inout_buffersize) __msabi;
*/
/* typedef bool32 (*getxstatefeaturesmask_f)(struct NtContext * context, */
/* uint64_t * out_featuremask)
* __msabi; */
/* typedef bool32 (*setxstatefeaturesmask_f)(struct NtContext * context, */
/* uint64_t featuremask) __msabi; */
/* getenabledxstatefeatures_f GetEnabledXStateFeatures; */
/* initializecontext_f InitializeContext; */
/* getxstatefeaturesmask_f GetXStateFeaturesMask; */
/* setxstatefeaturesmask_f SetXStateFeaturesMask; */
}
/**
* Requests authorization from operating system to do 256-bit math.
* @assume avx cpuid check performed by caller
*/
int _init_enableavx(void) {
if (IsMetal()) {
EnableAvx();
} else if (IsWindows()) {
EnableAvxOnWindows();
}
return 0;
}

30
libc/runtime/exit.c Normal file
View file

@ -0,0 +1,30 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
/**
* Exits program with grace.
*/
noreturn textexit void exit(int rc) {
__cxa_finalize(NULL);
_exit(rc);
unreachable;
}

58
libc/runtime/ezmap.c Normal file
View file

@ -0,0 +1,58 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/safemacros.h"
#include "libc/calls/calls.h"
#include "libc/limits.h"
#include "libc/runtime/ezmap.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h"
/**
* Memory-maps file for reading.
* An internal veneer for a common mmap() use-case.
*/
int mapfileread(const char *filename, struct MappedFile *mf) {
mf->addr = MAP_FAILED;
if ((mf->fd = open(filename, O_RDONLY)) != -1 &&
(mf->size = getfiledescriptorsize(mf->fd)) < INT_MAX &&
(mf->addr = mf->size
? mmap(NULL, mf->size, PROT_READ, MAP_SHARED, mf->fd, 0)
: NULL) != MAP_FAILED) {
return 0;
} else {
unmapfile(mf);
return -1;
}
}
/**
* Releases resource returned by mapfileread().
*/
int unmapfile(struct MappedFile *mf) {
int rc = 0;
rc |= munmap(mf->addr, mf->size);
rc |= close(mf->fd);
mf->fd = -1;
mf->addr = MAP_FAILED;
mf->size = 0;
return rc;
}

36
libc/runtime/ezmap.h Normal file
View file

@ -0,0 +1,36 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#ifndef COSMOPOLITAN_LIBC_EZMAP_H_
#define COSMOPOLITAN_LIBC_EZMAP_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct MappedFile {
int64_t fd;
void *addr;
size_t size;
};
int mapfileread(const char *filename, struct MappedFile *mf) hidden;
int unmapfile(struct MappedFile *mf) hidden;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_EZMAP_H_ */

46
libc/runtime/fastmath.S Normal file
View file

@ -0,0 +1,46 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 sw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
#include "libc/notice.inc"
.text.startup
.yoink __FILE__
/ Intel Manual V.1 §10.2.3 - MXCSR Control and Status Register
#define MXCSR_DE (1 << 1) /* Denormal Flag */
#define MXCSR_DAZ (1 << 6) /* Denormals Are Zeros */
#define MXCSR_DM (1 << 8) /* Denormal Operation Mask */
#define MXCSR_FTZ (1 << 15) /* Flush to Zero */
/ Initializes fast math.
/
/ Seymour Cray didn't care that 81.0/3.0 did not give exactly
/ 27.0 on the CDC 6000 class machines, and he was universally
/ respected for making the fastest machines around.
/ Linus Torvalds
__fast_math:
push %rbp
mov %rsp,%rbp
push %rax
stmxcsr (%rsp)
orl $MXCSR_FTZ+MXCSR_DAZ,(%rsp)
ldmxcsr (%rsp)
leave
ret
.endfn __fast_math,globl

View file

@ -0,0 +1,52 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/auxv.h"
struct FindComBinary {
bool once;
const char *res;
char buf[PATH_MAX];
};
static struct FindComBinary findcombinary_;
/**
* Returns path of binary without debug information, or null.
*
* @return path to non-debug binary, or -1 w/ errno
*/
const char *findcombinary(void) {
size_t len;
const char *p;
if (!findcombinary_.once) {
findcombinary_.once = true;
if ((p = (const char *)getauxval(AT_EXECFN)) &&
(len = strlen(p)) < ARRAYLEN(findcombinary_.buf)) {
findcombinary_.res = memcpy(findcombinary_.buf, p, len + 1);
if (len > 4 && memcmp(&findcombinary_.buf[len - 4], ".dbg", 4) == 0) {
findcombinary_.buf[len - 4] = '\0';
}
}
}
return findcombinary_.res;
}

View file

@ -0,0 +1,52 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/macros.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/auxv.h"
/**
* Returns path of binary with the debug information, or null.
*
* @return path to debug binary, or -1 w/ errno
*/
const char *finddebugbinary(void) {
static char buf[PATH_MAX];
if (buf[0]) return &buf[0];
const char *const trybins[] = {program_invocation_name,
(const char *)getauxval(AT_EXECFN)};
for (unsigned i = 0; i < ARRAYLEN(trybins); ++i) {
const char *res = trybins[i];
unsigned len = strlen(res);
if (4 < len && len < sizeof(buf) - 5) {
if (strcmp(res + len - 4, ".dbg") == 0) return res;
/* try suffixing extension, e.g. .com → .com.dbg */
memcpy(mempcpy(buf, res, len), ".dbg", 5);
if (fileexists(buf)) return &buf[0];
buf[0] = '\0';
}
}
errno = ENOENT;
return NULL;
}

View file

@ -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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/runtime/mappings.h"
size_t findmapping_(int32_t k, const struct MemoryCoord *coords, size_t count) {
size_t l, r, m;
l = 0;
r = count;
while (l < r) {
m = (l + r) >> 1;
if (coords[m].x > k) {
r = m;
} else {
l = m + 1;
}
}
return l;
}
/**
* Returns appropriate rightmost index.
*/
size_t findmapping(int32_t k) {
return findmapping_(k, _mm.p, _mm.i);
}
/**
* Returns appropriate rightmost index.
*/
size_t pickmapping(int32_t k) {
return findmapping_(k, _mm.p, _mm.i);
}

31
libc/runtime/fpreset.S Normal file
View file

@ -0,0 +1,31 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
.yoink __FILE__
/ Re-initializes FPU.
fpreset:
_fpreset:
.leafprologue
.profilable
finit
.leafepilogue
.endfn _fpreset,globl
.endfn fpreset,globl

36
libc/runtime/free_s.c Normal file
View file

@ -0,0 +1,36 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
#include "libc/mem/mem.h"
#include "libc/runtime/mappings.h"
#include "libc/runtime/runtime.h"
/**
* Frees memory, the Cosmopolitan way.
*
* The caller's pointer is zeroed. Stack and static memory is ignored.
* This doesn't require a dependency on malloc().
*/
void free_s(void *v) {
void **pp = (void **)v;
void *p = NULL;
lockxchg(pp, &p);
if (isheap(p)) weakfree(p);
}

213
libc/runtime/ftrace.greg.c Normal file
View file

@ -0,0 +1,213 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/alg/bisectcarleft.h"
#include "libc/bits/bits.h"
#include "libc/bits/safemacros.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/sigset.h"
#include "libc/dce.h"
#include "libc/macros.h"
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/missioncritical.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/nr.h"
#include "libc/sysv/consts/prot.h"
#include "libc/sysv/consts/sig.h"
/**
* @fileoverview Plain-text function call logging.
*
* Able to log ~2 million function calls per second, which is mostly
* bottlenecked by system call overhead. Log size is reasonable if piped
* into gzip.
*/
static char g_buf[512];
static const char *g_lastsymbol;
static struct SymbolTable *g_symbols;
forceinline int getnestinglevel(struct StackFrame *frame) {
int nesting = -2;
while (frame) {
++nesting;
frame = frame->next;
}
return max(0, nesting);
}
/**
* Prints name of function being called.
*
* We insert CALL instructions that point to this function, in the
* prologues of other functions. We assume those functions behave
* according to the System Five NexGen32e ABI.
*/
privileged interruptfn void ftrace_hook(void) {
size_t i, j, nesting;
const char *symbol;
struct StackFrame *frame;
LOAD_DEFAULT_RBX();
if (g_symbols && !(g_runstate & RUNSTATE_BROKEN)) {
frame = __builtin_frame_address(0);
symbol =
&g_symbols->name_base[g_symbols
->symbols[bisectcarleft(
(const int32_t(*)[2])g_symbols->symbols,
g_symbols->count,
frame->addr - g_symbols->addr_base)]
.name_rva];
if (symbol != g_lastsymbol &&
(nesting = getnestinglevel(frame)) * 2 < ARRAYLEN(g_buf) - 3) {
i = 2;
j = 0;
while (nesting--) {
g_buf[i++] = ' ';
g_buf[i++] = ' ';
}
while (i < ARRAYLEN(g_buf) - 2 && symbol[j]) {
g_buf[i++] = symbol[j++];
}
g_buf[i++] = '\n';
__print(g_buf, i);
}
g_lastsymbol = symbol;
}
RESTORE_RBX();
}
/**
* Rewrites code in memory to log function calls.
*
* We do this by searching each function for the nop instruction
* inserted by GCC when we use the -pg -mnop-mcount flags. There's no
* risk of corrupting data since the linker scripts won't mix code and
* data.
*
* Modules built with -O3 and without the profiling flags might have
* these same nop instructions, but that shouldn't be problematic since
* they're only there for the puposes of aligning jumps, and therefore
* aren't actually executed. However codebases that use huge function
* alignments with wide-nop slides could pose minor issues. Further note
* that Cosmopolitan sources are almost never intentionally written to
* use code alignment, since we've only seen a few cases where it helps.
*
* @see ape/ape.lds
*/
privileged void ftrace_install(void) {
/* TODO(jart): Is -fschedule-insns2 so aggro that we need XED here? */
size_t i;
intptr_t addr;
sigset_t oldmask;
uint64_t code, mcode;
unsigned char *p, *pe;
const intptr_t kMcount = (intptr_t)&mcount;
const intptr_t kFtraceHook = (intptr_t)&ftrace_hook;
const intptr_t kProgramCodeStart = (intptr_t)&_ereal;
const intptr_t kPrivilegedStart = (intptr_t)&__privileged_start;
const bool kIsBinaryAligned = !(kPrivilegedStart & (PAGESIZE - 1));
g_buf[0] = '+';
g_buf[1] = ' ';
sigprocmask(SIG_BLOCK, &kSigsetFull, &oldmask);
if (__mprotect((void *)g_symbols->addr_base,
kPrivilegedStart - g_symbols->addr_base,
kIsBinaryAligned ? PROT_READ | PROT_WRITE
: PROT_READ | PROT_WRITE | PROT_EXEC) != -1) {
for (i = 0; i < g_symbols->count - 1; ++i) {
if (g_symbols->addr_base + g_symbols->symbols[i].addr_rva <
kProgramCodeStart) {
continue; /* skip over real mode symbols */
}
if (g_symbols->addr_base + g_symbols->symbols[i].addr_rva >=
kPrivilegedStart) {
break; /* stop before privileged symbols */
}
for (p = (unsigned char *)(g_symbols->addr_base +
g_symbols->symbols[i].addr_rva),
pe = (unsigned char *)(g_symbols->addr_base +
g_symbols->symbols[i + 1].addr_rva);
p < pe - 8; ++p) {
code = read64le(p);
/*
* Test for -mrecord-mcount (w/ -fpie or -fpic)
*
* nopw 0x00(%rax,%rax,1) morphed by package.com
* call *mcount(%rip) linked w/o -static
* addr32 call mcount relaxed w/ -static
* addr32 call mcount relaxed w/ -static
*
* Note that gcc refuses to insert the six byte nop.
*/
if ((code & 0x0000FFFFFFFFFFFF) == 0x0000441F0F66 ||
(code & 0x0000FFFFFFFFFFFF) ==
((((kMcount - ((intptr_t)&p[2] + 4)) << 16) | 0xE867) &
0x0000FFFFFFFFFFFF) ||
(code & 0x0000FFFFFFFFFFFF) ==
((((kMcount - ((intptr_t)&p[2] + 4)) << 16) | 0xFF15) &
0x0000FFFFFFFFFFFF)) {
p[0] = 0x67;
p[1] = 0xE8;
addr = kFtraceHook - ((intptr_t)&p[2] + 4);
p[2] = addr >> 000;
p[3] = addr >> 010;
p[4] = addr >> 020;
p[5] = addr >> 030;
break;
}
/*
* Test for -mnop-mcount (w/ -fno-pie)
*/
mcode = code & 0x000000FFFFFFFFFF;
if ((mcode == 0x00441F0F /* nopl 0x00(%eax,%eax,1) [canonical] */) ||
(mcode == 0x00041F0F67 /* nopl (%eax,%eax,1) [older gcc] */)) {
if (p[-1] != 0x66 /* nopw 0x0(%rax,%rax,1) [donotwant] */) {
p[0] = 0xE8 /* call Jvds */;
addr = kFtraceHook - ((intptr_t)&p[1] + 4);
p[1] = addr >> 000;
p[2] = addr >> 010;
p[3] = addr >> 020;
p[4] = addr >> 030;
}
break;
}
}
}
__mprotect((void *)g_symbols->addr_base,
kPrivilegedStart - g_symbols->addr_base, PROT_READ | PROT_EXEC);
}
sigprocmask(SIG_SETMASK, &oldmask, NULL);
}
/**
* Installs plaintext function tracer. Do not call.
* @see libc/runtime/_init.S for documentation
*/
textstartup void ftrace_init(void) {
if ((g_symbols = opensymboltable(finddebugbinary()))) {
ftrace_install();
}
}

31
libc/runtime/g_argc.S Normal file
View file

@ -0,0 +1,31 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 sw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
.yoink __FILE__
.initbss 300,_init_g_argc
g_argc: .quad 0
.endobj g_argc,globl,hidden
.previous
.init.start 300,_init_g_argc
mov %r12,%rax
stosq
.init.end 300,_init_g_argc

48
libc/runtime/gc.h Normal file
View file

@ -0,0 +1,48 @@
#ifndef COSMOPOLITAN_LIBC_RUNTIME_GC_H_
#define COSMOPOLITAN_LIBC_RUNTIME_GC_H_
#include "libc/calls/calls.h"
#include "libc/runtime/runtime.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/**
* @fileoverview Cosmopolitan Return-Oriented Garbage Collector.
*
* This is the same thing as {@code std::unique_ptr<>} in C++ or the
* {@code defer} keyword in Go. We harness the power of ROP for good
* using very few lines of code.
*/
struct StackFrame;
/**
* Releases resource when function returns.
*
* @warning do not return a gc()'d pointer
* @warning do not realloc() with gc()'d pointer
*/
#define gc(THING) defer(weakfree, (THING))
/**
* Same as longjmp() but runs gc() / defer() destructors.
*/
void gclongjmp(jmp_buf, int) nothrow noreturn paramsnonnull();
/**
* Calls FN(ARG) when function returns.
*/
#define defer(FN, ARG) \
({ \
autotype(ARG) Arg = (ARG); \
/* prevent weird opts like tail call */ \
asm volatile("" : "+g"(Arg) : : "memory"); \
__defer(__builtin_frame_address(0), FN, Arg); \
asm volatile("" : "+g"(Arg) : : "memory"); \
Arg; \
})
void __defer(struct StackFrame *, void *, void *) hidden paramsnonnull((1, 2));
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_RUNTIME_GC_H_ */

115
libc/runtime/getdosargv.c Normal file
View file

@ -0,0 +1,115 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
#include "libc/bits/pushpop.h"
#include "libc/bits/safemacros.h"
#include "libc/runtime/internal.h"
#include "libc/str/appendchar.h"
#include "libc/str/str.h"
/* TODO(jart): Make early-stage data structures happen. */
#undef isspace
#undef iswspace
#define isspace(c) ((c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r')
#define iswspace(c) isspace(c)
struct DosArgv {
const char16_t *s;
char *p;
char *pe;
wint_t wc;
};
static textwindows void decodedosargv(struct DosArgv *st) {
st->s += getutf16(st->s, &st->wc);
}
static textwindows void appenddosargv(struct DosArgv *st, wint_t wc) {
if (st->p < st->pe) {
st->p += tpencode(st->p, st->pe - st->p, wc, false);
}
}
/**
* Tokenizes and transcodes Windows NT CLI args, thus avoiding
* CommandLineToArgv() schlepping in forty megs of dependencies.
*
* @param s is the command line string provided by the executive
* @param buf is where we'll store double-NUL-terminated decoded args
* @param size is how many bytes are available in buf
* @param argv is where we'll store the decoded arg pointer array, which
* is guaranteed to be NULL-terminated if max>0
* @param max specifies the item capacity of argv, or 0 to do scanning
* @return number of args written, excluding the NULL-terminator; or,
* if the output buffer wasn't passed, or was too short, then the
* number of args that *would* have been written is returned; and
* there are currently no failure conditions that would have this
* return -1 since it doesn't do system calls
* @see test/libc/dosarg_test.c
* @see libc/runtime/ntspawn.c
* @note kudos to Simon Tatham for figuring out quoting behavior
*/
textwindows int getdosargv(const char16_t *cmdline, char *buf, size_t size,
char **argv, size_t max) {
bool inquote;
size_t i, argc, slashes, quotes;
struct DosArgv st;
st.s = cmdline;
st.p = buf;
st.pe = buf + size;
argc = 0;
decodedosargv(&st);
while (st.wc) {
while (st.wc && iswspace(st.wc)) decodedosargv(&st);
if (!st.wc) break;
if (++argc < max) {
argv[argc - 1] = st.p < st.pe ? st.p : NULL;
}
inquote = false;
while (st.wc) {
if (!inquote && isspace(st.wc)) break;
if (st.wc == '"' || st.wc == '\\') {
slashes = 0;
quotes = 0;
while (st.wc == '\\') decodedosargv(&st), slashes++;
while (st.wc == '"') decodedosargv(&st), quotes++;
if (!quotes) {
while (slashes--) appenddosargv(&st, '\\');
} else {
while (slashes >= 2) appenddosargv(&st, '\\'), slashes -= 2;
if (slashes) appenddosargv(&st, '"'), quotes--;
if (quotes > 0) {
if (!inquote) quotes--;
for (i = 3; i <= quotes + 1; i += 3) appenddosargv(&st, '"');
inquote = (quotes % 3 == 0);
}
}
} else {
appenddosargv(&st, st.wc);
decodedosargv(&st);
}
}
appenddosargv(&st, '\0');
}
appenddosargv(&st, '\0');
if (size) buf[min(st.p - buf, size - 1)] = '\0';
if (max) argv[min(argc, max - 1)] = NULL;
return argc;
}

View file

@ -0,0 +1,67 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#ifndef COSMOPOLITAN_LIBC_DOSENVIRON_H_
#define COSMOPOLITAN_LIBC_DOSENVIRON_H_
#include "libc/bits/safemacros.h"
#include "libc/str/appendchar.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
/**
* Transcodes NT environment variable block from UTF-16 to UTF-8.
*
* @param env is a double NUL-terminated block of key=values
* @param buf is the new environment
* @param size is the byte capacity of buf
* @param envp stores NULL-terminated string pointer list
* @param max is the pointer count capacity of envp
* @return number of variables decoded, excluding NULL-terminator
*/
static inline int getdosenviron(const char16_t *env, char *buf, size_t size,
char **envp, size_t max) {
const char16_t *s = env;
size_t envc = 0;
if (size) {
wint_t wc;
char *p = buf;
char *pe = buf + size - 1;
if (p < pe) {
s += getutf16(s, &wc);
while (wc) {
if (++envc < max) {
envp[envc - 1] = p < pe ? p : NULL;
}
bool endstring;
do {
AppendChar(&p, pe, wc);
endstring = !wc;
s += getutf16(s, &wc);
} while (!endstring);
buf[min(p - buf, size - 2)] = u'\0';
}
}
AppendChar(&p, pe, '\0');
buf[min(p - buf, size - 1)] = u'\0';
}
if (max) envp[min(envc, max - 1)] = NULL;
return envc;
}
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_DOSENVIRON_H_ */

View file

@ -0,0 +1,29 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
.yoink __FILE__
/ Returns granularity of memory manager.
getpagesize:
.leafprologue
.profilable
mov $FRAMESIZE,%eax
.leafepilogue
.endfn getpagesize,globl

View file

@ -0,0 +1,54 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/conv/itoa.h"
#include "libc/runtime/missioncritical.h"
/**
* Debugs super low-level stuff, e.g.
*
* void GOT_HERE(int);
* INITIALIZER(100, _init_got_here_100, GOT_HERE(100));
* INITIALIZER(200, _init_got_here_200, GOT_HERE(200));
* INITIALIZER(300, _init_got_here_300, GOT_HERE(300));
* INITIALIZER(400, _init_got_here_400, GOT_HERE(400));
* INITIALIZER(500, _init_got_here_500, GOT_HERE(500));
* INITIALIZER(600, _init_got_here_600, GOT_HERE(600));
* INITIALIZER(700, _init_got_here_700, GOT_HERE(700));
* INITIALIZER(800, _init_got_here_800, GOT_HERE(800));
*
*/
privileged interruptfn void GOT_HERE(long num) {
size_t len;
char msg[48];
len = 0;
msg[len++] = 'g';
msg[len++] = 'o';
msg[len++] = 't';
msg[len++] = ' ';
msg[len++] = 'h';
msg[len++] = 'e';
msg[len++] = 'r';
msg[len++] = 'e';
msg[len++] = ' ';
len += int64toarray_radix10(num, &msg[len]);
msg[len++] = '\n';
msg[len] = '\0';
__print(msg, len);
}

88
libc/runtime/grow.c Normal file
View file

@ -0,0 +1,88 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/bits/safemacros.h"
#include "libc/conv/conv.h"
#include "libc/conv/sizemultiply.h"
#include "libc/macros.h"
#include "libc/mem/mem.h"
#include "libc/runtime/mappings.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
#define GUARANTEE_TERMINATOR 1
#define INITIAL_CAPACITY (32 - GUARANTEE_TERMINATOR)
/**
* Grows array, The Cosmopolitan Way.
*
* This function may be called once an array has run out of space. If p
* is NULL, a new array is allocated; otherwise, the array's made 1.5x
* bigger. It has been written that this amortizes list appends down to
* constant-time. Extended memory is zeroed. Growth is monotonic.
*
* If p points to to static memory or something on the stack, it'll be
* converted to dynamic memory automatically. This can make algorithms
* faster when the average case is a small amount of data. It also means
* functions using this (and free_s()) won't have a hard-requirement on
* malloc().
*
* Consider trying the higher-level append() and concat() APIs (defined
* in libc/alg/arraylist.h) as an alternative to directly using grow().
*
* @param pp points to pointer holding memory address
* @param capacity tracks maximum items that can be stored in p
* can only be 0 if p is NULL (see reallocarray() for non-monotonic)
* @param itemsize is the sizeof each item
* @return true on success, or false w/ errno and *p is NOT free()'d
* @error ENOMEM if realloc() not linked or mmap() failed
* @note tiny programs might need to explicitly YOINK(realloc)
* @see test/libc/runtime/grow_test.c
*/
bool grow(void *pp, size_t *capacity, size_t itemsize, size_t extra) {
void **p, *p1, *p2;
size_t n1, n2; /* item counts */
size_t t1, t2; /* byte counts */
extra += GUARANTEE_TERMINATOR; /* p ⊃ p[𝑖]==0 */
p = (void **)pp;
assert(itemsize);
assert((*p && *capacity) || (!*p && !*capacity));
assert(!isheap(*p) || ((intptr_t)*p & 15) == 0);
p1 = isheap(*p) ? *p : NULL;
p2 = NULL;
n1 = *capacity;
n2 = (*p ? n1 + (n1 >> 1) : max(4, INITIAL_CAPACITY / itemsize)) + extra;
if (sizemultiply(&t1, n1, itemsize) && sizemultiply(&t2, n2, itemsize)) {
if (weaken(realloc) && (p2 = weaken(realloc)(p1, ROUNDUP(t2, 32)))) {
if (!p1 && *p) memcpy(p2, *p, t1);
memset((char *)p2 + t1, 0, t2 - t1);
*capacity = n2;
*p = p2;
return true;
} else {
enomem();
}
} else {
eoverflow();
}
return false;
}

View file

@ -0,0 +1,66 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/alg/alg.h"
#include "libc/str/str.h"
static unsigned heapsortmax(int32_t (*A)[2], unsigned n, unsigned i, unsigned j,
unsigned k) {
unsigned m = i;
if (j < n && A[j][0] > A[m][0]) m = j;
if (k < n && A[k][0] > A[m][0]) m = k;
return m;
}
static void heapsortdown(int32_t (*A)[2], unsigned n, unsigned i) {
unsigned j;
int32_t t[2];
for (;;) {
unsigned j = heapsortmax(A, n, i, 2 * i + 1, 2 * i + 2);
if (j == i) break;
memcpy(t, A[i], sizeof(t));
memcpy(A[i], A[j], sizeof(t));
memcpy(A[j], t, sizeof(t));
i = j;
}
}
/**
* Sorts key-values.
*
* heapsortcar is a linearithmic / constant-memory / non-stable sorting
* function that's a tenth the size of the more generalized qsort() API.
* It can only sort arrays of 64-bit values, and comparisons happen by
* treating the lower 32-bits as a signed integer.
*
* @see test/libc/alg/heapsortcar_test.c
*/
void heapsortcar(int32_t (*A)[2], unsigned n) {
unsigned i;
int32_t t[2];
for (i = ((n - 2) / 2) + 1; i > 0; i--) {
heapsortdown(A, n, i - 1);
}
for (i = 0; i < n; i++) {
memcpy(t, A[n - i - 1], sizeof(t));
memcpy(A[n - i - 1], A[0], sizeof(t));
memcpy(A[0], t, sizeof(t));
heapsortdown(A, n - i - 1, 0);
}
}

145
libc/runtime/init.S Normal file
View file

@ -0,0 +1,145 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
#include "libc/runtime/internal.h"
#include "libc/sysv/consts/prot.h"
#include "libc/dce.h"
.yoink __FILE__
/ Decentralized function for process initialization.
/
/ Modules may inject cheap data structure initialization code into
/ this function using the .init.start and .init.end macros. That
/ code can use the LODS and STOS instructions to initialize memory
/ that's restricted to read-only after initialization by PIRO.
/
/ This is fast, since the linker is able to roll-up initialization
/ for large codebases comprised of many modules, into a perfectly
/ linear order. It also enables a common pattern we use, which we
/ call Referencing Is Initialization (RII).
/
/ C/C++ code should favor using ordinary constructors, since under
/ normal circumstances the compiler will clobber RDI and RSI which
/ are granted special meanings within this function.
/
/ @param r12 is argc (still callee saved)
/ @param r13 is argv (still callee saved)
/ @param r14 is envp (still callee saved)
/ @param r15 is envp (still callee saved)
/ @note rdi is __init_bss_start (callee monotonic lockstep)
/ @note rsi is __init_rodata_start (callee monotonic lockstep)
/ @see .init.start & .init.end (libc/macros.inc)
/ @see ape/ape.lds
.section .initprologue,"ax",@progbits
.type _init,@function
.globl _init
.comm g_runstate,4
_init: push %rbp
mov %rsp,%rbp
.profilable
ezlea __init_bss_start,di
ezlea __init_rodata_start,si
.previous/*
...
decentralized content
...
*/.section .initepilogue,"ax",@progbits
#if IsModeDbg()
_init_check_rdi_rsi:
jmp 2f
1: call abort
2: ezlea __init_bss_end,ax
cmp %rax,%rdi
jne 1b
ezlea __init_rodata_end,ax
cmp %rax,%rsi
jne 1b
3: .endfn _init_check_rdi_rsi
#endif
_woot: leave
ret
.previous
/ Decentralized section for packed data structures & initializers.
/
/ @see .initro (libc/macros.inc)
/ @see ape/ape.lds
.section .initroprologue,"a",@progbits
.type __init_rodata_start,@object
.type __init_rodata_end,@object
.globl __init_rodata_start,__init_rodata_end
.hidden __init_rodata_start,__init_rodata_end
.align __SIZEOF_POINTER__
__init_rodata_start:
.previous/*
...
decentralized content
...
*/.section .initroepilogue,"a",@progbits
__init_rodata_end:
.byte 0x90
.previous
/ Decentralized section for unpacked data structures.
/
/ Data in this section becomes read-only after initialization.
/
/ @see .piro.bss.init (libc/macros.inc)
/ @see libc/runtime/piro.c
/ @see ape/ape.lds
.section .piro.bss.init.1,"aw",@nobits
.type __init_bss_start,@object
.type __init_bss_end,@object
.globl __init_bss_start,__init_bss_end
.hidden __init_bss_start,__init_bss_end
.align __SIZEOF_POINTER__
__init_bss_start:
.previous/*
...
decentralized content
...
*/.section .piro.bss.init.3,"aw",@nobits
__init_bss_end:
.byte 0
.previous
/ Special area for Windows NT support code.
/
/ Isolating this code adds value for Windows users by minimizing
/ page faults through improved locality. On System Five the PIRO
/ runtime can unmap these pages.
/
/ @see libc/runtime/piro.c
/ @see ape/ape.lds
.section .textwindowsprologue,"ax",@progbits
.type __text_windows_start,@object
.type __text_windows_end,@object
.globl __text_windows_start,__text_windows_end
.hidden __text_windows_start,__text_windows_end
int3
__text_windows_start:
.previous/*
...
decentralized content
...
*/.section .textwindowsepilogue,"ax",@progbits
__text_windows_end:
int3
.previous

35
libc/runtime/internal.h Normal file
View file

@ -0,0 +1,35 @@
#ifndef COSMOPOLITAN_LIBC_RUNTIME_INTERNAL_H_
#define COSMOPOLITAN_LIBC_RUNTIME_INTERNAL_H_
#include "libc/dce.h"
#include "libc/runtime/runtime.h"
#define RUNSTATE_INITIALIZED (1 << 0)
#define RUNSTATE_BROKEN (1 << 1)
#define RUNSTATE_TERMINATE (1 << 2)
#define STACK_CEIL 0x700000000000ul
#define STACK_SIZE FRAMESIZE
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
hidden extern char **g_freebsdhint;
hidden extern unsigned g_runstate;
hidden extern void *g_stacktop;
void _init(void) hidden;
void __piro(int) hidden;
void *__cxa_finalize(void *) hidden;
int getdosargv(const char16_t *, char *, size_t, char **, size_t) hidden;
void __stack_chk_fail(void) noreturn relegated;
void __stack_chk_fail_local(void) noreturn relegated hidden;
forceinline void AssertNeverCalledWhileTerminating(void) {
if (!NoDebug() && (g_runstate & RUNSTATE_TERMINATE)) {
abort();
}
}
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_RUNTIME_INTERNAL_H_ */

View file

@ -0,0 +1,75 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/progn.h"
#include "libc/bits/safemacros.h"
#include "libc/mem/mem.h"
#include "libc/runtime/interruptiblecall.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/sa.h"
#include "libc/sysv/consts/sig.h"
STATIC_YOINK("_init_onntconsoleevent");
static struct InterruptibleCall *g_interruptiblecall;
noreturn static void interruptcall(int sig) {
longjmp(g_interruptiblecall->jb, 1);
unreachable;
}
/**
* Calls function that may be cancelled by a signal.
*
* @param state is allocated and zero'd by the caller; statesig and
* statesa_new.sa_mask may be set; it may be re-used w/o
* reinitializing; it may be static or heap memory; it may be stack
* memory if re-entrant behavior isn't needed
* @return the value returned by callback or -1 on interrupt; they may
* be differentiated using the statereturnval filed, which is only
* modified by this function when callbacks succeed
*/
intptr_t interruptiblecall(struct InterruptibleCall *icall,
intptr_t callback(intptr_t p1, intptr_t p2,
intptr_t p3, intptr_t p4),
intptr_t p1, intptr_t p2, intptr_t p3, intptr_t p4) {
intptr_t rc;
if (!icall->sig) icall->sig = SIGINT;
icall->sa_new.sa_handler = interruptcall;
icall->sa_new.sa_flags |= SA_RESTART | SA_RESETHAND;
if ((rc = (sigaction)(icall->sig, &icall->sa_new, &icall->sa_old)) != -1) {
g_interruptiblecall = PROGN((icall->prev = g_interruptiblecall), icall);
if (!setjmp(icall->jb)) {
icall->returnval = rc = callback(p1, p2, p3, p4);
} else {
rc = -1;
}
asm volatile("" ::: "memory");
struct InterruptibleCall *unwind;
for (;;) {
unwind = g_interruptiblecall;
(sigaction)(unwind->sig, &unwind->sa_old, NULL);
g_interruptiblecall = unwind->prev;
if (unwind == icall) break;
free_s(&unwind);
}
icall->prev = NULL;
}
return rc;
}

View file

@ -0,0 +1,26 @@
#ifndef COSMOPOLITAN_LIBC_RUNTIME_INTERRUPTIBLECALL_H_
#define COSMOPOLITAN_LIBC_RUNTIME_INTERRUPTIBLECALL_H_
#include "libc/runtime/runtime.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/calls.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct InterruptibleCall {
struct InterruptibleCall *prev;
intptr_t returnval;
int sig;
int flags;
jmp_buf jb;
struct sigaction sa_new;
struct sigaction sa_old;
};
intptr_t interruptiblecall(struct InterruptibleCall *state,
intptr_t callback(intptr_t p1, intptr_t p2,
intptr_t p3, intptr_t p4),
intptr_t p1, intptr_t p2, intptr_t p3, intptr_t p4);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_RUNTIME_INTERRUPTIBLECALL_H_ */

38
libc/runtime/isheap.c Normal file
View file

@ -0,0 +1,38 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/runtime/mappings.h"
/**
* Returns false if address can't be heap memory.
*/
bool isheap(void *p) {
size_t i;
struct MemoryCoord c;
if (!(kStackBottom <= (intptr_t)p && (intptr_t)p < kStackCeiling)) {
c = ADDRSIZE_TO_COORD(p, FRAMESIZE);
if ((i = findmapping(c.x))) {
return ISOVERLAPPING(_mm.p[i - 1], c);
} else {
return false;
}
} else {
return false;
}
}

23
libc/runtime/issetugid.c Normal file
View file

@ -0,0 +1,23 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/auxv.h"
int issetugid(void) { return !!getauxval(AT_SECURE); }

View file

@ -0,0 +1,38 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
.yoink __FILE__
#define BYTES 64
/ RII constant holding 'C:/WINDOWS/SYSTEM32' directory.
/
/ @note guarantees trailing slash if non-empty
.initbss 300,_init_kNtSystemDirectory
kNtSystemDirectory:
.zero BYTES
.endobj kNtSystemDirectory,globl
.previous
.init.start 300,_init_kNtSystemDirectory
pushpop BYTES,%rdx
mov __imp_GetSystemDirectoryA(%rip),%rax
call __getntsyspath
.init.end 300,_init_kNtSystemDirectory

View file

@ -0,0 +1,38 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
.yoink __FILE__
#define BYTES 64
/ RII constant holding 'C:/WINDOWS' directory.
/
/ @note guarantees trailing slash if non-empty
.initbss 300,_init_kNtWindowsDirectory
kNtWindowsDirectory:
.zero BYTES
.endobj kNtWindowsDirectory,globl
.previous
.init.start 300,_init_kNtWindowsDirectory
pushpop BYTES,%rdx
mov __imp_GetWindowsDirectoryA(%rip),%rax
call __getntsyspath
.init.end 300,_init_kNtWindowsDirectory

View file

@ -0,0 +1,33 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
.yoink __FILE__
mapanon:push %rbp
mov %rsp,%rbp
push %rbx
push %rbx
ezlea _base,bx
call __mapanon
pop %rbx
pop %rbx
pop %rbp
ret
.endfn mapanon,globl

28
libc/runtime/mapanon.c Normal file
View file

@ -0,0 +1,28 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/calls.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/prot.h"
void *__mapanon(size_t mapsize) {
return mmap(NULL, mapsize, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_NONBLOCK | MAP_ANONYMOUS, -1, 0);
}

31
libc/runtime/mapelfread.c Normal file
View file

@ -0,0 +1,31 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/elf/def.h"
#include "libc/elf/elf.h"
#include "libc/runtime/ezmap.h"
Elf64_Ehdr *mapelfread(const char *filename, struct MappedFile *mf) {
if (mapfileread(filename, mf) != -1 && iself64binary(mf->addr, mf->size)) {
return mf->addr;
} else {
unmapfile(mf);
return NULL;
}
}

22
libc/runtime/mappings.c Normal file
View file

@ -0,0 +1,22 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/runtime/mappings.h"
struct Mappings _mm;

78
libc/runtime/mappings.h Normal file
View file

@ -0,0 +1,78 @@
#ifndef COSMOPOLITAN_LIBC_RUNTIME_MAPPINGS_H_
#define COSMOPOLITAN_LIBC_RUNTIME_MAPPINGS_H_
#include "libc/dce.h"
#include "libc/macros.h"
#include "libc/runtime/runtime.h"
#define MMAP_MAX 300 /* TODO: crunch */
#define kStackCeiling 0x0000700000000000L
#define kStackBottom 0x0000600000000000L
#define kFixedMappingsStart 0x0000100000000000L /* cosmo won't auto-assign */
#define kFixedMappingsSize 0x0000100000000000L /* 16TB */
#define kMappingsStart 0x0000200000000000L /* cosmo auto-assigns here */
#define kMappingsSize 0x0000100000000000L /* 16TB */
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define ISOVERLAPPING(C1, C2) \
(((C1).x >= (C2).x && (C1).x <= (C2).y) || \
((C1).y >= (C2).x && (C1).y <= (C2).y))
#define ADDR_TO_COORD(ADDR) \
(int)(((intptr_t)(ADDR) & ~(FRAMESIZE - 1)) / FRAMESIZE)
#define COORD_TO_ADDR(COORD) (void *)((intptr_t)(COORD)*FRAMESIZE)
#define COORD_TO_SIZE(COORD) (void *)((intptr_t)(COORD)*FRAMESIZE)
#define ADDRSIZE_TO_COORD(ADDR, SIZE) \
((struct MemoryCoord){ \
.x = ADDR_TO_COORD(ADDR), \
.y = ADDR_TO_COORD(ADDR) + \
((unsigned)(ROUNDUP((SIZE), FRAMESIZE) / FRAMESIZE) - 1)})
#define COORD_TO_ADDRSIZE(COORD) \
((struct AddrSize){ \
.addr = COORD_TO_ADDR((COORD).x), \
.size = ((size_t)((COORD).y - (COORD).x + 1) * FRAMESIZE)})
#define GRANULATE_ADDRSIZE(ADDR, SIZE) \
do { \
struct AddrSize AdSiz; \
struct MemoryCoord MemCo; \
MemCo = ADDRSIZE_TO_COORD(*(ADDR), *(SIZE)); \
AdSiz = COORD_TO_ADDRSIZE(MemCo); \
*(ADDR) = AdSiz.addr; \
*(SIZE) = AdSiz.size; \
} while (0)
struct AddrSize {
void *addr;
size_t size;
};
/**
* Ordered inclusive 64kb-granular ranges on NexGen32e w/o PML5.
* c.𝑥 c.𝑦 so say c all.
* cₙ.𝑥 cₙ.𝑥 so say c all.
*/
struct Mappings {
size_t i;
struct MemoryCoord {
int32_t x, y;
} p[MMAP_MAX];
int64_t h[MMAP_MAX];
};
extern struct Mappings _mm;
bool isheap(void *);
size_t findmapping(int32_t);
size_t findmapping_(int32_t, const struct MemoryCoord *, size_t);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_RUNTIME_MAPPINGS_H_ */

46
libc/runtime/mergepages.S Normal file
View file

@ -0,0 +1,46 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/dce.h"
#include "libc/sysv/consts/madv.h"
#include "libc/sysv/consts/nr.h"
#include "libc/macros.h"
.text.startup
.yoink __FILE__
/ Merges page table entries for pages with identical content.
/
/ This is a hint. It can help trim physical memory for things
/ like extremely sparse data.
/
/ @param rdi is base address
/ @param rsi is byte length
mergepages:
.leafprologue
.profilable
mov $-PAGESIZE,%rax
and %rax,%rdi
and %rax,%rsi
mov __NR_madvise,%eax
mov MADV_MERGEABLE,%edx
test %edx,%edx
jz 1f
syscall
1: .leafepilogue
.endfn mergepages,globl

View file

@ -0,0 +1,143 @@
#ifndef COSMOPOLITAN_LIBC_INTERNAL_MISSIONCRITICAL_H_
#define COSMOPOLITAN_LIBC_INTERNAL_MISSIONCRITICAL_H_
#include "libc/bits/bits.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/nexgen32e/nexgen32e.h"
#include "libc/nt/console.h"
#include "libc/nt/enum/version.h"
#include "libc/nt/ntdll.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/teb.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/nr.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
/**
* @fileoverview Mission critical system calls.
*/
#define PRINT(STR) __print(STR, tinystrlen(STR))
#define NT_HAVE_IMPORT(SLOT) \
((void *)*SLOT && *SLOT != (void *)&missingno /* see libc/crt/crt.S */)
#define _EXIT(rc) \
({ \
int ExitAx; \
asm volatile("syscall" \
: "=a"(ExitAx) \
: "0"(__NR_exit), "D"(rc) \
: "rcx", "r11", "cc", "memory"); \
ExitAx; \
})
#define GETPID() \
({ \
int Res; \
asm("syscall" : "=a"(Res) : "0"(__NR_getpid) : "rcx", "r11", "cc"); \
Res; \
})
#define KILL(pid, sig) \
({ \
int KillAx; \
unsigned char Cf; \
asm volatile(CFLAG("clc\n\t" \
"syscall") \
: CF(Cf), "=a"(KillAx) \
: "1"(__NR_kill), "D"(pid), "S"(sig) \
: "rcx", "r11", "cc", "memory"); \
Cf ? -KillAx : KillAx; \
})
#define RAISE(SIG) \
({ \
int RaiseAx = -1; \
int Sig = (SIG); \
if (Sig == SIGTRAP) { \
DebugBreak(); \
} else if (!IsWindows()) { \
RaiseAx = KILL(GETPID(), Sig); \
} else { \
switch (Sig) { \
case SIGINT: \
GenerateConsoleCtrlEvent(kNtCtrlCEvent, 0); \
break; \
case SIGHUP: \
GenerateConsoleCtrlEvent(kNtCtrlCloseEvent, 0); \
break; \
case SIGQUIT: \
GenerateConsoleCtrlEvent(kNtCtrlBreakEvent, 0); \
break; \
default: \
for (;;) TerminateProcess(GetCurrentProcess(), 128 + Sig); \
} \
} \
RaiseAx; \
})
#define SCHED_YIELD() \
({ \
int64_t SyAx; \
if (!IsWindows()) { \
asm volatile("syscall" \
: "=a"(SyAx) \
: "0"(__NR_sched_yield) \
: "rcx", "r11", "cc", "memory"); \
} else { \
NtYieldExecution(); \
} \
0; \
})
#define WAIT4(PID, OPT_OUT_WSTATUS, OPTIONS, OPT_OUT_RUSAGE) \
({ \
int64_t WaAx; \
if (!IsWindows()) { \
register void *Reg10 asm("r10") = (OPT_OUT_RUSAGE); \
asm volatile("syscall" \
: "=a"(WaAx) \
: "0"(__NR_wait4), "D"(PID), "S"(OPT_OUT_WSTATUS), \
"d"(OPTIONS), "r"(Reg10) \
: "rcx", "r11", "cc", "memory"); \
} else { \
WaAx = wait4$nt(PID, OPT_OUT_WSTATUS, OPTIONS, OPT_OUT_RUSAGE); \
} \
WaAx; \
})
#if 0
/**
* Exits on Windows the hard way.
*/
#endif
#define NT_TERMINATE_PROCESS() \
do \
if (NtGetVersion() < kNtVersionFuture) { \
int64_t ax, cx; \
do \
asm volatile( \
"syscall" /* hook THIS system call */ \
: "=a"(ax), "=c"(cx) \
: "0"(NtGetVersion() < kNtVersionWindows8 \
? 0x0029 \
: NtGetVersion() < kNtVersionWindows81 \
? 0x002a \
: NtGetVersion() < kNtVersionWindows10 ? 0x002b \
: 0x002c), \
"1"(-1L /* GetCurrentProcess() */), "d"(42) \
: "r11", "cc", "memory"); \
while (!ax); \
} \
while (0)
interruptfn void __print(const void *, size_t);
#define LOAD_DEFAULT_RBX() /* disabled for now b/c clang */
#define RESTORE_RBX() /* disabled for now b/c clang */
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_INTERNAL_MISSIONCRITICAL_H_ */

155
libc/runtime/mmap.c Normal file
View file

@ -0,0 +1,155 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/macros.h"
#include "libc/nt/memory.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/mappings.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/errfuns.h"
#define VIP(X) (void *)(intptr_t)(X)
struct DirectMap {
void *addr;
int64_t maphandle;
};
static textwindows struct DirectMap directmap$nt(void *addr, size_t size,
unsigned prot, unsigned flags,
int fd, int64_t off) {
struct DirectMap res;
if ((res.maphandle = CreateFileMappingNuma(
fd != -1 ? g_fds.p[fd].handle : kNtInvalidHandleValue,
&kNtIsInheritable, prot2nt(prot, flags), size >> 32, size, NULL,
kNtNumaNoPreferredNode))) {
if (!(res.addr = MapViewOfFileExNuma(res.maphandle, fprot2nt(prot, flags),
off >> 32, off, size, addr,
kNtNumaNoPreferredNode))) {
CloseHandle(res.maphandle);
res.maphandle = kNtInvalidHandleValue;
res.addr = VIP(winerr());
}
} else {
res.maphandle = kNtInvalidHandleValue;
res.addr = VIP(winerr());
}
return res;
}
static struct DirectMap directmap(void *addr, size_t size, unsigned prot,
unsigned flags, int fd, int64_t off) {
if (!IsWindows()) {
return (struct DirectMap){mmap$sysv(addr, size, prot, flags, fd, off),
kNtInvalidHandleValue};
} else {
return directmap$nt(addr, size, prot, flags, fd, off);
}
}
/**
* Beseeches system for page-table entries.
*
* @param addr optionally requests a particular virtual base address,
* which needs to be 64kb aligned if passed (for NT compatibility)
* @param size should be >0 and multiple of PAGESIZE
* @param prot can have PROT_READ, PROT_WRITE, PROT_EXEC, PROT_NONE, etc.
* @param flags can have MAP_ANONYMOUS, MAP_SHARED, MAP_PRIVATE, etc.
* @param fd is an open()'d file descriptor whose contents shall be
* mapped, and is ignored if MAP_ANONYMOUS is specified
* @param offset specifies absolute byte index of fd's file for mapping,
* and should be zero if MAP_ANONYMOUS is specified
* @return virtual base address of new mapping, or MAP_FAILED w/ errno
*/
void *mmap(void *addr, size_t size, int prot, int flags, int fd, int64_t off) {
size_t i;
intptr_t p;
struct DirectMap dm;
struct MemoryCoord c;
p = (intptr_t)addr;
assert(!(0 < p && p < 0x200000));
assert(-0x800000000000L <= p && p <= 0x7fffffffffffL);
assert((flags & MAP_PRIVATE) ^ (flags & MAP_SHARED));
assert((flags & MAP_ANONYMOUS) ^ (fd != -1));
assert(off % PAGESIZE == 0);
assert(size > 0);
if (!(IsWindows() && fd != -1)) {
size = ROUNDUP(size, FRAMESIZE);
}
if (flags & MAP_FIXED) {
assert(addr != NULL);
assert((intptr_t)addr % FRAMESIZE == 0);
} else {
if (!addr) {
if (_mm.i) {
addr = COORD_TO_ADDR(_mm.p[_mm.i - 1].y + 1);
for (i = _mm.i; i; --i) {
if (_mm.p[i - 1].y + 1 + size / FRAMESIZE <=
ADDR_TO_COORD(kMappingsStart + kMappingsSize) &&
_mm.p[i - 1].y + 1 >= ADDR_TO_COORD(kMappingsStart)) {
addr = COORD_TO_ADDR(_mm.p[i - 1].y + 1);
break;
}
}
} else {
addr = VIP(kMappingsStart);
}
}
addr = (void *)ROUNDDOWN((intptr_t)addr, FRAMESIZE);
}
if (_mm.i == MMAP_MAX) {
return VIP(enomem());
}
if (flags & MAP_FIXED) {
munmap(addr, size);
} else {
c = ADDRSIZE_TO_COORD(addr, size);
if ((i = findmapping(c.y)) && ISOVERLAPPING(c, _mm.p[i - 1])) {
return VIP(einval());
}
}
dm = directmap(addr, size, prot, flags | MAP_FIXED, fd, off);
if (dm.addr == MAP_FAILED) return MAP_FAILED;
i = findmapping(ADDR_TO_COORD(dm.addr));
if (i < _mm.i) {
memmove(&_mm.p[i + 1], &_mm.p[i],
(intptr_t)&_mm.p[_mm.i] - (intptr_t)&_mm.p[i]);
memmove(&_mm.h[i + 1], &_mm.h[i],
(intptr_t)&_mm.h[_mm.i] - (intptr_t)&_mm.h[i]);
}
_mm.p[i] = ADDRSIZE_TO_COORD(dm.addr, size);
_mm.h[i] = dm.maphandle;
_mm.i++;
assert((intptr_t)dm.addr % __BIGGEST_ALIGNMENT__ == 0);
return dm.addr;
}

26
libc/runtime/mremap.c Normal file
View file

@ -0,0 +1,26 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/calls.h"
#include "libc/sysv/errfuns.h"
void *mremap(void *old_address, size_t old_size, size_t new_size, int flags,
void *new_address) {
return (void *)(intptr_t)enosys();
}

36
libc/runtime/msync-nt.c Normal file
View file

@ -0,0 +1,36 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/internal.h"
#include "libc/nt/files.h"
#include "libc/nt/memory.h"
#include "libc/runtime/mappings.h"
textwindows int msync$nt(void *addr, size_t size, int flags) {
size_t i, j;
struct MemoryCoord c;
if (!FlushViewOfFile(addr, size)) return winerr();
j = findmapping(ADDR_TO_COORD(addr));
c = ADDRSIZE_TO_COORD(addr, size);
for (i = j; i; --i) {
if (!ISOVERLAPPING(_mm.p[i - 1], c)) break;
FlushFileBuffers(_mm.h[i - 1]);
}
return 0;
}

41
libc/runtime/msync.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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/macros.h"
#include "libc/runtime/mappings.h"
#include "libc/sysv/consts/msync.h"
/**
* Synchronize memory mapping changes to disk.
*
* @param flags needs MS_SYNC or MS_ASYNC and can have MS_INVALIDATE
* @return 0 on success or -1 w/ errno
*/
int msync(void *addr, size_t size, int flags) {
assert(((flags & MS_SYNC) ^ (flags & MS_ASYNC)) || !(MS_SYNC && MS_ASYNC));
if (!IsWindows()) {
return msync$sysv(addr, size, flags);
} else {
return msync$nt(addr, size, flags);
}
}

View file

@ -0,0 +1,33 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
.yoink __FILE__
munmap: push %rbp
mov %rsp,%rbp
push %rbx
push %rbx
ezlea _base,bx
call __munmap
pop %rbx
pop %rbx
pop %rbp
ret
.endfn munmap,globl

106
libc/runtime/munmap.c Normal file
View file

@ -0,0 +1,106 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/nt/memory.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/mappings.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/fileno.h"
/**
* Releases memory pages.
*
* @param addr is a pointer within any memory mapped region the process
* has permission to control, such as address ranges returned by
* mmap(), the program image itself, etc.
* @param size is the amount of memory to unmap, which should be a
* multiple of PAGESIZE, and may be a subset of that which was
* mapped previously
* @return 0 on success, or -1 w/ errno
*/
int __munmap(void *addr, size_t size) {
int rc;
intptr_t p;
size_t i, j;
struct AddrSize a;
struct MemoryCoord c, m;
p = (intptr_t)addr;
assert(!(0 < p && p < 0x200000));
assert(-0x800000000000L <= p && p <= 0x7fffffffffffL);
if (!size) return 0;
if (!addr || addr == MAP_FAILED) return 0;
if (addr == NULL && size <= 0x200000) return 0;
addr = (void *)ROUNDDOWN((intptr_t)addr, FRAMESIZE);
size = ROUNDUP(size, FRAMESIZE);
rc = 0;
c = ADDRSIZE_TO_COORD(addr, size);
j = findmapping(c.y);
for (i = j; i; --i) {
m = _mm.p[i - 1];
assert(m.x <= m.y);
assert(c.y >= m.x);
if (c.x > m.y) {
break;
} else if (c.x > m.x && c.y < m.y) {
/* remove middle portion */
assert(!"map hole punching not implemented");
} else if (c.x > m.x && c.y >= m.y) {
/* remove righthand portion */
assert(!"map hole punching not implemented");
/* _mm.p[i - 1].y = c.x - 1; */
/* i++; */
/* break; */
} else if (c.x <= m.x && c.y < m.y) {
/* remove lefthand portion */
assert(!"map hole punching not implemented");
/* _mm.p[i - 1].x = c.y + 1; */
/* j--; */
} else if ((m.x >= c.x && m.x <= c.y) && (m.y >= c.x && m.y <= c.y)) {
a = COORD_TO_ADDRSIZE(m);
if (!IsWindows()) {
rc |= munmap$sysv(a.addr, a.size);
} else {
if (!UnmapViewOfFile(a.addr)) rc = -1;
if (!CloseHandle(_mm.h[i - 1])) rc = -1;
}
} else {
assert(!"wut");
}
}
if (i < j) {
if (j < _mm.i) {
memmove(&_mm.p[i], &_mm.p[j],
(intptr_t)&_mm.p[_mm.i] - (intptr_t)&_mm.p[j]);
memmove(&_mm.h[i], &_mm.h[j],
(intptr_t)&_mm.h[_mm.i] - (intptr_t)&_mm.h[j]);
}
_mm.i -= j - i;
}
return rc;
}

38
libc/runtime/munmap_s.c Normal file
View file

@ -0,0 +1,38 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
#include "libc/bits/pushpop.h"
#include "libc/calls/calls.h"
#include "libc/runtime/mappings.h"
#include "libc/runtime/runtime.h"
/**
* Closes memory mapping, the Cosmopolitan way.
*
* The caller's address holder is set to MAP_FAILED (-1) which is a
* no-op for subsequent invocations.
*
* @return 0 on success, or -1 w/ errno
*/
int munmap_s(void *addrp, uint64_t size) {
void **addrpp = (void **)addrp;
void *addr = (void *)pushpop(-1L);
return munmap(lockxchg(addrpp, &addr), size);
}

View file

@ -0,0 +1,37 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/nt/ntdll.h"
#include "libc/nt/struct/ldr.h"
#include "libc/nt/struct/ldrdatatableentry.h"
#include "libc/nt/struct/linkedlist.h"
#include "libc/nt/struct/teb.h"
#include "libc/str/str.h"
textwindows const struct NtLdrDataTableEntry *NtGetModule(
const char *basename) {
struct NtLinkedList *head = &NtGetPeb()->Ldr->InLoadOrderModuleList;
struct NtLinkedList *ldr = head->Next;
do {
const struct NtLdrDataTableEntry *dll =
(const struct NtLdrDataTableEntry *)ldr;
if (strcasecmp8to16(basename, dll->BaseDllName.Data) == 0) return dll;
} while ((ldr = ldr->Next) && ldr != head);
return NULL;
}

View file

@ -0,0 +1,60 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/alg/alg.h"
#include "libc/calls/calls.h"
#include "libc/elf/def.h"
#include "libc/elf/elf.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/prot.h"
/**
* Maps debuggable binary into memory and indexes symbol addresses.
*
* @return object freeable with closesymboltable(), or NULL w/ errno
*/
struct SymbolTable *opensymboltable(const char *filename) {
struct SymbolTable *t = MAP_FAILED;
const Elf64_Sym *symtab;
if (filename && (t = mapanon(BIGPAGESIZE)) != MAP_FAILED &&
mapelfread(filename, &t->mf) &&
(t->name_base = getelfstringtable(t->elf, t->elfsize)) != NULL &&
(symtab = getelfsymboltable(t->elf, t->elfsize, &t->count)) &&
sizeof(struct SymbolTable) + sizeof(struct Symbol) * t->count <
(t->scratch = BIGPAGESIZE)) {
unsigned j = 0;
getelfvirtualaddressrange(t->elf, t->elfsize, &t->addr_base, &t->addr_end);
for (unsigned i = 0; i < t->count; ++i) {
const Elf64_Sym *sym = &symtab[i];
if (iselfsymbolcontent(sym) &&
(sym->st_value >= t->addr_base && sym->st_value <= t->addr_end)) {
t->symbols[j].addr_rva = (unsigned)(sym->st_value - t->addr_base);
t->symbols[j].name_rva = sym->st_name;
j++;
}
}
t->count = j;
heapsortcar((int32_t(*)[2])t->symbols, t->count);
} else {
closesymboltable(&t);
}
return t == MAP_FAILED ? NULL : t;
}

33
libc/runtime/peekall.S Normal file
View file

@ -0,0 +1,33 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "ape/relocations.h"
#include "libc/macros.h"
.yoink __FILE__
/ Loads all pages from program image into memory.
peekall:.leafprologue
ezlea _base,si
ezlea _end,cx
0: mov (%rsi),%eax
add $PAGESIZE,%rsi
cmp %rcx,%rsi
jb 0b
.leafepilogue
.endfn peekall,globl

71
libc/runtime/piro.c Normal file
View file

@ -0,0 +1,71 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
αcτµαlly pδrταblε εxεcµταblε § post-initialization read-only
*/
#include "libc/bits/bits.h"
#include "libc/bits/safemacros.h"
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/prot.h"
#define getaddr(section) ((intptr_t)weakaddr(section))
static textstartup void __piro_protect(intptr_t start, intptr_t end, int prot) {
ssize_t len = end - start;
if (len > 0 && start && start % PAGESIZE == 0 && len % PAGESIZE == 0) {
if (mprotect((void *)(unsigned long)start, len, prot) == -1) abort();
}
}
/**
* Protects memory initialized at startup.
* e.g. function hooks, unpacked data structures, etc.
*
* This is only performed for executables of nontrivial size. It won't
* break the build if the α linker script wasn't used. Test code is
* protected too, so we don't end up like Knight Capital.
*
* @param prot can have PROT_{NONE,READ,WRITE,EXEC}
* @see ape/ape.lds
* @see libc/_start.S
*/
textstartup void __piro(int prot) {
if (getaddr("main") < getaddr("__test_start")) {
__piro_protect(getaddr("__test_start"), getaddr("__test_end"), PROT_NONE);
}
__piro_protect(getaddr("__ro"), getaddr("_etext"), PROT_READ);
__piro_protect(getaddr("__piro_start"), getaddr("__piro_end"), prot);
}

71
libc/runtime/print.greg.c Normal file
View file

@ -0,0 +1,71 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#define ShouldUseMsabiAttribute() 1
#include "libc/dce.h"
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/missioncritical.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/nr.h"
static privileged void __print$nt(const void *data, size_t len) {
int64_t hand;
uint32_t wrote;
char xmm[256] aligned(16);
savexmm(&xmm[128]);
hand = __imp_GetStdHandle(kNtStdErrorHandle);
__imp_WriteFile(hand, data, len, &wrote, NULL);
__imp_FlushFileBuffers(hand);
loadxmm(&xmm[128]);
}
/**
* Prints string, by any means necessary.
*
* This function offers a subset of write(STDERR_FILENO) functionality.
* It's designed to work even when the runtime hasn't initialized, e.g.
* before _init() gets called.
*
* @param len can be computed w/ tinystrlen()
* @clob nothing except flags
* @see PRINT()
*/
privileged interruptfn void __print(const void *data, size_t len) {
int64_t ax, ordinal;
LOAD_DEFAULT_RBX();
if (NT_HAVE_IMPORT(__imp_WriteFile)) {
__print$nt(data, len);
} else {
ordinal = __NR_write > 0 ? __NR_write : IsXnu() ? 0x2000004 : 4;
asm volatile("syscall"
: "=a"(ax)
: "0"(ordinal), "D"(STDERR_FILENO), "S"(data), "d"(len)
: "rcx", "r11", "memory", "cc");
if (ax == -1 && !hostos && !__NR_write) {
asm volatile("syscall"
: "=a"(ax)
: "0"(ordinal), "D"(STDERR_FILENO), "S"(data), "d"(len)
: "rcx", "r11", "memory", "cc");
}
}
RESTORE_RBX();
}

33
libc/runtime/progname.S Normal file
View file

@ -0,0 +1,33 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 sw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
.yoink __FILE__
/ Provides argv[0] The BSD Way.
.initbss 300,_init___progname
__progname:
.quad 0
.endobj __progname,globl,hidden
.previous
.init.start 300,_init___progname
mov %r13,%rax
stosq
.init.end 300,_init___progname

View file

@ -0,0 +1,38 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 sw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
.yoink __FILE__
/ Supplies basename(argv[0]) The GNU Way.
.initbss 400,_init_program_invocation_short_name
program_invocation_short_name:
.quad 0
.endobj program_invocation_short_name,globl
.previous
.init.start 400,_init_program_invocation_short_name
push %rdi
push %rsi
mov (%r13),%rdi
call basename
pop %rsi
pop %rdi
stosq
.init.end 400,_init_program_invocation_short_name

34
libc/runtime/quick_exit.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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
/**
* Terminates process normally, running minimal cleanup.
* @noreturn
*/
noreturn textexit void quick_exit(int rc) {
if (weaken(fflush)) {
if (weaken(stdout)) weaken(fflush)(*weaken(stdout));
if (weaken(stderr)) weaken(fflush)(*weaken(stderr));
}
_Exit(rc);
}

21
libc/runtime/rbx.h Normal file
View file

@ -0,0 +1,21 @@
#ifndef COSMOPOLITAN_LIBC_RUNTIME_RBX_H_
#define COSMOPOLITAN_LIBC_RUNTIME_RBX_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#if 0
#ifndef __llvm__
register uint8_t *__rbx asm("rbx");
#else
#define __rbx \
({ \
register uint8_t *Rbx asm("rbx"); \
asm("" : "=r"(Rbx)); \
Rbx; \
})
#endif
#endif
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_RUNTIME_RBX_H_ */

17
libc/runtime/ring.h Normal file
View file

@ -0,0 +1,17 @@
#ifndef COSMOPOLITAN_LIBC_RUNTIME_RING_H_
#define COSMOPOLITAN_LIBC_RUNTIME_RING_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct RingBuffer {
void *p;
char *_addr;
size_t _size;
};
void *ringalloc(struct RingBuffer *, size_t);
int ringfree(struct RingBuffer *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_RUNTIME_RING_H_ */

74
libc/runtime/ringalloc.c Normal file
View file

@ -0,0 +1,74 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/limits.h"
#include "libc/macros.h"
#include "libc/runtime/ring.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/prot.h"
/**
* Allocates ring buffer.
*
* Reads/writes wrap around on overflow.
*
*
* 𝑓..𝑓
*
*
*
* 𝑣..𝑣 𝑣..𝑣*
*
*
* @param r is metadata object owned by caller, initialized to zero
* @param n is byte length
* @return r->p, or NULL w/ errno
* @see ringfree(), balloc()
*/
void *ringalloc(struct RingBuffer *r, size_t n) {
void *a2;
int fd, rc;
size_t grain;
assert(!r->p);
assert(n > 0);
assert(n <= (INT_MAX - FRAMESIZE + 1) / 2);
if ((fd = openanon("ring", 0)) != -1) {
grain = ROUNDUP(n, FRAMESIZE);
rc = ftruncate(fd, grain * 2);
assert(rc != -1);
r->_size = grain * 2;
r->_addr = mmap(NULL, grain, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (r->_addr != MAP_FAILED) {
a2 = mmap(r->_addr + grain, grain, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_FIXED, fd, grain - n);
assert(a2 != MAP_FAILED);
r->p = r->_addr + grain - n;
if (IsWindows()) {
memset(r->p, 0, n); /* @see ftruncate() */
}
}
}
rc = close(fd);
assert(rc != -1);
return r->p;
}

35
libc/runtime/ringfree.c Normal file
View file

@ -0,0 +1,35 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/calls.h"
#include "libc/runtime/ring.h"
/**
* Frees ring buffer.
*
* @return 0 on success, or -1 w/ errno
*/
int ringfree(struct RingBuffer *r) {
if (r->p) {
r->p = NULL;
return munmap(r->_addr, r->_size);
} else {
return 0;
}
}

83
libc/runtime/runtime.h Normal file
View file

@ -0,0 +1,83 @@
#ifndef COSMOPOLITAN_LIBC_RUNTIME_RUNTIME_H_
#define COSMOPOLITAN_LIBC_RUNTIME_RUNTIME_H_
#include "libc/dce.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § runtime
*/
struct StackFrame {
struct StackFrame *next;
intptr_t addr;
};
typedef long jmp_buf[8] aligned(CACHELINE);
extern int g_argc; /* CRT */
extern char **g_argv; /* CRT */
extern char **environ; /* CRT */
extern unsigned long *g_auxv; /* CRT */
extern jmp_buf g_winmain; /* CRT */
extern char *program_invocation_name; /* RII */
extern char *program_invocation_short_name; /* RII */
extern uint64_t g_syscount; /* RII */
extern const uint64_t kStartTsc; /* RII */
extern const char kTmpPath[]; /* RII */
extern const char kNtSystemDirectory[]; /* RII */
extern const char kNtWindowsDirectory[]; /* RII */
extern unsigned char _base[] aligned(PAGESIZE); /* αpε */
extern char _ehead aligned(PAGESIZE); /* αpε */
extern char _ereal; /* αpε */
extern char __privileged_start; /* αpε */
extern char __test_start; /* αpε */
extern char __ro; /* αpε */
extern char _etext aligned(PAGESIZE); /* αpε */
extern char __piro_start; /* αpε */
extern char _edata aligned(PAGESIZE); /* αpε */
extern char __piro_end; /* αpε */
extern char _end aligned(PAGESIZE); /* αpε */
extern uint8_t __zip_start[]; /* αpε */
extern uint8_t __zip_end[]; /* αpε */
long missingno();
void mcount(void);
unsigned long getauxval(unsigned long);
void *mapanon(size_t) vallocesque attributeallocsize((1));
int setjmp(jmp_buf) libcesque returnstwice paramsnonnull();
void longjmp(jmp_buf, int) libcesque noreturn paramsnonnull();
void exit(int) noreturn;
void quick_exit(int) noreturn;
void _exit(int) libcesque noreturn;
void _Exit(int) libcesque noreturn;
void abort(void) noreturn noinstrument forcealignargpointer;
void abort_(void) asm("abort") noreturn noinstrument privileged;
void panic(void) noreturn noinstrument privileged;
void triplf(void) noreturn noinstrument privileged;
int __cxa_atexit(void *, void *, void *) libcesque;
int atfork(void *, void *) libcesque;
int atexit(void (*)(void)) libcesque;
void free_s(void *) paramsnonnull() libcesque;
int close_s(int *) paramsnonnull() libcesque;
char *getenv(const char *) paramsnonnull() nosideeffect libcesque;
int putenv(char *) paramsnonnull();
int setenv(const char *, const char *, int) paramsnonnull();
int unsetenv(const char *);
int clearenv(void);
void __fast_math(void);
void fpreset(void);
void savexmm(void *);
void loadxmm(void *);
void peekall(void);
int issetugid(void);
void weakfree(void *) libcesque;
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § runtime » optimizations
*/
#define _exit(RC) _Exit(RC)
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_RUNTIME_RUNTIME_H_ */

84
libc/runtime/runtime.mk Normal file
View file

@ -0,0 +1,84 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
#
# SYNOPSIS
#
# Cosmopolitan Runtime
#
# DESCRIPTION
#
# This package exports essential routines for userspace process
# initialization.
PKGS += LIBC_RUNTIME
LIBC_RUNTIME = $(LIBC_RUNTIME_A_DEPS) $(LIBC_RUNTIME_A)
LIBC_RUNTIME_ARTIFACTS += LIBC_RUNTIME_A
LIBC_RUNTIME_A = o/$(MODE)/libc/runtime/runtime.a
LIBC_RUNTIME_A_FILES := $(wildcard libc/runtime/*)
LIBC_RUNTIME_A_HDRS = $(filter %.h,$(LIBC_RUNTIME_A_FILES))
LIBC_RUNTIME_A_SRCS_S = $(filter %.S,$(LIBC_RUNTIME_A_FILES))
LIBC_RUNTIME_A_SRCS_C = $(filter %.c,$(LIBC_RUNTIME_A_FILES))
LIBC_RUNTIME_A_SRCS = \
$(LIBC_RUNTIME_A_SRCS_S) \
$(LIBC_RUNTIME_A_SRCS_C)
LIBC_RUNTIME_A_OBJS = \
$(LIBC_RUNTIME_A_SRCS:%=o/$(MODE)/%.zip.o) \
$(LIBC_RUNTIME_A_SRCS_S:%.S=o/$(MODE)/%.o) \
$(LIBC_RUNTIME_A_SRCS_C:%.c=o/$(MODE)/%.o)
LIBC_RUNTIME_A_CHECKS = \
$(LIBC_RUNTIME_A).pkg \
$(LIBC_RUNTIME_A_HDRS:%=o/$(MODE)/%.ok)
LIBC_RUNTIME_A_DIRECTDEPS = \
LIBC_BITS \
LIBC_CALLS \
LIBC_CONV \
LIBC_ELF \
LIBC_FMT \
LIBC_NEXGEN32E \
LIBC_NT_KERNELBASE \
LIBC_RAND \
LIBC_STR \
LIBC_STUBS \
LIBC_SYSV \
LIBC_SYSV_CALLS
LIBC_RUNTIME_A_DEPS := \
$(call uniq,$(foreach x,$(LIBC_RUNTIME_A_DIRECTDEPS),$($(x))))
$(LIBC_RUNTIME_A): \
libc/runtime/ \
$(LIBC_RUNTIME_A).pkg \
$(LIBC_RUNTIME_A_OBJS)
$(LIBC_RUNTIME_A).pkg: \
$(LIBC_RUNTIME_A_OBJS) \
$(foreach x,$(LIBC_RUNTIME_A_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/libc/runtime/asan.greg.o \
o/$(MODE)/libc/runtime/shadowargs.o \
o/$(MODE)/libc/runtime/__stack_chk_fail.o \
o/$(MODE)/libc/runtime/__stack_chk_guard.o: \
OVERRIDE_COPTS += \
$(NO_MAGIC)
# @see ape/ape.s for tuning parameters that make this safe
o/$(MODE)/libc/runtime/winmain.greg.o: \
DEFAULT_CPPFLAGS += \
-DSTACK_FRAME_UNLIMITED
LIBC_RUNTIME_LIBS = $(foreach x,$(LIBC_RUNTIME_ARTIFACTS),$($(x)))
LIBC_RUNTIME_SRCS = $(foreach x,$(LIBC_RUNTIME_ARTIFACTS),$($(x)_SRCS))
LIBC_RUNTIME_HDRS = $(foreach x,$(LIBC_RUNTIME_ARTIFACTS),$($(x)_HDRS))
LIBC_RUNTIME_BINS = $(foreach x,$(LIBC_RUNTIME_ARTIFACTS),$($(x)_BINS))
LIBC_RUNTIME_CHECKS = $(foreach x,$(LIBC_RUNTIME_ARTIFACTS),$($(x)_CHECKS))
LIBC_RUNTIME_OBJS = $(foreach x,$(LIBC_RUNTIME_ARTIFACTS),$($(x)_OBJS))
LIBC_RUNTIME_TESTS = $(foreach x,$(LIBC_RUNTIME_ARTIFACTS),$($(x)_TESTS))
$(LIBC_RUNTIME_OBJS): $(BUILD_FILES) libc/runtime/runtime.mk
.PHONY: o/$(MODE)/libc/runtime
o/$(MODE)/libc/runtime: $(LIBC_RUNTIME_CHECKS)

View file

@ -0,0 +1,61 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "ape/config.h"
#include "libc/bits/bits.h"
#include "libc/bits/pushpop.h"
#include "libc/nt/process.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/missioncritical.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/nr.h"
#define STACK_SMASH_MESSAGE "stack smashed\n"
/**
* Aborts program under enemy fire to avoid being taken alive.
*/
void __stack_chk_fail(void) {
if (!IsWindows()) {
const char *const msg = STACK_SMASH_MESSAGE;
const size_t len = pushpop(sizeof(STACK_SMASH_MESSAGE) - 1);
if (!IsMetal()) {
unsigned ax;
asm volatile("syscall"
: "=a"(ax)
: "0"(__NR_write), "D"(pushpop(STDERR_FILENO)), "S"(msg),
"d"(len)
: "rcx", "r11", "cc", "memory");
asm volatile("syscall"
: "=a"(ax)
: "0"(__NR_exit), "D"(pushpop(88))
: "rcx", "r11", "cc", "memory");
}
short(*ttys)[4] = (short(*)[4])XLM(BIOS_DATA_AREA);
unsigned long si;
unsigned cx;
asm volatile("rep outsb"
: "=S"(si), "=c"(cx)
: "0"(msg), "1"(len), "d"((*ttys)[1 /*COM2*/])
: "memory");
triplf();
}
NT_TERMINATE_PROCESS();
for (;;) TerminateProcess(GetCurrentProcess(), 42);
}

View file

@ -0,0 +1,22 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/runtime/internal.h"
void __stack_chk_fail_local(void) { __stack_chk_fail(); }

148
libc/runtime/startmain.S Normal file
View file

@ -0,0 +1,148 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/dce.h"
#include "libc/macros.h"
#include "libc/notice.inc"
#include "libc/runtime/internal.h"
#include "libc/sysv/consts/map.h"
#include "libc/dce.h"
#include "libc/runtime/mappings.h"
#include "libc/sysv/consts/prot.h"
.text.startup
.yoink __FILE__
/ Cosmopolitan process entrypoint.
/
/ @param r12 is argc
/ @param r13 is argv
/ @param r14 is environ
/ @param r15 is auxv
/ @noreturn
__executive:
.frame0
ezlea _base,bx
#ifdef __FAST_MATH__
call __fast_math
#endif
call _init
#if IsModeDbg()
call _init # _init() is idempotent
#endif
/*
#if !IsTiny()
/ Memory obfuscation for glibc, not for we
/
/ 64kb stack w/ 4kb guard alongside tuning in libc/integral/c.inc
/ e.g. -Werror=frame-larger-than=4096 is intended to guarantee no
/ stack overflow possible. We like malloc and only cleverly avoid
/ its use at the lowest levels of the runtime stack, without MMU.
/ We like this practicee because it's how Google runs production.
mov $kStackCeiling-STACKSIZE,%rdi
mov $STACKSIZE,%esi
mov $PROT_READ|PROT_WRITE,%edx
mov MAP_ANONYMOUS,%ecx
or MAP_FIXED,%ecx
or MAP_PRIVATE,%ecx
mov $-1,%r8d
xor %r9d,%r9d
call mmap
cmp $-1,%eax
je abort
lea STACKSIZE(%rax),%rsp
xor %ebp,%ebp
mov %rax,%rdi
mov $PAGESIZE,%esi
mov $PROT_NONE,%edx
call mprotect
cmp $-1,%eax
je abort
#endif
*/
orl $RUNSTATE_INITIALIZED,g_runstate(%rip)
ezlea __init_array_start,ax # static ctors in forward order
.weak __init_array_start # could be called multiple times
ezlea __init_array_end,cx # idempotency recommended
.weak __init_array_end # @see ape/ape.lds
1: cmp %rax,%rcx
je 2f
push %rax
push %rcx
call *(%rax)
pop %rcx
pop %rax
add $8,%rax
jmp 1b
2: nop
#if !IsTrustworthy()
mov $PROT_READ,%edi
call __piro
#endif
mov %r12,%rdi
mov %r13,%rsi
mov %r14,%rdx
.weak main
call main
mov %eax,%edi
call exit
.endfn __executive,weak,hidden
#ifdef __PG__
/ Enables plaintext function tracing if --ftrace flag passed.
/
/ The --ftrace CLI arg is removed before main() is called. This
/ code is intended for diagnostic purposes and assumes binaries
/ are trustworthy and stack isn't corrupted. Logging plain text
/ allows program structure to easily be visualized and hotspots
/ identified w/ sed | sort | uniq -c | sort. A compressed trace
/ can be made by appending --ftrace 2>&1 | gzip -4 >trace.gz to
/ the CLI arguments. Have fun.
/
/ @see libc/runtime/ftrace.greg.c
/ @see libc/crt/crt.S
.init.start 800,_init_ftrace
push %rdi
push %rsi
xor %edx,%edx
loadstr "--ftrace",di
xor %ecx,%ecx
0: inc %ecx
mov (%r13,%rcx,8),%rsi
test %edx,%edx
jz 1f
mov %rsi,-8(%r13,%rcx,8)
1: test %rsi,%rsi
jz 2f
test %edx,%edx
jnz 0b
call tinystrcmp
test %eax,%eax
setz %dl
jmp 0b
2: sub %rdx,%r12
test %edx,%edx
jz 2f
call ftrace_init
2: pop %rsi
pop %rdi
.init.end 800,_init_ftrace
#endif /* -pg */

14
libc/runtime/symbolic.h Normal file
View file

@ -0,0 +1,14 @@
#ifndef COSMOPOLITAN_LIBC_RUNTIME_SYMBOLIC_H_
#define COSMOPOLITAN_LIBC_RUNTIME_SYMBOLIC_H_
#ifdef __ASSEMBLER__
/* clang-format off */
#define SYMBOLIC(NAME) NAME(%rip)
#define LITERALLY(NAME) $NAME
/* clang-format on */
#else
#define SYMBOLIC(NAME) NAME
#define LITERALLY(NAME) NAME
#endif
#endif /* COSMOPOLITAN_LIBC_RUNTIME_SYMBOLIC_H_ */

59
libc/runtime/symbols.h Normal file
View file

@ -0,0 +1,59 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#ifndef COSMOPOLITAN_LIBC_SYMBOLS_H_
#define COSMOPOLITAN_LIBC_SYMBOLS_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
#include "libc/elf/elf.h"
#include "libc/runtime/ezmap.h"
COSMOPOLITAN_C_START_
struct Symbol {
unsigned addr_rva;
unsigned name_rva;
};
struct SymbolTable {
union {
struct MappedFile mf;
struct {
int64_t fd;
struct Elf64_Ehdr *elf;
size_t elfsize;
};
};
size_t scratch;
size_t count;
intptr_t addr_base;
intptr_t addr_end;
const char *name_base;
struct Symbol symbols[];
};
struct SymbolTable *getsymboltable(void);
const char *findcombinary(void);
const char *finddebugbinary(void);
struct SymbolTable *opensymboltable(const char *) nodiscard;
int closesymboltable(struct SymbolTable **);
const struct Symbol *bisectsymbol(struct SymbolTable *, intptr_t, int64_t *);
const char *getsymbolname(struct SymbolTable *, const struct Symbol *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_SYMBOLS_H_ */

26
libc/runtime/sysconf.c Normal file
View file

@ -0,0 +1,26 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/runtime/sysconf.h"
/**
* Returns configuration value about system.
* @param thing can be _SC_XXX
*/
long(sysconf)(int thing) { return __sysconf(thing); }

37
libc/runtime/sysconf.h Normal file
View file

@ -0,0 +1,37 @@
#ifndef COSMOPOLITAN_LIBC_RUNTIME_SYSCONF_H_
#define COSMOPOLITAN_LIBC_RUNTIME_SYSCONF_H_
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/auxv.h"
#define _SC_ARG_MAX 0
#define _SC_CLK_TCK 2
#define _SC_PAGESIZE 30
#define _SC_PAGE_SIZE 30
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
long sysconf(int);
#define sysconf(X) __sysconf(X)
forceinline long __sysconf(int thing) {
switch (thing) {
case _SC_ARG_MAX:
return ARG_MAX;
case _SC_CLK_TCK: {
extern const long __AT_CLKTCK asm("AT_CLKTCK");
long res = getauxval(__AT_CLKTCK);
if (!res) res = 100;
return res;
}
case _SC_PAGESIZE:
return FRAMESIZE;
default:
return -1;
}
}
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_RUNTIME_SYSCONF_H_ */

43
libc/runtime/unsetenv.c Normal file
View file

@ -0,0 +1,43 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/safemacros.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
/**
* Removes environment variable.
*/
int unsetenv(const char *name) {
if (isempty(name) || strchr(name, '=')) return einval();
if (environ) {
char **ep = environ;
size_t removed = 0;
size_t namelen = strlen(name);
do {
if (*ep && strncmp(*ep, name, namelen) == 0 && (*ep)[namelen] == '=') {
--removed;
} else if (removed) {
ep[removed] = *ep;
}
} while (*ep++);
}
return 0;
}

36
libc/runtime/weakfree.S Normal file
View file

@ -0,0 +1,36 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
.yoink __FILE__
/ Thunks free() if it's linked, otherwise do nothing.
/
/ @see free_s() which can ignore static/stack and clear refs
weakfree:
push %rbp
mov %rsp,%rbp
.weak free
ezlea free,ax
test %rax,%rax
jz 1f
call free
1: pop %rbp
ret
.endfn weakfree,globl

View file

@ -0,0 +1,62 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
#include "libc/bits/pushpop.h"
#include "libc/dce.h"
#include "libc/nt/console.h"
#include "libc/nt/enum/loadlibrarysearch.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/getdosenviron.h"
#include "libc/runtime/internal.h"
static void LoadFasterAndPreventHijacking(void) {
unsigned wrote;
if (!SetDefaultDllDirectories(kNtLoadLibrarySearchSearchSystem32)) {
WriteFile(GetStdHandle(kNtStdErrorHandle), "nodll\n", 6, &wrote, NULL);
ExitProcess(1);
}
}
noreturn textwindows int WinMain(void *hInstance, void *hPrevInstance,
const char *lpCmdLine, int nCmdShow) {
int i, count;
const char16_t *cmd16, *env16;
long auxarray[][2] = {{pushpop(0L), pushpop(0L)}};
char envblock[ENV_MAX], *envarray[512], argblock[ARG_MAX], *argarray[512];
LoadFasterAndPreventHijacking();
*(/*unconst*/ int *)&__hostos = pushpop(WINDOWS);
cmd16 = GetCommandLine();
env16 = GetEnvironmentStrings();
count = getdosargv(cmd16, argblock, ARG_MAX, argarray, 512);
for (i = 0; argarray[0][i]; ++i) {
if (argarray[0][i] == '\\') argarray[0][i] = '/';
}
getdosenviron(env16, envblock, ENV_MAX, envarray, 512);
FreeEnvironmentStrings(env16);
register int argc asm("r12") = count;
register char **argv asm("r13") = argarray;
register char **envp asm("r14") = envarray;
register long(*auxv)[2] asm("r15") = auxarray;
asm volatile("jmp\t__executive"
: /* no outputs */
: "r"(argc), "r"(argv), "r"(envp), "r"(auxv)
: "memory", "cc");
unreachable;
}