mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-06 11:18:30 +00:00
Get fork() working on Windows
This is done without using Microsoft's internal APIs. MAP_PRIVATE mappings are copied to the subprocess via a pipe, since Microsoft doesn't want us to have proper COW pages. MAP_SHARED mappings are remapped without needing to do any copying. Global variables need copying along with the stack and the whole heap of anonymous mem. This actually improves the reliability of the redbean http server although one shouldn't expect 10k+ connections on a home computer that isn't running software built to serve like Linux or FreeBSD.
This commit is contained in:
parent
aea89fe832
commit
db33973e0a
105 changed files with 1476 additions and 912 deletions
|
@ -28,10 +28,13 @@
|
|||
/ @param edi is exit code ∈ [0,256)
|
||||
/ @note _exit() is same thing
|
||||
/ @asyncsignalsafe
|
||||
_Exit: orl $RUNSTATE_TERMINATE,g_runstate(%rip)
|
||||
_Exit: push %rbp
|
||||
mov %rsp,%rbp
|
||||
orl $RUNSTATE_TERMINATE,g_runstate(%rip)
|
||||
#if SupportsWindows()
|
||||
testb IsWindows()
|
||||
jz 1f
|
||||
sub $32,%rsp
|
||||
movzbl %dil,%ecx # %ERRORLEVEL% is limitless
|
||||
4: call *__imp_ExitProcess(%rip)
|
||||
jmp 4b
|
||||
|
|
|
@ -25,7 +25,7 @@ bool AreMemoryIntervalsOk(const struct MemoryIntervals *mm) {
|
|||
for (i = 0; i < mm->i; ++i) {
|
||||
if (mm->p[i].y < mm->p[i].x) return false;
|
||||
if (i) {
|
||||
if (mm->h[i] || mm->h[i - 1]) {
|
||||
if (mm->p[i].h || mm->p[i - 1].h) {
|
||||
if (mm->p[i].x <= mm->p[i - 1].y) return false;
|
||||
} else {
|
||||
if (mm->p[i].x <= mm->p[i - 1].y + 1) return false;
|
||||
|
|
|
@ -17,42 +17,10 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/nt/memory.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/runtime/directmap.h"
|
||||
|
||||
static textwindows struct DirectMap DirectMapNt(void *addr, size_t size,
|
||||
unsigned prot, unsigned flags,
|
||||
int fd, int64_t off) {
|
||||
int64_t handle;
|
||||
struct DirectMap res;
|
||||
uint32_t protect, access;
|
||||
if (fd != -1) {
|
||||
handle = g_fds.p[fd].handle;
|
||||
} else {
|
||||
handle = kNtInvalidHandleValue;
|
||||
}
|
||||
protect = prot2nt(prot, flags);
|
||||
access = fprot2nt(prot, flags);
|
||||
if ((res.maphandle =
|
||||
CreateFileMappingNuma(handle, NULL, protect, size >> 32, size, NULL,
|
||||
kNtNumaNoPreferredNode))) {
|
||||
if (!(res.addr = MapViewOfFileExNuma(res.maphandle, access, off >> 32, off,
|
||||
size, addr, kNtNumaNoPreferredNode))) {
|
||||
CloseHandle(res.maphandle);
|
||||
res.maphandle = kNtInvalidHandleValue;
|
||||
res.addr = (void *)(intptr_t)winerr();
|
||||
}
|
||||
} else {
|
||||
res.maphandle = kNtInvalidHandleValue;
|
||||
res.addr = (void *)(intptr_t)winerr();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
struct DirectMap DirectMap(void *addr, size_t size, unsigned prot,
|
||||
unsigned flags, int fd, int64_t off) {
|
||||
if (!IsWindows()) {
|
||||
|
|
|
@ -9,6 +9,7 @@ struct DirectMap {
|
|||
};
|
||||
|
||||
struct DirectMap DirectMap(void *, size_t, unsigned, unsigned, int, int64_t);
|
||||
struct DirectMap DirectMapNt(void *, size_t, unsigned, unsigned, int, int64_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
51
libc/runtime/directmapnt.c
Normal file
51
libc/runtime/directmapnt.c
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/nt/memory.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/runtime/directmap.h"
|
||||
|
||||
textwindows struct DirectMap DirectMapNt(void *addr, size_t size, unsigned prot,
|
||||
unsigned flags, int fd, int64_t off) {
|
||||
int64_t handle;
|
||||
struct DirectMap res;
|
||||
uint32_t protect, access;
|
||||
if (fd != -1) {
|
||||
handle = g_fds.p[fd].handle;
|
||||
} else {
|
||||
handle = kNtInvalidHandleValue;
|
||||
}
|
||||
protect = prot2nt(prot, flags);
|
||||
access = fprot2nt(prot, flags);
|
||||
if ((res.maphandle =
|
||||
CreateFileMappingNuma(handle, NULL, protect, size >> 32, size, NULL,
|
||||
kNtNumaNoPreferredNode))) {
|
||||
if (!(res.addr = MapViewOfFileExNuma(res.maphandle, access, off >> 32, off,
|
||||
size, addr, kNtNumaNoPreferredNode))) {
|
||||
CloseHandle(res.maphandle);
|
||||
res.maphandle = kNtInvalidHandleValue;
|
||||
res.addr = (void *)(intptr_t)winerr();
|
||||
}
|
||||
} else {
|
||||
res.maphandle = kNtInvalidHandleValue;
|
||||
res.addr = (void *)(intptr_t)winerr();
|
||||
}
|
||||
return res;
|
||||
}
|
|
@ -27,12 +27,6 @@
|
|||
#include "libc/str/tpenc.h"
|
||||
#include "libc/str/utf16.h"
|
||||
|
||||
/* TODO(jart): Make early-stage data structures happen. */
|
||||
#undef isspace
|
||||
#undef iswspace
|
||||
#define isspace(c) ((c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r')
|
||||
#define iswspace(c) isspace(c)
|
||||
|
||||
struct DosArgv {
|
||||
const char16_t *s;
|
||||
char *p;
|
||||
|
|
|
@ -25,6 +25,7 @@ void *__cxa_finalize(void *) hidden;
|
|||
void _executive(int, char **, char **, long (*)[2]) hidden noreturn;
|
||||
void __stack_chk_fail(void) noreturn relegated;
|
||||
void __stack_chk_fail_local(void) noreturn relegated hidden;
|
||||
void _jmpstack(void *, void *, ...) hidden noreturn;
|
||||
long _setstack(void *, void *, ...) hidden;
|
||||
int GetDosArgv(const char16_t *, char *, size_t, char **, size_t) hidden;
|
||||
|
||||
|
|
38
libc/runtime/jmpstack.S
Normal file
38
libc/runtime/jmpstack.S
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.h"
|
||||
|
||||
/ Switches stack.
|
||||
/
|
||||
/ @param rdi is new rsp, passed as malloc(size) + size
|
||||
/ @param rsi is function to call in new stack space
|
||||
/ @param rdx,rcx,r8,r9 get passed as args to rsi
|
||||
/ @noreturn
|
||||
_jmpstack:
|
||||
mov %rdi,%rsp
|
||||
mov %rsi,%rax
|
||||
mov %rdx,%rdi
|
||||
mov %rcx,%rsi
|
||||
mov %r8,%rdx
|
||||
mov %r9,%rcx
|
||||
xor %rbp,%rbp
|
||||
call *%rax
|
||||
ud2
|
||||
.endfn _jmpstack,globl,hidden
|
|
@ -30,8 +30,6 @@ static void RemoveMemoryIntervals(struct MemoryIntervals *mm, int i, int n) {
|
|||
assert(i + n <= mm->i);
|
||||
memcpy(mm->p + i, mm->p + i + n,
|
||||
(intptr_t)(mm->p + mm->i) - (intptr_t)(mm->p + i + n));
|
||||
memcpy(mm->h + i, mm->h + i + n,
|
||||
(intptr_t)(mm->h + mm->i) - (intptr_t)(mm->h + i + n));
|
||||
mm->i -= n;
|
||||
}
|
||||
|
||||
|
@ -41,8 +39,6 @@ static void CreateMemoryInterval(struct MemoryIntervals *mm, int i) {
|
|||
assert(mm->i < ARRAYLEN(mm->p));
|
||||
memmove(mm->p + i + 1, mm->p + i,
|
||||
(intptr_t)(mm->p + mm->i) - (intptr_t)(mm->p + i));
|
||||
memmove(mm->h + i + 1, mm->h + i,
|
||||
(intptr_t)(mm->h + mm->i) - (intptr_t)(mm->h + i));
|
||||
++mm->i;
|
||||
}
|
||||
|
||||
|
@ -94,25 +90,31 @@ int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int TrackMemoryInterval(struct MemoryIntervals *mm, int x, int y, long h) {
|
||||
int TrackMemoryInterval(struct MemoryIntervals *mm, int x, int y, long h,
|
||||
int prot, int flags) {
|
||||
unsigned i;
|
||||
assert(y >= x);
|
||||
assert(AreMemoryIntervalsOk(mm));
|
||||
i = FindMemoryInterval(mm, x);
|
||||
if (i && x == mm->p[i - 1].y + 1 && h == mm->h[i - 1]) {
|
||||
if (i && x == mm->p[i - 1].y + 1 && h == mm->p[i - 1].h &&
|
||||
prot == mm->p[i - 1].prot && flags == mm->p[i - 1].flags) {
|
||||
mm->p[i - 1].y = y;
|
||||
if (i < mm->i && y + 1 == mm->p[i].x && h == mm->h[i]) {
|
||||
if (i < mm->i && y + 1 == mm->p[i].x && h == mm->p[i].h &&
|
||||
prot == mm->p[i].prot && flags == mm->p[i].flags) {
|
||||
mm->p[i - 1].y = mm->p[i].y;
|
||||
RemoveMemoryIntervals(mm, i, 1);
|
||||
}
|
||||
} else if (i < mm->i && y + 1 == mm->p[i].x && h == mm->h[i]) {
|
||||
} else if (i < mm->i && y + 1 == mm->p[i].x && h == mm->p[i].h &&
|
||||
prot == mm->p[i].prot && flags == mm->p[i].flags) {
|
||||
mm->p[i].x = x;
|
||||
} else {
|
||||
if (mm->i == ARRAYLEN(mm->p)) return enomem();
|
||||
CreateMemoryInterval(mm, i);
|
||||
mm->p[i].x = x;
|
||||
mm->p[i].y = y;
|
||||
mm->h[i] = h;
|
||||
mm->p[i].h = h;
|
||||
mm->p[i].prot = prot;
|
||||
mm->p[i].flags = flags;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -14,8 +14,10 @@ struct MemoryIntervals {
|
|||
struct MemoryInterval {
|
||||
int x;
|
||||
int y;
|
||||
long h;
|
||||
int prot;
|
||||
int flags;
|
||||
} p[128];
|
||||
long h[128];
|
||||
};
|
||||
|
||||
extern struct MemoryIntervals _mmi;
|
||||
|
@ -23,7 +25,7 @@ extern struct MemoryIntervals _mmi;
|
|||
unsigned FindMemoryInterval(const struct MemoryIntervals *, int) nosideeffect;
|
||||
bool AreMemoryIntervalsOk(const struct MemoryIntervals *) nosideeffect;
|
||||
void PrintMemoryIntervals(int, const struct MemoryIntervals *);
|
||||
int TrackMemoryInterval(struct MemoryIntervals *, int, int, long);
|
||||
int TrackMemoryInterval(struct MemoryIntervals *, int, int, long, int, int);
|
||||
int ReleaseMemoryIntervals(struct MemoryIntervals *, int, int,
|
||||
void (*)(struct MemoryIntervals *, int, int));
|
||||
void ReleaseMemoryNt(struct MemoryIntervals *, int, int);
|
||||
|
|
|
@ -35,7 +35,7 @@ void ReleaseMemoryNt(struct MemoryIntervals *mm, int l, int r) {
|
|||
for (i = l; i <= r; ++i) {
|
||||
ok = UnmapViewOfFile(GetFrameAddr(mm->p[i].x));
|
||||
assert(ok);
|
||||
ok = CloseHandle(mm->h[i]);
|
||||
ok = CloseHandle(mm->p[i].h);
|
||||
assert(ok);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,8 +39,6 @@
|
|||
#define ALIGNED(p) (!(IP(p) & (FRAMESIZE - 1)))
|
||||
#define CANONICAL(p) (-0x800000000000 <= IP(p) && IP(p) <= 0x7fffffffffff)
|
||||
|
||||
struct MemoryIntervals _mmi;
|
||||
|
||||
/**
|
||||
* Beseeches system for page-table entries.
|
||||
*
|
||||
|
@ -92,7 +90,7 @@ void *mmap(void *addr, size_t size, int prot, int flags, int fd, int64_t off) {
|
|||
}
|
||||
a = ROUNDDOWN((intptr_t)addr, FRAMESIZE) >> 16;
|
||||
b = ROUNDDOWN((intptr_t)addr + size - 1, FRAMESIZE) >> 16;
|
||||
if (TrackMemoryInterval(&_mmi, a, b, dm.maphandle) == -1) {
|
||||
if (TrackMemoryInterval(&_mmi, a, b, dm.maphandle, prot, flags) == -1) {
|
||||
abort();
|
||||
}
|
||||
if (weaken(__asan_map_shadow)) {
|
||||
|
|
22
libc/runtime/mmi.c
Normal file
22
libc/runtime/mmi.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 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/runtime/memtrack.h"
|
||||
|
||||
struct MemoryIntervals _mmi;
|
|
@ -30,7 +30,7 @@ textwindows int msync$nt(void *addr, size_t size, int flags) {
|
|||
for (i = FindMemoryInterval(&_mmi, x); i < _mmi.i; ++i) {
|
||||
if ((x >= _mmi.p[i].x && x <= _mmi.p[i].y) ||
|
||||
(y >= _mmi.p[i].x && y <= _mmi.p[i].y)) {
|
||||
FlushFileBuffers(_mmi.h[i]);
|
||||
FlushFileBuffers(_mmi.p[i].h);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ extern int g_argc; /* CRT */
|
|||
extern char **g_argv; /* CRT */
|
||||
extern char **environ; /* CRT */
|
||||
extern unsigned long *g_auxv; /* CRT */
|
||||
extern jmp_buf g_winmain; /* CRT */
|
||||
extern char *program_invocation_name; /* RII */
|
||||
extern char *program_invocation_short_name; /* RII */
|
||||
extern uint64_t g_syscount; /* RII */
|
||||
|
|
|
@ -64,11 +64,6 @@ $(LIBC_RUNTIME_A_OBJS): \
|
|||
OVERRIDE_CFLAGS += \
|
||||
$(NO_MAGIC)
|
||||
|
||||
# @see ape/ape.s for tuning parameters that make this safe
|
||||
o/$(MODE)/libc/runtime/winmain.greg.o: \
|
||||
DEFAULT_CPPFLAGS += \
|
||||
-DSTACK_FRAME_UNLIMITED
|
||||
|
||||
LIBC_RUNTIME_LIBS = $(foreach x,$(LIBC_RUNTIME_ARTIFACTS),$($(x)))
|
||||
LIBC_RUNTIME_SRCS = $(foreach x,$(LIBC_RUNTIME_ARTIFACTS),$($(x)_SRCS))
|
||||
LIBC_RUNTIME_HDRS = $(foreach x,$(LIBC_RUNTIME_ARTIFACTS),$($(x)_HDRS))
|
||||
|
|
|
@ -20,7 +20,10 @@
|
|||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/pushpop.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/nt/console.h"
|
||||
#include "libc/nt/enum/consolemodeflags.h"
|
||||
#include "libc/nt/enum/filetype.h"
|
||||
|
@ -34,8 +37,21 @@
|
|||
#include "libc/nt/struct/teb.h"
|
||||
#include "libc/runtime/getdosenviron.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/memtrack.h"
|
||||
#include "libc/runtime/missioncritical.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/winmain.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
|
||||
struct WinArgs {
|
||||
char *argv[512];
|
||||
char *envp[512];
|
||||
long auxv[1][2];
|
||||
char argblock[ARG_MAX];
|
||||
char envblock[ENV_MAX];
|
||||
};
|
||||
|
||||
static struct CmdExe {
|
||||
bool result;
|
||||
|
@ -46,13 +62,7 @@ static struct CmdExe {
|
|||
} oldin, oldout;
|
||||
} g_cmdexe;
|
||||
|
||||
static textwindows void MitigateDriveByDownloads(void) {
|
||||
unsigned wrote;
|
||||
if (!SetDefaultDllDirectories(kNtLoadLibrarySearchSearchSystem32)) {
|
||||
WriteFile(GetStdHandle(kNtStdErrorHandle), "nodll\n", 6, &wrote, NULL);
|
||||
ExitProcess(1);
|
||||
}
|
||||
}
|
||||
struct WinMain g_winmain;
|
||||
|
||||
static textwindows void RestoreCmdExe(void) {
|
||||
if (g_cmdexe.oldin.handle) {
|
||||
|
@ -104,6 +114,53 @@ static textwindows void NormalizeCmdExe(void) {
|
|||
}
|
||||
}
|
||||
|
||||
static textwindows char *AllocateMemory(void *addr, size_t size, int64_t *h) {
|
||||
return MapViewOfFileExNuma(
|
||||
(*h = CreateFileMappingNuma(-1, NULL, pushpop(kNtPageReadwrite), 0, size,
|
||||
NULL, kNtNumaNoPreferredNode)),
|
||||
kNtFileMapRead | kNtFileMapWrite, 0, 0, size, addr,
|
||||
kNtNumaNoPreferredNode);
|
||||
}
|
||||
|
||||
static textwindows noreturn void WinMainNew(int64_t hInstance,
|
||||
int64_t hPrevInstance,
|
||||
const char *lpCmdLine,
|
||||
int nCmdShow) {
|
||||
int64_t h;
|
||||
size_t size;
|
||||
int i, count;
|
||||
uint64_t data;
|
||||
struct WinArgs *wa;
|
||||
const char16_t *env16;
|
||||
g_winmain.nCmdShow = nCmdShow;
|
||||
g_winmain.hInstance = hInstance;
|
||||
g_winmain.hPrevInstance = hPrevInstance;
|
||||
NormalizeCmdExe();
|
||||
*(/*unconst*/ int *)&hostos = WINDOWS;
|
||||
size = ROUNDUP(STACKSIZE + sizeof(struct WinArgs), FRAMESIZE);
|
||||
data = 0x777000000000;
|
||||
data = (intptr_t)AllocateMemory((char *)data, size, &_mmi.p[0].h);
|
||||
_mmi.p[0].x = data >> 16;
|
||||
_mmi.p[0].y = (data >> 16) + ((size >> 16) - 1);
|
||||
_mmi.p[0].prot = PROT_READ | PROT_WRITE;
|
||||
_mmi.p[0].flags = MAP_PRIVATE | MAP_ANONYMOUS;
|
||||
_mmi.i = pushpop(1L);
|
||||
wa = (struct WinArgs *)(data + size - sizeof(struct WinArgs));
|
||||
count = GetDosArgv(GetCommandLine(), wa->argblock, ARG_MAX, wa->argv, 512);
|
||||
for (i = 0; wa->argv[0][i]; ++i) {
|
||||
if (wa->argv[0][i] == '\\') {
|
||||
wa->argv[0][i] = '/';
|
||||
}
|
||||
}
|
||||
env16 = GetEnvironmentStrings();
|
||||
GetDosEnviron(env16, wa->envblock, ENV_MAX, wa->envp, 512);
|
||||
FreeEnvironmentStrings(env16);
|
||||
wa->auxv[0][0] = pushpop(0L);
|
||||
wa->auxv[0][1] = pushpop(0L);
|
||||
_jmpstack((char *)data + STACKSIZE, _executive, count, wa->argv, wa->envp,
|
||||
wa->auxv);
|
||||
}
|
||||
|
||||
/**
|
||||
* Main function on Windows NT.
|
||||
*
|
||||
|
@ -130,30 +187,15 @@ static textwindows void NormalizeCmdExe(void) {
|
|||
* the downloads folder. Since we don't even use dynamic linking,
|
||||
* we've cargo culted some API calls, that may harden against it.
|
||||
*
|
||||
* 6. Finally, we need fork. Microsoft designed Windows to prevent us
|
||||
* from having fork() so we pass pipe handles in an environment
|
||||
* variable literally copy all the memory.
|
||||
*
|
||||
*/
|
||||
textwindows int WinMain(void *hInstance, void *hPrevInstance,
|
||||
const char *lpCmdLine, int nCmdShow) {
|
||||
char *stack;
|
||||
int i, count;
|
||||
const char16_t *cmd16, *env16;
|
||||
char *argv[512], *envp[512];
|
||||
char argblock[ARG_MAX], envblock[ENV_MAX];
|
||||
long auxv[][2] = {{pushpop(0L), pushpop(0L)}};
|
||||
MitigateDriveByDownloads();
|
||||
NormalizeCmdExe();
|
||||
*(/*unconst*/ int *)&hostos = WINDOWS;
|
||||
cmd16 = GetCommandLine();
|
||||
env16 = GetEnvironmentStrings();
|
||||
count = GetDosArgv(cmd16, argblock, ARG_MAX, argv, 512);
|
||||
for (i = 0; argv[0][i]; ++i) {
|
||||
if (argv[0][i] == '\\') argv[0][i] = '/';
|
||||
}
|
||||
GetDosEnviron(env16, envblock, ENV_MAX, envp, 512);
|
||||
FreeEnvironmentStrings(env16);
|
||||
stack = MapViewOfFileExNuma(
|
||||
CreateFileMappingNuma(-1, NULL, pushpop(kNtPageReadwrite), 0, STACKSIZE,
|
||||
NULL, kNtNumaNoPreferredNode),
|
||||
kNtFileMapRead | kNtFileMapWrite, 0, 0, STACKSIZE,
|
||||
(char *)0x777000000000 - STACKSIZE, kNtNumaNoPreferredNode);
|
||||
return _setstack(stack + STACKSIZE, _executive, count, argv, envp, auxv);
|
||||
textwindows int64_t WinMain(int64_t hInstance, int64_t hPrevInstance,
|
||||
const char *lpCmdLine, int nCmdShow) {
|
||||
SetDefaultDllDirectories(kNtLoadLibrarySearchSearchSystem32);
|
||||
if (weaken(winsockinit)) weaken(winsockinit)();
|
||||
if (weaken(WinMainForked)) weaken(WinMainForked)();
|
||||
WinMainNew(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
|
||||
}
|
||||
|
|
16
libc/runtime/winmain.h
Normal file
16
libc/runtime/winmain.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_RUNTIME_WINMAIN_H_
|
||||
#define COSMOPOLITAN_LIBC_RUNTIME_WINMAIN_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct WinMain {
|
||||
int nCmdShow;
|
||||
int64_t hInstance;
|
||||
int64_t hPrevInstance;
|
||||
};
|
||||
|
||||
extern struct WinMain g_winmain;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_RUNTIME_WINMAIN_H_ */
|
Loading…
Add table
Add a link
Reference in a new issue