diff --git a/ape/ape-m1.c b/ape/ape-m1.c index 86c282074..1cd64af16 100644 --- a/ape/ape-m1.c +++ b/ape/ape-m1.c @@ -544,8 +544,9 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd, /* load elf */ for (i = 0; i < e->e_phnum; ++i) { + void *addr; + unsigned long size; if (p[i].p_type != PT_LOAD) continue; - if (!p[i].p_memsz) continue; /* configure mapping */ prot = 0; @@ -556,36 +557,51 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd, /* load from file */ if (p[i].p_filesz) { - void *addr; int prot1, prot2; - unsigned long size; + 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 + */ 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 */ - if (b > c) b = c; - if (c > b && (~prot1 & PROT_WRITE)) { + wipe = MIN(b - a, c - a); + if (wipe && (~prot1 & PROT_WRITE)) { prot1 = PROT_READ | PROT_WRITE; } addr = (void *)(dynbase + (p[i].p_vaddr & -pagesz)); size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_filesz; rc = (long)mmap(addr, size, prot1, flags, fd, p[i].p_offset & -pagesz); if (rc < 0) Pexit(exe, rc, "prog mmap"); - if (c > b) Bzero((void *)(dynbase + a), b - a); + if (wipe) Bzero((void *)(dynbase + a), wipe); if (prot2 != prot1) { rc = mprotect(addr, size, prot2); if (rc < 0) Pexit(exe, rc, "prog mprotect"); } - } - - /* allocate extra bss */ - a = p[i].p_vaddr + p[i].p_filesz; - a = (a + (pagesz - 1)) & -pagesz; - b = p[i].p_vaddr + p[i].p_memsz; - if (b > a) { + /* allocate extra bss */ + if (c > b) { + flags |= MAP_ANONYMOUS; + rc = (long)mmap((void *)(dynbase + b), c - b, prot, flags, -1, 0); + if (rc < 0) Pexit(exe, rc, "extra bss mmap"); + } + } else { + /* allocate pure bss */ + addr = (void *)(dynbase + (p[i].p_vaddr & -pagesz)); + size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_memsz; flags |= MAP_ANONYMOUS; - rc = (long)mmap((void *)(dynbase + a), b - a, prot, flags, -1, 0); + rc = (long)mmap(addr, size, prot, flags, -1, 0); if (rc < 0) Pexit(exe, rc, "bss mmap"); } } @@ -861,7 +877,7 @@ int main(int argc, char **argv, char **envp) { } else if (argc < 2) { Emit("usage: ape PROG [ARGV1,ARGV2,...]\n" " ape - PROG [ARGV0,ARGV1,...]\n" - "actually portable executable loader silicon 1.5\n" + "actually portable executable loader silicon 1.6\n" "copyright 2023 justine alexandra roberts tunney\n" "https://justine.lol/ape.html\n"); _exit(1); diff --git a/ape/ape.S b/ape/ape.S index a2b5b1c17..aff5c6727 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.5\"\n" + .ascii "t=\"${TMPDIR:-${HOME:-.}}/.ape-1.6\"\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 105000000 +3: .long 106000000 4: .size ape.ident,.-ape.ident .type ape.ident,@object .previous @@ -1052,11 +1052,11 @@ PEIMPS = 0b11000000000000000000000001000000 .balign __SIZEOF_POINTER__ ape_pe: .ascin "PE",4 .short kNtImageFileMachineNexgen32e - .stub ape_pe_shnum,short // NumberOfSections + .short ape_pe_shnum // NumberOfSections .long 0x5c64126b // TimeDateStamp .long 0 // PointerToSymbolTable .long 0 // NumberOfSymbols - .stub ape_pe_optsz,short // SizeOfOptionalHeader + .short ape_pe_optsz // SizeOfOptionalHeader .short PEEXE // Characteristics .short kNtPe64bit // Optional Header Magic .byte 14 // MajorLinkerVersion @@ -1080,25 +1080,25 @@ ape_pe: .ascin "PE",4 .long ape_pe_sizeofheaders // SizeOfHeaders .long 0 // Checksum .short v_ntsubsystem // Subsystem: 0=Neutral,2=GUI,3=Console - .stub v_ntdllchar,short // DllCharacteristics - .quad 0x0000000000100000 // StackReserve - .quad 0x00000000000fc000 // StackCommit + .short v_ntdllchar // DllCharacteristics + .quad ape_stack_memsz2 // StackReserve + .quad 64 * 1024 // StackCommit .quad 0 // HeapReserve .quad 0 // HeapCommit .long 0 // LoaderFlags .long 2 // NumberOfDirectoryEntries .long 0,0 // ExportsDirectory - .stub ape_idata,long // ImportsDirectory - .stub ape_idata_idtsize,long // ImportsDirectorySize + .long ape_idata // ImportsDirectory + .long ape_idata_idtsize // ImportsDirectorySize .endobj ape_pe,globl .previous .section .pe.sections,"a",@progbits .ascin ".text",8 // Section Name - .stub ape_text_memsz,long // Virtual Size or Physical Address - .stub ape_text_rva,long // Relative Virtual Address - .stub ape_text_filesz,long // Physical Size - .stub ape_text_offset,long // Physical Offset + .long ape_text_memsz // Virtual Size or Physical Address + .long ape_text_rva // Relative Virtual Address + .long ape_text_filesz // Physical Size + .long ape_text_offset // Physical Offset .long 0 // Relocation Table Offset .long 0 // Line Number Table Offset .short 0 // Relocation Count @@ -1108,10 +1108,10 @@ ape_pe: .ascin "PE",4 .section .pe.sections,"a",@progbits .ascin ".data",8 // Section Name - .stub ape_ram_memsz,long // Virtual Size or Physical Address - .stub ape_ram_rva,long // Relative Virtual Address - .stub ape_ram_filesz,long // Physical Size - .stub ape_ram_offset,long // Physical Offset + .long ape_ram_memsz // Virtual Size or Physical Address + .long ape_ram_rva // Relative Virtual Address + .long ape_ram_filesz // Physical Size + .long ape_ram_offset // Physical Offset .long 0 // Relocation Table Offset .long 0 // Line Number Table Offset .short 0 // Relocation Count diff --git a/ape/apeuninstall.sh b/ape/apeuninstall.sh index 4279e219e..2274462de 100755 --- a/ape/apeuninstall.sh +++ b/ape/apeuninstall.sh @@ -38,6 +38,7 @@ for x in .ape \ .ape-1.3 \ .ape-1.4 \ .ape-1.5 \ + .ape-1.6 \ .ape-blink-0.9.2 \ .ape-blink-1.0.0; do rm -f \ diff --git a/ape/loader.c b/ape/loader.c index ffbdb3838..065b0444a 100644 --- a/ape/loader.c +++ b/ape/loader.c @@ -698,6 +698,8 @@ __attribute__((__noreturn__)) static void Spawn(int os, const char *exe, int fd, /* load elf */ for (i = 0; i < e->e_phnum; ++i) { + void *addr; + unsigned long size; if (p[i].p_type != PT_LOAD) continue; /* configure mapping */ @@ -707,38 +709,53 @@ __attribute__((__noreturn__)) static void Spawn(int os, const char *exe, int fd, if (p[i].p_flags & PF_W) prot |= PROT_WRITE; if (p[i].p_flags & PF_X) prot |= PROT_EXEC; - /* load from file */ if (p[i].p_filesz) { - void *addr; + /* load from file */ int prot1, prot2; - unsigned long size; + 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 + */ 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 */ - if (b > c) b = c; - if (c > b && (~prot1 & PROT_WRITE)) { + wipe = MIN(b - a, c - a); + if (wipe && (~prot1 & PROT_WRITE)) { prot1 = PROT_READ | PROT_WRITE; } addr = (void *)(dynbase + (p[i].p_vaddr & -pagesz)); size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_filesz; rc = Mmap(addr, size, prot1, flags, fd, p[i].p_offset & -pagesz, os); if (rc < 0) Pexit(os, exe, rc, "prog mmap"); - if (c > b) Bzero((void *)(dynbase + a), b - a); + if (wipe) Bzero((void *)(dynbase + a), wipe); if (prot2 != prot1) { rc = Mprotect(addr, size, prot2, os); if (rc < 0) Pexit(os, exe, rc, "prog mprotect"); } - } - - /* allocate extra bss */ - a = p[i].p_vaddr + p[i].p_filesz; - a = (a + (pagesz - 1)) & -pagesz; - b = p[i].p_vaddr + p[i].p_memsz; - if (b > a) { + /* allocate extra bss */ + if (c > b) { + flags |= MAP_ANONYMOUS; + rc = Mmap((void *)(dynbase + b), c - b, prot, flags, -1, 0, os); + if (rc < 0) Pexit(os, exe, rc, "extra bss mmap"); + } + } else { + /* allocate pure bss */ + addr = (void *)(dynbase + (p[i].p_vaddr & -pagesz)); + size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_memsz; flags |= MAP_ANONYMOUS; - rc = Mmap((void *)(dynbase + a), b - a, prot, flags, -1, 0, os); + rc = Mmap(addr, size, prot, flags, -1, 0, os); if (rc < 0) Pexit(os, exe, rc, "bss mmap"); } } @@ -874,7 +891,7 @@ static __attribute__((__noreturn__)) void ShowUsage(int os, int fd, int rc) { Print(os, fd, "NAME\n" "\n" - " actually portable executable loader version 1.5\n" + " actually portable executable loader version 1.6\n" " copyright 2023 justine alexandra roberts tunney\n" " https://justine.lol/ape.html\n" "\n" diff --git a/ape/start.S b/ape/start.S index c04b33d43..7a99d6f38 100644 --- a/ape/start.S +++ b/ape/start.S @@ -65,7 +65,7 @@ ape.ident: .long 1 1: .asciz "APE" 2: .balign 4 -3: .long 105000000 +3: .long 106000000 4: .size ape.ident,.-ape.ident .type ape.ident,@object diff --git a/build/bootstrap/ape.aarch64 b/build/bootstrap/ape.aarch64 index a46b1f515..329e3eb31 100755 Binary files a/build/bootstrap/ape.aarch64 and b/build/bootstrap/ape.aarch64 differ diff --git a/build/bootstrap/ape.elf b/build/bootstrap/ape.elf index f2e65048e..1b7284332 100755 Binary files a/build/bootstrap/ape.elf and b/build/bootstrap/ape.elf differ diff --git a/build/bootstrap/ape.macho b/build/bootstrap/ape.macho index 7be50986c..4987e2ff7 100755 Binary files a/build/bootstrap/ape.macho and b/build/bootstrap/ape.macho differ diff --git a/build/bootstrap/ape.silicon b/build/bootstrap/ape.silicon index 179a84f94..3fd81f30b 100755 Binary files a/build/bootstrap/ape.silicon and b/build/bootstrap/ape.silicon differ diff --git a/libc/calls/execve-sysv.c b/libc/calls/execve-sysv.c index 18eb8da32..68853b8e1 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.5", buf))) || - CanExecute((ape = Join(firstnonnull(getenv("HOME"), "."), ".ape-1.5", + ".ape-1.6", buf))) || + CanExecute((ape = Join(firstnonnull(getenv("HOME"), "."), ".ape-1.6", buf))))) { shargs[0] = ape; shargs[1] = "-"; diff --git a/tool/decode/pe2.c b/tool/decode/pe2.c index f9b755ef0..ba0862596 100644 --- a/tool/decode/pe2.c +++ b/tool/decode/pe2.c @@ -317,7 +317,9 @@ static void showpeheader(struct NtImageNtHeaders *pe) { printf("\n"); showpeoptionalheader(pecheckaddress(mz, mzsize, &pe->OptionalHeader, pe->FileHeader.SizeOfOptionalHeader)); - ShowSections(pecheckaddress(mz, mzsize, pe + 1, + ShowSections(pecheckaddress(mz, mzsize, + (char *)(pe + 1) + + pe->OptionalHeader.NumberOfRvaAndSizes * 8, pe->FileHeader.NumberOfSections * sizeof(struct NtImageSectionHeader)), pe->FileHeader.NumberOfSections);