mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-06-30 08:18:30 +00:00
Write tests for new APE loader and fix bugs
- Add FreeBSD-specific mmap() flags - Reduce size of the APE loader from 8kb to 4kb - Work towards fixing the Makefile build on WSL - Automate testing of APE no-modify-self behaviors - Make the ape.S shell script code cleaner and tinier - Improve the APE sanity check to test behavior better - Fixed issue with ShowCrashReports() sigaltstack() on BSDs - Delete symbols for S_MODE magnums which wasted compile time If you checked out yesterday's APE commit, please run: rm -f /usr/bin/ape o/tmp/ape /tmp/ape "${TMPDIR:-/tmp}/ape" Because this change fixes certain aspects of the new ABI. We don't have automated migrations for APE loader versions yet. Thanks! You can also download prebuilt binaries here: - https://justine.lol/ape.elf (Linux/FreeBSD/NetBSD/OpenBSD) - https://justine.lol/ape.macho (Apple) Install the appropriate one as `/usr/bin/ape`.
This commit is contained in:
parent
056dc5f554
commit
4e9662cbc7
75 changed files with 759 additions and 443 deletions
145
ape/ape.S
145
ape/ape.S
|
@ -550,25 +550,25 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang
|
|||
// extract the loader into a temp folder, and use it to
|
||||
// load the APE without modifying it.
|
||||
.ascii "t=\"${TMPDIR:-/tmp}/ape\"\n"
|
||||
.ascii "if [ ! -x \"$t\" ]; then\n"
|
||||
.ascii "if [ ! -d /Applications ]; then\n"
|
||||
.ascii "dd if=\"$o\" of=\"$t.$$\" skip=\""
|
||||
.shstub ape_loader_dd_skip,2
|
||||
.ascii "\" count=\""
|
||||
.shstub ape_loader_dd_count,2
|
||||
.ascii "\" bs=64\n"
|
||||
#if SupportsXnu() && defined(APE_LOADER_MACHO)
|
||||
.ascii "else\n"
|
||||
.ascii "dd if=\"$o\" of=\"$t.$$\" skip=\""
|
||||
.shstub ape_loader_macho_dd_skip,2
|
||||
.ascii "\" count=\""
|
||||
.shstub ape_loader_macho_dd_count,2
|
||||
.ascii "\" bs=64\n"
|
||||
#endif /* APE_LOADER_MACHO */
|
||||
.ascii "fi 2>/dev/null &&\n"
|
||||
.ascii "chmod 755 \"$t.$$\" &&\n"
|
||||
.ascii "mv \"$t.$$\" \"$t\"\n"
|
||||
.ascii "fi\n"
|
||||
.ascii "[ -x \"$t\" ] || {\n"
|
||||
.ascii "dd if=\"$o\" of=\"$t.$$\" skip=\""
|
||||
.shstub ape_loader_dd_skip,2
|
||||
.ascii "\" count=\""
|
||||
.shstub ape_loader_dd_count,2
|
||||
.ascii "\" bs=64 2>/dev/null\n"
|
||||
#if SupportsXnu()
|
||||
.ascii "[ -d /Applications ] && "
|
||||
.ascii "dd if=\"$t.$$\""
|
||||
.ascii " of=\"$t.$$\""
|
||||
.ascii " skip=6"
|
||||
.ascii " count=10"
|
||||
.ascii " bs=64"
|
||||
.ascii " conv=notrunc"
|
||||
.ascii " 2>/dev/null\n"
|
||||
#endif /* SupportsXnu() */
|
||||
.ascii "chmod 755 \"$t.$$\"\n"
|
||||
.ascii "mv -f \"$t.$$\" \"$t\"\n"
|
||||
.ascii "}\n"
|
||||
.ascii "exec \"$t\" \"$o\" \"$@\"\n"
|
||||
#endif /* APE_LOADER */
|
||||
#ifndef APE_NO_MODIFY_SELF
|
||||
|
@ -589,15 +589,40 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang
|
|||
// then permission clashes can happen between system users,
|
||||
// since only root is able to set the sticky bit, which can
|
||||
// be addressed simply by overriding the TMPDIR environment
|
||||
.ascii "o=\"${TMPDIR:-/tmp}/$0\"\n"
|
||||
.ascii "if [ ! -e \"$o\" ]; then\n"
|
||||
.ascii "d=\"$o\"\n"
|
||||
.ascii "o=\"$o.$$\"\n"
|
||||
.ascii "mkdir -p \"${o%/*}\" 2>/dev/null\n"
|
||||
.ascii "cp -f \"$0\" \"$o\" || exit 120\n"
|
||||
.ascii "t=\"${TMPDIR:-/tmp}/$0\"\n"
|
||||
.ascii "[ -e \"$t\" ] || {\n"
|
||||
.ascii "mkdir -p \"${t%/*}\" 2>/dev/null\n"
|
||||
.ascii "cp -f \"$o\" \"$t.$$\" &&\n"
|
||||
.ascii "mv -f \"$t.$$\" \"$t\" || exit 120\n"
|
||||
.ascii "o=\"$t\"\n"
|
||||
#endif /* APE_NO_MODIFY_SELF */
|
||||
.ascii "exec 7<> \"$o\" || exit 121\n"
|
||||
.ascii "printf '"
|
||||
.ascii "\\177ELF" # 0x0: ⌂ELF
|
||||
.ascii "\\2" # 4: long 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 "\\076\\0" # 12: NexGen32e
|
||||
.ascii "\\1\\0\\0\\0" # 14: elf v1.o
|
||||
.shstub ape_elf_entry,8 # 18: e_entry
|
||||
.shstub ape_elf_phoff,8 # 20: e_phoff
|
||||
.shstub ape_elf_shoff,8 # 28: e_shoff
|
||||
.ascii "\\0\\0\\0\\0" # 30: e_flags
|
||||
.ascii "\\100\\0" # 34: e_ehsize
|
||||
.ascii "\\070\\0" # 36: e_phentsize
|
||||
.shstub ape_elf_phnum,2 # 38: e_phnum
|
||||
.ascii "\\0\\0" # 3a: e_shentsize
|
||||
.shstub ape_elf_shnum,2 # 3c: e_shnum
|
||||
.shstub ape_elf_shstrndx,2 # 3e: e_shstrndx
|
||||
.ascii "' >&7\n"
|
||||
.ascii "exec 7<&-\n"
|
||||
#if SupportsXnu()
|
||||
.ascii "if [ -d /Applications ]; then\n"
|
||||
.ascii "[ -d /Applications ] && "
|
||||
.ascii "dd if=\"$o\""
|
||||
.ascii " of=\"$o\""
|
||||
.ascii " bs=8"
|
||||
|
@ -606,54 +631,20 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang
|
|||
.ascii "\" count=\""
|
||||
.shstub ape_macho_dd_count,2
|
||||
.ascii "\" conv=notrunc 2>/dev/null\n"
|
||||
.ascii "el"
|
||||
#endif /* XNU */
|
||||
.ascii "if exec 7<> \"$o\"; then\n"
|
||||
.ascii "printf '"
|
||||
.ascii "\\177ELF" # 0x0: ⌂ELF
|
||||
.ascii "\\2" # 4: long 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 "\\076\\0" # 12: NexGen32e
|
||||
.ascii "\\1\\0\\0\\0" # 14: elf v1.o
|
||||
.shstub ape_elf_entry,8 # 18: e_entry
|
||||
.shstub ape_elf_phoff,8 # 20: e_phoff
|
||||
.shstub ape_elf_shoff,8 # 28: e_shoff
|
||||
.ascii "\\0\\0\\0\\0" # 30: e_flags
|
||||
.ascii "\\100\\0" # 34: e_ehsize
|
||||
.ascii "\\070\\0" # 36: e_phentsize
|
||||
.shstub ape_elf_phnum,2 # 38: e_phnum
|
||||
.ascii "\\0\\0" # 3a: e_shentsize
|
||||
.shstub ape_elf_shnum,2 # 3c: e_shnum
|
||||
.shstub ape_elf_shstrndx,2 # 3e: e_shstrndx
|
||||
.ascii "' >&7\n"
|
||||
.ascii "exec 7<&-\n"
|
||||
.ascii "else\n"
|
||||
.ascii "exit 121\n"
|
||||
.ascii "fi\n"
|
||||
#ifndef APE_NO_MODIFY_SELF
|
||||
.ascii "exec \"$0\" \"$@\"\n" # optimistic execution
|
||||
.ascii "exec \"$0\" \"$@\"\n" # try to preserve argv[0]
|
||||
#else
|
||||
.ascii "mv -f \"$o\" \"$d\" 2>/dev/null\n"
|
||||
.ascii "o=\"$d\"\n"
|
||||
.ascii "fi\n"
|
||||
.ascii "}\n"
|
||||
.ascii "o=\"$t\"\n"
|
||||
.ascii "exec \"$o\" \"$@\"\n"
|
||||
#endif /* APE_NO_MODIFY_SELF */
|
||||
.ascii "R=$?\n"
|
||||
.ascii "\n"
|
||||
.ascii "if [ $R -eq 126 ] && [ \"$(uname -m)\" != x86_64 ]; then\n"
|
||||
.ascii "if Q=\"$(command -v qemu-x86_64)\"; then\n"
|
||||
.ascii "if [ \"$(uname -m)\" != x86_64 ]; then\n"
|
||||
.ascii "Q=\"$(command -v qemu-x86_64)\" &&\n"
|
||||
.ascii "exec \"$Q\" \"$o\" \"$@\"\n"
|
||||
.ascii "else\n"
|
||||
.ascii "echo error: need qemu-x86_64 >&2\n"
|
||||
.ascii "fi\n"
|
||||
#ifndef APE_NO_MODIFY_SELF
|
||||
.ascii "elif [ $R -eq 127 ]; then\n" # means argv[0] was wrong
|
||||
.ascii "else\n" # means argv[0] was wrong
|
||||
.ascii " exec \"$o\" \"$@\"\n" # so do a path resolution
|
||||
#endif /* APE_NO_MODIFY_SELF */
|
||||
.ascii "fi\n"
|
||||
|
@ -661,14 +652,16 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang
|
|||
.endobj apesh
|
||||
#ifdef APE_LOADER
|
||||
.section .ape.loader,"a",@progbits
|
||||
.align 64
|
||||
ape_loader:
|
||||
.incbin APE_LOADER
|
||||
.endobj ape_loader,globl
|
||||
.align 64
|
||||
ape_loader_end:
|
||||
nop
|
||||
.endobj ape_loader_end,globl
|
||||
.previous
|
||||
#endif /* APE_LOADER */
|
||||
#if SupportsXnu() && defined(APE_LOADER_MACHO)
|
||||
.section .ape.loader-macho,"a",@progbits
|
||||
.incbin APE_LOADER_MACHO
|
||||
.previous
|
||||
#endif /* APE_LOADER_MACHO */
|
||||
#endif /* SupportsWindows() || SupportsMetal() || SupportsXnu() */
|
||||
|
||||
#if SupportsSystemv() || SupportsMetal()
|
||||
|
@ -1521,12 +1514,9 @@ kernel: movabs $ape_stack_vaddr,%rsp
|
|||
.byte 0x0f,0x1f,0207 # nop rdi binbase
|
||||
.long (IMAGE_BASE_VIRTUAL-IMAGE_BASE_REAL)/512
|
||||
#endif
|
||||
.weak __hostos
|
||||
ezlea __hostos,ax
|
||||
test %rax,%rax
|
||||
jz 1f
|
||||
movb $METAL,(%rax)
|
||||
1: push $0
|
||||
push $METAL # sets __hostos in crt.S
|
||||
pop %rcx
|
||||
push $0
|
||||
mov %rsp,%rbp
|
||||
mov .Lenv0(%rip),%rax
|
||||
mov %rax,(%rbp) # envp[0][0]
|
||||
|
@ -1542,7 +1532,6 @@ kernel: movabs $ape_stack_vaddr,%rsp
|
|||
push $1 # argc
|
||||
xor %ebp,%ebp
|
||||
xor %eax,%eax
|
||||
xor %ecx,%ecx
|
||||
xor %edx,%edx
|
||||
xor %edi,%edi
|
||||
xor %esi,%esi
|
||||
|
|
37
ape/ape.lds
37
ape/ape.lds
|
@ -243,10 +243,12 @@ 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))
|
||||
HIDDEN(_ereal = .);
|
||||
. += 1;
|
||||
|
||||
/*END: realmode addressability guarantee */
|
||||
/*BEGIN: morphable code */
|
||||
. += 1;
|
||||
|
||||
/* Normal Code */
|
||||
*(.start)
|
||||
|
@ -283,6 +285,7 @@ SECTIONS {
|
|||
/* Privileged code invulnerable to magic */
|
||||
KEEP(*(.ape.pad.privileged));
|
||||
. += . > 0 ? 1 : 0;
|
||||
/*END: morphable code */
|
||||
HIDDEN(__privileged_start = .);
|
||||
. += . > 0 ? 1 : 0;
|
||||
*(.privileged)
|
||||
|
@ -390,21 +393,6 @@ SECTIONS {
|
|||
} :Ram
|
||||
|
||||
/*END: file content that's loaded by o/s */
|
||||
/*BEGIN: payload (for now, only the APE loader) */
|
||||
.payload ALIGN(64) : {
|
||||
/* Loader */
|
||||
HIDDEN(ape_loader = .);
|
||||
KEEP(*(.ape.loader))
|
||||
. = ALIGN(64);
|
||||
HIDDEN(ape_loader_end = .);
|
||||
#if SupportsXnu()
|
||||
HIDDEN(ape_loader_macho = .);
|
||||
KEEP(*(.ape.loader-macho))
|
||||
. = ALIGN(64);
|
||||
HIDDEN(ape_loader_macho_end = .);
|
||||
#endif
|
||||
}
|
||||
/*END: payload */
|
||||
/*BEGIN: bss memory void */
|
||||
|
||||
.zip . : {
|
||||
|
@ -552,13 +540,14 @@ HIDDEN(ape_bss_filesz = 0);
|
|||
HIDDEN(ape_bss_memsz = SIZEOF(.bss));
|
||||
HIDDEN(ape_bss_align = PAGESIZE);
|
||||
|
||||
SHSTUB2(ape_loader_dd_skip, RVA(ape_loader) / 64);
|
||||
SHSTUB2(ape_loader_dd_count, (ape_loader_end - ape_loader) / 64);
|
||||
|
||||
#if SupportsXnu()
|
||||
SHSTUB2(ape_loader_macho_dd_skip, RVA(ape_loader_macho) / 64);
|
||||
SHSTUB2(ape_loader_macho_dd_count, (ape_loader_macho_end - ape_loader_macho) / 64);
|
||||
#endif
|
||||
/* 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 */
|
||||
/* let ape.S dd read past the end of the file into the wrapping binaries */
|
||||
SHSTUB2(ape_loader_dd_skip, DEFINED(ape_loader) ? RVA(ape_loader) / 64 : 0);
|
||||
SHSTUB2(ape_loader_dd_count,
|
||||
DEFINED(ape_loader_end)
|
||||
? ROUNDUP(ape_loader_end - ape_loader, PAGESIZE) / 64
|
||||
: 0);
|
||||
|
||||
#if SupportsXnu()
|
||||
SHSTUB2(ape_macho_dd_skip, RVA(ape_macho) / 8);
|
||||
|
|
68
ape/ape.mk
68
ape/ape.mk
|
@ -22,6 +22,10 @@ APE_NO_MODIFY_SELF = \
|
|||
o/$(MODE)/ape/ape.lds \
|
||||
o/$(MODE)/ape/ape-no-modify-self.o
|
||||
|
||||
APE_COPY_SELF = \
|
||||
o/$(MODE)/ape/ape.lds \
|
||||
o/$(MODE)/ape/ape-copy-self.o
|
||||
|
||||
APELINK = \
|
||||
$(COMPILE) \
|
||||
-ALINK.ape \
|
||||
|
@ -29,6 +33,22 @@ APELINK = \
|
|||
$(LINKARGS) \
|
||||
$(OUTPUT_OPTION)
|
||||
|
||||
APE_LOADER_FLAGS = \
|
||||
-DNDEBUG \
|
||||
-iquote. \
|
||||
-Wall \
|
||||
-Wextra \
|
||||
-fpie \
|
||||
-Os \
|
||||
-ffreestanding \
|
||||
-mgeneral-regs-only \
|
||||
-mno-red-zone \
|
||||
-fno-ident \
|
||||
-fno-gnu-unique \
|
||||
-c \
|
||||
$(OUTPUT_OPTION) \
|
||||
$<
|
||||
|
||||
APE_FILES := $(wildcard ape/*.*)
|
||||
APE_HDRS = $(filter %.h,$(APE_FILES))
|
||||
APE_INCS = $(filter %.inc,$(APE_FILES))
|
||||
|
@ -50,31 +70,55 @@ o/ape/idata.inc: \
|
|||
|
||||
o/$(MODE)/ape/ape-no-modify-self.o: \
|
||||
ape/ape.S \
|
||||
o/$(MODE)/ape/ape \
|
||||
o/$(MODE)/ape/ape.macho
|
||||
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -DAPE_LOADER="\"o/$(MODE)/ape/ape\"" -DAPE_LOADER_MACHO="\"o/$(MODE)/ape/ape.macho\"" $<
|
||||
o/$(MODE)/ape/ape.elf
|
||||
@$(COMPILE) \
|
||||
-AOBJECTIFY.S \
|
||||
$(OBJECTIFY.S) \
|
||||
$(OUTPUT_OPTION) \
|
||||
-DAPE_NO_MODIFY_SELF \
|
||||
-DAPE_LOADER="\"o/$(MODE)/ape/ape.elf\"" $<
|
||||
|
||||
o/$(MODE)/ape/ape-copy-self.o: \
|
||||
ape/ape.S
|
||||
@$(COMPILE) \
|
||||
-AOBJECTIFY.S \
|
||||
$(OBJECTIFY.S) \
|
||||
$(OUTPUT_OPTION) \
|
||||
-DAPE_NO_MODIFY_SELF $<
|
||||
|
||||
o/$(MODE)/ape/loader.o: ape/loader.c
|
||||
@$(COMPILE) -AOBJECTIFY.c $(CC) -DNDEBUG -iquote. -Wall -Wextra -fpie -Os -g -ffreestanding -mno-red-zone -fno-ident -fno-gnu-unique -c $(OUTPUT_OPTION) $<
|
||||
|
||||
@$(COMPILE) -AOBJECTIFY.c $(CC) -DSUPPORT_VECTOR=0b01111001 -g $(APE_LOADER_FLAGS)
|
||||
o/$(MODE)/ape/loader-gcc.asm: ape/loader.c
|
||||
@$(COMPILE) -AOBJECTIFY.c $(CC) -DNDEBUG -iquote. -Wall -Wextra -fpie -Os -g -ffreestanding -mno-red-zone -fno-ident -fno-gnu-unique -c -S $(OUTPUT_OPTION) $<
|
||||
@$(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/ape: \
|
||||
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)
|
||||
o/$(MODE)/ape/loader-xnu-clang.asm: ape/loader.c
|
||||
@$(COMPILE) -AOBJECTIFY.c $(CLANG) -DSUPPORT_VECTOR=0b00001000 -S -g0 $(APE_LOADER_FLAGS)
|
||||
|
||||
o/$(MODE)/ape/ape.elf: o/$(MODE)/ape/ape.elf.dbg
|
||||
o/$(MODE)/ape/ape.macho: o/$(MODE)/ape/ape.macho.dbg
|
||||
|
||||
o/$(MODE)/ape/ape.elf.dbg: \
|
||||
o/$(MODE)/ape/loader.o \
|
||||
o/$(MODE)/ape/loader-elf.o \
|
||||
ape/loader.lds
|
||||
@$(ELFLINK) -s -z max-page-size=0x10
|
||||
@$(ELFLINK) -z max-page-size=0x10
|
||||
|
||||
o/$(MODE)/ape/ape.macho: \
|
||||
o/$(MODE)/ape/loader.o \
|
||||
o/$(MODE)/ape/ape.macho.dbg: \
|
||||
o/$(MODE)/ape/loader-xnu.o \
|
||||
o/$(MODE)/ape/loader-macho.o \
|
||||
ape/loader-macho.lds
|
||||
@$(ELFLINK) -s -z max-page-size=0x10
|
||||
@$(ELFLINK) -z max-page-size=0x10
|
||||
|
||||
.PHONY: o/$(MODE)/ape
|
||||
o/$(MODE)/ape: $(APE) \
|
||||
$(APE_CHECKS) \
|
||||
o/$(MODE)/ape/ape \
|
||||
o/$(MODE)/ape/ape.elf \
|
||||
o/$(MODE)/ape/ape.macho \
|
||||
o/$(MODE)/ape/ape-copy-self.o \
|
||||
o/$(MODE)/ape/ape-no-modify-self.o
|
||||
|
|
|
@ -9,19 +9,19 @@ fi
|
|||
if [ -f o/depend ]; then
|
||||
# mkdeps.com build was successfully run so assume we can build
|
||||
echo >&2
|
||||
echo running: make -j8 o//ape/ape >&2
|
||||
make -j8 o//ape/ape || exit
|
||||
echo running: make -j8 o//ape/ape.elf >&2
|
||||
make -j8 o//ape/ape.elf || exit
|
||||
echo done >&2
|
||||
else
|
||||
# no evidence we can build, use prebuilt one
|
||||
mkdir -p o//ape || exit
|
||||
cp -af build/bootstrap/ape o//ape/ape
|
||||
cp -af build/bootstrap/ape.elf o//ape/ape.elf
|
||||
fi
|
||||
|
||||
echo >&2
|
||||
echo installing o//ape/ape to /usr/bin/ape >&2
|
||||
echo sudo mv -f o//ape/ape /usr/bin/ape >&2
|
||||
sudo mv -f o//ape/ape /usr/bin/ape || exit
|
||||
echo installing o//ape/ape.elf to /usr/bin/ape >&2
|
||||
echo sudo mv -f o//ape/ape.elf /usr/bin/ape >&2
|
||||
sudo mv -f o//ape/ape.elf /usr/bin/ape || exit
|
||||
echo done >&2
|
||||
|
||||
if [ -e /proc/sys/fs/binfmt_misc/APE ]; then
|
||||
|
|
186
ape/loader-elf.S
186
ape/loader-elf.S
|
@ -17,6 +17,9 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/elf/def.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/macho.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
||||
// APE Loader Executable Structure
|
||||
|
@ -44,48 +47,6 @@ ehdr: .ascii "\177ELF"
|
|||
.word 0 # e_shstrndx
|
||||
.endobj ehdr,globl
|
||||
|
||||
// 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)
|
||||
// xor %eax,%eax
|
||||
// inc %eax
|
||||
// jmp 0x200000
|
||||
//
|
||||
// @see APE_LOADER_ENTRY
|
||||
jg47h: .org 0x47
|
||||
.endobj jg47h
|
||||
_start: mov %rsp,%rsi
|
||||
jmp ApeLoader
|
||||
.endfn _start,globl
|
||||
|
||||
// System Call Entrpoint
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// @see APE_LOADER_SYSCALL
|
||||
sc50h: .org 0x50
|
||||
.endobj sc50h
|
||||
__syscall_loader:
|
||||
clc
|
||||
syscall
|
||||
jc 1f
|
||||
ret
|
||||
1: neg %rax
|
||||
ret
|
||||
.endfn __syscall_loader,globl
|
||||
|
||||
.align 8
|
||||
phdrs: .long PT_LOAD # p_type
|
||||
.long PF_R|PF_X # p_flags
|
||||
|
@ -94,7 +55,7 @@ phdrs: .long PT_LOAD # p_type
|
|||
.quad ehdr # p_paddr
|
||||
.quad filesz # p_filesz
|
||||
.quad filesz # p_memsz
|
||||
.quad PAGESIZE # p_align
|
||||
.quad 64 # p_align
|
||||
|
||||
.long PT_LOAD # p_type
|
||||
.long PF_R|PF_W # p_flags
|
||||
|
@ -103,7 +64,7 @@ phdrs: .long PT_LOAD # p_type
|
|||
.quad bss # p_paddr
|
||||
.quad 0 # p_filesz
|
||||
.quad bsssize # p_memsz
|
||||
.quad PAGESIZE # p_align
|
||||
.quad 64 # p_align
|
||||
|
||||
.long PT_GNU_STACK # p_type
|
||||
.long PF_R|PF_W # p_flags
|
||||
|
@ -138,3 +99,140 @@ note: .long 2f-1f
|
|||
3: .long 901000000
|
||||
4: .endobj note
|
||||
notesize = . - note
|
||||
|
||||
.align 64,0 # for ape.S dd
|
||||
.org 0x180 # for ape.S dd
|
||||
|
||||
// APE Loader XNU Header
|
||||
//
|
||||
// This header is dd'd backwards by the APE shell script when
|
||||
// running on Mac OS X.
|
||||
//
|
||||
// @see ape/ape.S
|
||||
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
|
||||
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 0,0,0,0
|
||||
20: .long MAC_LC_SEGMENT_64
|
||||
.long 30f-20b
|
||||
.ascin "__TEXT",16
|
||||
.quad ehdr # 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**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
|
||||
.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 XNU # 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:
|
||||
.endobj macho
|
||||
|
||||
.align 64,0 # for ape.S dd
|
||||
.org 0x400 # 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: mov %rsp,%rsi
|
||||
jmp ApeLoader
|
||||
.endfn _start,globl
|
||||
|
||||
// System Call Entrpoint
|
||||
//
|
||||
// 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:
|
||||
clc
|
||||
syscall
|
||||
jc 1f
|
||||
ret
|
||||
1: neg %rax
|
||||
ret
|
||||
.endfn __syscall_loader,globl
|
||||
|
|
|
@ -41,7 +41,7 @@ macho: .long 0xFEEDFACE+1
|
|||
.long 30f-20b
|
||||
.ascin "__TEXT",16
|
||||
.quad macho # vaddr
|
||||
.quad filesz # memsz
|
||||
.quad 4096 # memsz
|
||||
.quad 0 # file offset
|
||||
.quad filesz # file size
|
||||
.long PROT_EXEC|PROT_READ|PROT_WRITE # maxprot
|
||||
|
@ -53,7 +53,7 @@ macho: .long 0xFEEDFACE+1
|
|||
.quad _start # vaddr
|
||||
.quad textsz # memsz
|
||||
.long textoff # offset
|
||||
.long 3 # align 2**3 = 8
|
||||
.long 6 # align 2**3 = 64
|
||||
.long 0 # reloc table offset
|
||||
.long 0 # relocation count
|
||||
.long MAC_S_ATTR_SOME_INSTRUCTIONS # section type & attributes
|
||||
|
@ -112,7 +112,7 @@ macho: .long 0xFEEDFACE+1
|
|||
60:
|
||||
.endobj macho,globl
|
||||
|
||||
.align 8
|
||||
.align 64
|
||||
_start: mov %rsp,%rsi
|
||||
jmp ApeLoader
|
||||
.endfn _start,globl
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
ENTRY(_start)
|
||||
OUTPUT_FORMAT(binary)
|
||||
|
||||
SECTIONS {
|
||||
. = 0x200000;
|
||||
|
|
194
ape/loader.c
194
ape/loader.c
|
@ -22,7 +22,7 @@
|
|||
#define TROUBLESHOOT_OS LINUX
|
||||
|
||||
/**
|
||||
* @fileoverview APE Loader for GNU/Systemd and FreeBSD/NetBSD/OpenBSD
|
||||
* @fileoverview APE Loader for GNU/Systemd/XNU/FreeBSD/NetBSD/OpenBSD
|
||||
*
|
||||
* We recommend using the normal APE design, where binaries assimilate
|
||||
* themselves once by self-modifying the first 64 bytes. If that can't
|
||||
|
@ -30,7 +30,7 @@
|
|||
*
|
||||
* m=tiny
|
||||
* make -j8 MODE=$m o/$m/ape o/$m/examples/printargs.com
|
||||
* o/$m/ape/ape o/$m/examples/printargs.com
|
||||
* o/$m/ape/ape.elf o/$m/examples/printargs.com
|
||||
*
|
||||
* This is an embeddable Actually Portable Executable interpreter. The
|
||||
* `ape/ape.S` bootloader embeds this binary inside each binary that's
|
||||
|
@ -45,8 +45,12 @@
|
|||
* so your APE loader may be installed to your system as follows:
|
||||
*
|
||||
* m=tiny
|
||||
* make -j8 MODE=$m o/$m/ape/ape
|
||||
* sudo cp o/$m/ape/ape /usr/bin/ape
|
||||
* make -j8 MODE=$m o/$m/ape/ape.elf
|
||||
* sudo cp o/$m/ape/ape.elf /usr/bin/ape
|
||||
*
|
||||
* For Mac OS X systems you should install the `ape.macho` executable:
|
||||
*
|
||||
* sudo cp o/$m/ape/ape.macho /usr/bin/ape
|
||||
*
|
||||
* Your APE loader may be used as a shebang interpreter by doing this:
|
||||
*
|
||||
|
@ -57,7 +61,7 @@
|
|||
* However you won't need to do that, if your APE Loader is registered
|
||||
* as a binfmt_misc interpreter. You can do that as follows with root:
|
||||
*
|
||||
* sudo cp -f o/$m/ape/ape /usr/bin
|
||||
* sudo cp -f o/$m/ape/ape.elf /usr/bin
|
||||
* f=/proc/sys/fs/binfmt_misc/register
|
||||
* sudo sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >$f"
|
||||
*
|
||||
|
@ -78,13 +82,23 @@
|
|||
*/
|
||||
|
||||
#define LINUX 1
|
||||
#define METAL 2
|
||||
#define WINDOWS 4
|
||||
#define XNU 8
|
||||
#define OPENBSD 16
|
||||
#define FREEBSD 32
|
||||
#define NETBSD 64
|
||||
|
||||
#define SupportsLinux() (SUPPORT_VECTOR & LINUX)
|
||||
#define SupportsXnu() (SUPPORT_VECTOR & XNU)
|
||||
#define SupportsFreebsd() (SUPPORT_VECTOR & FREEBSD)
|
||||
#define SupportsOpenbsd() (SUPPORT_VECTOR & OPENBSD)
|
||||
#define SupportsNetbsd() (SUPPORT_VECTOR & NETBSD)
|
||||
|
||||
#define IsLinux() (SupportsLinux() && os == LINUX)
|
||||
#define IsXnu() (SupportsXnu() && os == XNU)
|
||||
#define IsFreebsd() (SupportsFreebsd() && os == FREEBSD)
|
||||
#define IsOpenbsd() (SupportsOpenbsd() && os == OPENBSD)
|
||||
#define IsNetbsd() (SupportsNetbsd() && os == NETBSD)
|
||||
|
||||
#define O_RDONLY 0
|
||||
#define PROT_READ 1
|
||||
#define PROT_WRITE 2
|
||||
|
@ -92,7 +106,7 @@
|
|||
#define MAP_SHARED 1
|
||||
#define MAP_PRIVATE 2
|
||||
#define MAP_FIXED 16
|
||||
#define MAP_ANONYMOUS (os == LINUX ? 32 : 4096)
|
||||
#define MAP_ANONYMOUS (IsLinux() ? 32 : 4096)
|
||||
#define AT_EXECFN_LINUX 31
|
||||
#define AT_EXECFN_NETBSD 2014
|
||||
#define ELFCLASS64 2
|
||||
|
@ -235,15 +249,15 @@ static char *Itoa(char p[21], long x) {
|
|||
|
||||
#if TROUBLESHOOT
|
||||
const char *DescribeOs(int os) {
|
||||
if (os == LINUX) {
|
||||
if (IsLinux()) {
|
||||
return "GNU/SYSTEMD";
|
||||
} else if (os == XNU) {
|
||||
} else if (IsXnu()) {
|
||||
return "XNU";
|
||||
} else if (os == FREEBSD) {
|
||||
} else if (IsFreebsd()) {
|
||||
return "FREEBSD";
|
||||
} else if (os == OPENBSD) {
|
||||
} else if (IsOpenbsd()) {
|
||||
return "OPENBSD";
|
||||
} else if (os == NETBSD) {
|
||||
} else if (IsNetbsd()) {
|
||||
return "NETBSD";
|
||||
} else {
|
||||
return "WUT";
|
||||
|
@ -251,40 +265,42 @@ const char *DescribeOs(int os) {
|
|||
}
|
||||
#endif
|
||||
|
||||
__attribute__((__noreturn__)) static void Exit(long rc, int os) {
|
||||
__attribute__((__noreturn__)) static void Exit(int rc, int os) {
|
||||
asm volatile("call\t*%2"
|
||||
: /* no outputs */
|
||||
: "a"((os == LINUX ? 60 : 1) | (os == XNU ? 0x2000000 : 0)),
|
||||
"D"(rc), "m"(syscall)
|
||||
: "a"((IsLinux() ? 60 : 1) | (IsXnu() ? 0x2000000 : 0)), "D"(rc),
|
||||
"rm"(syscall)
|
||||
: "memory");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
static void Close(long fd, int os) {
|
||||
long ax, di;
|
||||
static void Close(int fd, int os) {
|
||||
int ax, di;
|
||||
asm volatile("call\t*%4"
|
||||
: "=a"(ax), "=D"(di)
|
||||
: "0"((os == LINUX ? 3 : 6) | (os == XNU ? 0x2000000 : 0)),
|
||||
"1"(fd), "m"(syscall)
|
||||
: "0"((IsLinux() ? 3 : 6) | (IsXnu() ? 0x2000000 : 0)), "1"(fd),
|
||||
"rm"(syscall)
|
||||
: "rcx", "rdx", "rsi", "r8", "r9", "r10", "r11", "memory", "cc");
|
||||
}
|
||||
|
||||
static long Read(long fd, void *data, unsigned long size, int os) {
|
||||
long ax, di, si, dx;
|
||||
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"((os == LINUX ? 0 : 3) | (os == XNU ? 0x2000000 : 0)),
|
||||
"1"(fd), "2"(data), "3"(size), "m"(syscall)
|
||||
: "0"((IsLinux() ? 0 : 3) | (IsXnu() ? 0x2000000 : 0)), "1"(fd),
|
||||
"2"(data), "3"(size), "rm"(syscall)
|
||||
: "rcx", "r8", "r9", "r10", "r11", "memory");
|
||||
return ax;
|
||||
}
|
||||
|
||||
static void Write(long fd, const void *data, unsigned long size, int os) {
|
||||
long ax, di, si, dx;
|
||||
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"((os == LINUX ? 1 : 4) | (os == XNU ? 0x2000000 : 0)),
|
||||
"1"(fd), "2"(data), "3"(size), "m"(syscall)
|
||||
: "0"((IsLinux() ? 1 : 4) | (IsXnu() ? 0x2000000 : 0)), "1"(fd),
|
||||
"2"(data), "3"(size), "rm"(syscall)
|
||||
: "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
|
||||
}
|
||||
|
||||
|
@ -292,58 +308,68 @@ 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) | (os == XNU ? 0x2000000 : 0)), "1"(prog), "2"(argv),
|
||||
"3"(envp), "m"(syscall)
|
||||
: "0"(59 | (IsXnu() ? 0x2000000 : 0)), "1"(prog), "2"(argv),
|
||||
"3"(envp), "rm"(syscall)
|
||||
: "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
|
||||
}
|
||||
|
||||
static long Access(const char *path, int mode, int os) {
|
||||
long ax, dx, di, si;
|
||||
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"((os == LINUX ? 21 : 33) | (os == XNU ? 0x2000000 : 0)),
|
||||
"1"(path), "2"(mode), "m"(syscall)
|
||||
: "0"((IsLinux() ? 21 : 33) | (IsXnu() ? 0x2000000 : 0)),
|
||||
"1"(path), "2"(mode), "rm"(syscall)
|
||||
: "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
|
||||
return ax;
|
||||
}
|
||||
|
||||
static void Msyscall(long p, long n, int os) {
|
||||
long ax, di, si;
|
||||
if (os == OPENBSD) {
|
||||
static int Msyscall(long p, long n, int os) {
|
||||
int ax;
|
||||
long di, si;
|
||||
if (!IsOpenbsd()) {
|
||||
return 0;
|
||||
} else {
|
||||
asm volatile("call\t*%6"
|
||||
: "=a"(ax), "=D"(di), "=S"(si)
|
||||
: "0"(37), "1"(p), "2"(n), "m"(syscall)
|
||||
: "0"(37), "1"(p), "2"(n), "rm"(syscall)
|
||||
: "rcx", "rdx", "r8", "r9", "r10", "r11", "memory", "cc");
|
||||
return ax;
|
||||
}
|
||||
}
|
||||
|
||||
static long Open(const char *path, long flags, long mode, int os) {
|
||||
long ax, di, si, dx;
|
||||
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"((os == LINUX ? 2 : 5) | (os == XNU ? 0x2000000 : 0)),
|
||||
"1"(path), "2"(flags), "3"(mode), "m"(syscall)
|
||||
: "rcx", "r8", "r9", "r10", "r11", "memory");
|
||||
: "0"((IsLinux() ? 2 : 5) | (IsXnu() ? 0x2000000 : 0)),
|
||||
"1"(path), "2"(flags), "3"(mode), "rm"(syscall)
|
||||
: "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
|
||||
return ax;
|
||||
}
|
||||
|
||||
__attribute__((__noinline__)) long Mmap(long addr, long size, long prot,
|
||||
long flags, long fd, long off, int os) {
|
||||
long ax;
|
||||
register long flags_ asm("r10") = flags;
|
||||
register long fd_ asm("r8") = fd;
|
||||
__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"
|
||||
"call\t*%8\n\t"
|
||||
"push\t%%r9\n\t"
|
||||
"call\t*%7\n\t"
|
||||
"pop\t%%r9\n\t"
|
||||
"pop\t%%r9"
|
||||
: "=a"(ax)
|
||||
: "0"((os == LINUX ? 9
|
||||
: os == FREEBSD ? 477
|
||||
: 197) |
|
||||
(os == XNU ? 0x2000000 : 0)),
|
||||
"D"(addr), "S"(size), "d"(prot), "r"(flags_), "r"(fd_),
|
||||
"r"(off_), "m"(syscall)
|
||||
: "rcx", "r11", "memory");
|
||||
: "=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;
|
||||
}
|
||||
|
||||
|
@ -514,20 +540,33 @@ __attribute__((__noreturn__)) static void Spawn(int os, const char *exe, int fd,
|
|||
Pexit(os, exe, 0, "ELF needs PT_LOAD phdr w/ PF_X");
|
||||
}
|
||||
Close(fd, os);
|
||||
Msyscall(code, codesize, 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
|
||||
register long r8 asm("r8") = syscall;
|
||||
|
||||
// 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%%ebx,%%ebx\n\t"
|
||||
"xor\t%%r9d,%%r9d\n\t"
|
||||
"xor\t%%r10d,%%r10d\n\t"
|
||||
"xor\t%%r11d,%%r11d\n\t"
|
||||
"xor\t%%r12d,%%r12d\n\t"
|
||||
"xor\t%%r13d,%%r13d\n\t"
|
||||
"xor\t%%r14d,%%r14d\n\t"
|
||||
"xor\t%%r15d,%%r15d\n\t"
|
||||
"xor\t%%ebx,%%ebx\n\t" // netbsd dosen't clear this
|
||||
"xor\t%%r12d,%%r12d\n\t" // netbsd dosen't clear this
|
||||
"xor\t%%r13d,%%r13d\n\t" // netbsd dosen't clear this
|
||||
"xor\t%%r14d,%%r14d\n\t" // netbsd dosen't clear this
|
||||
"xor\t%%r15d,%%r15d\n\t" // netbsd dosen't clear this
|
||||
"mov\t%%rdx,%%rsp\n\t"
|
||||
"xor\t%%edx,%%edx\n\t"
|
||||
"push\t%%rsi\n\t"
|
||||
|
@ -535,7 +574,7 @@ __attribute__((__noreturn__)) static void Spawn(int os, const char *exe, int fd,
|
|||
"xor\t%%ebp,%%ebp\n\t"
|
||||
"ret"
|
||||
: /* no outputs */
|
||||
: "D"(os == FREEBSD ? sp : 0), "S"(e->e_entry), "d"(sp), "c"(os),
|
||||
: "D"(IsFreebsd() ? sp : 0), "S"(e->e_entry), "d"(sp), "c"(os),
|
||||
"r"(r8)
|
||||
: "memory");
|
||||
__builtin_unreachable();
|
||||
|
@ -543,7 +582,8 @@ __attribute__((__noreturn__)) static void Spawn(int os, const char *exe, int fd,
|
|||
|
||||
__attribute__((__noreturn__)) void ApeLoader(long di, long *sp, char dl,
|
||||
struct ApeLoader *handoff) {
|
||||
long rc, *auxv;
|
||||
int rc;
|
||||
long *auxv;
|
||||
struct ElfEhdr *ehdr;
|
||||
int c, i, fd, os, argc;
|
||||
char *p, *exe, *prog, **argv, **envp, *page;
|
||||
|
@ -553,13 +593,15 @@ __attribute__((__noreturn__)) void ApeLoader(long di, long *sp, char dl,
|
|||
} u;
|
||||
|
||||
// detect freebsd
|
||||
if (di) {
|
||||
if (handoff) {
|
||||
os = handoff->os;
|
||||
} else if (SupportsFreebsd() && di) {
|
||||
os = FREEBSD;
|
||||
sp = (long *)di;
|
||||
} else if (dl == XNU) {
|
||||
} else if (SupportsXnu() && dl == XNU) {
|
||||
os = XNU;
|
||||
} else {
|
||||
os = LINUX;
|
||||
os = 0;
|
||||
}
|
||||
|
||||
// extract arguments
|
||||
|
@ -586,19 +628,18 @@ __attribute__((__noreturn__)) void ApeLoader(long di, long *sp, char dl,
|
|||
// no path searching is needed
|
||||
exe = handoff->prog;
|
||||
fd = handoff->fd;
|
||||
os = handoff->os;
|
||||
exe = handoff->prog;
|
||||
page = handoff->page;
|
||||
ehdr = (struct ElfEhdr *)handoff->page;
|
||||
} else {
|
||||
|
||||
// detect openbsd
|
||||
if (!auxv[0]) {
|
||||
if (SupportsOpenbsd() && !os && !auxv[0]) {
|
||||
os = OPENBSD;
|
||||
}
|
||||
|
||||
// detect netbsd
|
||||
if (os == LINUX) {
|
||||
if (SupportsNetbsd() && !os) {
|
||||
for (; auxv[0]; auxv += 2) {
|
||||
if (auxv[0] == AT_EXECFN_NETBSD) {
|
||||
os = NETBSD;
|
||||
|
@ -607,6 +648,11 @@ __attribute__((__noreturn__)) void ApeLoader(long di, long *sp, char dl,
|
|||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
|
@ -654,11 +700,13 @@ __attribute__((__noreturn__)) void ApeLoader(long di, long *sp, char dl,
|
|||
}
|
||||
#endif
|
||||
|
||||
if (Read32(page) == Read32("\177ELF") || Read32(page) == 0xFEEDFACE + 1) {
|
||||
if ((IsXnu() && Read32(page) == 0xFEEDFACE + 1) ||
|
||||
(!IsXnu() && Read32(page) == 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++) != '\'';) {
|
||||
|
|
15
ape/loader.h
15
ape/loader.h
|
@ -1,14 +1,13 @@
|
|||
#ifndef COSMOPOLITAN_APE_LOADER_H_
|
||||
#define COSMOPOLITAN_APE_LOADER_H_
|
||||
|
||||
#define APE_LOADER_BASE 0x200000
|
||||
#define APE_LOADER_SIZE 0x200000
|
||||
#define APE_LOADER_BSS (PAGESIZE * 2)
|
||||
#define APE_LOADER_STACK 0x7f0000000000
|
||||
#define APE_LOADER_ENTRY (APE_LOADER_BASE + 0x47)
|
||||
#define APE_LOADER_SYSCALL (APE_LOADER_BASE + 0x50)
|
||||
#define APE_BLOCK_BASE 0x7e0000000000
|
||||
#define APE_BLOCK_SIZE 0x000200000000
|
||||
#define APE_LOADER_BASE 0x200000
|
||||
#define APE_LOADER_SIZE 0x200000
|
||||
#define APE_LOADER_ENTRY 0x200400
|
||||
#define APE_LOADER_BSS (PAGESIZE * 2)
|
||||
#define APE_LOADER_STACK 0x7f0000000000
|
||||
#define APE_BLOCK_BASE 0x7e0000000000
|
||||
#define APE_BLOCK_SIZE 0x000200000000
|
||||
|
||||
struct ApeLoader {
|
||||
int fd;
|
||||
|
|
|
@ -17,16 +17,16 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
ENTRY(_start)
|
||||
OUTPUT_FORMAT(binary)
|
||||
|
||||
SECTIONS {
|
||||
. = 0x200000;
|
||||
.text : {
|
||||
*(.text)
|
||||
*(.rodata .rodata.*)
|
||||
. = ALIGN(4096);
|
||||
. = ALIGN(64);
|
||||
}
|
||||
filesz = . - ehdr;
|
||||
textsz = . - _start;
|
||||
.bss ALIGN(4096) : {
|
||||
bss = .;
|
||||
*(.bss)
|
||||
|
@ -39,3 +39,4 @@ SECTIONS {
|
|||
}
|
||||
|
||||
bsssize = SIZEOF(.bss);
|
||||
textoff = _start - ehdr;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue