diff --git a/ape/ape.S b/ape/ape.S index b3ad01212..80a277166 100644 --- a/ape/ape.S +++ b/ape/ape.S @@ -487,6 +487,36 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang .ascii "el" #endif .ascii "if exec 7<> \"$o\"; then\n" + +// Writes 32-bit ELF header if --32 is the first argument +// This should be changed to check $(uname -m) on ENOEXEC + .ascii "if [ x\"$1\" = x--32 ]; then\n" + .ascii "printf '" + .ascii "\\177ELF" # 0x0: ⌂ELF + .ascii "\\1" # 4: legacy mode + .ascii "\\1" # 5: little endian + .ascii "\\1" # 6: elf v1.o + .ascii "\\011" # 7: FreeBSD + .ascii "\\0" # 8: os/abi ver. + .ascii "\\0\\0\\0" # 9: padding 3/7 + .ascii "\\0\\0\\0\\0" # padding 4/7 + .ascii "\\2\\0" # 10: εxεcµταblε + .ascii "\\3\\0" # 12: i386 + .ascii "\\1\\0\\0\\0" # 14: elf v1.o + .shstub ape_elf32_entry,4 # 18: e_entry + .shstub ape_elf32_phoff,4 # 1c: e_phoff + .shstub ape_elf32_shoff,4 # 20: e_shoff + .ascii "\\0\\0\\0\\0" # 24: e_flags + .ascii "\\100\\0" # 28: e_ehsize + .ascii "\\040\\0" # 2a: e_phentsize + .shstub ape_elf32_phnum,2 # 2c: e_phnum + .ascii "\\0\\0" # 2e: e_shentsize + .shstub ape_elf32_shnum,2 # 30: e_shnum + .shstub ape_elf32_shstrndx,2 # 32: e_shstrndx + .ascii "' >&7\n" + .ascii "else\n" + +// Standard 64-bit ELF Header .ascii "printf '" .ascii "\\177ELF" # 0x0: ⌂ELF .ascii "\\2" # 4: long mode @@ -510,6 +540,8 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang .shstub ape_elf_shnum,2 # 3c: e_shnum .shstub ape_elf_shstrndx,2 # 3e: e_shstrndx .ascii "' >&7\n" + .ascii "fi\n" + .ascii "exec 7<&-\n" .ascii "fi\n" .ascii "exec \"$0\" \"$@\"\n" # etxtbsy tail recursion diff --git a/ape/ape.lds b/ape/ape.lds index d1b1db3e8..d119b120c 100644 --- a/ape/ape.lds +++ b/ape/ape.lds @@ -207,6 +207,9 @@ SECTIONS { HIDDEN(ape_phdrs = .); KEEP(*(.elf.phdrs)) HIDDEN(ape_phdrs_end = .); + HIDDEN(ape_phdrs32 = .); + KEEP(*(.elf.phdrs32)) + HIDDEN(ape_phdrs32_end = .); /* OpenBSD */ . = ALIGN(__SIZEOF_POINTER__); @@ -246,7 +249,7 @@ SECTIONS { /*END: realmode addressability guarantee */ /* Normal Code */ - *(.start) + KEEP(*(.start)) KEEP(*(.initprologue)) KEEP(*(SORT_BY_NAME(.init.*))) KEEP(*(.init)) @@ -445,6 +448,13 @@ PFSTUB4(ape_elf_phnum, (ape_phdrs_end - ape_phdrs) / 56); PFSTUB4(ape_elf_shnum, 0); PFSTUB4(ape_elf_shstrndx, 0); +PFSTUB4(ape_elf32_entry, _start32); +PFSTUB4(ape_elf32_phoff, RVA(ape_phdrs32)); +PFSTUB4(ape_elf32_shoff, 0); +PFSTUB4(ape_elf32_phnum, (ape_phdrs32_end - ape_phdrs32) / 32); +PFSTUB4(ape_elf32_shnum, 0); +PFSTUB4(ape_elf32_shstrndx, 0); + HIDDEN(__privileged_addr = ROUNDDOWN(__privileged_start, PAGESIZE)); HIDDEN(__privileged_size = (ROUNDUP(__privileged_end, PAGESIZE) - ROUNDDOWN(__privileged_start, PAGESIZE))); diff --git a/build/bootstrap/ar.com b/build/bootstrap/ar.com index 304bb55c3..37b388da9 100755 Binary files a/build/bootstrap/ar.com and b/build/bootstrap/ar.com differ diff --git a/build/bootstrap/package.com b/build/bootstrap/package.com index b7a169cc6..385da7645 100755 Binary files a/build/bootstrap/package.com and b/build/bootstrap/package.com differ diff --git a/build/definitions.mk b/build/definitions.mk index 96f22072b..92ccf3303 100644 --- a/build/definitions.mk +++ b/build/definitions.mk @@ -299,6 +299,11 @@ OBJECTIFY.greg.c = \ -fno-sanitize=all \ -c +OBJECTIFY.i386.c = \ + $(OBJECTIFY.c) \ + -m32 \ + -wrapper build/i386ify.sh + OBJECTIFY.ansi.c = $(CC) $(OBJECTIFY.c.flags) -ansi -Wextra -Werror -pedantic-errors -c OBJECTIFY.c99.c = $(CC) $(OBJECTIFY.c.flags) -std=c99 -Wextra -Werror -pedantic-errors -c OBJECTIFY.c11.c = $(CC) $(OBJECTIFY.c.flags) -std=c11 -Wextra -Werror -pedantic-errors -c diff --git a/build/i386ify.sh b/build/i386ify.sh new file mode 100755 index 000000000..440bd235d --- /dev/null +++ b/build/i386ify.sh @@ -0,0 +1,35 @@ +#!/bin/sh +# +# SYNOPSIS +# +# gcc -m32 -wrapper build/i386ify.sh -c -o foo.o foo.c +# +# OVERVIEW +# +# Compiles 32-bit code inside 64-bit ELF objects. + +if [ "${1##*/}" = as ]; then + FIRST=0 + for x; do + if [ $FIRST -eq 0 ]; then + set -- + FIRST=1 + fi + if [ "$x" = "--32" ]; then + continue + fi + if [ "${x##*.}" = s ]; then + { + printf "\t.section .yoink\n" + printf "\tnopl\t_start32\n" + printf "\t.previous\n" + printf "\t.code32\n" + cat "$x" + } >"$x".tmp + mv -f "$x".tmp "$x" + fi + set -- "$@" "$x" + done +fi + +exec "$@" diff --git a/build/rules.mk b/build/rules.mk index 4941db97e..64c9f9e38 100644 --- a/build/rules.mk +++ b/build/rules.mk @@ -64,6 +64,7 @@ o/$(MODE)/%.lds: %.lds ; @$(COMPILE) -APREPROCESS $(PREPROCESS.lds) o/$(MODE)/%.h.ok: %.h ; @$(COMPILE) -ACHECK.h $(COMPILE.c) -x c -g0 -o $@ $< o/$(MODE)/%.h.okk: %.h ; @$(COMPILE) -ACHECK.h $(COMPILE.cxx) -x c++ -g0 -o $@ $< o/$(MODE)/%.o: %.greg.c ; @$(COMPILE) -AOBJECTIFY.greg $(OBJECTIFY.greg.c) $(OUTPUT_OPTION) $< +o/$(MODE)/%.i386.o: %.i386.c ; @$(COMPILE) -AOBJECTIFY.i386 $(OBJECTIFY.i386.c) $(OUTPUT_OPTION) $< o/$(MODE)/%.greg.o: %.greg.c ; @$(COMPILE) -AOBJECTIFY.greg $(OBJECTIFY.greg.c) $(OUTPUT_OPTION) $< o/$(MODE)/%.ansi.o: %.ansi.c ; @$(COMPILE) -AOBJECTIFY.ansi $(OBJECTIFY.ansi.c) $(OUTPUT_OPTION) $< o/$(MODE)/%.ansi.o: %.c ; @$(COMPILE) -AOBJECTIFY.ansi $(OBJECTIFY.ansi.c) $(OUTPUT_OPTION) $< diff --git a/examples/i386.i386.c b/examples/i386.i386.c new file mode 100644 index 000000000..cced3dba7 --- /dev/null +++ b/examples/i386.i386.c @@ -0,0 +1,19 @@ +#if 0 +/*─────────────────────────────────────────────────────────────────╗ +│ To the extent possible under law, Justine Tunney has waived │ +│ all copyright and related or neighboring rights to this file, │ +│ as it is written in the following disclaimers: │ +│ • http://unlicense.org/ │ +│ • http://creativecommons.org/publicdomain/zero/1.0/ │ +╚─────────────────────────────────────────────────────────────────*/ +#endif +#include "libc/str/str.h" + +char kTenFour[10] = {4, 4, 4, 4, 4, 4, 4, 4, 4, 4}; + +int main32(int argc, char *argv[]) { + return argc; + if (memset(argv[0], 4, 10) != argv[0]) return 1; + if (memcmp(argv[0], kTenFour, 10)) return 2; + return 0; +} diff --git a/libc/elf/iself64binary.c b/libc/elf/iself64binary.c index 8a7b4b86a..3fc241917 100644 --- a/libc/elf/iself64binary.c +++ b/libc/elf/iself64binary.c @@ -23,5 +23,6 @@ bool IsElf64Binary(const Elf64_Ehdr *elf, size_t mapsize) { if (mapsize < sizeof(Elf64_Ehdr)) return false; if (memcmp(elf->e_ident, ELFMAG, 4)) return false; return (elf->e_ident[EI_CLASS] == ELFCLASSNONE || - elf->e_ident[EI_CLASS] == ELFCLASS64); + elf->e_ident[EI_CLASS] == ELFCLASS64 || + elf->e_ident[EI_CLASS] == ELFCLASS32); } diff --git a/libc/nexgen32e/bsrmax.S b/libc/nexgen32e/bsrmax.S index fb9a058b8..566a112d6 100644 --- a/libc/nexgen32e/bsrmax.S +++ b/libc/nexgen32e/bsrmax.S @@ -33,6 +33,7 @@ // @param rsi:rdi is 128-bit unsigned 𝑥 value // @return eax number in range [0,128) or undef if 𝑥 is 0 // @see also treasure trove of nearly identical functions +// @mode legacy,long bsrmax: .leafprologue .profilable bsr %rsi,%rax diff --git a/libc/runtime/crt32.S b/libc/runtime/crt32.S new file mode 100644 index 000000000..53a029496 --- /dev/null +++ b/libc/runtime/crt32.S @@ -0,0 +1,84 @@ +/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ +│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "ape/macros.internal.h" +#include "libc/dce.h" +#include "libc/elf/def.h" +#include "libc/macros.h" +.section .start,"ax",@progbits +.code32 + +// @fileoverview 80386 APE UNIX CRT +// +// This module is yoinked by build/i386ify.sh when GNU make +// builds source codes that have the .i386.c file extension +// thereby avoiding some 386 bloat when it isn't being used +// +// TODO: Verify we can't use 64-bit ELF with i386 e_machine + +_start32: + .weak main32 + call main32 + mov %eax,%ebx + pushpop 1,%eax # _exit() ordinal + push %ebx # hybrid calling convention + push %eax # should work on Linux+BSDs + int $0x80 + ud2 + .endfn _start32,globl,hidden + + .section .elf.phdrs32,"a",@progbits + .long PT_LOAD # text segment + .stub ape_rom_offset,long + .stub ape_rom_vaddr,long + .stub ape_rom_paddr,long + .stub ape_rom_filesz,long + .stub ape_rom_memsz,long + .long PF_R|PF_X # <-- wut + .stub ape_rom_align,long + .long PT_LOAD # data segment + .stub ape_ram_offset,long + .stub ape_ram_vaddr,long + .stub ape_ram_paddr,long + .stub ape_ram_filesz,long + .stub ape_ram_memsz,long + .long PF_R|PF_W + .stub ape_ram_align,long +#if SupportsLinux() +// Linux ignores mprotect() and returns 0 without this lool +// It has nothing to do with the stack, which is still exec + .long PT_GNU_STACK # p_type + .long 0 # p_offset + .long 0 # p_vaddr + .long 0 # p_paddr + .long 0 # p_filesz + .long 0 # p_memsz + .long PF_R|PF_W # p_flags + .long 16 # p_align +#endif +#if SupportsOpenbsd() || SupportsNetbsd() + .long PT_NOTE # notes + .stub ape_note_offset,long + .stub ape_note_vaddr,long + .stub ape_note_paddr,long + .stub ape_note_filesz,long + .stub ape_note_memsz,long + .long PF_R + .stub ape_note_align,long +#endif + .previous