From 33e8fc86871197d86d54ff6fe4937423776fda64 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Mon, 8 Mar 2021 10:56:09 -0800 Subject: [PATCH] Expose public garbage collector API for C language You can now do epic things like this: puts(_gc(xasprintf("%d", 123))); The _gc() API is shorthand for _defer() which works like Go's keyword: const char *s = xasprintf("%d", 123); _defer(free, s); puts(s); Be sure to always use -fno-omit-frame-pointer which makes code fast too. Enjoy! See also #114 --- build/config.mk | 5 -- libc/mem/defer.greg.c | 34 +++++++------ libc/mem/gc.c | 66 +++++++++++++++++++++++++ libc/nexgen32e/gclongjmp.S | 5 +- libc/nexgen32e/loadxmm.S | 5 +- libc/nexgen32e/longjmp.S | 2 +- libc/nexgen32e/nt2sysv.S | 4 +- libc/nexgen32e/savexmm.S | 5 +- libc/nexgen32e/setjmp.S | 2 +- libc/nexgen32e/triplf.S | 41 --------------- libc/runtime/free_s.c | 4 +- libc/runtime/gc.h | 30 +++++++++++ libc/runtime/gc.internal.h | 51 +++---------------- libc/runtime/grow.c | 4 +- libc/runtime/isheap.c | 2 +- libc/runtime/peekall.S | 6 +-- libc/runtime/print.greg.c | 4 +- libc/runtime/runtime.h | 22 ++++----- libc/runtime/stackchkfail.c | 25 +++++----- libc/runtime/{weakfree.S => weakfree.c} | 33 ++++++------- libc/testlib/benchrunner.c | 2 +- test/libc/release/smoke.c | 2 +- test/libc/runtime/grow_test.c | 8 +-- test/libc/runtime/mmap_test.c | 8 +-- tool/build/lib/throw.c | 2 +- tool/viz/printvideo.c | 2 +- 26 files changed, 192 insertions(+), 182 deletions(-) create mode 100644 libc/mem/gc.c delete mode 100644 libc/nexgen32e/triplf.S create mode 100644 libc/runtime/gc.h rename libc/runtime/{weakfree.S => weakfree.c} (75%) diff --git a/build/config.mk b/build/config.mk index 665a2e3ef..e04ca5584 100644 --- a/build/config.mk +++ b/build/config.mk @@ -282,11 +282,6 @@ endif # such as MSVC or XCode. You can run your binary objects through a tool # like objconv to convert them to COFF or MachO. Then use ANSI mode to # rollup one header file that'll enable linkage with minimal issues. -# -# Lastly note that in some cases, such as gc(), there simply isn't any -# ANSI workaround available. It's only in cases like that when we'll use -# the __asm__() header workaround, rather than simply removing it. We do -# however try to do that much less often than mainstream C libraries. ifeq ($(MODE), ansi) diff --git a/libc/mem/defer.greg.c b/libc/mem/defer.greg.c index eb55897a3..6df5e0f9c 100644 --- a/libc/mem/defer.greg.c +++ b/libc/mem/defer.greg.c @@ -31,23 +31,9 @@ forceinline bool PointerNotOwnedByParentStackFrame(struct StackFrame *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) { +void __deferer(struct StackFrame *frame, void *fn, void *arg) { size_t n2; struct Garbage *p2; - struct StackFrame *f2; - if (!arg) return; - f2 = __builtin_frame_address(0); - assert(__garbage.n); - assert(f2->next == frame); - assert(PointerNotOwnedByParentStackFrame(f2, frame, arg)); if (UNLIKELY(__garbage.i == __garbage.n)) { n2 = __garbage.n + (__garbage.n >> 1); p2 = malloc(n2 * sizeof(*__garbage.p)); @@ -63,3 +49,21 @@ void __defer(struct StackFrame *frame, void *fn, void *arg) { __garbage.i++; frame->addr = (intptr_t)__gc; } + +/** + * 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 *f2; + if (!arg) return; + f2 = __builtin_frame_address(0); + assert(__garbage.n); + assert(f2->next == frame); + assert(PointerNotOwnedByParentStackFrame(f2, frame, arg)); + __deferer(frame, fn, arg); +} diff --git a/libc/mem/gc.c b/libc/mem/gc.c new file mode 100644 index 000000000..f53eacec2 --- /dev/null +++ b/libc/mem/gc.c @@ -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 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/nexgen32e/stackframe.h" +#include "libc/runtime/gc.h" +#include "libc/runtime/runtime.h" + +/** + * Frees memory when function returns. + * + * This garbage collector overwrites the return address on the stack so + * that the RET instruction calls a trampoline which calls free(). It's + * loosely analogous to Go's defer keyword rather than a true cycle gc. + * + * const char *s = _gc(strdup("hello")); + * puts(s); + * + * This macro is equivalent to: + * + * _defer(free, ptr) + * + * @warning do not return a gc()'d pointer + * @warning do not realloc() with gc()'d pointer + * @warning be careful about static keyword due to impact of inlining + * @note you should use -fno-omit-frame-pointer + */ +void *(_gc)(void *thing) { + struct StackFrame *frame; + frame = __builtin_frame_address(0); + __deferer(frame->next, _weakfree, thing); + return thing; +} + +/** + * Calls fn(arg) when function returns. + * + * This garbage collector overwrites the return address on the stack so + * that the RET instruction calls a trampoline which calls free(). It's + * loosely analogous to Go's defer keyword rather than a true cycle gc. + * + * @warning do not return a gc()'d pointer + * @warning do not realloc() with gc()'d pointer + * @warning be careful about static keyword due to impact of inlining + * @note you should use -fno-omit-frame-pointer + */ +void *(_defer)(void *fn, void *arg) { + struct StackFrame *frame; + frame = __builtin_frame_address(0); + __deferer(frame->next, fn, arg); + return arg; +} diff --git a/libc/nexgen32e/gclongjmp.S b/libc/nexgen32e/gclongjmp.S index 71332655a..3787e30e4 100644 --- a/libc/nexgen32e/gclongjmp.S +++ b/libc/nexgen32e/gclongjmp.S @@ -29,7 +29,7 @@ // @assume system five nexgen32e abi conformant // @see examples/ctrlc.c // @noreturn -gclongjmp: +_gclongjmp: .leafprologue .profilable .weak __garbage @@ -57,5 +57,4 @@ gclongjmp: 2: pop %rsi pop %rdi jmp 0b - .endfn gclongjmp,globl - .source __FILE__ + .endfn _gclongjmp,globl diff --git a/libc/nexgen32e/loadxmm.S b/libc/nexgen32e/loadxmm.S index 24628744c..56d568fb0 100644 --- a/libc/nexgen32e/loadxmm.S +++ b/libc/nexgen32e/loadxmm.S @@ -23,7 +23,7 @@ // // @param %rdi points to &(forcealign(16) uint8_t[256])[128] // @note modern cpus have out-of-order execution engines -loadxmm: +_loadxmm: .leafprologue movaps -0x80(%rdi),%xmm0 movaps -0x70(%rdi),%xmm1 @@ -42,5 +42,4 @@ loadxmm: movaps 0x60(%rdi),%xmm14 movaps 0x70(%rdi),%xmm15 .leafepilogue - .endfn loadxmm,globl,hidden - .source __FILE__ + .endfn _loadxmm,globl,hidden diff --git a/libc/nexgen32e/longjmp.S b/libc/nexgen32e/longjmp.S index b46dadfab..223d2b5ad 100644 --- a/libc/nexgen32e/longjmp.S +++ b/libc/nexgen32e/longjmp.S @@ -26,7 +26,7 @@ // @noreturn // @assume system five nexgen32e abi conformant // @note code built w/ microsoft abi compiler can't call this -// @see gclongjmp() unwinds gc() destructors +// @see _gclongjmp() unwinds _gc() destructors longjmp:mov %esi,%eax test %eax,%eax jnz 1f diff --git a/libc/nexgen32e/nt2sysv.S b/libc/nexgen32e/nt2sysv.S index a01c207a8..cc14d9263 100644 --- a/libc/nexgen32e/nt2sysv.S +++ b/libc/nexgen32e/nt2sysv.S @@ -40,14 +40,14 @@ __nt2sysv: pushf ezlea _base,bx lea -0x80(%rbp),%rdi - call savexmm + call _savexmm mov %rcx,%rdi mov %rdx,%rsi mov %r8,%rdx mov %r9,%rcx call *%rax lea -0x80(%rbp),%rdi - call loadxmm + call _loadxmm popf pop %rsi pop %rdi diff --git a/libc/nexgen32e/savexmm.S b/libc/nexgen32e/savexmm.S index b6156bfb5..8bdd863b8 100644 --- a/libc/nexgen32e/savexmm.S +++ b/libc/nexgen32e/savexmm.S @@ -23,7 +23,7 @@ // // @param %rdi points to &(forcealign(16) uint8_t[256])[128] // @note modern cpus have out-of-order execution engines -savexmm: +_savexmm: .leafprologue movaps %xmm0,-0x80(%rdi) movaps %xmm1,-0x70(%rdi) @@ -42,5 +42,4 @@ savexmm: movaps %xmm14,0x60(%rdi) movaps %xmm15,0x70(%rdi) .leafepilogue - .endfn savexmm,globl,hidden - .source __FILE__ + .endfn _savexmm,globl,hidden diff --git a/libc/nexgen32e/setjmp.S b/libc/nexgen32e/setjmp.S index cc5cb975a..04c3a6deb 100644 --- a/libc/nexgen32e/setjmp.S +++ b/libc/nexgen32e/setjmp.S @@ -25,7 +25,7 @@ // @returnstwice // @assume system five nexgen32e abi conformant // @note code built w/ microsoft abi compiler can't call this -// @see longjmp(), gclongjmp() +// @see longjmp(), _gclongjmp() setjmp: lea 8(%rsp),%rax mov %rax,(%rdi) mov %rbx,8(%rdi) diff --git a/libc/nexgen32e/triplf.S b/libc/nexgen32e/triplf.S deleted file mode 100644 index 52219de06..000000000 --- a/libc/nexgen32e/triplf.S +++ /dev/null @@ -1,41 +0,0 @@ -/*-*- mode:unix-assembly; 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 │ -│ │ -│ Permission to use, copy, modify, and/or distribute this software for │ -│ any purpose with or without fee is hereby granted, provided that the │ -│ above copyright notice and this permission notice appear in all copies. │ -│ │ -│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ -│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ -│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ -│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ -│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ -│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ -│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ -│ PERFORMANCE OF THIS SOFTWARE. │ -╚─────────────────────────────────────────────────────────────────────────────*/ -#include "ape/macros.internal.h" -.real -.source __FILE__ -.code16 # ∩ .code32 ∩ .code64 - -// Hoses interrupt descriptor table and triple-faults the system. -// -// @see youtu.be/GIKfEAF2Yhw?t=67 -// @mode long,legacy,real -triplf: ud2 - push %bp - mov %sp,%bp - sub $8,%sp - movpp %bp,%si - lea -8(%bp),%di - pushpop 8,%cx - xor %ax,%ax - rep stosb -0: cli - lidt -8(%bp) - ud2 - jmp 0b - .endfn triplf,globl,protected diff --git a/libc/runtime/free_s.c b/libc/runtime/free_s.c index 254c79411..84622ec8a 100644 --- a/libc/runtime/free_s.c +++ b/libc/runtime/free_s.c @@ -26,5 +26,7 @@ void free_s(void *v) { void **pp = (void **)v; void *p = NULL; lockxchg(pp, &p); - if (isheap(p)) weakfree(p); + if (_isheap(p)) { + _weakfree(p); + } } diff --git a/libc/runtime/gc.h b/libc/runtime/gc.h new file mode 100644 index 000000000..7229b65c9 --- /dev/null +++ b/libc/runtime/gc.h @@ -0,0 +1,30 @@ +#ifndef COSMOPOLITAN_LIBC_RUNTIME_GC_H_ +#define COSMOPOLITAN_LIBC_RUNTIME_GC_H_ +#include "libc/calls/calls.h" +#include "libc/nexgen32e/stackframe.h" +#include "libc/runtime/runtime.h" +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +void *_gc(void *) hidden; +void *_defer(void *, void *) hidden; +void __defer(struct StackFrame *, void *, void *) hidden; +void __deferer(struct StackFrame *, void *, void *) hidden; +void _gclongjmp(jmp_buf, int) nothrow wontreturn; + +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) +#define _gc(THING) _defer((void *)_weakfree, (void *)(THING)) +#define _defer(FN, ARG) \ + ({ \ + autotype(ARG) Arg = (ARG); \ + /* prevent weird opts like tail call */ \ + asm volatile("" : "+g"(Arg) : : "memory"); \ + __defer((struct StackFrame *)__builtin_frame_address(0), FN, Arg); \ + asm volatile("" : "+g"(Arg) : : "memory"); \ + Arg; \ + }) +#endif /* defined(__GNUC__) && !defined(__STRICT_ANSI__) */ + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_RUNTIME_GC_H_ */ diff --git a/libc/runtime/gc.internal.h b/libc/runtime/gc.internal.h index 9ca8bec93..b077b118d 100644 --- a/libc/runtime/gc.internal.h +++ b/libc/runtime/gc.internal.h @@ -1,49 +1,10 @@ -#ifndef COSMOPOLITAN_LIBC_RUNTIME_GC_H_ -#define COSMOPOLITAN_LIBC_RUNTIME_GC_H_ -#include "libc/calls/calls.h" -#include "libc/nexgen32e/stackframe.h" -#include "libc/runtime/runtime.h" +#ifndef COSMOPOLITAN_LIBC_RUNTIME_GC_INTERNAL_H_ +#define COSMOPOLITAN_LIBC_RUNTIME_GC_INTERNAL_H_ +#include "libc/runtime/gc.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. - */ +#define gc(THING) _gc(THING) +#define defer(FN, ARG) _defer(FN, ARG) -/** - * 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((void *)weakfree, (void *)(THING)) - -/** - * Same as longjmp() but runs gc() / defer() destructors. - */ -void gclongjmp(jmp_buf, int) nothrow wontreturn paramsnonnull(); - -/** - * Calls FN(ARG) when function returns. - */ -#ifndef __VSCODE_INTELLISENSE__ -#define defer(FN, ARG) \ - ({ \ - autotype(ARG) Arg = (ARG); \ - /* prevent weird opts like tail call */ \ - asm volatile("" : "+g"(Arg) : : "memory"); \ - __defer((struct StackFrame *)__builtin_frame_address(0), FN, Arg); \ - asm volatile("" : "+g"(Arg) : : "memory"); \ - Arg; \ - }) -#endif /* __VSCODE_INTELLISENSE__ */ - -void __defer(struct StackFrame *, void *, void *) hidden paramsnonnull((1, 2)); - -COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* COSMOPOLITAN_LIBC_RUNTIME_GC_H_ */ +#endif /* COSMOPOLITAN_LIBC_RUNTIME_GC_INTERNAL_H_ */ diff --git a/libc/runtime/grow.c b/libc/runtime/grow.c index 6bf247c40..ff1e94e11 100644 --- a/libc/runtime/grow.c +++ b/libc/runtime/grow.c @@ -43,8 +43,8 @@ bool __grow(void *pp, size_t *capacity, size_t itemsize, size_t extra) { p = (void **)pp; assert(itemsize); assert((*p && *capacity) || (!*p && !*capacity)); - assert(!isheap(*p) || ((intptr_t)*p & 15) == 0); - p1 = isheap(*p) ? *p : NULL; + 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; diff --git a/libc/runtime/isheap.c b/libc/runtime/isheap.c index 9308d235a..37cf9d834 100644 --- a/libc/runtime/isheap.c +++ b/libc/runtime/isheap.c @@ -26,7 +26,7 @@ * @assume stack addresses are always greater than heap addresses * @assume stack memory isn't stored beneath %rsp (-mno-red-zone) */ -bool isheap(void *p) { +bool _isheap(void *p) { int x, i; uintptr_t rsp; asm("mov\t%%rsp,%0" : "=r"(rsp)); diff --git a/libc/runtime/peekall.S b/libc/runtime/peekall.S index 04d2ef9d0..a1f82ebc1 100644 --- a/libc/runtime/peekall.S +++ b/libc/runtime/peekall.S @@ -18,10 +18,10 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "ape/relocations.h" #include "libc/macros.internal.h" -.source __FILE__ // Loads all pages from program image into memory. -peekall:.leafprologue +_peekall: + .leafprologue ezlea _base,si ezlea _end,cx 0: mov (%rsi),%eax @@ -29,4 +29,4 @@ peekall:.leafprologue cmp %rcx,%rsi jb 0b .leafepilogue - .endfn peekall,globl + .endfn _peekall,globl diff --git a/libc/runtime/print.greg.c b/libc/runtime/print.greg.c index b821246db..ef84b92be 100644 --- a/libc/runtime/print.greg.c +++ b/libc/runtime/print.greg.c @@ -34,10 +34,10 @@ static void __sys_print_nt(const void *data, size_t len) { int64_t hand; char xmm[256]; uint32_t wrote; - savexmm(xmm + 128); + _savexmm(xmm + 128); hand = __imp_GetStdHandle(kNtStdErrorHandle); __imp_WriteFile(hand, data, len, &wrote, NULL); - loadxmm(xmm + 128); + _loadxmm(xmm + 128); } /** diff --git a/libc/runtime/runtime.h b/libc/runtime/runtime.h index d81f58a88..485284d11 100644 --- a/libc/runtime/runtime.h +++ b/libc/runtime/runtime.h @@ -33,7 +33,6 @@ extern unsigned char *__relo_end[]; /* α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)); @@ -45,34 +44,35 @@ void exit(int) wontreturn; void _exit(int) libcesque wontreturn; void _Exit(int) libcesque wontreturn; void abort(void) wontreturn noinstrument; -void triplf(void) wontreturn 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 fpreset(void); -void savexmm(void *); -void loadxmm(void *); -void peekall(void); int issetugid(void); -void weakfree(void *) libcesque; -bool isheap(void *); void *mmap(void *, uint64_t, int32_t, int32_t, int32_t, int64_t); void *mremap(void *, uint64_t, uint64_t, int32_t, void *); int munmap(void *, uint64_t); int mprotect(void *, uint64_t, int) privileged; int msync(void *, size_t, int); -void __print(const void *, size_t); -void __print_string(const char *); void *sbrk(intptr_t); int brk(void *); + +bool _isheap(void *); int NtGetVersion(void); +long missingno(); +void __print(const void *, size_t); +void __print_string(const char *); +void _loadxmm(void *); +void _peekall(void); +void _savexmm(void *); +void _weakfree(void *); +void free_s(void *) paramsnonnull() libcesque; +int close_s(int *) paramsnonnull() libcesque; COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/runtime/stackchkfail.c b/libc/runtime/stackchkfail.c index 1d1901750..ad42a392d 100644 --- a/libc/runtime/stackchkfail.c +++ b/libc/runtime/stackchkfail.c @@ -50,21 +50,22 @@ privileged noasan void __stack_chk_fail(void) { : "=S"(si), "=c"(cx) : "0"(msg), "1"(len), "d"(0x3F8 /* COM1 */) : "memory"); - triplf(); + asm("push\t$0\n\t" + "push\t$0\n\t" + "cli\n\t" + "lidt\t(%rsp)"); + for (;;) asm("ud2"); } if (NtGetVersion() < kNtVersionFuture) { do { - asm volatile( - "syscall" - : "=a"(ax), "=c"(cx) - : "0"(NtGetVersion() < kNtVersionWindows8 - ? 0x0029 - : NtGetVersion() < kNtVersionWindows81 - ? 0x002a - : NtGetVersion() < kNtVersionWindows10 ? 0x002b - : 0x002c), - "1"(pushpop(-1L)), "d"(42) - : "r11", "cc", "memory"); + asm volatile("syscall" + : "=a"(ax), "=c"(cx) + : "0"(NtGetVersion() < kNtVersionWindows8 ? 0x0029 + : NtGetVersion() < kNtVersionWindows81 ? 0x002a + : NtGetVersion() < kNtVersionWindows10 ? 0x002b + : 0x002c), + "1"(pushpop(-1L)), "d"(42) + : "r11", "cc", "memory"); } while (!ax); } for (;;) { diff --git a/libc/runtime/weakfree.S b/libc/runtime/weakfree.c similarity index 75% rename from libc/runtime/weakfree.S rename to libc/runtime/weakfree.c index d9499e271..b466568d1 100644 --- a/libc/runtime/weakfree.S +++ b/libc/runtime/weakfree.c @@ -1,7 +1,7 @@ -/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ -│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│ +/*-*- 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 │ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ @@ -16,20 +16,15 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/macros.internal.h" -.source __FILE__ +#include "libc/bits/weaken.h" +#include "libc/mem/mem.h" +#include "libc/runtime/runtime.h" -// 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 +/** + * Thunks free() if it's linked, otherwise do nothing. + */ +void _weakfree(void *p) { + if (weaken(free)) { + weaken(free)(p); + } +} diff --git a/libc/testlib/benchrunner.c b/libc/testlib/benchrunner.c index f11633a0f..d669f1ceb 100644 --- a/libc/testlib/benchrunner.c +++ b/libc/testlib/benchrunner.c @@ -51,7 +51,7 @@ void testlib_benchwarmup(void) { * @see BENCH() */ void testlib_runallbenchmarks(void) { - peekall(); + _peekall(); mlockall(MCL_CURRENT); nice(-1); __log_level = kLogWarn; diff --git a/test/libc/release/smoke.c b/test/libc/release/smoke.c index 2fca2b6ce..2f3618c9c 100644 --- a/test/libc/release/smoke.c +++ b/test/libc/release/smoke.c @@ -6,7 +6,7 @@ int main(int argc, char *argv[]) { s = strdup(argv[0]); s[0] = 'Z'; f = fopen("/dev/null", "w"); - fprintf(f, "hello world %d %s\n", argc, s); + fputs(_gc(xasprintf("hello world %d %s\n", argc, s)), f); fclose(f); rc = system("exit 42"); CHECK_NE(-1, rc); diff --git a/test/libc/runtime/grow_test.c b/test/libc/runtime/grow_test.c index dd118e0f0..3d4800ae6 100644 --- a/test/libc/runtime/grow_test.c +++ b/test/libc/runtime/grow_test.c @@ -46,9 +46,9 @@ TEST(grow, testStackMemory_convertsToDynamic) { int A[] = {1, 2, 3}; int *p = A; size_t capacity = ARRAYLEN(A); - if (!isheap(p)) { + if (!_isheap(p)) { EXPECT_TRUE(__grow(&p, &capacity, sizeof(int), 0)); - EXPECT_TRUE(isheap(p)); + EXPECT_TRUE(_isheap(p)); EXPECT_GT(capacity, ARRAYLEN(A)); EXPECT_EQ(1, p[0]); EXPECT_EQ(2, p[1]); @@ -86,9 +86,9 @@ TEST(grow, testOverflow_returnsFalseAndDoesNotFree) { int A[] = {1, 2, 3}; int *p = A; size_t capacity = ARRAYLEN(A); - if (!isheap(p)) { + if (!_isheap(p)) { EXPECT_FALSE(__grow(&p, &capacity, pushpop(SIZE_MAX), 0)); - EXPECT_FALSE(isheap(p)); + EXPECT_FALSE(_isheap(p)); EXPECT_EQ(capacity, ARRAYLEN(A)); EXPECT_EQ(1, p[0]); EXPECT_EQ(2, p[1]); diff --git a/test/libc/runtime/mmap_test.c b/test/libc/runtime/mmap_test.c index a35641e34..dec67cdbf 100644 --- a/test/libc/runtime/mmap_test.c +++ b/test/libc/runtime/mmap_test.c @@ -137,18 +137,18 @@ TEST(mmap, mapPrivate_writesDontChangeFile) { } TEST(isheap, nullPtr) { - ASSERT_FALSE(isheap(NULL)); + ASSERT_FALSE(_isheap(NULL)); } TEST(isheap, malloc) { - ASSERT_TRUE(isheap(gc(malloc(1)))); + ASSERT_TRUE(_isheap(gc(malloc(1)))); } TEST(isheap, emptyMalloc) { - ASSERT_TRUE(isheap(gc(malloc(0)))); + ASSERT_TRUE(_isheap(gc(malloc(0)))); } TEST(isheap, mallocOffset) { char *p = gc(malloc(131072)); - ASSERT_TRUE(isheap(p + 100000)); + ASSERT_TRUE(_isheap(p + 100000)); } diff --git a/tool/build/lib/throw.c b/tool/build/lib/throw.c index f8941fbc9..b6e07ecdb 100644 --- a/tool/build/lib/throw.c +++ b/tool/build/lib/throw.c @@ -34,7 +34,7 @@ static bool IsHaltingInitialized(struct Machine *m) { void HaltMachine(struct Machine *m, int code) { CHECK(IsHaltingInitialized(m)); - gclongjmp(m->onhalt, code); + _gclongjmp(m->onhalt, code); } void ThrowDivideError(struct Machine *m) { diff --git a/tool/viz/printvideo.c b/tool/viz/printvideo.c index 8517b4622..2b99559d8 100644 --- a/tool/viz/printvideo.c +++ b/tool/viz/printvideo.c @@ -1351,7 +1351,7 @@ static void OnExit(void) { } static void MakeLatencyLittleLessBad(void) { - peekall(); + _peekall(); LOGIFNEG1(mlockall(MCL_CURRENT)); LOGIFNEG1(nice(-5)); }