From 18ccfeb9191d723644d68ab125ad2cea696782ff Mon Sep 17 00:00:00 2001 From: Florian Lemaitre Date: Sat, 18 Sep 2021 01:49:10 +0200 Subject: [PATCH] Embed APE loader inside APE (#267) The `ape-no-modify-self.o` bootloader now has an mmap-based payload that helps read-only APE binaries be load faster since it doesn't need to copy any files. --- ape/ape.S | 26 +++++++++++++++++++++++++- ape/ape.lds | 12 ++++++++++++ ape/ape.mk | 4 ++-- 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/ape/ape.S b/ape/ape.S index 42a088287..85a468837 100644 --- a/ape/ape.S +++ b/ape/ape.S @@ -540,11 +540,30 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang // modify the binary to follow the local system's convention. // 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. + .ascii "type ape-loader >/dev/null 2>&1 && " + .ascii "exec ape-loader \"$o\" \"$@\"\n" +#ifdef APE_LOADER +// There is no system-wide APE loader, but there is one +// embedded inside the APE. So if the system is not MacOs, +// extract the loader into a temp folder, and use it to +// load the APE without modifying it. + .ascii "if [ ! -d /Applications ]; then\n" + .ascii "t=\"${TMPDIR:-/tmp}/ape-loader\"\n" + .ascii "[ -x \"$t\" ] || {\ndd 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" + .ascii "chmod 700 \"$t\"\n}\n" + .ascii "exec \"$t\" \"$o\" \"$@\"\n" + .ascii "fi\n" +#endif #ifndef APE_NO_MODIFY_SELF // The default behavior is: to overwrite the header in place. // We prefer this because it's a tiny constant one time cost. // We simply printf a 64-byte header and call execve() again. - .ascii "o=\"$(command -v \"$0\")\"\n" #ifdef APE_BUILDSAFE // This code is intended for binaries in build/bootstrap/. It // causes them to not self-modify since they're checked-in to @@ -645,6 +664,11 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang .ascii "fi\n" .ascii "exit $R\n" .endobj apesh +#ifdef APE_LOADER + .section .ape.loader,"a",@progbits + .incbin APE_LOADER + .previous +#endif /* APE_LOADER */ #endif /* SupportsWindows() || SupportsMetal() || SupportsXnu() */ #if SupportsSystemv() || SupportsMetal() diff --git a/ape/ape.lds b/ape/ape.lds index b772862b6..fc41a50b7 100644 --- a/ape/ape.lds +++ b/ape/ape.lds @@ -370,6 +370,15 @@ 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 = .); + } +/*END: payload */ /*BEGIN: bss memory void */ .zip . : { @@ -511,6 +520,9 @@ 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_macho_dd_skip, RVA(ape_macho) / 8); SHSTUB2(ape_macho_dd_count, (ape_macho_end - ape_macho) / 8); diff --git a/ape/ape.mk b/ape/ape.mk index 0a75630b0..af3e277f4 100644 --- a/ape/ape.mk +++ b/ape/ape.mk @@ -51,8 +51,8 @@ o/ape/idata.inc: \ $(APE_OBJS): $(BUILD_FILES) \ ape/ape.mk -o/$(MODE)/ape/ape-no-modify-self.o: ape/ape.S - @$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -DAPE_NO_MODIFY_SELF $< +o/$(MODE)/ape/ape-no-modify-self.o: ape/ape.S o/$(MODE)/examples/loader.elf + @$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -DAPE_LOADER="\"o/$(MODE)/examples/loader.elf\"" -DAPE_NO_MODIFY_SELF $< o/$(MODE)/ape/ape-buildsafe.o: ape/ape.S @$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -DAPE_BUILDSAFE $<