diff --git a/README.md b/README.md index 38cc79483..8a9ee2a18 100644 --- a/README.md +++ b/README.md @@ -264,6 +264,7 @@ printf 'main() { printf("hello world\\n"); }\n' >hello.c gcc -g -Os -static -nostdlib -nostdinc -fno-pie -no-pie -mno-red-zone \ -fno-omit-frame-pointer -pg -mnop-mcount -mno-tls-direct-seg-refs -gdwarf-4 \ -o hello.com.dbg hello.c -fuse-ld=bfd -Wl,-T,ape.lds -Wl,--gc-sections \ + -Wl,-z,common-page-size=0x1000 -Wl,-z,max-page-size=0x1000 \ -include cosmopolitan.h crt.o ape-no-modify-self.o cosmopolitan.a objcopy -S -O binary hello.com.dbg hello.com ``` @@ -427,7 +428,7 @@ server. You're welcome to join us! | Linux | 2.6.18 | 2007 | | Windows | 8 [1] | 2012 | | Mac OS X | 15.6 | 2018 | -| OpenBSD | 6.4 | 2018 | +| OpenBSD | 7 | 2021 | | FreeBSD | 13 | 2020 | | NetBSD | 9.2 | 2021 | diff --git a/ape/ape-m1.c b/ape/ape-m1.c index 7319eef38..bf615566c 100644 --- a/ape/ape-m1.c +++ b/ape/ape-m1.c @@ -59,7 +59,7 @@ struct Syslib { #define TROUBLESHOOT 0 -#define ELFCLASS64 2 +#define ELFCLASS32 1 #define ELFDATA2LSB 1 #define EM_AARCH64 183 #define ET_EXEC 2 @@ -431,7 +431,7 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd, codesize = 0; for (i = e->e_phnum; i--;) { if (p[i].p_type == PT_DYNAMIC) { - Pexit(exe, 0, "not a real executable"); + Pexit(exe, 0, "not a static executable"); } if (p[i].p_type != PT_LOAD) { continue; @@ -525,14 +525,15 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd, static void TryElf(struct ApeLoader *M, const char *exe, int fd, long *sp, long *bp, char *execfn) { - unsigned long n; - if (Read32(M->ehdr.buf) == Read32("\177ELF") && - M->ehdr.ehdr.e_type == ET_EXEC && M->ehdr.ehdr.e_machine == EM_AARCH64 && - M->ehdr.ehdr.e_ident[EI_CLASS] == ELFCLASS64 && - M->ehdr.ehdr.e_ident[EI_DATA] == ELFDATA2LSB && - (n = M->ehdr.ehdr.e_phnum * sizeof(M->phdr.phdr)) <= + unsigned size; + if (Read32(M->ehdr.buf) == Read32("\177ELF") && // + M->ehdr.ehdr.e_type == ET_EXEC && // + M->ehdr.ehdr.e_machine == EM_AARCH64 && // + M->ehdr.ehdr.e_ident[EI_CLASS] != ELFCLASS32 && // + M->ehdr.ehdr.e_phentsize >= sizeof(M->phdr.phdr) && // + (size = (unsigned)M->ehdr.ehdr.e_phnum * M->ehdr.ehdr.e_phentsize) <= sizeof(M->phdr.buf) && - pread(fd, M->phdr.buf, n, M->ehdr.ehdr.e_phoff) == n) { + pread(fd, M->phdr.buf, size, M->ehdr.ehdr.e_phoff) == size) { long auxv[][2] = { {AT_PHDR, (long)&M->phdr.phdr}, // {AT_PHENT, M->ehdr.ehdr.e_phentsize}, // diff --git a/ape/ape.S b/ape/ape.S index 10613668c..ced18bff4 100644 --- a/ape/ape.S +++ b/ape/ape.S @@ -43,6 +43,7 @@ #include "libc/nt/pedef.internal.h" #include "libc/runtime/pc.internal.h" #include "ape/ape.internal.h" +#include "libc/thread/tls.h" #include "libc/sysv/consts/prot.h" #define USE_SYMBOL_HACK 1 @@ -599,7 +600,7 @@ apesh: .ascii "\n@\n#'\"\n" // sixth edition shebang // There isn't a one-size-fits-all approach for this, thus we // present two choices. .ascii "o=\"$(command -v \"$0\")\"\n" -// Try to use a system-wide APE loader. +// Try to use system-wide APE loader. .ascii "[ x\"$1\" != x--assimilate ] && " .ascii "type ape >/dev/null 2>&1 && " .ascii "exec ape \"$o\" \"$@\"\n" @@ -609,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\"\n" + .ascii "t=\"${TMPDIR:-${HOME:-.}}/.ape-1.1\"\n" .ascii "[ -x \"$t\" ] || {\n" .ascii "mkdir -p \"${t%/*}\" &&\n" .ascii "dd if=\"$o\" of=\"$t.$$\" skip=" @@ -622,7 +623,7 @@ apesh: .ascii "\n@\n#'\"\n" // sixth edition shebang .ascii "dd if=\"$t.$$\"" .ascii " of=\"$t.$$\"" .ascii " skip=6" - .ascii " count=10" + .ascii " count=6" .ascii " bs=64" .ascii " conv=notrunc" .ascii " 2>/dev/null\n" @@ -746,6 +747,15 @@ ape_loader_end: .long PT_LOAD .long PF_R|PF_X + .stub ape_cod_offset,quad + .stub ape_cod_vaddr,quad + .stub ape_cod_paddr,quad + .stub ape_cod_filesz,quad + .stub ape_cod_memsz,quad + .stub ape_cod_align,quad + + .long PT_LOAD + .long PF_R .stub ape_rom_offset,quad .stub ape_rom_vaddr,quad .stub ape_rom_paddr,quad @@ -868,8 +878,8 @@ ape_macho: .long MAC_CPU_NEXGEN32E .long MAC_CPU_NEXGEN32E_ALL .long MAC_EXECUTE - .long 5 // number of load commands - .long 60f-10f // size of all load commands + .long 6 // number of load commands + .long 70f-10f // size of all load commands .long MAC_NOUNDEFS // flags .long 0 // reserved 10: .long MAC_LC_SEGMENT_64 @@ -880,26 +890,27 @@ ape_macho: 20: .long MAC_LC_SEGMENT_64 .long 30f-20b .ascin "__TEXT",16 + .stub ape_cod_vaddr,quad + .stub ape_cod_memsz,quad + .stub ape_cod_offset,quad + .stub ape_cod_filesz,quad + .long PROT_EXEC|PROT_READ|PROT_WRITE // maxprot + .long PROT_EXEC|PROT_READ // initprot + .long 0 // segment section count + .long 0 // flags +30: .long MAC_LC_SEGMENT_64 + .long 40f-30b + .ascin "__RODATA",16 .stub ape_rom_vaddr,quad .stub ape_rom_memsz,quad .stub ape_rom_offset,quad .stub ape_rom_filesz,quad .long PROT_EXEC|PROT_READ|PROT_WRITE // maxprot - .long PROT_EXEC|PROT_READ // initprot - .long 1 // segment section count + .long PROT_READ // initprot + .long 0 // segment section count .long 0 // flags -210: .ascin "__text",16 // section name (.text) - .ascin "__TEXT",16 - .stub ape_text_vaddr,quad - .stub ape_text_memsz,quad - .stub ape_text_offset,long - .long 12 // align 2**12 = 4096 - .long 0 // reloc table offset - .long 0 // relocation count - .long MAC_S_ATTR_SOME_INSTRUCTIONS // section type & attributes - .long 0,0,0 // reserved -30: .long MAC_LC_SEGMENT_64 - .long 40f-30b +40: .long MAC_LC_SEGMENT_64 + .long 50f-40b .ascin "__DATA",16 .stub ape_ram_vaddr,quad .stub ape_ram_memsz,quad @@ -907,39 +918,19 @@ ape_macho: .stub ape_ram_filesz,quad .long PROT_EXEC|PROT_READ|PROT_WRITE // maxprot .long PROT_READ|PROT_WRITE // initprot - .long 2 // segment section count + .long 0 // segment section count .long 0 // flags -310: .ascin "__data",16 // section name (.data) - .ascin "__DATA",16 - .stub ape_data_vaddr,quad - .stub ape_data_memsz,quad - .stub ape_data_offset,long - .long 12 // align 2**12 = 4096 - .long 0 // reloc table offset - .long 0 // relocation count - .long 0 // section type & attributes - .long 0,0,0 // reserved -320: .ascin "__bss",16 // section name (.bss) - .ascin "__DATA",16 - .stub ape_bss_vaddr,quad // virtual address - .stub ape_bss_memsz,quad // memory size - .long 0 // file offset - .long 12 // align 2**12 = 4096 - .long 0 // reloc table offset - .long 0 // relocation count - .long MAC_S_ZEROFILL // section type & attributes - .long 0,0,0 // reserved -40: .long MAC_LC_UUID - .long 50f-40b +50: .long MAC_LC_UUID + .long 60f-50b .stub ape_uuid1,quad .stub ape_uuid2,quad -50: .long MAC_LC_UNIXTHREAD - .long 60f-50b // cmdsize +60: .long MAC_LC_UNIXTHREAD + .long 70f-60b // cmdsize .long MAC_THREAD_NEXGEN32E // flavaflav - .long (520f-510f)/4 // count -510: .quad 0 // rax - .quad IMAGE_BASE_VIRTUAL // rbx - .quad _HOSTXNU // rcx + .long (620f-610f)/4 // count +610: .quad 0 // rax + .quad 0 // rbx + .quad 0 // rcx .quad 0 // rdx .quad 0 // rdi .quad 0 // rsi @@ -953,13 +944,13 @@ ape_macho: .quad 0 // r13 .quad 0 // r14 .quad 0 // r15 - .quad _start // rip + .quad _apple // rip .quad 0 // rflags .quad 0 // cs .quad 0 // fs .quad 0 // gs -520: -60: +620: +70: .endobj ape_macho,globl,hidden .previous /* .macho */ @@ -1785,7 +1776,6 @@ kernel: movabs $ape_stack_vaddr,%rsp .ldsvar v_ape_realbytes .ldsvar v_ape_highsectors .ldsvar ape_idata_ro - .ldsvar ape_pad_rodata .ldsvar ape_piro .ldsvar ape_piro_end .type ape_macho_end,@object @@ -1829,12 +1819,6 @@ ape_pad_text: ape_pad_privileged: .previous - .section .ape.pad.rodata,"a",@progbits - .type ape_pad_rodata,@object - .hidden ape_pad_rodata -ape_pad_rodata: - .previous - .section .ape.pad.data,"a",@progbits .type ape_pad_data,@object .hidden ape_pad_data @@ -1877,5 +1861,9 @@ __bss_start: __bss_end: .previous + .section .fstls,"awT",@nobits + .align TLS_ALIGNMENT + .previous + .end  \ No newline at end of file diff --git a/ape/ape.lds b/ape/ape.lds index dd1ff57cc..a5f5a4e4d 100644 --- a/ape/ape.lds +++ b/ape/ape.lds @@ -206,10 +206,10 @@ ENTRY(_start) PHDRS { Head PT_LOAD FLAGS(PF_X|PF_R); - Rom PT_LOAD FLAGS(PF_X|PF_R); - Ram PT_LOAD FLAGS(PF_W|PF_R); + Cod PT_LOAD FLAGS(PF_X|PF_R); + Rom PT_LOAD FLAGS(PF_R); Tls PT_TLS FLAGS(PF_W|PF_R); - Bss PT_LOAD FLAGS(PF_W|PF_R); + Ram PT_LOAD FLAGS(PF_W|PF_R); stack PT_GNU_STACK FLAGS(PF_W|PF_R); } @@ -221,7 +221,7 @@ SECTIONS { /*BEGIN: bsd addressability guarantee */ .head SEGMENT_START("text-segment", IMAGE_BASE_VIRTUAL) + SKEW : AT(IMAGE_BASE_REAL) { - HIDDEN(__executable_start = .); + __executable_start = .; /* Real Mode */ KEEP(*(.head)) @@ -230,9 +230,9 @@ SECTIONS { /* Executable & Linkable Format */ . = ALIGN(__SIZEOF_POINTER__); - HIDDEN(ape_phdrs = .); + ape_phdrs = .; KEEP(*(.elf.phdrs)) - HIDDEN(ape_phdrs_end = .); + ape_phdrs_end = .; KEEP(*(.emushprologue)) KEEP(*(.emush)) @@ -240,25 +240,29 @@ SECTIONS { /* OpenBSD */ . = ALIGN(__SIZEOF_POINTER__); - HIDDEN(ape_note = .); + ape_note = .; KEEP(*(.note.openbsd.ident)) KEEP(*(.note.netbsd.ident)) - HIDDEN(ape_note_end = .); + ape_note_end = .; /* Portable Executable */ KEEP(*(.pe.header)) - HIDDEN(ape_pe_sections = .); + ape_pe_sections = .; KEEP(*(.pe.sections)) - HIDDEN(ape_pe_sections_end = .); + ape_pe_sections_end = .; /* Mach-O */ KEEP(*(.macho)) . = ALIGN(__SIZEOF_POINTER__); - HIDDEN(ape_macho_end = .); + ape_macho_end = .; + + /* APE loader */ + KEEP(*(.ape.loader)) + . = ALIGN(CODE_GRANULE); KEEP(*(.ape.pad.head)) . = ALIGN(SupportsWindows() || SupportsMetal() ? CONSTANT(COMMONPAGESIZE) : 16); - HIDDEN(_ehead = .); + _ehead = .; } :Head /*BEGIN: nt addressability guarantee */ @@ -268,10 +272,7 @@ SECTIONS { /* Code that needs to be addressable in Real Mode */ *(.text.real) KEEP(*(SORT_BY_NAME(.sort.text.real.*))) - /* Code we want earlier in the binary w/o modifications */ - KEEP(*(.ape.loader)) - . = ALIGN(CODE_GRANULE); - HIDDEN(_ereal = .); + _ereal = .; /*END: realmode addressability guarantee */ /*BEGIN: morphable code */ . += CODE_GRANULE; @@ -318,9 +319,14 @@ SECTIONS { __privileged_end = .; . += . > 0 ? CODE_GRANULE : 0; + KEEP(*(.ape.pad.text)) + . = ALIGN(CONSTANT(COMMONPAGESIZE)); +/*END: Read Only Data (only needed for initialization) */ + } :Cod + /*BEGIN: Read Only Data */ - KEEP(*(.ape.pad.rodata)); + .rodata . : { KEEP(*(.rodata.pytab.0)); KEEP(*(.rodata.pytab.1)); KEEP(*(.rodata.pytab.2)); @@ -329,10 +335,6 @@ SECTIONS { *(.ubsan.types) *(.ubsan.data) - /* Unit Test & Fixture Registry */ - -/*BEGIN: Read only data that needn't be mapped after initialization */ - /* Legal Notices */ #if !defined(IM_FEELING_NAUGHTY) || defined(EMBED_NOTICES) KEEP(*(.commentprologue)) @@ -340,26 +342,28 @@ SECTIONS { KEEP(*(.commentepilogue)) #endif +/*BEGIN: read-only data that's only needed for initialization */ + /* Windows DLL Import Directory */ KEEP(*(.idata.ro)); KEEP(*(SORT_BY_NAME(.idata.ro.*))) . = ALIGN(__SIZEOF_POINTER__); - PROVIDE_HIDDEN(__init_array_start = .); + __init_array_start = .; KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) KEEP(*(.ctors)) KEEP(*(.init_array)) KEEP(*(.preinit_array)) - PROVIDE_HIDDEN(__init_array_end = .); + __init_array_end = .; . = ALIGN(__SIZEOF_POINTER__); - PROVIDE_HIDDEN(__fini_array_start = .); + __fini_array_start = .; KEEP(*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) KEEP(*(.fini_array)) KEEP(*(.dtors)) - PROVIDE_HIDDEN(__fini_array_end = .); + __fini_array_end = .; /* Encoded Data Structures w/ Linear Initialization Order */ KEEP(*(.initroprologue)) @@ -367,40 +371,39 @@ SECTIONS { KEEP(*(.initroepilogue)) KEEP(*(SORT_BY_NAME(.sort.rodata.*))) - KEEP(*(.ape.pad.text)) - . = ALIGN(CONSTANT(COMMONPAGESIZE)); - HIDDEN(_etext = .); - PROVIDE_HIDDEN(etext = .); -/*END: Read Only Data (only needed for initialization) */ - } :Rom +/*END: read-only data that's only needed for initialization */ - . = DATA_SEGMENT_ALIGN(CONSTANT(MAXPAGESIZE), CONSTANT(COMMONPAGESIZE)); + } :Rom /* initialization image for thread-local storage, this is copied */ /* out to actual TLS areas at runtime, so just make it read-only */ - .tdata : { + .tdata . : { _tdata_start = .; *(SORT_BY_ALIGNMENT(.tdata)) *(SORT_BY_ALIGNMENT(.tdata.*)) _tdata_end = .; + KEEP(*(.ape.pad.rodata)) . = ALIGN(CONSTANT(COMMONPAGESIZE)); + _etext = .; + PROVIDE(etext = .); } :Tls :Rom /*END: Read Only Data */ + . = DATA_SEGMENT_ALIGN(CONSTANT(MAXPAGESIZE), CONSTANT(COMMONPAGESIZE)); + . = DATA_SEGMENT_RELRO_END(0, .); + /* this only tells the linker about the layout of uninitialized */ /* TLS data, and does not advance the linker's location counter */ .tbss : { _tbss_start = .; *(SORT_BY_ALIGNMENT(.tbss)) *(SORT_BY_ALIGNMENT(.tbss.*)) - . = ALIGN(TLS_ALIGNMENT); + KEEP(*(.fstls)) /* the %fs register is based on this location */ _tbss_end = .; } :Tls - . = DATA_SEGMENT_RELRO_END(0, .); - - .data : { + .data . : { /*BEGIN: Read/Write Data */ KEEP(*(SORT_BY_NAME(.piro.data.sort.iat.*))) /*BEGIN: NT FORK COPYING */ @@ -427,23 +430,22 @@ SECTIONS { KEEP(*(.piro.pad.data)) KEEP(*(.dataepilogue)) /*END: NT FORK COPYING */ - HIDDEN(_edata = .); - PROVIDE_HIDDEN(edata = .); - HIDDEN(_ezip = .); /* <-- very deprecated */ - . = ALIGN(CONSTANT(COMMONPAGESIZE)); + _edata = .; + PROVIDE(edata = .); + _ezip = .; /* <-- very deprecated */ } :Ram /*END: file content that's loaded by o/s */ /*END: file content */ /*BEGIN: bss memory that's addressable */ - .bss ALIGN(64) : { + .bss : { /*BEGIN: NT FORK COPYING */ KEEP(*(.bssprologue)) KEEP(*(SORT_BY_NAME(.piro.bss.init.*))) *(.piro.bss) KEEP(*(SORT_BY_NAME(.piro.bss.sort.*))) - HIDDEN(__piro_end = .); + __piro_end = .; . += . > 0 ? CODE_GRANULE : 0; /*END: Post-Initialization Read-Only */ @@ -455,11 +457,13 @@ SECTIONS { KEEP(*(SORT_BY_NAME(.sort.bss.*))) KEEP(*(.bssepilogue)) + + . = ALIGN(64); + /*END: NT FORK COPYING */ - . = ALIGN(CONSTANT(COMMONPAGESIZE)); - HIDDEN(_end = .); - PROVIDE_HIDDEN(end = .); - } :Bss + _end = .; + PROVIDE(end = .); + } :Ram . = DATA_SEGMENT_END(.); @@ -527,67 +531,60 @@ PFSTUB4(ape_elf_phnum, (ape_phdrs_end - ape_phdrs) / 56); PFSTUB4(ape_elf_shnum, 0); PFSTUB4(ape_elf_shstrndx, 0); -HIDDEN(_tls_size = _tbss_end - _tdata_start); -HIDDEN(_tdata_size = _tdata_end - _tdata_start); -HIDDEN(_tbss_size = _tbss_end - _tbss_start); -HIDDEN(_tbss_offset = _tbss_start - _tdata_start); -HIDDEN(_tls_content = (_tdata_end - _tdata_start) + (_tbss_end - _tbss_start)); -HIDDEN(_tls_align = 1); +_tls_size = _tbss_end - _tdata_start; +_tdata_size = _tdata_end - _tdata_start; +_tbss_size = _tbss_end - _tbss_start; +_tbss_offset = _tbss_start - _tdata_start; +_tls_content = (_tdata_end - _tdata_start) + (_tbss_end - _tbss_start); +_tls_align = 1; -HIDDEN(ape_rom_offset = 0); -HIDDEN(ape_rom_vaddr = ADDR(.head)); -HIDDEN(ape_rom_paddr = LOADADDR(.head)); -HIDDEN(ape_rom_filesz = LOADADDR(.data) - ape_rom_paddr); -HIDDEN(ape_rom_memsz = ADDR(.data) - ADDR(.head)); -HIDDEN(ape_rom_align = CONSTANT(COMMONPAGESIZE)); -HIDDEN(ape_rom_rva = RVA(ape_rom_vaddr)); +ape_cod_offset = 0; +ape_cod_vaddr = ADDR(.head); +ape_cod_paddr = LOADADDR(.head); +ape_cod_filesz = SIZEOF(.head) + SIZEOF(.text); +ape_cod_memsz = ape_cod_filesz; +ape_cod_align = CONSTANT(COMMONPAGESIZE); +ape_cod_rva = RVA(ape_cod_vaddr); -HIDDEN(ape_ram_offset = ape_rom_offset + ape_rom_filesz); -HIDDEN(ape_ram_vaddr = ADDR(.data)); -HIDDEN(ape_ram_paddr = LOADADDR(.data)); -HIDDEN(ape_ram_filesz = SIZEOF(.data)); -HIDDEN(ape_ram_memsz = ADDR(.bss) + SIZEOF(.bss) - ape_ram_vaddr); -HIDDEN(ape_ram_align = CONSTANT(COMMONPAGESIZE)); -HIDDEN(ape_ram_rva = RVA(ape_ram_vaddr)); +ape_rom_offset = ape_cod_offset + ape_cod_filesz; +ape_rom_vaddr = ADDR(.rodata); +ape_rom_paddr = LOADADDR(.rodata); +ape_rom_filesz = SIZEOF(.rodata) + SIZEOF(.tdata); +ape_rom_memsz = ape_rom_filesz; +ape_rom_align = CONSTANT(COMMONPAGESIZE); +ape_rom_rva = RVA(ape_rom_vaddr); -HIDDEN(ape_stack_pf = DEFINED(ape_stack_pf) ? ape_stack_pf : PF_R | PF_W); -HIDDEN(ape_stack_prot = _PF2PROT(ape_stack_pf)); -HIDDEN(ape_stack_offset = ape_ram_offset + ape_ram_filesz); -HIDDEN(ape_stack_vaddr = DEFINED(ape_stack_vaddr) ? ape_stack_vaddr : 0x700000000000); -HIDDEN(ape_stack_paddr = ape_ram_paddr + ape_ram_filesz); -HIDDEN(ape_stack_filesz = 0); -HIDDEN(ape_stack_memsz = DEFINED(ape_stack_memsz) ? ape_stack_memsz : APE_STACKSIZE); -HIDDEN(ape_stack_align = 16); +ape_ram_offset = ape_rom_offset + ape_rom_filesz; +ape_ram_vaddr = ADDR(.data); +ape_ram_paddr = LOADADDR(.data); +ape_ram_filesz = SIZEOF(.data); +ape_ram_memsz = SIZEOF(.data) + SIZEOF(.bss); +ape_ram_align = CONSTANT(COMMONPAGESIZE); +ape_ram_rva = RVA(ape_ram_vaddr); -HIDDEN(ape_note_offset = ape_rom_offset + (ape_note - ape_rom_vaddr)); -HIDDEN(ape_note_vaddr = ape_note); -HIDDEN(ape_note_paddr = ape_rom_paddr + ape_note_offset); -HIDDEN(ape_note_filesz = ape_note_end - ape_note); -HIDDEN(ape_note_memsz = ape_note_filesz); -HIDDEN(ape_note_align = __SIZEOF_POINTER__); +ape_stack_pf = DEFINED(ape_stack_pf) ? ape_stack_pf : PF_R | PF_W; +ape_stack_prot = _PF2PROT(ape_stack_pf); +ape_stack_offset = 0; +ape_stack_vaddr = DEFINED(ape_stack_vaddr) ? ape_stack_vaddr : 0x700000000000; +ape_stack_paddr = ape_ram_paddr + ape_ram_filesz; +ape_stack_filesz = 0; +ape_stack_memsz = DEFINED(ape_stack_memsz) ? ape_stack_memsz : APE_STACKSIZE; +ape_stack_align = 16; -HIDDEN(ape_text_offset = ape_rom_offset + LOADADDR(.text) - ape_rom_paddr); -HIDDEN(ape_text_paddr = LOADADDR(.text)); -HIDDEN(ape_text_vaddr = ADDR(.text)); -HIDDEN(ape_text_filesz = SIZEOF(.text) + SIZEOF(.tdata)); -HIDDEN(ape_text_memsz = SIZEOF(.text) + SIZEOF(.tdata)); -HIDDEN(ape_text_align = CONSTANT(COMMONPAGESIZE)); -HIDDEN(ape_text_rva = RVA(ape_text_vaddr)); +ape_note_offset = ape_cod_offset + (ape_note - ape_cod_vaddr); +ape_note_vaddr = ape_note; +ape_note_paddr = ape_cod_paddr + ape_note_offset; +ape_note_filesz = ape_note_end - ape_note; +ape_note_memsz = ape_note_filesz; +ape_note_align = __SIZEOF_POINTER__; -HIDDEN(ape_data_offset = ape_ram_offset + LOADADDR(.data) - ape_ram_paddr); -HIDDEN(ape_data_paddr = LOADADDR(.data)); -HIDDEN(ape_data_vaddr = ADDR(.data)); -HIDDEN(ape_data_filesz = SIZEOF(.data)); -HIDDEN(ape_data_memsz = SIZEOF(.data)); -HIDDEN(ape_data_align = CONSTANT(COMMONPAGESIZE)); -HIDDEN(ape_data_rva = RVA(ape_data_vaddr)); - -HIDDEN(ape_bss_offset = ape_ram_offset + LOADADDR(.bss) - ape_ram_paddr); -HIDDEN(ape_bss_paddr = LOADADDR(.bss)); -HIDDEN(ape_bss_vaddr = ADDR(.bss)); -HIDDEN(ape_bss_filesz = 0); -HIDDEN(ape_bss_memsz = SIZEOF(.bss)); -HIDDEN(ape_bss_align = CONSTANT(COMMONPAGESIZE)); +ape_text_offset = ape_cod_offset + LOADADDR(.text) - ape_cod_paddr; +ape_text_paddr = LOADADDR(.text); +ape_text_vaddr = ADDR(.text); +ape_text_filesz = SIZEOF(.text) + SIZEOF(.rodata) + SIZEOF(.tdata); +ape_text_memsz = ape_text_filesz; +ape_text_align = CONSTANT(COMMONPAGESIZE); +ape_text_rva = RVA(ape_text_vaddr); /* we roundup here because xnu wants the file load segments page-aligned */ /* but we don't want to add the nop padding to the ape program, so we'll */ @@ -602,17 +599,17 @@ SHSTUB2(ape_loader_dd_count, #define IDENTITY(X) X -#define APE_DECLARE_FIXED_DECIMAL(F, X) \ - HIDDEN(X##_quad = DEFINED(X) ? ((F(X) < 1000000000 ? 32 : F(X) / 1000000000 % 10 + 48) << 000 | \ - (F(X) < 100000000 ? 32 : F(X) / 100000000 % 10 + 48) << 010 | \ - (F(X) < 10000000 ? 32 : F(X) / 10000000 % 10 + 48) << 020 | \ - (F(X) < 1000000 ? 32 : F(X) / 1000000 % 10 + 48) << 030 | \ - (F(X) < 100000 ? 32 : F(X) / 100000 % 10 + 48) << 040 | \ - (F(X) < 10000 ? 32 : F(X) / 10000 % 10 + 48) << 050 | \ - (F(X) < 1000 ? 32 : F(X) / 1000 % 10 + 48) << 060 | \ - (F(X) < 100 ? 32 : F(X) / 100 % 10 + 48) << 070) : 0); \ - HIDDEN(X##_short = DEFINED(X) ? ((F(X) < 10 ? 32 : F(X) / 10 % 10 + 48) << 000 | \ - (F(X) % 10 + 48) << 010) : 0) +#define APE_DECLARE_FIXED_DECIMAL(F, X) \ + X##_quad = DEFINED(X) ? ((F(X) < 1000000000 ? 32 : F(X) / 1000000000 % 10 + 48) << 000 | \ + (F(X) < 100000000 ? 32 : F(X) / 100000000 % 10 + 48) << 010 | \ + (F(X) < 10000000 ? 32 : F(X) / 10000000 % 10 + 48) << 020 | \ + (F(X) < 1000000 ? 32 : F(X) / 1000000 % 10 + 48) << 030 | \ + (F(X) < 100000 ? 32 : F(X) / 100000 % 10 + 48) << 040 | \ + (F(X) < 10000 ? 32 : F(X) / 10000 % 10 + 48) << 050 | \ + (F(X) < 1000 ? 32 : F(X) / 1000 % 10 + 48) << 060 | \ + (F(X) < 100 ? 32 : F(X) / 100 % 10 + 48) << 070) : 0; \ + X##_short = DEFINED(X) ? ((F(X) < 10 ? 32 : F(X) / 10 % 10 + 48) << 000 | \ + (F(X) % 10 + 48) << 010) : 0 APE_DECLARE_FIXED_DECIMAL(RVA, blink_linux_aarch64); APE_DECLARE_FIXED_DECIMAL(IDENTITY, blink_linux_aarch64_size); @@ -622,13 +619,12 @@ APE_DECLARE_FIXED_DECIMAL(IDENTITY, blink_xnu_aarch64_size); #endif /* APE_IS_SHELL_SCRIPT */ #if SupportsMetal() -HIDDEN(v_ape_realsectors = - MIN(0x70000 - IMAGE_BASE_REAL, ROUNDUP(RVA(_ezip), 512)) / 512); -HIDDEN(v_ape_realbytes = v_ape_realsectors * 512); -HIDDEN(v_ape_realdwords = v_ape_realsectors * (512 / 4)); -HIDDEN(v_ape_allsectors = ROUNDUP(RVA(_ezip), 512) / 512); -HIDDEN(v_ape_allbytes = v_ape_allsectors * 512); -HIDDEN(v_ape_highsectors = MIN(0xffff, v_ape_allsectors - v_ape_realsectors)); +v_ape_realsectors = MIN(0x70000 - IMAGE_BASE_REAL, ROUNDUP(RVA(_ezip), 512)) / 512; +v_ape_realbytes = v_ape_realsectors * 512; +v_ape_realdwords = v_ape_realsectors * (512 / 4); +v_ape_allsectors = ROUNDUP(RVA(_ezip), 512) / 512; +v_ape_allbytes = v_ape_allsectors * 512; +v_ape_highsectors = MIN(0xffff, v_ape_allsectors - v_ape_realsectors); TSSDESCSTUB2(_tss, _tss, _tss_end ? _tss_end - _tss - 1 : 0); #endif @@ -650,19 +646,8 @@ TSSDESCSTUB2(_tss, _tss, _tss_end ? _tss_end - _tss - 1 : 0); KMH(ape_uuid1, X); \ XORSHIFT(ape_uuid2, X); \ KMH(ape_uuid2, X) -HIDDEN(ape_uuid1 = 88172645463325252); -HIDDEN(ape_uuid2 = 88172645463325252); -CHURN(ape_bss_align); -CHURN(ape_bss_filesz); -CHURN(ape_bss_memsz); -CHURN(ape_bss_offset); -CHURN(ape_bss_paddr); -CHURN(ape_data_filesz); -CHURN(ape_data_memsz); -CHURN(ape_data_offset); -CHURN(ape_data_paddr); -CHURN(ape_data_rva); -CHURN(ape_data_vaddr); +ape_uuid1 = 88172645463325252; +ape_uuid2 = 88172645463325252; CHURN(ape_elf_entry); CHURN(ape_elf_phnum); CHURN(ape_elf_phoff); @@ -691,7 +676,14 @@ CHURN(ape_rom_memsz); CHURN(ape_rom_offset); CHURN(ape_rom_paddr); CHURN(ape_rom_rva); -CHURN(ape_rom_vaddr); +CHURN(ape_cod_vaddr); +CHURN(ape_cod_align); +CHURN(ape_cod_filesz); +CHURN(ape_cod_memsz); +CHURN(ape_cod_offset); +CHURN(ape_cod_paddr); +CHURN(ape_cod_rva); +CHURN(ape_cod_vaddr); CHURN(ape_text_align); CHURN(ape_text_filesz); CHURN(ape_text_memsz); @@ -724,22 +716,22 @@ CHURN(WinMain); #if SupportsWindows() || SupportsMetal() #define LINK_WINDOWS (SupportsWindows() && !DEFINED(EfiMain)) PFSTUB4(ape_pe_offset, ape_pe - ape_mz); -HIDDEN(ape_pe_optsz = ape_pe_sections - (ape_pe + 24)); -HIDDEN(ape_pe_shnum = (ape_pe_sections_end - ape_pe_sections) / 40); -HIDDEN(ape_pe_base = IMAGE_BASE_VIRTUAL); -HIDDEN(ape_idata = LINK_WINDOWS ? RVA(ape_idata_iat) : 0); -HIDDEN(ape_idata_iatsize = LINK_WINDOWS ? ape_idata_iatend - ape_idata_iat : 0); -HIDDEN(ape_idata = LINK_WINDOWS ? RVA(ape_idata_idt) : 0); -HIDDEN(ape_idata_idtsize = LINK_WINDOWS ? ape_idata_idtend - ape_idata_idt : 0); -HIDDEN(v_ntversion = LINK_WINDOWS ? 6 : 1); -HIDDEN(v_ntdllchar = LINK_WINDOWS ? 288 : 0); -HIDDEN(v_ntsubversion = LINK_WINDOWS ? 6 : 5); -HIDDEN(v_ntsubsystem = (LINK_WINDOWS - ? (DEFINED(GetMessage) - ? kNtImageSubsystemWindowsGui - : kNtImageSubsystemWindowsCui) - : kNtImageSubsystemEfiApplication)); -HIDDEN(ape_pe_entry = LINK_WINDOWS ? WinMain : EfiMain); +ape_pe_optsz = ape_pe_sections - (ape_pe + 24); +ape_pe_shnum = (ape_pe_sections_end - ape_pe_sections) / 40; +ape_pe_base = IMAGE_BASE_VIRTUAL; +ape_idata = LINK_WINDOWS ? RVA(ape_idata_iat) : 0; +ape_idata_iatsize = LINK_WINDOWS ? ape_idata_iatend - ape_idata_iat : 0; +ape_idata = LINK_WINDOWS ? RVA(ape_idata_idt) : 0; +ape_idata_idtsize = LINK_WINDOWS ? ape_idata_idtend - ape_idata_idt : 0; +v_ntversion = LINK_WINDOWS ? 6 : 1; +v_ntdllchar = LINK_WINDOWS ? 288 : 0; +v_ntsubversion = LINK_WINDOWS ? 6 : 5; +v_ntsubsystem = (LINK_WINDOWS + ? (DEFINED(GetMessage) + ? kNtImageSubsystemWindowsGui + : kNtImageSubsystemWindowsCui) + : kNtImageSubsystemEfiApplication); +ape_pe_entry = LINK_WINDOWS ? WinMain : EfiMain; #endif #if SupportsXnu() diff --git a/ape/ape.mk b/ape/ape.mk index f92a695a6..60c52d8b2 100644 --- a/ape/ape.mk +++ b/ape/ape.mk @@ -86,7 +86,6 @@ APE_LOADER_FLAGS = \ -Os \ -ffreestanding \ -mgeneral-regs-only \ - -mno-red-zone \ -fno-ident \ -fno-gnu-unique \ -c \ @@ -178,14 +177,14 @@ o/$(MODE)/ape/ape-copy-self.o: \ $(OUTPUT_OPTION) \ -DAPE_NO_MODIFY_SELF $< -o/$(MODE)/ape/loader.o: ape/loader.c ape/loader.h +o/$(MODE)/ape/loader.o: ape/loader.c @$(COMPILE) -AOBJECTIFY.c $(CC) -DSUPPORT_VECTOR=0b01111001 -g $(APE_LOADER_FLAGS) o/$(MODE)/ape/loader-gcc.asm: ape/loader.c @$(COMPILE) -AOBJECTIFY.c $(CC) -DSUPPORT_VECTOR=0b01111001 -S -g0 $(APE_LOADER_FLAGS) o/$(MODE)/ape/loader-clang.asm: ape/loader.c @$(COMPILE) -AOBJECTIFY.c $(CLANG) -DSUPPORT_VECTOR=0b01111001 -S -g0 $(APE_LOADER_FLAGS) -o/$(MODE)/ape/loader-xnu.o: ape/loader.c ape/loader.h +o/$(MODE)/ape/loader-xnu.o: ape/loader.c @$(COMPILE) -AOBJECTIFY.c $(CC) -DSUPPORT_VECTOR=0b00001000 -g $(APE_LOADER_FLAGS) o/$(MODE)/ape/loader-xnu-gcc.asm: ape/loader.c @$(COMPILE) -AOBJECTIFY.c $(CC) -DSUPPORT_VECTOR=0b00001000 -S -g0 $(APE_LOADER_FLAGS) @@ -212,7 +211,7 @@ o/$(MODE)/ape/ape.macho.dbg: private \ o/$(MODE)/ape/ape.macho.dbg: \ o/$(MODE)/ape/loader-xnu.o \ o/$(MODE)/ape/loader-macho.o \ - ape/loader-macho.lds + ape/loader.lds @$(ELFLINK) .PHONY: o/$(MODE)/ape diff --git a/ape/apeuninstall.sh b/ape/apeuninstall.sh index 5cad154a8..a1526ad89 100755 --- a/ape/apeuninstall.sh +++ b/ape/apeuninstall.sh @@ -11,7 +11,7 @@ fi echo "APE Uninstaller intends to run (in pseudo-shell)" echo echo " sudo echo -1 into /proc/sys/fs/binfmt_misc/APE*" - echo " sudo rm -f /usr/bin/ape ~/.ape o/tmp/.ape /tmp/.ape" + echo " sudo rm -f /usr/bin/ape ~/.ape /tmp/.ape # etc." echo echo "You may then use ape/apeinstall.sh to reinstall it" echo @@ -23,4 +23,23 @@ for f in /proc/sys/fs/binfmt_misc/APE*; do $SUDO sh -c "echo -1 >$f" || exit fi done -$SUDO rm -f /usr/bin/ape ~/.ape o/tmp/.ape o/tmp/ape /tmp/.ape /tmp/ape || exit + +# system installation +if [ -f /usr/bin/ape ]; then + $SUDO rm -f /usr/bin/ape +fi + +# legacy installations +rm -f o/tmp/ape /tmp/ape "${TMPDIR:-/tmp}/ape" + +# ad-hoc installations +for x in .ape \ + .ape-1.1 \ + .ape-blink-0.9.2 \ + .ape-blink-1.0.0; do + rm -f \ + ~/$x \ + /tmp/$x \ + o/tmp/$x \ + "${TMPDIR:-/tmp}/$x" +done diff --git a/ape/loader-elf.S b/ape/loader-elf.S index 86c19ffc8..37a4086e3 100644 --- a/ape/loader-elf.S +++ b/ape/loader-elf.S @@ -25,6 +25,8 @@ // APE Loader Executable Structure // Linux, FreeBSD, NetBSD, OpenBSD + .section .head + .balign 8 ehdr: .ascii "\177ELF" .byte ELFCLASS64 @@ -49,21 +51,21 @@ ehdr: .ascii "\177ELF" .balign 8 phdrs: .long PT_LOAD // p_type - .long PF_R|PF_X // p_flags + .long PF_R // p_flags .quad 0 // p_offset .quad ehdr // p_vaddr .quad ehdr // p_paddr - .quad filesz // p_filesz - .quad filesz // p_memsz + .quad rosize // p_filesz + .quad rosize // p_memsz .quad 4096 // p_align .long PT_LOAD // p_type - .long PF_R|PF_W // p_flags - .quad 0 // p_offset - .quad bss // p_vaddr - .quad bss // p_paddr - .quad 0 // p_filesz - .quad bsssize // p_memsz + .long PF_X // p_flags + .quad rosize // p_offset + .quad text // p_vaddr + .quad text // p_paddr + .quad textsz // p_filesz + .quad textsz // p_memsz .quad 4096 // p_align .long PT_GNU_STACK // p_type @@ -72,7 +74,7 @@ phdrs: .long PT_LOAD // p_type .quad 0 // p_vaddr .quad 0 // p_paddr .quad 0 // p_filesz - .quad 0 // p_memsz + .quad 8*1024*1024 // p_memsz .quad 16 // p_align .long PT_NOTE // p_type @@ -101,7 +103,7 @@ note: .long 2f-1f notesize = . - note .balign 64,0 // for ape.S dd - .org 0x180 // for ape.S dd + .org 64*6 // for ape.S dd // APE Loader XNU Header // @@ -113,8 +115,8 @@ macho: .long 0xFEEDFACE+1 .long MAC_CPU_NEXGEN32E .long MAC_CPU_NEXGEN32E_ALL .long MAC_EXECUTE - .long 5 // number of load commands - .long 60f-10f // size of all load commands + .long 4 // number of load commands + .long 50f-10f // size of all load commands .long MAC_NOUNDEFS // flags .long 0 // reserved 10: .long MAC_LC_SEGMENT_64 @@ -126,56 +128,25 @@ macho: .long 0xFEEDFACE+1 .long 30f-20b .ascin "__TEXT",16 .quad ehdr // vaddr - .quad 4096 // memsz + .quad filesz // memsz .quad 0 // file offset .quad filesz // file size .long PROT_EXEC|PROT_READ|PROT_WRITE // maxprot .long PROT_EXEC|PROT_READ // initprot - .long 1 // segment section count + .long 0 // segment section count .long 0 // flags -210: .ascin "__text",16 // section name (.text) - .ascin "__TEXT",16 - .quad _start // vaddr - .quad textsz // memsz - .long textoff // offset - .long 6 // align 2**6 = 64 - .long 0 // reloc table offset - .long 0 // relocation count - .long MAC_S_ATTR_SOME_INSTRUCTIONS // section type & attributes - .long 0,0,0 // reserved -30: .long MAC_LC_SEGMENT_64 +30: .long MAC_LC_UUID .long 40f-30b - .ascin "__DATA",16 - .quad bss // vaddr - .quad bsssize // memsz - .quad 0 // offset - .quad 0 // file size - .long PROT_EXEC|PROT_READ|PROT_WRITE // maxprot - .long PROT_READ|PROT_WRITE // initprot - .long 1 // segment section count - .long 0 // flags -310: .ascin "__bss",16 // section name (.bss) - .ascin "__DATA",16 - .quad bss // vaddr - .quad bsssize // memsz - .long 0 // offset - .long 12 // align 2**12 = 4096 - .long 0 // reloc table offset - .long 0 // relocation count - .long MAC_S_ZEROFILL // section type & attributes - .long 0,0,0 // reserved -40: .long MAC_LC_UUID - .long 50f-40b .quad 0x3fb29ee4ac6c87aa // uuid1 - .quad 0xdd2c9bb866d9eef8 // uuid2 -50: .long MAC_LC_UNIXTHREAD - .long 60f-50b // cmdsize + .quad 0xdd2c9bb866d9eef9 // uuid2 +40: .long MAC_LC_UNIXTHREAD + .long 50f-40b // cmdsize .long MAC_THREAD_NEXGEN32E // flavaflav - .long (520f-510f)/4 // count -510: .quad 0 // rax + .long (420f-410f)/4 // count +410: .quad 0 // rax .quad 0 // rbx .quad 0 // rcx - .quad _HOSTXNU // rdx + .quad 0 // rdx .quad 0 // rdi .quad 0 // rsi .quad 0 // rbp @@ -188,62 +159,41 @@ macho: .long 0xFEEDFACE+1 .quad 0 // r13 .quad 0 // r14 .quad 0 // r15 - .quad _start // rip + .quad _apple // rip .quad 0 // rflags .quad 0 // cs .quad 0 // fs .quad 0 // gs -520: -60: +420: +50: .endobj macho .balign 64,0 // for ape.S dd - .org 0x400 // for ape.S dd + .org 64*12 // for ape.S dd -// Ape Loader Entrpoint -// -// This is normally called by the operating system. However it may -// be called by the Actually Portable Executables themselves, when -// re-executing a program. Just do this: -// -// memcpy(0x200000, loader) -// lea handoff(%rip),%rcx -// lea argblock(%rip),%rsp -// jmp 0x200400 -// -// @see APE_LOADER_ENTRY -// @see ape/loader.h -_start: - -// Hack for detecting M1 Rosetta environment. -// https://github.com/jart/cosmopolitan/issues/429#issuecomment-1166704377 - cmp $-1,%ebx - jne 0f - cmp $+1,%edx - jne 0f - mov $_HOSTXNU,%dl - xor %ecx,%ecx - -0: mov %rsp,%rsi + .text +_apple: mov $_HOSTXNU,%dl // xnu's not unix! +_start: mov %rsp,%rsi // save real stack + sub $1024*1024,%rsp // room for allocs jmp ApeLoader .endfn _start,globl + .endfn _apple,globl -// System Call Entrpoint +// Invokes system call. // -// This function is used by the APE loader to make system calls. -// We also pass a reference to this function to the APE binary's -// _start() function. It's needed because on OpenBSD, msyscall() -// restricts which pages can issue system calls, and it can only -// be called once. Therefore if we want to be load and re-load a -// binary multiple times without calling the system execve(), we -// need to be able to handover the SYSCALL function. We hardcode -// this to a fixed address, but that shouldn't be used, since we -// would ideally want to move it to a random page in the future. -__syscall_loader: +// This function has eight parameters. The first seven are for +// arguments passed along to the system call. The eight is for +// the magic number that indicates which system call is called +// +// The return value follows the Linux kernel convention, where +// errors are returned as `-errno`. BSD systems are normalized +// to follow this convention automatically. +SystemCall: + mov %rcx,%r10 + mov 16(%rsp),%eax clc syscall - jc 1f - ret -1: neg %rax - ret - .endfn __syscall_loader,globl + jnc 1f + neg %rax +1: ret + .endfn SystemCall,globl diff --git a/ape/loader-macho.S b/ape/loader-macho.S index 6d2b31e96..9adc82d42 100644 --- a/ape/loader-macho.S +++ b/ape/loader-macho.S @@ -23,116 +23,88 @@ // APE Loader Executable Structure for XNU - .balign 4096 + .section .head + + .balign 64 macho: .long 0xFEEDFACE+1 .long MAC_CPU_NEXGEN32E .long MAC_CPU_NEXGEN32E_ALL .long MAC_EXECUTE - .long 5 # number of load commands - .long 60f-10f # size of all load commands - .long MAC_NOUNDEFS # flags - .long 0 # reserved + .long 4 // number of load commands + .long 50f-10f // size of all load commands + .long MAC_NOUNDEFS // flags + .long 0 // reserved 10: .long MAC_LC_SEGMENT_64 - .long 20f-10b # unmaps first page dir - .ascin "__PAGEZERO",16 # consistent with linux - .quad 0,0x200000,0,0 # which forbids mem <2m + .long 20f-10b // unmaps first page dir + .ascin "__PAGEZERO",16 // consistent with linux + .quad 0,0x200000,0,0 // which forbids mem <2m .long 0,0,0,0 20: .long MAC_LC_SEGMENT_64 .long 30f-20b .ascin "__TEXT",16 - .quad macho # vaddr - .quad 4096 # memsz - .quad 0 # file offset - .quad filesz # file size - .long PROT_EXEC|PROT_READ|PROT_WRITE # maxprot - .long PROT_EXEC|PROT_READ # initprot - .long 1 # segment section count - .long 0 # flags -210: .ascin "__text",16 # section name (.text) - .ascin "__TEXT",16 - .quad _start # vaddr - .quad textsz # memsz - .long textoff # offset - .long 6 # align 2**3 = 64 - .long 0 # reloc table offset - .long 0 # relocation count - .long MAC_S_ATTR_SOME_INSTRUCTIONS # section type & attributes - .long 0,0,0 # reserved -30: .long MAC_LC_SEGMENT_64 + .quad macho // vaddr + .quad filesz // memsz + .quad 0 // file offset + .quad filesz // file size + .long PROT_EXEC|PROT_READ|PROT_WRITE // maxprot + .long PROT_EXEC|PROT_READ // initprot + .long 0 // segment section count + .long 0 // flags +30: .long MAC_LC_UUID .long 40f-30b - .ascin "__DATA",16 - .quad bss # vaddr - .quad bsssize # memsz - .quad 0 # offset - .quad 0 # file size - .long PROT_EXEC|PROT_READ|PROT_WRITE # maxprot - .long PROT_READ|PROT_WRITE # initprot - .long 1 # segment section count - .long 0 # flags -310: .ascin "__bss",16 # section name (.bss) - .ascin "__DATA",16 - .quad bss # vaddr - .quad bsssize # memsz - .long 0 # offset - .long 12 # align 2**12 = 4096 - .long 0 # reloc table offset - .long 0 # relocation count - .long MAC_S_ZEROFILL # section type & attributes - .long 0,0,0 # reserved -40: .long MAC_LC_UUID - .long 50f-40b - .quad 0x3fb29ee4ac6c87aa # uuid1 - .quad 0xdd2c9bb866d9eef8 # uuid2 -50: .long MAC_LC_UNIXTHREAD - .long 60f-50b # cmdsize - .long MAC_THREAD_NEXGEN32E # flavaflav - .long (520f-510f)/4 # count -510: .quad 0 # rax - .quad 0 # rbx - .quad 0 # rcx - .quad _HOSTXNU # rdx - .quad 0 # rdi - .quad 0 # rsi - .quad 0 # rbp - .quad 0 # rsp - .quad 0 # r8 - .quad 0 # r9 - .quad 0 # r10 - .quad 0 # r11 - .quad 0 # r12 - .quad 0 # r13 - .quad 0 # r14 - .quad 0 # r15 - .quad _start # rip - .quad 0 # rflags - .quad 0 # cs - .quad 0 # fs - .quad 0 # gs -520: -60: + .quad 0x3fb29ee4ac6c87aa // uuid1 + .quad 0xdd2c9bb866d9eef8 // uuid2 +40: .long MAC_LC_UNIXTHREAD + .long 50f-40b // cmdsize + .long MAC_THREAD_NEXGEN32E // flavaflav + .long (420f-410f)/4 // count +410: .quad 0 // rax + .quad 0 // rbx + .quad 0 // rcx + .quad 0 // rdx + .quad 0 // rdi + .quad 0 // rsi + .quad 0 // rbp + .quad 0 // rsp + .quad 0 // r8 + .quad 0 // r9 + .quad 0 // r10 + .quad 0 // r11 + .quad 0 // r12 + .quad 0 // r13 + .quad 0 // r14 + .quad 0 // r15 + .quad _start // rip + .quad 0 // rflags + .quad 0 // cs + .quad 0 // fs + .quad 0 // gs +420: +50: .endobj macho,globl .balign 64 -_start: - -// Hack for detecting M1 Rosetta environment. -// https://github.com/jart/cosmopolitan/issues/429#issuecomment-1166704377 - cmp $-1,%ebx - jne 0f - cmp $+1,%edx - jne 0f - mov $_HOSTXNU,%dl - xor %ecx,%ecx - -0: mov %rsp,%rsi +_start: mov $_HOSTXNU,%dl // xnu's not unix! + mov %rsp,%rsi // save real stack + sub $1024*1024,%rsp // room for allocs jmp ApeLoader .endfn _start,globl -__syscall_loader: +// Invokes system call. +// +// This function has eight parameters. The first seven are for +// arguments passed along to the system call. The eight is for +// the magic number that indicates which system call is called +// +// The return value follows the Linux kernel convention, where +// errors are returned as `-errno`. BSD systems are normalized +// to follow this convention automatically. +SystemCall: + mov %rcx,%r10 + mov 16(%rsp),%eax clc syscall - jc 1f - ret -1: neg %rax - ret - .endfn __syscall_loader,globl + jnc 1f + neg %rax +1: ret + .endfn SystemCall,globl diff --git a/ape/loader-macho.lds b/ape/loader-macho.lds deleted file mode 100644 index 973c182a5..000000000 --- a/ape/loader-macho.lds +++ /dev/null @@ -1,42 +0,0 @@ -/*-*- mode: ld-script; indent-tabs-mode: nil; tab-width: 2; coding: utf-8 -*-│ -│vi: set et sts=2 tw=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. │ -╚─────────────────────────────────────────────────────────────────────────────*/ -ENTRY(_start) - -SECTIONS { - . = 0x200000; - .text : { - *(.text) - *(.rodata .rodata.*) - . = ALIGN(4096); - } - filesz = . - macho; - textsz = . - _start; - .bss ALIGN(4096) : { - bss = .; - *(.bss) - . = ALIGN(4096); - } - memsz = . - macho; - /DISCARD/ : { - *(.*) - } -} - -bsssize = SIZEOF(.bss); -textoff = _start - macho; diff --git a/ape/loader.c b/ape/loader.c index 44d4550c4..103775969 100644 --- a/ape/loader.c +++ b/ape/loader.c @@ -16,11 +16,6 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "ape/loader.h" - -#define SET_EXE_FILE 0 /* needs root ;_; */ -#define TROUBLESHOOT 0 -#define TROUBLESHOOT_OS LINUX /** * @fileoverview APE Loader for GNU/Systemd/XNU/FreeBSD/NetBSD/OpenBSD @@ -110,7 +105,7 @@ #define MAP_ANONYMOUS (IsLinux() ? 32 : 4096) #define AT_EXECFN_LINUX 31 #define AT_EXECFN_NETBSD 2014 -#define ELFCLASS64 2 +#define ELFCLASS32 1 #define ELFDATA2LSB 1 #define EM_NEXGEN32E 62 #define ET_EXEC 2 @@ -127,6 +122,10 @@ #define PR_SET_MM 35 #define PR_SET_MM_EXE_FILE 13 +#define Min(X, Y) ((Y) > (X) ? (X) : (Y)) +#define Roundup(X, K) (((X) + (K)-1) & -(K)) +#define Rounddown(X, K) ((X) & -(K)) + #define Read32(S) \ ((unsigned)(255 & (S)[3]) << 030 | (unsigned)(255 & (S)[2]) << 020 | \ (unsigned)(255 & (S)[1]) << 010 | (unsigned)(255 & (S)[0]) << 000) @@ -141,14 +140,6 @@ (unsigned long)(255 & (S)[1]) << 010 | \ (unsigned long)(255 & (S)[0]) << 000) -struct PathSearcher { - char os; - unsigned long namelen; - const char *name; - const char *syspath; - char path[1024]; -}; - struct ElfEhdr { unsigned char e_ident[16]; unsigned short e_type; @@ -177,26 +168,43 @@ struct ElfPhdr { unsigned long p_align; }; -extern char ehdr[]; -extern char _end[]; -static void *syscall_; -static struct PathSearcher ps; -extern char __syscall_loader[]; +union ElfEhdrBuf { + struct ElfEhdr ehdr; + char buf[4096]; +}; -#if SET_EXE_FILE -static char relocated; -#endif +union ElfPhdrBuf { + struct ElfPhdr phdr; + char buf[4096]; +}; + +struct PathSearcher { + int os; + const char *name; + const char *syspath; + unsigned long namelen; + char path[1024]; +}; + +struct ApeLoader { + union ElfEhdrBuf ehdr; + union ElfPhdrBuf phdr; + struct PathSearcher ps; +}; + +long SystemCall(long arg1, // + long arg2, // + long arg3, // + long arg4, // + long arg5, // + long arg6, // + long arg7, // + long magi); static int ToLower(int c) { return 'A' <= c && c <= 'Z' ? c + ('a' - 'A') : c; } -char *MemCpy(char *d, const char *s, unsigned long n) { - unsigned long i = 0; - for (; i < n; ++i) d[i] = s[i]; - return d + n; -} - static unsigned long StrLen(const char *s) { unsigned long n = 0; while (*s++) ++n; @@ -212,6 +220,22 @@ static const char *MemChr(const char *s, unsigned char c, unsigned long n) { return 0; } +static void *MemMove(void *a, const void *b, unsigned long n) { + char *d = a; + unsigned long i; + const char *s = b; + if (d > s) { + for (i = n; i--;) { + d[i] = s[i]; + } + } else { + for (i = 0; i < n; ++i) { + d[i] = s[i]; + } + } + return d; +} + static char *GetEnv(char **p, const char *s) { unsigned long i, j; if (p) { @@ -256,168 +280,105 @@ static char *Itoa(char p[21], long x) { return Utoa(p, x); } -#if TROUBLESHOOT -const char *DescribeOs(int os) { - if (IsLinux()) { - return "GNU/SYSTEMD"; - } else if (IsXnu()) { - return "XNU"; - } else if (IsFreebsd()) { - return "FREEBSD"; - } else if (IsOpenbsd()) { - return "OPENBSD"; - } else if (IsNetbsd()) { - return "NETBSD"; - } else { - return "WUT"; - } -} -#endif - __attribute__((__noreturn__)) static void Exit(int rc, int os) { - asm volatile("call\t*%2" - : /* no outputs */ - : "a"((IsLinux() ? 60 : 1) | (IsXnu() ? 0x2000000 : 0)), "D"(rc), - "rm"(syscall_) - : "memory"); + SystemCall(rc, 0, 0, 0, 0, 0, 0, + (IsLinux() ? 60 : 1) | (IsXnu() ? 0x2000000 : 0)); __builtin_unreachable(); } -static void Close(int fd, int os) { - int ax, di; - asm volatile("call\t*%4" - : "=a"(ax), "=D"(di) - : "0"((IsLinux() ? 3 : 6) | (IsXnu() ? 0x2000000 : 0)), "1"(fd), - "rm"(syscall_) - : "rcx", "rdx", "rsi", "r8", "r9", "r10", "r11", "memory", "cc"); +static int Close(int fd, int os) { + return SystemCall(fd, 0, 0, 0, 0, 0, 0, + (IsLinux() ? 3 : 6) | (IsXnu() ? 0x2000000 : 0)); } -static int Read(int fd, void *data, int size, int os) { - long si; - int ax, di, dx; - asm volatile("call\t*%8" - : "=a"(ax), "=D"(di), "=S"(si), "=d"(dx) - : "0"((IsLinux() ? 0 : 3) | (IsXnu() ? 0x2000000 : 0)), "1"(fd), - "2"(data), "3"(size), "rm"(syscall_) - : "rcx", "r8", "r9", "r10", "r11", "memory"); - return ax; +static long Pread(int fd, void *data, unsigned long size, long off, int os) { + long magi; + if (IsLinux()) { + magi = 0x011; + } else if (IsXnu()) { + magi = 0x2000099; + } else if (IsFreebsd()) { + magi = 0x1db; + } else if (IsOpenbsd()) { + magi = 0x0a9; // OpenBSD v7.3+ + } else if (IsNetbsd()) { + magi = 0x0ad; + } else { + __builtin_unreachable(); + } + return SystemCall(fd, (long)data, size, off, off, 0, 0, magi); } -static void Write(int fd, const void *data, int size, int os) { - long si; - int ax, di, dx; - asm volatile("call\t*%8" - : "=a"(ax), "=D"(di), "=S"(si), "=d"(dx) - : "0"((IsLinux() ? 1 : 4) | (IsXnu() ? 0x2000000 : 0)), "1"(fd), - "2"(data), "3"(size), "rm"(syscall_) - : "rcx", "r8", "r9", "r10", "r11", "memory", "cc"); +static long Write(int fd, const void *data, unsigned long size, int os) { + return SystemCall(fd, (long)data, size, 0, 0, 0, 0, + (IsLinux() ? 1 : 4) | (IsXnu() ? 0x2000000 : 0)); } -static void Execve(const char *prog, char **argv, char **envp, int os) { - long ax, di, si, dx; - asm volatile("call\t*%8" - : "=a"(ax), "=D"(di), "=S"(si), "=d"(dx) - : "0"(59 | (IsXnu() ? 0x2000000 : 0)), "1"(prog), "2"(argv), - "3"(envp), "rm"(syscall_) - : "rcx", "r8", "r9", "r10", "r11", "memory", "cc"); +static int Execve(const char *prog, char **argv, char **envp, int os) { + return SystemCall((long)prog, (long)argv, (long)envp, 0, 0, 0, 0, + 59 | (IsXnu() ? 0x2000000 : 0)); } static int Access(const char *path, int mode, int os) { - int ax, si; - long dx, di; - asm volatile("call\t*%7" - : "=a"(ax), "=D"(di), "=S"(si), "=d"(dx) - : "0"((IsLinux() ? 21 : 33) | (IsXnu() ? 0x2000000 : 0)), - "1"(path), "2"(mode), "rm"(syscall_) - : "rcx", "r8", "r9", "r10", "r11", "memory", "cc"); - return ax; + return SystemCall((long)path, mode, 0, 0, 0, 0, 0, + (IsLinux() ? 21 : 33) | (IsXnu() ? 0x2000000 : 0)); } -static int Msyscall(long p, long n, int os) { - int ax; - long di, si; - if (!IsOpenbsd()) { - return 0; +static int Msyscall(long p, unsigned long n, int os) { + if (IsOpenbsd()) { + return SystemCall(p, n, 0, 0, 0, 0, 0, 37); } else { - asm volatile("call\t*%6" - : "=a"(ax), "=D"(di), "=S"(si) - : "0"(37), "1"(p), "2"(n), "rm"(syscall_) - : "rcx", "rdx", "r8", "r9", "r10", "r11", "memory", "cc"); - return ax; + return 0; } } static int Open(const char *path, int flags, int mode, int os) { - long di; - int ax, dx, si; - asm volatile("call\t*%8" - : "=a"(ax), "=D"(di), "=S"(si), "=d"(dx) - : "0"((IsLinux() ? 2 : 5) | (IsXnu() ? 0x2000000 : 0)), - "1"(path), "2"(flags), "3"(mode), "rm"(syscall_) - : "rcx", "r8", "r9", "r10", "r11", "memory", "cc"); - return ax; + return SystemCall((long)path, flags, mode, 0, 0, 0, 0, + (IsLinux() ? 2 : 5) | (IsXnu() ? 0x2000000 : 0)); } -__attribute__((__noinline__)) static long Mmap(long addr, long size, int prot, - int flags, int fd, long off, - int os) { - long ax, di, si, dx; - register int flags_ asm("r10") = flags; - register int fd_ asm("r8") = fd; - register long off_ asm("r9") = off; - asm volatile("push\t%%r9\n\t" - "push\t%%r9\n\t" - "call\t*%7\n\t" - "pop\t%%r9\n\t" - "pop\t%%r9" - : "=a"(ax), "=D"(di), "=S"(si), "=d"(dx), "+r"(flags_), - "+r"(fd_), "+r"(off_) - : "rm"(syscall_), - "0"((IsLinux() ? 9 - : IsFreebsd() ? 477 - : 197) | - (IsXnu() ? 0x2000000 : 0)), - "1"(addr), "2"(size), "3"(prot) - : "rcx", "r11", "memory", "cc"); - return ax; -} - -int MunmapLinux(const void *addr, unsigned long size) { - int ax; - asm volatile("syscall" - : "=a"(ax) - : "0"(11), "D"(addr), "S"(size) - : "rcx", "r11", "memory"); - return ax; -} - -int PrctlLinux(int op, long a, long b, long c, long d) { - int rc; - asm volatile("mov\t%5,%%r10\n\t" - "mov\t%6,%%r8\n\t" - "syscall" - : "=a"(rc) - : "0"(157), "D"(op), "S"(a), "d"(b), "g"(c), "g"(d) - : "rcx", "r8", "r10", "r11", "memory"); - return rc; -} - -static void Emit(int os, const char *s) { - Write(2, s, StrLen(s), os); -} - -static void Perror(int os, const char *c, int rc, const char *s) { - char ibuf[21]; - Emit(os, "ape error: "); - Emit(os, c); - Emit(os, ": "); - Emit(os, s); - if (rc) { - Emit(os, " failed errno="); - Itoa(ibuf, -rc); - Emit(os, ibuf); +static long Mmap(void *addr, unsigned long size, int prot, int flags, int fd, + long off, int os) { + long magi; + if (IsLinux()) { + magi = 9; + } else if (IsXnu()) { + magi = 0x2000000 | 197; + } else if (IsFreebsd()) { + magi = 477; + } else if (IsOpenbsd()) { + magi = 49; // OpenBSD v7.3+ + } else if (IsNetbsd()) { + magi = 197; + } else { + __builtin_unreachable(); } - Emit(os, "\n"); + return SystemCall((long)addr, size, prot, flags, fd, off, off, magi); +} + +static long Print(int os, int fd, const char *s, ...) { + int c; + unsigned n; + char b[512]; + __builtin_va_list va; + __builtin_va_start(va, s); + for (n = 0; s; s = __builtin_va_arg(va, const char *)) { + while ((c = *s++)) { + if (n < sizeof(b)) { + b[n++] = c; + } + } + } + __builtin_va_end(va); + return Write(fd, b, n, os); +} + +static void Perror(int os, const char *thing, long rc, const char *reason) { + char ibuf[21]; + ibuf[0] = 0; + if (rc) Itoa(ibuf, -rc); + Print(os, 2, "ape error: ", thing, ": ", reason, + rc ? " failed w/ errno " : "", ibuf, "\n", 0l); } __attribute__((__noreturn__)) static void Pexit(int os, const char *c, int rc, @@ -432,6 +393,15 @@ static int StrCmp(const char *l, const char *r) { return (l[i] & 255) - (r[i] & 255); } +static void *MemSet(void *a, int c, unsigned long n) { + char *d = a; + unsigned long i; + for (i = 0; i < n; ++i) { + d[i] = c; + } + return d; +} + static char EndsWithIgnoreCase(const char *p, unsigned long n, const char *s) { unsigned long i, m; if (n >= (m = StrLen(s))) { @@ -458,8 +428,8 @@ static char AccessCommand(struct PathSearcher *ps, const char *suffix, suffixlen = StrLen(suffix); if (pathlen + 1 + ps->namelen + suffixlen + 1 > sizeof(ps->path)) return 0; if (pathlen && ps->path[pathlen - 1] != '/') ps->path[pathlen++] = '/'; - MemCpy(ps->path + pathlen, ps->name, ps->namelen); - MemCpy(ps->path + pathlen + ps->namelen, suffix, suffixlen + 1); + MemMove(ps->path + pathlen, ps->name, ps->namelen); + MemMove(ps->path + pathlen + ps->namelen, suffix, suffixlen + 1); return !Access(ps->path, X_OK, ps->os); } @@ -507,37 +477,30 @@ static char *Commandv(struct PathSearcher *ps, int os, const char *name, } __attribute__((__noreturn__)) static void Spawn(int os, const char *exe, int fd, - long *sp, char *page, - struct ElfEhdr *e) { + long *sp, struct ElfEhdr *e, + struct ElfPhdr *p) { long rc; - unsigned long i; int prot, flags; - struct ElfPhdr *p; long code, codesize; - if (e->e_type != ET_EXEC) { - Pexit(os, exe, 0, "ELF e_type != ET_EXEC"); - } - if (e->e_machine != EM_NEXGEN32E) { - Pexit(os, exe, 0, "ELF e_machine != EM_NEXGEN32E"); - } - if (e->e_ident[EI_CLASS] != ELFCLASS64) { - Pexit(os, exe, 0, "ELF e_ident[EI_CLASS] != ELFCLASS64"); - } - if (e->e_ident[EI_DATA] != ELFDATA2LSB) { - Pexit(os, exe, 0, "ELF e_ident[EI_DATA] != ELFDATA2LSB"); - } - if (e->e_phoff + e->e_phnum * sizeof(*p) > 0x1000) { - Pexit(os, exe, 0, "ELF phdrs need to be in first page"); - } + unsigned long a, b, i; + code = 0; codesize = 0; - for (p = (struct ElfPhdr *)(page + e->e_phoff), i = e->e_phnum; i--;) { + for (i = e->e_phnum; i--;) { if (p[i].p_type == PT_DYNAMIC) { - Pexit(os, exe, 0, "not a real executable"); + Pexit(os, exe, 0, "not a static executable"); } - if (p[i].p_type != PT_LOAD) continue; - if ((p[i].p_vaddr | p[i].p_filesz | p[i].p_memsz | p[i].p_offset) & 0xfff) { - Pexit(os, exe, 0, "APE phdrs must be 4096-aligned and 4096-padded"); + if (p[i].p_type != PT_LOAD) { + continue; + } + if (!p[i].p_memsz) { + continue; + } + if (p[i].p_vaddr & 4095) { + Pexit(os, exe, 0, "APE phdr addr must be 4096-aligned"); + } + if (p[i].p_offset & 4095) { + Pexit(os, exe, 0, "APE phdr offset must be 4096-aligned"); } prot = 0; flags = MAP_FIXED | MAP_PRIVATE; @@ -552,16 +515,20 @@ __attribute__((__noreturn__)) static void Spawn(int os, const char *exe, int fd, code = p[i].p_vaddr; codesize = p[i].p_filesz; } - if (p[i].p_memsz > p[i].p_filesz) { - if ((rc = Mmap(p[i].p_vaddr + p[i].p_filesz, p[i].p_memsz - p[i].p_filesz, - prot, flags | MAP_ANONYMOUS, -1, 0, os)) < 0) { - Pexit(os, exe, rc, "bss mmap()"); + if (p[i].p_filesz) { + if ((rc = Mmap((void *)p[i].p_vaddr, p[i].p_filesz, prot, flags, fd, + p[i].p_offset, os)) < 0) { + Pexit(os, exe, rc, "image mmap"); + } + if ((a = Min(-p[i].p_filesz & 4095, p[i].p_memsz - p[i].p_filesz))) { + MemSet((void *)(p[i].p_vaddr + p[i].p_filesz), 0, a); } } - if (p[i].p_filesz) { - if ((rc = Mmap(p[i].p_vaddr, p[i].p_filesz, prot, flags, fd, - p[i].p_offset, os)) < 0) { - Pexit(os, exe, rc, "image mmap()"); + if ((b = Roundup(p[i].p_memsz, 4096)) > + (a = Roundup(p[i].p_filesz, 4096))) { + if ((rc = Mmap((void *)p[i].p_vaddr + a, b - a, prot, + flags | MAP_ANONYMOUS, -1, 0, os)) < 0) { + Pexit(os, exe, rc, "bss mmap"); } } } @@ -569,34 +536,15 @@ __attribute__((__noreturn__)) static void Spawn(int os, const char *exe, int fd, Pexit(os, exe, 0, "ELF needs PT_LOAD phdr w/ PF_X"); } -#if SET_EXE_FILE - // change /proc/pid/exe to new executable path - if (IsLinux() && relocated) { - MunmapLinux((char *)0x200000, (long)(_end - ehdr)); - PrctlLinux(PR_SET_MM, PR_SET_MM_EXE_FILE, fd, 0, 0); - } -#endif - Close(fd, os); - - // authorize only the loaded program to issue system calls. if this - // fails, then we pass a link to our syscall function to the program - // since it probably means a userspace program executed this loader - // and passed us a custom syscall function earlier. - if (Msyscall(code, codesize, os) != -1) { - syscall_ = 0; - } - -#if TROUBLESHOOT - Emit(TROUBLESHOOT_OS, "preparing to jump\n"); -#endif + Msyscall(code, codesize, os); // we clear all the general registers we can to have some wiggle room // to extend the behavior of this loader in the future. we don't need // to clear the xmm registers since the ape loader should be compiled // with the -mgeneral-regs-only flag. - register void *r8 asm("r8") = syscall_; asm volatile("xor\t%%eax,%%eax\n\t" + "xor\t%%r8d,%%r8d\n\t" "xor\t%%r9d,%%r9d\n\t" "xor\t%%r10d,%%r10d\n\t" "xor\t%%r11d,%%r11d\n\t" @@ -612,28 +560,36 @@ __attribute__((__noreturn__)) static void Spawn(int os, const char *exe, int fd, "xor\t%%ebp,%%ebp\n\t" "ret" : /* no outputs */ - : "D"(IsFreebsd() ? sp : 0), "S"(e->e_entry), "d"(sp), "c"(os), - "r"(r8) + : "D"(IsFreebsd() ? sp : 0), "S"(e->e_entry), "d"(sp), "c"(os) : "memory"); __builtin_unreachable(); } -__attribute__((__noreturn__)) void ApeLoader(long di, long *sp, char dl, - struct ApeLoader *handoff) { +static void TryElf(struct ApeLoader *M, const char *exe, int fd, long *sp, + int os) { + unsigned size; + if (Read32(M->ehdr.buf) == Read32("\177ELF") && // + M->ehdr.ehdr.e_type == ET_EXEC && // + M->ehdr.ehdr.e_machine == EM_NEXGEN32E && // + M->ehdr.ehdr.e_ident[EI_CLASS] != ELFCLASS32 && // + M->ehdr.ehdr.e_phentsize >= sizeof(M->phdr.phdr) && // + (size = (unsigned)M->ehdr.ehdr.e_phnum * M->ehdr.ehdr.e_phentsize) <= + sizeof(M->phdr.buf) && + Pread(fd, M->phdr.buf, size, M->ehdr.ehdr.e_phoff, os) == size) { + Spawn(os, exe, fd, sp, &M->ehdr.ehdr, &M->phdr.phdr); + } +} + +__attribute__((__noreturn__)) void ApeLoader(long di, long *sp, char dl) { int rc; - long *auxv; - struct ElfEhdr *eh; - int c, i, fd, os, argc; - char *p, *exe, *prog, **argv, **envp, *page; - static union { - struct ElfEhdr ehdr; - char p[0x1000]; - } u; + unsigned i, n; + int c, fd, os, argc; + struct ApeLoader *M; + long *auxv, *ap, *ew; + char *p, *exe, *prog, **argv, **envp; // detect freebsd - if (handoff) { - os = handoff->os; - } else if (SupportsXnu() && dl == XNU) { + if (SupportsXnu() && dl == XNU) { os = XNU; } else if (SupportsFreebsd() && di) { os = FREEBSD; @@ -653,134 +609,109 @@ __attribute__((__noreturn__)) void ApeLoader(long di, long *sp, char dl, } } - // get syscall function pointer - if (handoff && handoff->systemcall) { - syscall_ = handoff->systemcall; + // detect openbsd + if (SupportsOpenbsd() && !os && !auxv[0]) { + os = OPENBSD; + } + + // detect netbsd and find end of words + for (ap = auxv; ap[0]; ap += 2) { + if (SupportsNetbsd() && !os && ap[0] == AT_EXECFN_NETBSD) { + os = NETBSD; + } + } + ew = 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 + if (!os) { + os = LINUX; + } + + // we can load via shell, shebang, or binfmt_misc + 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. + prog = (char *)sp[3]; + argc = sp[3] = sp[0] - 3; + argv = (char **)((sp += 3) + 1); + } else if (argc < 2) { + Print(os, 2, + "usage: ape PROG [ARGV1,ARGV2,...]\n" + " ape - PROG [ARGV0,ARGV1,...]\n" + "αcτµαlly pδrταblε εxεcµταblε loader v1.1\n" + "copyright 2022 justine alexandra roberts tunney\n" + "https://justine.lol/ape.html\n", + 0l); + Exit(1, os); } else { - syscall_ = __syscall_loader; + prog = (char *)sp[2]; + argc = sp[1] = sp[0] - 1; + argv = (char **)((sp += 1) + 1); } - if (handoff) { - // we were called by ape_execve() - // no argument parsing is needed - // no path searching is needed - exe = handoff->prog; - fd = handoff->fd; - exe = handoff->prog; - page = handoff->page; - eh = (struct ElfEhdr *)handoff->page; - } else { - - // detect openbsd - if (SupportsOpenbsd() && !os && !auxv[0]) { - os = OPENBSD; - } - - // detect netbsd - if (SupportsNetbsd() && !os) { - for (; auxv[0]; auxv += 2) { - if (auxv[0] == AT_EXECFN_NETBSD) { - os = NETBSD; - break; - } - } - } - - // default operating system - if (!os) { - os = LINUX; - } - -#if SET_EXE_FILE - if (IsLinux() && !relocated) { - char *b1 = (char *)0x200000; - char *b2 = (char *)0x300000; - void (*pApeLoader)(long, long *, char, struct ApeLoader *); - Mmap((long)b2, (long)(_end - ehdr), PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0, os); - relocated = 1; - MemCpy(b2, b1, (long)(_end - ehdr)); - pApeLoader = (void *)((char *)&ApeLoader - b1 + b2); - pApeLoader(di, sp, dl, handoff); - } -#endif - - // we can load via shell, shebang, or binfmt_misc - 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. - prog = (char *)sp[3]; - argc = sp[3] = sp[0] - 3; - argv = (char **)((sp += 3) + 1); - } else if (argc < 2) { - Emit(os, "usage: ape PROG [ARGV1,ARGV2,...]\n" - " ape - PROG [ARGV0,ARGV1,...]\n" - "αcτµαlly pδrταblε εxεcµταblε loader v1.o\n" - "copyright 2022 justine alexandra roberts tunney\n" - "https://justine.lol/ape.html\n"); - Exit(1, os); - } else { - prog = (char *)sp[2]; - argc = sp[1] = sp[0] - 1; - argv = (char **)((sp += 1) + 1); - } - - if (!(exe = Commandv(&ps, os, prog, GetEnv(envp, "PATH")))) { - Pexit(os, prog, 0, "not found (maybe chmod +x)"); - } else if ((fd = Open(exe, O_RDONLY, 0, os)) < 0) { - Pexit(os, exe, fd, "open"); - } else if ((rc = Read(fd, u.p, sizeof(u.p), os)) < 0) { - Pexit(os, exe, rc, "read"); - } else if (rc != sizeof(u.p) && Read32(u.p) != Read32("\177ELF")) { - Pexit(os, exe, 0, "too small"); - } - - page = u.p; - eh = &u.ehdr; + // 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)"); + } 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) { + Pexit(os, exe, rc, "read"); + } else if (rc != sizeof(M->ehdr.buf)) { + Pexit(os, exe, 0, "too small"); } -#if TROUBLESHOOT - Emit(TROUBLESHOOT_OS, "os = "); - Emit(TROUBLESHOOT_OS, DescribeOs(os)); - Emit(TROUBLESHOOT_OS, "\n"); - for (i = 0; i < argc; ++i) { - Emit(TROUBLESHOOT_OS, "argv = "); - Emit(TROUBLESHOOT_OS, argv[i]); - Emit(TROUBLESHOOT_OS, "\n"); + // change argv[0] to resolved path if it's ambiguous + if (argc > 0 && *prog != '/' && *exe == '/' && !StrCmp(prog, argv[0])) { + argv[0] = exe; } -#endif - if ((IsXnu() && Read32(page) == 0xFEEDFACE + 1) || - (!IsXnu() && Read32(page) == Read32("\177ELF"))) { + // ape intended behavior + // 1. if file is a native executable, try to run it natively + // 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 4096 bytes of file + // 5. elf program headers may appear anywhere in the binary + if ((IsXnu() && Read32(M->ehdr.buf) == 0xFEEDFACE + 1) || + (!IsXnu() && Read32(M->ehdr.buf) == Read32("\177ELF"))) { Close(fd, os); Execve(exe, argv, envp, os); } - - // TODO(jart): Parse Mach-O for old APE binary support on XNU. - for (p = page; p < page + sizeof(u.p); ++p) { - if (Read64(p) != Read64("printf '")) continue; - for (i = 0, p += 8; p + 3 < page + sizeof(u.p) && (c = *p++) != '\'';) { - if (c == '\\') { - if ('0' <= *p && *p <= '7') { - c = *p++ - '0'; + if (Read64(M->ehdr.buf) == Read64("MZqFpD='") || + Read64(M->ehdr.buf) == Read64("jartsr='")) { + for (p = M->ehdr.buf; p < M->ehdr.buf + sizeof(M->ehdr.buf); ++p) { + if (Read64(p) != Read64("printf '")) { + continue; + } + for (i = 0, p += 8; + p + 3 < M->ehdr.buf + sizeof(M->ehdr.buf) && (c = *p++) != '\'';) { + if (c == '\\') { if ('0' <= *p && *p <= '7') { - c *= 8; - c += *p++ - '0'; + c = *p++ - '0'; if ('0' <= *p && *p <= '7') { c *= 8; c += *p++ - '0'; + if ('0' <= *p && *p <= '7') { + c *= 8; + c += *p++ - '0'; + } } } } + M->ehdr.buf[i++] = c; + } + if (i >= sizeof(M->ehdr.ehdr)) { + TryElf(M, exe, fd, sp, os); } - page[i++] = c; - } - if (i >= 64 && Read32(page) == Read32("\177ELF")) { - Spawn(os, exe, fd, sp, page, eh); } } - - Pexit(os, exe, 0, "could not find printf elf in first page"); + TryElf(M, exe, fd, sp, os); + Pexit(os, exe, 0, "Not an acceptable APE/ELF executable for x86-64"); } diff --git a/ape/loader.h b/ape/loader.h deleted file mode 100644 index 1892401c9..000000000 --- a/ape/loader.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef COSMOPOLITAN_APE_LOADER_H_ -#define COSMOPOLITAN_APE_LOADER_H_ - -#define APE_LOADER_BASE 0x200000 -#define APE_LOADER_SIZE 0x200000 -#define APE_LOADER_ENTRY 0x200400 -#define APE_LOADER_BSS (4096 * 2) -#define APE_LOADER_STACK 0x7f0000000000 -#define APE_BLOCK_BASE 0x7e0000000000 -#define APE_BLOCK_SIZE 0x000200000000 - -struct ApeLoader { - int fd; - int os; - char *prog; - char *page; - void *systemcall; -}; - -#endif /* COSMOPOLITAN_APE_LOADER_H_ */ diff --git a/ape/loader.lds b/ape/loader.lds index 0e3488386..326bbfeb3 100644 --- a/ape/loader.lds +++ b/ape/loader.lds @@ -20,24 +20,20 @@ ENTRY(_start) SECTIONS { . = 0x200000; - .text : { - *(.text) + .rodata : { + KEEP(*(.head)) *(.rodata .rodata.*) - . = ALIGN(64); - } - filesz = . - ehdr; - textsz = . - _start; - .bss ALIGN(4096) : { - bss = .; - *(.bss) . = ALIGN(4096); } - _end = .; - memsz = _end - ehdr; + .text : { + text = .; + *(.text) + } /DISCARD/ : { *(.*) } } -bsssize = SIZEOF(.bss); -textoff = _start - ehdr; +textsz = SIZEOF(.text); +rosize = SIZEOF(.rodata); +filesz = SIZEOF(.rodata) + SIZEOF(.text); diff --git a/build/bootstrap/ape.elf b/build/bootstrap/ape.elf index acdb60d3f..3218e7f76 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 a151b59c6..e29b98751 100755 Binary files a/build/bootstrap/ape.macho and b/build/bootstrap/ape.macho differ diff --git a/build/bootstrap/cocmd.com b/build/bootstrap/cocmd.com index ff1769d7b..d3846b120 100755 Binary files a/build/bootstrap/cocmd.com and b/build/bootstrap/cocmd.com differ diff --git a/build/bootstrap/compile.com b/build/bootstrap/compile.com index 36ddb819f..812b104b5 100755 Binary files a/build/bootstrap/compile.com and b/build/bootstrap/compile.com differ diff --git a/build/definitions.mk b/build/definitions.mk index 2b515e927..e041cdbcd 100644 --- a/build/definitions.mk +++ b/build/definitions.mk @@ -91,7 +91,7 @@ VM = o/third_party/qemu/qemu-aarch64 HOSTS ?= pi silicon else ARCH = x86_64 -HOSTS ?= freebsd openbsd netbsd rhel7 rhel5 xnu win10 +HOSTS ?= freebsd openbsd openbsd73 netbsd rhel7 rhel5 xnu win10 endif ifeq ($(PREFIX),) @@ -241,7 +241,10 @@ DEFAULT_LDFLAGS = \ -nostdlib \ --gc-sections \ --build-id=none \ - --no-dynamic-linker #--cref -Map=$@.map + --no-dynamic-linker + +# # generate linker report files +# DEFAULT_LDFLAGS += --cref -Map=$@.map ifeq ($(ARCH), aarch64) DEFAULT_LDFLAGS += \ diff --git a/libc/calls/calls.mk b/libc/calls/calls.mk index bba78da4b..987f3d879 100644 --- a/libc/calls/calls.mk +++ b/libc/calls/calls.mk @@ -123,6 +123,7 @@ endif o/$(MODE)/libc/calls/execl.o \ o/$(MODE)/libc/calls/execle.o \ o/$(MODE)/libc/calls/execlp.o \ +o/$(MODE)/libc/calls/execvpe.o \ o/$(MODE)/libc/calls/statfs.o \ o/$(MODE)/libc/calls/fstatfs.o \ o/$(MODE)/libc/calls/execve-sysv.o \ diff --git a/libc/calls/copy_file_range.c b/libc/calls/copy_file_range.c index be6cb8164..cf20058e2 100644 --- a/libc/calls/copy_file_range.c +++ b/libc/calls/copy_file_range.c @@ -124,6 +124,6 @@ ssize_t copy_file_range(int infd, int64_t *opt_in_out_inoffset, int outfd, END_CANCELLATION_POINT; STRACE("copy_file_range(%d, %s, %d, %s, %'zu, %#x) → %'ld% m", infd, DescribeInOutInt64(rc, opt_in_out_inoffset), outfd, - DescribeInOutInt64(rc, opt_in_out_outoffset), uptobytes, flags); + DescribeInOutInt64(rc, opt_in_out_outoffset), uptobytes, flags, rc); return rc; } diff --git a/libc/calls/execlp.c b/libc/calls/execlp.c index a2d97538d..962f20f46 100644 --- a/libc/calls/execlp.c +++ b/libc/calls/execlp.c @@ -19,6 +19,7 @@ #include "libc/calls/calls.h" #include "libc/mem/alloca.h" #include "libc/runtime/runtime.h" +#include "libc/str/str.h" #include "libc/sysv/errfuns.h" /** @@ -40,10 +41,16 @@ int execlp(const char *prog, const char *arg, ... /*, NULL*/) { char **argv; va_list va, vb; char pathbuf[PATH_MAX]; - if (!(exe = commandv(prog, pathbuf, sizeof(pathbuf)))) return -1; + + // resolve path of executable + if (!(exe = commandv(prog, pathbuf, sizeof(pathbuf)))) { + return -1; + } + + // turn varargs into array va_copy(vb, va); va_start(va, arg); - for (i = 0; va_arg(va, const char *); ++i) donothing; + for (i = 0; va_arg(va, const char *); ++i) (void)0; va_end(va); argv = alloca((i + 2) * sizeof(char *)); va_start(vb, arg); @@ -52,5 +59,14 @@ int execlp(const char *prog, const char *arg, ... /*, NULL*/) { if (!(argv[i] = va_arg(vb, const char *))) break; } va_end(vb); + + // change argv[0] to resolved path if it's ambiguous + // otherwise the program won't have much luck finding itself + if (argv[0] && *prog != '/' && *exe == '/' && !strcmp(prog, argv[0])) { + argv[0] = exe; + } + + // execute program + // tail call shouldn't be possible return execv(exe, argv); } diff --git a/libc/calls/execve-sysv.c b/libc/calls/execve-sysv.c index b99b976a2..095a23161 100644 --- a/libc/calls/execve-sysv.c +++ b/libc/calls/execve-sysv.c @@ -85,9 +85,9 @@ 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", buf))) || - CanExecute( - (ape = Join(firstnonnull(getenv("HOME"), "."), ".ape", buf))))) { + ".ape-1.1", buf))) || + CanExecute((ape = Join(firstnonnull(getenv("HOME"), "."), ".ape-1.1", + buf))))) { shargs[0] = ape; shargs[1] = "-"; shargs[2] = prog; diff --git a/libc/calls/execvpe.c b/libc/calls/execvpe.c index 1b067cce1..891388f2e 100644 --- a/libc/calls/execvpe.c +++ b/libc/calls/execvpe.c @@ -19,7 +19,9 @@ #include "libc/calls/calls.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" +#include "libc/mem/alloca.h" #include "libc/mem/mem.h" +#include "libc/str/str.h" #include "libc/sysv/errfuns.h" /** @@ -35,9 +37,32 @@ * @vforksafe */ int execvpe(const char *prog, char *const argv[], char *const *envp) { - char *exe; + size_t i; + char *exe, **argv2; char pathbuf[PATH_MAX]; - if (IsAsan() && !__asan_is_valid_str(prog)) return efault(); - if (!(exe = commandv(prog, pathbuf, sizeof(pathbuf)))) return -1; + + // validate memory + if (IsAsan() && + (!__asan_is_valid_str(prog) || !__asan_is_valid_strlist(argv))) { + return efault(); + } + + // resolve path of executable + if (!(exe = commandv(prog, pathbuf, sizeof(pathbuf)))) { + return -1; + } + + // change argv[0] to resolved path if it's ambiguous + // otherwise the program won't have much luck finding itself + if (argv[0] && *prog != '/' && *exe == '/' && !strcmp(prog, argv[0])) { + for (i = 0; argv[i++];) (void)0; + argv2 = alloca(i * sizeof(*argv)); + memcpy(argv2, argv, i * sizeof(*argv)); + argv2[0] = exe; + argv = argv2; + } + + // execute program + // tail call shouldn't be possible return execve(exe, argv, envp); } diff --git a/libc/calls/lseek.c b/libc/calls/lseek.c index ca6bbffa5..098fd3713 100644 --- a/libc/calls/lseek.c +++ b/libc/calls/lseek.c @@ -25,6 +25,7 @@ #include "libc/intrin/strace.internal.h" #include "libc/intrin/weaken.h" #include "libc/log/backtrace.internal.h" +#include "libc/sysv/errfuns.h" #include "libc/zipos/zipos.internal.h" /** @@ -79,12 +80,14 @@ int64_t lseek(int fd, int64_t offset, int whence) { if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) { rc = _weaken(__zipos_lseek)( (struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, offset, whence); - } else if (!IsWindows() && !IsOpenbsd() && !IsNetbsd()) { + } else if (IsLinux() || IsXnu() || IsFreebsd() || IsOpenbsd()) { rc = sys_lseek(fd, offset, whence, 0); - } else if (IsOpenbsd() || IsNetbsd()) { + } else if (IsNetbsd()) { rc = sys_lseek(fd, offset, offset, whence); - } else { + } else if (IsWindows()) { rc = sys_lseek_nt(fd, offset, whence); + } else { + rc = enosys(); } STRACE("lseek(%d, %'ld, %s) → %'ld% m", fd, offset, DescribeWhence(whence), rc); diff --git a/libc/crt/crt.S b/libc/crt/crt.S index 2a554ab4c..acd7c2000 100644 --- a/libc/crt/crt.S +++ b/libc/crt/crt.S @@ -22,6 +22,16 @@ #include "libc/runtime/internal.h" .section .start,"ax",@progbits +#if SupportsXnu() && defined(__x86_64__) +// XNU AMD64 Entrypoint +// +// @note Rosetta barely implements MAC_LC_UNIXTHREAD +// @note Rosetta sets many registers to weird values +_apple: mov $_HOSTXNU,%cl + jmp 1f + .endfn _apple,weak,hidden +#endif + // System Five userspace program entrypoint. // // @param rsp is [n,argv₀..argvₙ₋₁,0,envp₀..,0,auxv₀..,0,..] @@ -32,18 +42,6 @@ _start: #ifdef __x86_64__ -#if SupportsXnu() -// Hack for detecting M1 Rosetta environment. -// https://github.com/jart/cosmopolitan/issues/429#issuecomment-1166704377 - cmp $-1,%ebx - jne 0f - cmp $+1,%edx - jne 0f - mov $_HOSTXNU,%cl - xor %edi,%edi -0: -#endif - #if SupportsFreebsd() // detect free besiyata dishmaya test %rdi,%rdi @@ -54,7 +52,7 @@ _start: #endif // set operating system when already detected - mov %cl,__hostos(%rip) +1: mov %cl,__hostos(%rip) // get startup timestamp as early as possible // its used by --strace flag and kprintf() %T diff --git a/libc/sysv/calls/__sys_mmap.S b/libc/sysv/calls/__sys_mmap.S index b755700cb..13c9ea4cf 100644 --- a/libc/sysv/calls/__sys_mmap.S +++ b/libc/sysv/calls/__sys_mmap.S @@ -1,2 +1,2 @@ #include "libc/sysv/macros.internal.h" -.scall __sys_mmap,0x0c50c51dd20c5009,222,197,globl,hidden +.scall __sys_mmap,0x0c50311dd20c5009,222,197,globl,hidden diff --git a/libc/sysv/calls/sys_ftruncate.S b/libc/sysv/calls/sys_ftruncate.S index cfc07882a..72a0a5271 100644 --- a/libc/sysv/calls/sys_ftruncate.S +++ b/libc/sysv/calls/sys_ftruncate.S @@ -1,2 +1,2 @@ #include "libc/sysv/macros.internal.h" -.scall sys_ftruncate,0x8c98c99e028c984d,46,201,globl,hidden +.scall sys_ftruncate,0x8c98a89e028c984d,46,201,globl,hidden diff --git a/libc/sysv/calls/sys_lseek.S b/libc/sysv/calls/sys_lseek.S index 801f686de..be69cf837 100644 --- a/libc/sysv/calls/sys_lseek.S +++ b/libc/sysv/calls/sys_lseek.S @@ -1,2 +1,2 @@ #include "libc/sysv/macros.internal.h" -.scall sys_lseek,0x0c70c71de20c7008,62,199,globl,hidden +.scall sys_lseek,0x0c70a61de20c7008,62,199,globl,hidden diff --git a/libc/sysv/calls/sys_pread.S b/libc/sysv/calls/sys_pread.S index 3e5c635f7..76ab54a36 100644 --- a/libc/sysv/calls/sys_pread.S +++ b/libc/sysv/calls/sys_pread.S @@ -1,2 +1,2 @@ #include "libc/sysv/macros.internal.h" -.scall sys_pread,0x8ad8ad9db2899811,67,153,globl,hidden +.scall sys_pread,0x8ad8a99db2899811,67,153,globl,hidden diff --git a/libc/sysv/calls/sys_preadv.S b/libc/sysv/calls/sys_preadv.S index 5c8c1d5b9..4995aaed0 100644 --- a/libc/sysv/calls/sys_preadv.S +++ b/libc/sysv/calls/sys_preadv.S @@ -1,2 +1,2 @@ #include "libc/sysv/macros.internal.h" -.scall sys_preadv,0x92190b9212a1c927,69,540,globl,hidden +.scall sys_preadv,0x9218ab9212a1c927,69,540,globl,hidden diff --git a/libc/sysv/calls/sys_pwrite.S b/libc/sysv/calls/sys_pwrite.S index 7493fbecf..00d8fc5ca 100644 --- a/libc/sysv/calls/sys_pwrite.S +++ b/libc/sysv/calls/sys_pwrite.S @@ -1,2 +1,2 @@ #include "libc/sysv/macros.internal.h" -.scall sys_pwrite,0x8ae8ae9dc289a812,68,154,globl,hidden +.scall sys_pwrite,0x8ae8aa9dc289a812,68,154,globl,hidden diff --git a/libc/sysv/calls/sys_pwritev.S b/libc/sysv/calls/sys_pwritev.S index c4338ef62..c9692bf80 100644 --- a/libc/sysv/calls/sys_pwritev.S +++ b/libc/sysv/calls/sys_pwritev.S @@ -1,2 +1,2 @@ #include "libc/sysv/macros.internal.h" -.scall sys_pwritev,0x92290c9222a1d928,70,541,globl,hidden +.scall sys_pwritev,0x9228ac9222a1d928,70,541,globl,hidden diff --git a/libc/sysv/calls/sys_truncate.S b/libc/sysv/calls/sys_truncate.S index e75465ae2..4a3fcf6d0 100644 --- a/libc/sysv/calls/sys_truncate.S +++ b/libc/sysv/calls/sys_truncate.S @@ -1,2 +1,2 @@ #include "libc/sysv/macros.internal.h" -.scall sys_truncate,0x8c88c89df28c884c,45,200,globl,hidden +.scall sys_truncate,0x8c88a79df28c884c,45,200,globl,hidden diff --git a/libc/sysv/consts.sh b/libc/sysv/consts.sh index 963d90a25..3f48294f1 100755 --- a/libc/sysv/consts.sh +++ b/libc/sysv/consts.sh @@ -1706,16 +1706,16 @@ syscon nr __NR_fstat 0x0005 0x0050 0x2000153 0x0153 0x0227 0x0035 syscon nr __NR_lstat 0x0006 0x0fff 0x2000154 0x0154 0x0028 0x0028 0x1b9 0xfff syscon nr __NR_poll 0x0007 0x0fff 0x20000e6 0x00e6 0x00d1 0x00fc 0x0d1 0xfff syscon nr __NR_ppoll 0x010f 0x0049 0xfff 0xfff 0x0221 0x006d 0xfff 0xfff -syscon nr __NR_lseek 0x0008 0x003e 0x20000c7 0x00c7 0x01de 0x00c7 0x0c7 0xfff -syscon nr __NR_mmap 0x0009 0x00de 0x20000c5 0x00c5 0x01dd 0x00c5 0x0c5 0xfff +syscon nr __NR_lseek 0x0008 0x003e 0x20000c7 0x00c7 0x01de 0x00a6 0x0c7 0xfff # OpenBSD 7.3+ +syscon nr __NR_mmap 0x0009 0x00de 0x20000c5 0x00c5 0x01dd 0x0031 0x0c5 0xfff # OpenBSD 7.3+ syscon nr __NR_msync 0x001a 0x00e3 0x2000041 0x0041 0x0041 0x0100 0x115 0xfff syscon nr __NR_mprotect 0x000a 0x00e2 0x200004a 0x004a 0x004a 0x004a 0x04a 0xfff syscon nr __NR_munmap 0x000b 0x00d7 0x2000049 0x0049 0x0049 0x0049 0x049 0xfff syscon nr __NR_sigaction 0x000d 0x0086 0x200002e 0x002e 0x01a0 0x002e 0x154 0xfff syscon nr __NR_sigprocmask 0x000e 0x0087 0x2000149 0x0149 0x0154 0x0030 0x125 0xfff syscon nr __NR_ioctl 0x0010 0x001d 0x2000036 0x0036 0x0036 0x0036 0x036 0xfff -syscon nr __NR_pread 0x0011 0x0043 0x2000099 0x0099 0x01db 0x00ad 0x0ad 0xfff -syscon nr __NR_pwrite 0x0012 0x0044 0x200009a 0x009a 0x01dc 0x00ae 0x0ae 0xfff +syscon nr __NR_pread 0x0011 0x0043 0x2000099 0x0099 0x01db 0x00a9 0x0ad 0xfff # OpenBSD 7.3+ +syscon nr __NR_pwrite 0x0012 0x0044 0x200009a 0x009a 0x01dc 0x00aa 0x0ae 0xfff # OpenBSD 7.3+ syscon nr __NR_readv 0x0013 0x0041 0x2000078 0x0078 0x0078 0x0078 0x078 0xfff syscon nr __NR_writev 0x0014 0x0042 0x2000079 0x0079 0x0079 0x0079 0x079 0xfff syscon nr __NR_access 0x0015 0x0fff 0x2000021 0x0021 0x0021 0x0021 0x021 0xfff @@ -1779,8 +1779,8 @@ syscon nr __NR_fcntl 0x0048 0x0019 0x200005c 0x005c 0x005c 0x005c syscon nr __NR_flock 0x0049 0x0020 0x2000083 0x0083 0x0083 0x0083 0x083 0xfff syscon nr __NR_fsync 0x004a 0x0052 0x200005f 0x005f 0x005f 0x005f 0x05f 0xfff syscon nr __NR_fdatasync 0x004b 0x0053 0x20000bb 0x00bb 0x0226 0x005f 0x0f1 0xfff -syscon nr __NR_truncate 0x004c 0x002d 0x20000c8 0x00c8 0x01df 0x00c8 0x0c8 0xfff -syscon nr __NR_ftruncate 0x004d 0x002e 0x20000c9 0x00c9 0x01e0 0x00c9 0x0c9 0xfff +syscon nr __NR_truncate 0x004c 0x002d 0x20000c8 0x00c8 0x01df 0x00a7 0x0c8 0xfff # OpenBSD 7.3+ +syscon nr __NR_ftruncate 0x004d 0x002e 0x20000c9 0x00c9 0x01e0 0x00a8 0x0c9 0xfff # OpenBSD 7.3+ syscon nr __NR_getcwd 0x004f 0x0011 0xfff 0xfff 0x0146 0x0130 0x128 0xfff syscon nr __NR_chdir 0x0050 0x0031 0x200000c 0x000c 0x000c 0x000c 0x00c 0xfff syscon nr __NR_fchdir 0x0051 0x0032 0x200000d 0x000d 0x000d 0x000d 0x00d 0xfff @@ -1964,8 +1964,8 @@ syscon nr __NR_sync_file_range 0x0115 0x0054 0xfff 0xfff 0xfff 0xfff syscon nr __NR_vmsplice 0x0116 0x004b 0xfff 0xfff 0xfff 0xfff 0xfff 0xfff syscon nr __NR_migrate_pages 0x0100 0x00ee 0xfff 0xfff 0xfff 0xfff 0xfff 0xfff syscon nr __NR_move_pages 0x0117 0x00ef 0xfff 0xfff 0xfff 0xfff 0xfff 0xfff -syscon nr __NR_preadv 0x0127 0x0045 0xfff 0xfff 0x0121 0x010b 0x121 0xfff -syscon nr __NR_pwritev 0x0128 0x0046 0xfff 0xfff 0x0122 0x010c 0x122 0xfff +syscon nr __NR_preadv 0x0127 0x0045 0xfff 0xfff 0x0121 0x00ab 0x121 0xfff # OpenBSD 7.3+ +syscon nr __NR_pwritev 0x0128 0x0046 0xfff 0xfff 0x0122 0x00aa 0x122 0xfff # OpenBSD 7.3+ syscon nr __NR_utimensat 0x0118 0x0058 0xfff 0xfff 0x0223 0x0054 0x1d3 0xfff syscon nr __NR_fallocate 0x011d 0x002f 0xfff 0xfff 0xfff 0xfff 0xfff 0xfff syscon nr __NR_posix_fallocate 0xfff 0xfff 0xfff 0xfff 0x0212 0xfff 0x1df 0xfff diff --git a/libc/sysv/consts/__NR_ftruncate.S b/libc/sysv/consts/__NR_ftruncate.S index d8087ca18..87e88ccfa 100644 --- a/libc/sysv/consts/__NR_ftruncate.S +++ b/libc/sysv/consts/__NR_ftruncate.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon nr,__NR_ftruncate,0x004d,0x002e,0x20000c9,0x00c9,0x01e0,0x00c9,0x0c9,0xfff +.syscon nr,__NR_ftruncate,0x004d,0x002e,0x20000c9,0x00c9,0x01e0,0x00a8,0x0c9,0xfff diff --git a/libc/sysv/consts/__NR_lseek.S b/libc/sysv/consts/__NR_lseek.S index 00860cbfa..ae5351fff 100644 --- a/libc/sysv/consts/__NR_lseek.S +++ b/libc/sysv/consts/__NR_lseek.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon nr,__NR_lseek,0x0008,0x003e,0x20000c7,0x00c7,0x01de,0x00c7,0x0c7,0xfff +.syscon nr,__NR_lseek,0x0008,0x003e,0x20000c7,0x00c7,0x01de,0x00a6,0x0c7,0xfff diff --git a/libc/sysv/consts/__NR_mmap.S b/libc/sysv/consts/__NR_mmap.S index 2e3c8bc75..800992f3a 100644 --- a/libc/sysv/consts/__NR_mmap.S +++ b/libc/sysv/consts/__NR_mmap.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon nr,__NR_mmap,0x0009,0x00de,0x20000c5,0x00c5,0x01dd,0x00c5,0x0c5,0xfff +.syscon nr,__NR_mmap,0x0009,0x00de,0x20000c5,0x00c5,0x01dd,0x0031,0x0c5,0xfff diff --git a/libc/sysv/consts/__NR_pread.S b/libc/sysv/consts/__NR_pread.S index 5d071aac8..ddf74c805 100644 --- a/libc/sysv/consts/__NR_pread.S +++ b/libc/sysv/consts/__NR_pread.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon nr,__NR_pread,0x0011,0x0043,0x2000099,0x0099,0x01db,0x00ad,0x0ad,0xfff +.syscon nr,__NR_pread,0x0011,0x0043,0x2000099,0x0099,0x01db,0x00a9,0x0ad,0xfff diff --git a/libc/sysv/consts/__NR_preadv.S b/libc/sysv/consts/__NR_preadv.S index 77f9e97ab..c911ba8ed 100644 --- a/libc/sysv/consts/__NR_preadv.S +++ b/libc/sysv/consts/__NR_preadv.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon nr,__NR_preadv,0x0127,0x0045,0xfff,0xfff,0x0121,0x010b,0x121,0xfff +.syscon nr,__NR_preadv,0x0127,0x0045,0xfff,0xfff,0x0121,0x00ab,0x121,0xfff diff --git a/libc/sysv/consts/__NR_pwrite.S b/libc/sysv/consts/__NR_pwrite.S index 1d9ca0b36..90cd9021b 100644 --- a/libc/sysv/consts/__NR_pwrite.S +++ b/libc/sysv/consts/__NR_pwrite.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon nr,__NR_pwrite,0x0012,0x0044,0x200009a,0x009a,0x01dc,0x00ae,0x0ae,0xfff +.syscon nr,__NR_pwrite,0x0012,0x0044,0x200009a,0x009a,0x01dc,0x00aa,0x0ae,0xfff diff --git a/libc/sysv/consts/__NR_pwritev.S b/libc/sysv/consts/__NR_pwritev.S index 19cae2166..7e9a5405c 100644 --- a/libc/sysv/consts/__NR_pwritev.S +++ b/libc/sysv/consts/__NR_pwritev.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon nr,__NR_pwritev,0x0128,0x0046,0xfff,0xfff,0x0122,0x010c,0x122,0xfff +.syscon nr,__NR_pwritev,0x0128,0x0046,0xfff,0xfff,0x0122,0x00aa,0x122,0xfff diff --git a/libc/sysv/consts/__NR_truncate.S b/libc/sysv/consts/__NR_truncate.S index 856786287..cfd85a49c 100644 --- a/libc/sysv/consts/__NR_truncate.S +++ b/libc/sysv/consts/__NR_truncate.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon nr,__NR_truncate,0x004c,0x002d,0x20000c8,0x00c8,0x01df,0x00c8,0x0c8,0xfff +.syscon nr,__NR_truncate,0x004c,0x002d,0x20000c8,0x00c8,0x01df,0x00a7,0x0c8,0xfff diff --git a/libc/sysv/macros.internal.h b/libc/sysv/macros.internal.h index ed3f80ce0..20c53f379 100644 --- a/libc/sysv/macros.internal.h +++ b/libc/sysv/macros.internal.h @@ -50,6 +50,8 @@ ldr w9,[x9,#:lo12:__hostos] tbz x9,#3,1f // !IsXnu() mov x16,#\arm_xnu // apple ordinal + mov x9,#0 // clear carry flag + adds x9,x9,#0 // clear carry flag svc #0 // issue system call bcs 1f b _sysret diff --git a/libc/sysv/syscalls.sh b/libc/sysv/syscalls.sh index c1620fed3..90c7253b1 100755 --- a/libc/sysv/syscalls.sh +++ b/libc/sysv/syscalls.sh @@ -42,8 +42,8 @@ scall __sys_fstat 0x1b80352272153005 0x050 globl hidden # needs __stat2linux() scall __sys_lstat 0x1b90280282154006 0xfff globl hidden # needs __stat2linux(); blocked on Android scall __sys_poll 0x8d18fc8d128e6807 0xfff globl hidden scall sys_ppoll 0xfff86da21ffff90f 0x049 globl hidden # consider INTON/INTOFF tutorial in examples/unbourne.c -scall sys_lseek 0x0c70c71de20c7008 0x03e globl hidden # netbsd+openbsd:evilpad -scall __sys_mmap 0x0c50c51dd20c5009 0x0de globl hidden # netbsd+openbsd:pad +scall sys_lseek 0x0c70a61de20c7008 0x03e globl hidden # netbsd:evilpad, OpenBSD 7.3+ +scall __sys_mmap 0x0c50311dd20c5009 0x0de globl hidden # netbsd:pad, OpenBSD 7.3+ scall sys_msync 0x915900841284181a 0x0e3 globl hidden scall sys_mprotect 0x04a04a04a204a00a 0x0e2 globl hidden scall __sys_munmap 0x049049049204900b 0x0d7 globl hidden @@ -51,8 +51,8 @@ scall sys_sigaction 0x15402e1a0202e00d 0x086 globl hidden # rt_sigaction on Lun scall __sys_sigprocmask 0x125030154214900e 0x087 globl hidden # a.k.a. rt_sigprocmask, openbsd:byvalue, a.k.a. pthread_sigmask scall sys_ioctl 0x0360360362036010 0x01d globl hidden scall sys_ioctl_cp 0x8368368362836810 0x01d globl hidden # intended for TCSBRK -scall sys_pread 0x8ad8ad9db2899811 0x043 globl hidden # a.k.a. pread64; netbsd+openbsd:pad -scall sys_pwrite 0x8ae8ae9dc289a812 0x044 globl hidden # a.k.a. pwrite64; netbsd+openbsd:pad +scall sys_pread 0x8ad8a99db2899811 0x043 globl hidden # a.k.a. pread64; netbsd:pad, OpenBSD 7.3+ +scall sys_pwrite 0x8ae8aa9dc289a812 0x044 globl hidden # a.k.a. pwrite64; netbsd:pad, OpenBSD 7.3+ scall sys_readv 0x8788788782878813 0x041 globl hidden scall sys_writev 0x8798798792879814 0x042 globl hidden scall __sys_pipe 0x02a10721e202a016 0x03b globl hidden # NOTE: pipe2() on FreeBSD and Linux Aarch64; XNU is pipe(void)→eax:edx @@ -118,8 +118,8 @@ scall __sys_fcntl_cp 0x85c85c85c285c848 0x019 globl hidden # intended for F_SET scall sys_flock 0x8838838832883849 0x020 globl hidden scall sys_fsync 0x85f85f85f285f84a 0x052 globl hidden scall sys_fdatasync 0x8f185fa2628bb84b 0x053 globl hidden # fsync() on openbsd -scall sys_truncate 0x8c88c89df28c884c 0x02d globl hidden # netbsd+openbsd:pad -scall sys_ftruncate 0x8c98c99e028c984d 0x02e globl hidden # netbsd+openbsd:pad +scall sys_truncate 0x8c88a79df28c884c 0x02d globl hidden # netbsd:pad, OpenBSD 7.3+ +scall sys_ftruncate 0x8c98a89e028c984d 0x02e globl hidden # netbsd:pad, OpenBSD 7.3+ scall sys_getcwd 0x128130146ffff04f 0x011 globl hidden scall sys_chdir 0x00c00c00c200c050 0x031 globl hidden scall sys_fchdir 0x00d00d00d200d051 0x032 globl hidden @@ -296,8 +296,8 @@ scall sys_vmsplice 0xfffffffffffff116 0x04b globl hidden scall sys_migrate_pages 0xfffffffffffff100 0x0ee globl # no wrapper; numa numa yay scall sys_move_pages 0xfffffffffffff117 0x0ef globl # no wrapper; NOTE: We view Red Hat versions as "epochs" for all distros. #──────────────────────RHEL 5.0 LIMIT──────────────────────────────── # ←┬─ last distro with gplv2 licensed compiler c. 2007 -scall sys_preadv 0x92190b9212a1c927 0x045 globl hidden # ├─ last distro with system v shell script init -scall sys_pwritev 0x92290c9222a1d928 0x046 globl hidden # ├─ rob landley unleashes busybox gpl lawsuits +scall sys_preadv 0x9218ab9212a1c927 0x045 globl hidden # ├─ last distro with system v shell script init +scall sys_pwritev 0x9228ac9222a1d928 0x046 globl hidden # ├─ rob landley unleashes busybox gpl lawsuits scall __sys_utimensat 0x1d3054223ffff118 0x058 globl hidden # ├─ python modules need this due to pep513 scall sys_fallocate 0xfffffffffffff91d 0x02f globl # ├─ end of life 2020-11-30 (extended) scall sys_posix_fallocate 0x9dffffa12fffffff 0xfff globl hidden # └─ cosmopolitan supports rhel5+ @@ -774,7 +774,7 @@ scall sys_rtprio_thread 0xffffff1d2fffffff 0xfff globl # no wrapper #scall getrtable 0xfff137ffffffffff 0xfff globl #scall getthrid 0xfff12bffffffffff 0xfff globl #scall kbind 0xfff056ffffffffff 0xfff globl -#scall mquery 0xfff11effffffffff 0xfff globl # openbsd:pad +#scall mquery 0xfff11effffffffff 0xfff globl # openbsd:pad (todo) #scall obreak 0x011011ffffffffff 0xfff globl #scall sendsyslog 0xfff070ffffffffff 0xfff globl #scall setrtable 0xfff136ffffffffff 0xfff globl diff --git a/libc/testlib/showerror.c b/libc/testlib/showerror.c index 42a894edd..5edb74e41 100644 --- a/libc/testlib/showerror.c +++ b/libc/testlib/showerror.c @@ -16,6 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/assert.h" #include "libc/calls/calls.h" #include "libc/errno.h" #include "libc/fmt/fmt.h" @@ -49,9 +50,9 @@ void testlib_showerror(const char *file, int line, const char *func, "\t\t got %s\n" "\t%s%s\n" "\t%s%s\n", - RED2, UNBOLD, BLUE1, file, (long)line, RESET, method, func, - g_fixturename, hostname, getpid(), gettid(), code, v1, symbol, v2, - SUBTLE, strerror(errno), GetProgramExecutableName(), RESET); + RED2, UNBOLD, BLUE1, file, line, RESET, method, func, g_fixturename, + hostname, getpid(), gettid(), code, v1, symbol, v2, SUBTLE, + strerror(errno), GetProgramExecutableName(), RESET); free(v1); free(v2); } diff --git a/libc/testlib/testmain.c b/libc/testlib/testmain.c index e6dbc0582..75f92c486 100644 --- a/libc/testlib/testmain.c +++ b/libc/testlib/testmain.c @@ -16,6 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "ape/sections.internal.h" +#include "libc/assert.h" #include "libc/calls/calls.h" #include "libc/calls/struct/rlimit.h" #include "libc/calls/struct/sigaction.h" @@ -49,6 +51,7 @@ #include "libc/sysv/consts/f.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/poll.h" +#include "libc/sysv/consts/prot.h" #include "libc/sysv/consts/rlimit.h" #include "libc/sysv/consts/sig.h" #include "libc/testlib/testlib.h" diff --git a/test/libc/calls/write_test.c b/test/libc/calls/write_test.c index aaad1fb68..f1f4c20c3 100644 --- a/test/libc/calls/write_test.c +++ b/test/libc/calls/write_test.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" #include "libc/calls/calls.h" +#include "libc/calls/cp.internal.h" #include "libc/calls/internal.h" #include "libc/calls/struct/iovec.h" #include "libc/calls/struct/iovec.internal.h" @@ -100,8 +101,10 @@ BENCH(write, bench) { ASSERT_SYS(0, 3, open("/dev/null", O_WRONLY)); EZBENCH2("write", donothing, write(3, "hello", 5)); EZBENCH2("writev", donothing, writev(3, &(struct iovec){"hello", 5}, 1)); + BEGIN_CANCELLATION_POINT; EZBENCH2("sys_write", donothing, sys_write(3, "hello", 5)); EZBENCH2("sys_writev", donothing, sys_writev(3, &(struct iovec){"hello", 5}, 1)); + END_CANCELLATION_POINT; ASSERT_SYS(0, 0, close(3)); } diff --git a/test/libc/release/test.mk b/test/libc/release/test.mk index 986a79f09..9db6fe7d3 100644 --- a/test/libc/release/test.mk +++ b/test/libc/release/test.mk @@ -35,8 +35,11 @@ o/$(MODE)/test/libc/release/smoke.o: \ -Os \ -fno-pie \ -nostdinc \ + -Wl,--gc-sections \ -fno-omit-frame-pointer \ -include o/cosmopolitan.h \ + -Wl,-z,max-page-size=0x1000 \ + -Wl,-z,common-page-size=0x1000 \ $< o/$(MODE)/test/libc/release/smoke.com.dbg: \ @@ -49,6 +52,9 @@ o/$(MODE)/test/libc/release/smoke.com.dbg: \ -static \ -no-pie \ -nostdlib \ + --gc-sections \ + -z max-page-size=0x1000 \ + -z common-page-size=0x1000 \ -T o/$(MODE)/ape/public/ape.lds \ o/$(MODE)/test/libc/release/smoke.o \ o/$(MODE)/libc/crt/crt.o \ @@ -66,6 +72,9 @@ o/$(MODE)/test/libc/release/smoke-nms.com.dbg: \ -static \ -no-pie \ -nostdlib \ + --gc-sections \ + -z max-page-size=0x1000 \ + -z common-page-size=0x1000 \ -T o/$(MODE)/ape/public/ape.lds \ o/$(MODE)/test/libc/release/smoke.o \ o/$(MODE)/libc/crt/crt.o \ @@ -84,6 +93,9 @@ o/$(MODE)/test/libc/release/smoke-chibicc.com.dbg: \ -static \ -no-pie \ -nostdlib \ + --gc-sections \ + -z max-page-size=0x1000 \ + -z common-page-size=0x1000 \ -T o/$(MODE)/ape/public/ape.lds \ o/$(MODE)/test/libc/release/smoke-chibicc.o \ o/$(MODE)/libc/crt/crt.o \ @@ -121,6 +133,9 @@ o/$(MODE)/test/libc/release/smokecxx.com.dbg: \ -static \ -no-pie \ -nostdlib \ + --gc-sections \ + -z max-page-size=0x1000 \ + -z common-page-size=0x1000 \ -T o/$(MODE)/ape/public/ape.lds \ o/$(MODE)/test/libc/release/smokecxx.o \ o/$(MODE)/libc/crt/crt.o \ @@ -138,7 +153,10 @@ o/$(MODE)/test/libc/release/smokecxx.o: \ -Os \ -fno-pie \ -nostdinc \ + -Wl,--gc-sections \ -fno-omit-frame-pointer \ + -z max-page-size=0x1000 \ + -z common-page-size=0x1000 \ -include o/cosmopolitan.h \ test/libc/release/smokecxx.cc @@ -152,6 +170,9 @@ o/$(MODE)/test/libc/release/smokeansi.com.dbg: \ -static \ -no-pie \ -nostdlib \ + --gc-sections \ + -z max-page-size=0x1000 \ + -z common-page-size=0x1000 \ -T o/$(MODE)/ape/public/ape.lds \ o/$(MODE)/test/libc/release/smokeansi.o \ o/$(MODE)/libc/crt/crt.o \ @@ -170,8 +191,11 @@ o/$(MODE)/test/libc/release/smokeansi.o: \ -static \ -fno-pie \ -nostdinc \ + -Wl,--gc-sections \ -fno-omit-frame-pointer \ -include o/cosmopolitan.h \ + -Wl,-z,max-page-size=0x1000 \ + -Wl,-z,common-page-size=0x1000 \ test/libc/release/smoke.c # TODO(jart): Rewrite these shell scripts as C code. diff --git a/tool/emacs/cosmo-c-builtins.el b/tool/emacs/cosmo-c-builtins.el index 7612015cb..d70bed890 100644 --- a/tool/emacs/cosmo-c-builtins.el +++ b/tool/emacs/cosmo-c-builtins.el @@ -45,7 +45,10 @@ '("__builtin_va_list")) (gcc-builtin-functions - '("__builtin_add_overflow" + '("__builtin_va_start" + "__builtin_va_arg" + "__builtin_va_end" + "__builtin_add_overflow" "__builtin_add_overflow_p" "__builtin_alloc" "__builtin_alloca"