mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +00:00
Make improvements
- Implement openpty() - Add `--assimilate` flag to APE bootloader - Restore Linux vDSO clock_gettime() support - Use `$(APE_NO_MODIFY_SELF)` on more programs
This commit is contained in:
parent
cef50f2a6b
commit
d44ff6ce1f
33 changed files with 600 additions and 251 deletions
50
README.md
50
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
|
||||
<https://justine.lol/cosmopolitan/cosmopolitan-tiny.zip> instead. See
|
||||
<https://justine.lol/cosmopolitan/download.html>.
|
||||
|
||||
### MacOS
|
||||
|
||||
|
|
56
ape/ape.S
56
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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
19
libc/calls/asan.internal.h
Normal file
19
libc/calls/asan.internal.h
Normal file
|
@ -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_ */
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
15
libc/calls/clock_gettime.h
Normal file
15
libc/calls/clock_gettime.h
Normal file
|
@ -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_ */
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
4
third_party/bzip2/bzip2.mk
vendored
4
third_party/bzip2/bzip2.mk
vendored
|
@ -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): \
|
||||
|
|
4
third_party/lua/lua.mk
vendored
4
third_party/lua/lua.mk
vendored
|
@ -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: \
|
||||
|
|
2
third_party/lz4cli/lz4cli.mk
vendored
2
third_party/lz4cli/lz4cli.mk
vendored
|
@ -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): \
|
||||
|
|
1
third_party/mbedtls/ecp.c
vendored
1
third_party/mbedtls/ecp.c
vendored
|
@ -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
|
||||
|
|
2
third_party/quickjs/quickjs.mk
vendored
2
third_party/quickjs/quickjs.mk
vendored
|
@ -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: \
|
||||
|
|
|
@ -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();
|
||||
|
|
166
tool/viz/vdsosyms.c
Normal file
166
tool/viz/vdsosyms.c
Normal file
|
@ -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();
|
||||
}
|
Loading…
Reference in a new issue