diff --git a/README.md b/README.md index 2e8477863..2e44683bc 100644 --- a/README.md +++ b/README.md @@ -28,21 +28,57 @@ printf 'main() { printf("hello world\\n"); }\n' >hello.c gcc -g -Os -static -nostdlib -nostdinc -fno-pie -no-pie -mno-red-zone \ -fno-omit-frame-pointer -pg -mnop-mcount \ -o hello.com.dbg hello.c -fuse-ld=bfd -Wl,-T,ape.lds \ - -include cosmopolitan.h crt.o ape.o cosmopolitan.a + -include cosmopolitan.h crt.o ape-no-modify-self.o cosmopolitan.a objcopy -S -O binary hello.com.dbg hello.com ``` -You now have a portable program. Please note that your APE binary will -assimilate itself as a conventional resident of your platform after the -first run, so it can be fast and efficient for subsequent executions. +You now have a portable program. ```sh ./hello.com -bash -c './hello.com' # zsh/fish workaround (we upstreamed patches) +bash -c './hello.com' # zsh/fish workaround (we patched them in 2021) ``` -So if you intend to copy the binary to Windows or Mac then please do -that before you run it, not after. +Since we used the `ape-no-modify-self.o` bootloader (rather than +`ape.o`) your executable will not modify itself when it's run. What +it'll instead do, is extract a 4kb program to `${TMPDIR:-/tmp}` that +maps your program into memory without needing to copy it. It's possible +to install the APE loader systemwide as follows. + +```sh +# (1) linux systems that want binfmt_misc +ape/apeinstall.sh + +# (2) for linux/freebsd/netbsd/openbsd systems +cp build/bootstrap/ape.elf /usr/bin/ape + +# (3) for mac os x systems +cp build/bootstrap/ape.macho /usr/bin/ape +``` + +If you followed steps (2) and (3) then there's going to be a slight +constant-time startup latency each time you run an APE binary. Your +system might also prevent your APE program from being installed to a +system directory as a setuid binary or a script interpreter. To solve +that, you can use the following flag to turn your binary into the +platform local format (ELF or Mach-O): + +```sh +./hello.com --assimilate +``` + +There's also some other useful flags that get baked into your binary by +default: + +```sh +./hello.com --strace +./hello.com --ftrace +``` + +If you want your `hello.com` program to be much tinier, more on the +order of 16kb rather than 60kb, then all you have to do is use + instead. See +. ### MacOS diff --git a/ape/ape.S b/ape/ape.S index c7f02a217..5074682c0 100644 --- a/ape/ape.S +++ b/ape/ape.S @@ -542,34 +542,37 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang // present two choices. .ascii "o=\"$(command -v \"$0\")\"\n" // Try to use a system-wide APE loader. - .ascii "type ape >/dev/null 2>&1 && " - .ascii "exec ape \"$o\" \"$@\"\n" + .ascii "[ x\"$1\" != x--assimilate ] && " + .ascii "type ape >/dev/null 2>&1 && " + .ascii "exec ape \"$o\" \"$@\"\n" #ifdef APE_LOADER // There is no system-wide APE loader, but there is one // embedded inside the APE. So if the system is not MacOs, // extract the loader into a temp folder, and use it to // load the APE without modifying it. - .ascii "t=\"${TMPDIR:-/tmp}/ape\"\n" - .ascii "[ -x \"$t\" ] || {\n" - .ascii "dd if=\"$o\" of=\"$t.$$\" skip=\"" - .shstub ape_loader_dd_skip,2 - .ascii "\" count=\"" - .shstub ape_loader_dd_count,2 - .ascii "\" bs=64 2>/dev/null\n" + .ascii "[ x\"$1\" != x--assimilate ] && {\n" + .ascii "t=\"${TMPDIR:-/tmp}/ape\"\n" + .ascii "[ -x \"$t\" ] || {\n" + .ascii "dd if=\"$o\" of=\"$t.$$\" skip=\"" + .shstub ape_loader_dd_skip,2 + .ascii "\" count=\"" + .shstub ape_loader_dd_count,2 + .ascii "\" bs=64 2>/dev/null\n" #if SupportsXnu() - .ascii "[ -d /Applications ] && " - .ascii "dd if=\"$t.$$\"" - .ascii " of=\"$t.$$\"" - .ascii " skip=6" - .ascii " count=10" - .ascii " bs=64" - .ascii " conv=notrunc" - .ascii " 2>/dev/null\n" + .ascii "[ -d /Applications ] && " + .ascii "dd if=\"$t.$$\"" + .ascii " of=\"$t.$$\"" + .ascii " skip=6" + .ascii " count=10" + .ascii " bs=64" + .ascii " conv=notrunc" + .ascii " 2>/dev/null\n" #endif /* SupportsXnu() */ - .ascii "chmod 755 \"$t.$$\"\n" - .ascii "mv -f \"$t.$$\" \"$t\"\n" + .ascii "chmod 755 \"$t.$$\"\n" + .ascii "mv -f \"$t.$$\" \"$t\"\n" + .ascii "}\n" + .ascii "exec \"$t\" \"$o\" \"$@\"\n" .ascii "}\n" - .ascii "exec \"$t\" \"$o\" \"$@\"\n" #endif /* APE_LOADER */ #ifndef APE_NO_MODIFY_SELF // The default behavior is: to overwrite the header in place. @@ -590,11 +593,13 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang // since only root is able to set the sticky bit, which can // be addressed simply by overriding the TMPDIR environment .ascii "t=\"${TMPDIR:-/tmp}/$0\"\n" - .ascii "[ -e \"$t\" ] || {\n" - .ascii "mkdir -p \"${t%/*}\" 2>/dev/null\n" - .ascii "cp -f \"$o\" \"$t.$$\" &&\n" - .ascii "mv -f \"$t.$$\" \"$t\" || exit 120\n" - .ascii "o=\"$t\"\n" + .ascii "[ x\"$1\" != x--assimilate ] || [ ! -e \"$t\" ] && {\n" + .ascii "[ x\"$1\" != x--assimilate ] && {\n" + .ascii "mkdir -p \"${t%/*}\" 2>/dev/null\n" + .ascii "cp -f \"$o\" \"$t.$$\" &&\n" + .ascii "mv -f \"$t.$$\" \"$t\" || exit 120\n" + .ascii "o=\"$t\"\n" + .ascii "}\n" #endif /* APE_NO_MODIFY_SELF */ .ascii "exec 7<> \"$o\" || exit 121\n" .ascii "printf '" @@ -632,6 +637,7 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang .shstub ape_macho_dd_count,2 .ascii "\" conv=notrunc 2>/dev/null\n" #endif /* XNU */ + .ascii "[ x\"$1\" = x--assimilate ] && exit 0\n" #ifndef APE_NO_MODIFY_SELF .ascii "exec \"$0\" \"$@\"\n" # try to preserve argv[0] #else diff --git a/examples/examples.mk b/examples/examples.mk index 388b019b3..75002a90f 100644 --- a/examples/examples.mk +++ b/examples/examples.mk @@ -112,6 +112,14 @@ o/$(MODE)/examples/nomodifyself.com.dbg: \ $(APE_NO_MODIFY_SELF) @$(APELINK) +o/$(MODE)/examples/greenbean.com.dbg: \ + $(EXAMPLES_DEPS) \ + o/$(MODE)/examples/greenbean.o \ + o/$(MODE)/examples/examples.pkg \ + $(CRT) \ + $(APE_NO_MODIFY_SELF) + @$(APELINK) + o/$(MODE)/examples/hellolua.com.dbg: \ $(EXAMPLES_DEPS) \ o/$(MODE)/examples/hellolua.o \ @@ -162,4 +170,5 @@ usr/share/dict/words: usr/share/dict/words.gz .PHONY: o/$(MODE)/examples o/$(MODE)/examples: \ o/$(MODE)/examples/package \ + o/$(MODE)/examples/pyapp \ $(EXAMPLES_BINS) diff --git a/examples/greenbean.c b/examples/greenbean.c index 275bab40b..0d475bd85 100644 --- a/examples/greenbean.c +++ b/examples/greenbean.c @@ -70,20 +70,20 @@ * Like redbean, greenbean has superior performance too, with an * advantage on benchmarks biased towards high connection counts * - * $ sudo wrk -c 300 -t 32 --latency http://10.10.10.124:8080/ + * $ wrk -c 300 -t 32 --latency http://10.10.10.124:8080/ * Running 10s test @ http://10.10.10.124:8080/ * 32 threads and 300 connections * Thread Stats Avg Stdev Max +/- Stdev - * Latency 1.07ms 8.27ms 138.55ms 98.58% - * Req/Sec 37.98k 12.61k 117.65k 80.11% + * Latency 661.06us 5.11ms 96.22ms 98.85% + * Req/Sec 42.38k 8.90k 90.47k 84.65% * Latency Distribution - * 50% 200.00us - * 75% 227.00us - * 90% 303.00us - * 99% 32.46ms - * 10033090 requests in 8.31s, 2.96GB read - * Requests/sec: 1207983.58 - * Transfer/sec: 365.19MB + * 50% 184.00us + * 75% 201.00us + * 90% 224.00us + * 99% 11.99ms + * 10221978 requests in 7.60s, 3.02GB read + * Requests/sec: 1345015.69 + * Transfer/sec: 406.62MB * */ @@ -97,6 +97,7 @@ "Referrer-Policy: origin\r\n" \ "Cache-Control: private; max-age=0\r\n" +int threads; _Atomic(int) workers; _Atomic(int) messages; _Atomic(int) listening; @@ -114,7 +115,9 @@ int Worker(void *id) { server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (server == -1) { - if (LOGGING) kprintf("%s() failed %m\n", "socket"); + kprintf("socket() failed %m\n" + " try running: sudo prlimit --pid=$$ --nofile=%d\n", + threads * 2); goto WorkerFinished; } @@ -127,8 +130,8 @@ int Worker(void *id) { errno = 0; if (bind(server, &addr, sizeof(addr)) == -1) { - if (LOGGING) kprintf("%s() failed %m\n", "socket"); - goto WorkerFinished; + kprintf("%s() failed %m\n", "socket"); + goto CloseWorker; } listen(server, 1); @@ -246,8 +249,9 @@ int Worker(void *id) { --listening; // inform the parent that this clone has finished -WorkerFinished: +CloseWorker: close(server); +WorkerFinished: --workers; return 0; } @@ -267,9 +271,9 @@ void PrintStatus(void) { } int main(int argc, char *argv[]) { + int i; char **tls; char **stack; - int i, threads; uint32_t *hostips; // ShowCrashReports(); @@ -295,7 +299,6 @@ int main(int argc, char *argv[]) { if ((1 <= threads && threads <= INT_MAX) && (tls = malloc(threads * sizeof(*tls))) && (stack = malloc(threads * sizeof(*stack)))) { - if (!threads) threads = GetCpuCount(); for (i = 0; i < threads; ++i) { if ((tls[i] = __initialize_tls(malloc(64))) && (stack[i] = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE, diff --git a/examples/nomodifyself.c b/examples/nomodifyself.c index 7db1e89e6..c3c5be75f 100644 --- a/examples/nomodifyself.c +++ b/examples/nomodifyself.c @@ -21,7 +21,7 @@ int main(int argc, char *argv[]) { if (_base[0] == 'M' && _base[1] == 'Z') { printf("success: %s spawned without needing to modify its " - "executable header, thanks to APE loader\n", + "executable header", argv[0]); if (!IsWindows()) { printf(", thanks to APE loader!\n"); diff --git a/test/libc/calls/execve_test.c b/libc/calls/__clock_gettime.S similarity index 65% rename from test/libc/calls/execve_test.c rename to libc/calls/__clock_gettime.S index 2dd8ae76e..3e5d052c9 100644 --- a/test/libc/calls/execve_test.c +++ b/libc/calls/__clock_gettime.S @@ -1,5 +1,5 @@ -/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ -│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ +│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ @@ -16,36 +16,15 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/calls.h" -#include "libc/dce.h" -#include "libc/log/check.h" -#include "libc/runtime/runtime.h" -#include "libc/testlib/testlib.h" +#include "libc/macros.internal.h" -void SetUp(void) { - if (getenv("_WEIRDENV")) { - for (char **e = environ; *e; ++e) { - if (!strcmp(*e, "WEIRD")) { - exit(0); - } - } - exit(7); - } -} + .initbss 201,_init___clock_gettime +__clock_gettime: + .quad 0 + .endobj __clock_gettime,globl,hidden + .previous -TEST(execve, testWeirdEnvironmentVariable) { - char *prog; - int pid, ws; - if (IsWindows()) return; - if (IsOpenbsd()) return; - prog = GetProgramExecutableName(); - ASSERT_NE(-1, (pid = fork())); - if (!pid) { - execve(prog, (char *const[]){prog, 0}, - (char *const[]){"_WEIRDENV=1", "WEIRD", 0}); - _Exit(127); - } - ASSERT_NE(-1, wait(&ws)); - EXPECT_TRUE(WIFEXITED(ws)); - EXPECT_EQ(0, WEXITSTATUS(ws)); -} + .init.start 201,_init___clock_gettime + ezlea __clock_gettime_init,ax + stosq + .init.end 201,_init___clock_gettime diff --git a/libc/calls/asan.internal.h b/libc/calls/asan.internal.h new file mode 100644 index 000000000..e73bbd39c --- /dev/null +++ b/libc/calls/asan.internal.h @@ -0,0 +1,19 @@ +#ifndef COSMOPOLITAN_LIBC_CALLS_ASAN_INTERNAL_H_ +#define COSMOPOLITAN_LIBC_CALLS_ASAN_INTERNAL_H_ +#include "libc/bits/asmflag.h" +#include "libc/calls/struct/timespec.h" +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +forceinline bool __asan_is_valid_timespec(const struct timespec *ts) { + bool zf; + asm(ZFLAG_ASM("cmpw\t$0,0x7fff8000(%1)") + : ZFLAG_CONSTRAINT(zf) + : "r"((intptr_t)ts >> 3) + : "memory"); + return zf; +} + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_CALLS_ASAN_INTERNAL_H_ */ diff --git a/libc/calls/clock_gettime-nt.c b/libc/calls/clock_gettime-nt.c index e9bca40f2..50dcb25de 100644 --- a/libc/calls/clock_gettime-nt.c +++ b/libc/calls/clock_gettime-nt.c @@ -27,6 +27,7 @@ textwindows int sys_clock_gettime_nt(int clockid, struct timespec *ts) { struct timespec res; struct NtFileTime ft; static struct timespec mono; + if (!ts) return efault(); if (clockid == CLOCK_REALTIME) { GetSystemTimeAsFileTime(&ft); *ts = FileTimeToTimeSpec(ft); diff --git a/test/libc/time/nowl_test.c b/libc/calls/clock_gettime-xnu.c similarity index 73% rename from test/libc/time/nowl_test.c rename to libc/calls/clock_gettime-xnu.c index a09d77df7..3b911f9c2 100644 --- a/test/libc/time/nowl_test.c +++ b/libc/calls/clock_gettime-xnu.c @@ -1,7 +1,7 @@ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ ╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ @@ -16,24 +16,20 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/struct/timespec.h" -#include "libc/nexgen32e/rdtscp.h" -#include "libc/sysv/consts/clock.h" -#include "libc/testlib/ezbench.h" -#include "libc/testlib/testlib.h" -#include "libc/time/time.h" +#include "libc/calls/calls.h" +#include "libc/calls/internal.h" -TEST(nowl, testIsMonotonic) { - long double a = nowl(); - long double b = nowl(); - EXPECT_TRUE(b > a); -} - -BENCH(nowl, bench) { - volatile int64_t c; - volatile long double x; - volatile struct timespec ts; - EZBENCH2("rdtsc", donothing, c = rdtsc()); - EZBENCH2("nowl", donothing, x = nowl()); - EZBENCH2("clock_gettime", donothing, clock_gettime(CLOCK_MONOTONIC, &ts)); +int sys_clock_gettime_xnu(int clockid, struct timespec *ts) { + axdx_t ad; + ad = sys_gettimeofday((struct timeval *)ts, NULL, NULL); + if (ad.ax != -1) { + if (ad.ax) { + ts->tv_sec = ad.ax; + ts->tv_nsec = ad.dx; + } + ts->tv_nsec *= 1000; + return 0; + } else { + return -1; + } } diff --git a/libc/calls/clock_gettime.c b/libc/calls/clock_gettime.c index ab086c746..8b4a962ed 100644 --- a/libc/calls/clock_gettime.c +++ b/libc/calls/clock_gettime.c @@ -17,6 +17,10 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" +#include "libc/bits/asmflag.h" +#include "libc/bits/bits.h" +#include "libc/calls/asan.internal.h" +#include "libc/calls/clock_gettime.h" #include "libc/calls/internal.h" #include "libc/calls/state.internal.h" #include "libc/calls/strace.internal.h" @@ -26,11 +30,10 @@ #include "libc/fmt/conv.h" #include "libc/intrin/asan.internal.h" #include "libc/intrin/describeflags.internal.h" +#include "libc/mem/alloca.h" #include "libc/nt/synchronization.h" #include "libc/sysv/errfuns.h" -static typeof(sys_clock_gettime) *__clock_gettime = sys_clock_gettime; - /** * Returns nanosecond time. * @@ -38,6 +41,13 @@ static typeof(sys_clock_gettime) *__clock_gettime = sys_clock_gettime; * time. Among the more popular is CLOCK_MONOTONIC. This function has a * zero syscall implementation of that on modern x86. * + * nowl l: 45𝑐 15𝑛𝑠 + * rdtsc l: 13𝑐 4𝑛𝑠 + * gettimeofday l: 44𝑐 14𝑛𝑠 + * clock_gettime l: 40𝑐 13𝑛𝑠 + * __clock_gettime l: 35𝑐 11𝑛𝑠 + * sys_clock_gettime l: 220𝑐 71𝑛𝑠 + * * @param clockid can be CLOCK_REALTIME, CLOCK_MONOTONIC, etc. * @param ts is where the result is stored * @return 0 on success, or -1 w/ errno @@ -46,54 +56,49 @@ static typeof(sys_clock_gettime) *__clock_gettime = sys_clock_gettime; * @asyncsignalsafe */ noinstrument int clock_gettime(int clockid, struct timespec *ts) { - int rc, e; - axdx_t ad; - char buf[45]; - if (!ts) { + int rc; + char *buf; + if (IsAsan() && !__asan_is_valid_timespec(ts)) { rc = efault(); - } else if (IsAsan() && !__asan_is_valid(ts, sizeof(*ts))) { - rc = efault(); - } else if (clockid == -1) { - rc = einval(); - } else if (!IsWindows()) { - e = errno; - if ((rc = __clock_gettime(clockid, ts))) { - errno = e; - ad = sys_gettimeofday((struct timeval *)ts, NULL, NULL); - assert(ad.ax != -1); - if (SupportsXnu() && ad.ax) { - ts->tv_sec = ad.ax; - ts->tv_nsec = ad.dx; - } - ts->tv_nsec *= 1000; - rc = 0; - } } else { - rc = sys_clock_gettime_nt(clockid, ts); + rc = __clock_gettime(clockid, ts); } +#if SYSDEBUG if (!__time_critical) { + buf = alloca(45); STRACE("clock_gettime(%d, [%s]) → %d% m", clockid, - DescribeTimespec(buf, sizeof(buf), rc, ts), rc); + DescribeTimespec(buf, 45, rc, ts), rc); } +#endif return rc; } /** - * Returns fast system clock_gettime() if it exists. + * Returns pointer to fastest clock_gettime(). */ -void *__get_clock_gettime(void) { - void *vdso; - static bool once; - static void *result; - if (!once) { - if ((vdso = __vdsofunc("__vdso_clock_gettime"))) { - __clock_gettime = result = vdso; - } - once = true; +clock_gettime_f *__get_clock_gettime(bool *opt_out_isfast) { + bool isfast; + clock_gettime_f *res; + if (IsLinux() && (res = __vdsosym("LINUX_2.6", "__vdso_clock_gettime"))) { + isfast = true; + } else if (IsXnu()) { + isfast = false; + res = sys_clock_gettime_xnu; + } else if (IsWindows()) { + isfast = true; + res = sys_clock_gettime_nt; + } else { + isfast = false; + res = sys_clock_gettime; } - return result; + if (opt_out_isfast) { + *opt_out_isfast = isfast; + } + return res; } -const void *const __clock_gettime_ctor[] initarray = { - __get_clock_gettime, -}; +hidden int __clock_gettime_init(int clockid, struct timespec *ts) { + clock_gettime_f *gettime; + __clock_gettime = gettime = __get_clock_gettime(0); + return gettime(clockid, ts); +} diff --git a/libc/calls/clock_gettime.h b/libc/calls/clock_gettime.h new file mode 100644 index 000000000..0fa6758a6 --- /dev/null +++ b/libc/calls/clock_gettime.h @@ -0,0 +1,15 @@ +#ifndef COSMOPOLITAN_LIBC_CALLS_CLOCK_GETTIME_H_ +#define COSMOPOLITAN_LIBC_CALLS_CLOCK_GETTIME_H_ +#include "libc/calls/struct/timespec.h" +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +typedef int clock_gettime_f(int, struct timespec *); + +extern clock_gettime_f *__clock_gettime; +hidden clock_gettime_f __clock_gettime_init; +hidden clock_gettime_f *__get_clock_gettime(bool *); + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_CALLS_CLOCK_GETTIME_H_ */ diff --git a/libc/calls/gettimeofday.c b/libc/calls/gettimeofday.c index 5698a2370..5b129ec60 100644 --- a/libc/calls/gettimeofday.c +++ b/libc/calls/gettimeofday.c @@ -59,7 +59,7 @@ int gettimeofday(struct timeval *tv, struct timezone *tz) { static textstartup void __gettimeofday_init(void) { void *vdso; - if ((vdso = __vdsofunc("__vdso_gettimeofday"))) { + if ((vdso = __vdsosym("LINUX_2.6", "__vdso_gettimeofday"))) { __gettimeofday = vdso; } } diff --git a/libc/calls/internal.h b/libc/calls/internal.h index 482ff1476..84d6cb098 100644 --- a/libc/calls/internal.h +++ b/libc/calls/internal.h @@ -118,6 +118,7 @@ i32 __sys_sigprocmask(i32, const sigset *, sigset *, u64) hidden; i32 __sys_utimensat(i32, const char *, const struct timespec *, i32) hidden; i32 __sys_wait4(i32, i32 *, i32, struct rusage *) hidden; i32 sys_clock_gettime(i32, struct timespec *) hidden; +i32 sys_clock_gettime_xnu(i32, struct timespec *) hidden; i32 sys_fstat(i32, struct stat *) hidden; i32 sys_fstatat(i32, const char *, struct stat *, i32) hidden; i32 sys_futimes(i32, const struct timeval *) hidden; diff --git a/libc/calls/mman.greg.c b/libc/calls/mman.greg.c index 89df1691a..fa0623e50 100644 --- a/libc/calls/mman.greg.c +++ b/libc/calls/mman.greg.c @@ -83,7 +83,7 @@ noasan textreal uint64_t *__get_virtual(struct mman *mm, uint64_t *t, /** * Sorts, rounds, and filters BIOS memory map. */ -static noasan texthead void __normalize_e820(struct mman *mm) { +static noasan textreal void __normalize_e820(struct mman *mm) { uint64_t a, b; uint64_t x, y; unsigned i, j, n; @@ -113,7 +113,7 @@ static noasan texthead void __normalize_e820(struct mman *mm) { /** * Identity maps all usable physical memory to its negative address. */ -static noasan texthead void __invert_memory(struct mman *mm, uint64_t *pml4t) { +static noasan textreal void __invert_memory(struct mman *mm, uint64_t *pml4t) { uint64_t i, j, *m, p, pe; for (i = 0; i < mm->e820n; ++i) { for (p = mm->e820[i].addr, pe = mm->e820[i].addr + mm->e820[i].size; @@ -126,7 +126,7 @@ static noasan texthead void __invert_memory(struct mman *mm, uint64_t *pml4t) { } } -noasan texthead void __setup_mman(struct mman *mm, uint64_t *pml4t) { +noasan textreal void __setup_mman(struct mman *mm, uint64_t *pml4t) { __normalize_e820(mm); __invert_memory(mm, pml4t); } diff --git a/libc/calls/nanosleep.c b/libc/calls/nanosleep.c index da5f71860..4f0e6edc3 100644 --- a/libc/calls/nanosleep.c +++ b/libc/calls/nanosleep.c @@ -16,6 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/asan.internal.h" #include "libc/calls/calls.h" #include "libc/calls/internal.h" #include "libc/calls/state.internal.h" @@ -31,7 +32,8 @@ noinstrument int nanosleep(const struct timespec *req, struct timespec *rem) { int rc; char buf[2][45]; - if (!req) { + if (!req || (IsAsan() && (!__asan_is_valid_timespec(req) || + (rem && !__asan_is_valid_timespec(rem))))) { rc = efault(); } else if (req->tv_sec < 0 || !(0 <= req->tv_nsec && req->tv_nsec <= 999999999)) { diff --git a/libc/calls/now.c b/libc/calls/now.c index 3db0d9625..83012eba4 100644 --- a/libc/calls/now.c +++ b/libc/calls/now.c @@ -20,6 +20,7 @@ #include "libc/bits/initializer.internal.h" #include "libc/bits/safemacros.internal.h" #include "libc/calls/calls.h" +#include "libc/calls/clock_gettime.h" #include "libc/calls/internal.h" #include "libc/calls/state.internal.h" #include "libc/calls/strace.internal.h" @@ -32,10 +33,11 @@ #include "libc/sysv/consts/clock.h" #include "libc/time/time.h" +static clock_gettime_f *__gettime; + static struct Now { uint64_t k0; long double r0, cpn; - typeof(sys_clock_gettime) *clock_gettime; } g_now; static long double GetTimeSample(void) { @@ -90,7 +92,7 @@ static long double nowl_art(void) { static long double nowl_vdso(void) { long double secs; struct timespec tv; - g_now.clock_gettime(CLOCK_REALTIME, &tv); + __gettime(CLOCK_REALTIME, &tv); secs = tv.tv_nsec; secs *= 1 / 1e9L; secs += tv.tv_sec; @@ -98,9 +100,10 @@ static long double nowl_vdso(void) { } long double nowl_setup(void) { + bool isfast; uint64_t ticks; - if (0 && (g_now.clock_gettime = __get_clock_gettime())) { - // TODO(jart): Re-enable this. + __gettime = __get_clock_gettime(&isfast); + if (isfast) { nowl = nowl_vdso; } else if (X86_HAVE(INVTSC)) { RefreshTime(); diff --git a/libc/calls/openpty.c b/libc/calls/openpty.c index 2e1b282ab..080d6ef8c 100644 --- a/libc/calls/openpty.c +++ b/libc/calls/openpty.c @@ -17,33 +17,44 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" +#include "libc/calls/ioctl.h" #include "libc/calls/termios.h" +#include "libc/fmt/itoa.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/pty.h" +#include "libc/sysv/consts/termios.h" #include "libc/sysv/errfuns.h" /** * Opens new pseudo teletypewriter. * - * @param ilduce receives controlling tty rw fd on success - * @param aworker receives subordinate tty rw fd on success - * @param termp may be passed to tune a century of legacy behaviors - * @param winp may be passed to set terminal display dimensions + * @param mfd receives controlling tty rw fd on success + * @param sfd receives subordinate tty rw fd on success + * @param tio may be passed to tune a century of legacy behaviors + * @param wsz may be passed to set terminal display dimensions * @params flags is usually O_RDWR|O_NOCTTY - * @return file descriptor, or -1 w/ errno + * @return 0 on success, or -1 w/ errno */ -int openpty(int *ilduce, int *aworker, char *name, const struct termios *termp, - const struct winsize *winp) { - return enosys(); - /* TODO(jart) */ - /* int fd, flags; */ - /* flags = O_RDWR | O_NOCTTY; */ - /* if ((fd = posix_openpt(flags)) != -1) { */ - /* if (ioctl(m, TIOCSPTLCK, &n) || ioctl(m, TIOCGPTN, &n)) { */ - /* } else { */ - /* close(fd); */ - /* } */ - /* } else { */ - /* return -1; */ - /* } */ +int openpty(int *mfd, int *sfd, char *name, const struct termios *tio, + const struct winsize *wsz) { + int m, s, n; + char buf[20]; + if ((m = open("/dev/ptmx", O_RDWR | O_NOCTTY)) != -1) { + n = 0; + if (!ioctl(m, TIOCSPTLCK, &n) || !ioctl(m, TIOCGPTN, &n)) { + if (!name) name = buf; + name[0] = '/', name[1] = 'd', name[2] = 'e', name[3] = 'v'; + name[4] = '/', name[5] = 'p', name[6] = 't', name[7] = 's'; + name[8] = '/', FormatInt32(name + 9, n); + if ((s = open(name, O_RDWR | O_NOCTTY)) != -1) { + if (tio) ioctl(s, TCSETS, tio); + if (wsz) ioctl(s, TIOCSWINSZ, wsz); + *mfd = m; + *sfd = s; + return 0; + } + } + close(m); + } + return -1; } diff --git a/libc/calls/syscall_support-sysv.internal.h b/libc/calls/syscall_support-sysv.internal.h index f39cf80bd..3312ca2b3 100644 --- a/libc/calls/syscall_support-sysv.internal.h +++ b/libc/calls/syscall_support-sysv.internal.h @@ -12,8 +12,7 @@ int __notziposat(int, const char *); int gethostname_bsd(char *, size_t) hidden; int gethostname_linux(char *, size_t) hidden; int gethostname_nt(char *, size_t, int) hidden; -void *__get_clock_gettime(void) hidden; -void *__vdsofunc(const char *) hidden; +void *__vdsosym(const char *, const char *) hidden; void __onfork(void) hidden; void __restore_rt() hidden; void __restore_rt_netbsd(void) hidden; diff --git a/libc/calls/utimensat.c b/libc/calls/utimensat.c index d4efa6aa2..c72ec739a 100644 --- a/libc/calls/utimensat.c +++ b/libc/calls/utimensat.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/weaken.h" +#include "libc/calls/asan.internal.h" #include "libc/calls/calls.h" #include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" @@ -39,7 +40,8 @@ int utimensat(int dirfd, const char *path, const struct timespec ts[2], int rc; char buf[12]; if (IsAsan() && (!__asan_is_valid(path, 1) || - (ts && !__asan_is_valid(ts, sizeof(struct timespec) * 2)))) { + (ts && (!__asan_is_valid_timespec(ts + 0) || + !__asan_is_valid_timespec(ts + 1))))) { rc = efault(); } else if (weaken(__zipos_notat) && (rc = __zipos_notat(dirfd, path)) == -1) { STRACE("zipos mkdirat not supported yet"); diff --git a/libc/calls/vdsofunc.greg.c b/libc/calls/vdsofunc.greg.c index 9e1e1fa40..b54fd40e8 100644 --- a/libc/calls/vdsofunc.greg.c +++ b/libc/calls/vdsofunc.greg.c @@ -18,76 +18,136 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/bits.h" #include "libc/calls/calls.h" +#include "libc/calls/strace.internal.h" #include "libc/elf/scalar.h" #include "libc/elf/struct/ehdr.h" +#include "libc/elf/struct/phdr.h" #include "libc/elf/struct/shdr.h" #include "libc/elf/struct/sym.h" -#include "libc/log/libfatal.internal.h" +#include "libc/elf/struct/verdaux.h" +#include "libc/elf/struct/verdef.h" +#include "libc/intrin/kprintf.h" #include "libc/runtime/runtime.h" #include "libc/sysv/consts/auxv.h" -#define LAZY_RHEL7_RELOCATION 0xfffff - -#define GetStr(tab, rva) ((char *)(tab) + (rva)) -#define GetSection(e, s) ((void *)((intptr_t)(e) + (size_t)(s)->sh_offset)) -#define GetShstrtab(e) GetSection(e, GetShdr(e, (e)->e_shstrndx)) -#define GetSectionName(e, s) GetStr(GetShstrtab(e), (s)->sh_name) -#define GetPhdr(e, i) \ - ((Elf64_Phdr *)((intptr_t)(e) + (e)->e_phoff + \ - (size_t)(e)->e_phentsize * (i))) -#define GetShdr(e, i) \ - ((Elf64_Shdr *)((intptr_t)(e) + (e)->e_shoff + \ - (size_t)(e)->e_shentsize * (i))) - -static char *GetDynamicStringTable(Elf64_Ehdr *e, size_t *n) { - char *name; - Elf64_Half i; - Elf64_Shdr *shdr; - for (i = 0; i < e->e_shnum; ++i) { - shdr = GetShdr(e, i); - name = GetSectionName(e, GetShdr(e, i)); - if (shdr->sh_type == SHT_STRTAB) { - name = GetSectionName(e, GetShdr(e, i)); - if (name && READ64LE(name) == READ64LE(".dynstr")) { - if (n) *n = shdr->sh_size; - return GetSection(e, shdr); - } - } - } - return 0; +static inline int CompareStrings(const char *l, const char *r) { + size_t i = 0; + while (l[i] == r[i] && r[i]) ++i; + return (l[i] & 255) - (r[i] & 255); } -static Elf64_Sym *GetDynamicSymbolTable(Elf64_Ehdr *e, Elf64_Xword *n) { - Elf64_Half i; - Elf64_Shdr *shdr; - for (i = e->e_shnum; i > 0; --i) { - shdr = GetShdr(e, i - 1); - if (shdr->sh_type == SHT_DYNSYM) { - if (shdr->sh_entsize != sizeof(Elf64_Sym)) continue; - if (n) *n = shdr->sh_size / shdr->sh_entsize; - return GetSection(e, shdr); +static inline int CheckDsoSymbolVersion(Elf64_Verdef *vd, int sym, + const char *name, char *strtab) { + Elf64_Verdaux *aux; + for (;; vd = (Elf64_Verdef *)((char *)vd + vd->vd_next)) { + if (!(vd->vd_flags & VER_FLG_BASE) && + (vd->vd_ndx & 0x7fff) == (sym & 0x7fff)) { + aux = (Elf64_Verdaux *)((char *)vd + vd->vd_aux); + return !CompareStrings(name, strtab + aux->vda_name); + } + if (!vd->vd_next) { + return 0; } } - return 0; } /** - * Returns Linux Kernel Virtual Dynamic Shared Object function address. + * Returns address of vDSO function. */ -void *__vdsofunc(const char *name) { - size_t m; - char *names; +void *__vdsosym(const char *version, const char *name) { + void *p; + size_t i; Elf64_Ehdr *ehdr; - Elf64_Xword i, n; - Elf64_Sym *symtab, *sym; - if ((ehdr = (Elf64_Ehdr *)getauxval(AT_SYSINFO_EHDR)) && - (names = GetDynamicStringTable(ehdr, &m)) && - (symtab = GetDynamicSymbolTable(ehdr, &n))) { - for (i = 0; i < n; ++i) { - if (!__strcmp(names + symtab[i].st_name, name)) { - return (char *)ehdr + (symtab[i].st_value & LAZY_RHEL7_RELOCATION); - } + Elf64_Phdr *phdr; + char *strtab = 0; + size_t *dyn, base; + unsigned long *ap; + Elf64_Sym *symtab = 0; + uint16_t *versym = 0; + Elf_Symndx *hashtab = 0; + Elf64_Verdef *verdef = 0; + + for (ehdr = 0, ap = __auxv; ap[0]; ap += 2) { + if (ap[0] == AT_SYSINFO_EHDR) { + ehdr = (void *)ap[1]; + break; } } + if (!ehdr || READ32LE(ehdr->e_ident) != READ32LE("\177ELF")) { + KERNTRACE("__vdsosym() → AT_SYSINFO_EHDR ELF not found"); + return 0; + } + + phdr = (void *)((char *)ehdr + ehdr->e_phoff); + for (base = -1, dyn = 0, i = 0; i < ehdr->e_phnum; + i++, phdr = (void *)((char *)phdr + ehdr->e_phentsize)) { + switch (phdr->p_type) { + case PT_LOAD: + // modern linux uses the base address zero, but elders + // e.g. rhel7 uses the base address 0xffffffffff700000 + base = (size_t)ehdr + phdr->p_offset - phdr->p_vaddr; + break; + case PT_DYNAMIC: + dyn = (void *)((char *)ehdr + phdr->p_offset); + break; + default: + break; + } + } + if (!dyn || base == -1) { + KERNTRACE("__vdsosym() → missing program headers"); + return 0; + } + + for (i = 0; dyn[i]; i += 2) { + p = (void *)(base + dyn[i + 1]); + switch (dyn[i]) { + case DT_STRTAB: + strtab = p; + break; + case DT_SYMTAB: + symtab = p; + break; + case DT_HASH: + hashtab = p; + break; + case DT_VERSYM: + versym = p; + break; + case DT_VERDEF: + verdef = p; + break; + } + } + if (!strtab || !symtab || !hashtab) { + KERNTRACE("__vdsosym() → tables not found"); + return 0; + } + if (!verdef) { + versym = 0; + } + + for (i = 0; i < hashtab[1]; i++) { + if (ELF64_ST_TYPE(symtab[i].st_info) != STT_FUNC && + ELF64_ST_TYPE(symtab[i].st_info) != STT_OBJECT && + ELF64_ST_TYPE(symtab[i].st_info) != STT_NOTYPE) { + continue; + } + if (ELF64_ST_BIND(symtab[i].st_info) != STB_GLOBAL) { + continue; + } + if (!symtab[i].st_shndx) { + continue; + } + if (CompareStrings(name, strtab + symtab[i].st_name)) { + continue; + } + if (versym && !CheckDsoSymbolVersion(verdef, versym[i], version, strtab)) { + continue; + } + return (void *)(base + symtab[i].st_value); + } + + KERNTRACE("__vdsosym() → symbol not found"); return 0; } diff --git a/libc/elf/checkelfaddress.c b/libc/elf/checkelfaddress.c index d42221a46..12e38520c 100644 --- a/libc/elf/checkelfaddress.c +++ b/libc/elf/checkelfaddress.c @@ -17,12 +17,16 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/elf/elf.h" +#include "libc/intrin/kprintf.h" #include "libc/runtime/runtime.h" void CheckElfAddress(const Elf64_Ehdr *elf, size_t mapsize, intptr_t addr, size_t addrsize) { #if !(TRUSTWORTHY + ELF_TRUSTWORTHY + 0) || ELF_UNTRUSTWORTHY + 0 if (addr < (intptr_t)elf || addr + addrsize > (intptr_t)elf + mapsize) { + /* kprintf("%p-%p falls outside interval %p-%p", // */ + /* addr, addr + addrsize, // */ + /* elf, (char *)elf + mapsize); // */ abort(); } #endif diff --git a/libc/elf/scalar.h b/libc/elf/scalar.h index d7e4c7ad3..93919c8b8 100644 --- a/libc/elf/scalar.h +++ b/libc/elf/scalar.h @@ -2,15 +2,16 @@ #define COSMOPOLITAN_LIBC_ELF_SCALAR_H_ #if !(__ASSEMBLER__ + __LINKER__ + 0) -#define Elf64_Half uint16_t -#define Elf64_Word uint32_t -#define Elf64_Sword int32_t -#define Elf64_Xword uint64_t -#define Elf64_Sxword int64_t -#define Elf64_Addr uint64_t -#define Elf64_Off uint64_t +#define Elf64_Addr uint64_t +#define Elf64_Half uint16_t +#define Elf64_Off uint64_t #define Elf64_Section uint16_t -#define Elf64_Versym Elf64_Half +#define Elf64_Sword int32_t +#define Elf64_Sxword int64_t +#define Elf64_Versym Elf64_Half +#define Elf64_Word uint32_t +#define Elf64_Xword uint64_t +#define Elf_Symndx uint32_t #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* COSMOPOLITAN_LIBC_ELF_SCALAR_H_ */ diff --git a/libc/sysv/consts.sh b/libc/sysv/consts.sh index c2bab986f..9edf6a7bb 100755 --- a/libc/sysv/consts.sh +++ b/libc/sysv/consts.sh @@ -1323,7 +1323,6 @@ syscon termios TIOCSETD 0x5423 0x8004741b 0x8004741b 0x8004741b 0x800474 syscon termios TIOCSIG 0x40045436 0x2000745f 0x2004745f 0x8004745f 0x8004745f 0 # boop syscon termios TIOCSPGRP 0x5410 0x80047476 0x80047476 0x80047476 0x80047476 0 # boop syscon termios TIOCSTI 0x5412 0x80017472 0x80017472 0 0 0 # boop -syscon termios TIOCGPTN 0x80045430 0 0x4004740f 0 0 0 # boop syscon termios TIOCGSID 0x5429 0x40047463 0x40047463 0x40047463 0x40047463 0 # boop syscon termios TABLDISC 0 0x3 0 0x3 0x3 0 # boop syscon termios SLIPDISC 0 0x4 0x4 0x4 0x4 0 # boop @@ -1508,6 +1507,8 @@ syscon termios CSTOP 19 19 19 19 19 0 # unix consensus # Pseudoteletypewriter Control # # group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary +syscon pty TIOCGPTN 0x80045430 0 0x4004740f 0 0 0 # boop +syscon pty TIOCSPTLCK 0x40045431 0 0 0 0 0 # boop syscon pty TIOCPKT 0x5420 0x80047470 0x80047470 0x80047470 0x80047470 -1 # boop syscon pty TIOCPKT_DATA 0 0 0 0 0 0 # consensus syscon pty TIOCPKT_FLUSHREAD 1 1 1 1 1 1 # unix consensus @@ -1517,7 +1518,6 @@ syscon pty TIOCPKT_START 8 8 8 8 8 8 # unix consensus syscon pty TIOCPKT_NOSTOP 16 16 16 16 16 16 # unix consensus syscon pty TIOCPKT_DOSTOP 32 32 32 32 32 32 # unix consensus syscon pty TIOCPKT_IOCTL 64 64 64 64 64 64 # unix consensus -syscon pty TIOCSPTLCK 0x40045431 0 0 0 0 -1 # boop syscon pty PTMGET 0 0 0 0x40287401 0x40287401 -1 # for /dev/ptm # Modem Control diff --git a/libc/sysv/errfuns.h b/libc/sysv/errfuns.h index 5a0fc56e9..efdc02c37 100644 --- a/libc/sysv/errfuns.h +++ b/libc/sysv/errfuns.h @@ -154,11 +154,14 @@ intptr_t erfkill(void) relegated; intptr_t ehwpoison(void) relegated; #if defined(__MNO_RED_ZONE__) && defined(__GNUC__) && !defined(__STRICT_ANSI__) -#define __ERRFUN(FUNC) \ - ({ \ - intptr_t NegOne; \ - asm("call\t" FUNC : "=a"(NegOne), "=m"(errno)); \ - NegOne; \ +#define __ERRFUN(FUNC) \ + ({ \ + intptr_t NegOne; \ + asm volatile("call\t" FUNC \ + : "=a"(NegOne) \ + : /* no outputs */ \ + : "rcx", "memory"); \ + NegOne; \ }) #define einval() __ERRFUN("einval") #define eperm() __ERRFUN("eperm") diff --git a/test/libc/calls/clock_gettime_test.c b/test/libc/calls/clock_gettime_test.c index e67d61473..ce54e88de 100644 --- a/test/libc/calls/clock_gettime_test.c +++ b/test/libc/calls/clock_gettime_test.c @@ -16,14 +16,40 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/calls.h" +#include "libc/calls/clock_gettime.h" +#include "libc/calls/internal.h" #include "libc/calls/struct/timespec.h" -#include "libc/sysv/consts/clock.h" +#include "libc/calls/struct/timeval.h" +#include "libc/calls/syscall_support-sysv.internal.h" +#include "libc/nexgen32e/rdtsc.h" +#include "libc/runtime/runtime.h" +#include "libc/sysv/consts/auxv.h" #include "libc/testlib/ezbench.h" #include "libc/testlib/testlib.h" +#include "libc/time/time.h" + +TEST(clock_gettime, test) { + bool isfast; + struct timespec ts = {0}; + ASSERT_EQ(0, clock_gettime(0, &ts)); + ASSERT_NE(0, ts.tv_sec); + ASSERT_NE(0, ts.tv_nsec); + if (__is_linux_2_6_23()) { + ASSERT_GT((intptr_t)__get_clock_gettime(&isfast), + getauxval(AT_SYSINFO_EHDR)); + ASSERT_TRUE(isfast); + } +} BENCH(clock_gettime, bench) { + struct timeval tv; struct timespec ts; + gettimeofday(&tv, 0); // trigger init + clock_gettime(0, &ts); // trigger init EZBENCH2("nowl", donothing, nowl()); - EZBENCH2("clock_gettime", donothing, clock_gettime(CLOCK_REALTIME, &ts)); + EZBENCH2("rdtsc", donothing, rdtsc()); + EZBENCH2("gettimeofday", donothing, gettimeofday(&tv, 0)); + EZBENCH2("clock_gettime", donothing, clock_gettime(0, &ts)); + EZBENCH2("__clock_gettime", donothing, __clock_gettime(0, &ts)); + EZBENCH2("sys_clock_gettime", donothing, sys_clock_gettime(0, &ts)); } diff --git a/test/libc/runtime/ape_test.c b/test/libc/runtime/ape_test.c index fb140b008..6a765435a 100644 --- a/test/libc/runtime/ape_test.c +++ b/test/libc/runtime/ape_test.c @@ -20,6 +20,7 @@ #include "libc/calls/sigbits.h" #include "libc/calls/struct/sigaction.h" #include "libc/errno.h" +#include "libc/intrin/kprintf.h" #include "libc/mem/io.h" #include "libc/runtime/runtime.h" #include "libc/sysv/consts/o.h" diff --git a/third_party/bzip2/bzip2.mk b/third_party/bzip2/bzip2.mk index c387dfd95..cc5e8a3ba 100644 --- a/third_party/bzip2/bzip2.mk +++ b/third_party/bzip2/bzip2.mk @@ -51,7 +51,7 @@ o/$(MODE)/third_party/bzip2/bzip2.com.dbg: \ o/$(MODE)/third_party/bzip2/bzip2.o \ o/$(MODE)/third_party/bzip2/bzip2.a.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/bzip2/bzip2recover.com.dbg: \ @@ -59,7 +59,7 @@ o/$(MODE)/third_party/bzip2/bzip2recover.com.dbg: \ o/$(MODE)/third_party/bzip2/bzip2recover.o \ o/$(MODE)/third_party/bzip2/bzip2.a.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) $(THIRD_PARTY_BZIP2_A_OBJS): \ diff --git a/third_party/lua/lua.mk b/third_party/lua/lua.mk index 2005072d1..9a42729dc 100644 --- a/third_party/lua/lua.mk +++ b/third_party/lua/lua.mk @@ -59,7 +59,7 @@ o/$(MODE)/third_party/lua/lua.com.dbg: \ $(THIRD_PARTY_LUA_A).pkg \ o/$(MODE)/third_party/lua/lua.main.o \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/lua/luac.com.dbg: \ @@ -68,7 +68,7 @@ o/$(MODE)/third_party/lua/luac.com.dbg: \ $(THIRD_PARTY_LUA_A).pkg \ o/$(MODE)/third_party/lua/luac.main.o \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/lua/lua.com: \ diff --git a/third_party/lz4cli/lz4cli.mk b/third_party/lz4cli/lz4cli.mk index 568db66c6..2c1b93d19 100644 --- a/third_party/lz4cli/lz4cli.mk +++ b/third_party/lz4cli/lz4cli.mk @@ -56,7 +56,7 @@ o/$(MODE)/third_party/lz4cli/lz4cli.com.dbg: \ $(THIRD_PARTY_LZ4CLI_DEPS) \ $(THIRD_PARTY_LZ4CLI_OBJS) \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) $(THIRD_PARTY_LZ4CLI_OBJS): \ diff --git a/third_party/mbedtls/ecp.c b/third_party/mbedtls/ecp.c index c60d6fc64..fc269bd5e 100644 --- a/third_party/mbedtls/ecp.c +++ b/third_party/mbedtls/ecp.c @@ -512,6 +512,7 @@ int mbedtls_ecp_check_budget( const mbedtls_ecp_group *grp, * SECP384R1 192 IANA, NIST, FRANCE, GERMANY, NSA * X25519 112-128 IANA * X448 224 IANA + * SECP256K1 128 BITCOIN * BP384R1 GERMANY * SECP521R1 FRANCE * GC512A RUSSIA diff --git a/third_party/quickjs/quickjs.mk b/third_party/quickjs/quickjs.mk index 83c5749aa..72c17d6b4 100644 --- a/third_party/quickjs/quickjs.mk +++ b/third_party/quickjs/quickjs.mk @@ -145,7 +145,7 @@ o/$(MODE)/third_party/quickjs/qjs.com.dbg: \ o/$(MODE)/third_party/quickjs/repl.o \ o/$(MODE)/third_party/quickjs/qjscalc.o \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/quickjs/qjs.com: \ diff --git a/tool/decode/elf.c b/tool/decode/elf.c index 4a6a4b6e3..82262c124 100644 --- a/tool/decode/elf.c +++ b/tool/decode/elf.c @@ -157,7 +157,8 @@ static void printelfsectionheader(int i, char *shstrtab) { static void printelfsectionheaders(void) { Elf64_Half i; - char *shstrtab = GetElfSectionNameStringTable(elf, st->st_size); + char *shstrtab; + shstrtab = GetElfSectionNameStringTable(elf, st->st_size); if (shstrtab) { printf("\n"); printf("\t.org\t%#x\n", elf->e_shoff); @@ -341,7 +342,6 @@ int main(int argc, char *argv[]) { fprintf(stderr, "error: not an elf executable: %'s\n", path); exit(1); } - elf = (Elf64_Ehdr *)getauxval(AT_SYSINFO_EHDR); startfile(); printelfehdr(); printelfsegmentheaders(); diff --git a/tool/viz/vdsosyms.c b/tool/viz/vdsosyms.c new file mode 100644 index 000000000..39fecbfd2 --- /dev/null +++ b/tool/viz/vdsosyms.c @@ -0,0 +1,166 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/strace.internal.h" +#include "libc/elf/def.h" +#include "libc/elf/scalar.h" +#include "libc/elf/struct/ehdr.h" +#include "libc/elf/struct/phdr.h" +#include "libc/elf/struct/sym.h" +#include "libc/elf/struct/verdaux.h" +#include "libc/elf/struct/verdef.h" +#include "libc/intrin/kprintf.h" +#include "libc/runtime/runtime.h" +#include "libc/sysv/consts/auxv.h" + +static inline void PrintDsoSymbolVersions(Elf64_Verdef *vd, int sym, + char *strtab) { + Elf64_Verdaux *aux; + for (;; vd = (Elf64_Verdef *)((char *)vd + vd->vd_next)) { + if (!(vd->vd_flags & VER_FLG_BASE) && + (vd->vd_ndx & 0x7fff) == (sym & 0x7fff)) { + aux = (Elf64_Verdaux *)((char *)vd + vd->vd_aux); + kprintf(" %s", strtab + aux->vda_name); + } + if (!vd->vd_next) { + break; + } + } +} + +int PrintVdsoSymbols(void) { + void *p; + size_t i; + Elf64_Ehdr *ehdr; + Elf64_Phdr *phdr; + char *strtab = 0; + size_t *dyn, base; + unsigned long *ap; + Elf64_Sym *symtab = 0; + uint16_t *versym = 0; + Elf_Symndx *hashtab = 0; + Elf64_Verdef *verdef = 0; + const char *typename, *bindname; + + for (ehdr = 0, ap = __auxv; ap[0]; ap += 2) { + if (ap[0] == AT_SYSINFO_EHDR) { + ehdr = (void *)ap[1]; + break; + } + } + if (!ehdr) { + kprintf("error: AT_SYSINFO_EHDR not found\n"); + return 1; + } + + phdr = (void *)((char *)ehdr + ehdr->e_phoff); + for (base = -1, dyn = 0, i = 0; i < ehdr->e_phnum; + i++, phdr = (void *)((char *)phdr + ehdr->e_phentsize)) { + switch (phdr->p_type) { + case PT_LOAD: + // modern linux uses the base address zero, but elders + // e.g. rhel7 uses the base address 0xffffffffff700000 + base = (size_t)ehdr + phdr->p_offset - phdr->p_vaddr; + break; + case PT_DYNAMIC: + dyn = (void *)((char *)ehdr + phdr->p_offset); + break; + default: + break; + } + } + if (!dyn || base == -1) { + kprintf("error: missing program headers\n"); + return 2; + } + + for (i = 0; dyn[i]; i += 2) { + p = (void *)(base + dyn[i + 1]); + switch (dyn[i]) { + case DT_STRTAB: + strtab = p; + break; + case DT_SYMTAB: + symtab = p; + break; + case DT_HASH: + hashtab = p; + break; + case DT_VERSYM: + versym = p; + break; + case DT_VERDEF: + verdef = p; + break; + } + } + if (!verdef) { + versym = 0; + } + + if (!strtab || !symtab || !hashtab) { + kprintf("error: strtab/symtab/hashtab not found\n"); + return 3; + } + + for (i = 0; i < hashtab[1]; i++) { + if (!symtab[i].st_shndx) { + continue; + } + + switch (ELF64_ST_BIND(symtab[i].st_info)) { + case STB_LOCAL: + bindname = "locl"; + break; + case STB_GLOBAL: + bindname = "glob"; + break; + case STB_WEAK: + bindname = "weak"; + break; + default: + bindname = "????"; + break; + } + + switch (ELF64_ST_TYPE(symtab[i].st_info)) { + case STT_FUNC: + typename = "func"; + break; + case STT_OBJECT: + typename = " obj"; + break; + case STT_NOTYPE: + typename = "none"; + break; + default: + typename = "????"; + break; + } + + kprintf("%s %s %-40s", bindname, typename, strtab + symtab[i].st_name); + PrintDsoSymbolVersions(verdef, versym[i], strtab); + kprintf("\n"); + } + + return 0; +} + +int main(int argc, char *argv[]) { + return PrintVdsoSymbols(); +}