mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-03-06 08:56:22 +00:00
Mint APE Loader v1.5
This change ports APE Loader to Linux AARCH64, so that Raspberry Pi users can run programs like redbean, without the executable needing to modify itself. Progress has also slipped into this change on the issue of making progress better conforming to user expectations and industry standards regarding which symbols we're allowed to declare
This commit is contained in:
parent
6843150e0c
commit
7e0a09feec
510 changed files with 1783 additions and 1483 deletions
4
.vscode/c_cpp_properties.json
vendored
4
.vscode/c_cpp_properties.json
vendored
|
@ -41,8 +41,8 @@
|
||||||
"interruptfn=",
|
"interruptfn=",
|
||||||
"optimizespeed=",
|
"optimizespeed=",
|
||||||
"forcealignargpointer=",
|
"forcealignargpointer=",
|
||||||
"noasan=",
|
"dontasan=",
|
||||||
"noubsan=",
|
"dontubsan=",
|
||||||
"donothing=",
|
"donothing=",
|
||||||
"nosideeffect=",
|
"nosideeffect=",
|
||||||
"unreachable=",,
|
"unreachable=",,
|
||||||
|
|
|
@ -143,8 +143,8 @@ machine](https://github.com/jart/blink) by adding the following to the
|
||||||
top of your main.c file:
|
top of your main.c file:
|
||||||
|
|
||||||
```c
|
```c
|
||||||
STATIC_YOINK("blink_linux_aarch64"); // for raspberry pi
|
__static_yoink("blink_linux_aarch64"); // for raspberry pi
|
||||||
STATIC_YOINK("blink_xnu_aarch64"); // is apple silicon
|
__static_yoink("blink_xnu_aarch64"); // is apple silicon
|
||||||
```
|
```
|
||||||
|
|
||||||
The benefit is you'll have single file executables that'll run on both
|
The benefit is you'll have single file executables that'll run on both
|
||||||
|
|
|
@ -72,7 +72,9 @@ SECTIONS {
|
||||||
KEEP(*(SORT_NONE(.fini)))
|
KEEP(*(SORT_NONE(.fini)))
|
||||||
} =0x1f2003d5
|
} =0x1f2003d5
|
||||||
|
|
||||||
.privileged ALIGN(CONSTANT(COMMONPAGESIZE)) : {
|
. += CONSTANT(COMMONPAGESIZE);
|
||||||
|
|
||||||
|
.privileged : {
|
||||||
__privileged_start = .;
|
__privileged_start = .;
|
||||||
*(.privileged*)
|
*(.privileged*)
|
||||||
} =0x1f2003d6
|
} =0x1f2003d6
|
||||||
|
@ -119,7 +121,7 @@ SECTIONS {
|
||||||
_etext = .;
|
_etext = .;
|
||||||
PROVIDE(etext = .);
|
PROVIDE(etext = .);
|
||||||
|
|
||||||
. = ALIGN(CONSTANT(COMMONPAGESIZE));
|
. += CONSTANT(COMMONPAGESIZE);
|
||||||
. = DATA_SEGMENT_ALIGN(CONSTANT(COMMONPAGESIZE), CONSTANT(COMMONPAGESIZE));
|
. = DATA_SEGMENT_ALIGN(CONSTANT(COMMONPAGESIZE), CONSTANT(COMMONPAGESIZE));
|
||||||
|
|
||||||
.eh_frame : ONLY_IF_RW {
|
.eh_frame : ONLY_IF_RW {
|
||||||
|
|
18
ape/ape-m1.c
18
ape/ape-m1.c
|
@ -190,6 +190,19 @@ static int StrCmp(const char *l, const char *r) {
|
||||||
return (l[i] & 255) - (r[i] & 255);
|
return (l[i] & 255) - (r[i] & 255);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *BaseName(const char *s) {
|
||||||
|
int c;
|
||||||
|
const char *b = "";
|
||||||
|
if (s) {
|
||||||
|
while ((c = *s++)) {
|
||||||
|
if (c == '/') {
|
||||||
|
b = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
static void Bzero(void *a, unsigned long n) {
|
static void Bzero(void *a, unsigned long n) {
|
||||||
long z;
|
long z;
|
||||||
char *p, *e;
|
char *p, *e;
|
||||||
|
@ -848,7 +861,7 @@ int main(int argc, char **argv, char **envp) {
|
||||||
} else if (argc < 2) {
|
} else if (argc < 2) {
|
||||||
Emit("usage: ape PROG [ARGV1,ARGV2,...]\n"
|
Emit("usage: ape PROG [ARGV1,ARGV2,...]\n"
|
||||||
" ape - PROG [ARGV0,ARGV1,...]\n"
|
" ape - PROG [ARGV0,ARGV1,...]\n"
|
||||||
"actually portable executable loader silicon 1.4\n"
|
"actually portable executable loader silicon 1.5\n"
|
||||||
"copyright 2023 justine alexandra roberts tunney\n"
|
"copyright 2023 justine alexandra roberts tunney\n"
|
||||||
"https://justine.lol/ape.html\n");
|
"https://justine.lol/ape.html\n");
|
||||||
_exit(1);
|
_exit(1);
|
||||||
|
@ -871,7 +884,8 @@ int main(int argc, char **argv, char **envp) {
|
||||||
pe = M->ehdr.buf + rc;
|
pe = M->ehdr.buf + rc;
|
||||||
|
|
||||||
// resolve argv[0] to reflect path search
|
// resolve argv[0] to reflect path search
|
||||||
if (argc > 0 && *prog != '/' && *exe == '/' && !StrCmp(prog, argv[0])) {
|
if ((argc > 0 && *prog != '/' && *exe == '/' && !StrCmp(prog, argv[0])) ||
|
||||||
|
!StrCmp(BaseName(prog), argv[0])) {
|
||||||
tp -= (n = StrLen(exe) + 1);
|
tp -= (n = StrLen(exe) + 1);
|
||||||
MemMove(tp, exe, n);
|
MemMove(tp, exe, n);
|
||||||
argv[0] = tp;
|
argv[0] = tp;
|
||||||
|
|
|
@ -610,7 +610,7 @@ apesh: .ascii "\n@\n#'\"\n" // sixth edition shebang
|
||||||
// extract the loader into a temp folder, and use it to
|
// extract the loader into a temp folder, and use it to
|
||||||
// load the APE without modifying it.
|
// load the APE without modifying it.
|
||||||
.ascii "[ x\"$1\" != x--assimilate ] && {\n"
|
.ascii "[ x\"$1\" != x--assimilate ] && {\n"
|
||||||
.ascii "t=\"${TMPDIR:-${HOME:-.}}/.ape-1.4\"\n"
|
.ascii "t=\"${TMPDIR:-${HOME:-.}}/.ape-1.5\"\n"
|
||||||
.ascii "[ -x \"$t\" ] || {\n"
|
.ascii "[ -x \"$t\" ] || {\n"
|
||||||
.ascii "mkdir -p \"${t%/*}\" &&\n"
|
.ascii "mkdir -p \"${t%/*}\" &&\n"
|
||||||
.ascii "dd if=\"$o\" of=\"$t.$$\" skip="
|
.ascii "dd if=\"$o\" of=\"$t.$$\" skip="
|
||||||
|
@ -717,8 +717,8 @@ emush: .ascii "\n@\n#'\"\n"
|
||||||
.previous
|
.previous
|
||||||
// ...
|
// ...
|
||||||
// decentralized section (.emush)
|
// decentralized section (.emush)
|
||||||
// - STATIC_YOINK("blink_linux_aarch64"); // for raspberry pi
|
// - __static_yoink("blink_linux_aarch64"); // for raspberry pi
|
||||||
// - STATIC_YOINK("blink_xnu_aarch64"); // is apple silicon
|
// - __static_yoink("blink_xnu_aarch64"); // is apple silicon
|
||||||
// ...
|
// ...
|
||||||
.section .emushepilogue,"a",@progbits
|
.section .emushepilogue,"a",@progbits
|
||||||
.ascii "echo \"$0: this ape binary lacks $m support\" >&2\n"
|
.ascii "echo \"$0: this ape binary lacks $m support\" >&2\n"
|
||||||
|
@ -818,7 +818,7 @@ ape.ident:
|
||||||
.long 1
|
.long 1
|
||||||
1: .asciz "APE"
|
1: .asciz "APE"
|
||||||
2: .balign 4
|
2: .balign 4
|
||||||
3: .long 104000000
|
3: .long 105000000
|
||||||
4: .size ape.ident,.-ape.ident
|
4: .size ape.ident,.-ape.ident
|
||||||
.type ape.ident,@object
|
.type ape.ident,@object
|
||||||
.previous
|
.previous
|
||||||
|
|
|
@ -432,6 +432,7 @@ SECTIONS {
|
||||||
KEEP(*(SORT_BY_NAME(.piro.data.sort.*)))
|
KEEP(*(SORT_BY_NAME(.piro.data.sort.*)))
|
||||||
KEEP(*(.piro.pad.data))
|
KEEP(*(.piro.pad.data))
|
||||||
KEEP(*(.dataepilogue))
|
KEEP(*(.dataepilogue))
|
||||||
|
. = ALIGN(512);
|
||||||
/*END: NT FORK COPYING */
|
/*END: NT FORK COPYING */
|
||||||
_edata = .;
|
_edata = .;
|
||||||
PROVIDE(edata = .);
|
PROVIDE(edata = .);
|
||||||
|
|
50
ape/ape.mk
50
ape/ape.mk
|
@ -35,7 +35,7 @@ APELINK = \
|
||||||
$(FIXUPOBJ) \
|
$(FIXUPOBJ) \
|
||||||
$@
|
$@
|
||||||
|
|
||||||
APE_SRCS = ape/ape.S
|
APE_SRCS = ape/ape.S ape/start.S ape/launch.S ape/systemcall.S
|
||||||
APE_OBJS = o/$(MODE)/ape/ape.o
|
APE_OBJS = o/$(MODE)/ape/ape.o
|
||||||
APE_NO_MODIFY_SELF = $(APE)
|
APE_NO_MODIFY_SELF = $(APE)
|
||||||
APE_COPY_SELF = $(APE)
|
APE_COPY_SELF = $(APE)
|
||||||
|
@ -52,6 +52,54 @@ o/$(MODE)/ape/aarch64.lds: \
|
||||||
libc/macros.internal.h \
|
libc/macros.internal.h \
|
||||||
libc/str/str.h
|
libc/str/str.h
|
||||||
|
|
||||||
|
APE_LOADER_LDFLAGS = \
|
||||||
|
-pie \
|
||||||
|
-static \
|
||||||
|
-nostdlib \
|
||||||
|
--no-dynamic-linker \
|
||||||
|
-z norelro \
|
||||||
|
-z common-page-size=0x4000 \
|
||||||
|
-z max-page-size=0x4000
|
||||||
|
|
||||||
|
APE_LOADER_FLAGS = \
|
||||||
|
-DNDEBUG \
|
||||||
|
-iquote. \
|
||||||
|
-Wall \
|
||||||
|
-Wextra \
|
||||||
|
-fpie \
|
||||||
|
-Os \
|
||||||
|
-ffreestanding \
|
||||||
|
-mgeneral-regs-only \
|
||||||
|
-fno-asynchronous-unwind-tables \
|
||||||
|
-fno-stack-protector \
|
||||||
|
-fno-ident \
|
||||||
|
-fno-gnu-unique \
|
||||||
|
-c \
|
||||||
|
$(OUTPUT_OPTION) \
|
||||||
|
$<
|
||||||
|
|
||||||
|
o/$(MODE)/ape/ape.elf: o/$(MODE)/ape/ape.elf.dbg
|
||||||
|
$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -g $< $@
|
||||||
|
|
||||||
|
o/$(MODE)/ape/ape.elf.dbg: \
|
||||||
|
o/$(MODE)/ape/start.o \
|
||||||
|
o/$(MODE)/ape/loader.o \
|
||||||
|
o/$(MODE)/ape/launch.o \
|
||||||
|
o/$(MODE)/ape/systemcall.o
|
||||||
|
@$(COMPILE) -ALINK.elf $(LD) $(APE_LOADER_LDFLAGS) -o $@ $(patsubst %.lds,-T %.lds,$^)
|
||||||
|
|
||||||
|
o/$(MODE)/ape/loader.o: ape/loader.c
|
||||||
|
@$(COMPILE) -AOBJECTIFY.c $(CC) -DSUPPORT_VECTOR=1 -g $(APE_LOADER_FLAGS)
|
||||||
|
o/$(MODE)/ape/start.o: ape/start.S
|
||||||
|
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
|
||||||
|
o/$(MODE)/ape/launch.o: ape/launch.S
|
||||||
|
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
|
||||||
|
o/$(MODE)/ape/systemcall.o: ape/systemcall.S
|
||||||
|
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
|
||||||
|
|
||||||
|
.PHONY: o/$(MODE)/ape
|
||||||
|
o/$(MODE)/ape: o/$(MODE)/ape/ape.elf
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
APE = o/$(MODE)/ape/ape.o \
|
APE = o/$(MODE)/ape/ape.o \
|
||||||
|
|
|
@ -37,6 +37,7 @@ for x in .ape \
|
||||||
.ape-1.1 \
|
.ape-1.1 \
|
||||||
.ape-1.3 \
|
.ape-1.3 \
|
||||||
.ape-1.4 \
|
.ape-1.4 \
|
||||||
|
.ape-1.5 \
|
||||||
.ape-blink-0.9.2 \
|
.ape-blink-0.9.2 \
|
||||||
.ape-blink-1.0.0; do
|
.ape-blink-1.0.0; do
|
||||||
rm -f \
|
rm -f \
|
||||||
|
|
41
ape/launch.S
41
ape/launch.S
|
@ -34,7 +34,44 @@
|
||||||
// @param rdx is stack pointer (becomes zero)
|
// @param rdx is stack pointer (becomes zero)
|
||||||
// @param rcx is passed through as-is
|
// @param rcx is passed through as-is
|
||||||
// @noreturn
|
// @noreturn
|
||||||
Launch: xor %r8d,%r8d
|
Launch:
|
||||||
|
#ifdef __aarch64__
|
||||||
|
|
||||||
|
mov x16,x1
|
||||||
|
mov sp,x2
|
||||||
|
mov x1,0
|
||||||
|
mov x2,0
|
||||||
|
mov x3,0
|
||||||
|
mov x4,0
|
||||||
|
mov x5,0
|
||||||
|
mov x6,0
|
||||||
|
mov x7,0
|
||||||
|
mov x8,0
|
||||||
|
mov x9,0
|
||||||
|
mov x10,0
|
||||||
|
mov x11,0
|
||||||
|
mov x12,0
|
||||||
|
mov x13,0
|
||||||
|
mov x14,0
|
||||||
|
mov x15,0
|
||||||
|
mov x17,0
|
||||||
|
mov x19,0
|
||||||
|
mov x20,0
|
||||||
|
mov x21,0
|
||||||
|
mov x22,0
|
||||||
|
mov x23,0
|
||||||
|
mov x24,0
|
||||||
|
mov x25,0
|
||||||
|
mov x26,0
|
||||||
|
mov x27,0
|
||||||
|
mov x28,0
|
||||||
|
mov x29,0
|
||||||
|
mov x30,0
|
||||||
|
br x16
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
xor %r8d,%r8d
|
||||||
xor %r9d,%r9d
|
xor %r9d,%r9d
|
||||||
xor %r10d,%r10d
|
xor %r10d,%r10d
|
||||||
xor %r11d,%r11d
|
xor %r11d,%r11d
|
||||||
|
@ -50,4 +87,6 @@ Launch: xor %r8d,%r8d
|
||||||
xor %ebx,%ebx
|
xor %ebx,%ebx
|
||||||
xor %eax,%eax
|
xor %eax,%eax
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
#endif
|
||||||
.endfn Launch,globl
|
.endfn Launch,globl
|
||||||
|
|
162
ape/loader.c
162
ape/loader.c
|
@ -98,6 +98,12 @@
|
||||||
#define IsOpenbsd() (SupportsOpenbsd() && os == OPENBSD)
|
#define IsOpenbsd() (SupportsOpenbsd() && os == OPENBSD)
|
||||||
#define IsNetbsd() (SupportsNetbsd() && os == NETBSD)
|
#define IsNetbsd() (SupportsNetbsd() && os == NETBSD)
|
||||||
|
|
||||||
|
#ifdef __aarch64__
|
||||||
|
#define IsAarch64() 1
|
||||||
|
#else
|
||||||
|
#define IsAarch64() 0
|
||||||
|
#endif
|
||||||
|
|
||||||
#define O_RDONLY 0
|
#define O_RDONLY 0
|
||||||
#define PROT_NONE 0
|
#define PROT_NONE 0
|
||||||
#define PROT_READ 1
|
#define PROT_READ 1
|
||||||
|
@ -111,6 +117,7 @@
|
||||||
#define ELFCLASS32 1
|
#define ELFCLASS32 1
|
||||||
#define ELFDATA2LSB 1
|
#define ELFDATA2LSB 1
|
||||||
#define EM_NEXGEN32E 62
|
#define EM_NEXGEN32E 62
|
||||||
|
#define EM_AARCH64 183
|
||||||
#define ET_EXEC 2
|
#define ET_EXEC 2
|
||||||
#define ET_DYN 3
|
#define ET_DYN 3
|
||||||
#define PT_LOAD 1
|
#define PT_LOAD 1
|
||||||
|
@ -229,6 +236,19 @@ static int StrCmp(const char *l, const char *r) {
|
||||||
return (l[i] & 255) - (r[i] & 255);
|
return (l[i] & 255) - (r[i] & 255);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *BaseName(const char *s) {
|
||||||
|
int c;
|
||||||
|
const char *b = "";
|
||||||
|
if (s) {
|
||||||
|
while ((c = *s++)) {
|
||||||
|
if (c == '/') {
|
||||||
|
b = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
static void Bzero(void *a, unsigned long n) {
|
static void Bzero(void *a, unsigned long n) {
|
||||||
long z;
|
long z;
|
||||||
char *p, *e;
|
char *p, *e;
|
||||||
|
@ -354,42 +374,86 @@ __attribute__((__noinline__)) static long CallSystem(long arg1, long arg2,
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((__noreturn__)) static void Exit(long rc, int os) {
|
__attribute__((__noreturn__)) static void Exit(long rc, int os) {
|
||||||
CallSystem(rc, 0, 0, 0, 0, 0, 0, IsLinux() ? 60 : 1, os);
|
int numba;
|
||||||
|
if (IsLinux()) {
|
||||||
|
if (IsAarch64()) {
|
||||||
|
numba = 94;
|
||||||
|
} else {
|
||||||
|
numba = 60;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
numba = 1;
|
||||||
|
}
|
||||||
|
CallSystem(rc, 0, 0, 0, 0, 0, 0, numba, os);
|
||||||
__builtin_unreachable();
|
__builtin_unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int Close(int fd, int os) {
|
static int Close(int fd, int os) {
|
||||||
return CallSystem(fd, 0, 0, 0, 0, 0, 0, IsLinux() ? 3 : 6, os);
|
int numba;
|
||||||
|
if (IsLinux()) {
|
||||||
|
if (IsAarch64()) {
|
||||||
|
numba = 57;
|
||||||
|
} else {
|
||||||
|
numba = 3;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
numba = 6;
|
||||||
|
}
|
||||||
|
return CallSystem(fd, 0, 0, 0, 0, 0, 0, numba, os);
|
||||||
}
|
}
|
||||||
|
|
||||||
static long Pread(int fd, void *data, unsigned long size, long off, int os) {
|
static long Pread(int fd, void *data, unsigned long size, long off, int os) {
|
||||||
long magi;
|
long numba;
|
||||||
if (IsLinux()) {
|
if (IsLinux()) {
|
||||||
magi = 0x011;
|
if (IsAarch64()) {
|
||||||
|
numba = 0x043;
|
||||||
|
} else {
|
||||||
|
numba = 0x011;
|
||||||
|
}
|
||||||
} else if (IsXnu()) {
|
} else if (IsXnu()) {
|
||||||
magi = 0x2000099;
|
numba = 0x2000099;
|
||||||
} else if (IsFreebsd()) {
|
} else if (IsFreebsd()) {
|
||||||
magi = 0x1db;
|
numba = 0x1db;
|
||||||
} else if (IsOpenbsd()) {
|
} else if (IsOpenbsd()) {
|
||||||
magi = 0x0a9; /* OpenBSD v7.3+ */
|
numba = 0x0a9; /* OpenBSD v7.3+ */
|
||||||
} else if (IsNetbsd()) {
|
} else if (IsNetbsd()) {
|
||||||
magi = 0x0ad;
|
numba = 0x0ad;
|
||||||
} else {
|
} else {
|
||||||
__builtin_unreachable();
|
__builtin_unreachable();
|
||||||
}
|
}
|
||||||
return SystemCall(fd, (long)data, size, off, off, 0, 0, magi);
|
return SystemCall(fd, (long)data, size, off, off, 0, 0, numba);
|
||||||
}
|
}
|
||||||
|
|
||||||
static long Write(int fd, const void *data, unsigned long size, int os) {
|
static long Write(int fd, const void *data, unsigned long size, int os) {
|
||||||
return CallSystem(fd, (long)data, size, 0, 0, 0, 0, IsLinux() ? 1 : 4, os);
|
int numba;
|
||||||
|
if (IsLinux()) {
|
||||||
|
if (IsAarch64()) {
|
||||||
|
numba = 64;
|
||||||
|
} else {
|
||||||
|
numba = 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
numba = 4;
|
||||||
|
}
|
||||||
|
return CallSystem(fd, (long)data, size, 0, 0, 0, 0, numba, os);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int Execve(const char *prog, char **argv, char **envp, int os) {
|
static int Execve(const char *prog, char **argv, char **envp, int os) {
|
||||||
return CallSystem((long)prog, (long)argv, (long)envp, 0, 0, 0, 0, 59, os);
|
int numba;
|
||||||
|
if (IsLinux() && IsAarch64()) {
|
||||||
|
numba = 221;
|
||||||
|
} else {
|
||||||
|
numba = 59;
|
||||||
|
}
|
||||||
|
return CallSystem((long)prog, (long)argv, (long)envp, 0, 0, 0, 0, numba, os);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int Access(const char *path, int mode, int os) {
|
static int Access(const char *path, int mode, int os) {
|
||||||
return CallSystem((long)path, mode, 0, 0, 0, 0, 0, IsLinux() ? 21 : 33, os);
|
if (IsLinux() && IsAarch64()) {
|
||||||
|
return SystemCall(-100, (long)path, mode, 0, 0, 0, 0, 48);
|
||||||
|
} else {
|
||||||
|
return CallSystem((long)path, mode, 0, 0, 0, 0, 0, IsLinux() ? 21 : 33, os);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int Msyscall(long p, unsigned long n, int os) {
|
static int Msyscall(long p, unsigned long n, int os) {
|
||||||
|
@ -401,31 +465,49 @@ static int Msyscall(long p, unsigned long n, int os) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int Open(const char *path, int flags, int mode, int os) {
|
static int Open(const char *path, int flags, int mode, int os) {
|
||||||
return CallSystem((long)path, flags, mode, 0, 0, 0, 0, IsLinux() ? 2 : 5, os);
|
if (IsLinux() && IsAarch64()) {
|
||||||
|
return SystemCall(-100, (long)path, flags, mode, 0, 0, 0, 56);
|
||||||
|
} else {
|
||||||
|
return CallSystem((long)path, flags, mode, 0, 0, 0, 0, IsLinux() ? 2 : 5,
|
||||||
|
os);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int Mprotect(void *addr, unsigned long size, int prot, int os) {
|
static int Mprotect(void *addr, unsigned long size, int prot, int os) {
|
||||||
return CallSystem((long)addr, size, prot, 0, 0, 0, 0, IsLinux() ? 10 : 74,
|
int numba;
|
||||||
os);
|
if (IsLinux()) {
|
||||||
|
if (IsAarch64()) {
|
||||||
|
numba = 226;
|
||||||
|
} else {
|
||||||
|
numba = 10;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
numba = 74;
|
||||||
|
}
|
||||||
|
return CallSystem((long)addr, size, prot, 0, 0, 0, 0, numba, os);
|
||||||
}
|
}
|
||||||
|
|
||||||
static long Mmap(void *addr, unsigned long size, int prot, int flags, int fd,
|
static long Mmap(void *addr, unsigned long size, int prot, int flags, int fd,
|
||||||
long off, int os) {
|
long off, int os) {
|
||||||
long magi;
|
long numba;
|
||||||
if (IsLinux()) {
|
if (IsLinux()) {
|
||||||
magi = 9;
|
if (IsAarch64()) {
|
||||||
|
numba = 222;
|
||||||
|
} else {
|
||||||
|
numba = 9;
|
||||||
|
}
|
||||||
} else if (IsXnu()) {
|
} else if (IsXnu()) {
|
||||||
magi = 0x2000000 | 197;
|
numba = 0x2000000 | 197;
|
||||||
} else if (IsFreebsd()) {
|
} else if (IsFreebsd()) {
|
||||||
magi = 477;
|
numba = 477;
|
||||||
} else if (IsOpenbsd()) {
|
} else if (IsOpenbsd()) {
|
||||||
magi = 49; /* OpenBSD v7.3+ */
|
numba = 49; /* OpenBSD v7.3+ */
|
||||||
} else if (IsNetbsd()) {
|
} else if (IsNetbsd()) {
|
||||||
magi = 197;
|
numba = 197;
|
||||||
} else {
|
} else {
|
||||||
__builtin_unreachable();
|
__builtin_unreachable();
|
||||||
}
|
}
|
||||||
return SystemCall((long)addr, size, prot, flags, fd, off, off, magi);
|
return SystemCall((long)addr, size, prot, flags, fd, off, off, numba);
|
||||||
}
|
}
|
||||||
|
|
||||||
static long Print(int os, int fd, const char *s, ...) {
|
static long Print(int os, int fd, const char *s, ...) {
|
||||||
|
@ -703,9 +785,15 @@ static const char *TryElf(struct ApeLoader *M, const char *exe, int fd,
|
||||||
if (e->e_type != ET_EXEC && e->e_type != ET_DYN) {
|
if (e->e_type != ET_EXEC && e->e_type != ET_DYN) {
|
||||||
return "ELF not ET_EXEC or ET_DYN";
|
return "ELF not ET_EXEC or ET_DYN";
|
||||||
}
|
}
|
||||||
|
#ifdef __aarch64__
|
||||||
|
if (e->e_machine != EM_AARCH64) {
|
||||||
|
return "couldn't find ELF header with AARCH64 machine type";
|
||||||
|
}
|
||||||
|
#else
|
||||||
if (e->e_machine != EM_NEXGEN32E) {
|
if (e->e_machine != EM_NEXGEN32E) {
|
||||||
return "couldn't find ELF header with x86-64 machine type";
|
return "couldn't find ELF header with x86-64 machine type";
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
if (e->e_phentsize != sizeof(struct ElfPhdr)) {
|
if (e->e_phentsize != sizeof(struct ElfPhdr)) {
|
||||||
Pexit(os, exe, 0, "e_phentsize is wrong");
|
Pexit(os, exe, 0, "e_phentsize is wrong");
|
||||||
}
|
}
|
||||||
|
@ -796,7 +884,7 @@ static __attribute__((__noreturn__)) void ShowUsage(int os, int fd, int rc) {
|
||||||
Print(os, fd,
|
Print(os, fd,
|
||||||
"NAME\n"
|
"NAME\n"
|
||||||
"\n"
|
"\n"
|
||||||
" actually portable executable loader version 1.4\n"
|
" actually portable executable loader version 1.5\n"
|
||||||
" copyright 2023 justine alexandra roberts tunney\n"
|
" copyright 2023 justine alexandra roberts tunney\n"
|
||||||
" https://justine.lol/ape.html\n"
|
" https://justine.lol/ape.html\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
@ -814,10 +902,10 @@ static __attribute__((__noreturn__)) void ShowUsage(int os, int fd, int rc) {
|
||||||
Exit(rc, os);
|
Exit(rc, os);
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((__noreturn__)) void ApeLoader(long di, long *sp, char dl) {
|
__attribute__((__noreturn__)) //
|
||||||
|
void ApeLoader(long di, long *sp, char dl) {
|
||||||
int rc;
|
int rc;
|
||||||
unsigned i, n;
|
unsigned i, n;
|
||||||
int usetheforce;
|
|
||||||
int c, fd, os, argc;
|
int c, fd, os, argc;
|
||||||
struct ApeLoader *M;
|
struct ApeLoader *M;
|
||||||
unsigned long pagesz;
|
unsigned long pagesz;
|
||||||
|
@ -879,14 +967,11 @@ __attribute__((__noreturn__)) void ApeLoader(long di, long *sp, char dl) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* parse flags */
|
/* parse flags */
|
||||||
usetheforce = 0;
|
|
||||||
while (argc > 1) {
|
while (argc > 1) {
|
||||||
if (argv[1][0] != '-') break; /* normal argument */
|
if (argv[1][0] != '-') break; /* normal argument */
|
||||||
if (!argv[1][1]) break; /* hyphen argument */
|
if (!argv[1][1]) break; /* hyphen argument */
|
||||||
if (!StrCmp(argv[1], "-h") || !StrCmp(argv[1], "--help")) {
|
if (!StrCmp(argv[1], "-h") || !StrCmp(argv[1], "--help")) {
|
||||||
ShowUsage(os, 1, 0);
|
ShowUsage(os, 1, 0);
|
||||||
} else if (!StrCmp(argv[1], "-f")) {
|
|
||||||
usetheforce = 1;
|
|
||||||
} else {
|
} else {
|
||||||
Print(os, 2, ape, ": invalid flag (pass -h for help)\n", 0l);
|
Print(os, 2, ape, ": invalid flag (pass -h for help)\n", 0l);
|
||||||
Exit(1, os);
|
Exit(1, os);
|
||||||
|
@ -926,25 +1011,16 @@ __attribute__((__noreturn__)) void ApeLoader(long di, long *sp, char dl) {
|
||||||
pe = M->ehdr.buf + rc;
|
pe = M->ehdr.buf + rc;
|
||||||
|
|
||||||
/* change argv[0] to resolved path if it's ambiguous */
|
/* change argv[0] to resolved path if it's ambiguous */
|
||||||
if (argc > 0 && *prog != '/' && *exe == '/' && !StrCmp(prog, argv[0])) {
|
if ((argc > 0 && *prog != '/' && *exe == '/' && !StrCmp(prog, argv[0])) ||
|
||||||
|
!StrCmp(BaseName(prog), argv[0])) {
|
||||||
argv[0] = exe;
|
argv[0] = exe;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ape intended behavior
|
/* ape intended behavior
|
||||||
1. if file is a native executable, try to run it natively
|
1. if ape, will scan shell script for elf printf statements
|
||||||
2. if ape, will scan shell script for elf printf statements
|
2. shell script may have multiple lines producing elf headers
|
||||||
3. shell script may have multiple lines producing elf headers
|
3. all elf printf lines must exist in the first 8192 bytes of file
|
||||||
4. all elf printf lines must exist in the first 8192 bytes of file
|
4. elf program headers may appear anywhere in the binary */
|
||||||
5. elf program headers may appear anywhere in the binary */
|
|
||||||
if (!usetheforce &&
|
|
||||||
((IsXnu() && READ32(M->ehdr.buf) == 0xFEEDFACE + 1) ||
|
|
||||||
(!IsXnu() && READ32(M->ehdr.buf) == READ32("\177ELF")))) {
|
|
||||||
Close(fd, os);
|
|
||||||
Execve(exe, argv, envp, os);
|
|
||||||
if ((fd = Open(exe, O_RDONLY, 0, os)) < 0) {
|
|
||||||
Pexit(os, exe, rc, "execve and open failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (READ64(M->ehdr.buf) == READ64("MZqFpD='") ||
|
if (READ64(M->ehdr.buf) == READ64("MZqFpD='") ||
|
||||||
READ64(M->ehdr.buf) == READ64("jartsr='") ||
|
READ64(M->ehdr.buf) == READ64("jartsr='") ||
|
||||||
READ64(M->ehdr.buf) == READ64("APEDBG='")) {
|
READ64(M->ehdr.buf) == READ64("APEDBG='")) {
|
||||||
|
|
13
ape/start.S
13
ape/start.S
|
@ -19,6 +19,15 @@
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
|
|
||||||
|
#ifdef __aarch64__
|
||||||
|
|
||||||
|
_start: mov x1,sp
|
||||||
|
mov x29,0
|
||||||
|
bl ApeLoader
|
||||||
|
.endfn _start,globl
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
XnuEntrypoint:
|
XnuEntrypoint:
|
||||||
mov $_HOSTXNU,%dl // xnu's not unix!
|
mov $_HOSTXNU,%dl // xnu's not unix!
|
||||||
ElfEntrypoint:
|
ElfEntrypoint:
|
||||||
|
@ -56,6 +65,8 @@ ape.ident:
|
||||||
.long 1
|
.long 1
|
||||||
1: .asciz "APE"
|
1: .asciz "APE"
|
||||||
2: .balign 4
|
2: .balign 4
|
||||||
3: .long 104000000
|
3: .long 105000000
|
||||||
4: .size ape.ident,.-ape.ident
|
4: .size ape.ident,.-ape.ident
|
||||||
.type ape.ident,@object
|
.type ape.ident,@object
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -28,6 +28,16 @@
|
||||||
// errors are returned as `-errno`. BSD systems are normalized
|
// errors are returned as `-errno`. BSD systems are normalized
|
||||||
// to follow this convention automatically.
|
// to follow this convention automatically.
|
||||||
SystemCall:
|
SystemCall:
|
||||||
|
#ifdef __aarch64__
|
||||||
|
mov x8,x7
|
||||||
|
mov x9,0
|
||||||
|
adds x9,x9,0
|
||||||
|
svc 0
|
||||||
|
bcs 1f
|
||||||
|
ret
|
||||||
|
1: neg x0,x0
|
||||||
|
ret
|
||||||
|
#else
|
||||||
mov %rcx,%r10
|
mov %rcx,%r10
|
||||||
mov 16(%rsp),%eax
|
mov 16(%rsp),%eax
|
||||||
clc
|
clc
|
||||||
|
@ -35,4 +45,5 @@ SystemCall:
|
||||||
jnc 1f
|
jnc 1f
|
||||||
neg %rax
|
neg %rax
|
||||||
1: ret
|
1: ret
|
||||||
|
#endif
|
||||||
.endfn SystemCall,globl
|
.endfn SystemCall,globl
|
||||||
|
|
BIN
build/bootstrap/ape.aarch64
Executable file
BIN
build/bootstrap/ape.aarch64
Executable file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -75,7 +75,7 @@ extern char *ttyraster(char *, const struct TtyRgb *, size_t, size_t,
|
||||||
|
|
||||||
#ifndef ttyquant
|
#ifndef ttyquant
|
||||||
#define ttyquant() (&g_ttyquant_)
|
#define ttyquant() (&g_ttyquant_)
|
||||||
#define TTYQUANT() VEIL("r", &g_ttyquant_)
|
#define TTYQUANT() __veil("r", &g_ttyquant_)
|
||||||
#define rgb2tty(...) (ttyquant()->rgb2tty(__VA_ARGS__))
|
#define rgb2tty(...) (ttyquant()->rgb2tty(__VA_ARGS__))
|
||||||
#define tty2rgb(...) (ttyquant()->tty2rgb(__VA_ARGS__))
|
#define tty2rgb(...) (ttyquant()->tty2rgb(__VA_ARGS__))
|
||||||
#define rgb2ttyf(...) (ttyquant()->rgb2ttyf(__VA_ARGS__))
|
#define rgb2ttyf(...) (ttyquant()->rgb2ttyf(__VA_ARGS__))
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
#include "third_party/mbedtls/ssl.h"
|
#include "third_party/mbedtls/ssl.h"
|
||||||
#include "third_party/mbedtls/x509_crt.h"
|
#include "third_party/mbedtls/x509_crt.h"
|
||||||
|
|
||||||
STATIC_YOINK("ssl_root_support");
|
__static_yoink("ssl_root_support");
|
||||||
|
|
||||||
#define MODE_NONE 0
|
#define MODE_NONE 0
|
||||||
#define MODE_FILE 1
|
#define MODE_FILE 1
|
||||||
|
|
|
@ -75,8 +75,8 @@
|
||||||
* the following functions to further expand the information shown by
|
* the following functions to further expand the information shown by
|
||||||
* the NDEBUG check failure:
|
* the NDEBUG check failure:
|
||||||
*
|
*
|
||||||
* STATIC_YOINK("__die");
|
* __static_yoink("__die");
|
||||||
* STATIC_YOINK("strerror");
|
* __static_yoink("strerror");
|
||||||
*
|
*
|
||||||
* Please note that backtraces aren't ever available in MODE=tiny.
|
* Please note that backtraces aren't ever available in MODE=tiny.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
* o//examples/crashreport.com
|
* o//examples/crashreport.com
|
||||||
*/
|
*/
|
||||||
|
|
||||||
noubsan int main(int argc, char *argv[]) {
|
dontubsan int main(int argc, char *argv[]) {
|
||||||
kprintf("----------------\n");
|
kprintf("----------------\n");
|
||||||
kprintf(" THIS IS A TEST \n");
|
kprintf(" THIS IS A TEST \n");
|
||||||
kprintf("SIMULATING CRASH\n");
|
kprintf("SIMULATING CRASH\n");
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/sysv/consts/sig.h"
|
#include "libc/sysv/consts/sig.h"
|
||||||
|
|
||||||
STATIC_YOINK("strerror");
|
__static_yoink("strerror");
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
sigset_t ss;
|
sigset_t ss;
|
||||||
|
|
|
@ -48,7 +48,7 @@
|
||||||
#include "third_party/libcxx/vector"
|
#include "third_party/libcxx/vector"
|
||||||
#include "tool/viz/lib/knobs.h"
|
#include "tool/viz/lib/knobs.h"
|
||||||
|
|
||||||
STATIC_YOINK("zipos");
|
__static_yoink("zipos");
|
||||||
|
|
||||||
#define USAGE \
|
#define USAGE \
|
||||||
" [ROM] [FMV]\n\
|
" [ROM] [FMV]\n\
|
||||||
|
|
|
@ -15,8 +15,8 @@
|
||||||
* Yes this works on Windows.
|
* Yes this works on Windows.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
STATIC_YOINK("_tr");
|
__static_yoink("_tr");
|
||||||
STATIC_YOINK("_sed");
|
__static_yoink("_sed");
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
system("x=world\n"
|
system("x=world\n"
|
||||||
|
|
|
@ -28,12 +28,12 @@
|
||||||
* Please note that, by default, APE binaries only use the serial port
|
* Please note that, by default, APE binaries only use the serial port
|
||||||
* for stdio. To get the VGA console as an added bonus:
|
* for stdio. To get the VGA console as an added bonus:
|
||||||
*
|
*
|
||||||
* STATIC_YOINK("vga_console");
|
* __static_yoink("vga_console");
|
||||||
*
|
*
|
||||||
* Should be added to the top of your main() program source file.
|
* Should be added to the top of your main() program source file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
STATIC_YOINK("vga_console");
|
__static_yoink("vga_console");
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
volatile long double x = -.5;
|
volatile long double x = -.5;
|
||||||
|
|
|
@ -24,9 +24,9 @@
|
||||||
* qemu-system-x86_64 -hda o//examples/vga2.com -serial stdio
|
* qemu-system-x86_64 -hda o//examples/vga2.com -serial stdio
|
||||||
*/
|
*/
|
||||||
|
|
||||||
STATIC_YOINK("vga_console");
|
__static_yoink("vga_console");
|
||||||
STATIC_YOINK("_idt");
|
__static_yoink("_idt");
|
||||||
STATIC_YOINK("EfiMain");
|
__static_yoink("EfiMain");
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
int i;
|
int i;
|
||||||
|
|
|
@ -18,8 +18,8 @@ void __assert_fail(const char *, const char *, int) relegated;
|
||||||
#ifdef COSMO
|
#ifdef COSMO
|
||||||
extern bool __assert_disable;
|
extern bool __assert_disable;
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
#define _unassert(x) __assert_macro(x, #x)
|
#define unassert(x) __assert_macro(x, #x)
|
||||||
#define _npassert(x) __assert_macro(x, #x)
|
#define npassert(x) __assert_macro(x, #x)
|
||||||
#define __assert_macro(x, s) \
|
#define __assert_macro(x, s) \
|
||||||
({ \
|
({ \
|
||||||
if (__builtin_expect(!(x), 0)) { \
|
if (__builtin_expect(!(x), 0)) { \
|
||||||
|
@ -29,14 +29,14 @@ extern bool __assert_disable;
|
||||||
(void)0; \
|
(void)0; \
|
||||||
})
|
})
|
||||||
#else
|
#else
|
||||||
#define _npassert(x) \
|
#define npassert(x) \
|
||||||
({ \
|
({ \
|
||||||
if (__builtin_expect(!(x), 0)) { \
|
if (__builtin_expect(!(x), 0)) { \
|
||||||
__builtin_trap(); \
|
__builtin_trap(); \
|
||||||
} \
|
} \
|
||||||
(void)0; \
|
(void)0; \
|
||||||
})
|
})
|
||||||
#define _unassert(x) \
|
#define unassert(x) \
|
||||||
({ \
|
({ \
|
||||||
if (__builtin_expect(!(x), 0)) { \
|
if (__builtin_expect(!(x), 0)) { \
|
||||||
__builtin_unreachable(); \
|
__builtin_unreachable(); \
|
||||||
|
|
|
@ -35,7 +35,7 @@ unsigned alarm(unsigned seconds) {
|
||||||
struct itimerval it;
|
struct itimerval it;
|
||||||
bzero(&it, sizeof(it));
|
bzero(&it, sizeof(it));
|
||||||
it.it_value.tv_sec = seconds;
|
it.it_value.tv_sec = seconds;
|
||||||
_npassert(!setitimer(ITIMER_REAL, &it, &it));
|
npassert(!setitimer(ITIMER_REAL, &it, &it));
|
||||||
if (!it.it_value.tv_sec && !it.it_value.tv_usec) {
|
if (!it.it_value.tv_sec && !it.it_value.tv_usec) {
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -80,11 +80,11 @@ static struct timespec GetNanosleepLatency(void) {
|
||||||
if (!(nanos = g_nanosleep_latency)) {
|
if (!(nanos = g_nanosleep_latency)) {
|
||||||
BLOCK_CANCELLATIONS;
|
BLOCK_CANCELLATIONS;
|
||||||
for (cgt = __clock_gettime_get(0);;) {
|
for (cgt = __clock_gettime_get(0);;) {
|
||||||
_npassert(!cgt(CLOCK_REALTIME_PRECISE, &x));
|
npassert(!cgt(CLOCK_REALTIME_PRECISE, &x));
|
||||||
rc = sys_clock_nanosleep(CLOCK_REALTIME, 0, &w, 0);
|
rc = sys_clock_nanosleep(CLOCK_REALTIME, 0, &w, 0);
|
||||||
_npassert(!rc || rc == EINTR);
|
npassert(!rc || rc == EINTR);
|
||||||
if (!rc) {
|
if (!rc) {
|
||||||
_npassert(!cgt(CLOCK_REALTIME_PRECISE, &y));
|
npassert(!cgt(CLOCK_REALTIME_PRECISE, &y));
|
||||||
nanos = timespec_tonanos(timespec_sub(y, x));
|
nanos = timespec_tonanos(timespec_sub(y, x));
|
||||||
g_nanosleep_latency = nanos;
|
g_nanosleep_latency = nanos;
|
||||||
break;
|
break;
|
||||||
|
@ -115,10 +115,10 @@ static errno_t SpinNanosleep(int clock, int flags, const struct timespec *req,
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
cgt = __clock_gettime_get(0);
|
cgt = __clock_gettime_get(0);
|
||||||
_npassert(!cgt(CLOCK_REALTIME, &start));
|
npassert(!cgt(CLOCK_REALTIME, &start));
|
||||||
for (;;) {
|
for (;;) {
|
||||||
sched_yield();
|
sched_yield();
|
||||||
_npassert(!cgt(CLOCK_REALTIME, &now));
|
npassert(!cgt(CLOCK_REALTIME, &now));
|
||||||
if (flags & TIMER_ABSTIME) {
|
if (flags & TIMER_ABSTIME) {
|
||||||
if (timespec_cmp(now, *req) >= 0) {
|
if (timespec_cmp(now, *req) >= 0) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
// Implements dup(), dup2(), dup3(), and F_DUPFD for Windows.
|
// Implements dup(), dup2(), dup3(), and F_DUPFD for Windows.
|
||||||
textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) {
|
textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) {
|
||||||
int64_t rc, proc, handle;
|
int64_t rc, proc, handle;
|
||||||
_unassert(!(flags & ~O_CLOEXEC));
|
unassert(!(flags & ~O_CLOEXEC));
|
||||||
|
|
||||||
__fds_lock();
|
__fds_lock();
|
||||||
|
|
||||||
|
|
|
@ -45,9 +45,9 @@ static void sys_dup3_test(void) {
|
||||||
|
|
||||||
int32_t sys_dup3(int32_t oldfd, int32_t newfd, int flags) {
|
int32_t sys_dup3(int32_t oldfd, int32_t newfd, int flags) {
|
||||||
int how;
|
int how;
|
||||||
_unassert(oldfd >= 0);
|
unassert(oldfd >= 0);
|
||||||
_unassert(newfd >= 0);
|
unassert(newfd >= 0);
|
||||||
_unassert(!(flags & ~O_CLOEXEC));
|
unassert(!(flags & ~O_CLOEXEC));
|
||||||
|
|
||||||
if (IsFreebsd()) {
|
if (IsFreebsd()) {
|
||||||
if (flags & O_CLOEXEC) {
|
if (flags & O_CLOEXEC) {
|
||||||
|
|
|
@ -85,8 +85,8 @@ int sys_execve(const char *prog, char *const argv[], char *const envp[]) {
|
||||||
(CanExecute((ape = "/usr/bin/ape")) ||
|
(CanExecute((ape = "/usr/bin/ape")) ||
|
||||||
CanExecute((ape = Join(firstnonnull(getenv("TMPDIR"),
|
CanExecute((ape = Join(firstnonnull(getenv("TMPDIR"),
|
||||||
firstnonnull(getenv("HOME"), ".")),
|
firstnonnull(getenv("HOME"), ".")),
|
||||||
".ape-1.4", buf))) ||
|
".ape-1.5", buf))) ||
|
||||||
CanExecute((ape = Join(firstnonnull(getenv("HOME"), "."), ".ape-1.4",
|
CanExecute((ape = Join(firstnonnull(getenv("HOME"), "."), ".ape-1.5",
|
||||||
buf))))) {
|
buf))))) {
|
||||||
shargs[0] = ape;
|
shargs[0] = ape;
|
||||||
shargs[1] = "-";
|
shargs[1] = "-";
|
||||||
|
|
|
@ -52,7 +52,7 @@ int fadvise(int fd, uint64_t offset, uint64_t len, int advice) {
|
||||||
} else {
|
} else {
|
||||||
rc = sys_fadvise_netbsd(fd, offset, offset, len, advice);
|
rc = sys_fadvise_netbsd(fd, offset, offset, len, advice);
|
||||||
}
|
}
|
||||||
_npassert(rc >= 0);
|
npassert(rc >= 0);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
errno = rc;
|
errno = rc;
|
||||||
rc = -1;
|
rc = -1;
|
||||||
|
|
|
@ -158,7 +158,7 @@ static int fd_to_mem_fd(const int infd, char *path) {
|
||||||
if (path) {
|
if (path) {
|
||||||
FormatInt32(stpcpy(path, "COSMOPOLITAN_INIT_ZIPOS="), fd);
|
FormatInt32(stpcpy(path, "COSMOPOLITAN_INIT_ZIPOS="), fd);
|
||||||
}
|
}
|
||||||
_unassert(readRc == st.st_size);
|
unassert(readRc == st.st_size);
|
||||||
return fd;
|
return fd;
|
||||||
} else if (!success) {
|
} else if (!success) {
|
||||||
errno = e;
|
errno = e;
|
||||||
|
|
|
@ -29,12 +29,12 @@ int __fixupnewfd(int fd, int flags) {
|
||||||
int file_mode;
|
int file_mode;
|
||||||
if (fd != -1) {
|
if (fd != -1) {
|
||||||
if (flags & O_CLOEXEC) {
|
if (flags & O_CLOEXEC) {
|
||||||
_unassert((file_mode = __sys_fcntl(fd, F_GETFD)) != -1);
|
unassert((file_mode = __sys_fcntl(fd, F_GETFD)) != -1);
|
||||||
_unassert(!__sys_fcntl(fd, F_SETFD, file_mode | FD_CLOEXEC));
|
unassert(!__sys_fcntl(fd, F_SETFD, file_mode | FD_CLOEXEC));
|
||||||
}
|
}
|
||||||
if (flags & O_NONBLOCK) {
|
if (flags & O_NONBLOCK) {
|
||||||
_unassert((file_mode = __sys_fcntl(fd, F_GETFL)) != -1);
|
unassert((file_mode = __sys_fcntl(fd, F_GETFL)) != -1);
|
||||||
_unassert(!__sys_fcntl(fd, F_SETFL, file_mode | O_NONBLOCK));
|
unassert(!__sys_fcntl(fd, F_SETFL, file_mode | O_NONBLOCK));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fd;
|
return fd;
|
||||||
|
|
|
@ -31,7 +31,7 @@ textwindows int sys_ftruncate_nt(int64_t handle, uint64_t length) {
|
||||||
if ((ok = SetFilePointerEx(handle, 0, &tell, kNtFileCurrent))) {
|
if ((ok = SetFilePointerEx(handle, 0, &tell, kNtFileCurrent))) {
|
||||||
ok = SetFilePointerEx(handle, length, NULL, kNtFileBegin) &&
|
ok = SetFilePointerEx(handle, length, NULL, kNtFileBegin) &&
|
||||||
SetEndOfFile(handle);
|
SetEndOfFile(handle);
|
||||||
_npassert(SetFilePointerEx(handle, tell, NULL, kNtFileBegin));
|
npassert(SetFilePointerEx(handle, tell, NULL, kNtFileBegin));
|
||||||
}
|
}
|
||||||
if (ok) {
|
if (ok) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -52,7 +52,7 @@ char *getcwd(char *buf, size_t size) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else if (_weaken(malloc)) {
|
} else if (_weaken(malloc)) {
|
||||||
_unassert(!__vforked);
|
unassert(!__vforked);
|
||||||
if (!size) size = PATH_MAX;
|
if (!size) size = PATH_MAX;
|
||||||
if (!(p = _weaken(malloc)(size))) {
|
if (!(p = _weaken(malloc)(size))) {
|
||||||
STRACE("getcwd(%p, %'zu) %m", buf, size);
|
STRACE("getcwd(%p, %'zu) %m", buf, size);
|
||||||
|
@ -60,7 +60,7 @@ char *getcwd(char *buf, size_t size) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
einval();
|
einval();
|
||||||
STRACE("getcwd() needs buf≠0 or STATIC_YOINK(\"malloc\")");
|
STRACE("getcwd() needs buf≠0 or __static_yoink(\"malloc\")");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
|
|
|
@ -44,7 +44,7 @@ int getppid(void) {
|
||||||
} else {
|
} else {
|
||||||
rc = sys_getppid_nt();
|
rc = sys_getppid_nt();
|
||||||
}
|
}
|
||||||
_npassert(rc >= 0);
|
npassert(rc >= 0);
|
||||||
STRACE("%s() → %d", "getppid", rc);
|
STRACE("%s() → %d", "getppid", rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@ uint32_t getuid(void) {
|
||||||
} else {
|
} else {
|
||||||
rc = GetUserNameHash();
|
rc = GetUserNameHash();
|
||||||
}
|
}
|
||||||
_npassert(rc >= 0);
|
npassert(rc >= 0);
|
||||||
STRACE("%s() → %d", "getuid", rc);
|
STRACE("%s() → %d", "getuid", rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ uint32_t getgid(void) {
|
||||||
} else {
|
} else {
|
||||||
rc = GetUserNameHash();
|
rc = GetUserNameHash();
|
||||||
}
|
}
|
||||||
_npassert(rc >= 0);
|
npassert(rc >= 0);
|
||||||
STRACE("%s() → %d", "getgid", rc);
|
STRACE("%s() → %d", "getgid", rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -291,7 +291,7 @@ static textwindows int createHostInfo(
|
||||||
char name[IFNAMSIZ];
|
char name[IFNAMSIZ];
|
||||||
int count, i;
|
int count, i;
|
||||||
/* __hostInfo must be empty */
|
/* __hostInfo must be empty */
|
||||||
_unassert(__hostInfo == NULL);
|
unassert(__hostInfo == NULL);
|
||||||
for (aa = firstAdapter; aa; aa = aa->Next) {
|
for (aa = firstAdapter; aa; aa = aa->Next) {
|
||||||
/* Skip all the interfaces with no address and the ones that are not AF_INET
|
/* Skip all the interfaces with no address and the ones that are not AF_INET
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -47,12 +47,12 @@
|
||||||
#define MAP_FIXED_linux 0x00000010
|
#define MAP_FIXED_linux 0x00000010
|
||||||
#define MAP_SHARED_linux 0x00000001
|
#define MAP_SHARED_linux 0x00000001
|
||||||
|
|
||||||
STATIC_YOINK("_init_metalfile");
|
__static_yoink("_init_metalfile");
|
||||||
|
|
||||||
void *__ape_com_base;
|
void *__ape_com_base;
|
||||||
size_t __ape_com_size = 0;
|
size_t __ape_com_size = 0;
|
||||||
|
|
||||||
textstartup noasan void InitializeMetalFile(void) {
|
textstartup dontasan void InitializeMetalFile(void) {
|
||||||
if (IsMetal()) {
|
if (IsMetal()) {
|
||||||
/*
|
/*
|
||||||
* Copy out a pristine image of the program — before the program might
|
* Copy out a pristine image of the program — before the program might
|
||||||
|
@ -61,7 +61,7 @@ textstartup noasan void InitializeMetalFile(void) {
|
||||||
* This code is included if a symbol "file:/proc/self/exe" is defined
|
* This code is included if a symbol "file:/proc/self/exe" is defined
|
||||||
* (see libc/calls/metalfile.internal.h & libc/calls/metalfile_init.S).
|
* (see libc/calls/metalfile.internal.h & libc/calls/metalfile_init.S).
|
||||||
* The zipos code will automatically arrange to do this. Alternatively,
|
* The zipos code will automatically arrange to do this. Alternatively,
|
||||||
* user code can STATIC_YOINK this symbol.
|
* user code can __static_yoink this symbol.
|
||||||
*/
|
*/
|
||||||
size_t size = ROUNDUP(_ezip - __executable_start, 4096);
|
size_t size = ROUNDUP(_ezip - __executable_start, 4096);
|
||||||
// TODO(jart): Restore support for ZIPOS on metal.
|
// TODO(jart): Restore support for ZIPOS on metal.
|
||||||
|
@ -70,7 +70,7 @@ textstartup noasan void InitializeMetalFile(void) {
|
||||||
dm = sys_mmap_metal(NULL, size, PROT_READ | PROT_WRITE,
|
dm = sys_mmap_metal(NULL, size, PROT_READ | PROT_WRITE,
|
||||||
MAP_SHARED_linux | MAP_ANONYMOUS_linux, -1, 0);
|
MAP_SHARED_linux | MAP_ANONYMOUS_linux, -1, 0);
|
||||||
copied_base = dm.addr;
|
copied_base = dm.addr;
|
||||||
_npassert(copied_base != (void *)-1);
|
npassert(copied_base != (void *)-1);
|
||||||
memcpy(copied_base, (void *)(BANE + IMAGE_BASE_PHYSICAL), size);
|
memcpy(copied_base, (void *)(BANE + IMAGE_BASE_PHYSICAL), size);
|
||||||
__ape_com_base = copied_base;
|
__ape_com_base = copied_base;
|
||||||
__ape_com_size = size;
|
__ape_com_size = size;
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#include "libc/runtime/pc.internal.h"
|
#include "libc/runtime/pc.internal.h"
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
|
|
||||||
noasan int sys_munmap_metal(void *addr, size_t size) {
|
dontasan int sys_munmap_metal(void *addr, size_t size) {
|
||||||
size_t i;
|
size_t i;
|
||||||
uint64_t *e, paddr;
|
uint64_t *e, paddr;
|
||||||
struct mman *mm = __get_mm();
|
struct mman *mm = __get_mm();
|
||||||
|
|
|
@ -92,7 +92,7 @@ static long double nowl_art(void) {
|
||||||
static long double nowl_vdso(void) {
|
static long double nowl_vdso(void) {
|
||||||
long double secs;
|
long double secs;
|
||||||
struct timespec tv;
|
struct timespec tv;
|
||||||
_unassert(__gettime);
|
unassert(__gettime);
|
||||||
__gettime(CLOCK_REALTIME_PRECISE, &tv);
|
__gettime(CLOCK_REALTIME_PRECISE, &tv);
|
||||||
secs = tv.tv_nsec;
|
secs = tv.tv_nsec;
|
||||||
secs *= 1 / 1e9L;
|
secs *= 1 / 1e9L;
|
||||||
|
|
|
@ -53,7 +53,7 @@ static textwindows int sys_open_nt_console(int dirfd,
|
||||||
-1) {
|
-1) {
|
||||||
g_fds.p[fd].extra = sys_open_nt_impl(dirfd, mp->conout,
|
g_fds.p[fd].extra = sys_open_nt_impl(dirfd, mp->conout,
|
||||||
(flags & ~O_ACCMODE) | O_WRONLY, mode);
|
(flags & ~O_ACCMODE) | O_WRONLY, mode);
|
||||||
_npassert(g_fds.p[fd].extra != -1);
|
npassert(g_fds.p[fd].extra != -1);
|
||||||
} else {
|
} else {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@
|
||||||
*
|
*
|
||||||
* If your main() source file has this statement:
|
* If your main() source file has this statement:
|
||||||
*
|
*
|
||||||
* STATIC_YOINK("zipos");
|
* __static_yoink("zipos");
|
||||||
*
|
*
|
||||||
* Then you can read zip assets by adding a `"/zip/..."` prefix to `file`, e.g.
|
* Then you can read zip assets by adding a `"/zip/..."` prefix to `file`, e.g.
|
||||||
*
|
*
|
||||||
|
|
|
@ -66,8 +66,8 @@ static int openpty_impl(int *mfd, int *sfd, char *name,
|
||||||
*mfd = m;
|
*mfd = m;
|
||||||
*sfd = s;
|
*sfd = s;
|
||||||
if (name) strcpy(name, t.sname);
|
if (name) strcpy(name, t.sname);
|
||||||
if (tio) _npassert(!tcsetattr(s, TCSAFLUSH, tio));
|
if (tio) npassert(!tcsetattr(s, TCSAFLUSH, tio));
|
||||||
if (wsz) _npassert(!tcgetwinsize(s, wsz));
|
if (wsz) npassert(!tcgetwinsize(s, wsz));
|
||||||
return 0;
|
return 0;
|
||||||
OnError:
|
OnError:
|
||||||
if (m != -1) sys_close(m);
|
if (m != -1) sys_close(m);
|
||||||
|
|
|
@ -51,10 +51,10 @@ errno_t posix_fadvise(int fd, int64_t offset, int64_t len, int advice) {
|
||||||
rc = sys_fadvise(fd, offset, len, advice);
|
rc = sys_fadvise(fd, offset, len, advice);
|
||||||
} else if (IsFreebsd()) {
|
} else if (IsFreebsd()) {
|
||||||
rc = sys_fadvise(fd, offset, len, advice);
|
rc = sys_fadvise(fd, offset, len, advice);
|
||||||
_unassert(rc >= 0);
|
unassert(rc >= 0);
|
||||||
} else if (IsNetbsd()) {
|
} else if (IsNetbsd()) {
|
||||||
rc = sys_fadvise_netbsd(fd, offset, offset, len, advice);
|
rc = sys_fadvise_netbsd(fd, offset, offset, len, advice);
|
||||||
_unassert(rc >= 0);
|
unassert(rc >= 0);
|
||||||
} else if (IsWindows()) {
|
} else if (IsWindows()) {
|
||||||
rc = sys_fadvise_nt(fd, offset, len, advice);
|
rc = sys_fadvise_nt(fd, offset, len, advice);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -76,7 +76,7 @@ ssize_t pread(int fd, void *buf, size_t size, int64_t offset) {
|
||||||
} else {
|
} else {
|
||||||
rc = ebadf();
|
rc = ebadf();
|
||||||
}
|
}
|
||||||
_npassert(rc == -1 || (size_t)rc <= size);
|
npassert(rc == -1 || (size_t)rc <= size);
|
||||||
|
|
||||||
END_CANCELLATION_POINT;
|
END_CANCELLATION_POINT;
|
||||||
DATATRACE("pread(%d, [%#.*hhs%s], %'zu, %'zd) → %'zd% m", fd,
|
DATATRACE("pread(%d, [%#.*hhs%s], %'zu, %'zd) → %'zd% m", fd,
|
||||||
|
|
|
@ -69,9 +69,9 @@ ssize_t pwrite(int fd, const void *buf, size_t size, int64_t offset) {
|
||||||
if (rc != -1) {
|
if (rc != -1) {
|
||||||
wrote = (size_t)rc;
|
wrote = (size_t)rc;
|
||||||
if (!wrote) {
|
if (!wrote) {
|
||||||
_npassert(size == 0);
|
npassert(size == 0);
|
||||||
} else {
|
} else {
|
||||||
_npassert(wrote <= size);
|
npassert(wrote <= size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ static textwindows inline bool HasWorkingConsole(void) {
|
||||||
return !!(__ntconsolemode[0] | __ntconsolemode[1] | __ntconsolemode[2]);
|
return !!(__ntconsolemode[0] | __ntconsolemode[1] | __ntconsolemode[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static noubsan void RaiseSigFpe(void) {
|
static dontubsan void RaiseSigFpe(void) {
|
||||||
volatile int x = 0;
|
volatile int x = 0;
|
||||||
x = 1 / x;
|
x = 1 / x;
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,7 +81,7 @@ static textwindows ssize_t sys_read_nt_impl(struct Fd *fd, void *data,
|
||||||
if (!ok && GetLastError() == kNtErrorIoPending) ok = true;
|
if (!ok && GetLastError() == kNtErrorIoPending) ok = true;
|
||||||
if (ok) ok = GetOverlappedResult(fd->handle, &overlap, &got, true);
|
if (ok) ok = GetOverlappedResult(fd->handle, &overlap, &got, true);
|
||||||
// restore file pointer which windows clobbers, even on error
|
// restore file pointer which windows clobbers, even on error
|
||||||
_unassert(SetFilePointerEx(fd->handle, position, 0, SEEK_SET));
|
unassert(SetFilePointerEx(fd->handle, position, 0, SEEK_SET));
|
||||||
}
|
}
|
||||||
if (ok) {
|
if (ok) {
|
||||||
return got;
|
return got;
|
||||||
|
|
|
@ -181,7 +181,7 @@ skip_readlink:
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
k = rc;
|
k = rc;
|
||||||
_npassert(k <= p);
|
npassert(k <= p);
|
||||||
if (k==p)
|
if (k==p)
|
||||||
goto toolong;
|
goto toolong;
|
||||||
if (!k) {
|
if (!k) {
|
||||||
|
|
|
@ -49,13 +49,13 @@
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
#ifdef SYSDEBUG
|
#ifdef SYSDEBUG
|
||||||
STATIC_YOINK("strsignal"); // for kprintf()
|
__static_yoink("strsignal"); // for kprintf()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if SupportsWindows()
|
#if SupportsWindows()
|
||||||
STATIC_YOINK("_init_onntconsoleevent");
|
__static_yoink("_init_onntconsoleevent");
|
||||||
STATIC_YOINK("_check_sigwinch");
|
__static_yoink("_check_sigwinch");
|
||||||
STATIC_YOINK("_init_wincrash");
|
__static_yoink("_init_wincrash");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define SA_RESTORER 0x04000000
|
#define SA_RESTORER 0x04000000
|
||||||
|
|
|
@ -28,7 +28,7 @@ sigset_t _sigsetmask(sigset_t neu) {
|
||||||
if (IsMetal() || IsWindows()) {
|
if (IsMetal() || IsWindows()) {
|
||||||
__sig_mask(SIG_SETMASK, &neu, &res);
|
__sig_mask(SIG_SETMASK, &neu, &res);
|
||||||
} else {
|
} else {
|
||||||
_npassert(!sys_sigprocmask(SIG_SETMASK, &neu, &res));
|
npassert(!sys_sigprocmask(SIG_SETMASK, &neu, &res));
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ unsigned sleep(unsigned seconds) {
|
||||||
struct timespec tv = {seconds};
|
struct timespec tv = {seconds};
|
||||||
if (!(rc = clock_nanosleep(CLOCK_REALTIME, 0, &tv, &tv))) return 0;
|
if (!(rc = clock_nanosleep(CLOCK_REALTIME, 0, &tv, &tv))) return 0;
|
||||||
if (rc == ECANCELED) return -1u;
|
if (rc == ECANCELED) return -1u;
|
||||||
_npassert(rc == EINTR);
|
npassert(rc == EINTR);
|
||||||
unslept = tv.tv_sec;
|
unslept = tv.tv_sec;
|
||||||
if (tv.tv_nsec && unslept < UINT_MAX) {
|
if (tv.tv_nsec && unslept < UINT_MAX) {
|
||||||
++unslept;
|
++unslept;
|
||||||
|
|
|
@ -29,6 +29,6 @@
|
||||||
*/
|
*/
|
||||||
struct timespec timespec_mono(void) {
|
struct timespec timespec_mono(void) {
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
_npassert(!clock_gettime(CLOCK_MONOTONIC, &ts));
|
npassert(!clock_gettime(CLOCK_MONOTONIC, &ts));
|
||||||
return ts;
|
return ts;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,6 @@
|
||||||
*/
|
*/
|
||||||
struct timespec timespec_real(void) {
|
struct timespec timespec_real(void) {
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
_npassert(!clock_gettime(CLOCK_REALTIME, &ts));
|
npassert(!clock_gettime(CLOCK_REALTIME, &ts));
|
||||||
return ts;
|
return ts;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ struct timespec timespec_sleep(struct timespec delay) {
|
||||||
BLOCK_CANCELLATIONS;
|
BLOCK_CANCELLATIONS;
|
||||||
bzero(&remain, sizeof(remain));
|
bzero(&remain, sizeof(remain));
|
||||||
if ((rc = clock_nanosleep(CLOCK_REALTIME, 0, &delay, &remain))) {
|
if ((rc = clock_nanosleep(CLOCK_REALTIME, 0, &delay, &remain))) {
|
||||||
_npassert(rc == EINTR);
|
npassert(rc == EINTR);
|
||||||
}
|
}
|
||||||
ALLOW_CANCELLATIONS;
|
ALLOW_CANCELLATIONS;
|
||||||
return remain;
|
return remain;
|
||||||
|
|
|
@ -33,6 +33,6 @@
|
||||||
errno_t timespec_sleep_until(struct timespec abs_deadline) {
|
errno_t timespec_sleep_until(struct timespec abs_deadline) {
|
||||||
errno_t rc;
|
errno_t rc;
|
||||||
rc = clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &abs_deadline, 0);
|
rc = clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &abs_deadline, 0);
|
||||||
_npassert(!rc || rc == EINTR || rc == ECANCELED);
|
npassert(!rc || rc == EINTR || rc == ECANCELED);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,6 @@
|
||||||
*/
|
*/
|
||||||
struct timeval timeval_real(void) {
|
struct timeval timeval_real(void) {
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
_npassert(!gettimeofday(&tv, 0));
|
npassert(!gettimeofday(&tv, 0));
|
||||||
return tv;
|
return tv;
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,15 +76,15 @@ static textwindows void GetNtName(char *name, int kind) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline textwindows noasan int GetNtMajorVersion(void) {
|
static inline textwindows dontasan int GetNtMajorVersion(void) {
|
||||||
return NtGetPeb()->OSMajorVersion;
|
return NtGetPeb()->OSMajorVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline textwindows noasan int GetNtMinorVersion(void) {
|
static inline textwindows dontasan int GetNtMinorVersion(void) {
|
||||||
return NtGetPeb()->OSMinorVersion;
|
return NtGetPeb()->OSMinorVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline textwindows noasan int GetNtBuildNumber(void) {
|
static inline textwindows dontasan int GetNtBuildNumber(void) {
|
||||||
return NtGetPeb()->OSBuildNumber;
|
return NtGetPeb()->OSBuildNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -473,10 +473,10 @@ int unveil(const char *path, const char *permissions) {
|
||||||
if (permissions) return einval();
|
if (permissions) return einval();
|
||||||
if (IsOpenbsd()) return 0;
|
if (IsOpenbsd()) return 0;
|
||||||
if (landlock_abi_version != -1) {
|
if (landlock_abi_version != -1) {
|
||||||
_unassert(landlock_abi_version >= 1);
|
unassert(landlock_abi_version >= 1);
|
||||||
return landlock_abi_version;
|
return landlock_abi_version;
|
||||||
} else {
|
} else {
|
||||||
_unassert(landlock_abi_errno);
|
unassert(landlock_abi_errno);
|
||||||
errno = landlock_abi_errno;
|
errno = landlock_abi_errno;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ static textwindows ssize_t sys_write_nt_impl(int fd, void *data, size_t size,
|
||||||
if (!ok && GetLastError() == kNtErrorIoPending) ok = true;
|
if (!ok && GetLastError() == kNtErrorIoPending) ok = true;
|
||||||
if (ok) ok = GetOverlappedResult(handle, &overlap, &sent, true);
|
if (ok) ok = GetOverlappedResult(handle, &overlap, &sent, true);
|
||||||
// restore file pointer which windows clobbers, even on error
|
// restore file pointer which windows clobbers, even on error
|
||||||
_unassert(SetFilePointerEx(handle, position, 0, SEEK_SET));
|
unassert(SetFilePointerEx(handle, position, 0, SEEK_SET));
|
||||||
}
|
}
|
||||||
if (ok) {
|
if (ok) {
|
||||||
return sent;
|
return sent;
|
||||||
|
|
|
@ -55,6 +55,6 @@
|
||||||
* @see unbing() for inverse
|
* @see unbing() for inverse
|
||||||
*/
|
*/
|
||||||
int bing(int b, int intent) {
|
int bing(int b, int intent) {
|
||||||
_unassert(0 <= b && b < 256);
|
unassert(0 <= b && b < 256);
|
||||||
return kCp437[b & 0xff];
|
return kCp437[b & 0xff];
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
size_t uint64toarray_fixed16(uint64_t x, char b[hasatleast 17], uint8_t k) {
|
size_t uint64toarray_fixed16(uint64_t x, char b[hasatleast 17], uint8_t k) {
|
||||||
char *p;
|
char *p;
|
||||||
_unassert(k <= 64 && !(k & 3));
|
unassert(k <= 64 && !(k & 3));
|
||||||
for (p = b; k > 0;) *p++ = "0123456789abcdef"[(x >> (k -= 4)) & 15];
|
for (p = b; k > 0;) *p++ = "0123456789abcdef"[(x >> (k -= 4)) & 15];
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
return p - b;
|
return p - b;
|
||||||
|
|
|
@ -194,19 +194,22 @@ typedef struct {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef privileged
|
#ifndef privileged
|
||||||
#if !defined(__STRICT_ANSI__) && \
|
#define privileged \
|
||||||
(__has_attribute(__visibility__) || defined(__GNUC__))
|
_Section(".privileged") dontinline dontinstrument dontubsan dontasan
|
||||||
#define privileged _Section(".privileged")
|
|
||||||
#else
|
|
||||||
#define privileged _Section(".privileged")
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef dontinstrument
|
#ifndef dontinstrument
|
||||||
#if !defined(__STRICT_ANSI__) && \
|
#if !defined(__STRICT_ANSI__) && \
|
||||||
(__has_attribute(__no_instrument_function__) || \
|
(__has_attribute(__no_instrument_function__) || \
|
||||||
(__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 204)
|
(__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 204)
|
||||||
|
#if ((__GNUC__ + 0) >= 7 && !defined(__chibicc__)) || \
|
||||||
|
__has_attribute(__patchable_function_entry__)
|
||||||
|
#define dontinstrument \
|
||||||
|
__attribute__((__no_instrument_function__, \
|
||||||
|
__patchable_function_entry__(0, 0)))
|
||||||
|
#else
|
||||||
#define dontinstrument __attribute__((__no_instrument_function__))
|
#define dontinstrument __attribute__((__no_instrument_function__))
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
#define dontinstrument
|
#define dontinstrument
|
||||||
#endif
|
#endif
|
||||||
|
@ -569,17 +572,17 @@ typedef struct {
|
||||||
#if ((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 408 || \
|
#if ((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 408 || \
|
||||||
__has_attribute(__no_sanitize_address__)) && \
|
__has_attribute(__no_sanitize_address__)) && \
|
||||||
!defined(__STRICT_ANSI__)
|
!defined(__STRICT_ANSI__)
|
||||||
#define noasan __attribute__((__no_sanitize_address__))
|
#define dontasan __attribute__((__no_sanitize_address__))
|
||||||
#else
|
#else
|
||||||
#define noasan
|
#define dontasan
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 408 || \
|
#if ((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 408 || \
|
||||||
__has_attribute(__no_sanitize_undefined__)) && \
|
__has_attribute(__no_sanitize_undefined__)) && \
|
||||||
!defined(__STRICT_ANSI__)
|
!defined(__STRICT_ANSI__)
|
||||||
#define noubsan __attribute__((__no_sanitize_undefined__))
|
#define dontubsan __attribute__((__no_sanitize_undefined__))
|
||||||
#else
|
#else
|
||||||
#define noubsan
|
#define dontubsan
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __STRICT_ANSI__
|
#ifdef __STRICT_ANSI__
|
||||||
|
@ -645,11 +648,7 @@ void abort(void) wontreturn;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef _Section
|
#ifndef _Section
|
||||||
#if !defined(__STRICT_ANSI__) && !defined(__APPLE__)
|
|
||||||
#define _Section(s) __attribute__((__section__(s)))
|
#define _Section(s) __attribute__((__section__(s)))
|
||||||
#else
|
|
||||||
#define _Section(s)
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__x86_64__) && !defined(__llvm__)
|
#if defined(__x86_64__) && !defined(__llvm__)
|
||||||
|
@ -772,69 +771,69 @@ void abort(void) wontreturn;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef __STRICT_ANSI__
|
#ifndef __STRICT_ANSI__
|
||||||
#define VEIL(CONSTRAINT, EXPRESSION) \
|
#define __veil(CONSTRAINT, EXPRESSION) \
|
||||||
({ \
|
({ \
|
||||||
autotype(EXPRESSION) VeiledValue = (EXPRESSION); \
|
autotype(EXPRESSION) VeiledValue = (EXPRESSION); \
|
||||||
asm("" : "=" CONSTRAINT ""(VeiledValue) : "0"(VeiledValue)); \
|
asm("" : "=" CONSTRAINT ""(VeiledValue) : "0"(VeiledValue)); \
|
||||||
VeiledValue; \
|
VeiledValue; \
|
||||||
})
|
})
|
||||||
#else
|
#else
|
||||||
#define VEIL(CONSTRAINT, EXPRESSION) (EXPRESSION)
|
#define __veil(CONSTRAINT, EXPRESSION) (EXPRESSION)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef __STRICT_ANSI__
|
#ifndef __STRICT_ANSI__
|
||||||
#define CONCEAL(CONSTRAINT, EXPRESSION) \
|
#define __conceal(CONSTRAINT, EXPRESSION) \
|
||||||
({ \
|
({ \
|
||||||
autotype(EXPRESSION) VeiledValue = (EXPRESSION); \
|
autotype(EXPRESSION) VeiledValue = (EXPRESSION); \
|
||||||
asm volatile("" : "=" CONSTRAINT ""(VeiledValue) : "0"(VeiledValue)); \
|
asm volatile("" : "=" CONSTRAINT ""(VeiledValue) : "0"(VeiledValue)); \
|
||||||
VeiledValue; \
|
VeiledValue; \
|
||||||
})
|
})
|
||||||
#else
|
#else
|
||||||
#define CONCEAL(CONSTRAINT, EXPRESSION) (EXPRESSION)
|
#define __conceal(CONSTRAINT, EXPRESSION) (EXPRESSION)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef __STRICT_ANSI__
|
#ifndef __STRICT_ANSI__
|
||||||
#define EXPROPRIATE(EXPRESSION) \
|
#define __expropriate(EXPRESSION) \
|
||||||
({ \
|
({ \
|
||||||
asm volatile("" ::"g"(EXPRESSION) : "memory"); \
|
asm volatile("" ::"g"(EXPRESSION) : "memory"); \
|
||||||
0; \
|
0; \
|
||||||
})
|
})
|
||||||
#else
|
#else
|
||||||
#define EXPROPRIATE(EXPRESSION) (EXPRESSION)
|
#define __expropriate(EXPRESSION) (EXPRESSION)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(__STRICT_ANSI__) && !defined(__APPLE__) && defined(__x86_64__)
|
#if !defined(__STRICT_ANSI__) && !defined(__APPLE__) && defined(__x86_64__)
|
||||||
#define YOINK(SYMBOL) \
|
#define __yoink(SYMBOL) \
|
||||||
asm(".section .yoink\n\tnopl\t%0\n\t.previous" : : "m"(SYMBOL))
|
asm(".section .yoink\n\tnopl\t%0\n\t.previous" : : "m"(SYMBOL))
|
||||||
#elif defined(__aarch64__)
|
#elif defined(__aarch64__)
|
||||||
#define YOINK(SYMBOL) \
|
#define __yoink(SYMBOL) \
|
||||||
asm(".section .yoink\n\tb\t%0\n\t.previous" : : "m"(SYMBOL))
|
asm(".section .yoink\n\tb\t%0\n\t.previous" : : "m"(SYMBOL))
|
||||||
#else
|
#else
|
||||||
#define YOINK(SYMBOL) (void)0
|
#define __yoink(SYMBOL) (void)0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(__STRICT_ANSI__) && !defined(__APPLE__) && defined(__x86_64__)
|
#if !defined(__STRICT_ANSI__) && !defined(__APPLE__) && defined(__x86_64__)
|
||||||
#define STATIC_YOINK(SYMBOLSTR) \
|
#define __static_yoink(SYMBOLSTR) \
|
||||||
asm(".section .yoink\n\tnopl\t\"" SYMBOLSTR "\"\n\t.previous")
|
asm(".section .yoink\n\tnopl\t\"" SYMBOLSTR "\"\n\t.previous")
|
||||||
#elif defined(__aarch64__)
|
#elif defined(__aarch64__)
|
||||||
#define STATIC_YOINK(SYMBOLSTR) \
|
#define __static_yoink(SYMBOLSTR) \
|
||||||
asm(".section .yoink\n\tb\t\"" SYMBOLSTR "\"\n\t.previous")
|
asm(".section .yoink\n\tb\t\"" SYMBOLSTR "\"\n\t.previous")
|
||||||
#else
|
#else
|
||||||
#define STATIC_YOINK(SYMBOLSTR)
|
#define __static_yoink(SYMBOLSTR)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(IM_FEELING_NAUGHTY)
|
#if !defined(IM_FEELING_NAUGHTY)
|
||||||
#define STATIC_YOINK_SOURCE(PATH) STATIC_YOINK(PATH)
|
#define __static_yoink_source(PATH) __static_yoink(PATH)
|
||||||
#else
|
#else
|
||||||
#define STATIC_YOINK_SOURCE(PATH)
|
#define __static_yoink_source(PATH)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define __strong_reference(sym, aliassym) \
|
#define __strong_reference(sym, aliassym) \
|
||||||
extern typeof(sym) aliassym __attribute__((__alias__(#sym)))
|
extern __typeof(sym) aliassym __attribute__((__alias__(#sym)))
|
||||||
#define __weak_reference(sym, alias) \
|
#define __weak_reference(sym, alias) \
|
||||||
asm(".weak\t" #alias "\n\t" \
|
__asm__(".weak\t" #alias "\n\t" \
|
||||||
".equ\t" #alias ", " #sym "\n\t" \
|
".equ\t" #alias ", " #sym "\n\t" \
|
||||||
".type\t" #alias ",@notype")
|
".type\t" #alias ",@notype")
|
||||||
|
|
||||||
#define __funline \
|
#define __funline \
|
||||||
extern __inline \
|
extern __inline \
|
||||||
|
|
|
@ -82,8 +82,7 @@
|
||||||
#else
|
#else
|
||||||
#define APE_STACKSIZE 4194304 /* default 4mb stack */
|
#define APE_STACKSIZE 4194304 /* default 4mb stack */
|
||||||
#endif
|
#endif
|
||||||
#define APE_PAGESIZE 0x10000 /* i386+ */
|
#define APE_PAGESIZE 0x10000 /* i386+ */
|
||||||
#define APE_GUARDSIZE 0x4000 /* b/c apple m1 */
|
|
||||||
|
|
||||||
#define BUFSIZ 0x1000 /* best stdio default */
|
#define BUFSIZ 0x1000 /* best stdio default */
|
||||||
#define CHAR_BIT 8 /* b/c von neumann */
|
#define CHAR_BIT 8 /* b/c von neumann */
|
||||||
|
|
|
@ -20,19 +20,15 @@
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns auxiliary value, or zero if kernel didn't provide it.
|
* Returns auxiliary value better.
|
||||||
*
|
|
||||||
* This function is typically regarded as a libc implementation detail;
|
|
||||||
* thus, the source code is the documentation.
|
|
||||||
*
|
*
|
||||||
* @param at is `AT_...` search key
|
* @param at is `AT_...` search key
|
||||||
* @return true if value was found
|
* @return true if value was found
|
||||||
* @see libc/sysv/consts.sh
|
* @see libc/sysv/consts.sh
|
||||||
* @see System Five Application Binary Interface § 3.4.3
|
* @see System Five Application Binary Interface § 3.4.3
|
||||||
* @error ENOENT when value not found
|
|
||||||
* @asyncsignalsafe
|
* @asyncsignalsafe
|
||||||
*/
|
*/
|
||||||
struct AuxiliaryValue _getauxval(unsigned long at) {
|
dontasan struct AuxiliaryValue _getauxval(unsigned long at) {
|
||||||
unsigned long *ap;
|
unsigned long *ap;
|
||||||
for (ap = __auxv; ap[0]; ap += 2) {
|
for (ap = __auxv; ap[0]; ap += 2) {
|
||||||
if (at == ap[0]) {
|
if (at == ap[0]) {
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
#include "libc/intrin/strace.internal.h"
|
#include "libc/intrin/strace.internal.h"
|
||||||
#include "libc/runtime/memtrack.internal.h"
|
#include "libc/runtime/memtrack.internal.h"
|
||||||
|
|
||||||
noasan bool AreMemoryIntervalsOk(const struct MemoryIntervals *mm) {
|
dontasan bool AreMemoryIntervalsOk(const struct MemoryIntervals *mm) {
|
||||||
/* asan runtime depends on this function */
|
/* asan runtime depends on this function */
|
||||||
int i;
|
int i;
|
||||||
size_t wantsize;
|
size_t wantsize;
|
||||||
|
|
|
@ -52,7 +52,7 @@
|
||||||
#include "third_party/dlmalloc/dlmalloc.h"
|
#include "third_party/dlmalloc/dlmalloc.h"
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
|
|
||||||
STATIC_YOINK("_init_asan");
|
__static_yoink("_init_asan");
|
||||||
|
|
||||||
#if IsModeDbg()
|
#if IsModeDbg()
|
||||||
// MODE=dbg
|
// MODE=dbg
|
||||||
|
@ -342,7 +342,7 @@ static char *__asan_hexcpy(char *p, uint64_t x, uint8_t k) {
|
||||||
|
|
||||||
static void __asan_exit(void) {
|
static void __asan_exit(void) {
|
||||||
kprintf("your asan runtime needs\n"
|
kprintf("your asan runtime needs\n"
|
||||||
"\tSTATIC_YOINK(\"__die\");\n"
|
"\t__static_yoink(\"__die\");\n"
|
||||||
"in order to show you backtraces\n");
|
"in order to show you backtraces\n");
|
||||||
_Exitr(99);
|
_Exitr(99);
|
||||||
}
|
}
|
||||||
|
@ -457,7 +457,7 @@ static struct AsanFault __asan_checka(const signed char *s, long ndiv8) {
|
||||||
* This is normally abstracted by the compiler. In some cases, it may be
|
* This is normally abstracted by the compiler. In some cases, it may be
|
||||||
* desirable to perform an ASAN memory safety check explicitly, e.g. for
|
* desirable to perform an ASAN memory safety check explicitly, e.g. for
|
||||||
* system call wrappers that need to vet memory passed to the kernel, or
|
* system call wrappers that need to vet memory passed to the kernel, or
|
||||||
* string library routines that use the `noasan` keyword due to compiler
|
* string library routines that use the `dontasan` keyword due to compiler
|
||||||
* generated ASAN being too costly. This function is fast especially for
|
* generated ASAN being too costly. This function is fast especially for
|
||||||
* large memory ranges since this takes a few picoseconds for each byte.
|
* large memory ranges since this takes a few picoseconds for each byte.
|
||||||
*
|
*
|
||||||
|
@ -766,11 +766,11 @@ static void __asan_report_memory_origin_image(intptr_t a, int z) {
|
||||||
kprintf("\tunknown please supply .com.dbg symbols or set COMDBG\n");
|
kprintf("\tunknown please supply .com.dbg symbols or set COMDBG\n");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
kprintf("\tunknown please STATIC_YOINK(\"GetSymbolTable\");\n");
|
kprintf("\tunknown please __static_yoink(\"GetSymbolTable\");\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static noasan void __asan_onmemory(void *x, void *y, size_t n, void *a) {
|
static dontasan void __asan_onmemory(void *x, void *y, size_t n, void *a) {
|
||||||
const unsigned char *p = x;
|
const unsigned char *p = x;
|
||||||
struct ReportOriginHeap *t = a;
|
struct ReportOriginHeap *t = a;
|
||||||
if ((p <= t->a && t->a < p + n) ||
|
if ((p <= t->a && t->a < p + n) ||
|
||||||
|
@ -790,7 +790,7 @@ static void __asan_report_memory_origin_heap(const unsigned char *a, int z) {
|
||||||
t.z = z;
|
t.z = z;
|
||||||
_weaken(malloc_inspect_all)(__asan_onmemory, &t);
|
_weaken(malloc_inspect_all)(__asan_onmemory, &t);
|
||||||
} else {
|
} else {
|
||||||
kprintf("\tunknown please STATIC_YOINK(\"malloc_inspect_all\");\n");
|
kprintf("\tunknown please __static_yoink(\"malloc_inspect_all\");\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1117,7 +1117,7 @@ int __asan_print_trace(void *p) {
|
||||||
kprintf("\n%*lx %s", 12, e->bt.p[i],
|
kprintf("\n%*lx %s", 12, e->bt.p[i],
|
||||||
_weaken(GetSymbolByAddr)
|
_weaken(GetSymbolByAddr)
|
||||||
? _weaken(GetSymbolByAddr)(e->bt.p[i])
|
? _weaken(GetSymbolByAddr)(e->bt.p[i])
|
||||||
: "please STATIC_YOINK(\"GetSymbolByAddr\")");
|
: "please __static_yoink(\"GetSymbolByAddr\")");
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1482,7 +1482,8 @@ static textstartup void __asan_shadow_mapping(struct MemoryIntervals *m,
|
||||||
static textstartup void __asan_shadow_existing_mappings(void) {
|
static textstartup void __asan_shadow_existing_mappings(void) {
|
||||||
__asan_shadow_mapping(&_mmi, 0);
|
__asan_shadow_mapping(&_mmi, 0);
|
||||||
__asan_map_shadow(GetStackAddr(), GetStackSize());
|
__asan_map_shadow(GetStackAddr(), GetStackSize());
|
||||||
__asan_poison((void *)GetStackAddr(), APE_GUARDSIZE, kAsanStackOverflow);
|
__asan_poison((void *)GetStackAddr(), getauxval(AT_PAGESZ),
|
||||||
|
kAsanStackOverflow);
|
||||||
}
|
}
|
||||||
|
|
||||||
forceinline ssize_t __write_str(const char *s) {
|
forceinline ssize_t __write_str(const char *s) {
|
||||||
|
@ -1509,7 +1510,7 @@ void __asan_init(int argc, char **argv, char **envp, intptr_t *auxv) {
|
||||||
__asan_shadow_existing_mappings();
|
__asan_shadow_existing_mappings();
|
||||||
__asan_map_shadow((uintptr_t)__executable_start, _end - __executable_start);
|
__asan_map_shadow((uintptr_t)__executable_start, _end - __executable_start);
|
||||||
__asan_map_shadow(0, 4096);
|
__asan_map_shadow(0, 4096);
|
||||||
__asan_poison(0, APE_GUARDSIZE, kAsanNullPage);
|
__asan_poison(0, getauxval(AT_PAGESZ), kAsanNullPage);
|
||||||
if (!IsWindows()) {
|
if (!IsWindows()) {
|
||||||
sys_mprotect((void *)0x7fff8000, 0x10000, PROT_READ);
|
sys_mprotect((void *)0x7fff8000, 0x10000, PROT_READ);
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ void _bt(const char *fmt, ...) {
|
||||||
errno = e;
|
errno = e;
|
||||||
} else {
|
} else {
|
||||||
kprintf("_bt() can't show backtrace because you need:\n"
|
kprintf("_bt() can't show backtrace because you need:\n"
|
||||||
"\tSTATIC_YOINK(\"ShowBacktrace\");\n"
|
"\t__static_yoink(\"ShowBacktrace\");\n"
|
||||||
"to be linked.\n");
|
"to be linked.\n");
|
||||||
if (_weaken(PrintBacktraceUsingSymbols) && _weaken(GetSymbolTable)) {
|
if (_weaken(PrintBacktraceUsingSymbols) && _weaken(GetSymbolTable)) {
|
||||||
e = errno;
|
e = errno;
|
||||||
|
@ -58,8 +58,8 @@ void _bt(const char *fmt, ...) {
|
||||||
errno = e;
|
errno = e;
|
||||||
} else {
|
} else {
|
||||||
kprintf("_bt() can't show backtrace because you need:\n"
|
kprintf("_bt() can't show backtrace because you need:\n"
|
||||||
"\tSTATIC_YOINK(\"PrintBacktraceUsingSymbols\");\n"
|
"\t__static_yoink(\"PrintBacktraceUsingSymbols\");\n"
|
||||||
"\tSTATIC_YOINK(\"GetSymbolTable\");\n"
|
"\t__static_yoink(\"GetSymbolTable\");\n"
|
||||||
"to be linked.\n");
|
"to be linked.\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
STATIC_YOINK("__cxa_finalize");
|
__static_yoink("__cxa_finalize");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds global destructor.
|
* Adds global destructor.
|
||||||
|
@ -42,7 +42,7 @@ STATIC_YOINK("__cxa_finalize");
|
||||||
* @return 0 on success or nonzero w/ errno
|
* @return 0 on success or nonzero w/ errno
|
||||||
* @note folks have forked libc in past just to unbloat atexit()
|
* @note folks have forked libc in past just to unbloat atexit()
|
||||||
*/
|
*/
|
||||||
noasan int __cxa_atexit(void *fp, void *arg, void *pred) {
|
dontasan int __cxa_atexit(void *fp, void *arg, void *pred) {
|
||||||
/* asan runtime depends on this function */
|
/* asan runtime depends on this function */
|
||||||
unsigned i;
|
unsigned i;
|
||||||
struct CxaAtexitBlock *b, *b2;
|
struct CxaAtexitBlock *b, *b2;
|
||||||
|
@ -61,7 +61,7 @@ noasan int __cxa_atexit(void *fp, void *arg, void *pred) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i = _bsr(~b->mask);
|
i = _bsr(~b->mask);
|
||||||
_unassert(i < ARRAYLEN(b->p));
|
unassert(i < ARRAYLEN(b->p));
|
||||||
b->mask |= 1u << i;
|
b->mask |= 1u << i;
|
||||||
b->p[i].fp = fp;
|
b->p[i].fp = fp;
|
||||||
b->p[i].arg = arg;
|
b->p[i].arg = arg;
|
||||||
|
|
|
@ -60,7 +60,7 @@ StartOverLocked:
|
||||||
if (!pred) {
|
if (!pred) {
|
||||||
b2 = b->next;
|
b2 = b->next;
|
||||||
if (b2) {
|
if (b2) {
|
||||||
_unassert(b != &__cxa_blocks.root);
|
unassert(b != &__cxa_blocks.root);
|
||||||
if (_weaken(free)) {
|
if (_weaken(free)) {
|
||||||
_weaken(free)(b);
|
_weaken(free)(b);
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,15 +32,15 @@
|
||||||
|
|
||||||
static uint64_t sys_mmap_metal_break;
|
static uint64_t sys_mmap_metal_break;
|
||||||
|
|
||||||
noasan static struct DirectMap bad_mmap(void) {
|
dontasan static struct DirectMap bad_mmap(void) {
|
||||||
struct DirectMap res;
|
struct DirectMap res;
|
||||||
res.addr = (void *)-1;
|
res.addr = (void *)-1;
|
||||||
res.maphandle = -1;
|
res.maphandle = -1;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
noasan struct DirectMap sys_mmap_metal(void *vaddr, size_t size, int prot,
|
dontasan struct DirectMap sys_mmap_metal(void *vaddr, size_t size, int prot,
|
||||||
int flags, int fd, int64_t off) {
|
int flags, int fd, int64_t off) {
|
||||||
/* asan runtime depends on this function */
|
/* asan runtime depends on this function */
|
||||||
size_t i;
|
size_t i;
|
||||||
struct mman *mm;
|
struct mman *mm;
|
||||||
|
|
|
@ -72,7 +72,7 @@ textwindows struct DirectMap sys_mmap_nt(void *addr, size_t size, int prot,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_unassert(flags & MAP_ANONYMOUS);
|
unassert(flags & MAP_ANONYMOUS);
|
||||||
fl = (struct ProtectNt){kNtPageExecuteReadwrite,
|
fl = (struct ProtectNt){kNtPageExecuteReadwrite,
|
||||||
kNtFileMapWrite | kNtFileMapExecute};
|
kNtFileMapWrite | kNtFileMapExecute};
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,11 +43,11 @@ static void *_mapframe(void *p, int f) {
|
||||||
if (!rc) {
|
if (!rc) {
|
||||||
return p;
|
return p;
|
||||||
} else {
|
} else {
|
||||||
_unassert(errno == ENOMEM);
|
unassert(errno == ENOMEM);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_unassert(errno == ENOMEM);
|
unassert(errno == ENOMEM);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,14 +71,14 @@ static void *_mapframe(void *p, int f) {
|
||||||
* @return new value for `e` or null w/ errno
|
* @return new value for `e` or null w/ errno
|
||||||
* @raise ENOMEM if we require more vespene gas
|
* @raise ENOMEM if we require more vespene gas
|
||||||
*/
|
*/
|
||||||
noasan void *_extend(void *p, size_t n, void *e, int f, intptr_t h) {
|
dontasan void *_extend(void *p, size_t n, void *e, int f, intptr_t h) {
|
||||||
char *q;
|
char *q;
|
||||||
_unassert(!((uintptr_t)SHADOW(p) & (G - 1)));
|
unassert(!((uintptr_t)SHADOW(p) & (G - 1)));
|
||||||
_unassert((uintptr_t)p + (G << kAsanScale) <= h);
|
unassert((uintptr_t)p + (G << kAsanScale) <= h);
|
||||||
// TODO(jart): Make this spin less in non-ASAN mode.
|
// TODO(jart): Make this spin less in non-ASAN mode.
|
||||||
for (q = e; q < ((char *)p + n); q += 8) {
|
for (q = e; q < ((char *)p + n); q += 8) {
|
||||||
if (!((uintptr_t)q & (G - 1))) {
|
if (!((uintptr_t)q & (G - 1))) {
|
||||||
_unassert(q + G <= (char *)h);
|
unassert(q + G <= (char *)h);
|
||||||
if (!_mapframe(q, f)) return 0;
|
if (!_mapframe(q, f)) return 0;
|
||||||
if (IsAsan()) {
|
if (IsAsan()) {
|
||||||
if (!((uintptr_t)SHADOW(q) & (G - 1))) {
|
if (!((uintptr_t)SHADOW(q) & (G - 1))) {
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
#include "libc/assert.h"
|
#include "libc/assert.h"
|
||||||
#include "libc/runtime/memtrack.internal.h"
|
#include "libc/runtime/memtrack.internal.h"
|
||||||
|
|
||||||
noasan unsigned FindMemoryInterval(const struct MemoryIntervals *mm, int x) {
|
dontasan unsigned FindMemoryInterval(const struct MemoryIntervals *mm, int x) {
|
||||||
unsigned l, m, r;
|
unsigned l, m, r;
|
||||||
l = 0;
|
l = 0;
|
||||||
r = mm->i;
|
r = mm->i;
|
||||||
|
@ -31,6 +31,6 @@ noasan unsigned FindMemoryInterval(const struct MemoryIntervals *mm, int x) {
|
||||||
r = m;
|
r = m;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_unassert(l == mm->i || x <= mm->p[l].y);
|
unassert(l == mm->i || x <= mm->p[l].y);
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
#include "libc/thread/thread.h"
|
#include "libc/thread/thread.h"
|
||||||
|
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
STATIC_YOINK("_init_g_fds");
|
__static_yoink("_init_g_fds");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct Fds g_fds;
|
struct Fds g_fds;
|
||||||
|
@ -49,7 +49,7 @@ static textwindows dontinline void SetupWinStd(struct Fds *fds, int i, int x) {
|
||||||
textstartup void __init_fds(void) {
|
textstartup void __init_fds(void) {
|
||||||
struct Fds *fds;
|
struct Fds *fds;
|
||||||
__fds_lock_obj._type = PTHREAD_MUTEX_RECURSIVE;
|
__fds_lock_obj._type = PTHREAD_MUTEX_RECURSIVE;
|
||||||
fds = VEIL("r", &g_fds);
|
fds = __veil("r", &g_fds);
|
||||||
fds->n = 4;
|
fds->n = 4;
|
||||||
atomic_store_explicit(&fds->f, 3, memory_order_relaxed);
|
atomic_store_explicit(&fds->f, 3, memory_order_relaxed);
|
||||||
if (_weaken(_extend)) {
|
if (_weaken(_extend)) {
|
||||||
|
@ -73,9 +73,9 @@ textstartup void __init_fds(void) {
|
||||||
fds->p[1].kind = pushpop(kFdSerial);
|
fds->p[1].kind = pushpop(kFdSerial);
|
||||||
fds->p[2].kind = pushpop(kFdSerial);
|
fds->p[2].kind = pushpop(kFdSerial);
|
||||||
}
|
}
|
||||||
fds->p[0].handle = VEIL("r", 0x3F8ull);
|
fds->p[0].handle = __veil("r", 0x3F8ull);
|
||||||
fds->p[1].handle = VEIL("r", 0x3F8ull);
|
fds->p[1].handle = __veil("r", 0x3F8ull);
|
||||||
fds->p[2].handle = VEIL("r", 0x3F8ull);
|
fds->p[2].handle = __veil("r", 0x3F8ull);
|
||||||
} else if (IsWindows()) {
|
} else if (IsWindows()) {
|
||||||
SetupWinStd(fds, 0, kNtStdInputHandle);
|
SetupWinStd(fds, 0, kNtStdInputHandle);
|
||||||
SetupWinStd(fds, 1, kNtStdOutputHandle);
|
SetupWinStd(fds, 1, kNtStdOutputHandle);
|
||||||
|
|
|
@ -16,28 +16,33 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/errno.h"
|
||||||
|
#include "libc/intrin/_getauxval.internal.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/consts/auxv.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns auxiliary value, or zero if kernel didn't provide it.
|
* Returns auxiliary value.
|
||||||
*
|
*
|
||||||
* This function is typically regarded as a libc implementation detail;
|
* @return auxiliary value or 0 if `key` not found
|
||||||
* thus, the source code is the documentation.
|
|
||||||
*
|
|
||||||
* @return auxiliary value or 0 if `at` not found
|
|
||||||
* @see libc/sysv/consts.sh
|
* @see libc/sysv/consts.sh
|
||||||
* @see System Five Application Binary Interface § 3.4.3
|
* @see System Five Application Binary Interface § 3.4.3
|
||||||
* @error ENOENT when value not found
|
* @error ENOENT when value not found
|
||||||
* @asyncsignalsafe
|
* @asyncsignalsafe
|
||||||
*/
|
*/
|
||||||
unsigned long getauxval(unsigned long at) {
|
unsigned long getauxval(unsigned long key) {
|
||||||
unsigned long res, *ap;
|
struct AuxiliaryValue x;
|
||||||
for (ap = __auxv; ap[0]; ap += 2) {
|
x = _getauxval(key);
|
||||||
if (at == ap[0]) {
|
if (key == AT_PAGESZ) {
|
||||||
return ap[1];
|
if (!x.isfound) {
|
||||||
|
x.value = 16384;
|
||||||
}
|
}
|
||||||
|
x.isfound = true;
|
||||||
|
}
|
||||||
|
if (x.isfound) {
|
||||||
|
return x.value;
|
||||||
|
} else {
|
||||||
|
errno = ENOENT;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
enoent();
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
#define kBufSize 1024
|
#define kBufSize 1024
|
||||||
#define kPid "TracerPid:\t"
|
#define kPid "TracerPid:\t"
|
||||||
|
|
||||||
static textwindows noasan bool IsBeingDebugged(void) {
|
static textwindows dontasan bool IsBeingDebugged(void) {
|
||||||
return !!NtGetPeb()->BeingDebugged;
|
return !!NtGetPeb()->BeingDebugged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,9 +38,9 @@ bool IsWsl1(void) {
|
||||||
if (res) return res & 1;
|
if (res) return res & 1;
|
||||||
if (!IsLinux()) return res = 2, false;
|
if (!IsLinux()) return res = 2, false;
|
||||||
int e = errno;
|
int e = errno;
|
||||||
_unassert(__sys_mmap((void *)1, 4096, PROT_READ | PROT_WRITE,
|
unassert(__sys_mmap((void *)1, 4096, PROT_READ | PROT_WRITE,
|
||||||
MAP_FIXED | MAP_PRIVATE | ANONYMOUS | GROWSDOWN, -1, 0,
|
MAP_FIXED | MAP_PRIVATE | ANONYMOUS | GROWSDOWN, -1, 0,
|
||||||
0) == MAP_FAILED);
|
0) == MAP_FAILED);
|
||||||
bool tmp = errno == ENOTSUP;
|
bool tmp = errno == ENOTSUP;
|
||||||
errno = e;
|
errno = e;
|
||||||
res = 2 | tmp;
|
res = 2 | tmp;
|
||||||
|
|
|
@ -82,7 +82,7 @@ void *kmalloc(size_t size) {
|
||||||
}
|
}
|
||||||
__kmalloc_unlock();
|
__kmalloc_unlock();
|
||||||
if (p) {
|
if (p) {
|
||||||
_unassert(!((intptr_t)(p + i) & (KMALLOC_ALIGN - 1)));
|
unassert(!((intptr_t)(p + i) & (KMALLOC_ALIGN - 1)));
|
||||||
if (IsAsan()) __asan_poison(p + i + size, n - size, kAsanHeapOverrun);
|
if (IsAsan()) __asan_poison(p + i + size, n - size, kAsanHeapOverrun);
|
||||||
return p + i;
|
return p + i;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -57,6 +57,7 @@
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/str/tab.internal.h"
|
#include "libc/str/tab.internal.h"
|
||||||
#include "libc/str/utf16.h"
|
#include "libc/str/utf16.h"
|
||||||
|
#include "libc/sysv/consts/auxv.h"
|
||||||
#include "libc/sysv/consts/nr.h"
|
#include "libc/sysv/consts/nr.h"
|
||||||
#include "libc/sysv/consts/prot.h"
|
#include "libc/sysv/consts/prot.h"
|
||||||
#include "libc/thread/tls.h"
|
#include "libc/thread/tls.h"
|
||||||
|
@ -187,7 +188,7 @@ privileged bool kisdangerous(const void *p) {
|
||||||
if (IsStackFrame(frame)) return false;
|
if (IsStackFrame(frame)) return false;
|
||||||
if (kismapped(frame)) return false;
|
if (kismapped(frame)) return false;
|
||||||
}
|
}
|
||||||
if (GetStackAddr() + APE_GUARDSIZE <= (uintptr_t)p &&
|
if (GetStackAddr() + 16384 <= (uintptr_t)p &&
|
||||||
(uintptr_t)p < GetStackAddr() + GetStackSize()) {
|
(uintptr_t)p < GetStackAddr() + GetStackSize()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
#define IGNORE_LEAKS(FUNC) \
|
#define IGNORE_LEAKS(FUNC) \
|
||||||
STATIC_YOINK("_leaky_start"); \
|
__static_yoink("_leaky_start"); \
|
||||||
void *_leaky_##FUNC[] _Section(".piro.relo.sort.leaky.2." #FUNC \
|
void *_leaky_##FUNC[] _Section(".piro.relo.sort.leaky.2." #FUNC \
|
||||||
",\"aw\",@init_array #") = {FUNC}
|
",\"aw\",@init_array #") = {FUNC}
|
||||||
|
|
||||||
|
|
|
@ -36,9 +36,9 @@ static inline const unsigned char *memchr_pure(const unsigned char *s,
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
noasan static inline const unsigned char *memchr_sse(const unsigned char *s,
|
dontasan static inline const unsigned char *memchr_sse(const unsigned char *s,
|
||||||
unsigned char c,
|
unsigned char c,
|
||||||
size_t n) {
|
size_t n) {
|
||||||
size_t i;
|
size_t i;
|
||||||
unsigned k;
|
unsigned k;
|
||||||
unsigned m;
|
unsigned m;
|
||||||
|
|
|
@ -36,9 +36,9 @@ static inline const unsigned char *memrchr_pure(const unsigned char *s,
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
noasan static inline const unsigned char *memrchr_sse(const unsigned char *s,
|
dontasan static inline const unsigned char *memrchr_sse(const unsigned char *s,
|
||||||
unsigned char c,
|
unsigned char c,
|
||||||
size_t n) {
|
size_t n) {
|
||||||
size_t i;
|
size_t i;
|
||||||
unsigned k, m;
|
unsigned k, m;
|
||||||
xmm_t v, t = {c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c};
|
xmm_t v, t = {c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c};
|
||||||
|
|
|
@ -50,7 +50,7 @@
|
||||||
static void *MoveMemoryIntervals(struct MemoryInterval *d,
|
static void *MoveMemoryIntervals(struct MemoryInterval *d,
|
||||||
const struct MemoryInterval *s, int n) {
|
const struct MemoryInterval *s, int n) {
|
||||||
int i;
|
int i;
|
||||||
_unassert(n >= 0);
|
unassert(n >= 0);
|
||||||
if (d > s) {
|
if (d > s) {
|
||||||
for (i = n; i--;) {
|
for (i = n; i--;) {
|
||||||
d[i] = s[i];
|
d[i] = s[i];
|
||||||
|
@ -64,8 +64,8 @@ static void *MoveMemoryIntervals(struct MemoryInterval *d,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void RemoveMemoryIntervals(struct MemoryIntervals *mm, int i, int n) {
|
static void RemoveMemoryIntervals(struct MemoryIntervals *mm, int i, int n) {
|
||||||
_unassert(i >= 0);
|
unassert(i >= 0);
|
||||||
_unassert(i + n <= mm->i);
|
unassert(i + n <= mm->i);
|
||||||
MoveMemoryIntervals(mm->p + i, mm->p + i + n, mm->i - (i + n));
|
MoveMemoryIntervals(mm->p + i, mm->p + i + n, mm->i - (i + n));
|
||||||
mm->i -= n;
|
mm->i -= n;
|
||||||
}
|
}
|
||||||
|
@ -109,9 +109,9 @@ static bool ExtendMemoryIntervals(struct MemoryIntervals *mm) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int CreateMemoryInterval(struct MemoryIntervals *mm, int i) {
|
int CreateMemoryInterval(struct MemoryIntervals *mm, int i) {
|
||||||
_unassert(i >= 0);
|
unassert(i >= 0);
|
||||||
_unassert(i <= mm->i);
|
unassert(i <= mm->i);
|
||||||
_unassert(mm->n >= 0);
|
unassert(mm->n >= 0);
|
||||||
if (UNLIKELY(mm->i == mm->n) && !ExtendMemoryIntervals(mm)) return enomem();
|
if (UNLIKELY(mm->i == mm->n) && !ExtendMemoryIntervals(mm)) return enomem();
|
||||||
MoveMemoryIntervals(mm->p + i + 1, mm->p + i, mm->i++ - i);
|
MoveMemoryIntervals(mm->p + i + 1, mm->p + i, mm->i++ - i);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -130,7 +130,7 @@ int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y,
|
||||||
void wf(struct MemoryIntervals *, int, int)) {
|
void wf(struct MemoryIntervals *, int, int)) {
|
||||||
unsigned l, r;
|
unsigned l, r;
|
||||||
ASSERT_MEMTRACK();
|
ASSERT_MEMTRACK();
|
||||||
_unassert(y >= x);
|
unassert(y >= x);
|
||||||
if (!mm->i) return 0;
|
if (!mm->i) return 0;
|
||||||
// binary search for the lefthand side
|
// binary search for the lefthand side
|
||||||
l = FindMemoryInterval(mm, x);
|
l = FindMemoryInterval(mm, x);
|
||||||
|
@ -140,8 +140,8 @@ int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y,
|
||||||
// binary search for the righthand side
|
// binary search for the righthand side
|
||||||
r = FindMemoryInterval(mm, y);
|
r = FindMemoryInterval(mm, y);
|
||||||
if (r == mm->i || (r > l && y < mm->p[r].x)) --r;
|
if (r == mm->i || (r > l && y < mm->p[r].x)) --r;
|
||||||
_unassert(r >= l);
|
unassert(r >= l);
|
||||||
_unassert(x <= mm->p[r].y);
|
unassert(x <= mm->p[r].y);
|
||||||
|
|
||||||
// remove the middle of an existing map
|
// remove the middle of an existing map
|
||||||
//
|
//
|
||||||
|
@ -162,11 +162,11 @@ int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y,
|
||||||
// ----|mmmm|----------------- after
|
// ----|mmmm|----------------- after
|
||||||
//
|
//
|
||||||
if (x > mm->p[l].x && x <= mm->p[l].y) {
|
if (x > mm->p[l].x && x <= mm->p[l].y) {
|
||||||
_unassert(y >= mm->p[l].y);
|
unassert(y >= mm->p[l].y);
|
||||||
if (IsWindows()) return einval();
|
if (IsWindows()) return einval();
|
||||||
mm->p[l].size -= (size_t)(mm->p[l].y - (x - 1)) * FRAMESIZE;
|
mm->p[l].size -= (size_t)(mm->p[l].y - (x - 1)) * FRAMESIZE;
|
||||||
mm->p[l].y = x - 1;
|
mm->p[l].y = x - 1;
|
||||||
_unassert(mm->p[l].x <= mm->p[l].y);
|
unassert(mm->p[l].x <= mm->p[l].y);
|
||||||
++l;
|
++l;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,11 +177,11 @@ int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y,
|
||||||
// ---------------|mm|-------- after
|
// ---------------|mm|-------- after
|
||||||
//
|
//
|
||||||
if (y >= mm->p[r].x && y < mm->p[r].y) {
|
if (y >= mm->p[r].x && y < mm->p[r].y) {
|
||||||
_unassert(x <= mm->p[r].x);
|
unassert(x <= mm->p[r].x);
|
||||||
if (IsWindows()) return einval();
|
if (IsWindows()) return einval();
|
||||||
mm->p[r].size -= (size_t)((y + 1) - mm->p[r].x) * FRAMESIZE;
|
mm->p[r].size -= (size_t)((y + 1) - mm->p[r].x) * FRAMESIZE;
|
||||||
mm->p[r].x = y + 1;
|
mm->p[r].x = y + 1;
|
||||||
_unassert(mm->p[r].x <= mm->p[r].y);
|
unassert(mm->p[r].x <= mm->p[r].y);
|
||||||
--r;
|
--r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,7 +199,7 @@ int TrackMemoryInterval(struct MemoryIntervals *mm, int x, int y, long h,
|
||||||
long offset, long size) {
|
long offset, long size) {
|
||||||
unsigned i;
|
unsigned i;
|
||||||
ASSERT_MEMTRACK();
|
ASSERT_MEMTRACK();
|
||||||
_unassert(y >= x);
|
unassert(y >= x);
|
||||||
i = FindMemoryInterval(mm, x);
|
i = FindMemoryInterval(mm, x);
|
||||||
|
|
||||||
// try to extend the righthand side of the lefthand entry
|
// try to extend the righthand side of the lefthand entry
|
||||||
|
|
|
@ -54,14 +54,14 @@ struct ReclaimedPage {
|
||||||
/**
|
/**
|
||||||
* Allocates new page of physical memory.
|
* Allocates new page of physical memory.
|
||||||
*/
|
*/
|
||||||
noasan texthead uint64_t __new_page(struct mman *mm) {
|
dontasan texthead uint64_t __new_page(struct mman *mm) {
|
||||||
uint64_t p = mm->frp;
|
uint64_t p = mm->frp;
|
||||||
if (p != NOPAGE) {
|
if (p != NOPAGE) {
|
||||||
uint64_t q;
|
uint64_t q;
|
||||||
struct ReclaimedPage *rp = (struct ReclaimedPage *)(BANE + p);
|
struct ReclaimedPage *rp = (struct ReclaimedPage *)(BANE + p);
|
||||||
_unassert(p == (p & PAGE_TA));
|
unassert(p == (p & PAGE_TA));
|
||||||
q = rp->next;
|
q = rp->next;
|
||||||
_unassert(q == (q & PAGE_TA) || q == NOPAGE);
|
unassert(q == (q & PAGE_TA) || q == NOPAGE);
|
||||||
mm->frp = q;
|
mm->frp = q;
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
@ -81,8 +81,8 @@ noasan texthead uint64_t __new_page(struct mman *mm) {
|
||||||
* Returns pointer to page table entry for page at virtual address.
|
* Returns pointer to page table entry for page at virtual address.
|
||||||
* Additional page tables are allocated if needed as a side-effect.
|
* Additional page tables are allocated if needed as a side-effect.
|
||||||
*/
|
*/
|
||||||
noasan textreal uint64_t *__get_virtual(struct mman *mm, uint64_t *t,
|
dontasan textreal uint64_t *__get_virtual(struct mman *mm, uint64_t *t,
|
||||||
int64_t vaddr, bool maketables) {
|
int64_t vaddr, bool maketables) {
|
||||||
uint64_t *e, p;
|
uint64_t *e, p;
|
||||||
unsigned char h;
|
unsigned char h;
|
||||||
for (h = 39;; h -= 9) {
|
for (h = 39;; h -= 9) {
|
||||||
|
@ -101,7 +101,7 @@ noasan textreal uint64_t *__get_virtual(struct mman *mm, uint64_t *t,
|
||||||
/**
|
/**
|
||||||
* Sorts, rounds, and filters BIOS memory map.
|
* Sorts, rounds, and filters BIOS memory map.
|
||||||
*/
|
*/
|
||||||
static noasan textreal void __normalize_e820(struct mman *mm, uint64_t top) {
|
static dontasan textreal void __normalize_e820(struct mman *mm, uint64_t top) {
|
||||||
uint64_t a, b;
|
uint64_t a, b;
|
||||||
uint64_t x, y;
|
uint64_t x, y;
|
||||||
unsigned i, j, n;
|
unsigned i, j, n;
|
||||||
|
@ -134,9 +134,10 @@ static noasan textreal void __normalize_e820(struct mman *mm, uint64_t top) {
|
||||||
/**
|
/**
|
||||||
* Identity maps an area of physical memory to its negative address.
|
* Identity maps an area of physical memory to its negative address.
|
||||||
*/
|
*/
|
||||||
noasan textreal uint64_t *__invert_memory_area(struct mman *mm, uint64_t *pml4t,
|
dontasan textreal uint64_t *__invert_memory_area(struct mman *mm,
|
||||||
uint64_t ps, uint64_t size,
|
uint64_t *pml4t, uint64_t ps,
|
||||||
uint64_t pte_flags) {
|
uint64_t size,
|
||||||
|
uint64_t pte_flags) {
|
||||||
uint64_t pe = ps + size, p, *m = NULL;
|
uint64_t pe = ps + size, p, *m = NULL;
|
||||||
ps = ROUNDDOWN(ps, 4096);
|
ps = ROUNDDOWN(ps, 4096);
|
||||||
pe = ROUNDUP(pe, 4096);
|
pe = ROUNDUP(pe, 4096);
|
||||||
|
@ -152,7 +153,7 @@ noasan textreal uint64_t *__invert_memory_area(struct mman *mm, uint64_t *pml4t,
|
||||||
/**
|
/**
|
||||||
* Increments the reference count for a page of physical memory.
|
* Increments the reference count for a page of physical memory.
|
||||||
*/
|
*/
|
||||||
noasan void __ref_page(struct mman *mm, uint64_t *pml4t, uint64_t p) {
|
dontasan void __ref_page(struct mman *mm, uint64_t *pml4t, uint64_t p) {
|
||||||
uint64_t *m, e;
|
uint64_t *m, e;
|
||||||
m = __invert_memory_area(mm, pml4t, p, 4096, PAGE_RW | PAGE_XD);
|
m = __invert_memory_area(mm, pml4t, p, 4096, PAGE_RW | PAGE_XD);
|
||||||
if (m) {
|
if (m) {
|
||||||
|
@ -167,8 +168,8 @@ noasan void __ref_page(struct mman *mm, uint64_t *pml4t, uint64_t p) {
|
||||||
/**
|
/**
|
||||||
* Increments the reference counts for an area of physical memory.
|
* Increments the reference counts for an area of physical memory.
|
||||||
*/
|
*/
|
||||||
noasan void __ref_pages(struct mman *mm, uint64_t *pml4t, uint64_t ps,
|
dontasan void __ref_pages(struct mman *mm, uint64_t *pml4t, uint64_t ps,
|
||||||
uint64_t size) {
|
uint64_t size) {
|
||||||
uint64_t p = ROUNDDOWN(ps, 4096), e = ROUNDUP(ps + size, 4096);
|
uint64_t p = ROUNDDOWN(ps, 4096), e = ROUNDUP(ps + size, 4096);
|
||||||
while (p != e) {
|
while (p != e) {
|
||||||
__ref_page(mm, pml4t, p);
|
__ref_page(mm, pml4t, p);
|
||||||
|
@ -179,9 +180,9 @@ noasan void __ref_pages(struct mman *mm, uint64_t *pml4t, uint64_t ps,
|
||||||
/**
|
/**
|
||||||
* Reclaims a page of physical memory for later use.
|
* Reclaims a page of physical memory for later use.
|
||||||
*/
|
*/
|
||||||
static noasan void __reclaim_page(struct mman *mm, uint64_t p) {
|
static dontasan void __reclaim_page(struct mman *mm, uint64_t p) {
|
||||||
struct ReclaimedPage *rp = (struct ReclaimedPage *)(BANE + p);
|
struct ReclaimedPage *rp = (struct ReclaimedPage *)(BANE + p);
|
||||||
_unassert(p == (p & PAGE_TA));
|
unassert(p == (p & PAGE_TA));
|
||||||
rp->next = mm->frp;
|
rp->next = mm->frp;
|
||||||
mm->frp = p;
|
mm->frp = p;
|
||||||
}
|
}
|
||||||
|
@ -191,7 +192,7 @@ static noasan void __reclaim_page(struct mman *mm, uint64_t p) {
|
||||||
* page if there are no virtual addresses (excluding the negative space)
|
* page if there are no virtual addresses (excluding the negative space)
|
||||||
* referring to it.
|
* referring to it.
|
||||||
*/
|
*/
|
||||||
noasan void __unref_page(struct mman *mm, uint64_t *pml4t, uint64_t p) {
|
dontasan void __unref_page(struct mman *mm, uint64_t *pml4t, uint64_t p) {
|
||||||
uint64_t *m, e;
|
uint64_t *m, e;
|
||||||
m = __invert_memory_area(mm, pml4t, p, 4096, PAGE_RW | PAGE_XD);
|
m = __invert_memory_area(mm, pml4t, p, 4096, PAGE_RW | PAGE_XD);
|
||||||
if (m) {
|
if (m) {
|
||||||
|
@ -207,7 +208,8 @@ noasan void __unref_page(struct mman *mm, uint64_t *pml4t, uint64_t p) {
|
||||||
/**
|
/**
|
||||||
* Identity maps all usable physical memory to its negative address.
|
* Identity maps all usable physical memory to its negative address.
|
||||||
*/
|
*/
|
||||||
static noasan textreal void __invert_memory(struct mman *mm, uint64_t *pml4t) {
|
static dontasan textreal void __invert_memory(struct mman *mm,
|
||||||
|
uint64_t *pml4t) {
|
||||||
uint64_t i, j, *m, p, pe;
|
uint64_t i, j, *m, p, pe;
|
||||||
for (i = 0; i < mm->e820n; ++i) {
|
for (i = 0; i < mm->e820n; ++i) {
|
||||||
uint64_t ps = mm->e820[i].addr, size = mm->e820[i].size;
|
uint64_t ps = mm->e820[i].addr, size = mm->e820[i].size;
|
||||||
|
@ -230,8 +232,8 @@ static noasan textreal void __invert_memory(struct mman *mm, uint64_t *pml4t) {
|
||||||
: "i"(offsetof(type, member))); \
|
: "i"(offsetof(type, member))); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
noasan textreal void __setup_mman(struct mman *mm, uint64_t *pml4t,
|
dontasan textreal void __setup_mman(struct mman *mm, uint64_t *pml4t,
|
||||||
uint64_t top) {
|
uint64_t top) {
|
||||||
export_offsetof(struct mman, pc_drive_base_table);
|
export_offsetof(struct mman, pc_drive_base_table);
|
||||||
export_offsetof(struct mman, pc_drive_last_sector);
|
export_offsetof(struct mman, pc_drive_last_sector);
|
||||||
export_offsetof(struct mman, pc_drive_last_head);
|
export_offsetof(struct mman, pc_drive_last_head);
|
||||||
|
@ -257,8 +259,8 @@ noasan textreal void __setup_mman(struct mman *mm, uint64_t *pml4t,
|
||||||
/**
|
/**
|
||||||
* Maps APE-defined ELF program headers into memory and clears BSS.
|
* Maps APE-defined ELF program headers into memory and clears BSS.
|
||||||
*/
|
*/
|
||||||
noasan textreal void __map_phdrs(struct mman *mm, uint64_t *pml4t, uint64_t b,
|
dontasan textreal void __map_phdrs(struct mman *mm, uint64_t *pml4t, uint64_t b,
|
||||||
uint64_t top) {
|
uint64_t top) {
|
||||||
struct Elf64_Phdr *p;
|
struct Elf64_Phdr *p;
|
||||||
uint64_t i, f, v, m, *e;
|
uint64_t i, f, v, m, *e;
|
||||||
extern char ape_phdrs[] __attribute__((__weak__));
|
extern char ape_phdrs[] __attribute__((__weak__));
|
||||||
|
@ -292,8 +294,9 @@ noasan textreal void __map_phdrs(struct mman *mm, uint64_t *pml4t, uint64_t b,
|
||||||
* Reclaims memory pages which were used at boot time but which can now be
|
* Reclaims memory pages which were used at boot time but which can now be
|
||||||
* made available for the application.
|
* made available for the application.
|
||||||
*/
|
*/
|
||||||
noasan textreal void __reclaim_boot_pages(struct mman *mm, uint64_t skip_start,
|
dontasan textreal void __reclaim_boot_pages(struct mman *mm,
|
||||||
uint64_t skip_end) {
|
uint64_t skip_start,
|
||||||
|
uint64_t skip_end) {
|
||||||
uint64_t p = mm->frp, q = IMAGE_BASE_REAL, i, n = mm->e820n, b, e;
|
uint64_t p = mm->frp, q = IMAGE_BASE_REAL, i, n = mm->e820n, b, e;
|
||||||
for (i = 0; i < n; ++i) {
|
for (i = 0; i < n; ++i) {
|
||||||
b = mm->e820[i].addr;
|
b = mm->e820[i].addr;
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#include "libc/thread/thread.h"
|
#include "libc/thread/thread.h"
|
||||||
|
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
STATIC_YOINK("_init__mmi");
|
__static_yoink("_init__mmi");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct MemoryIntervals _mmi;
|
struct MemoryIntervals _mmi;
|
||||||
|
|
|
@ -48,9 +48,9 @@
|
||||||
*/
|
*/
|
||||||
bool __nocolor;
|
bool __nocolor;
|
||||||
|
|
||||||
optimizesize textstartup noasan void __nocolor_init(int argc, char **argv,
|
optimizesize textstartup dontasan void __nocolor_init(int argc, char **argv,
|
||||||
char **envp,
|
char **envp,
|
||||||
intptr_t *auxv) {
|
intptr_t *auxv) {
|
||||||
char *s;
|
char *s;
|
||||||
__nocolor = (IsWindows() && !IsAtLeastWindows10()) ||
|
__nocolor = (IsWindows() && !IsAtLeastWindows10()) ||
|
||||||
((s = getenv("TERM")) && IsDumb(s));
|
((s = getenv("TERM")) && IsDumb(s));
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
*
|
*
|
||||||
* @see IsAtLeastWindows10()
|
* @see IsAtLeastWindows10()
|
||||||
*/
|
*/
|
||||||
textwindows noasan int NtGetVersion(void) {
|
textwindows dontasan int NtGetVersion(void) {
|
||||||
return (NtGetPeb()->OSMajorVersion & 0xff) << 8 | NtGetPeb()->OSMinorVersion;
|
return (NtGetPeb()->OSMajorVersion & 0xff) << 8 | NtGetPeb()->OSMinorVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
void(pthread_cleanup_pop)(struct _pthread_cleanup_buffer *cb, int execute) {
|
void(pthread_cleanup_pop)(struct _pthread_cleanup_buffer *cb, int execute) {
|
||||||
struct PosixThread *pt;
|
struct PosixThread *pt;
|
||||||
if (__tls_enabled && (pt = (struct PosixThread *)__get_tls()->tib_pthread)) {
|
if (__tls_enabled && (pt = (struct PosixThread *)__get_tls()->tib_pthread)) {
|
||||||
_unassert(cb == pt->cleanup);
|
unassert(cb == pt->cleanup);
|
||||||
pt->cleanup = cb->__prev;
|
pt->cleanup = cb->__prev;
|
||||||
}
|
}
|
||||||
if (execute) {
|
if (execute) {
|
||||||
|
|
|
@ -35,7 +35,7 @@ void *pthread_getspecific(pthread_key_t k) {
|
||||||
// pthread_key_create() or after key has been deleted with
|
// pthread_key_create() or after key has been deleted with
|
||||||
// pthread_key_delete() is undefined."
|
// pthread_key_delete() is undefined."
|
||||||
// ──Quoth POSIX.1-2017
|
// ──Quoth POSIX.1-2017
|
||||||
_unassert(0 <= k && k < PTHREAD_KEYS_MAX);
|
unassert(0 <= k && k < PTHREAD_KEYS_MAX);
|
||||||
_unassert(atomic_load_explicit(_pthread_key_dtor + k, memory_order_acquire));
|
unassert(atomic_load_explicit(_pthread_key_dtor + k, memory_order_acquire));
|
||||||
return __get_tls()->tib_keys[k];
|
return __get_tls()->tib_keys[k];
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,8 +35,8 @@
|
||||||
*/
|
*/
|
||||||
int pthread_key_delete(pthread_key_t k) {
|
int pthread_key_delete(pthread_key_t k) {
|
||||||
uint64_t mask;
|
uint64_t mask;
|
||||||
_unassert(0 <= k && k < PTHREAD_KEYS_MAX);
|
unassert(0 <= k && k < PTHREAD_KEYS_MAX);
|
||||||
_unassert(atomic_load_explicit(_pthread_key_dtor + k, memory_order_acquire));
|
unassert(atomic_load_explicit(_pthread_key_dtor + k, memory_order_acquire));
|
||||||
atomic_store_explicit(_pthread_key_dtor + k, 0, memory_order_release);
|
atomic_store_explicit(_pthread_key_dtor + k, 0, memory_order_release);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,8 +35,8 @@ int pthread_setspecific(pthread_key_t k, const void *val) {
|
||||||
// pthread_key_create() or after key has been deleted with
|
// pthread_key_create() or after key has been deleted with
|
||||||
// pthread_key_delete() is undefined."
|
// pthread_key_delete() is undefined."
|
||||||
// ──Quoth POSIX.1-2017
|
// ──Quoth POSIX.1-2017
|
||||||
_unassert(0 <= k && k < PTHREAD_KEYS_MAX);
|
unassert(0 <= k && k < PTHREAD_KEYS_MAX);
|
||||||
_unassert(atomic_load_explicit(_pthread_key_dtor + k, memory_order_acquire));
|
unassert(atomic_load_explicit(_pthread_key_dtor + k, memory_order_acquire));
|
||||||
__get_tls()->tib_keys[k] = val;
|
__get_tls()->tib_keys[k] = val;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,14 +48,14 @@ errno_t(pthread_spin_lock)(pthread_spinlock_t *spin) {
|
||||||
LOCKTRACE("pthread_spin_lock(%t)", spin);
|
LOCKTRACE("pthread_spin_lock(%t)", spin);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
_unassert(x == 1);
|
unassert(x == 1);
|
||||||
LOCKTRACE("pthread_spin_lock(%t) trying...", spin);
|
LOCKTRACE("pthread_spin_lock(%t) trying...", spin);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
for (;;) {
|
for (;;) {
|
||||||
x = atomic_exchange_explicit(&spin->_lock, 1, memory_order_acquire);
|
x = atomic_exchange_explicit(&spin->_lock, 1, memory_order_acquire);
|
||||||
if (!x) break;
|
if (!x) break;
|
||||||
_unassert(x == 1);
|
unassert(x == 1);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -34,6 +34,6 @@ errno_t(pthread_spin_trylock)(pthread_spinlock_t *spin) {
|
||||||
int x;
|
int x;
|
||||||
x = atomic_exchange_explicit(&spin->_lock, 1, memory_order_acquire);
|
x = atomic_exchange_explicit(&spin->_lock, 1, memory_order_acquire);
|
||||||
if (!x) return 0;
|
if (!x) return 0;
|
||||||
_unassert(x == 1);
|
unassert(x == 1);
|
||||||
return EBUSY;
|
return EBUSY;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16)));
|
||||||
* @return pointer to nul byte
|
* @return pointer to nul byte
|
||||||
* @asyncsignalsafe
|
* @asyncsignalsafe
|
||||||
*/
|
*/
|
||||||
noasan char *stpcpy(char *d, const char *s) {
|
dontasan char *stpcpy(char *d, const char *s) {
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
if (IsAsan()) {
|
if (IsAsan()) {
|
||||||
__asan_verify(d, strlen(s) + 1);
|
__asan_verify(d, strlen(s) + 1);
|
||||||
|
|
|
@ -32,7 +32,7 @@ static inline const char *strchr_pure(const char *s, int c) {
|
||||||
|
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16)));
|
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16)));
|
||||||
noasan static inline const char *strchr_sse(const char *s, unsigned char c) {
|
dontasan static inline const char *strchr_sse(const char *s, unsigned char c) {
|
||||||
unsigned k;
|
unsigned k;
|
||||||
unsigned m;
|
unsigned m;
|
||||||
xmm_t v, *p;
|
xmm_t v, *p;
|
||||||
|
@ -55,7 +55,7 @@ noasan static inline const char *strchr_sse(const char *s, unsigned char c) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static noasan inline const char *strchr_x64(const char *p, uint64_t c) {
|
static dontasan inline const char *strchr_x64(const char *p, uint64_t c) {
|
||||||
unsigned a, b;
|
unsigned a, b;
|
||||||
uint64_t w, x, y;
|
uint64_t w, x, y;
|
||||||
for (c *= 0x0101010101010101;; p += 8) {
|
for (c *= 0x0101010101010101;; p += 8) {
|
||||||
|
@ -103,7 +103,7 @@ char *strchr(const char *s, int c) {
|
||||||
} else {
|
} else {
|
||||||
r = strchr_pure(s, c);
|
r = strchr_pure(s, c);
|
||||||
}
|
}
|
||||||
_unassert(!r || *r || !(c & 255));
|
unassert(!r || *r || !(c & 255));
|
||||||
return (char *)r;
|
return (char *)r;
|
||||||
#else
|
#else
|
||||||
char *r;
|
char *r;
|
||||||
|
@ -112,7 +112,7 @@ char *strchr(const char *s, int c) {
|
||||||
if (!*s) return NULL;
|
if (!*s) return NULL;
|
||||||
}
|
}
|
||||||
r = strchr_x64(s, c);
|
r = strchr_x64(s, c);
|
||||||
_unassert(!r || *r || !c);
|
unassert(!r || *r || !c);
|
||||||
return r;
|
return r;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,8 @@ static inline const char *strchrnul_pure(const char *s, int c) {
|
||||||
|
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16)));
|
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16)));
|
||||||
noasan static inline const char *strchrnul_sse(const char *s, unsigned char c) {
|
dontasan static inline const char *strchrnul_sse(const char *s,
|
||||||
|
unsigned char c) {
|
||||||
unsigned k;
|
unsigned k;
|
||||||
unsigned m;
|
unsigned m;
|
||||||
xmm_t v, *p;
|
xmm_t v, *p;
|
||||||
|
@ -52,7 +53,7 @@ noasan static inline const char *strchrnul_sse(const char *s, unsigned char c) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
noasan static const char *strchrnul_x64(const char *p, uint64_t c) {
|
dontasan static const char *strchrnul_x64(const char *p, uint64_t c) {
|
||||||
unsigned a, b;
|
unsigned a, b;
|
||||||
uint64_t w, x, y;
|
uint64_t w, x, y;
|
||||||
for (c *= 0x0101010101010101;; p += 8) {
|
for (c *= 0x0101010101010101;; p += 8) {
|
||||||
|
@ -101,7 +102,7 @@ char *strchrnul(const char *s, int c) {
|
||||||
} else {
|
} else {
|
||||||
r = strchrnul_pure(s, c);
|
r = strchrnul_pure(s, c);
|
||||||
}
|
}
|
||||||
_unassert((*r & 255) == (c & 255) || !*r);
|
unassert((*r & 255) == (c & 255) || !*r);
|
||||||
return (char *)r;
|
return (char *)r;
|
||||||
#else
|
#else
|
||||||
char *r;
|
char *r;
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
* @return is <0, 0, or >0 based on uint8_t comparison
|
* @return is <0, 0, or >0 based on uint8_t comparison
|
||||||
* @asyncsignalsafe
|
* @asyncsignalsafe
|
||||||
*/
|
*/
|
||||||
noasan int strcmp(const char *a, const char *b) {
|
dontasan int strcmp(const char *a, const char *b) {
|
||||||
int c;
|
int c;
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
uint64_t v, w, d;
|
uint64_t v, w, d;
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue