From 1d8937d52828b164e9a9b8b0a5d86ed9391c13c9 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Thu, 17 Aug 2023 07:21:13 -0700 Subject: [PATCH] Mint APE Loader v1.7 This change reduces the memory requirements of your APE Loader by 10x, in terms of virtual memory size, thanks to the help of alloca(). We're also now creating argument blocks with the same layout across systems. --- ape/ape-m1.c | 240 +++++++++++++++------------------- ape/ape.S | 4 +- ape/loader.c | 114 +++++++++------- ape/start.S | 3 +- bin/ape-install | 2 + bin/ape-uninstall | 1 + build/bootstrap/ape.aarch64 | Bin 9360 -> 9400 bytes build/bootstrap/ape.elf | Bin 9454 -> 9454 bytes build/bootstrap/ape.macho | Bin 9454 -> 9454 bytes build/bootstrap/ape.silicon | Bin 35160 -> 0 bytes examples/ctrlc.c | 98 ++++++++------ examples/stackexplorer.c | 69 ++++++++++ examples/stat.c | 6 +- examples/statfs.c | 4 +- libc/calls/__sig2.c | 1 + libc/calls/execve-sysv.c | 4 +- libc/calls/getrlimit.c | 4 +- libc/calls/read.c | 2 +- libc/calls/setrlimit.c | 7 + libc/calls/statfs2cosmo.c | 2 +- libc/intrin/describeframe.c | 11 +- libc/runtime/cosmo2.c | 6 +- libc/runtime/runtime.h | 1 + libc/runtime/winmain.greg.c | 28 ++-- test/libc/calls/statfs_test.c | 3 +- tool/build/apelink.c | 4 +- tool/build/lib/errnos.S | 123 ----------------- tool/build/lib/lines.c | 56 -------- tool/build/lib/lines.h | 18 --- tool/build/unbuffer.c | 21 +-- tool/build/x86combos.c | 191 --------------------------- 31 files changed, 367 insertions(+), 656 deletions(-) delete mode 100755 build/bootstrap/ape.silicon create mode 100644 examples/stackexplorer.c delete mode 100644 tool/build/lib/errnos.S delete mode 100644 tool/build/lib/lines.c delete mode 100644 tool/build/lib/lines.h delete mode 100644 tool/build/x86combos.c diff --git a/ape/ape-m1.c b/ape/ape-m1.c index 1cd64af16..f7e7941c7 100644 --- a/ape/ape-m1.c +++ b/ape/ape-m1.c @@ -87,11 +87,9 @@ struct Syslib { #define AT_RANDOM 25 #define AT_EXECFN 31 -#define STACK_SIZE (8ul * 1024 * 1024) -#define STACK_ALIGN (sizeof(long) * 2) -#define AUXV_BYTES (sizeof(long) * 2 * 15) +#define AUXV_WORDS 29 -// from the xnu codebase +/* from the xnu codebase */ #define _COMM_PAGE_START_ADDRESS 0x0000000FFFFFC000ul #define _COMM_PAGE_APRR_SUPPORT (_COMM_PAGE_START_ADDRESS + 0x10C) #define _COMM_PAGE_APRR_WRITE_ENABLE (_COMM_PAGE_START_ADDRESS + 0x110) @@ -149,7 +147,7 @@ union ElfEhdrBuf { union ElfPhdrBuf { struct ElfPhdr phdr; - char buf[4096]; + char buf[1024]; }; struct PathSearcher { @@ -160,15 +158,7 @@ struct PathSearcher { }; struct ApeLoader { - union ElfEhdrBuf ehdr; struct PathSearcher ps; - // this memory shall be discarded by the guest - ////////////////////////////////////////////// - // this memory shall be known to guest program - union { - char argblock[ARG_MAX]; - long numblock[ARG_MAX / sizeof(long)]; - }; union ElfPhdrBuf phdr; struct Syslib lib; char rando[16]; @@ -561,19 +551,15 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd, unsigned long wipe; prot1 = prot; prot2 = prot; - /* - * when we ask the system to map the interval [vaddr,vaddr+filesz) - * it might schlep extra file content into memory on both the left - * and the righthand side. that's because elf doesn't require that - * either side of the interval be aligned on the system page size. - * - * normally we can get away with ignoring these junk bytes. but if - * the segment defines bss memory (i.e. memsz > filesz) then we'll - * need to clear the extra bytes in the page, if they exist. - * - * since we can't do that if we're mapping a read-only page, we'll - * actually map it with write permissions and protect it afterward - */ + /* when we ask the system to map the interval [vaddr,vaddr+filesz) + it might schlep extra file content into memory on both the left + and the righthand side. that's because elf doesn't require that + either side of the interval be aligned on the system page size. + normally we can get away with ignoring these junk bytes. but if + the segment defines bss memory (i.e. memsz > filesz) then we'll + need to clear the extra bytes in the page, if they exist. since + we can't do that if we're mapping a read-only page, we can just + map it with write permissions and call mprotect on it afterward */ a = p[i].p_vaddr + p[i].p_filesz; /* end of file content */ b = (a + (pagesz - 1)) & -pagesz; /* first pure bss page */ c = p[i].p_vaddr + p[i].p_memsz; /* end of segment data */ @@ -648,16 +634,17 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd, __builtin_unreachable(); } -static const char *TryElf(struct ApeLoader *M, const char *exe, int fd, - long *sp, long *bp, char *execfn) { +static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf, + const char *exe, int fd, long *sp, long *auxv, + char *execfn) { long i, rc; unsigned size; struct ElfEhdr *e; struct ElfPhdr *p; /* validate elf header */ - e = &M->ehdr.ehdr; - if (READ32(M->ehdr.buf) != READ32("\177ELF")) { + e = &ebuf->ehdr; + if (READ32(ebuf->buf) != READ32("\177ELF")) { return "didn't embed ELF magic"; } if (e->e_ident[EI_CLASS] == ELFCLASS32) { @@ -678,7 +665,7 @@ static const char *TryElf(struct ApeLoader *M, const char *exe, int fd, } /* read program headers */ - rc = pread(fd, M->phdr.buf, size, M->ehdr.ehdr.e_phoff); + rc = pread(fd, M->phdr.buf, size, ebuf->ehdr.e_phoff); if (rc < 0) return "failed to read ELF program headers"; if (rc != size) return "truncated read of ELF program headers"; @@ -735,26 +722,35 @@ static const char *TryElf(struct ApeLoader *M, const char *exe, int fd, } /* simulate linux auxiliary values */ - long auxv[][2] = { - {AT_PHDR, (long)&M->phdr.phdr}, // - {AT_PHENT, M->ehdr.ehdr.e_phentsize}, // - {AT_PHNUM, M->ehdr.ehdr.e_phnum}, // - {AT_ENTRY, M->ehdr.ehdr.e_entry}, // - {AT_PAGESZ, pagesz}, // - {AT_UID, getuid()}, // - {AT_EUID, geteuid()}, // - {AT_GID, getgid()}, // - {AT_EGID, getegid()}, // - {AT_HWCAP, 0xffb3ffffu}, // - {AT_HWCAP2, 0x181}, // - {AT_SECURE, issetugid()}, // - {AT_RANDOM, (long)M->rando}, // - {AT_EXECFN, (long)execfn}, // - {0, 0}, // - }; - _Static_assert(sizeof(auxv) == AUXV_BYTES, - "Please update the AUXV_BYTES constant"); - MemMove(bp, auxv, sizeof(auxv)); + auxv[0] = AT_PHDR; + auxv[1] = (long)&M->phdr.phdr; + auxv[2] = AT_PHENT; + auxv[3] = ebuf->ehdr.e_phentsize; + auxv[4] = AT_PHNUM; + auxv[5] = ebuf->ehdr.e_phnum; + auxv[6] = AT_ENTRY; + auxv[7] = ebuf->ehdr.e_entry; + auxv[8] = AT_PAGESZ; + auxv[9] = pagesz; + auxv[10] = AT_UID; + auxv[11] = getuid(); + auxv[12] = AT_EUID; + auxv[13] = geteuid(); + auxv[14] = AT_GID; + auxv[15] = getgid(); + auxv[16] = AT_EGID; + auxv[17] = getegid(); + auxv[18] = AT_HWCAP; + auxv[19] = 0xffb3ffffu; + auxv[20] = AT_HWCAP2; + auxv[21] = 0x181; + auxv[22] = AT_SECURE; + auxv[23] = issetugid(); + auxv[24] = AT_RANDOM; + auxv[25] = (long)M->rando; + auxv[26] = AT_EXECFN; + auxv[27] = (long)execfn; + auxv[28] = 0; /* we're now ready to load */ Spawn(exe, fd, sp, e, p, &M->lib); @@ -788,31 +784,17 @@ static long sys_mmap(void *addr, size_t size, int prot, int flags, int fd, int main(int argc, char **argv, char **envp) { long z; void *map; - long *sp, *bp, *ip; int c, i, n, fd, rc; struct ApeLoader *M; - unsigned char rando[24]; + long *sp, *sp2, *auxv; + union ElfEhdrBuf *ebuf; char *p, *pe, *tp, *exe, *prog, *execfn; - // generate some hard random data - if (getentropy(rando, sizeof(rando))) { - Pexit(argv[0], -1, "getentropy"); - } + /* allocate loader memory in program's arg block */ + n = sizeof(struct ApeLoader); + M = __builtin_alloca(n); - // make the stack look like a linux one - map = mmap((void *)(0x7f0000000000 | (long)rando[23] << 32), STACK_SIZE, - PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - if (map == MAP_FAILED) { - Pexit(argv[0], -1, "stack mmap"); - } - - // put argument block at top of allocated stack - z = (long)map; - z += STACK_SIZE - sizeof(struct ApeLoader); - z &= -_Alignof(struct ApeLoader); - M = (struct ApeLoader *)z; - - // expose screwy apple libs + /* expose apple libs */ M->lib.magic = SYSLIB_MAGIC; M->lib.version = SYSLIB_VERSION; M->lib.fork = sys_fork; @@ -833,44 +815,24 @@ int main(int argc, char **argv, char **envp) { M->lib.dispatch_semaphore_wait = dispatch_semaphore_wait; M->lib.dispatch_walltime = dispatch_walltime; - // copy system provided argument block - bp = M->numblock; - tp = M->argblock + sizeof(M->argblock); - *bp++ = argc; - for (i = 0; i < argc; ++i) { - tp -= (n = StrLen(argv[i]) + 1); - MemMove(tp, argv[i], n); - *bp++ = (long)tp; - } - *bp++ = 0; - for (i = 0; envp[i]; ++i) { - tp -= (n = StrLen(envp[i]) + 1); - MemMove(tp, envp[i], n); - *bp++ = (long)tp; - } - *bp++ = 0; - - // get arguments that point into our block - sp = M->numblock; - argc = *sp; - argv = (char **)(sp + 1); - envp = (char **)(sp + 1 + argc + 1); - - // xnu stores getauxval(at_execfn) in getenv("_") + /* getenv("_") is close enough to at_execfn */ execfn = argc > 0 ? argv[0] : 0; for (i = 0; envp[i]; ++i) { if (envp[i][0] == '_' && envp[i][1] == '=') { execfn = envp[i] + 2; - break; } } - // interpret command line arguments + /* sneak the system five abi back out of args */ + sp = (long *)(argv - 1); + auxv = (long *)(envp + i + 1); + + /* interpret command line arguments */ if (argc >= 3 && !StrCmp(argv[1], "-")) { - // if the first argument is a hyphen then we give the user the - // power to change argv[0] or omit it entirely. most operating - // systems don't permit the omission of argv[0] but we do, b/c - // it's specified by ANSI X3.159-1988. + /* if the first argument is a hyphen then we give the user the + power to change argv[0] or omit it entirely. most operating + systems don't permit the omission of argv[0] but we do, b/c + it's specified by ANSI X3.159-1988. */ prog = (char *)sp[3]; argc = sp[3] = sp[0] - 3; argv = (char **)((sp += 3) + 1); @@ -887,19 +849,41 @@ int main(int argc, char **argv, char **envp) { argv = (char **)((sp += 1) + 1); } - // search for executable + /* create new bottom of stack for spawned program + system v abi aligns this on a 16-byte boundary + grows down the alloc by poking the guard pages */ + n = (auxv - sp + AUXV_WORDS + 1) * sizeof(long); + sp2 = __builtin_alloca(n); + if ((long)sp2 & 15) ++sp2; + for (; n > 0; n -= pagesz) { + ((char *)sp2)[n - 1] = 0; + } + MemMove(sp2, sp, (auxv - sp) * sizeof(long)); + argv = (char **)(sp2 + 1); + envp = (char **)(sp2 + 1 + argc + 1); + auxv = sp2 + (auxv - sp); + sp = sp2; + + /* allocate ephemeral memory for reading file */ + n = sizeof(union ElfEhdrBuf); + ebuf = __builtin_alloca(n); + for (; n > 0; n -= pagesz) { + ((char *)ebuf)[n - 1] = 0; + } + + /* search for executable */ if (!(exe = Commandv(&M->ps, prog, GetEnv(envp, "PATH")))) { Pexit(prog, 0, "not found (maybe chmod +x)"); } else if ((fd = openat(AT_FDCWD, exe, O_RDONLY)) < 0) { Pexit(exe, -1, "open"); - } else if ((rc = read(fd, M->ehdr.buf, sizeof(M->ehdr.buf))) < 0) { + } else if ((rc = read(fd, ebuf->buf, sizeof(ebuf->buf))) < 0) { Pexit(exe, -1, "read"); - } else if ((unsigned long)rc < sizeof(M->ehdr.ehdr)) { + } else if ((unsigned long)rc < sizeof(ebuf->ehdr)) { Pexit(exe, 0, "too small"); } - pe = M->ehdr.buf + rc; + pe = ebuf->buf + rc; - // resolve argv[0] to reflect path search + /* resolve argv[0] to reflect path search */ if ((argc > 0 && *prog != '/' && *exe == '/' && !StrCmp(prog, argv[0])) || !StrCmp(BaseName(prog), argv[0])) { tp -= (n = StrLen(exe) + 1); @@ -907,28 +891,20 @@ int main(int argc, char **argv, char **envp) { argv[0] = tp; } - // squeeze and align the argument block - ip = (long *)(((long)tp - AUXV_BYTES) & -sizeof(long)); - ip -= (n = bp - sp); - ip = (long *)((long)ip & -STACK_ALIGN); - MemMove(ip, sp, n * sizeof(long)); - bp = ip + n; - sp = ip; + /* generate some hard random data */ + if (getentropy(M->rando, sizeof(M->rando))) { + Pexit(argv[0], -1, "getentropy"); + } - // relocate the guest's random numbers - MemMove(M->rando, rando, sizeof(M->rando)); - Bzero(rando, sizeof(rando)); - - // ape intended behavior - // 1. if file is an elf executable, it'll be used as-is - // 2. if ape, will scan shell script for elf printf statements - // 3. shell script may have multiple lines producing elf headers - // 4. all elf printf lines must exist in the first 8192 bytes of file - // 5. elf program headers may appear anywhere in the binary - if (READ64(M->ehdr.buf) == READ64("MZqFpD='") || - READ64(M->ehdr.buf) == READ64("jartsr='") || - READ64(M->ehdr.buf) == READ64("APEDBG='")) { - for (p = M->ehdr.buf; p < pe; ++p) { + /* ape intended behavior + 1. if ape, will scan shell script for elf printf statements + 2. shell script may have multiple lines producing elf headers + 3. all elf printf lines must exist in the first 8192 bytes of file + 4. elf program headers may appear anywhere in the binary */ + if (READ64(ebuf->buf) == READ64("MZqFpD='") || + READ64(ebuf->buf) == READ64("jartsr='") || + READ64(ebuf->buf) == READ64("APEDBG='")) { + for (p = ebuf->buf; p < pe; ++p) { if (READ64(p) != READ64("printf '")) { continue; } @@ -946,15 +922,15 @@ int main(int argc, char **argv, char **envp) { } } } - M->ehdr.buf[i++] = c; - if (i >= sizeof(M->ehdr.buf)) { + ebuf->buf[i++] = c; + if (i >= sizeof(ebuf->buf)) { break; } } - if (i >= sizeof(M->ehdr.ehdr)) { - TryElf(M, exe, fd, sp, bp, execfn); + if (i >= sizeof(ebuf->ehdr)) { + TryElf(M, ebuf, exe, fd, sp, auxv, execfn); } } } - Pexit(exe, 0, TryElf(M, exe, fd, sp, bp, execfn)); + Pexit(exe, 0, TryElf(M, ebuf, exe, fd, sp, auxv, execfn)); } diff --git a/ape/ape.S b/ape/ape.S index ed97635b0..292216969 100644 --- a/ape/ape.S +++ b/ape/ape.S @@ -610,7 +610,7 @@ apesh: .ascii "\n@\n#'\"\n" // sixth edition shebang // extract the loader into a temp folder, and use it to // load the APE without modifying it. .ascii "[ x\"$1\" != x--assimilate ] && {\n" - .ascii "t=\"${TMPDIR:-${HOME:-.}}/.ape-1.6\"\n" + .ascii "t=\"${TMPDIR:-${HOME:-.}}/.ape-1.7\"\n" .ascii "[ -x \"$t\" ] || {\n" .ascii "mkdir -p \"${t%/*}\" &&\n" .ascii "dd if=\"$o\" of=\"$t.$$\" skip=" @@ -818,7 +818,7 @@ ape.ident: .long 1 1: .asciz "APE" 2: .balign 4 -3: .long 106000000 +3: .long 107000000 4: .size ape.ident,.-ape.ident .type ape.ident,@object .previous diff --git a/ape/loader.c b/ape/loader.c index 065b0444a..2b5d898d9 100644 --- a/ape/loader.c +++ b/ape/loader.c @@ -158,7 +158,7 @@ { \ char ibuf[19] = {0}; \ Utox(ibuf, VAR); \ - Print(os, 2, #VAR " ", ibuf, "\n", 0l); \ + Print(os, 2, ibuf, " " #VAR, "\n", 0l); \ } struct ElfEhdr { @@ -196,7 +196,7 @@ union ElfEhdrBuf { union ElfPhdrBuf { struct ElfPhdr phdr; - char buf[4096]; + char buf[1024]; }; struct PathSearcher { @@ -208,7 +208,6 @@ struct PathSearcher { }; struct ApeLoader { - union ElfEhdrBuf ehdr; union ElfPhdrBuf phdr; struct PathSearcher ps; char path[1024]; @@ -622,7 +621,6 @@ __attribute__((__noreturn__)) static void Spawn(int os, const char *exe, int fd, found_code = 0; found_entry = 0; virtmin = virtmax = 0; - if (!pagesz) pagesz = 4096; if (pagesz & (pagesz - 1)) { Pexit(os, exe, 0, "AT_PAGESZ isn't two power"); } @@ -715,19 +713,15 @@ __attribute__((__noreturn__)) static void Spawn(int os, const char *exe, int fd, unsigned long wipe; prot1 = prot; prot2 = prot; - /* - * when we ask the system to map the interval [vaddr,vaddr+filesz) - * it might schlep extra file content into memory on both the left - * and the righthand side. that's because elf doesn't require that - * either side of the interval be aligned on the system page size. - * - * normally we can get away with ignoring these junk bytes. but if - * the segment defines bss memory (i.e. memsz > filesz) then we'll - * need to clear the extra bytes in the page, if they exist. - * - * since we can't do that if we're mapping a read-only page, we'll - * actually map it with write permissions and protect it afterward - */ + /* when we ask the system to map the interval [vaddr,vaddr+filesz) + it might schlep extra file content into memory on both the left + and the righthand side. that's because elf doesn't require that + either side of the interval be aligned on the system page size. + normally we can get away with ignoring these junk bytes. but if + the segment defines bss memory (i.e. memsz > filesz) then we'll + need to clear the extra bytes in the page, if they exist. since + we can't do that if we're mapping a read-only page, we can just + map it with write permissions and call mprotect on it afterward */ a = p[i].p_vaddr + p[i].p_filesz; /* end of file content */ b = (a + (pagesz - 1)) & -pagesz; /* first pure bss page */ c = p[i].p_vaddr + p[i].p_memsz; /* end of segment data */ @@ -768,8 +762,9 @@ __attribute__((__noreturn__)) static void Spawn(int os, const char *exe, int fd, Launch(IsFreebsd() ? sp : 0, dynbase + e->e_entry, sp, os); } -static const char *TryElf(struct ApeLoader *M, const char *exe, int fd, - long *sp, long *auxv, unsigned long pagesz, int os) { +static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf, + const char *exe, int fd, long *sp, long *auxv, + unsigned long pagesz, int os) { long i, rc; unsigned size; struct ElfEhdr *e; @@ -782,8 +777,8 @@ static const char *TryElf(struct ApeLoader *M, const char *exe, int fd, } /* validate elf header */ - e = &M->ehdr.ehdr; - if (READ32(M->ehdr.buf) != READ32("\177ELF")) { + e = &ebuf->ehdr; + if (READ32(ebuf->buf) != READ32("\177ELF")) { return "didn't embed ELF magic"; } if (e->e_ident[EI_CLASS] == ELFCLASS32) { @@ -891,7 +886,7 @@ static __attribute__((__noreturn__)) void ShowUsage(int os, int fd, int rc) { Print(os, fd, "NAME\n" "\n" - " actually portable executable loader version 1.6\n" + " actually portable executable loader version 1.7\n" " copyright 2023 justine alexandra roberts tunney\n" " https://justine.lol/ape.html\n" "\n" @@ -909,14 +904,14 @@ static __attribute__((__noreturn__)) void ShowUsage(int os, int fd, int rc) { Exit(rc, os); } -__attribute__((__noreturn__)) // -void ApeLoader(long di, long *sp, char dl) { - int rc; - unsigned i, n; +__attribute__((__noreturn__)) void ApeLoader(long di, long *sp, char dl) { + int rc, n; + unsigned i; int c, fd, os, argc; struct ApeLoader *M; unsigned long pagesz; - long *auxv, *ap, *ew; + union ElfEhdrBuf *ebuf; + long *auxv, *ap, *endp, *sp2; char *p, *pe, *exe, *ape, *prog, **argv, **envp; (void)Utox; @@ -935,7 +930,7 @@ void ApeLoader(long di, long *sp, char dl) { argc = *sp; argv = (char **)(sp + 1); envp = (char **)(sp + 1 + argc + 1); - auxv = (long *)(sp + 1 + argc + 1); + auxv = sp + 1 + argc + 1; for (;;) { if (!*auxv++) { break; @@ -960,15 +955,12 @@ void ApeLoader(long di, long *sp, char dl) { os = NETBSD; } } - ew = ap + 1; + if (!pagesz) { + pagesz = 4096; + } + endp = ap + 1; - /* allocate loader memory */ - n = sizeof(*M) / sizeof(long); - MemMove(sp - n, sp, (char *)ew - (char *)sp); - sp -= n, argv -= n, envp -= n, auxv -= n; - M = (struct ApeLoader *)(ew - n); - - /* default operating system */ + /* the default operating system */ if (!os) { os = LINUX; } @@ -1005,17 +997,43 @@ void ApeLoader(long di, long *sp, char dl) { argv = (char **)((sp += 1) + 1); } + /* allocate loader memory in program's arg block */ + n = sizeof(struct ApeLoader); + M = __builtin_alloca(n); + + /* create new bottom of stack for spawned program + system v abi aligns this on a 16-byte boundary + grows down the alloc by poking the guard pages */ + n = (endp - sp + 1) * sizeof(long); + sp2 = __builtin_alloca(n); + if ((long)sp2 & 15) ++sp2; + for (; n > 0; n -= pagesz) { + ((char *)sp2)[n - 1] = 0; + } + MemMove(sp2, sp, (endp - sp) * sizeof(long)); + argv = (char **)(sp2 + 1); + envp = (char **)(sp2 + 1 + argc + 1); + auxv = (char **)(sp2 + (auxv - sp)); + sp = sp2; + + /* allocate ephemeral memory for reading file */ + n = sizeof(union ElfEhdrBuf); + ebuf = __builtin_alloca(n); + for (; n > 0; n -= pagesz) { + ((char *)ebuf)[n - 1] = 0; + } + /* resolve path of executable and read its first page */ if (!(exe = Commandv(&M->ps, os, prog, GetEnv(envp, "PATH")))) { Pexit(os, prog, 0, "not found (maybe chmod +x or ./ needed)"); } else if ((fd = Open(exe, O_RDONLY, 0, os)) < 0) { Pexit(os, exe, fd, "open"); - } else if ((rc = Pread(fd, M->ehdr.buf, sizeof(M->ehdr.buf), 0, os)) < 0) { + } else if ((rc = Pread(fd, ebuf->buf, sizeof(ebuf->buf), 0, os)) < 0) { Pexit(os, exe, rc, "read"); - } else if ((unsigned long)rc < sizeof(M->ehdr.ehdr)) { + } else if ((unsigned long)rc < sizeof(ebuf->ehdr)) { Pexit(os, exe, 0, "too small"); } - pe = M->ehdr.buf + rc; + pe = ebuf->buf + rc; /* change argv[0] to resolved path if it's ambiguous */ if ((argc > 0 && *prog != '/' && *exe == '/' && !StrCmp(prog, argv[0])) || @@ -1028,10 +1046,10 @@ void ApeLoader(long di, long *sp, char dl) { 2. shell script may have multiple lines producing elf headers 3. all elf printf lines must exist in the first 8192 bytes of file 4. elf program headers may appear anywhere in the binary */ - if (READ64(M->ehdr.buf) == READ64("MZqFpD='") || - READ64(M->ehdr.buf) == READ64("jartsr='") || - READ64(M->ehdr.buf) == READ64("APEDBG='")) { - for (p = M->ehdr.buf; p < pe; ++p) { + if (READ64(ebuf->buf) == READ64("MZqFpD='") || + READ64(ebuf->buf) == READ64("jartsr='") || + READ64(ebuf->buf) == READ64("APEDBG='")) { + for (p = ebuf->buf; p < pe; ++p) { if (READ64(p) != READ64("printf '")) { continue; } @@ -1049,15 +1067,15 @@ void ApeLoader(long di, long *sp, char dl) { } } } - M->ehdr.buf[i++] = c; - if (i >= sizeof(M->ehdr.buf)) { + ebuf->buf[i++] = c; + if (i >= sizeof(ebuf->buf)) { break; } } - if (i >= sizeof(M->ehdr.ehdr)) { - TryElf(M, exe, fd, sp, auxv, pagesz, os); + if (i >= sizeof(ebuf->ehdr)) { + TryElf(M, ebuf, exe, fd, sp, auxv, pagesz, os); } } } - Pexit(os, exe, 0, TryElf(M, exe, fd, sp, auxv, pagesz, os)); + Pexit(os, exe, 0, TryElf(M, ebuf, exe, fd, sp, auxv, pagesz, os)); } diff --git a/ape/start.S b/ape/start.S index 7a99d6f38..c75183c8e 100644 --- a/ape/start.S +++ b/ape/start.S @@ -32,7 +32,6 @@ XnuEntrypoint: mov $_HOSTXNU,%dl // xnu's not unix! ElfEntrypoint: mov %rsp,%rsi // save real stack - sub $1024*1024,%rsp // room for allocs call ApeLoader .endfn ElfEntrypoint,globl .endfn XnuEntrypoint,globl @@ -65,7 +64,7 @@ ape.ident: .long 1 1: .asciz "APE" 2: .balign 4 -3: .long 106000000 +3: .long 107000000 4: .size ape.ident,.-ape.ident .type ape.ident,@object diff --git a/bin/ape-install b/bin/ape-install index 2552a1f4a..829e27c58 100755 --- a/bin/ape-install +++ b/bin/ape-install @@ -23,6 +23,8 @@ echo "Author: Justine Tunney " >&2 if [ -f o/depend ] && make -j8 o//ape; then echo "successfully recompiled ape loader" >&2 +elif [ -x o//ape/ape.elf ] && [ -x o//ape/ape.macho ]; then + echo "using ape loader you compiled earlier" >&2 elif [ -d build/bootstrap ]; then # if make isn't being used then it's unlikely the user changed the sources # in that case the prebuilt binaries should be completely up-to-date diff --git a/bin/ape-uninstall b/bin/ape-uninstall index e50d8b60e..f18c38473 100755 --- a/bin/ape-uninstall +++ b/bin/ape-uninstall @@ -48,6 +48,7 @@ for x in .ape \ .ape-1.4 \ .ape-1.5 \ .ape-1.6 \ + .ape-1.7 \ .ape-blink-0.9.2 \ .ape-blink-1.0.0; do rm -f \ diff --git a/build/bootstrap/ape.aarch64 b/build/bootstrap/ape.aarch64 index 329e3eb31d06b9f7c7f4fed5859319cd91dd3c0d..6dfb4e999b1fdda9239de6e7ff971a459e2ff139 100755 GIT binary patch delta 3549 zcmZWseQ;A%7C-mhBu(42P212kZ6QgkE9GOcLZPTTeTj7ybP+H+!`E(Giv!ZtZNNX4 zU7V!Qaj{{sms>3Y3oYnM;^?A)YZqoL>MB^4nHJWMmC>|T`3UaPD$=LL?C+%sI_{gf zIp>}8yZ4^2d+tlyyw~QnO=hE_d``vfMU;3_l+^Ke24ccclX`X8xLg(DrriG*o_L2X zk%HOXb<4+b+%Qgq$@c+HVj>0mNuFT)*u4iIRu-~Jm$SvWeI$T90Qdp2xkSr~9HD^s zR^`Z#_i+mP4RVHG#y->Ua zli3Eovw2N@_G{G^^3!zkRh!B0l1oi@6?bA=GSH&VwY2^?pr3Odc^h(H0Ju1XY8ibG=qV6WYzKh!{OeE$HkoXwWJLSamn|`)kp>~|oNRUQfO{9OJ zL&Sjm7P4wi7dumx{HQ|=L0*g!`WmIAN4i!vr%xy@jNI~Fykqb-RVza|b!Dp>0aMRe z=-2Y)^vMq_@P>mKs#c##ho%#S6v_`x;aQ<|3hSNE3R(x}kmhAsy#Ymut=qP7hval< z4-bqqVzE$usK`PEtq57`<0e(x!iqzTSm=SrRQa}IYK?MBWQZ5a+cF%}ap2oyPpaLQ z{&-jTi>dR%(WFCgZi;u*A)bZtF^9)()nSbJkYl|X{^k8FJd;%I%5pT}1|FV$a%MBR7$j4j&&MJ zT*3g%Ai9AEYq&7301w(f0`~(MXyKXU3tZoHze~IhKs19Yzr{teE}QxuebO^}+Cti1 zlt6sb&3#@f?)?U_P+gRJa20hk^mO;_B;1!aY>PLzd#^(0B=X;zPCot88Q{ecFN}?6 zs(qu-5w$F4Z@NN6CHGWcc2)r!@NbF7eVwb+?u6AV++y&QE2N@Hx^S!M9ed^K`l^~V zsx*M^`HK9_Y2uYkB)~My6X_|M14G4B$jfkn6-(*dW1HvsjFhZmYS&2l|x!x zIvuJe>+ob4n4gIDL`S5)$R+MZ_jH!fT9=W0zuaUMX=%a51AKx!lH&+mAlytirk#yy zcV`22t7)UNyTBtIZQd27BFZO3W)a!oK${-&h666K8zEkYYv?0H?zDll7w|st#`m7T zf_EbvdYuf7^+=!Y&@sroz#j!gx+5n+-8pJNLn*aQPE)mWO^6Qi8Rh24GClV&*n{q; z8=}j+EpFjU%A0XougkZ)#e$^#7&aS7tl@~5l1>lco*c*8BHp9!#5Y3+@STmpZX-E^ z{R6nKQ+KuQpGy1XX{3I^sgabtP9Dp( z2RhB<+lOopB8#8%l8Am@hZ410h(H%bp2t>$Xp<-4h6_75$rkHE&`Zno5)Ag&SV-ti zRzs@{DC3uAnO&_4>>~dFT&zY&%0c%vsNFwYU*8XLEl6y#6`RaOudC+yu}{b1zO(Yd zyg9#GitC;?x~d4p;WVqmbPzUC zT1n`b%iwJbw)W@0d1GkSKVKYaKXr1%HZ(Ny;lXQp7dV@9@La(^*aW%|k59${(jP0v zGz^^CZhp`$mohMJWbvFv91nh4xR!Zh@GP86$>`TvFjK^Da3?3EZ zHH;ec;3X(#%%DC9WMYa7V+;cy+>SD4lZPEMXWoqW6%1>`;Uz}Ac(R-RoV`2Cn>EoRE$x|iJeBcu zdWU&?TFo=29mbu8U7QZ)7foP!sqcDBNj$;jvae{iY$`rqp0E$XEf@;^445tBkmxue zd{QLj=Vfz=-SJi`G)XOt!DAwqd>PtZXfZ#0(2|JJa9ouGC3dz@Y9-IJqq1wF-ErVY z>*%vMrIRZApk0{!JMqJ{IAzjm$tKwyuH-HolImelE3`pbG0Dz?a^9pF_+39~#=O+u zlGHk8n41S{k7tcb5-|jumz1aMcO@rGgnWGEVeI?k)uyGi2i?y5I2)7x(i!PTlg1sD z;nF#|DK}GeiyQ_fl?_#vm(58}IlE9kgtyg6*H_DMSvB0afZrvu{D$iECz4h@B8T11 F{{eBMef|Id delta 3527 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 delta 3337 zcmY*ce{dAl9pAmXz{!v75dw`^oQqlEBE!fHVDAXQtlWk7;yXn7ol;GUAWb?ngp{L`Nq(g{7L@%MUPghizJEI)q8H0q(-Sb z0650aZfADU5^V5MVsBAzd4Sjpiu032k7u=Ql;6;{YFoB$X1ot3o`eG7x*ASdud4+t z_!e~);Y{7c@Gp|d4eF(g4-jvF=6duJV$a59 ztaPpxq*WU+oxommLROww4#r;1Je)0Ar{wOKUfh+?7Xoi3@Zv+n5d1E48AjzJ?6{P7*Ld#lR3x$d~8B{vEAz@AirU>E{+;`LQ0#vpoShDwU6>SI3=`}1vkV9sW0Hga~g66SFTutd+v;D9Mdyjkn!-qAGV0es9>l zNciTk`ysJ*Au{hY;kyt}g;;<}D7ieWO^2OQYZ$+hj*p1OBS?va{KiL+3Rd+KwMH@b z$*AUWQCy_(J}iiJB#ITWj>g1?r_>n9CI=p!gT@;FjwB5~1$1H^kN84I!oJWA67MHD zq(K*Ap9`@)LQKAPpjfzBM(kCyN%E?X5-7uVt?whisa!ZPiv?3iVY1-w%VK{C_9_1w z2h#h>%X+N*txWl8Vi$dk-p(ZZGRpcslI$l+Z9h#G4*u8b7#ccb?~y4#!>S%uYYuMI z%vTcdQ8ucm)lNV$ewvi`vE&C-x#t5KY;O<|`1Z>ONOFuQ8~RDI&xh<5f&Ath?{<%R zC#YFSxX+Cr2?;d4LNqHXjv9&_5o*=upP3bn+URMd;MdU1jVPV9@F)I(IKz>k(V&@L z{_L!1&34Tk@K6UY9Ur`@$NBe!=RE|aRw!vZ2=C*){-GTE+Q(`Ho8*unCHEmX0wg|r zel}zOR+P;gC;>-?4?A9|lO#z=^@84|Dcz^=ZARDBCP*@czA!5><}|Ykg`OuUYkf%L zC$*lDfM$LwKO4|Pn)#2wv$FpUQEPpaS_dQ4YKjSOI-l~JqYZTuCyM3I&b}pELooMZ ztnwmBoUY8cf&qrZsjK@^))rM~=&IJTL!$6xA*xg% zyvvOkGtGU{J>gh4W&{ z@2IE22g~A!ev69OyeLspZR#e%&!_k`$A$!s+vGe1R1G4G%DJmREE2>r5X%H{8;C7} zxEaKLK}0}Uf>36H`U@!1aY9^|d9C>2g>|SxCa9HB`vIBp^O)X6lCwJhTJaK@<}VgM zm({jw+x(06jWBdJ6aFPJKTotzhINJHJffsOLjGb!6TY6TsMTfH?4p7VR3VJz+z zID9ldh`ZQcpoy)*m!8Kj$36Ep)Dk_id%iUFdf}stzZow$zw-tDCNv!bG~5U<>zMFT zUoR{`K^U!`vay2L<^=Yrc{vC_C$b`%4p&MDse=x6yfl67WAt4pm|*u`(bEn+`$QATnyy#EKX6tS&ZZ$^3q)4kdD() zibUIh82%GrnZ2MEG__vxZBxAegqw^HIWxWx@Wx6MD<+CHKIX40uwE?IpG~dj;otxLow!o%$lJeJbQT4F#_Y(FSXPghIu{W5cd4 zo0mo7D&1*`dMClY$(*>8Dyi$P>y-F{Mv!sbqf_oM{{}qX_`?JG!2{Jx$*YOOgXhS5Np&m^`j+N~iAG0MX`B%Cl%-$!PlS_?i^V;3Y6Tboz?$YEx z4-9NW+*`#1Zw1PxiV^PLRxzgynV8NB;XTe8RLY#(WmFv{vN^n>{o2fy6-xKnqa+&u zcwm}!tI|D4`E|P#8^LMbEbt%_0#kdkYn5LXub*_>kfM^LM;Ld88S05Bh9ANgKL>7X w6&EHl{C{4djtS>qaHD>wpU2@fkWR;seORi_&Nl~EycnfH`L1Ji6@Qff1JlMceE^RK&UB{x z$G&sVIrp63Jzw{Js(z|I{@CQ=Qpf-Nic4R3@;2%Jun(P<9+C=^9qaQBx`}_3UYKZb z{yrzCIN@^DN-rjsxyq$|iHBXoQYP`;+-((=H#i(*F5W!D;n?Kp%7G8Y-&)1Y+*={w zm&mO1-FPpVrKJfeZ+A@PBg#spUa6~R{EZdFzaagS?W7;`bqH|8OMIO9=7fyHzE0ax z$Vbr`WVG9IvQiY!lF?E!Cq4)dndQ`%WjQ>J9fVOectVZ~LXlru7Vsx2*u8Vc zLTWl0FiNKAqfWW~*AVKXIaz|NWab}Xe-hfO0xa0G^G>xX6;RD;iOj0P#LM~9Vub-} z8VIEC0;mm&wJeb7R(UdW?5pU6{R7NgZ`lSSW`jihq#8UWo0k#DNYjNtt?8=N1Cks+ z3P!EDqcWf`!Ri232D#=fbG4n%m*c<0l8h~GX8brCa~}1%)sc6}h_$%MU_LiF$s6G* zCY@Kyhgo?)tLUahS>={SGRVUaY(g46(3}l5=tRo9Sw;VU)vB0t>1=Ygcv)o#YL#%o zc=c@JTfC}SlS9Fit;JN)Q)@;mx7cU?_Lr6wvkx8Nry~6HP??2L>pOg9uIOz0n;WgP zzfR3Xe65@GS3G2BsHmu~jN(_cflRST#2v&V?#y}O_3q3WGO~3?W{V{h-Bdm%zH{aH z<8VlPjnAXr6r}??gBkf*_;DOGYiu z6Y_Z}nA%o^`Wcz#a114cS>sVat3hv#k-wMX@Ea8hmxV&JP>`-QPa`3lIH0kf)ur;jc+XIreKsBm~@z<#QI18Rp<(f09vwA(*9?DY`942{bF9nZp z6omQt$JqUKscz z48$+W?dxE}e?~N;$EmGX^s&TXfj72N(Nh*8ZH4{)6S~umYnHVRn+$AHRuezYd+auw zAo|Um*a|kq5eYf|?=LJ1Mx>)+7<77(A35A}v;bc{HCYINYI$d^;D>rZ*C}#WFTNX5 z8%qNe3?cXWO;a$%#7R7MyI9DmQJr|Q@M|k5)yVTUe1AAw0BYZACw~WW zGTuGR^vwP!5ps5-V0y(l4=X#ap$da-W+mXMN72+32I-5R+@>A|p8i4JQ6#(-L3}wE> z0M0Gc#}&sL@E)~1_IcI>jht1b3sgSB_}_({U%<}&>x7j_u(APGc+b!?C>?Nukb0ZZiaEDUcs5@Fraf`{}KEyCQeNfQ{ zy%EE$Hg>CKD2a(2?j$|ji6JhC?N=SzaKu>cj>OMs`OLiOI#7krjRlPsLfOck4p#m2?&iyJq)HBZ%hJek*p zEKfOxT68G-HA()7xOF1NMvv0g>bO;F#z%5Qo5)=7bHHHyQu@8mEel={xCMK_O201F zv849(E@33ZKlbhE z7U9M>?{!mUeMg8#_LCX%$)ukfR(Y?9S>Ko1B-22>+8CES2x};Ny=al{S>51G7Vl=Hh{oxdc&Jc9YzG7_p^Yqr!;1=Q%7Q zW|wWzT;Q_PYNdaJk=>q*21U1Cmmv2-In2+YT^Sc6Uvz9v`n}IEgTe>U^$#2M2gEGH z{-LL1u*uBQNm!`Hi^8vJbP0fr52X8tg=uXbisJKPB>6~oJrnDX#rpZ|dI|;$T&1Vm zNaXld@scnnz5x|Hp!lbm8WefTXg%QX2d<+c(Dsh{C(?)4zyzdEK>s!9$CG$~@t*CI z^s7r+O2GWO|X zw>zcD)QO24s#$7FwB_o{Tbh6HP;`TLR-`e>oZ%G1Ajr&%1iz_O;<4rSU*VsTx!p;@ z)=oLL`?mS;{GBx6 zv?6}u=)}9zxyYbCx<*^Hmn3~?Zrio|mbr4*TYD)7rgO$QGvuy*m5-Vw;5!9x9n=cI zgpLbban{F5=91M*yT(K&q8`Ri4n>eM71zK6_aK6t z`6K&%-}n7~zCYjhy}LrM&|e%WxmYTFOnD(p_@|`p zGf9d_&bIu9;IY7&Nd88!PR`~@s9gSjes5?*{y6`=qQ@%Ld6Goz>Rq=>(q5@E08@;g z+rsRkh1lT3#NMdh_8_t66z9i_p2%vODZi<0(l&0|z<3W#9DxGix*ASduc-wr_(pX( z;Y?l6@Gp|d_3NdK_Ytp;=DPF}V$a+ITsK2br_>1CleD(g*)*$Fa^IbbMeCuEthBEX zq*WU+oxpB$Oje#;0>*C5Jd`b2t>o^UT-=?|=K^mT@Ztl+5kp=GU(xkAMp4=U}QkTAys69n-J?mOvt0VtAD=}kyNRvOOpu0wgi{TlcWd6dgj=Az;J!*MBqtpoVD=8r z2h7;@GT~=wHu;ufyU22;;c}wRPA!qlgskMA2dB<%S(1PmCHH%*ED~CFf2j51R3+De zC9xXA%tAdxsmkcJcZt;$CSa72Acx<-gl|Vc6=DG@q2%(gHW_wGtzrCXIzA*Ck02!y@*5vQDp=Kz)f&azBcqxp zL~)VA`>`O_;V4$bIvNuno>F5Zo9ugR1{!PhTaq;R6wrxvBH{}j4*NnkNxYZjkOp0d zeI~?q2{HNl{$k-~8L^j7C&_C*N}vqewZ4x4r*dKcG!{%Dg~@`yFN^(!*r)s}97yj= zFYB@LH#6mDh+Xs%dOMTs$tY`jNV1nGwY@Z1IPhPqBWUQ1y-TM2EUS7%tvRqxGha@? zN7<;NRx1I;_!&~(!;Y3el{nIBF?Y3APp$7KH-qSl%ywGKq6)esZjv_IuHM+@pCP87?Zn|@oihG6c+Smh;> zJdea(Cb=QKSQ|YR&`t#5OIk^vC;TcyTQ-vlw8twY;Ii^JG8OlQwGBk>)wZON#}u(w z%}eot6z@>mAtCy{S>(3SdGVU()o+6X1Op6*Q&;z-tc|M9&{fT42Swq@TvVw-c$XV8 zrlynU^=$rUGd5=%;pcX`^Sm&>!+8`yLTN{?z`K3D{yESq8yDTIt2HF4t1-oVS~w^a zguNK*lj4`f0gq|xMbWe^0Nq3651likD8)9d9gah`Q`D+YDEUpOzO{MLFJ ze5fpr=r^i}&5IHx)uOH^{6dOfcWg-DxQ)+3K-D0^sGPeT#5_SP2C-NWcYxR^h+9GI z6GQ}rB?x6Is6T@uZ70Qbnb(RRnOlb{WP(~5wI7rjzkumoBsnYcuNE(qY5r32vsrD6 zw%NaEUk^iP1L0o~^RqI=AiC-kPkO2qve#S0-!>{mZJjq>mdr1CxIPhWZ-t}mAL2Lfm)(RcFvY2UN3x@@i*cH=eNGVUxlV)fQB0ZW*rw^>T84r zCC-+Z@9lHLnEW=U7%m)8cHh+abE<>JKn=2n z=$bgXE(7KWn3T7xWBB5Y(TZk4Q?8fwBD@ORVX-A)c0x~Se+3bfws9$h5%}bDSY+(i zCQ$7atNl!SP7w}IdqJ;?_nS9lu^)!E#vPm>#>GG$&EgaVocTx&A}`Gq4(d1^rAV|5 zh`~Psmf3S^K~w8R-!{ejPq@kWfHUQD0dFirv0|cFqa*&h0_*u={prMdHqJZDInB5m z+6zkVC*m<+&kRB&o*iKPikrgdD2?~~*D~CrcDpKaPI#{qqP&ZD=L*fm z=GZ+=v%wq&6Hh396GeUiainvjhss6o-KEddS|>uj%TVyT5N)s$NGMcHJT~m=vRPR) zuF{#7sCNqNTgF5f-0h1@R_36~TYayCEYitk~XgIU8pLRCx|It2ucXUym{q1a+ z@>A}zOwy2yJE@%x$480X9OR#qgmgN7{DV?;dVZ>++CX9q1tZ*qJcVovOMXd6a=;Mk z2ap&9$%@b>f$j$(o5oU_M*}plO^YE-n#2hyPH6gd+hP;i$Y}GhAw+^W+TXcXHbPCh z-`D+Pcfar6WSDc#%$%9|&6zVZ7v15#%b$Fm#2Cl$@Ca!L_Bh72G7%JG;}A*^jK;E} z+ZWxv$grHG*FJLLYej#@k)A&wqtRHtXjS>O$#Qw=S{aM*@emIM%3(CR%Oq)2|^0r$5)(C2hHtPRzX9I^Uld{@y|6j4Ha^b_4yk{gYU4eP88RYq&W z8k@{tJ07k=Mc^0dei)l2Q7H0py;bt9%FceO2O&&npJ%UqvVoQHNzIcVS`266*>3!W^c;V)RKR-P>t+*IALLT^ z8!A|fVF7D1;O80X@vNo$9P;Vo*w2eNR^G!)A^rrj>qX%-em0RoeDQIXN<4@B=Q-pB zz5mzjUd`wCcr=r5@{H==w9AsR(4#S>dbHnD@@|jBS}*hVMd+Gal{BrF^OBBj0k&#; zM5cR&_r5ihK9Pke{jEN>isH8sYrS!DnVj>AtOl{x8!yX-^6AczY=kW9`$)-m9&zI4 zErupO(XI6+DD^^Cqg&{?gW9`@g|yAmWBBX(LCuyehDKiFwx*aCi=W1CXIZT1h-h<2Ol< z{r*IDSC25p7Xo&7Jj{X{6PTx27#nzMFkJ2zvV8ijEZ7R1dwF&!6Xh-o8s9%#M-S>C zonxT$%Mr}ex?x?gbufH51A2`KER-uqp^lTeZp~!oF~+mCOBgFZgu1mH0_tCa_SU8( zx|1H-VyNYk-2W+PeLFd+;MgW^Z7cHbj0gP%TiXJ-M7m!>R3=-y;@>cOn^knZ6vhK;<= z?d8~E{Qe<>bZ$poAEI9(^o)kBCT^uXD2ICPjYqlk^w46ooiOiuS+OzH*u_Msn4%gRe3*EZDztzU-^Yfx_6A;tdJ=_HSyWBu7& z`yPufHPkdBHIyw#1%Afngn1Tfdy&l``|J_M`7k#O*P)G6e(?h4=@VEeN6@%6(4B+6 zdtn!Tl(BprKBVDNPwC@Re=d9-F7F-Ik?9*Ju-%ft=Byu47TUm+8js z{t)S_zY5Pe@X}DdihMof`>(+6USefRdlb0?@}A4#IoyjwdNO_ZVbE^ra(K2z*kV`* zTL-4;y+WpsNBaYDYpawR%81|y) zw6&ALYcaQIOr~OC7qOevpqt;QG=&iMUKh96^c z8SS=0w+`i}A{e>E+Ny{SqMt&3KibiO@tlJG<9A6JA>eF_^F8{?_0B^g6xT92d!f$ zUUkr#PVwr4))a~@2dz4a?FX$RC|-Zi3QSOs&$rm!oqMulK=;U-1HO;X4d^*tU_ZvE z^rju%rH{NYP_yjhu)GI#=W4ch``SAOO8r;!x9X6;dG-77HT_dTk6ZRgcfq^Q4?KDD zoq=)Z&JFlsQybd0yLA(#f>N|Kahz08gSG;1#H$V_VxHEZt%=DLTMi~_DYhR>#GI-@ zTXQB#yB4FZh1|G6>j>Bm<{$aC#AN2V0zcZ!Wd+*eU}LZmVbbQcm?+SZDsbL%voCdq3_R_bAua?c?SjNnf##i*yFIxo{=qv zH!$~y9U>hzHEUV(#Ek< zxd=pyOLkBPo7WaGj~_Ny$nk;2$YVszLuU!ob!nN- zor|zU_JwR%5A^}Qzxz#x;=i>V?=HrkW@ydgB6111HKKpv&GFcWreYtOhJ9!{_MxMI zM+U}rw0Cepyhp>NqkS*78@9dG;UGWFq5dymmzq>%Opk-_+^Ez=etQ1~Wvw0D_yg!E zhrX52Yk>Y0-mh$BUeqV!+%ZLJ(iG^^_1F)X;#qme4N{Z-&%8`uz`nPm0emm^8(Bzm zNKM*=7DLu1?OtPo)L#NwP>9F=IL>!b5PX-gSMI?6Zyff2Pp3RPkz)dRgd4R z1J1O6qdi$E_|nl*=xxRh-HkO<`#ouw@w)6l7wnbRv{J}&;JcqkUap6ErfeF&_YTYf z!U^`YqQk+OE})J+*kumN>b}R)Y2Wpxp?A6DE+40JZwI|SQNiI|;IJCwWjf9Q zi>$q)Vz3}T{uSoY_8}}MX9t!9!{vml1z7k$X5MzhKG>Z9InLWbvS)d3HhhXVMGEcz(Pv(=cElTkQoh(Fq z3|b@jNiBxcU&98FFCKQStSe(M2Qsi0jmBCu&WC;2?gJ*pZ_->nYZ}_ujgt4f)hHj{ z%$*wC7>~Knd5#^Nl#ls-sN+s{sxXfACt|L{zC2#+`MpTPkD@cIs}vnKg6n4;>vgY7ymFz404(sm~Qha{cwU$eE z7jmq?r)B*MF!q>}1xeti_UrRuyZuk2?x`3T{I=arm?c?j@{_H#`AOEPh;#F6p%?S@ zR5Rwqb(pi%zdnPKw`8RJ`;*W1gLvVGu}pq;=)-rwp66V_T_i&GcNem#wRb1n9l=M$vR z68Q4~%9i3>R)cd1){NXY&7i~1sej5HS2RLC2`%S>;$Cz`YFnz-rE;_m zyovl{pg(}T`zlz$P<~pEhSt?fcfQu4!PwxOVxW1+5J#s`pMu6$v2Jka7xot$1-uWz z9wXAP?5MN41?`%L`gHPHJ=5m{)})ip-0e66FJ_tU91eT_!I7s5aXzDc7uARF2QrF* z&0?0}&bd!Hw{#+{ombY%KG?Sw{U#khs$ia9K;8-*X|GRf{guJ+cDC)xw`WbVrv+_(V!C`NyZunzu49+%!k5oVIHl z`jYIFMlV>Jc2UEQ0ASPJF=**eK;@mVBQfPggK1|#o^8LUMddjbv)WT0_{#f z`!yH`E#?C6>7B=pUVwdB>{3%ZV}}ncRp!4P?Y)RKIfym+3fAN=um+?3h7|Mxd$evH z=BB%a^CV&2`2_3Edz+H>j;ysE31gjUORcwgV(V({S;}x#XNn6CAgn~j%UE1 zfu1*7+V&h{Lg1MhoA;by@qqCr3R*7zb~thPYL9- zKANTHxd7MJy602iM)r9UZ8^hf0=-|t?_CPdwp@q34)z^I(1-Ep#(cTvectDoYji&E zNe%v@tyuACihs}YUH&TkIA5rY0iAOX%vWf9!;*0zU-45~&{GN&Ildjr;BUFQ227c+ z(4-IJWcVBOeepi?UKq(jP1NW#C+U9^He-OXjWHFKn0 zUY?sL9i=mtlpK8JFzVjTk8vNH!uro+UXTxx=Mu_^5nX*~3kQ94PFuiVeQ)|>=wR`| zU)&3fI`|B?7UQ(Nn0X4Zrj-1s9q0Ag@_C)ZdA)ZOgFndd)uN1lloV=#FKCDVBO7bO z{H5|(JG&~8zE2oiOaA3*yT|%|2)U>Y&hzW3E#m@LG9|pD97Ah#xhQ1)UE6HPFKL3W zIN@(BPO0h3vv}voYXVPSfDNI&#(B~}5%z0CV@G-D%;bj;${t9V+XIYlgAP0Fv*(!P zr8!A{SwO&h<8FFyJOUvB0ps3HzDI|Uh(Pb&k`ZVwry-Cn(ECSPJH{Z8za5J(4nf}6 zBBp)jM1)BQ@P!_-YsTy0XT%SBVao?@QtXl5NfBR>r`RFc?TM)heGk?VN^6@Iv3a!p zR@kSUf0|Oh2eJalpy#Djj4Rb4)9}~BG}gIc8vD6n8fS%JdQ23Z8%5_u(X*oHxl!~j zQS_}*ba51YTNGUyMK6n@4N>$RQS{wW^qMGoLlphPD7sCdo%k}1V^<%{edUpq2sp`4 zID9Zn#1P*aDO7ECnHyXVo4tuSU8c%fvA*79XN^u%wfPp&WH*bVSY}v$yLeBL;r2Ub zPNP3(P0P#6yHAG{dMM9LQF&&_d1fkkOqH%iQ(aw?Xtz0BriwbVXkKrwY*ffPo2km| z5S`XKE50!mXXee-RiYgZYqiBC&YCgnX0fKx>9RJMMN^%5y{VzfVGvXKF2*>CKn@e0{Yiy_zv+GSw6=t#0Qg5pg zr>@UoHoLijIn1Ui=CavDXFXcVs5@qd!{)d}WcXiPW3twntHgEFN!nl&85SwzVG+3t z<;*Uz#_AH+IjkTRqDI8ZwnvRZ-2V ztW^y+xfK(slC zTzJcKxwE0Z(n9FEn$RD!(QbhuIISDZs0N*} z;S*hgrQX!gBr8DAsvV|!QBmZKLVzIr#w;#JV?(70EfwV~wl&|Fi+W)(ImNPazx}|k=+h6Tp2OC zDw|ox6hm)YCmQZtB_fy2(Zr}xcH;x4sw#(QZGe4NI~sux8G_wtTeF5n9d^`MXA@`6 zy*YpOH3g;))h5~=Fgw;jbtE}bkkTW~yC#FvTwPCtAQ!7M*+nykNVK^uW`|RJ!0MpM z6x~3YxlMMP745oe=GF#6a_RD-h00);-DX_H>{hcfvzM=wmo7U$;do?H%xl) z<*^*ocg)0NUna+je@$(ndk094cYbm_DiUWz;?a?KOe9vm^-h()Ri<+Ey*I_!*T^w_ z4^2GbOfh|DO!1^h42)%7lw;PSMCzX^0xAM30xAM30xAM30xAM30xAM30xAM30xAM3 z0xAM30xAM30xAM30xAM30xAM30xAM30xAM30xAM30xAM30xAM30xAM30xAM30xAM3 z0xAM30xAM30xAM30xAM30xAM30xAM30xAM30xAM30xAM30xAM30{?pmh^V>@;RA%p z2+CamAn-&k2#{&|x4(xTnU-)HfHWjg%5k_rfWt@o+!Taa2uSDdN2o(Mfba(d9mlvC z2=ft^A*?}IkI;^Qe*~O+0pZ^fP9mH`xQM`b#-$+SA(SFKgn(N;xdDVM0lE-M5LV&l z0;AC=-$??(yx!_!MpI>_+394)iVbFmjTtNJY?ZY}T;<}j)|+M4iKxozw3}R&7NgUQ zJ6$X`huK((dpKO*oaD4tH<;?avD7*f)j6zg9WKjIDq3T6)H15qTy3pVh{#dVs}omeG|D3Rsu^Sb&M&llkuP2A#U2g zXxjM}F8c$nhx>_azNBg-r`#?<0=hS1BnY}wgLt|Z0x^;Db3Oiy=BLH*vt#)0#_**v z{E8SJ=6{X;hhzBtG5o<8{%8z;B8ER1!+#jVpNZi=j^PJl_+Si=J9e*We{u{zI))z~ z!%vCfXT|VR41a$N|4c|vuPP18LmbjJzZZz3WLwLye0{QG%jl;@S|F6mCIVdpjE^oLyF|4Da= zp_QM@e@W_uB|ia%QzR?{GMF5ZJa+L)LD{BHi*sMN)v(Z}&6{%Yi%)a@ zblJNzaK!YNU$)G9n>~8(9r}6gD|IjSrp1+PzCC5{=DgQ-T(|90eMP-F;dEYE*5CT} zJi2q|L(i;u@-@rHzb#tXS@;<@?&5z}|Nk_7(#>1!Kf3?OcgBCp RDqlF=ImMPawfU~j{{lzvw%Gsx diff --git a/examples/ctrlc.c b/examples/ctrlc.c index b8a1cb1d2..8fa769f2f 100644 --- a/examples/ctrlc.c +++ b/examples/ctrlc.c @@ -10,53 +10,75 @@ #include "libc/calls/calls.h" #include "libc/calls/struct/sigaction.h" #include "libc/errno.h" -#include "libc/log/check.h" -#include "libc/log/color.internal.h" -#include "libc/log/log.h" -#include "libc/mem/mem.h" -#include "libc/nt/thread.h" #include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" -#include "libc/str/str.h" -#include "libc/sysv/consts/exit.h" -#include "libc/sysv/consts/fileno.h" +#include "libc/sysv/consts/limits.h" #include "libc/sysv/consts/sig.h" -volatile bool gotctrlc; - -void GotCtrlC(int sig) { - gotctrlc = true; +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 } int main(int argc, char *argv[]) { - ssize_t rc; - size_t got, wrote; - unsigned char buf[512]; - struct sigaction saint = {.sa_handler = GotCtrlC}; - fprintf(stderr, "This echos stdio until Ctrl+C is pressed.\n"); - CHECK_NE(-1, sigaction(SIGINT, &saint, NULL)); + + printf("echoing stdin until ctrl+c is pressed\n"); + + // you need to set your signal handler using sigaction() rather than + // signal(), since the latter uses .sa_flags=SA_RESTART, which means + // read will restart itself after signals, rather than raising EINTR + sigaction(SIGINT, &(struct sigaction){.sa_handler = SignalHandler}, 0); + for (;;) { - rc = read(0, buf, 512); - if (rc != -1) { - got = rc; - } else { - CHECK_EQ(EINTR, errno); - break; + + // 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 + char buf[PIPE_BUF]; + + // read data from standard input + // + // since this is a blocking operation and we're not performing a + // cpu-bound operation it is almost with absolute certainty that + // when the ctrl-c signal gets delivered, it'll happen in read() + // + // 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. + int got = read(0, buf, sizeof(buf)); + + // check if the read operation failed + // negative one is the *only* return value to indicate errors + if (got == -1) { + if (errno == EINTR) { + // a signal handler was invoked during the read operation + // since we have only one such signal handler it's sigint + // if we didn't have any signal handlers in our app, then + // we wouldn't need to check this errno. using SA_RESTART + // is another great way to avoid having to worry about it + // 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"); + exit(0); + } else { + // log it in the unlikely event something else went wrong + perror(""); + exit(1); + } } - if (!got) break; - rc = write(1, buf, got); - if (rc != -1) { - wrote = rc; - } else { - CHECK_EQ(EINTR, errno); - break; + + // check if the user typed ctrl-d which closes the input handle + if (!got) { + printf("got eof\n"); + exit(0); } - CHECK_EQ(got, wrote); + + // relay read data to standard output + // + // it's usually safe to ignore the return code of write. the + // operating system will send SIGPIPE if there's any problem + // which kills the process by default + write(1, buf, got); } - if (gotctrlc) { - fprintf(stderr, "Got Ctrl+C\n"); - } else { - fprintf(stderr, "Got EOF\n"); - } - return 0; } diff --git a/examples/stackexplorer.c b/examples/stackexplorer.c new file mode 100644 index 000000000..13f60f134 --- /dev/null +++ b/examples/stackexplorer.c @@ -0,0 +1,69 @@ +#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/mem/alg.h" +#include "libc/mem/mem.h" +#include "libc/runtime/runtime.h" +#include "libc/stdio/stdio.h" +#include "libc/x/xasprintf.h" + +/** + * @fileoverview Process Initialization Stack Explorer + */ + +struct Thing { + intptr_t i; + char *s; +}; + +struct Things { + size_t n; + struct Thing *p; +} things; + +void Append(intptr_t i, char *s) { + things.p = realloc(things.p, ++things.n * sizeof(*things.p)); + things.p[things.n - 1].i = i; + things.p[things.n - 1].s = s; +} + +int Compare(const void *a, const void *b) { + struct Thing *x = (struct Thing *)a; + struct Thing *y = (struct Thing *)b; + if (x->i < y->i) return +1; + if (x->i > y->i) return -1; + return 0; +} + +int main(int argc, char *argv[]) { + Append((uintptr_t)__builtin_frame_address(0), "__builtin_frame_address(0)"); + Append((uintptr_t)__oldstack, "__oldstack"); + for (int i = 0;; ++i) { + Append((uintptr_t)&argv[i], xasprintf("&argv[%d] = %`'s", i, argv[i])); + if (!argv[i]) break; + Append((uintptr_t)argv[i], xasprintf("argv[%d] = %`'s", i, argv[i])); + } + for (int i = 0;; ++i) { + Append((uintptr_t)&environ[i], + xasprintf("&environ[%d] = %`'s", i, environ[i])); + if (!environ[i]) break; + Append((uintptr_t)environ[i], + xasprintf("environ[%d] = %`'s", i, environ[i])); + } + for (int i = 0;; i += 2) { + Append((uintptr_t)&__auxv[i], xasprintf("&auxv[%d] = %ld", i, __auxv[i])); + if (!__auxv[i]) break; + Append((uintptr_t)&__auxv[i + 1], + xasprintf("&auxv[%d] = %#lx", i + 1, __auxv[i + 1])); + } + qsort(things.p, things.n, sizeof(*things.p), Compare); + for (int i = 0; i < things.n; ++i) { + printf("%012lx %s\n", things.p[i].i, things.p[i].s); + } +} diff --git a/examples/stat.c b/examples/stat.c index 5ad75aa02..080e2d3be 100644 --- a/examples/stat.c +++ b/examples/stat.c @@ -7,8 +7,8 @@ │ • http://creativecommons.org/publicdomain/zero/1.0/ │ ╚─────────────────────────────────────────────────────────────────*/ #endif -#include "libc/calls/calls.h" #include "libc/calls/struct/stat.h" +#include "libc/calls/calls.h" #include "libc/errno.h" #include "libc/fmt/conv.h" #include "libc/fmt/fmt.h" @@ -90,6 +90,10 @@ void PrintFileMetadata(const char *pathname, struct stat *st) { int main(int argc, char *argv[]) { size_t i; struct stat st; + if (argc <= 1) { + PrintFileMetadata(".", &st); + return 0; + } for (i = 1; i < argc; ++i) { if (!strcmp(argv[i], "-n")) { numeric = true; diff --git a/examples/statfs.c b/examples/statfs.c index 1c5560dca..ce6367794 100644 --- a/examples/statfs.c +++ b/examples/statfs.c @@ -40,7 +40,9 @@ dontinline void ShowIt(const char *path) { "total file nodes in filesystem"); printf("f_ffree = %,zu (%s)\n", sf.f_ffree, "free file nodes in filesystem"); - printf("f_fsid = %#lx (%s)\n", sf.f_fsid, "filesystem id"); + printf("f_fsid = %#lx (%s)\n", + sf.f_fsid.__val[0] | (uint64_t)sf.f_fsid.__val[1] << 32, + "filesystem id"); printf("f_owner = %#lx (%s)\n", sf.f_owner, "user that created mount"); printf("f_namelen = %,zu (%s)\n", sf.f_namelen, "maximum length of filenames"); diff --git a/libc/calls/__sig2.c b/libc/calls/__sig2.c index a82910732..a1bd6d9a5 100644 --- a/libc/calls/__sig2.c +++ b/libc/calls/__sig2.c @@ -180,6 +180,7 @@ textwindows bool __sig_handle(int sigops, int sig, int si_code, case (intptr_t)SIG_DFL: if (__sig_is_fatal(sig)) { STRACE("terminating on %G", sig); + _restorewintty(); ExitProcess(sig); } // fallthrough diff --git a/libc/calls/execve-sysv.c b/libc/calls/execve-sysv.c index 68853b8e1..19f0352d5 100644 --- a/libc/calls/execve-sysv.c +++ b/libc/calls/execve-sysv.c @@ -85,8 +85,8 @@ int sys_execve(const char *prog, char *const argv[], char *const envp[]) { (CanExecute((ape = "/usr/bin/ape")) || CanExecute((ape = Join(firstnonnull(getenv("TMPDIR"), firstnonnull(getenv("HOME"), ".")), - ".ape-1.6", buf))) || - CanExecute((ape = Join(firstnonnull(getenv("HOME"), "."), ".ape-1.6", + ".ape-1.7", buf))) || + CanExecute((ape = Join(firstnonnull(getenv("HOME"), "."), ".ape-1.7", buf))))) { shargs[0] = ape; shargs[1] = "-"; diff --git a/libc/calls/getrlimit.c b/libc/calls/getrlimit.c index 8ec08d5dd..54f66935c 100644 --- a/libc/calls/getrlimit.c +++ b/libc/calls/getrlimit.c @@ -43,8 +43,8 @@ int getrlimit(int resource, struct rlimit *rlim) { } else if (!IsWindows()) { rc = sys_getrlimit(resource, rlim); } else if (resource == RLIMIT_STACK) { - rlim->rlim_cur = (uintptr_t)ape_stack_memsz; - rlim->rlim_max = (uintptr_t)ape_stack_memsz; + rlim->rlim_cur = GetStaticStackSize(); + rlim->rlim_max = GetStaticStackSize(); rc = 0; } else if (resource == RLIMIT_AS) { rlim->rlim_cur = __virtualmax; diff --git a/libc/calls/read.c b/libc/calls/read.c index 7beb98342..fc2914b9c 100644 --- a/libc/calls/read.c +++ b/libc/calls/read.c @@ -26,10 +26,10 @@ #include "libc/intrin/asan.internal.h" #include "libc/intrin/strace.internal.h" #include "libc/intrin/weaken.h" +#include "libc/runtime/zipos.internal.h" #include "libc/sock/internal.h" #include "libc/sock/sock.h" #include "libc/sysv/errfuns.h" -#include "libc/runtime/zipos.internal.h" /** * Reads data from file descriptor. diff --git a/libc/calls/setrlimit.c b/libc/calls/setrlimit.c index 21779e720..e43e05cb9 100644 --- a/libc/calls/setrlimit.c +++ b/libc/calls/setrlimit.c @@ -23,6 +23,7 @@ #include "libc/intrin/asan.internal.h" #include "libc/intrin/describeflags.internal.h" #include "libc/intrin/strace.internal.h" +#include "libc/macros.internal.h" #include "libc/sysv/consts/rlimit.h" #include "libc/sysv/errfuns.h" @@ -31,6 +32,12 @@ * * The following resources are recommended: * + * - `RLIMIT_STACK` controls how much stack memory is available to the + * main thread. This setting is inherited across fork() and execve() + * Please note it's only safe for Cosmopolitan programs, to set this + * value to at least `PTHREAD_STACK_MIN * 2`. On Windows this cannot + * be used to extend the stack, which is currently hard-coded. + * * - `RLIMIT_AS` limits the size of the virtual address space. This will * work on all platforms except WSL. It is emulated on XNU and Windows * which means it won't propagate across execve() currently. diff --git a/libc/calls/statfs2cosmo.c b/libc/calls/statfs2cosmo.c index 084417657..60cc73805 100644 --- a/libc/calls/statfs2cosmo.c +++ b/libc/calls/statfs2cosmo.c @@ -278,7 +278,7 @@ void statfs2cosmo(struct statfs *f, const union statfs_meta *m) { f_files = m->netbsd.f_files; f_ffree = m->netbsd.f_ffree; f_fsid = m->netbsd.f_fsid; - f_namelen = f->f_namelen; + f_namelen = 511; f_frsize = m->netbsd.f_bsize; f_flags = m->netbsd.f_flags; f_owner = m->netbsd.f_owner; diff --git a/libc/intrin/describeframe.c b/libc/intrin/describeframe.c index 8d13ba28e..a651a825f 100644 --- a/libc/intrin/describeframe.c +++ b/libc/intrin/describeframe.c @@ -48,13 +48,10 @@ static const char *GetFrameName(int x) { } else if (IsMemtrackFrame(x)) { return "memtrack"; } else if (IsOldStackFrame(x)) { - return "oldstack"; - } else if (IsWindows() && - (((GetStaticStackAddr(0) + GetStackSize()) >> 16) <= x && - x <= ((GetStaticStackAddr(0) + GetStackSize() + - sizeof(struct WinArgs) - 1) >> - 16))) { - return "mainstack"; + return "system stack"; + } else if (((GetStaticStackAddr(0) + GetStackSize()) >> 16) <= x && + x <= ((GetStaticStackAddr(0) + GetStackSize() - 1) >> 16)) { + return "static stack"; } else if ((int)((intptr_t)__executable_start >> 16) <= x && x <= (int)(((intptr_t)_end - 1) >> 16)) { return "image"; diff --git a/libc/runtime/cosmo2.c b/libc/runtime/cosmo2.c index 3cae9c5d0..e999b31c7 100644 --- a/libc/runtime/cosmo2.c +++ b/libc/runtime/cosmo2.c @@ -110,9 +110,9 @@ wontreturn textstartup void cosmo(long *sp, struct Syslib *m1) { // get page size unsigned long pagesz = 4096; - for (int i = 0; auxv[i]; auxv += 2) { - if (auxv[0] == AT_PAGESZ) { - pagesz = auxv[1]; + for (int i = 0; auxv[i]; i += 2) { + if (auxv[i] == AT_PAGESZ) { + pagesz = auxv[i + 1]; break; } } diff --git a/libc/runtime/runtime.h b/libc/runtime/runtime.h index cebe1fb5e..b69815b8e 100644 --- a/libc/runtime/runtime.h +++ b/libc/runtime/runtime.h @@ -83,6 +83,7 @@ extern char kTmpPath[]; extern const char kNtSystemDirectory[]; extern const char kNtWindowsDirectory[]; extern size_t __virtualmax; +extern size_t __stackmax; extern bool __isworker; /* utilities */ void _intsort(int *, size_t); diff --git a/libc/runtime/winmain.greg.c b/libc/runtime/winmain.greg.c index 918e8285e..361fd022b 100644 --- a/libc/runtime/winmain.greg.c +++ b/libc/runtime/winmain.greg.c @@ -48,6 +48,7 @@ #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" #include "libc/runtime/winargs.internal.h" #include "libc/sock/internal.h" @@ -119,9 +120,9 @@ __msabi static textwindows void DeduplicateStdioHandles(void) { } __msabi static textwindows wontreturn void WinMainNew(const char16_t *cmdline) { + size_t stacksize; struct WinArgs *wa; - size_t allocsize, stacksize; - uintptr_t stackaddr, allocaddr; + uintptr_t stackaddr; __oldstack = (intptr_t)__builtin_frame_address(0); if (NtGetPeb()->OSMajorVersion >= 10 && (intptr_t)v_ntsubsystem == kNtImageSubsystemWindowsCui) { @@ -138,26 +139,23 @@ __msabi static textwindows wontreturn void WinMainNew(const char16_t *cmdline) { _mmi.n = ARRAYLEN(_mmi.s); stackaddr = GetStaticStackAddr(0); stacksize = GetStaticStackSize(); - allocaddr = stackaddr; - allocsize = stacksize + sizeof(struct WinArgs); __imp_MapViewOfFileEx((_mmi.p[0].h = __imp_CreateFileMappingW( -1, &kNtIsInheritable, kNtPageExecuteReadwrite, - allocsize >> 32, allocsize, NULL)), - kNtFileMapWrite | kNtFileMapExecute, 0, 0, allocsize, - (void *)allocaddr); + stacksize >> 32, stacksize, NULL)), + kNtFileMapWrite | kNtFileMapExecute, 0, 0, stacksize, + (void *)stackaddr); int prot = (intptr_t)ape_stack_prot; if (~prot & PROT_EXEC) { - uint32_t oldprot; - __imp_VirtualProtect((void *)allocaddr, allocsize, kNtPageReadwrite, - &oldprot); + uint32_t old; + __imp_VirtualProtect((void *)stackaddr, stacksize, kNtPageReadwrite, &old); } - _mmi.p[0].x = allocaddr >> 16; - _mmi.p[0].y = (allocaddr >> 16) + ((allocsize - 1) >> 16); + _mmi.p[0].x = stackaddr >> 16; + _mmi.p[0].y = (stackaddr >> 16) + ((stacksize - 1) >> 16); _mmi.p[0].prot = prot; _mmi.p[0].flags = 0x00000026; // stack+anonymous - _mmi.p[0].size = allocsize; + _mmi.p[0].size = stacksize; _mmi.i = 1; - wa = (struct WinArgs *)(allocaddr + stacksize); + wa = (struct WinArgs *)(stackaddr + (stacksize - sizeof(struct WinArgs))); int count = GetDosArgv(cmdline, wa->argblock, ARRAYLEN(wa->argblock), wa->argv, ARRAYLEN(wa->argv)); for (int i = 0; wa->argv[0][i]; ++i) { @@ -169,7 +167,7 @@ __msabi static textwindows wontreturn void WinMainNew(const char16_t *cmdline) { GetDosEnviron(env16, wa->envblock, ARRAYLEN(wa->envblock) - 8, wa->envp, ARRAYLEN(wa->envp) - 1); __imp_FreeEnvironmentStringsW(env16); - _jmpstack((char *)(stackaddr + stacksize - (intptr_t)ape_stack_align), cosmo, + _jmpstack((char *)(stackaddr + (stacksize - sizeof(struct WinArgs))), cosmo, count, wa->argv, wa->envp, wa->auxv); } diff --git a/test/libc/calls/statfs_test.c b/test/libc/calls/statfs_test.c index 1f9c6ca24..24b6d4167 100644 --- a/test/libc/calls/statfs_test.c +++ b/test/libc/calls/statfs_test.c @@ -16,8 +16,9 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/calls.h" #include "libc/calls/struct/statfs.h" +#include "libc/calls/calls.h" +#include "libc/calls/struct/stat.h" #include "libc/sysv/consts/o.h" #include "libc/testlib/testlib.h" diff --git a/tool/build/apelink.c b/tool/build/apelink.c index 56e9c9ac0..cbffbd1b1 100644 --- a/tool/build/apelink.c +++ b/tool/build/apelink.c @@ -1390,7 +1390,7 @@ static char *GenerateElfNotes(char *p) { char *save; save = p = ALIGN(p, 4); noteoff = p - prologue; - p = GenerateElfNote(p, "APE", 1, 106000000); + p = GenerateElfNote(p, "APE", 1, 107000000); if (support_vector & _HOSTOPENBSD) { p = GenerateElfNote(p, "OpenBSD", 1, 0); } @@ -1946,7 +1946,7 @@ int main(int argc, char *argv[]) { // otherwise try to use the ad-hoc self-extracted loader, securely if (loaders.n) { - p = stpcpy(p, "t=\"${TMPDIR:-${HOME:-.}}/.ape-1.6\"\n" + p = stpcpy(p, "t=\"${TMPDIR:-${HOME:-.}}/.ape-1.7\"\n" "[ x\"$1\" != x--assimilate ] && " "[ -x \"$t\" ] && " "exec \"$t\" \"$o\" \"$@\"\n"); diff --git a/tool/build/lib/errnos.S b/tool/build/lib/errnos.S deleted file mode 100644 index 0cc9e3307..000000000 --- a/tool/build/lib/errnos.S +++ /dev/null @@ -1,123 +0,0 @@ -/*-*- mode:asm; 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 │ -│ │ -│ 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/macros.internal.h" - - .macro .e local:req linux:req - .globl \local - .long \local-kLinuxErrnos - .byte \linux - .endm - -// Lookup table translating errnos between systems. -// -// @see libc/sysv/systemfive.S - .rodata - .balign 4 -kLinuxErrnos: - .e EPERM,1 - .e ENOENT,2 - .e ESRCH,3 - .e EINTR,4 - .e EIO,5 - .e ENXIO,6 - .e E2BIG,7 - .e ENOEXEC,8 - .e EBADF,9 - .e ECHILD,10 - .e EAGAIN,11 - .e ENOMEM,12 - .e EACCES,13 - .e EFAULT,14 - .e ENOTBLK,15 - .e EBUSY,16 - .e EEXIST,17 - .e EXDEV,18 - .e ENODEV,19 - .e ENOTDIR,20 - .e EISDIR,21 - .e EINVAL,22 - .e ENFILE,23 - .e EMFILE,24 - .e ENOTTY,25 - .e ETXTBSY,26 - .e EFBIG,27 - .e ENOSPC,28 - .e ESPIPE,29 - .e EROFS,30 - .e EMLINK,31 - .e EPIPE,32 - .e EDOM,33 - .e ERANGE,34 - .e EDEADLK,35 - .e ENAMETOOLONG,36 - .e ENOLCK,37 - .e ENOSYS,38 - .e ENOTEMPTY,39 - .e ELOOP,40 - .e ENOMSG,42 - .e EIDRM,43 - .e EUSERS,87 - .e ENOTSOCK,88 - .e EDESTADDRREQ,89 - .e EMSGSIZE,90 - .e EPROTOTYPE,91 - .e ENOPROTOOPT,92 - .e EPROTONOSUPPORT,93 - .e ESOCKTNOSUPPORT,94 - .e EOPNOTSUPP,95 - .e EPFNOSUPPORT,96 - .e EAFNOSUPPORT,97 - .e EADDRINUSE,98 - .e EADDRNOTAVAIL,99 - .e EL2NSYNC,45 - .e EL3HLT,46 - .e EL3RST,47 - .e ELNRNG,48 - .e ETIME,62 - .e ENONET,64 - .e EREMOTE,66 - .e EPROTO,71 - .e EBADMSG,74 - .e EOVERFLOW,75 - .e EILSEQ,84 - .e ERESTART,85 - .e ENETDOWN,100 - .e ENETUNREACH,101 - .e ENETRESET,102 - .e ECONNABORTED,103 - .e ECONNRESET,104 - .e ENOBUFS,105 - .e EISCONN,106 - .e ENOTCONN,107 - .e ESHUTDOWN,108 - .e ETOOMANYREFS,109 - .e ETIMEDOUT,110 - .e ECONNREFUSED,111 - .e EHOSTDOWN,112 - .e EHOSTUNREACH,113 - .e EALREADY,114 - .e EINPROGRESS,115 - .e ESTALE,116 - .e EDQUOT,122 - .e ECANCELED,125 - .e EOWNERDEAD,130 - .e ENOTRECOVERABLE,131 - .long 0 - .byte 0 - .endobj kLinuxErrnos,globl diff --git a/tool/build/lib/lines.c b/tool/build/lib/lines.c deleted file mode 100644 index 7c68f47e6..000000000 --- a/tool/build/lib/lines.c +++ /dev/null @@ -1,56 +0,0 @@ -/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ -│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ -╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2021 Justine Alexandra Roberts Tunney │ -│ │ -│ 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 "tool/build/lib/lines.h" -#include "libc/limits.h" -#include "libc/mem/mem.h" -#include "libc/str/str.h" - -struct Lines *NewLines(void) { - return calloc(1, sizeof(struct Lines)); -} - -void FreeLines(struct Lines *lines) { - size_t i; - for (i = 0; i < lines->n; ++i) { - free(lines->p[i]); - } - free(lines); -} - -void AppendLine(struct Lines *lines, const char *s, size_t n) { - lines->p = realloc(lines->p, ++lines->n * sizeof(*lines->p)); - lines->p[lines->n - 1] = strndup(s, n); -} - -void AppendLines(struct Lines *lines, const char *s) { - const char *p; - for (;;) { - p = strchr(s, '\n'); - if (p) { - AppendLine(lines, s, p - s); - s = p + 1; - } else { - if (*s) { - // gcc11 whines about SIZE_MAX > PTRDIFF_MAX - AppendLine(lines, s, PTRDIFF_MAX); - } - break; - } - } -} diff --git a/tool/build/lib/lines.h b/tool/build/lib/lines.h deleted file mode 100644 index bbd3bc78e..000000000 --- a/tool/build/lib/lines.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_LINES_H_ -#define COSMOPOLITAN_TOOL_BUILD_LIB_LINES_H_ -#if !(__ASSEMBLER__ + __LINKER__ + 0) -COSMOPOLITAN_C_START_ - -struct Lines { - size_t n; - char **p; -}; - -struct Lines *NewLines(void); -void FreeLines(struct Lines *); -void AppendLine(struct Lines *, const char *, size_t); -void AppendLines(struct Lines *, const char *); - -COSMOPOLITAN_C_END_ -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_LINES_H_ */ diff --git a/tool/build/unbuffer.c b/tool/build/unbuffer.c index 6686b6b30..17c681640 100644 --- a/tool/build/unbuffer.c +++ b/tool/build/unbuffer.c @@ -81,13 +81,13 @@ int main(int argc, char *argv[]) { if (!(prog = commandv(argv[optind], pathbuf, sizeof(pathbuf)))) { kprintf("%s: command not found\n", argv[optind]); - return __COUNTER__ + 1; + exit(1); } if (outputpath) { if ((outfd = creat(outputpath, 0644)) == -1) { perror(outputpath); - return __COUNTER__ + 1; + exit(1); } } @@ -97,12 +97,12 @@ int main(int argc, char *argv[]) { if (tcgetattr(1, &tio)) { perror("tcgetattr"); - return __COUNTER__ + 1; + exit(1); } if (openpty(&mfd, &sfd, 0, &tio, &wsz)) { perror("openpty"); - return __COUNTER__ + 1; + exit(1); } ignore.sa_flags = 0; @@ -116,7 +116,7 @@ int main(int argc, char *argv[]) { if ((pid = fork()) == -1) { perror("fork"); - return __COUNTER__ + 1; + exit(1); } if (!pid) { @@ -148,13 +148,13 @@ int main(int argc, char *argv[]) { rc = 0; } else { perror("read"); - return __COUNTER__ + 1; + exit(1); } } if (!(got = rc)) { if (waitpid(pid, &ws, 0) == -1) { perror("waitpid"); - return __COUNTER__ + 1; + exit(1); } break; } @@ -164,7 +164,7 @@ int main(int argc, char *argv[]) { wrote = rc; } else { perror("write"); - return __COUNTER__ + 1; + exit(1); } } if (outputpath) { @@ -174,7 +174,7 @@ int main(int argc, char *argv[]) { wrote = rc; } else { perror("write"); - return __COUNTER__ + 1; + exit(1); } } } @@ -187,6 +187,7 @@ int main(int argc, char *argv[]) { if (WIFEXITED(ws)) { return WEXITSTATUS(ws); } else { - return 128 + WTERMSIG(ws); + raise(WTERMSIG(ws)); + exit(128 + WTERMSIG(ws)); } } diff --git a/tool/build/x86combos.c b/tool/build/x86combos.c deleted file mode 100644 index a21459407..000000000 --- a/tool/build/x86combos.c +++ /dev/null @@ -1,191 +0,0 @@ -/*-*- 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 │ -│ │ -│ 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/log/check.h" -#include "libc/macros.internal.h" -#include "libc/stdio/stdio.h" -#include "libc/str/str.h" -#include "libc/sysv/consts/o.h" -#include "third_party/xed/x86.h" - -const char kPrefixes[][8] = { - {}, - {0x66}, - {0x67}, - {0x40}, - {0x6F}, - {0x66, 0x6F}, - {0x66, 0x40}, - {0x66, 0x6F}, - {0x67, 0x40}, - {0x67, 0x6F}, - {0x66, 0x67}, - {0x66, 0x67, 0x40}, - {0x66, 0x67, 0x6F}, - - {0x0F}, - {0x0F, 0x66}, - {0x0F, 0x67}, - {0x0F, 0x40}, - {0x0F, 0x6F}, - {0x0F, 0x66, 0x6F}, - {0x0F, 0x66, 0x40}, - {0x0F, 0x66, 0x6F}, - {0x0F, 0x67, 0x40}, - {0x0F, 0x67, 0x6F}, - {0x0F, 0x66, 0x67}, - {0x0F, 0x66, 0x67, 0x40}, - {0x0F, 0x66, 0x67, 0x6F}, - - {0xF3, 0x0F}, - {0xF3, 0x66, 0x0F}, - {0xF3, 0x67, 0x0F}, - {0xF3, 0x40, 0x0F}, - {0xF3, 0x6F, 0x0F}, - {0xF3, 0x66, 0x6F, 0x0F}, - {0xF3, 0x66, 0x40, 0x0F}, - {0xF3, 0x66, 0x6F, 0x0F}, - {0xF3, 0x67, 0x40, 0x0F}, - {0xF3, 0x67, 0x6F, 0x0F}, - {0xF3, 0x66, 0x67, 0x0F}, - {0xF3, 0x66, 0x67, 0x40, 0x0F}, - {0xF3, 0x66, 0x67, 0x6F, 0x0F}, - - {0xF2, 0x0F}, - {0xF2, 0x66, 0x0F}, - {0xF2, 0x67, 0x0F}, - {0xF2, 0x40, 0x0F}, - {0xF2, 0x6F, 0x0F}, - {0xF2, 0x66, 0x6F, 0x0F}, - {0xF2, 0x66, 0x40, 0x0F}, - {0xF2, 0x66, 0x6F, 0x0F}, - {0xF2, 0x67, 0x40, 0x0F}, - {0xF2, 0x67, 0x6F, 0x0F}, - {0xF2, 0x66, 0x67, 0x0F}, - {0xF2, 0x66, 0x67, 0x40, 0x0F}, - {0xF2, 0x66, 0x67, 0x6F, 0x0F}, - -}; - -const uint8_t kModrmPicks[] = { - 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x0, 0x8, 0x10, - 0x18, 0x20, 0x28, 0x30, 0x38, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, - 0x46, 0x47, 0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x78, 0x80, - 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x80, 0x88, 0x90, 0x98, - 0xa0, 0xa8, 0xb0, 0xb8, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, - 0xc7, 0xc0, 0xc8, 0xd0, 0xd8, 0xe0, 0xe8, 0xf0, 0xf8, -}; - -const uint8_t kOpMap0[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, - 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, - 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, - 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, - 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, - 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, - 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, - 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, - 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, - 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, - 255, -}; - -void WriteOp(int fd, struct XedDecodedInst *xedd) { - int i; - char buf[128], *p; - p = stpcpy(buf, ".byte "); - for (i = 0; i < xedd->length; ++i) { - if (i) *p++ = ','; - *p++ = '0'; - *p++ = 'x'; - *p++ = "0123456789abcdef"[(xedd->bytes[i] & 0xf0) >> 4]; - *p++ = "0123456789abcdef"[xedd->bytes[i] & 0x0f]; - } - *p++ = '\n'; - CHECK_NE(-1, write(fd, buf, p - buf)); -} - -int main(int argc, char *argv[]) { - int i, j, k, l, m, n, p, o, fd; - uint8_t op[16]; - struct XedDecodedInst xedd[1]; - fd = open("/tmp/ops.s", O_CREAT | O_TRUNC | O_RDWR, 0644); - for (o = 0; o < ARRAYLEN(kOpMap0); ++o) { - for (p = 0; p < ARRAYLEN(kPrefixes); ++p) { - memset(op, 0x55, 16); - n = strlen(kPrefixes[p]); - memcpy(op, kPrefixes[p], n); - op[n] = kOpMap0[o]; - xed_decoded_inst_zero_set_mode(xedd, XED_MACHINE_MODE_LONG_64); - if (!xed_instruction_length_decode(xedd, op, XED_MAX_INSTRUCTION_BYTES)) { - if (xedd->op.has_modrm && xedd->op.has_sib) { - for (i = 0; i < ARRAYLEN(kModrmPicks); ++i) { - for (j = 0; j < ARRAYLEN(kModrmPicks); ++j) { - memset(op, 0x55, 16); - n = strlen(kPrefixes[p]); - memcpy(op, kPrefixes[p], n); - op[n] = kOpMap0[o]; - op[xedd->op.pos_modrm] = kModrmPicks[i]; - op[xedd->op.pos_sib] = kModrmPicks[j]; - xed_decoded_inst_zero_set_mode(xedd, XED_MACHINE_MODE_LONG_64); - if (!xed_instruction_length_decode(xedd, op, - XED_MAX_INSTRUCTION_BYTES)) { - WriteOp(fd, xedd); - } - } - } - } else if (xedd->op.has_modrm) { - for (i = 0; i < ARRAYLEN(kModrmPicks); ++i) { - memset(op, 0x55, 16); - n = strlen(kPrefixes[p]); - memcpy(op, kPrefixes[p], n); - op[n] = kOpMap0[o]; - op[xedd->op.pos_modrm] = kModrmPicks[i]; - xed_decoded_inst_zero_set_mode(xedd, XED_MACHINE_MODE_LONG_64); - if (!xed_instruction_length_decode(xedd, op, - XED_MAX_INSTRUCTION_BYTES)) { - WriteOp(fd, xedd); - } - } - } else { - WriteOp(fd, xedd); - } - } - } - } - close(fd); - system("as -o /tmp/ops.o /tmp/ops.s"); - system("objdump -wd /tmp/ops.o |" - " grep -v data16 |" - " grep -v addr32 |" - " grep -v '(bad)' |" - " sed 's/^[ :[:xdigit:]]*//' |" - " sed 's/^[ :[:xdigit:]]*//' |" - " sed 's/[[:space:]]#.*$//' |" - " grep -v 'rex\\.' |" - " sort -u"); - return 0; -}