mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 06:53:33 +00:00
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
This commit is contained in:
parent
0ad609268f
commit
33e8fc8687
26 changed files with 192 additions and 182 deletions
|
@ -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)
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
66
libc/mem/gc.c
Normal file
66
libc/mem/gc.c
Normal 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 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;
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
30
libc/runtime/gc.h
Normal file
30
libc/runtime/gc.h
Normal file
|
@ -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_ */
|
|
@ -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_ */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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) */
|
||||
|
|
|
@ -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 (;;) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -51,7 +51,7 @@ void testlib_benchwarmup(void) {
|
|||
* @see BENCH()
|
||||
*/
|
||||
void testlib_runallbenchmarks(void) {
|
||||
peekall();
|
||||
_peekall();
|
||||
mlockall(MCL_CURRENT);
|
||||
nice(-1);
|
||||
__log_level = kLogWarn;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -1351,7 +1351,7 @@ static void OnExit(void) {
|
|||
}
|
||||
|
||||
static void MakeLatencyLittleLessBad(void) {
|
||||
peekall();
|
||||
_peekall();
|
||||
LOGIFNEG1(mlockall(MCL_CURRENT));
|
||||
LOGIFNEG1(nice(-5));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue