mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +00:00
Make improvements
- Polyfill readlink("foo/") dir check on Windows - Support asynchronous signal delivery on Windows - Restore Windows Console from execve() daisy chain - Work around bug in AARCH64 Optimized Routines memcmp() - Disable unbourne.com shell completion on Windows for now - Don't always set virtual terminal input state on console - Remove Musl Libc's unusual preservation of realpath("//") - Make realpath() strongly link malloc() to pass configure test - Delete cosh.com shell, now that unbourne.com works on Windows!
This commit is contained in:
parent
f9c9a323fe
commit
425c055116
40 changed files with 581 additions and 706 deletions
318
examples/cosh.c
318
examples/cosh.c
|
@ -1,318 +0,0 @@
|
|||
#if 0
|
||||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/dirent.h"
|
||||
#include "libc/calls/struct/rusage.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/appendresourcereport.internal.h"
|
||||
#include "libc/log/internal.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/append.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/sysv/consts/dt.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "third_party/linenoise/linenoise.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Cosmopolitan Shell
|
||||
*
|
||||
* This doesn't have script language features like UNBOURNE.COM but it
|
||||
* works on Windows and, unlike CMD.EXE, has CTRL-P, CTRL-R, and other
|
||||
* GNU Emacs / Readline keyboard shortcuts.
|
||||
*
|
||||
* One day we'll have UNBOURNE.COM working on Windows but the code isn't
|
||||
* very maintainable sadly.
|
||||
*/
|
||||
|
||||
volatile int gotint;
|
||||
|
||||
static void OnInterrupt(int sig) {
|
||||
gotint = sig;
|
||||
}
|
||||
|
||||
static void AddUniqueCompletion(linenoiseCompletions *c, char *s) {
|
||||
size_t i;
|
||||
if (!s) return;
|
||||
for (i = 0; i < c->len; ++i) {
|
||||
if (!strcmp(s, c->cvec[i])) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
c->cvec = realloc(c->cvec, ++c->len * sizeof(*c->cvec));
|
||||
c->cvec[c->len - 1] = s;
|
||||
}
|
||||
|
||||
static void CompleteFilename(const char *p, const char *q, const char *b,
|
||||
linenoiseCompletions *c) {
|
||||
DIR *d;
|
||||
char *buf;
|
||||
const char *g;
|
||||
struct dirent *e;
|
||||
if ((buf = malloc(512))) {
|
||||
if ((g = memrchr(p, '/', q - p))) {
|
||||
*(char *)mempcpy(buf, p, MIN(g - p, 511)) = 0;
|
||||
p = ++g;
|
||||
} else {
|
||||
strcpy(buf, ".");
|
||||
}
|
||||
if ((d = opendir(buf))) {
|
||||
while ((e = readdir(d))) {
|
||||
if (!strcmp(e->d_name, ".")) continue;
|
||||
if (!strcmp(e->d_name, "..")) continue;
|
||||
if (!strncmp(e->d_name, p, q - p)) {
|
||||
snprintf(buf, 512, "%.*s%s%s", p - b, b, e->d_name,
|
||||
e->d_type == DT_DIR ? "/" : "");
|
||||
AddUniqueCompletion(c, strdup(buf));
|
||||
}
|
||||
}
|
||||
closedir(d);
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
}
|
||||
|
||||
static void ShellCompletion(const char *p, linenoiseCompletions *c) {
|
||||
const char *q, *b;
|
||||
for (b = p, q = (p += strlen(p)); p > b; --p) {
|
||||
if (!isalnum(p[-1]) &&
|
||||
(p[-1] != '.' && p[-1] != '_' && p[-1] != '-' && p[-1] != '+' &&
|
||||
p[-1] != '[' && p[-1] != '/' && p[-1] != '\\')) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
CompleteFilename(p, q, b, c);
|
||||
}
|
||||
|
||||
static char *ShellHint(const char *p, const char **ansi1, const char **ansi2) {
|
||||
char *h = 0;
|
||||
linenoiseCompletions c = {0};
|
||||
ShellCompletion(p, &c);
|
||||
if (c.len == 1) {
|
||||
h = strdup(c.cvec[0] + strlen(p));
|
||||
}
|
||||
linenoiseFreeCompletions(&c);
|
||||
return h;
|
||||
}
|
||||
|
||||
static char *MakePrompt(char *p) {
|
||||
char *s, buf[256];
|
||||
if (!gethostname(buf, sizeof(buf))) {
|
||||
p = stpcpy(p, "\e[95m");
|
||||
if ((s = getenv("USER"))) {
|
||||
p = stpcpy(p, s);
|
||||
*p++ = '@';
|
||||
}
|
||||
p = stpcpy(p, buf);
|
||||
*p++ = ':';
|
||||
}
|
||||
p = stpcpy(p, "\e[96m");
|
||||
if ((s = getcwd(buf, sizeof(buf)))) {
|
||||
p = stpcpy(p, s);
|
||||
}
|
||||
return stpcpy(p, "\e[0m>: ");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
bool timeit;
|
||||
int64_t nanos;
|
||||
struct rusage ru;
|
||||
struct timespec ts1, ts2;
|
||||
char *prog, path[PATH_MAX];
|
||||
sigset_t chldmask, savemask;
|
||||
int stdoutflags, stderrflags;
|
||||
int n, rc, ws, child, killcount;
|
||||
const char *stdoutpath, *stderrpath;
|
||||
struct sigaction sa, saveint, savequit;
|
||||
char *p, *line, **args, *arg, *start, *state, prompt[1024];
|
||||
linenoiseSetFreeHintsCallback(free);
|
||||
linenoiseSetHintsCallback(ShellHint);
|
||||
linenoiseSetCompletionCallback(ShellCompletion);
|
||||
MakePrompt(prompt);
|
||||
while ((line = linenoiseWithHistory(prompt, "cmd"))) {
|
||||
n = 0;
|
||||
start = line;
|
||||
if (_startswith(start, "time ")) {
|
||||
timeit = true;
|
||||
start += 5;
|
||||
} else {
|
||||
timeit = false;
|
||||
}
|
||||
stdoutpath = 0;
|
||||
stderrpath = 0;
|
||||
stdoutflags = 0;
|
||||
stderrflags = 0;
|
||||
args = xcalloc(1, sizeof(*args));
|
||||
while ((arg = strtok_r(start, " \t\r\n", &state))) {
|
||||
// cmd >>stdout.txt
|
||||
if (arg[0] == '>' && arg[1] == '>') {
|
||||
stdoutflags = O_WRONLY | O_APPEND | O_CREAT;
|
||||
stdoutpath = arg + 2;
|
||||
} else if (arg[0] == '>') {
|
||||
// cmd >stdout.txt
|
||||
stdoutflags = O_WRONLY | O_CREAT | O_TRUNC;
|
||||
stdoutpath = arg + 1;
|
||||
} else if (arg[0] == '2' && arg[1] == '>' && arg[2] == '>') {
|
||||
// cmd 2>>stderr.txt
|
||||
stderrflags = O_WRONLY | O_APPEND | O_CREAT;
|
||||
stderrpath = arg + 3;
|
||||
} else if (arg[0] == '2' && arg[1] == '>') {
|
||||
// cmd 2>stderr.txt
|
||||
stderrflags = O_WRONLY | O_CREAT | O_TRUNC;
|
||||
stderrpath = arg + 2;
|
||||
} else {
|
||||
// arg
|
||||
args = xrealloc(args, (++n + 1) * sizeof(*args));
|
||||
args[n - 1] = arg;
|
||||
args[n - 0] = 0;
|
||||
}
|
||||
start = 0;
|
||||
}
|
||||
if (n > 0) {
|
||||
if ((prog = commandv(args[0], path, sizeof(path)))) {
|
||||
|
||||
// let keyboard interrupts kill child and not shell
|
||||
gotint = 0;
|
||||
killcount = 0;
|
||||
sa.sa_flags = 0;
|
||||
sa.sa_handler = SIG_IGN;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sigaction(SIGQUIT, &sa, &savequit);
|
||||
sa.sa_handler = OnInterrupt;
|
||||
sigaction(SIGINT, &sa, &saveint);
|
||||
sigemptyset(&chldmask);
|
||||
sigaddset(&chldmask, SIGCHLD);
|
||||
sigprocmask(SIG_BLOCK, &chldmask, &savemask);
|
||||
|
||||
// record timestamp
|
||||
if (timeit) {
|
||||
clock_gettime(CLOCK_REALTIME, &ts1);
|
||||
}
|
||||
|
||||
// launch process
|
||||
if (!(child = vfork())) {
|
||||
if (stdoutpath) {
|
||||
close(1);
|
||||
open(stdoutpath, stdoutflags, 0644);
|
||||
}
|
||||
if (stderrpath) {
|
||||
close(2);
|
||||
open(stderrpath, stderrflags, 0644);
|
||||
}
|
||||
sigaction(SIGINT, &saveint, 0);
|
||||
sigaction(SIGQUIT, &savequit, 0);
|
||||
sigprocmask(SIG_SETMASK, &savemask, 0);
|
||||
execv(prog, args);
|
||||
_Exit(127);
|
||||
}
|
||||
|
||||
// wait for process
|
||||
for (;;) {
|
||||
if (gotint) {
|
||||
switch (killcount) {
|
||||
case 0:
|
||||
// ctrl-c
|
||||
// we do nothing
|
||||
// terminals broadcast sigint to process group
|
||||
rc = 0;
|
||||
break;
|
||||
case 1:
|
||||
// ctrl-c ctrl-c
|
||||
// we try sending sigterm
|
||||
rc = kill(child, SIGTERM);
|
||||
break;
|
||||
default:
|
||||
// ctrl-c ctrl-c ctrl-c ...
|
||||
// we use kill -9 as our last resort
|
||||
rc = kill(child, SIGKILL);
|
||||
break;
|
||||
}
|
||||
if (rc == -1) {
|
||||
fprintf(stderr, "kill failed: %m\n");
|
||||
exit(1);
|
||||
}
|
||||
++killcount;
|
||||
gotint = 0;
|
||||
}
|
||||
rc = wait4(0, &ws, 0, &ru);
|
||||
if (rc != -1) {
|
||||
break;
|
||||
} else if (errno == EINTR) {
|
||||
errno = 0;
|
||||
} else {
|
||||
fprintf(stderr, "wait failed: %m\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// print resource consumption for `time` pseudocommand
|
||||
if (timeit) {
|
||||
clock_gettime(CLOCK_REALTIME, &ts2);
|
||||
if (ts2.tv_sec == ts1.tv_sec) {
|
||||
nanos = ts2.tv_nsec - ts1.tv_nsec;
|
||||
} else {
|
||||
nanos = (ts2.tv_sec - ts1.tv_sec) * 1000000000LL;
|
||||
nanos += 1000000000LL - ts1.tv_nsec;
|
||||
nanos += ts2.tv_nsec;
|
||||
}
|
||||
printf("took %,ldµs wall time\n", nanos / 1000);
|
||||
p = 0;
|
||||
AppendResourceReport(&p, &ru, "\n");
|
||||
fputs(p, stdout);
|
||||
free(p);
|
||||
}
|
||||
|
||||
// update prompt to reflect exit status
|
||||
p = prompt;
|
||||
if (WIFEXITED(ws)) {
|
||||
if (WEXITSTATUS(ws)) {
|
||||
if (!__nocolor) p = stpcpy(p, "\e[1;31m");
|
||||
p = stpcpy(p, "rc=");
|
||||
p = FormatInt32(p, WEXITSTATUS(ws));
|
||||
if (128 < WEXITSTATUS(ws) && WEXITSTATUS(ws) <= 128 + 32) {
|
||||
*p++ = ' ';
|
||||
p = stpcpy(p, strsignal(WEXITSTATUS(ws) - 128));
|
||||
}
|
||||
if (!__nocolor) p = stpcpy(p, "\e[0m");
|
||||
*p++ = ' ';
|
||||
}
|
||||
} else {
|
||||
if (!__nocolor) p = stpcpy(p, "\e[1;31m");
|
||||
p = stpcpy(p, strsignal(WTERMSIG(ws)));
|
||||
if (!__nocolor) p = stpcpy(p, "\e[0m");
|
||||
*p++ = ' ';
|
||||
}
|
||||
MakePrompt(p);
|
||||
|
||||
sigprocmask(SIG_SETMASK, &savemask, 0);
|
||||
sigaction(SIGINT, &saveint, 0);
|
||||
sigaction(SIGQUIT, &savequit, 0);
|
||||
} else {
|
||||
fprintf(stderr, "%s: %s: command not found\n", argv[0], args[0]);
|
||||
}
|
||||
}
|
||||
free(line);
|
||||
free(args);
|
||||
}
|
||||
}
|
|
@ -10,14 +10,25 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/struct/pollfd.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/limits.h"
|
||||
#include "libc/sysv/consts/poll.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
|
||||
volatile bool gotsig;
|
||||
|
||||
void SignalHandler(int sig) {
|
||||
// we don't need to do anything in our signal handler since the signal
|
||||
// delivery itself causes a visible state change, saying what happened
|
||||
const char *s = "SignalHandler() called\n";
|
||||
write(1, s, strlen(s)); // notice both functions are @asyncsignalsafe
|
||||
// however this will help if delivered asynchronously in cpubound code
|
||||
// it's also necessary to discern spurious interrupts from real signal
|
||||
gotsig = true;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
@ -31,6 +42,16 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
for (;;) {
|
||||
|
||||
// some programs are blocked on cpu rather than i/o
|
||||
// such programs shall rely on asynchronous signals
|
||||
printf("doing cpu task...\n");
|
||||
for (volatile int i = 0; i < INT_MAX / 20; ++i) {
|
||||
if (gotsig) {
|
||||
printf("\rgot ctrl+c asynchronously\n");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
// posix guarantees atomic i/o if you use pipe_buf sized buffers
|
||||
// that way we don't need to worry about things like looping and
|
||||
// we can also be assured that multiple actors wont have tearing
|
||||
|
@ -45,6 +66,7 @@ int main(int argc, char *argv[]) {
|
|||
// it's possible to be more precise if we were building library
|
||||
// code. for example, you can block signals using sigprocmask()
|
||||
// and then use pselect() to do the waiting.
|
||||
printf("doing read i/o task...\n");
|
||||
int got = read(0, buf, sizeof(buf));
|
||||
|
||||
// check if the read operation failed
|
||||
|
@ -59,8 +81,13 @@ int main(int argc, char *argv[]) {
|
|||
// however EINTR is very useful, when we choose to use it
|
||||
// the \r character is needed so when the line is printed
|
||||
// it'll overwrite the ^C that got echo'd with the ctrl-c
|
||||
printf("\rgot ctrl+c\n");
|
||||
if (gotsig) {
|
||||
printf("\rgot ctrl+c via i/o eintr\n");
|
||||
exit(0);
|
||||
} else {
|
||||
printf("\rgot spurious eintr\n");
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// log it in the unlikely event something else went wrong
|
||||
perror("<stdin>");
|
||||
|
|
|
@ -55,7 +55,7 @@ int rawmode(void) {
|
|||
static bool once;
|
||||
struct termios t;
|
||||
if (!once) {
|
||||
if (tcgetattr(1, &oldterm)) {
|
||||
if (!tcgetattr(1, &oldterm)) {
|
||||
atexit(restoretty);
|
||||
} else {
|
||||
perror("tcgetattr");
|
||||
|
|
|
@ -5816,8 +5816,11 @@ static ssize_t preadfd(void) {
|
|||
retry:
|
||||
if (!parsefile->fd && isatty(0)) {
|
||||
linenoiseSetFreeHintsCallback(free);
|
||||
if (!IsWindows()) {
|
||||
// TODO(jart): Cache $PATH search.
|
||||
linenoiseSetHintsCallback(ShellHint);
|
||||
linenoiseSetCompletionCallback(ShellCompletion);
|
||||
}
|
||||
if ((p = linenoiseWithHistory(">: ", "unbourne"))) {
|
||||
nr = min(strlen(p), IBUFSIZ - 2);
|
||||
memcpy(buf, p, nr);
|
||||
|
|
|
@ -73,7 +73,7 @@ typedef int sig_atomic_t;
|
|||
|
||||
bool32 isatty(int);
|
||||
char *getcwd(char *, size_t);
|
||||
char *realpath(const char *, char *);
|
||||
char *realpath(const char *, char *) __wur;
|
||||
char *ttyname(int);
|
||||
int access(const char *, int) dontthrow;
|
||||
int chdir(const char *);
|
||||
|
|
|
@ -65,6 +65,13 @@ $(LIBC_CALLS_A).pkg: \
|
|||
$(LIBC_CALLS_A_OBJS) \
|
||||
$(foreach x,$(LIBC_CALLS_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
# we can't use sanitizers because:
|
||||
# we're on a stack owned by win32 without tls
|
||||
o/$(MODE)/libc/calls/onntconsoleevent.o: private \
|
||||
COPTS += \
|
||||
-ffreestanding \
|
||||
-fno-sanitize=all
|
||||
|
||||
# we can't use asan because:
|
||||
# siginfo_t memory is owned by kernels
|
||||
o/$(MODE)/libc/calls/siginfo2cosmo.o: private \
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/nt/thread.h"
|
||||
#include "libc/nt/thunk/msabi.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/stack.h"
|
||||
|
@ -56,10 +57,10 @@
|
|||
extern long __klog_handle;
|
||||
|
||||
__msabi extern typeof(CloseHandle) *const __imp_CloseHandle;
|
||||
__msabi extern typeof(WaitForSingleObject) *const __imp_WaitForSingleObject;
|
||||
__msabi extern typeof(GetExitCodeProcess) *const __imp_GetExitCodeProcess;
|
||||
__msabi extern typeof(UnmapViewOfFile) *const __imp_UnmapViewOfFile;
|
||||
__msabi extern typeof(TerminateThread) *const __imp_TerminateThread;
|
||||
__msabi extern typeof(UnmapViewOfFile) *const __imp_UnmapViewOfFile;
|
||||
__msabi extern typeof(WaitForSingleObject) *const __imp_WaitForSingleObject;
|
||||
|
||||
wontreturn void __switch_stacks(intptr_t, long, long, long,
|
||||
void (*)(intptr_t, intptr_t, long, long),
|
||||
|
@ -70,10 +71,10 @@ __msabi static keywords bool32 sys_execve_nt_event(uint32_t dwCtrlType) {
|
|||
}
|
||||
|
||||
static keywords void PurgeHandle(intptr_t h) {
|
||||
if (h && h != -1) {
|
||||
if (!h) return;
|
||||
if (h == -1) return;
|
||||
__imp_CloseHandle(h);
|
||||
}
|
||||
}
|
||||
|
||||
static keywords void PurgeThread(intptr_t h) {
|
||||
if (h && h != -1) {
|
||||
|
|
|
@ -17,15 +17,14 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/nt/enum/filetype.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/nt/console.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows bool32 sys_isatty_nt(int fd) {
|
||||
if (__isfdopen(fd)) {
|
||||
if (__isfdkind(fd, kFdConsole) ||
|
||||
(__isfdkind(fd, kFdFile) &&
|
||||
GetFileType(g_fds.p[fd].handle) == kNtFileTypeChar)) {
|
||||
uint32_t mode;
|
||||
if (GetConsoleMode(g_fds.p[fd].handle, &mode)) {
|
||||
return true;
|
||||
} else {
|
||||
enotty();
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/systeminfo.h"
|
||||
|
|
|
@ -17,49 +17,143 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/dll.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/nexgen32e/nt2sysv.h"
|
||||
#include "libc/nt/enum/context.h"
|
||||
#include "libc/nt/enum/ctrlevent.h"
|
||||
#include "libc/nt/enum/threadaccess.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/struct/context.h"
|
||||
#include "libc/nt/thread.h"
|
||||
#include "libc/nt/thunk/msabi.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/sicode.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/thread/posixthread.internal.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/thread/tls.h"
|
||||
#include "libc/thread/tls2.internal.h"
|
||||
|
||||
#ifdef __x86_64__
|
||||
|
||||
textwindows bool32 __onntconsoleevent(uint32_t dwCtrlType) {
|
||||
struct CosmoTib tib;
|
||||
// WIN32 doesn't have the System V red-zone. Microsoft says they reserve
|
||||
// the right to trample all over it. so we technically don't need to use
|
||||
// this value. it's just not clear how common it is for WIN32 to clobber
|
||||
// the red zone, which means broken code could seem to mostly work which
|
||||
// means it's better that we're not the ones responsible for breaking it
|
||||
#define kRedzoneSize 128
|
||||
|
||||
// win32 spawns a thread on its own just to deliver sigint
|
||||
// TODO(jart): make signal code lockless so we can delete!
|
||||
if (__tls_enabled && !__get_tls_win32()) {
|
||||
bzero(&tib, sizeof(tib));
|
||||
tib.tib_self = &tib;
|
||||
tib.tib_self2 = &tib;
|
||||
atomic_store_explicit(&tib.tib_tid, GetCurrentThreadId(),
|
||||
memory_order_relaxed);
|
||||
__set_tls_win32(&tib);
|
||||
// Both Microsoft and the Fifth Bell System agree on this one.
|
||||
#define kStackAlign 16
|
||||
|
||||
__msabi extern typeof(CloseHandle) *const __imp_CloseHandle;
|
||||
__msabi extern typeof(GetLastError) *const __imp_GetLastError;
|
||||
__msabi extern typeof(GetStdHandle) *const __imp_GetStdHandle;
|
||||
__msabi extern typeof(GetThreadContext) *const __imp_GetThreadContext;
|
||||
__msabi extern typeof(OpenThread) *const __imp_OpenThread;
|
||||
__msabi extern typeof(ResumeThread) *const __imp_ResumeThread;
|
||||
__msabi extern typeof(SuspendThread) *const __imp_SuspendThread;
|
||||
__msabi extern typeof(WriteFile) *const __imp_WriteFile;
|
||||
|
||||
int WinThreadLaunch(int, int, int (*)(int, int), intptr_t);
|
||||
|
||||
static unsigned long StrLen(const char *s) {
|
||||
unsigned long n = 0;
|
||||
while (*s++) ++n;
|
||||
return n;
|
||||
}
|
||||
|
||||
STRACE("__onntconsoleevent(%u)", dwCtrlType);
|
||||
static void Log(const char *s) {
|
||||
#ifndef NDEBUG
|
||||
__imp_WriteFile(__imp_GetStdHandle(kNtStdErrorHandle), s, StrLen(s), 0, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int GetSig(uint32_t dwCtrlType) {
|
||||
switch (dwCtrlType) {
|
||||
case kNtCtrlCEvent:
|
||||
__sig_add(0, SIGINT, SI_KERNEL);
|
||||
return true;
|
||||
return SIGINT;
|
||||
case kNtCtrlBreakEvent:
|
||||
__sig_add(0, SIGQUIT, SI_KERNEL);
|
||||
return true;
|
||||
return SIGQUIT;
|
||||
case kNtCtrlCloseEvent:
|
||||
case kNtCtrlLogoffEvent: // only received by services
|
||||
case kNtCtrlShutdownEvent: // only received by services
|
||||
__sig_add(0, SIGHUP, SI_KERNEL);
|
||||
return true;
|
||||
return SIGHUP;
|
||||
default:
|
||||
return false;
|
||||
__builtin_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
__msabi textwindows dontinstrument dontasan dontubsan bool32
|
||||
__onntconsoleevent(uint32_t dwCtrlType) {
|
||||
|
||||
// the signal to be delivered
|
||||
int sig = GetSig(dwCtrlType);
|
||||
int sic = SI_KERNEL;
|
||||
|
||||
// if we don't have tls, then we can't hijack a safe stack from a
|
||||
// thread so just try our luck punting the signal to the next i/o
|
||||
if (!__tls_enabled) {
|
||||
goto PuntSignal;
|
||||
}
|
||||
|
||||
// we're on a stack that's owned by win32. to make matters worse,
|
||||
// win32 spawns a totally new thread just to invoke this handler.
|
||||
// that means most of the cosmo runtime is broken right now which
|
||||
// means we can't call the user signal handler safely. what we'll
|
||||
// do instead is pick a posix thread at random to hijack, pretend
|
||||
// to be that thread, use its stack, and then deliver this signal
|
||||
// asynchronously if it isn't blocked. hopefully it won't longjmp
|
||||
// because once the handler returns, we'll restore the old thread
|
||||
bool gotsome = false;
|
||||
pthread_spin_lock(&_pthread_lock);
|
||||
for (struct Dll *e = dll_first(_pthread_list); e && !gotsome;
|
||||
e = dll_next(_pthread_list, e)) {
|
||||
struct PosixThread *pt = POSIXTHREAD_CONTAINER(e);
|
||||
int tid = atomic_load_explicit(&pt->tib->tib_tid, memory_order_acquire);
|
||||
if (tid <= 0) continue; // -1 means spawning, 0 means terminated
|
||||
if (pt->tib->tib_sigmask & (1ull << (sig - 1))) continue; // blocked
|
||||
intptr_t th;
|
||||
if ((th = __imp_OpenThread(kNtThreadSuspendResume | kNtThreadGetContext,
|
||||
false, tid))) {
|
||||
uint32_t old_suspend_count = __imp_SuspendThread(th);
|
||||
if (old_suspend_count != -1u) {
|
||||
if (!old_suspend_count &&
|
||||
atomic_load_explicit(&pt->status, memory_order_acquire) <
|
||||
kPosixThreadTerminated) {
|
||||
struct NtContext ctx;
|
||||
__repstosb(&ctx, 0, sizeof(ctx));
|
||||
ctx.ContextFlags = kNtContextControl;
|
||||
if (__imp_GetThreadContext(th, &ctx)) {
|
||||
gotsome = true;
|
||||
pthread_spin_unlock(&_pthread_lock);
|
||||
__set_tls_win32(pt->tib);
|
||||
WinThreadLaunch(sig, sic, __sig_raise,
|
||||
ROUNDDOWN(ctx.Rsp - kRedzoneSize, kStackAlign) - 8);
|
||||
} else {
|
||||
Log("GetThreadContext failed\n");
|
||||
}
|
||||
}
|
||||
__imp_ResumeThread(th);
|
||||
} else {
|
||||
Log("SuspendThread failed\n");
|
||||
}
|
||||
__imp_CloseHandle(th);
|
||||
} else {
|
||||
Log("OpenThread failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (!gotsome) {
|
||||
pthread_spin_unlock(&_pthread_lock);
|
||||
PuntSignal:
|
||||
__sig_add(0, sig, sic);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* __x86_64__ */
|
||||
|
|
|
@ -18,17 +18,11 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/macros.internal.h"
|
||||
.text.windows
|
||||
|
||||
__onntconsoleevent_nt:
|
||||
ezlea __onntconsoleevent,ax
|
||||
jmp __nt2sysv
|
||||
.endfn __onntconsoleevent_nt,globl,hidden
|
||||
|
||||
.init.start 300,_init_onntconsoleevent
|
||||
testb IsWindows()
|
||||
jz 1f
|
||||
ezlea __onntconsoleevent_nt,cx
|
||||
ezlea __onntconsoleevent,cx
|
||||
pushpop 1,%rdx
|
||||
ntcall __imp_SetConsoleCtrlHandler
|
||||
1: .init.end 300,_init_onntconsoleevent,globl,hidden
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
#include "libc/errno.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/nomultics.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/console.h"
|
||||
|
@ -107,6 +106,7 @@ StartOver:
|
|||
// since for overlapped i/o, we always use GetOverlappedResult
|
||||
ok = ReadFile(handle, targetdata, targetsize, 0, &overlap);
|
||||
if (!ok && GetLastError() == kNtErrorIoPending) {
|
||||
TryAgain:
|
||||
// the i/o operation is in flight; blocking is unavoidable
|
||||
// if we're in a non-blocking mode, then immediately abort
|
||||
// if an interrupt is pending then we abort before waiting
|
||||
|
@ -137,6 +137,9 @@ StartOver:
|
|||
// overlapped is allocated on stack, so it's important we wait
|
||||
// for windows to acknowledge that it's done using that memory
|
||||
ok = GetOverlappedResult(handle, &overlap, &got, true);
|
||||
if (!ok && GetLastError() == kNtErrorIoIncomplete) {
|
||||
goto TryAgain;
|
||||
}
|
||||
}
|
||||
CloseHandle(overlap.hEvent);
|
||||
} else {
|
||||
|
|
|
@ -20,8 +20,11 @@
|
|||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/mem/alloca.h"
|
||||
#include "libc/nt/createfile.h"
|
||||
#include "libc/nt/enum/accessmask.h"
|
||||
#include "libc/nt/enum/creationdisposition.h"
|
||||
#include "libc/nt/enum/fileflagandattributes.h"
|
||||
#include "libc/nt/enum/filesharemode.h"
|
||||
#include "libc/nt/enum/filetype.h"
|
||||
#include "libc/nt/enum/fsctl.h"
|
||||
#include "libc/nt/enum/io.h"
|
||||
#include "libc/nt/files.h"
|
||||
|
@ -34,28 +37,45 @@
|
|||
|
||||
textwindows ssize_t sys_readlinkat_nt(int dirfd, const char *path, char *buf,
|
||||
size_t bufsiz) {
|
||||
|
||||
char16_t path16[PATH_MAX];
|
||||
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1;
|
||||
size_t len = strlen16(path16);
|
||||
bool must_be_directory = len > 1 && path16[len - 1] == '\\';
|
||||
if (must_be_directory) path16[--len] = 0;
|
||||
|
||||
int64_t h;
|
||||
ssize_t rc;
|
||||
uint64_t w;
|
||||
wint_t x, y;
|
||||
volatile char *memory;
|
||||
uint32_t i, j, n, mem;
|
||||
char16_t path16[PATH_MAX], *p;
|
||||
struct NtReparseDataBuffer *rdb;
|
||||
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1;
|
||||
mem = 16384;
|
||||
memory = alloca(mem);
|
||||
uint32_t mem = 16384;
|
||||
volatile char *memory = alloca(mem);
|
||||
CheckLargeStackAllocation((char *)memory, mem);
|
||||
rdb = (struct NtReparseDataBuffer *)memory;
|
||||
if ((h = CreateFile(path16, 0, 0, 0, kNtOpenExisting,
|
||||
struct NtReparseDataBuffer *rdb = (struct NtReparseDataBuffer *)memory;
|
||||
if ((h = CreateFile(path16, kNtFileReadAttributes,
|
||||
kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete,
|
||||
0, kNtOpenExisting,
|
||||
kNtFileFlagOpenReparsePoint | kNtFileFlagBackupSemantics,
|
||||
0)) != -1) {
|
||||
if (DeviceIoControl(h, kNtFsctlGetReparsePoint, 0, 0, rdb, mem, &n, 0)) {
|
||||
|
||||
// if path had trailing slash, assert last component is directory
|
||||
if (must_be_directory) {
|
||||
struct NtByHandleFileInformation wst;
|
||||
if (GetFileType(h) != kNtFileTypeDisk ||
|
||||
(GetFileInformationByHandle(h, &wst) &&
|
||||
!(wst.dwFileAttributes & kNtFileAttributeDirectory))) {
|
||||
return enotdir();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t bc;
|
||||
if (DeviceIoControl(h, kNtFsctlGetReparsePoint, 0, 0, rdb, mem, &bc, 0)) {
|
||||
if (rdb->ReparseTag == kNtIoReparseTagSymlink) {
|
||||
i = 0;
|
||||
j = 0;
|
||||
n = rdb->SymbolicLinkReparseBuffer.PrintNameLength / sizeof(char16_t);
|
||||
p = (char16_t *)((char *)rdb->SymbolicLinkReparseBuffer.PathBuffer +
|
||||
|
||||
uint32_t i = 0;
|
||||
uint32_t j = 0;
|
||||
uint32_t n =
|
||||
rdb->SymbolicLinkReparseBuffer.PrintNameLength / sizeof(char16_t);
|
||||
char16_t *p =
|
||||
(char16_t *)((char *)rdb->SymbolicLinkReparseBuffer.PathBuffer +
|
||||
rdb->SymbolicLinkReparseBuffer.PrintNameOffset);
|
||||
if (n >= 3 && isalpha(p[0]) && p[1] == ':' && p[2] == '\\') {
|
||||
p[1] = p[0];
|
||||
|
@ -63,15 +83,18 @@ textwindows ssize_t sys_readlinkat_nt(int dirfd, const char *path, char *buf,
|
|||
p[2] = '/';
|
||||
}
|
||||
while (i < n) {
|
||||
x = p[i++] & 0xffff;
|
||||
|
||||
wint_t x = p[i++] & 0xffff;
|
||||
if (!IsUcs2(x)) {
|
||||
if (i < n) {
|
||||
y = p[i++] & 0xffff;
|
||||
wint_t y = p[i++] & 0xffff;
|
||||
x = MergeUtf16(x, y);
|
||||
} else {
|
||||
x = 0xfffd;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t w;
|
||||
if (x < 0200) {
|
||||
if (x == '\\') {
|
||||
x = '/';
|
||||
|
@ -95,6 +118,7 @@ textwindows ssize_t sys_readlinkat_nt(int dirfd, const char *path, char *buf,
|
|||
} else {
|
||||
rc = -1;
|
||||
}
|
||||
|
||||
CloseHandle(h);
|
||||
} else {
|
||||
rc = __fix_enotdir(-1, path16);
|
||||
|
|
|
@ -24,8 +24,8 @@
|
|||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Reads symbolic link.
|
||||
|
@ -40,12 +40,20 @@
|
|||
* and this buffer will *not* be nul-terminated
|
||||
* @return number of bytes written to buf, or -1 w/ errno; if the
|
||||
* return is equal to bufsiz then truncation may have occurred
|
||||
* @error EINVAL if path isn't a symbolic link
|
||||
* @raise EINVAL if path isn't a symbolic link
|
||||
* @raise ENOENT if `path` didn't exist
|
||||
* @raise ENOTDIR if parent component existed that's not a directory
|
||||
* @raise ENOTDIR if base component ends with slash and is not a dir
|
||||
* @raise ENAMETOOLONG if symlink-resolved `path` length exceeds `PATH_MAX`
|
||||
* @raise ENAMETOOLONG if component in `path` exists longer than `NAME_MAX`
|
||||
* @raise EBADF on relative `path` when `dirfd` isn't open or `AT_FDCWD`
|
||||
* @raise ELOOP if a loop was detected resolving parent components
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
ssize_t readlinkat(int dirfd, const char *path, char *buf, size_t bufsiz) {
|
||||
ssize_t bytes;
|
||||
if ((IsAsan() && !__asan_is_valid(buf, bufsiz)) || (bufsiz && !buf)) {
|
||||
if ((bufsiz && !buf) || (IsAsan() && (!__asan_is_valid_str(path) ||
|
||||
!__asan_is_valid(buf, bufsiz)))) {
|
||||
bytes = efault();
|
||||
} else if (_weaken(__zipos_notat) &&
|
||||
(bytes = __zipos_notat(dirfd, path)) == -1) {
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include "libc/calls/struct/winsize.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/nt/console.h"
|
||||
#include "libc/nt/struct/consolescreenbufferinfoex.h"
|
||||
#include "libc/sysv/consts/sicode.h"
|
||||
|
@ -66,7 +65,6 @@ __attribute__((__constructor__)) static void sigwinch_init(void) {
|
|||
if (!IsWindows()) return;
|
||||
unsigned ws = __get_console_size();
|
||||
atomic_store_explicit(&__win_winsize, ws, memory_order_release);
|
||||
STRACE("sigwinch_init() → %08x", ws);
|
||||
}
|
||||
|
||||
#endif /* __x86_64__ */
|
||||
|
|
|
@ -185,18 +185,23 @@ textwindows int tcsetattr_nt(int fd, int opt, const struct termios *tio) {
|
|||
if (opt == TCSAFLUSH) {
|
||||
FlushConsoleInputBuffer(hInput);
|
||||
}
|
||||
inmode &=
|
||||
~(kNtEnableLineInput | kNtEnableEchoInput | kNtEnableProcessedInput);
|
||||
inmode &= ~(kNtEnableLineInput | kNtEnableEchoInput |
|
||||
kNtEnableProcessedInput | kNtEnableVirtualTerminalInput);
|
||||
inmode |= kNtEnableWindowInput;
|
||||
__ttymagic = 0;
|
||||
if (tio->c_lflag & ICANON) {
|
||||
inmode |= kNtEnableLineInput;
|
||||
inmode |= kNtEnableLineInput | kNtEnableProcessedInput;
|
||||
} else {
|
||||
__ttymagic |= kFdTtyMunging;
|
||||
if (tio->c_cc[VMIN] != 1) {
|
||||
STRACE("tcsetattr c_cc[VMIN] must be 1 on Windows");
|
||||
return einval();
|
||||
}
|
||||
if (IsAtLeastWindows10()) {
|
||||
// - keys like f1, up, etc. get turned into \e ansi codes
|
||||
// - totally destroys default console gui (e.g. up arrow)
|
||||
inmode |= kNtEnableVirtualTerminalInput;
|
||||
}
|
||||
}
|
||||
if (!(tio->c_iflag & ICRNL)) {
|
||||
__ttymagic |= kFdTtyNoCr2Nl;
|
||||
|
@ -220,13 +225,11 @@ textwindows int tcsetattr_nt(int fd, int opt, const struct termios *tio) {
|
|||
if (!(tio->c_lflag & ISIG)) {
|
||||
__ttymagic |= kFdTtyNoIsigs;
|
||||
}
|
||||
if (IsAtLeastWindows10()) {
|
||||
inmode |= kNtEnableVirtualTerminalInput;
|
||||
}
|
||||
__vintr = tio->c_cc[VINTR];
|
||||
__vquit = tio->c_cc[VQUIT];
|
||||
if ((tio->c_lflag & ISIG) && //
|
||||
tio->c_cc[VINTR] == CTRL('C')) {
|
||||
// allows ctrl-c to be delivered asynchronously via win32
|
||||
inmode |= kNtEnableProcessedInput;
|
||||
}
|
||||
ok = SetConsoleMode(hInput, inmode);
|
||||
|
|
|
@ -20,7 +20,9 @@
|
|||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/nt/createfile.h"
|
||||
#include "libc/nt/enum/accessmask.h"
|
||||
#include "libc/nt/enum/creationdisposition.h"
|
||||
|
@ -30,6 +32,8 @@
|
|||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/nt/thread.h"
|
||||
#include "libc/nt/thunk/msabi.h"
|
||||
#include "libc/thread/tls.h"
|
||||
#include "libc/thread/tls2.internal.h"
|
||||
|
||||
/**
|
||||
* @fileoverview makes windows stdin handle capable of being poll'd
|
||||
|
@ -56,11 +60,24 @@ __msabi extern typeof(CreateFile) *const __imp_CreateFileW;
|
|||
__msabi extern typeof(CreateNamedPipe) *const __imp_CreateNamedPipeW;
|
||||
__msabi extern typeof(CreateSemaphore) *const __imp_CreateSemaphoreW;
|
||||
__msabi extern typeof(CreateThread) *const __imp_CreateThread;
|
||||
__msabi extern typeof(GetCurrentThreadId) *const __imp_GetCurrentThreadId;
|
||||
__msabi extern typeof(GetStdHandle) *const __imp_GetStdHandle;
|
||||
__msabi extern typeof(ReadFile) *const __imp_ReadFile;
|
||||
__msabi extern typeof(WaitForSingleObject) *const __imp_WaitForSingleObject;
|
||||
__msabi extern typeof(WriteFile) *const __imp_WriteFile;
|
||||
|
||||
static unsigned long StrLen(const char *s) {
|
||||
unsigned long n = 0;
|
||||
while (*s++) ++n;
|
||||
return n;
|
||||
}
|
||||
|
||||
static void Log(const char *s) {
|
||||
#if 0
|
||||
__imp_WriteFile(__imp_GetStdHandle(kNtStdErrorHandle), s, StrLen(s), 0, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
__msabi static dontasan dontubsan dontinstrument textwindows uint32_t
|
||||
WinStdinThread(void *lpParameter) {
|
||||
char buf[4096];
|
||||
|
@ -75,19 +92,19 @@ WinStdinThread(void *lpParameter) {
|
|||
__imp_CloseHandle(g_fds.stdin.inisem);
|
||||
|
||||
// relay stdin to process
|
||||
NTTRACE("<stdin> activated");
|
||||
Log("<stdin> activated\n");
|
||||
for (;;) {
|
||||
if (!__imp_ReadFile(g_fds.stdin.handle, buf, sizeof(buf), &got, 0)) {
|
||||
NTTRACE("<stdin> read failed");
|
||||
Log("<stdin> read failed\n");
|
||||
goto Finish;
|
||||
}
|
||||
if (!got) {
|
||||
NTTRACE("<stdin> end of file");
|
||||
Log("<stdin> end of file\n");
|
||||
goto Finish;
|
||||
}
|
||||
for (i = 0; i < got; i += wrote) {
|
||||
if (!__imp_WriteFile(g_fds.stdin.writer, buf + i, got - i, &wrote, 0)) {
|
||||
NTTRACE("<stdin> failed to write to pipe");
|
||||
Log("<stdin> failed to write to pipe\n");
|
||||
goto Finish;
|
||||
}
|
||||
}
|
||||
|
@ -106,13 +123,13 @@ dontasan dontubsan dontinstrument textwindows void WinMainStdin(void) {
|
|||
if (!SupportsWindows()) return;
|
||||
hStdin = __imp_GetStdHandle(kNtStdInputHandle);
|
||||
if (hStdin == kNtInvalidHandleValue) {
|
||||
NTTRACE("<stdin> GetStdHandle failed");
|
||||
Log("<stdin> GetStdHandle failed\n");
|
||||
return;
|
||||
}
|
||||
// create non-inherited semaphore with initial value of 0
|
||||
hSemaphore = __imp_CreateSemaphoreW(0, 0, 1, 0);
|
||||
if (!hSemaphore) {
|
||||
NTTRACE("<stdin> CreateSemaphore failed");
|
||||
Log("<stdin> CreateSemaphore failed\n");
|
||||
return;
|
||||
}
|
||||
__create_pipe_name(pipename);
|
||||
|
@ -120,18 +137,18 @@ dontasan dontubsan dontinstrument textwindows void WinMainStdin(void) {
|
|||
pipename, kNtPipeAccessInbound | kNtFileFlagOverlapped,
|
||||
kNtPipeTypeByte | kNtPipeReadmodeByte, 1, 4096, 4096, 0, 0);
|
||||
if (hReader == kNtInvalidHandleValue) {
|
||||
NTTRACE("<stdin> CreateNamedPipe failed");
|
||||
Log("<stdin> CreateNamedPipe failed\n");
|
||||
return;
|
||||
}
|
||||
hWriter = __imp_CreateFileW(pipename, kNtGenericWrite, 0, 0, kNtOpenExisting,
|
||||
kNtFileFlagOverlapped, 0);
|
||||
if (hWriter == kNtInvalidHandleValue) {
|
||||
NTTRACE("<stdin> CreateFile failed");
|
||||
Log("<stdin> CreateFile failed\n");
|
||||
return;
|
||||
}
|
||||
hThread = __imp_CreateThread(0, 65536, WinStdinThread, 0, 0, 0);
|
||||
if (!hThread) {
|
||||
NTTRACE("<stdin> CreateThread failed");
|
||||
Log("<stdin> CreateThread failed\n");
|
||||
return;
|
||||
}
|
||||
g_fds.stdin.handle = hStdin;
|
||||
|
|
|
@ -25,11 +25,11 @@
|
|||
// This function switches us over, so that we can start using the
|
||||
// runtime facilities.
|
||||
//
|
||||
// @param %rdi is arg
|
||||
// @param %rsi is tid
|
||||
// @param %rdi is arg1
|
||||
// @param %rsi is arg2
|
||||
// @param %rdx is func
|
||||
// @param %rcx is stack
|
||||
// @return %rax is exit code
|
||||
// @return %rax is res
|
||||
// @see clone()
|
||||
WinThreadLaunch:
|
||||
push %rbx
|
|
@ -1,218 +0,0 @@
|
|||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||
╚──────────────────────────────────────────────────────────────────────────────╝
|
||||
│ │
|
||||
│ Optimized Routines │
|
||||
│ Copyright (c) 1999-2022, Arm Limited. │
|
||||
│ │
|
||||
│ Permission is hereby granted, free of charge, to any person obtaining │
|
||||
│ a copy of this software and associated documentation files (the │
|
||||
│ "Software"), to deal in the Software without restriction, including │
|
||||
│ without limitation the rights to use, copy, modify, merge, publish, │
|
||||
│ distribute, sublicense, and/or sell copies of the Software, and to │
|
||||
│ permit persons to whom the Software is furnished to do so, subject to │
|
||||
│ the following conditions: │
|
||||
│ │
|
||||
│ The above copyright notice and this permission notice shall be │
|
||||
│ included in all copies or substantial portions of the Software. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │
|
||||
│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │
|
||||
│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │
|
||||
│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │
|
||||
│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │
|
||||
│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │
|
||||
│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │
|
||||
│ │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/aarch64/asmdefs.internal.h"
|
||||
|
||||
#define __memcmp_aarch64 memcmp
|
||||
|
||||
.ident "\n\n\
|
||||
Optimized Routines (MIT License)\n\
|
||||
Copyright 2022 ARM Limited\n"
|
||||
.include "libc/disclaimer.inc"
|
||||
|
||||
/* Assumptions:
|
||||
*
|
||||
* ARMv8-a, AArch64, Advanced SIMD, unaligned accesses.
|
||||
*/
|
||||
|
||||
#define src1 x0
|
||||
#define src2 x1
|
||||
#define limit x2
|
||||
#define result w0
|
||||
|
||||
#define data1 x3
|
||||
#define data1w w3
|
||||
#define data2 x4
|
||||
#define data2w w4
|
||||
#define data3 x5
|
||||
#define data3w w5
|
||||
#define data4 x6
|
||||
#define data4w w6
|
||||
#define tmp x6
|
||||
#define src1end x7
|
||||
#define src2end x8
|
||||
|
||||
|
||||
ENTRY (__memcmp_aarch64)
|
||||
PTR_ARG (0)
|
||||
PTR_ARG (1)
|
||||
SIZE_ARG (2)
|
||||
|
||||
cmp limit, 16
|
||||
b.lo L(less16)
|
||||
ldp data1, data3, [src1]
|
||||
ldp data2, data4, [src2]
|
||||
ccmp data1, data2, 0, ne
|
||||
ccmp data3, data4, 0, eq
|
||||
b.ne L(return2)
|
||||
|
||||
add src1end, src1, limit
|
||||
add src2end, src2, limit
|
||||
cmp limit, 32
|
||||
b.ls L(last_bytes)
|
||||
cmp limit, 160
|
||||
b.hs L(loop_align)
|
||||
sub limit, limit, 32
|
||||
|
||||
.p2align 4
|
||||
L(loop32):
|
||||
ldp data1, data3, [src1, 16]
|
||||
ldp data2, data4, [src2, 16]
|
||||
cmp data1, data2
|
||||
ccmp data3, data4, 0, eq
|
||||
b.ne L(return2)
|
||||
cmp limit, 16
|
||||
b.ls L(last_bytes)
|
||||
|
||||
ldp data1, data3, [src1, 32]
|
||||
ldp data2, data4, [src2, 32]
|
||||
cmp data1, data2
|
||||
ccmp data3, data4, 0, eq
|
||||
b.ne L(return2)
|
||||
add src1, src1, 32
|
||||
add src2, src2, 32
|
||||
L(last64):
|
||||
subs limit, limit, 32
|
||||
b.hi L(loop32)
|
||||
|
||||
/* Compare last 1-16 bytes using unaligned access. */
|
||||
L(last_bytes):
|
||||
ldp data1, data3, [src1end, -16]
|
||||
ldp data2, data4, [src2end, -16]
|
||||
L(return2):
|
||||
cmp data1, data2
|
||||
csel data1, data1, data3, ne
|
||||
csel data2, data2, data4, ne
|
||||
|
||||
/* Compare data bytes and set return value to 0, -1 or 1. */
|
||||
L(return):
|
||||
#ifndef __AARCH64EB__
|
||||
rev data1, data1
|
||||
rev data2, data2
|
||||
#endif
|
||||
cmp data1, data2
|
||||
cset result, ne
|
||||
cneg result, result, lo
|
||||
ret
|
||||
|
||||
.p2align 4
|
||||
L(less16):
|
||||
add src1end, src1, limit
|
||||
add src2end, src2, limit
|
||||
tbz limit, 3, L(less8)
|
||||
ldr data1, [src1]
|
||||
ldr data2, [src2]
|
||||
ldr data3, [src1end, -8]
|
||||
ldr data4, [src2end, -8]
|
||||
b L(return2)
|
||||
|
||||
.p2align 4
|
||||
L(less8):
|
||||
tbz limit, 2, L(less4)
|
||||
ldr data1w, [src1]
|
||||
ldr data2w, [src2]
|
||||
ldr data3w, [src1end, -4]
|
||||
ldr data4w, [src2end, -4]
|
||||
b L(return2)
|
||||
|
||||
L(less4):
|
||||
tbz limit, 1, L(less2)
|
||||
ldrh data1w, [src1]
|
||||
ldrh data2w, [src2]
|
||||
cmp data1w, data2w
|
||||
b.ne L(return)
|
||||
L(less2):
|
||||
mov result, 0
|
||||
tbz limit, 0, L(return_zero)
|
||||
ldrb data1w, [src1end, -1]
|
||||
ldrb data2w, [src2end, -1]
|
||||
sub result, data1w, data2w
|
||||
L(return_zero):
|
||||
ret
|
||||
|
||||
L(loop_align):
|
||||
ldp data1, data3, [src1, 16]
|
||||
ldp data2, data4, [src2, 16]
|
||||
cmp data1, data2
|
||||
ccmp data3, data4, 0, eq
|
||||
b.ne L(return2)
|
||||
|
||||
/* Align src2 and adjust src1, src2 and limit. */
|
||||
and tmp, src2, 15
|
||||
sub tmp, tmp, 16
|
||||
sub src2, src2, tmp
|
||||
add limit, limit, tmp
|
||||
sub src1, src1, tmp
|
||||
sub limit, limit, 64 + 16
|
||||
|
||||
.p2align 4
|
||||
L(loop64):
|
||||
ldr q0, [src1, 16]
|
||||
ldr q1, [src2, 16]
|
||||
subs limit, limit, 64
|
||||
ldr q2, [src1, 32]
|
||||
ldr q3, [src2, 32]
|
||||
eor v0.16b, v0.16b, v1.16b
|
||||
eor v1.16b, v2.16b, v3.16b
|
||||
ldr q2, [src1, 48]
|
||||
ldr q3, [src2, 48]
|
||||
umaxp v0.16b, v0.16b, v1.16b
|
||||
ldr q4, [src1, 64]!
|
||||
ldr q5, [src2, 64]!
|
||||
eor v1.16b, v2.16b, v3.16b
|
||||
eor v2.16b, v4.16b, v5.16b
|
||||
umaxp v1.16b, v1.16b, v2.16b
|
||||
umaxp v0.16b, v0.16b, v1.16b
|
||||
umaxp v0.16b, v0.16b, v0.16b
|
||||
fmov tmp, d0
|
||||
ccmp tmp, 0, 0, hi
|
||||
b.eq L(loop64)
|
||||
|
||||
/* If equal, process last 1-64 bytes using scalar loop. */
|
||||
add limit, limit, 64 + 16
|
||||
cbz tmp, L(last64)
|
||||
|
||||
/* Determine the 8-byte aligned offset of the first difference. */
|
||||
#ifdef __AARCH64EB__
|
||||
rev16 tmp, tmp
|
||||
#endif
|
||||
rev tmp, tmp
|
||||
clz tmp, tmp
|
||||
bic tmp, tmp, 7
|
||||
sub tmp, tmp, 48
|
||||
ldr data1, [src1, tmp]
|
||||
ldr data2, [src2, tmp]
|
||||
#ifndef __AARCH64EB__
|
||||
rev data1, data1
|
||||
rev data2, data2
|
||||
#endif
|
||||
mov result, 1
|
||||
cmp data1, data2
|
||||
cneg result, result, lo
|
||||
ret
|
||||
|
||||
END (__memcmp_aarch64)
|
|
@ -85,10 +85,6 @@ wontreturn void _Exit(int exitcode) {
|
|||
#endif
|
||||
} else if (IsWindows()) {
|
||||
uint32_t waitstatus;
|
||||
// Restoring the CMD.EXE program to its original state is critical.
|
||||
if (_weaken(__restore_console_win32)) {
|
||||
_weaken(__restore_console_win32)();
|
||||
}
|
||||
// What Microsoft calls an exit code, POSIX calls a status code. See
|
||||
// also the WEXITSTATUS() and WIFEXITED() macros that POSIX defines.
|
||||
waitstatus = exitcode;
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include "libc/intrin/likely.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/str/str.h"
|
||||
#ifndef __aarch64__
|
||||
|
||||
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
|
||||
|
||||
|
@ -83,5 +82,3 @@ int memcmp(const void *a, const void *b, size_t n) {
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* __aarch64__ */
|
||||
|
|
22
libc/intrin/pthreadlist.c
Normal file
22
libc/intrin/pthreadlist.c
Normal file
|
@ -0,0 +1,22 @@
|
|||
/*-*- 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 2023 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/intrin/dll.h"
|
||||
#include "libc/thread/posixthread.internal.h"
|
||||
|
||||
struct Dll *_pthread_list;
|
22
libc/intrin/pthreadlock.c
Normal file
22
libc/intrin/pthreadlock.c
Normal file
|
@ -0,0 +1,22 @@
|
|||
/*-*- 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 2023 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/thread/posixthread.internal.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
pthread_spinlock_t _pthread_lock;
|
|
@ -30,8 +30,6 @@
|
|||
#include "libc/errno.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/backtrace.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
|
@ -44,7 +42,7 @@ asm(".ident\t\"\\n\\n\
|
|||
Musl libc (MIT License)\\n\
|
||||
Copyright 2005-2014 Rich Felker, et. al.\"");
|
||||
asm(".include \"libc/disclaimer.inc\"");
|
||||
/* clang-format off */
|
||||
// clang-format off
|
||||
|
||||
static inline bool IsSlash(char c)
|
||||
{
|
||||
|
@ -60,7 +58,7 @@ static size_t GetSlashLen(const char *s)
|
|||
|
||||
static char *ResolvePath(char *d, const char *s, size_t n)
|
||||
{
|
||||
if (d || (_weaken(malloc) && (d = _weaken(malloc)(n+1)))) {
|
||||
if (d || (d = malloc(n+1))) {
|
||||
return memmove(d, s, n+1);
|
||||
} else {
|
||||
enomem();
|
||||
|
@ -71,11 +69,26 @@ static char *ResolvePath(char *d, const char *s, size_t n)
|
|||
/**
|
||||
* Returns absolute pathname.
|
||||
*
|
||||
* This function removes `/./` and `/../` components. IF the path is a
|
||||
* symbolic link then it's resolved.
|
||||
* This function removes `/./` and `/../` components. If any individual
|
||||
* path component is a symbolic link, then it'll be resolved. Any slash
|
||||
* characters that repeat (e.g. `//`) will collapse into one (i.e. `/`)
|
||||
*
|
||||
* @param resolved needs PATH_MAX bytes or NULL to use malloc()
|
||||
* @return resolved or NULL w/ errno
|
||||
* This implementation is consistent with glibc, in that `"//"` becomes
|
||||
* `"/"` unlike Musl Libc, which considers that special (not sure why?)
|
||||
* This is the only change Cosmopolitan Libc made vs. Musl's realpath()
|
||||
* aside from also being permissive about backslashes, to help Windows.
|
||||
*
|
||||
* @param filename is the path that needs to be resolved
|
||||
* @param resolved needs PATH_MAX bytes, or NULL to use malloc()
|
||||
* @return resolved path, or NULL w/ errno
|
||||
* @raise EINVAL if `filename` is NULL
|
||||
* @raise ENOENT if `filename` is an empty string
|
||||
* @raise ENOMEM if `resolved` is NULL and malloc() failed
|
||||
* @raise ENOENT if `filename` didn't exist
|
||||
* @raise ENOTDIR if directory component existed that's not a directory
|
||||
* @raise ENOTDIR if base component ends with slash and is not a dir
|
||||
* @raise ENAMETOOLONG if filename resolution exceeded `PATH_MAX`
|
||||
* @raise ELOOP if too many symlinks were encountered
|
||||
*/
|
||||
char *realpath(const char *filename, char *resolved)
|
||||
{
|
||||
|
@ -84,8 +97,6 @@ char *realpath(const char *filename, char *resolved)
|
|||
size_t k, p, q, l, l0, cnt=0, nup=0;
|
||||
char output[PATH_MAX], stack[PATH_MAX+1], *z;
|
||||
|
||||
/* STRACE("realpath(%#s, %#s)", filename, resolved); */
|
||||
|
||||
if (!filename) {
|
||||
einval();
|
||||
return 0;
|
||||
|
@ -118,9 +129,6 @@ restart:
|
|||
q=0;
|
||||
output[q++] = '/';
|
||||
p++;
|
||||
/* Initial // is special. */
|
||||
if (IsSlash(stack[p]) && !IsSlash(stack[p+1]))
|
||||
output[q++] = '/';
|
||||
continue;
|
||||
}
|
||||
|
21
libc/nt/enum/context.h
Normal file
21
libc/nt/enum/context.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_NT_ENUM_CONTEXT_H_
|
||||
#define COSMOPOLITAN_LIBC_NT_ENUM_CONTEXT_H_
|
||||
|
||||
#define kNtContextAmd64 0x00100000
|
||||
|
||||
#define kNtContextControl (kNtContextAmd64 | 0x00000001)
|
||||
#define kNtContextInteger (kNtContextAmd64 | 0x00000002)
|
||||
#define kNtContextSegments (kNtContextAmd64 | 0x00000004)
|
||||
#define kNtContextFloatingPoint (kNtContextAmd64 | 0x00000008)
|
||||
#define kNtContextDebugRegisters (kNtContextAmd64 | 0x00000010)
|
||||
|
||||
#define kNtContextFull \
|
||||
(kNtContextControl | kNtContextInteger | kNtContextFloatingPoint)
|
||||
|
||||
#define kNtContextAll \
|
||||
(kNtContextControl | kNtContextInteger | kNtContextSegments | \
|
||||
kNtContextFloatingPoint | kNtContextDebugRegisters)
|
||||
|
||||
#define kNtContextXstate (kNtContextAmd64 | 0x00000040)
|
||||
|
||||
#endif /* COSMOPOLITAN_LIBC_NT_ENUM_CONTEXT_H_ */
|
18
libc/nt/kernel32/GetThreadContext.S
Normal file
18
libc/nt/kernel32/GetThreadContext.S
Normal file
|
@ -0,0 +1,18 @@
|
|||
#include "libc/nt/codegen.h"
|
||||
.imp kernel32,__imp_GetThreadContext,GetThreadContext
|
||||
|
||||
.text.windows
|
||||
.ftrace1
|
||||
GetThreadContext:
|
||||
.ftrace2
|
||||
#ifdef __x86_64__
|
||||
push %rbp
|
||||
mov %rsp,%rbp
|
||||
mov __imp_GetThreadContext(%rip),%rax
|
||||
jmp __sysv2nt
|
||||
#elif defined(__aarch64__)
|
||||
mov x0,#0
|
||||
ret
|
||||
#endif
|
||||
.endfn GetThreadContext,globl
|
||||
.previous
|
18
libc/nt/kernel32/InitializeContext.S
Normal file
18
libc/nt/kernel32/InitializeContext.S
Normal file
|
@ -0,0 +1,18 @@
|
|||
#include "libc/nt/codegen.h"
|
||||
.imp kernel32,__imp_InitializeContext,InitializeContext
|
||||
|
||||
.text.windows
|
||||
.ftrace1
|
||||
InitializeContext:
|
||||
.ftrace2
|
||||
#ifdef __x86_64__
|
||||
push %rbp
|
||||
mov %rsp,%rbp
|
||||
mov __imp_InitializeContext(%rip),%rax
|
||||
jmp __sysv2nt
|
||||
#elif defined(__aarch64__)
|
||||
mov x0,#0
|
||||
ret
|
||||
#endif
|
||||
.endfn InitializeContext,globl
|
||||
.previous
|
20
libc/nt/kernel32/ResumeThread.S
Normal file
20
libc/nt/kernel32/ResumeThread.S
Normal file
|
@ -0,0 +1,20 @@
|
|||
#include "libc/nt/codegen.h"
|
||||
.imp kernel32,__imp_ResumeThread,ResumeThread
|
||||
|
||||
.text.windows
|
||||
.ftrace1
|
||||
ResumeThread:
|
||||
.ftrace2
|
||||
#ifdef __x86_64__
|
||||
push %rbp
|
||||
mov %rsp,%rbp
|
||||
mov %rdi,%rcx
|
||||
sub $32,%rsp
|
||||
call *__imp_ResumeThread(%rip)
|
||||
leave
|
||||
#elif defined(__aarch64__)
|
||||
mov x0,#0
|
||||
#endif
|
||||
ret
|
||||
.endfn ResumeThread,globl
|
||||
.previous
|
|
@ -11,9 +11,9 @@
|
|||
# Name Actual DLL Arity
|
||||
imp '' CloseHandle kernel32 1
|
||||
imp '' CreateDirectoryW kernel32 2
|
||||
imp '' CreateFileA kernel32 7
|
||||
imp '' CreateFileMappingNumaW kernel32 7
|
||||
imp '' CreateFileMappingW kernel32 6
|
||||
imp '' CreateFileA kernel32 7
|
||||
imp '' CreateFileW kernel32 7
|
||||
imp '' CreateNamedPipeW kernel32 8
|
||||
imp '' CreatePipe kernel32 4
|
||||
|
@ -162,6 +162,7 @@ imp 'GetSystemTimePreciseAsFileTime' GetSystemTimePreciseAsFileTime kernel3
|
|||
imp 'GetSystemTimes' GetSystemTimes kernel32 3
|
||||
imp 'GetTempPath' GetTempPathW kernel32 2
|
||||
imp 'GetTempPathA' GetTempPathA kernel32 2
|
||||
imp 'GetThreadContext' GetThreadContext kernel32 2
|
||||
imp 'GetThreadIOPendingFlag' GetThreadIOPendingFlag kernel32 2
|
||||
imp 'GetThreadId' GetThreadId kernel32 1
|
||||
imp 'GetThreadPriority' GetThreadPriority kernel32 1
|
||||
|
@ -182,6 +183,7 @@ imp 'HeapCreate' HeapCreate kernel32 3
|
|||
imp 'HeapDestroy' HeapDestroy kernel32 1
|
||||
imp 'HeapFree' HeapFree kernel32 3
|
||||
imp 'HeapReAlloc' HeapReAlloc kernel32 4
|
||||
imp 'InitializeContext' InitializeContext kernel32 4 # Windows 7+
|
||||
imp 'InitializeCriticalSection' InitializeCriticalSection kernel32 1
|
||||
imp 'InitializeCriticalSectionAndSpinCount' InitializeCriticalSectionAndSpinCount kernel32 2
|
||||
imp 'InitializeProcThreadAttributeList' InitializeProcThreadAttributeList kernel32 4
|
||||
|
@ -223,6 +225,7 @@ imp 'ReleaseSemaphore' ReleaseSemaphore kernel32 3
|
|||
imp 'RemoveVectoredContinueHandler' RemoveVectoredContinueHandler kernel32 1
|
||||
imp 'RemoveVectoredExceptionHandler' RemoveVectoredExceptionHandler kernel32 1
|
||||
imp 'ResetEvent' ResetEvent kernel32 1
|
||||
imp 'ResumeThread' ResumeThread kernel32 1
|
||||
imp 'SetConsoleActiveScreenBuffer' SetConsoleActiveScreenBuffer kernel32 1 # TODO(jart): 6.2 and higher
|
||||
imp 'SetConsoleCP' SetConsoleCP kernel32 1 # TODO(jart): 6.2 and higher
|
||||
imp 'SetConsoleCtrlHandler' SetConsoleCtrlHandler kernel32 2
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_NT_THREADS_H_
|
||||
#define COSMOPOLITAN_LIBC_NT_THREADS_H_
|
||||
#include "libc/nt/struct/context.h"
|
||||
#include "libc/nt/struct/overlapped.h"
|
||||
#include "libc/nt/struct/securityattributes.h"
|
||||
#include "libc/nt/thunk/msabi.h"
|
||||
|
@ -60,6 +61,10 @@ bool32 TlsFree(uint32_t);
|
|||
bool32 TlsSetValue(uint32_t, void *);
|
||||
void *TlsGetValue(uint32_t);
|
||||
|
||||
uint32_t SuspendThread(int64_t hThread);
|
||||
uint32_t ResumeThread(int64_t hThread);
|
||||
bool32 GetThreadContext(int64_t hThread, struct NtContext *in_out_lpContext);
|
||||
|
||||
#if ShouldUseMsabiAttribute()
|
||||
#include "libc/nt/thunk/thread.inc"
|
||||
#endif /* ShouldUseMsabiAttribute() */
|
||||
|
|
|
@ -40,8 +40,6 @@
|
|||
extern unsigned char __tls_mov_nt_rax[];
|
||||
extern unsigned char __tls_add_nt_rax[];
|
||||
|
||||
struct Dll *_pthread_list;
|
||||
pthread_spinlock_t _pthread_lock;
|
||||
static struct PosixThread _pthread_main;
|
||||
_Alignas(TLS_ALIGNMENT) static char __static_tls[6016];
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@
|
|||
__static_yoink("_check_sigchld");
|
||||
|
||||
extern int64_t __wincrashearly;
|
||||
bool32 __onntconsoleevent_nt(uint32_t);
|
||||
bool32 __onntconsoleevent(uint32_t);
|
||||
void sys_setitimer_nt_reset(void);
|
||||
void kmalloc_unlock(void);
|
||||
|
||||
|
@ -308,8 +308,8 @@ textwindows void WinMainForked(void) {
|
|||
}
|
||||
AddVectoredExceptionHandler(1, (void *)_weaken(__wincrash_nt));
|
||||
}
|
||||
if (_weaken(__onntconsoleevent_nt)) {
|
||||
SetConsoleCtrlHandler(_weaken(__onntconsoleevent_nt), 1);
|
||||
if (_weaken(__onntconsoleevent)) {
|
||||
SetConsoleCtrlHandler(_weaken(__onntconsoleevent), 1);
|
||||
}
|
||||
|
||||
// jump back into function below
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
#include "libc/runtime/stack.h"
|
||||
#include "libc/runtime/winargs.internal.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
|
||||
#ifdef __x86_64__
|
||||
|
@ -66,6 +67,7 @@ __msabi extern typeof(GetConsoleMode) *const __imp_GetConsoleMode;
|
|||
__msabi extern typeof(GetCurrentProcess) *const __imp_GetCurrentProcess;
|
||||
__msabi extern typeof(GetCurrentProcessId) *const __imp_GetCurrentProcessId;
|
||||
__msabi extern typeof(GetEnvironmentStrings) *const __imp_GetEnvironmentStringsW;
|
||||
__msabi extern typeof(GetFileAttributes) *const __imp_GetFileAttributesW;
|
||||
__msabi extern typeof(GetStdHandle) *const __imp_GetStdHandle;
|
||||
__msabi extern typeof(MapViewOfFileEx) *const __imp_MapViewOfFileEx;
|
||||
__msabi extern typeof(SetConsoleCP) *const __imp_SetConsoleCP;
|
||||
|
@ -73,7 +75,6 @@ __msabi extern typeof(SetConsoleMode) *const __imp_SetConsoleMode;
|
|||
__msabi extern typeof(SetConsoleOutputCP) *const __imp_SetConsoleOutputCP;
|
||||
__msabi extern typeof(SetStdHandle) *const __imp_SetStdHandle;
|
||||
__msabi extern typeof(VirtualProtect) *const __imp_VirtualProtect;
|
||||
__msabi extern typeof(WriteFile) *const __imp_WriteFile;
|
||||
// clang-format on
|
||||
|
||||
extern void cosmo(int, char **, char **, long (*)[2]) wontreturn;
|
||||
|
@ -84,20 +85,6 @@ static const signed char kNtStdio[3] = {
|
|||
(signed char)kNtStdErrorHandle,
|
||||
};
|
||||
|
||||
static const short kConsoleModes[3] = {
|
||||
kNtEnableProcessedInput | kNtEnableLineInput | kNtEnableEchoInput |
|
||||
kNtEnableMouseInput | kNtEnableQuickEditMode | kNtEnableExtendedFlags |
|
||||
kNtEnableAutoPosition | kNtEnableInsertMode |
|
||||
kNtEnableVirtualTerminalInput,
|
||||
kNtEnableProcessedOutput | kNtEnableWrapAtEolOutput |
|
||||
kNtEnableVirtualTerminalProcessing,
|
||||
kNtEnableProcessedOutput | kNtEnableWrapAtEolOutput |
|
||||
kNtEnableVirtualTerminalProcessing,
|
||||
};
|
||||
|
||||
static uint32_t __init_pid;
|
||||
static uint32_t __console_mode[3];
|
||||
|
||||
forceinline int IsAlpha(int c) {
|
||||
return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z');
|
||||
}
|
||||
|
@ -108,16 +95,6 @@ __msabi long __oops_win32(void) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// called by _exit to undo our config changes to cmd.exe
|
||||
// it must never ever be called from forked subprocesses
|
||||
void __restore_console_win32(void) {
|
||||
if (__imp_GetCurrentProcessId() == __init_pid) {
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
__imp_SetConsoleMode(__imp_GetStdHandle(kNtStdio[i]), __console_mode[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// https://nullprogram.com/blog/2022/02/18/
|
||||
__msabi static inline char16_t *MyCommandLine(void) {
|
||||
void *cmd;
|
||||
|
@ -128,6 +105,15 @@ __msabi static inline char16_t *MyCommandLine(void) {
|
|||
return cmd;
|
||||
}
|
||||
|
||||
// returns true if utf-8 path is a win32-style path that exists
|
||||
__msabi static textwindows bool32 WinFileExists(const char *path) {
|
||||
uint16_t path16[PATH_MAX];
|
||||
size_t z = ARRAYLEN(path16);
|
||||
size_t n = tprecode8to16(path16, z, path).ax;
|
||||
if (n >= z - 1) return false;
|
||||
return __imp_GetFileAttributesW(path16) != -1u;
|
||||
}
|
||||
|
||||
// this ensures close(1) won't accidentally close(2) for example
|
||||
__msabi static textwindows void DeduplicateStdioHandles(void) {
|
||||
for (long i = 0; i < 3; ++i) {
|
||||
|
@ -144,27 +130,30 @@ __msabi static textwindows void DeduplicateStdioHandles(void) {
|
|||
}
|
||||
}
|
||||
|
||||
__msabi static textwindows wontreturn void WinMainNew(const char16_t *cmdline) {
|
||||
size_t stacksize;
|
||||
struct WinArgs *wa;
|
||||
uintptr_t stackaddr;
|
||||
__init_pid = __pid;
|
||||
// main function of windows init process
|
||||
// i.e. first process spawned that isn't forked
|
||||
__msabi static textwindows wontreturn void WinInit(const char16_t *cmdline) {
|
||||
__oldstack = (intptr_t)__builtin_frame_address(0);
|
||||
|
||||
// make console into utf-8 ansi/xterm style tty
|
||||
if (NtGetPeb()->OSMajorVersion >= 10 &&
|
||||
(intptr_t)v_ntsubsystem == kNtImageSubsystemWindowsCui) {
|
||||
__imp_SetConsoleCP(kNtCpUtf8);
|
||||
__imp_SetConsoleOutputCP(kNtCpUtf8);
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
int64_t hand = __imp_GetStdHandle(kNtStdio[i]);
|
||||
__imp_GetConsoleMode(hand, __console_mode + i);
|
||||
__imp_SetConsoleMode(hand, kConsoleModes[i]);
|
||||
for (int i = 1; i <= 2; ++i) {
|
||||
uint32_t m;
|
||||
intptr_t h = __imp_GetStdHandle(kNtStdio[i]);
|
||||
__imp_GetConsoleMode(h, &m);
|
||||
__imp_SetConsoleMode(h, m | kNtEnableVirtualTerminalProcessing);
|
||||
}
|
||||
}
|
||||
|
||||
// allocate memory for stack and argument block
|
||||
_Static_assert(sizeof(struct WinArgs) % FRAMESIZE == 0, "");
|
||||
_mmi.p = _mmi.s;
|
||||
_mmi.n = ARRAYLEN(_mmi.s);
|
||||
stackaddr = GetStaticStackAddr(0);
|
||||
stacksize = GetStaticStackSize();
|
||||
uintptr_t stackaddr = GetStaticStackAddr(0);
|
||||
size_t stacksize = GetStaticStackSize();
|
||||
__imp_MapViewOfFileEx((_mmi.p[0].h = __imp_CreateFileMappingW(
|
||||
-1, &kNtIsInheritable, kNtPageExecuteReadwrite,
|
||||
stacksize >> 32, stacksize, NULL)),
|
||||
|
@ -181,25 +170,47 @@ __msabi static textwindows wontreturn void WinMainNew(const char16_t *cmdline) {
|
|||
_mmi.p[0].flags = 0x00000026; // stack+anonymous
|
||||
_mmi.p[0].size = stacksize;
|
||||
_mmi.i = 1;
|
||||
wa = (struct WinArgs *)(stackaddr + (stacksize - sizeof(struct WinArgs)));
|
||||
struct WinArgs *wa =
|
||||
(struct WinArgs *)(stackaddr + (stacksize - sizeof(struct WinArgs)));
|
||||
|
||||
// parse utf-16 command into utf-8 argv array in argument block
|
||||
int count = GetDosArgv(cmdline, wa->argblock, ARRAYLEN(wa->argblock),
|
||||
wa->argv, ARRAYLEN(wa->argv));
|
||||
for (int i = 0; wa->argv[0][i]; ++i) {
|
||||
if (wa->argv[0][i] == '\\') {
|
||||
wa->argv[0][i] = '/';
|
||||
|
||||
// munge argv so dos paths become cosmo paths
|
||||
for (int i = 0; wa->argv[i]; ++i) {
|
||||
if (wa->argv[i][0] == '\\' && //
|
||||
wa->argv[i][1] == '\\') {
|
||||
// don't munge new technology style paths
|
||||
continue;
|
||||
}
|
||||
if (!WinFileExists(wa->argv[i])) {
|
||||
// don't munge if we're not certain it's a file
|
||||
continue;
|
||||
}
|
||||
// use forward slashes
|
||||
for (int j = 0; wa->argv[i][j]; ++j) {
|
||||
if (wa->argv[i][j] == '\\') {
|
||||
wa->argv[i][j] = '/';
|
||||
}
|
||||
}
|
||||
if (IsAlpha(wa->argv[0][0]) && //
|
||||
wa->argv[0][1] == ':' && //
|
||||
wa->argv[0][2] == '/') {
|
||||
wa->argv[0][1] = wa->argv[0][0];
|
||||
wa->argv[0][0] = '/';
|
||||
// turn c:/... into /c/...
|
||||
if (IsAlpha(wa->argv[i][0]) && //
|
||||
wa->argv[i][1] == ':' && //
|
||||
wa->argv[i][2] == '/') {
|
||||
wa->argv[i][1] = wa->argv[i][0];
|
||||
wa->argv[i][0] = '/';
|
||||
}
|
||||
}
|
||||
|
||||
// translate utf-16 win32 environment into utf-8 environment variables
|
||||
char16_t *env16 = __imp_GetEnvironmentStringsW();
|
||||
GetDosEnviron(env16, wa->envblock, ARRAYLEN(wa->envblock) - 8, wa->envp,
|
||||
ARRAYLEN(wa->envp) - 1);
|
||||
__imp_FreeEnvironmentStringsW(env16);
|
||||
__envp = &wa->envp[0];
|
||||
|
||||
// handover control to cosmopolitan runtime
|
||||
_jmpstack((char *)(stackaddr + (stacksize - sizeof(struct WinArgs))), cosmo,
|
||||
count, wa->argv, wa->envp, wa->auxv);
|
||||
}
|
||||
|
@ -227,7 +238,7 @@ __msabi textwindows int64_t WinMain(int64_t hInstance, int64_t hPrevInstance,
|
|||
if (_weaken(WinMainForked)) {
|
||||
_weaken(WinMainForked)();
|
||||
}
|
||||
WinMainNew(cmdline);
|
||||
WinInit(cmdline);
|
||||
}
|
||||
|
||||
#endif /* __x86_64__ */
|
||||
|
|
|
@ -49,6 +49,7 @@ textwindows int __wsablock(struct Fd *fd, struct NtOverlapped *overlapped,
|
|||
// our i/o operation never happened because it failed
|
||||
return __winsockerr();
|
||||
}
|
||||
TryAgain:
|
||||
// our i/o operation is in flight and it needs to block
|
||||
abort_errno = EAGAIN;
|
||||
if (fd->flags & O_NONBLOCK) {
|
||||
|
@ -87,10 +88,15 @@ textwindows int __wsablock(struct Fd *fd, struct NtOverlapped *overlapped,
|
|||
// we wait for win32 to acknowledge that it's done using that memory.
|
||||
if (WSAGetOverlappedResult(fd->handle, overlapped, &got, true, flags)) {
|
||||
return got;
|
||||
} else if (WSAGetLastError() == kNtErrorOperationAborted) {
|
||||
}
|
||||
switch (WSAGetLastError()) {
|
||||
case kNtErrorIoIncomplete:
|
||||
goto TryAgain;
|
||||
case kNtErrorOperationAborted:
|
||||
errno = abort_errno;
|
||||
return -1;
|
||||
} else {
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,6 +94,12 @@ o/$(MODE)/libc/fmt/strsignal.greg.o: private \
|
|||
-ffreestanding \
|
||||
$(NO_MAGIC)
|
||||
|
||||
# we can't use sanitizers because:
|
||||
# WinMain calls this
|
||||
o/$(MODE)/libc/str/tprecode8to16.o: private \
|
||||
COPTS += \
|
||||
-fno-sanitize=all
|
||||
|
||||
o/$(MODE)/libc/str/eastasianwidth.bin: \
|
||||
libc/str/eastasianwidth.txt \
|
||||
o/$(MODE)/tool/decode/mkwides.com
|
||||
|
|
|
@ -24,8 +24,8 @@
|
|||
#include "libc/str/thompike.h"
|
||||
#include "libc/str/utf16.h"
|
||||
|
||||
/* 34x speedup for ascii */
|
||||
static inline dontasan axdx_t tprecode8to16_sse2(char16_t *dst, size_t dstsize,
|
||||
// 34x speedup for ascii
|
||||
static inline axdx_t tprecode8to16_sse2(char16_t *dst, size_t dstsize,
|
||||
const char *src, axdx_t r) {
|
||||
uint8_t v1[16], v2[16], vz[16];
|
||||
memset(vz, 0, 16);
|
||||
|
@ -62,9 +62,11 @@ axdx_t tprecode8to16(char16_t *dst, size_t dstsize, const char *src) {
|
|||
r.ax = 0;
|
||||
r.dx = 0;
|
||||
for (;;) {
|
||||
#ifdef __x86_64__
|
||||
if (!IsTiny() && !((uintptr_t)(src + r.dx) & 15)) {
|
||||
r = tprecode8to16_sse2(dst, dstsize, src, r);
|
||||
}
|
||||
#endif
|
||||
x = src[r.dx++] & 0377;
|
||||
if (x >= 0300) {
|
||||
a = ThomPikeByte(x);
|
||||
|
|
|
@ -47,6 +47,8 @@ TEST(readlink, enoent) {
|
|||
TEST(readlink, enotdir) {
|
||||
char buf[32];
|
||||
ASSERT_SYS(0, 0, touch("o", 0644));
|
||||
ASSERT_SYS(ENOTDIR, -1, readlink("o/", buf, 32));
|
||||
ASSERT_SYS(ENOTDIR, -1, readlink("o/o/..", buf, 32));
|
||||
ASSERT_SYS(ENOTDIR, -1, readlink("o/doesnotexist", buf, 32));
|
||||
}
|
||||
|
||||
|
@ -95,7 +97,7 @@ TEST(readlinkat, frootloop) {
|
|||
}
|
||||
}
|
||||
|
||||
TEST(readlinkat, statReadsNameLength) {
|
||||
TEST(readlinkat, statReadsNameLength_countsUtf8Bytes) {
|
||||
struct stat st;
|
||||
ASSERT_SYS(0, 0, symlink("froÒt", "froÒt"));
|
||||
ASSERT_SYS(0, 0, fstatat(AT_FDCWD, "froÒt", &st, AT_SYMLINK_NOFOLLOW));
|
||||
|
|
75
test/libc/mem/realpath_test.c
Normal file
75
test/libc/mem/realpath_test.c
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*-*- 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 2023 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/calls.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
char testlib_enable_tmp_setup_teardown;
|
||||
|
||||
void SetUp(void) {
|
||||
touch("conftest.a", 0644);
|
||||
symlink("conftest.a", "conftest.l");
|
||||
mkdir("conftest.d", 0755);
|
||||
}
|
||||
|
||||
TEST(realpath, test1) {
|
||||
char *name = gc(realpath("conftest.a", NULL));
|
||||
ASSERT_TRUE(name && *name == '/');
|
||||
}
|
||||
|
||||
TEST(realpath, test2) {
|
||||
ASSERT_EQ(NULL, gc(realpath("conftest.b/../conftest.a", NULL)));
|
||||
}
|
||||
|
||||
TEST(realpath, test3) {
|
||||
char *name = gc(realpath("conftest.l/../conftest.a", NULL));
|
||||
if (IsWindows()) {
|
||||
// WIN32 acts as a flat namespace, rather than linear inode crawl.
|
||||
// GNU ./configure scripts consider this outcome to be acceptable.
|
||||
ASSERT_NE(NULL, name);
|
||||
} else {
|
||||
// Every other OS FS is a UNIX inode crawl.
|
||||
ASSERT_SYS(ENOTDIR, NULL, name);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(realpath, test4) {
|
||||
ASSERT_SYS(ENOTDIR, NULL, gc(realpath("conftest.a/", NULL)));
|
||||
}
|
||||
|
||||
TEST(realpath, test5) {
|
||||
char *name1 = gc(realpath(".", NULL));
|
||||
char *name2 = gc(realpath("conftest.d//./..", NULL));
|
||||
ASSERT_NE(NULL, name1);
|
||||
ASSERT_NE(NULL, name2);
|
||||
ASSERT_STREQ(name1, name2);
|
||||
}
|
||||
|
||||
TEST(realpath, test6) {
|
||||
// musl libc fails this test
|
||||
// comment say // is special but doesn't say why :/
|
||||
char *name = gc(realpath("//", NULL));
|
||||
ASSERT_NE(NULL, name);
|
||||
EXPECT_STREQ("/", name);
|
||||
}
|
1
third_party/finger/finger.c
vendored
1
third_party/finger/finger.c
vendored
|
@ -45,6 +45,7 @@
|
|||
#include "libc/runtime/utmp.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/sock/struct/sockaddr.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/time/time.h"
|
||||
|
|
|
@ -1458,8 +1458,9 @@ static char *SecondPass2(char *p, struct Input *in) {
|
|||
// the new file size. that's only possible if all the fat ape hdrs
|
||||
// we generate are able to fit inside the prologue.
|
||||
p = ALIGN(p, 8);
|
||||
// TODO(jart): Figure out why not skewing corrupts pe import table
|
||||
in->we_must_skew_pe_vaspace =
|
||||
ROUNDUP(p - prologue + in->size_of_pe_headers,
|
||||
1 || ROUNDUP(p - prologue + in->size_of_pe_headers,
|
||||
(int)in->pe->OptionalHeader.FileAlignment) > in->minload;
|
||||
if (!in->we_must_skew_pe_vaspace) {
|
||||
in->pe_e_lfanew = p - prologue;
|
||||
|
|
Loading…
Reference in a new issue