mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 11:37:35 +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
|
// extract the loader into a temp folder, and use it to
|
||||||
// load the APE without modifying it.
|
// load the APE without modifying it.
|
||||||
.ascii "t=\"${TMPDIR:-/tmp}/ape\"\n"
|
.ascii "t=\"${TMPDIR:-/tmp}/ape\"\n"
|
||||||
.ascii "if [ ! -x \"$t\" ]; then\n"
|
.ascii "[ -x \"$t\" ] || {\n"
|
||||||
.ascii "if [ ! -d /Applications ]; then\n"
|
.ascii "dd if=\"$o\" of=\"$t.$$\" skip=\""
|
||||||
.ascii "dd if=\"$o\" of=\"$t.$$\" skip=\""
|
.shstub ape_loader_dd_skip,2
|
||||||
.shstub ape_loader_dd_skip,2
|
.ascii "\" count=\""
|
||||||
.ascii "\" count=\""
|
.shstub ape_loader_dd_count,2
|
||||||
.shstub ape_loader_dd_count,2
|
.ascii "\" bs=64 2>/dev/null\n"
|
||||||
.ascii "\" bs=64\n"
|
#if SupportsXnu()
|
||||||
#if SupportsXnu() && defined(APE_LOADER_MACHO)
|
.ascii "[ -d /Applications ] && "
|
||||||
.ascii "else\n"
|
.ascii "dd if=\"$t.$$\""
|
||||||
.ascii "dd if=\"$o\" of=\"$t.$$\" skip=\""
|
.ascii " of=\"$t.$$\""
|
||||||
.shstub ape_loader_macho_dd_skip,2
|
.ascii " skip=6"
|
||||||
.ascii "\" count=\""
|
.ascii " count=10"
|
||||||
.shstub ape_loader_macho_dd_count,2
|
.ascii " bs=64"
|
||||||
.ascii "\" bs=64\n"
|
.ascii " conv=notrunc"
|
||||||
#endif /* APE_LOADER_MACHO */
|
.ascii " 2>/dev/null\n"
|
||||||
.ascii "fi 2>/dev/null &&\n"
|
#endif /* SupportsXnu() */
|
||||||
.ascii "chmod 755 \"$t.$$\" &&\n"
|
.ascii "chmod 755 \"$t.$$\"\n"
|
||||||
.ascii "mv \"$t.$$\" \"$t\"\n"
|
.ascii "mv -f \"$t.$$\" \"$t\"\n"
|
||||||
.ascii "fi\n"
|
.ascii "}\n"
|
||||||
.ascii "exec \"$t\" \"$o\" \"$@\"\n"
|
.ascii "exec \"$t\" \"$o\" \"$@\"\n"
|
||||||
#endif /* APE_LOADER */
|
#endif /* APE_LOADER */
|
||||||
#ifndef APE_NO_MODIFY_SELF
|
#ifndef APE_NO_MODIFY_SELF
|
||||||
|
@ -589,15 +589,40 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang
|
||||||
// then permission clashes can happen between system users,
|
// then permission clashes can happen between system users,
|
||||||
// since only root is able to set the sticky bit, which can
|
// since only root is able to set the sticky bit, which can
|
||||||
// be addressed simply by overriding the TMPDIR environment
|
// be addressed simply by overriding the TMPDIR environment
|
||||||
.ascii "o=\"${TMPDIR:-/tmp}/$0\"\n"
|
.ascii "t=\"${TMPDIR:-/tmp}/$0\"\n"
|
||||||
.ascii "if [ ! -e \"$o\" ]; then\n"
|
.ascii "[ -e \"$t\" ] || {\n"
|
||||||
.ascii "d=\"$o\"\n"
|
.ascii "mkdir -p \"${t%/*}\" 2>/dev/null\n"
|
||||||
.ascii "o=\"$o.$$\"\n"
|
.ascii "cp -f \"$o\" \"$t.$$\" &&\n"
|
||||||
.ascii "mkdir -p \"${o%/*}\" 2>/dev/null\n"
|
.ascii "mv -f \"$t.$$\" \"$t\" || exit 120\n"
|
||||||
.ascii "cp -f \"$0\" \"$o\" || exit 120\n"
|
.ascii "o=\"$t\"\n"
|
||||||
#endif /* APE_NO_MODIFY_SELF */
|
#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()
|
#if SupportsXnu()
|
||||||
.ascii "if [ -d /Applications ]; then\n"
|
.ascii "[ -d /Applications ] && "
|
||||||
.ascii "dd if=\"$o\""
|
.ascii "dd if=\"$o\""
|
||||||
.ascii " of=\"$o\""
|
.ascii " of=\"$o\""
|
||||||
.ascii " bs=8"
|
.ascii " bs=8"
|
||||||
|
@ -606,54 +631,20 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang
|
||||||
.ascii "\" count=\""
|
.ascii "\" count=\""
|
||||||
.shstub ape_macho_dd_count,2
|
.shstub ape_macho_dd_count,2
|
||||||
.ascii "\" conv=notrunc 2>/dev/null\n"
|
.ascii "\" conv=notrunc 2>/dev/null\n"
|
||||||
.ascii "el"
|
|
||||||
#endif /* XNU */
|
#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
|
#ifndef APE_NO_MODIFY_SELF
|
||||||
.ascii "exec \"$0\" \"$@\"\n" # optimistic execution
|
.ascii "exec \"$0\" \"$@\"\n" # try to preserve argv[0]
|
||||||
#else
|
#else
|
||||||
.ascii "mv -f \"$o\" \"$d\" 2>/dev/null\n"
|
.ascii "}\n"
|
||||||
.ascii "o=\"$d\"\n"
|
.ascii "o=\"$t\"\n"
|
||||||
.ascii "fi\n"
|
|
||||||
.ascii "exec \"$o\" \"$@\"\n"
|
.ascii "exec \"$o\" \"$@\"\n"
|
||||||
#endif /* APE_NO_MODIFY_SELF */
|
#endif /* APE_NO_MODIFY_SELF */
|
||||||
.ascii "R=$?\n"
|
.ascii "R=$?\n"
|
||||||
.ascii "\n"
|
.ascii "if [ \"$(uname -m)\" != x86_64 ]; then\n"
|
||||||
.ascii "if [ $R -eq 126 ] && [ \"$(uname -m)\" != x86_64 ]; then\n"
|
.ascii "Q=\"$(command -v qemu-x86_64)\" &&\n"
|
||||||
.ascii "if Q=\"$(command -v qemu-x86_64)\"; then\n"
|
|
||||||
.ascii "exec \"$Q\" \"$o\" \"$@\"\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
|
#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
|
.ascii " exec \"$o\" \"$@\"\n" # so do a path resolution
|
||||||
#endif /* APE_NO_MODIFY_SELF */
|
#endif /* APE_NO_MODIFY_SELF */
|
||||||
.ascii "fi\n"
|
.ascii "fi\n"
|
||||||
|
@ -661,14 +652,16 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang
|
||||||
.endobj apesh
|
.endobj apesh
|
||||||
#ifdef APE_LOADER
|
#ifdef APE_LOADER
|
||||||
.section .ape.loader,"a",@progbits
|
.section .ape.loader,"a",@progbits
|
||||||
|
.align 64
|
||||||
|
ape_loader:
|
||||||
.incbin APE_LOADER
|
.incbin APE_LOADER
|
||||||
|
.endobj ape_loader,globl
|
||||||
|
.align 64
|
||||||
|
ape_loader_end:
|
||||||
|
nop
|
||||||
|
.endobj ape_loader_end,globl
|
||||||
.previous
|
.previous
|
||||||
#endif /* APE_LOADER */
|
#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() */
|
#endif /* SupportsWindows() || SupportsMetal() || SupportsXnu() */
|
||||||
|
|
||||||
#if SupportsSystemv() || SupportsMetal()
|
#if SupportsSystemv() || SupportsMetal()
|
||||||
|
@ -1521,12 +1514,9 @@ kernel: movabs $ape_stack_vaddr,%rsp
|
||||||
.byte 0x0f,0x1f,0207 # nop rdi binbase
|
.byte 0x0f,0x1f,0207 # nop rdi binbase
|
||||||
.long (IMAGE_BASE_VIRTUAL-IMAGE_BASE_REAL)/512
|
.long (IMAGE_BASE_VIRTUAL-IMAGE_BASE_REAL)/512
|
||||||
#endif
|
#endif
|
||||||
.weak __hostos
|
push $METAL # sets __hostos in crt.S
|
||||||
ezlea __hostos,ax
|
pop %rcx
|
||||||
test %rax,%rax
|
push $0
|
||||||
jz 1f
|
|
||||||
movb $METAL,(%rax)
|
|
||||||
1: push $0
|
|
||||||
mov %rsp,%rbp
|
mov %rsp,%rbp
|
||||||
mov .Lenv0(%rip),%rax
|
mov .Lenv0(%rip),%rax
|
||||||
mov %rax,(%rbp) # envp[0][0]
|
mov %rax,(%rbp) # envp[0][0]
|
||||||
|
@ -1542,7 +1532,6 @@ kernel: movabs $ape_stack_vaddr,%rsp
|
||||||
push $1 # argc
|
push $1 # argc
|
||||||
xor %ebp,%ebp
|
xor %ebp,%ebp
|
||||||
xor %eax,%eax
|
xor %eax,%eax
|
||||||
xor %ecx,%ecx
|
|
||||||
xor %edx,%edx
|
xor %edx,%edx
|
||||||
xor %edi,%edi
|
xor %edi,%edi
|
||||||
xor %esi,%esi
|
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 */
|
/* Code that needs to be addressable in Real Mode */
|
||||||
*(.text.real)
|
*(.text.real)
|
||||||
KEEP(*(SORT_BY_NAME(.sort.text.real.*)))
|
KEEP(*(SORT_BY_NAME(.sort.text.real.*)))
|
||||||
|
/* Code we want earlier in the binary w/o modifications */
|
||||||
|
KEEP(*(.ape.loader))
|
||||||
HIDDEN(_ereal = .);
|
HIDDEN(_ereal = .);
|
||||||
. += 1;
|
|
||||||
|
|
||||||
/*END: realmode addressability guarantee */
|
/*END: realmode addressability guarantee */
|
||||||
|
/*BEGIN: morphable code */
|
||||||
|
. += 1;
|
||||||
|
|
||||||
/* Normal Code */
|
/* Normal Code */
|
||||||
*(.start)
|
*(.start)
|
||||||
|
@ -283,6 +285,7 @@ SECTIONS {
|
||||||
/* Privileged code invulnerable to magic */
|
/* Privileged code invulnerable to magic */
|
||||||
KEEP(*(.ape.pad.privileged));
|
KEEP(*(.ape.pad.privileged));
|
||||||
. += . > 0 ? 1 : 0;
|
. += . > 0 ? 1 : 0;
|
||||||
|
/*END: morphable code */
|
||||||
HIDDEN(__privileged_start = .);
|
HIDDEN(__privileged_start = .);
|
||||||
. += . > 0 ? 1 : 0;
|
. += . > 0 ? 1 : 0;
|
||||||
*(.privileged)
|
*(.privileged)
|
||||||
|
@ -390,21 +393,6 @@ SECTIONS {
|
||||||
} :Ram
|
} :Ram
|
||||||
|
|
||||||
/*END: file content that's loaded by o/s */
|
/*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 */
|
/*BEGIN: bss memory void */
|
||||||
|
|
||||||
.zip . : {
|
.zip . : {
|
||||||
|
@ -552,13 +540,14 @@ HIDDEN(ape_bss_filesz = 0);
|
||||||
HIDDEN(ape_bss_memsz = SIZEOF(.bss));
|
HIDDEN(ape_bss_memsz = SIZEOF(.bss));
|
||||||
HIDDEN(ape_bss_align = PAGESIZE);
|
HIDDEN(ape_bss_align = PAGESIZE);
|
||||||
|
|
||||||
SHSTUB2(ape_loader_dd_skip, RVA(ape_loader) / 64);
|
/* we roundup here because xnu wants the file load segments page-aligned */
|
||||||
SHSTUB2(ape_loader_dd_count, (ape_loader_end - ape_loader) / 64);
|
/* 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 */
|
||||||
#if SupportsXnu()
|
SHSTUB2(ape_loader_dd_skip, DEFINED(ape_loader) ? RVA(ape_loader) / 64 : 0);
|
||||||
SHSTUB2(ape_loader_macho_dd_skip, RVA(ape_loader_macho) / 64);
|
SHSTUB2(ape_loader_dd_count,
|
||||||
SHSTUB2(ape_loader_macho_dd_count, (ape_loader_macho_end - ape_loader_macho) / 64);
|
DEFINED(ape_loader_end)
|
||||||
#endif
|
? ROUNDUP(ape_loader_end - ape_loader, PAGESIZE) / 64
|
||||||
|
: 0);
|
||||||
|
|
||||||
#if SupportsXnu()
|
#if SupportsXnu()
|
||||||
SHSTUB2(ape_macho_dd_skip, RVA(ape_macho) / 8);
|
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.lds \
|
||||||
o/$(MODE)/ape/ape-no-modify-self.o
|
o/$(MODE)/ape/ape-no-modify-self.o
|
||||||
|
|
||||||
|
APE_COPY_SELF = \
|
||||||
|
o/$(MODE)/ape/ape.lds \
|
||||||
|
o/$(MODE)/ape/ape-copy-self.o
|
||||||
|
|
||||||
APELINK = \
|
APELINK = \
|
||||||
$(COMPILE) \
|
$(COMPILE) \
|
||||||
-ALINK.ape \
|
-ALINK.ape \
|
||||||
|
@ -29,6 +33,22 @@ APELINK = \
|
||||||
$(LINKARGS) \
|
$(LINKARGS) \
|
||||||
$(OUTPUT_OPTION)
|
$(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_FILES := $(wildcard ape/*.*)
|
||||||
APE_HDRS = $(filter %.h,$(APE_FILES))
|
APE_HDRS = $(filter %.h,$(APE_FILES))
|
||||||
APE_INCS = $(filter %.inc,$(APE_FILES))
|
APE_INCS = $(filter %.inc,$(APE_FILES))
|
||||||
|
@ -50,31 +70,55 @@ o/ape/idata.inc: \
|
||||||
|
|
||||||
o/$(MODE)/ape/ape-no-modify-self.o: \
|
o/$(MODE)/ape/ape-no-modify-self.o: \
|
||||||
ape/ape.S \
|
ape/ape.S \
|
||||||
o/$(MODE)/ape/ape \
|
o/$(MODE)/ape/ape.elf
|
||||||
o/$(MODE)/ape/ape.macho
|
@$(COMPILE) \
|
||||||
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -DAPE_LOADER="\"o/$(MODE)/ape/ape\"" -DAPE_LOADER_MACHO="\"o/$(MODE)/ape/ape.macho\"" $<
|
-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
|
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
|
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.o \
|
||||||
o/$(MODE)/ape/loader-elf.o \
|
o/$(MODE)/ape/loader-elf.o \
|
||||||
ape/loader.lds
|
ape/loader.lds
|
||||||
@$(ELFLINK) -s -z max-page-size=0x10
|
@$(ELFLINK) -z max-page-size=0x10
|
||||||
|
|
||||||
o/$(MODE)/ape/ape.macho: \
|
o/$(MODE)/ape/ape.macho.dbg: \
|
||||||
o/$(MODE)/ape/loader.o \
|
o/$(MODE)/ape/loader-xnu.o \
|
||||||
o/$(MODE)/ape/loader-macho.o \
|
o/$(MODE)/ape/loader-macho.o \
|
||||||
ape/loader-macho.lds
|
ape/loader-macho.lds
|
||||||
@$(ELFLINK) -s -z max-page-size=0x10
|
@$(ELFLINK) -z max-page-size=0x10
|
||||||
|
|
||||||
.PHONY: o/$(MODE)/ape
|
.PHONY: o/$(MODE)/ape
|
||||||
o/$(MODE)/ape: $(APE) \
|
o/$(MODE)/ape: $(APE) \
|
||||||
$(APE_CHECKS) \
|
$(APE_CHECKS) \
|
||||||
o/$(MODE)/ape/ape \
|
o/$(MODE)/ape/ape.elf \
|
||||||
o/$(MODE)/ape/ape.macho \
|
o/$(MODE)/ape/ape.macho \
|
||||||
|
o/$(MODE)/ape/ape-copy-self.o \
|
||||||
o/$(MODE)/ape/ape-no-modify-self.o
|
o/$(MODE)/ape/ape-no-modify-self.o
|
||||||
|
|
|
@ -9,19 +9,19 @@ fi
|
||||||
if [ -f o/depend ]; then
|
if [ -f o/depend ]; then
|
||||||
# mkdeps.com build was successfully run so assume we can build
|
# mkdeps.com build was successfully run so assume we can build
|
||||||
echo >&2
|
echo >&2
|
||||||
echo running: make -j8 o//ape/ape >&2
|
echo running: make -j8 o//ape/ape.elf >&2
|
||||||
make -j8 o//ape/ape || exit
|
make -j8 o//ape/ape.elf || exit
|
||||||
echo done >&2
|
echo done >&2
|
||||||
else
|
else
|
||||||
# no evidence we can build, use prebuilt one
|
# no evidence we can build, use prebuilt one
|
||||||
mkdir -p o//ape || exit
|
mkdir -p o//ape || exit
|
||||||
cp -af build/bootstrap/ape o//ape/ape
|
cp -af build/bootstrap/ape.elf o//ape/ape.elf
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo >&2
|
echo >&2
|
||||||
echo installing o//ape/ape to /usr/bin/ape >&2
|
echo installing o//ape/ape.elf to /usr/bin/ape >&2
|
||||||
echo sudo mv -f o//ape/ape /usr/bin/ape >&2
|
echo sudo mv -f o//ape/ape.elf /usr/bin/ape >&2
|
||||||
sudo mv -f o//ape/ape /usr/bin/ape || exit
|
sudo mv -f o//ape/ape.elf /usr/bin/ape || exit
|
||||||
echo done >&2
|
echo done >&2
|
||||||
|
|
||||||
if [ -e /proc/sys/fs/binfmt_misc/APE ]; then
|
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. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/elf/def.h"
|
#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"
|
#include "libc/macros.internal.h"
|
||||||
|
|
||||||
// APE Loader Executable Structure
|
// APE Loader Executable Structure
|
||||||
|
@ -44,48 +47,6 @@ ehdr: .ascii "\177ELF"
|
||||||
.word 0 # e_shstrndx
|
.word 0 # e_shstrndx
|
||||||
.endobj ehdr,globl
|
.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
|
.align 8
|
||||||
phdrs: .long PT_LOAD # p_type
|
phdrs: .long PT_LOAD # p_type
|
||||||
.long PF_R|PF_X # p_flags
|
.long PF_R|PF_X # p_flags
|
||||||
|
@ -94,7 +55,7 @@ phdrs: .long PT_LOAD # p_type
|
||||||
.quad ehdr # p_paddr
|
.quad ehdr # p_paddr
|
||||||
.quad filesz # p_filesz
|
.quad filesz # p_filesz
|
||||||
.quad filesz # p_memsz
|
.quad filesz # p_memsz
|
||||||
.quad PAGESIZE # p_align
|
.quad 64 # p_align
|
||||||
|
|
||||||
.long PT_LOAD # p_type
|
.long PT_LOAD # p_type
|
||||||
.long PF_R|PF_W # p_flags
|
.long PF_R|PF_W # p_flags
|
||||||
|
@ -103,7 +64,7 @@ phdrs: .long PT_LOAD # p_type
|
||||||
.quad bss # p_paddr
|
.quad bss # p_paddr
|
||||||
.quad 0 # p_filesz
|
.quad 0 # p_filesz
|
||||||
.quad bsssize # p_memsz
|
.quad bsssize # p_memsz
|
||||||
.quad PAGESIZE # p_align
|
.quad 64 # p_align
|
||||||
|
|
||||||
.long PT_GNU_STACK # p_type
|
.long PT_GNU_STACK # p_type
|
||||||
.long PF_R|PF_W # p_flags
|
.long PF_R|PF_W # p_flags
|
||||||
|
@ -138,3 +99,140 @@ note: .long 2f-1f
|
||||||
3: .long 901000000
|
3: .long 901000000
|
||||||
4: .endobj note
|
4: .endobj note
|
||||||
notesize = . - 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
|
.long 30f-20b
|
||||||
.ascin "__TEXT",16
|
.ascin "__TEXT",16
|
||||||
.quad macho # vaddr
|
.quad macho # vaddr
|
||||||
.quad filesz # memsz
|
.quad 4096 # memsz
|
||||||
.quad 0 # file offset
|
.quad 0 # file offset
|
||||||
.quad filesz # file size
|
.quad filesz # file size
|
||||||
.long PROT_EXEC|PROT_READ|PROT_WRITE # maxprot
|
.long PROT_EXEC|PROT_READ|PROT_WRITE # maxprot
|
||||||
|
@ -53,7 +53,7 @@ macho: .long 0xFEEDFACE+1
|
||||||
.quad _start # vaddr
|
.quad _start # vaddr
|
||||||
.quad textsz # memsz
|
.quad textsz # memsz
|
||||||
.long textoff # offset
|
.long textoff # offset
|
||||||
.long 3 # align 2**3 = 8
|
.long 6 # align 2**3 = 64
|
||||||
.long 0 # reloc table offset
|
.long 0 # reloc table offset
|
||||||
.long 0 # relocation count
|
.long 0 # relocation count
|
||||||
.long MAC_S_ATTR_SOME_INSTRUCTIONS # section type & attributes
|
.long MAC_S_ATTR_SOME_INSTRUCTIONS # section type & attributes
|
||||||
|
@ -112,7 +112,7 @@ macho: .long 0xFEEDFACE+1
|
||||||
60:
|
60:
|
||||||
.endobj macho,globl
|
.endobj macho,globl
|
||||||
|
|
||||||
.align 8
|
.align 64
|
||||||
_start: mov %rsp,%rsi
|
_start: mov %rsp,%rsi
|
||||||
jmp ApeLoader
|
jmp ApeLoader
|
||||||
.endfn _start,globl
|
.endfn _start,globl
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
ENTRY(_start)
|
ENTRY(_start)
|
||||||
OUTPUT_FORMAT(binary)
|
|
||||||
|
|
||||||
SECTIONS {
|
SECTIONS {
|
||||||
. = 0x200000;
|
. = 0x200000;
|
||||||
|
|
194
ape/loader.c
194
ape/loader.c
|
@ -22,7 +22,7 @@
|
||||||
#define TROUBLESHOOT_OS LINUX
|
#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
|
* We recommend using the normal APE design, where binaries assimilate
|
||||||
* themselves once by self-modifying the first 64 bytes. If that can't
|
* themselves once by self-modifying the first 64 bytes. If that can't
|
||||||
|
@ -30,7 +30,7 @@
|
||||||
*
|
*
|
||||||
* m=tiny
|
* m=tiny
|
||||||
* make -j8 MODE=$m o/$m/ape o/$m/examples/printargs.com
|
* 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
|
* This is an embeddable Actually Portable Executable interpreter. The
|
||||||
* `ape/ape.S` bootloader embeds this binary inside each binary that's
|
* `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:
|
* so your APE loader may be installed to your system as follows:
|
||||||
*
|
*
|
||||||
* m=tiny
|
* m=tiny
|
||||||
* make -j8 MODE=$m o/$m/ape/ape
|
* make -j8 MODE=$m o/$m/ape/ape.elf
|
||||||
* sudo cp o/$m/ape/ape /usr/bin/ape
|
* 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:
|
* 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
|
* 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:
|
* 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
|
* f=/proc/sys/fs/binfmt_misc/register
|
||||||
* sudo sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >$f"
|
* sudo sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >$f"
|
||||||
*
|
*
|
||||||
|
@ -78,13 +82,23 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define LINUX 1
|
#define LINUX 1
|
||||||
#define METAL 2
|
|
||||||
#define WINDOWS 4
|
|
||||||
#define XNU 8
|
#define XNU 8
|
||||||
#define OPENBSD 16
|
#define OPENBSD 16
|
||||||
#define FREEBSD 32
|
#define FREEBSD 32
|
||||||
#define NETBSD 64
|
#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 O_RDONLY 0
|
||||||
#define PROT_READ 1
|
#define PROT_READ 1
|
||||||
#define PROT_WRITE 2
|
#define PROT_WRITE 2
|
||||||
|
@ -92,7 +106,7 @@
|
||||||
#define MAP_SHARED 1
|
#define MAP_SHARED 1
|
||||||
#define MAP_PRIVATE 2
|
#define MAP_PRIVATE 2
|
||||||
#define MAP_FIXED 16
|
#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_LINUX 31
|
||||||
#define AT_EXECFN_NETBSD 2014
|
#define AT_EXECFN_NETBSD 2014
|
||||||
#define ELFCLASS64 2
|
#define ELFCLASS64 2
|
||||||
|
@ -235,15 +249,15 @@ static char *Itoa(char p[21], long x) {
|
||||||
|
|
||||||
#if TROUBLESHOOT
|
#if TROUBLESHOOT
|
||||||
const char *DescribeOs(int os) {
|
const char *DescribeOs(int os) {
|
||||||
if (os == LINUX) {
|
if (IsLinux()) {
|
||||||
return "GNU/SYSTEMD";
|
return "GNU/SYSTEMD";
|
||||||
} else if (os == XNU) {
|
} else if (IsXnu()) {
|
||||||
return "XNU";
|
return "XNU";
|
||||||
} else if (os == FREEBSD) {
|
} else if (IsFreebsd()) {
|
||||||
return "FREEBSD";
|
return "FREEBSD";
|
||||||
} else if (os == OPENBSD) {
|
} else if (IsOpenbsd()) {
|
||||||
return "OPENBSD";
|
return "OPENBSD";
|
||||||
} else if (os == NETBSD) {
|
} else if (IsNetbsd()) {
|
||||||
return "NETBSD";
|
return "NETBSD";
|
||||||
} else {
|
} else {
|
||||||
return "WUT";
|
return "WUT";
|
||||||
|
@ -251,40 +265,42 @@ const char *DescribeOs(int os) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
__attribute__((__noreturn__)) static void Exit(long rc, int os) {
|
__attribute__((__noreturn__)) static void Exit(int rc, int os) {
|
||||||
asm volatile("call\t*%2"
|
asm volatile("call\t*%2"
|
||||||
: /* no outputs */
|
: /* no outputs */
|
||||||
: "a"((os == LINUX ? 60 : 1) | (os == XNU ? 0x2000000 : 0)),
|
: "a"((IsLinux() ? 60 : 1) | (IsXnu() ? 0x2000000 : 0)), "D"(rc),
|
||||||
"D"(rc), "m"(syscall)
|
"rm"(syscall)
|
||||||
: "memory");
|
: "memory");
|
||||||
__builtin_unreachable();
|
__builtin_unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Close(long fd, int os) {
|
static void Close(int fd, int os) {
|
||||||
long ax, di;
|
int ax, di;
|
||||||
asm volatile("call\t*%4"
|
asm volatile("call\t*%4"
|
||||||
: "=a"(ax), "=D"(di)
|
: "=a"(ax), "=D"(di)
|
||||||
: "0"((os == LINUX ? 3 : 6) | (os == XNU ? 0x2000000 : 0)),
|
: "0"((IsLinux() ? 3 : 6) | (IsXnu() ? 0x2000000 : 0)), "1"(fd),
|
||||||
"1"(fd), "m"(syscall)
|
"rm"(syscall)
|
||||||
: "rcx", "rdx", "rsi", "r8", "r9", "r10", "r11", "memory", "cc");
|
: "rcx", "rdx", "rsi", "r8", "r9", "r10", "r11", "memory", "cc");
|
||||||
}
|
}
|
||||||
|
|
||||||
static long Read(long fd, void *data, unsigned long size, int os) {
|
static int Read(int fd, void *data, int size, int os) {
|
||||||
long ax, di, si, dx;
|
long si;
|
||||||
|
int ax, di, dx;
|
||||||
asm volatile("call\t*%8"
|
asm volatile("call\t*%8"
|
||||||
: "=a"(ax), "=D"(di), "=S"(si), "=d"(dx)
|
: "=a"(ax), "=D"(di), "=S"(si), "=d"(dx)
|
||||||
: "0"((os == LINUX ? 0 : 3) | (os == XNU ? 0x2000000 : 0)),
|
: "0"((IsLinux() ? 0 : 3) | (IsXnu() ? 0x2000000 : 0)), "1"(fd),
|
||||||
"1"(fd), "2"(data), "3"(size), "m"(syscall)
|
"2"(data), "3"(size), "rm"(syscall)
|
||||||
: "rcx", "r8", "r9", "r10", "r11", "memory");
|
: "rcx", "r8", "r9", "r10", "r11", "memory");
|
||||||
return ax;
|
return ax;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Write(long fd, const void *data, unsigned long size, int os) {
|
static void Write(int fd, const void *data, int size, int os) {
|
||||||
long ax, di, si, dx;
|
long si;
|
||||||
|
int ax, di, dx;
|
||||||
asm volatile("call\t*%8"
|
asm volatile("call\t*%8"
|
||||||
: "=a"(ax), "=D"(di), "=S"(si), "=d"(dx)
|
: "=a"(ax), "=D"(di), "=S"(si), "=d"(dx)
|
||||||
: "0"((os == LINUX ? 1 : 4) | (os == XNU ? 0x2000000 : 0)),
|
: "0"((IsLinux() ? 1 : 4) | (IsXnu() ? 0x2000000 : 0)), "1"(fd),
|
||||||
"1"(fd), "2"(data), "3"(size), "m"(syscall)
|
"2"(data), "3"(size), "rm"(syscall)
|
||||||
: "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
|
: "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;
|
long ax, di, si, dx;
|
||||||
asm volatile("call\t*%8"
|
asm volatile("call\t*%8"
|
||||||
: "=a"(ax), "=D"(di), "=S"(si), "=d"(dx)
|
: "=a"(ax), "=D"(di), "=S"(si), "=d"(dx)
|
||||||
: "0"((59) | (os == XNU ? 0x2000000 : 0)), "1"(prog), "2"(argv),
|
: "0"(59 | (IsXnu() ? 0x2000000 : 0)), "1"(prog), "2"(argv),
|
||||||
"3"(envp), "m"(syscall)
|
"3"(envp), "rm"(syscall)
|
||||||
: "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
|
: "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
|
||||||
}
|
}
|
||||||
|
|
||||||
static long Access(const char *path, int mode, int os) {
|
static int Access(const char *path, int mode, int os) {
|
||||||
long ax, dx, di, si;
|
int ax, si;
|
||||||
|
long dx, di;
|
||||||
asm volatile("call\t*%7"
|
asm volatile("call\t*%7"
|
||||||
: "=a"(ax), "=D"(di), "=S"(si), "=d"(dx)
|
: "=a"(ax), "=D"(di), "=S"(si), "=d"(dx)
|
||||||
: "0"((os == LINUX ? 21 : 33) | (os == XNU ? 0x2000000 : 0)),
|
: "0"((IsLinux() ? 21 : 33) | (IsXnu() ? 0x2000000 : 0)),
|
||||||
"1"(path), "2"(mode), "m"(syscall)
|
"1"(path), "2"(mode), "rm"(syscall)
|
||||||
: "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
|
: "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
|
||||||
return ax;
|
return ax;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Msyscall(long p, long n, int os) {
|
static int Msyscall(long p, long n, int os) {
|
||||||
long ax, di, si;
|
int ax;
|
||||||
if (os == OPENBSD) {
|
long di, si;
|
||||||
|
if (!IsOpenbsd()) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
asm volatile("call\t*%6"
|
asm volatile("call\t*%6"
|
||||||
: "=a"(ax), "=D"(di), "=S"(si)
|
: "=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");
|
: "rcx", "rdx", "r8", "r9", "r10", "r11", "memory", "cc");
|
||||||
|
return ax;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static long Open(const char *path, long flags, long mode, int os) {
|
static int Open(const char *path, int flags, int mode, int os) {
|
||||||
long ax, di, si, dx;
|
long di;
|
||||||
|
int ax, dx, si;
|
||||||
asm volatile("call\t*%8"
|
asm volatile("call\t*%8"
|
||||||
: "=a"(ax), "=D"(di), "=S"(si), "=d"(dx)
|
: "=a"(ax), "=D"(di), "=S"(si), "=d"(dx)
|
||||||
: "0"((os == LINUX ? 2 : 5) | (os == XNU ? 0x2000000 : 0)),
|
: "0"((IsLinux() ? 2 : 5) | (IsXnu() ? 0x2000000 : 0)),
|
||||||
"1"(path), "2"(flags), "3"(mode), "m"(syscall)
|
"1"(path), "2"(flags), "3"(mode), "rm"(syscall)
|
||||||
: "rcx", "r8", "r9", "r10", "r11", "memory");
|
: "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
|
||||||
return ax;
|
return ax;
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((__noinline__)) long Mmap(long addr, long size, long prot,
|
__attribute__((__noinline__)) static long Mmap(long addr, long size, int prot,
|
||||||
long flags, long fd, long off, int os) {
|
int flags, int fd, long off,
|
||||||
long ax;
|
int os) {
|
||||||
register long flags_ asm("r10") = flags;
|
long ax, di, si, dx;
|
||||||
register long fd_ asm("r8") = fd;
|
register int flags_ asm("r10") = flags;
|
||||||
|
register int fd_ asm("r8") = fd;
|
||||||
register long off_ asm("r9") = off;
|
register long off_ asm("r9") = off;
|
||||||
asm volatile("push\t%%r9\n\t"
|
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"
|
"pop\t%%r9"
|
||||||
: "=a"(ax)
|
: "=a"(ax), "=D"(di), "=S"(si), "=d"(dx), "+r"(flags_),
|
||||||
: "0"((os == LINUX ? 9
|
"+r"(fd_), "+r"(off_)
|
||||||
: os == FREEBSD ? 477
|
: "rm"(syscall),
|
||||||
: 197) |
|
"0"((IsLinux() ? 9
|
||||||
(os == XNU ? 0x2000000 : 0)),
|
: IsFreebsd() ? 477
|
||||||
"D"(addr), "S"(size), "d"(prot), "r"(flags_), "r"(fd_),
|
: 197) |
|
||||||
"r"(off_), "m"(syscall)
|
(IsXnu() ? 0x2000000 : 0)),
|
||||||
: "rcx", "r11", "memory");
|
"1"(addr), "2"(size), "3"(prot)
|
||||||
|
: "rcx", "r11", "memory", "cc");
|
||||||
return ax;
|
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");
|
Pexit(os, exe, 0, "ELF needs PT_LOAD phdr w/ PF_X");
|
||||||
}
|
}
|
||||||
Close(fd, os);
|
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
|
#if TROUBLESHOOT
|
||||||
Emit(TROUBLESHOOT_OS, "preparing to jump\n");
|
Emit(TROUBLESHOOT_OS, "preparing to jump\n");
|
||||||
#endif
|
#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"
|
asm volatile("xor\t%%eax,%%eax\n\t"
|
||||||
"xor\t%%ebx,%%ebx\n\t"
|
|
||||||
"xor\t%%r9d,%%r9d\n\t"
|
"xor\t%%r9d,%%r9d\n\t"
|
||||||
"xor\t%%r10d,%%r10d\n\t"
|
"xor\t%%r10d,%%r10d\n\t"
|
||||||
"xor\t%%r11d,%%r11d\n\t"
|
"xor\t%%r11d,%%r11d\n\t"
|
||||||
"xor\t%%r12d,%%r12d\n\t"
|
"xor\t%%ebx,%%ebx\n\t" // netbsd dosen't clear this
|
||||||
"xor\t%%r13d,%%r13d\n\t"
|
"xor\t%%r12d,%%r12d\n\t" // netbsd dosen't clear this
|
||||||
"xor\t%%r14d,%%r14d\n\t"
|
"xor\t%%r13d,%%r13d\n\t" // netbsd dosen't clear this
|
||||||
"xor\t%%r15d,%%r15d\n\t"
|
"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"
|
"mov\t%%rdx,%%rsp\n\t"
|
||||||
"xor\t%%edx,%%edx\n\t"
|
"xor\t%%edx,%%edx\n\t"
|
||||||
"push\t%%rsi\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"
|
"xor\t%%ebp,%%ebp\n\t"
|
||||||
"ret"
|
"ret"
|
||||||
: /* no outputs */
|
: /* 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)
|
"r"(r8)
|
||||||
: "memory");
|
: "memory");
|
||||||
__builtin_unreachable();
|
__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,
|
__attribute__((__noreturn__)) void ApeLoader(long di, long *sp, char dl,
|
||||||
struct ApeLoader *handoff) {
|
struct ApeLoader *handoff) {
|
||||||
long rc, *auxv;
|
int rc;
|
||||||
|
long *auxv;
|
||||||
struct ElfEhdr *ehdr;
|
struct ElfEhdr *ehdr;
|
||||||
int c, i, fd, os, argc;
|
int c, i, fd, os, argc;
|
||||||
char *p, *exe, *prog, **argv, **envp, *page;
|
char *p, *exe, *prog, **argv, **envp, *page;
|
||||||
|
@ -553,13 +593,15 @@ __attribute__((__noreturn__)) void ApeLoader(long di, long *sp, char dl,
|
||||||
} u;
|
} u;
|
||||||
|
|
||||||
// detect freebsd
|
// detect freebsd
|
||||||
if (di) {
|
if (handoff) {
|
||||||
|
os = handoff->os;
|
||||||
|
} else if (SupportsFreebsd() && di) {
|
||||||
os = FREEBSD;
|
os = FREEBSD;
|
||||||
sp = (long *)di;
|
sp = (long *)di;
|
||||||
} else if (dl == XNU) {
|
} else if (SupportsXnu() && dl == XNU) {
|
||||||
os = XNU;
|
os = XNU;
|
||||||
} else {
|
} else {
|
||||||
os = LINUX;
|
os = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// extract arguments
|
// extract arguments
|
||||||
|
@ -586,19 +628,18 @@ __attribute__((__noreturn__)) void ApeLoader(long di, long *sp, char dl,
|
||||||
// no path searching is needed
|
// no path searching is needed
|
||||||
exe = handoff->prog;
|
exe = handoff->prog;
|
||||||
fd = handoff->fd;
|
fd = handoff->fd;
|
||||||
os = handoff->os;
|
|
||||||
exe = handoff->prog;
|
exe = handoff->prog;
|
||||||
page = handoff->page;
|
page = handoff->page;
|
||||||
ehdr = (struct ElfEhdr *)handoff->page;
|
ehdr = (struct ElfEhdr *)handoff->page;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// detect openbsd
|
// detect openbsd
|
||||||
if (!auxv[0]) {
|
if (SupportsOpenbsd() && !os && !auxv[0]) {
|
||||||
os = OPENBSD;
|
os = OPENBSD;
|
||||||
}
|
}
|
||||||
|
|
||||||
// detect netbsd
|
// detect netbsd
|
||||||
if (os == LINUX) {
|
if (SupportsNetbsd() && !os) {
|
||||||
for (; auxv[0]; auxv += 2) {
|
for (; auxv[0]; auxv += 2) {
|
||||||
if (auxv[0] == AT_EXECFN_NETBSD) {
|
if (auxv[0] == AT_EXECFN_NETBSD) {
|
||||||
os = 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
|
// we can load via shell, shebang, or binfmt_misc
|
||||||
if (argc >= 3 && !StrCmp(argv[1], "-")) {
|
if (argc >= 3 && !StrCmp(argv[1], "-")) {
|
||||||
// if the first argument is a hyphen then we give the user the
|
// 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
|
#endif
|
||||||
|
|
||||||
if (Read32(page) == Read32("\177ELF") || Read32(page) == 0xFEEDFACE + 1) {
|
if ((IsXnu() && Read32(page) == 0xFEEDFACE + 1) ||
|
||||||
|
(!IsXnu() && Read32(page) == Read32("\177ELF"))) {
|
||||||
Close(fd, os);
|
Close(fd, os);
|
||||||
Execve(exe, argv, envp, 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) {
|
for (p = page; p < page + sizeof(u.p); ++p) {
|
||||||
if (Read64(p) != Read64("printf '")) continue;
|
if (Read64(p) != Read64("printf '")) continue;
|
||||||
for (i = 0, p += 8; p + 3 < page + sizeof(u.p) && (c = *p++) != '\'';) {
|
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_
|
#ifndef COSMOPOLITAN_APE_LOADER_H_
|
||||||
#define COSMOPOLITAN_APE_LOADER_H_
|
#define COSMOPOLITAN_APE_LOADER_H_
|
||||||
|
|
||||||
#define APE_LOADER_BASE 0x200000
|
#define APE_LOADER_BASE 0x200000
|
||||||
#define APE_LOADER_SIZE 0x200000
|
#define APE_LOADER_SIZE 0x200000
|
||||||
#define APE_LOADER_BSS (PAGESIZE * 2)
|
#define APE_LOADER_ENTRY 0x200400
|
||||||
#define APE_LOADER_STACK 0x7f0000000000
|
#define APE_LOADER_BSS (PAGESIZE * 2)
|
||||||
#define APE_LOADER_ENTRY (APE_LOADER_BASE + 0x47)
|
#define APE_LOADER_STACK 0x7f0000000000
|
||||||
#define APE_LOADER_SYSCALL (APE_LOADER_BASE + 0x50)
|
#define APE_BLOCK_BASE 0x7e0000000000
|
||||||
#define APE_BLOCK_BASE 0x7e0000000000
|
#define APE_BLOCK_SIZE 0x000200000000
|
||||||
#define APE_BLOCK_SIZE 0x000200000000
|
|
||||||
|
|
||||||
struct ApeLoader {
|
struct ApeLoader {
|
||||||
int fd;
|
int fd;
|
||||||
|
|
|
@ -17,16 +17,16 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
ENTRY(_start)
|
ENTRY(_start)
|
||||||
OUTPUT_FORMAT(binary)
|
|
||||||
|
|
||||||
SECTIONS {
|
SECTIONS {
|
||||||
. = 0x200000;
|
. = 0x200000;
|
||||||
.text : {
|
.text : {
|
||||||
*(.text)
|
*(.text)
|
||||||
*(.rodata .rodata.*)
|
*(.rodata .rodata.*)
|
||||||
. = ALIGN(4096);
|
. = ALIGN(64);
|
||||||
}
|
}
|
||||||
filesz = . - ehdr;
|
filesz = . - ehdr;
|
||||||
|
textsz = . - _start;
|
||||||
.bss ALIGN(4096) : {
|
.bss ALIGN(4096) : {
|
||||||
bss = .;
|
bss = .;
|
||||||
*(.bss)
|
*(.bss)
|
||||||
|
@ -39,3 +39,4 @@ SECTIONS {
|
||||||
}
|
}
|
||||||
|
|
||||||
bsssize = SIZEOF(.bss);
|
bsssize = SIZEOF(.bss);
|
||||||
|
textoff = _start - ehdr;
|
||||||
|
|
Binary file not shown.
BIN
build/bootstrap/ape.elf
Executable file
BIN
build/bootstrap/ape.elf
Executable file
Binary file not shown.
BIN
build/bootstrap/apetest.com
Executable file
BIN
build/bootstrap/apetest.com
Executable file
Binary file not shown.
|
@ -27,28 +27,38 @@ EOF
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
build/sanitycheck2
|
if [ ! -f /proc/sys/fs/binfmt_misc/status ]; then
|
||||||
if [ $? -ne 123 ]; then
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
STATUS="$(build/bootstrap/apetest.com)"
|
||||||
|
if [ x"$STATUS" != xsuccess ]; then
|
||||||
cat <<'EOF' >&2
|
cat <<'EOF' >&2
|
||||||
|
|
||||||
ERROR
|
ERROR
|
||||||
|
|
||||||
Thompson Shell Backwards Compatibility Issue Detected
|
APE Execution error.
|
||||||
|
|
||||||
DETAILS
|
DETAILS
|
||||||
|
|
||||||
Your system has likely been configured to use binfmt_misc and wine.
|
Your system has probably been configured to use binfmt_misc. You need
|
||||||
You need to run the command below which will install a /usr/bin/ape
|
to run the command below to install /usr/bin/ape and register it with
|
||||||
program and then register it with binfmt_misc. See ape/loader.c for
|
binfmt_misc. See ape/loader.c for source code, and technical details.
|
||||||
source code and technical details.
|
|
||||||
|
|
||||||
WORKAROUND
|
WORKAROUND
|
||||||
|
|
||||||
ape/apeinstall.sh
|
ape/apeinstall.sh
|
||||||
|
|
||||||
|
NOTES
|
||||||
|
|
||||||
|
If it still doesn't work, possibly due to an overly aggressive WINE
|
||||||
|
or WSL registration, or possibly due to the ordering of definitions,
|
||||||
|
then one troubleshooting step is to just unregister everything using
|
||||||
|
sudo sh -c 'echo -1 >/proc/sys/fs/binfmt_misc/status' and try again.
|
||||||
|
|
||||||
SEE ALSO
|
SEE ALSO
|
||||||
|
|
||||||
https://justine.storage.googleapis.com/ape.html
|
https://justine.lol/ape.html
|
||||||
|
|
||||||
EOF
|
EOF
|
||||||
kill $1
|
kill $1
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
MZboop=123
|
|
||||||
exit $MZboop
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -34,12 +34,22 @@
|
||||||
|
|
||||||
char program_executable_name[PATH_MAX];
|
char program_executable_name[PATH_MAX];
|
||||||
|
|
||||||
|
static inline char *StrCat(char buf[PATH_MAX], const char *a, const char *b) {
|
||||||
|
char *p, *e;
|
||||||
|
p = buf;
|
||||||
|
e = buf + PATH_MAX;
|
||||||
|
while (*a && p < e) *p++ = *a++;
|
||||||
|
while (*b && p < e) *p++ = *b++;
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void GetProgramExecutableNameImpl(char *p, char *e) {
|
static inline void GetProgramExecutableNameImpl(char *p, char *e) {
|
||||||
char *q;
|
char *q;
|
||||||
ssize_t rc;
|
ssize_t rc;
|
||||||
size_t i, n;
|
size_t i, n;
|
||||||
union {
|
union {
|
||||||
int cmd[4];
|
int cmd[4];
|
||||||
|
char path[PATH_MAX];
|
||||||
char16_t path16[PATH_MAX];
|
char16_t path16[PATH_MAX];
|
||||||
} u;
|
} u;
|
||||||
|
|
||||||
|
@ -61,7 +71,11 @@ static inline void GetProgramExecutableNameImpl(char *p, char *e) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (__argc && (q = __argv[0]) && !sys_faccessat(AT_FDCWD, q, F_OK, 0)) {
|
// if argv[0] exists then turn it into an absolute path. we also try
|
||||||
|
// adding a .com suffix since the ape auto-appends it when resolving
|
||||||
|
if (__argc && (((q = __argv[0]) && !sys_faccessat(AT_FDCWD, q, F_OK, 0)) ||
|
||||||
|
((q = StrCat(u.path, __argv[0], ".com")) &&
|
||||||
|
!sys_faccessat(AT_FDCWD, q, F_OK, 0)))) {
|
||||||
if (*q != '/') {
|
if (*q != '/') {
|
||||||
if (q[0] == '.' && q[1] == '/') {
|
if (q[0] == '.' && q[1] == '/') {
|
||||||
q += 2;
|
q += 2;
|
||||||
|
@ -78,12 +92,12 @@ static inline void GetProgramExecutableNameImpl(char *p, char *e) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if argv[0] doesn't exist, then fallback to interpreter name
|
||||||
if ((rc = sys_readlinkat(AT_FDCWD, "/proc/self/exe", p, e - p - 1)) > 0 ||
|
if ((rc = sys_readlinkat(AT_FDCWD, "/proc/self/exe", p, e - p - 1)) > 0 ||
|
||||||
(rc = sys_readlinkat(AT_FDCWD, "/proc/curproc/file", p, e - p - 1)) > 0) {
|
(rc = sys_readlinkat(AT_FDCWD, "/proc/curproc/file", p, e - p - 1)) > 0) {
|
||||||
p[rc] = 0;
|
p[rc] = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsFreebsd() || IsNetbsd()) {
|
if (IsFreebsd() || IsNetbsd()) {
|
||||||
u.cmd[0] = CTL_KERN;
|
u.cmd[0] = CTL_KERN;
|
||||||
u.cmd[1] = KERN_PROC;
|
u.cmd[1] = KERN_PROC;
|
||||||
|
@ -101,7 +115,7 @@ static inline void GetProgramExecutableNameImpl(char *p, char *e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns absolute path of executable.
|
* Returns absolute path of program.
|
||||||
*/
|
*/
|
||||||
char *GetProgramExecutableName(void) {
|
char *GetProgramExecutableName(void) {
|
||||||
int e;
|
int e;
|
||||||
|
|
|
@ -58,7 +58,7 @@ int __ensurefds_unlocked(int fd) {
|
||||||
if (!(p2 = weaken(malloc)(n2 * sizeof(*p1)))) return -1;
|
if (!(p2 = weaken(malloc)(n2 * sizeof(*p1)))) return -1;
|
||||||
__cxa_atexit(FreeOldFdsArray, p1, 0);
|
__cxa_atexit(FreeOldFdsArray, p1, 0);
|
||||||
memcpy(p2, p1, n1 * sizeof(*p1));
|
memcpy(p2, p1, n1 * sizeof(*p1));
|
||||||
bzero(p2 + n1, (p2 + n2) - (p2 + n1));
|
bzero(p2 + n1, (n2 - n1) * sizeof(*p1));
|
||||||
g_fds.p = p2;
|
g_fds.p = p2;
|
||||||
g_fds.n = n2;
|
g_fds.n = n2;
|
||||||
return fd;
|
return fd;
|
||||||
|
|
|
@ -16,10 +16,15 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/bits/weaken.h"
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/calls/sig.internal.h"
|
#include "libc/calls/sig.internal.h"
|
||||||
|
#include "libc/calls/strace.internal.h"
|
||||||
|
#include "libc/errno.h"
|
||||||
#include "libc/nt/errors.h"
|
#include "libc/nt/errors.h"
|
||||||
#include "libc/nt/runtime.h"
|
#include "libc/nt/runtime.h"
|
||||||
|
#include "libc/runtime/internal.h"
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/sysv/consts/sicode.h"
|
#include "libc/sysv/consts/sicode.h"
|
||||||
#include "libc/sysv/consts/sig.h"
|
#include "libc/sysv/consts/sig.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
@ -37,12 +42,18 @@ static textwindows ssize_t sys_write_nt_impl(int fd, void *data, size_t size,
|
||||||
// return ebadf(); /* handled by consts.sh */
|
// return ebadf(); /* handled by consts.sh */
|
||||||
// case kNtErrorNotEnoughQuota:
|
// case kNtErrorNotEnoughQuota:
|
||||||
// return edquot(); /* handled by consts.sh */
|
// return edquot(); /* handled by consts.sh */
|
||||||
case kNtErrorBrokenPipe: // broken pipe
|
case kNtErrorBrokenPipe: // broken pipe
|
||||||
case kNtErrorNoData: // closing named pipe
|
case kNtErrorNoData: // closing named pipe
|
||||||
__sig_raise(SIGPIPE, SI_KERNEL); //
|
if (weaken(__sig_raise)) {
|
||||||
return epipe(); //
|
weaken(__sig_raise)(SIGPIPE, SI_KERNEL);
|
||||||
case kNtErrorAccessDenied: // write doesn't return EACCESS
|
return epipe();
|
||||||
return ebadf(); //
|
} else {
|
||||||
|
STRACE("broken pipe");
|
||||||
|
__restorewintty();
|
||||||
|
_Exit(128 + EPIPE);
|
||||||
|
}
|
||||||
|
case kNtErrorAccessDenied: // write doesn't return EACCESS
|
||||||
|
return ebadf(); //
|
||||||
default:
|
default:
|
||||||
return __winerr();
|
return __winerr();
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
.long \systemv - kDos2Errno
|
.long \systemv - kDos2Errno
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
.section .rodata
|
.section .rodata,"a",@progbits
|
||||||
.underrun
|
.underrun
|
||||||
kDos2Errno:
|
kDos2Errno:
|
||||||
// .e kNtErrorInvalidFunction,ENOSYS # in consts.sh
|
// .e kNtErrorInvalidFunction,ENOSYS # in consts.sh
|
||||||
|
|
|
@ -106,8 +106,10 @@ void ShowCrashReports(void) {
|
||||||
bzero(&ss, sizeof(ss));
|
bzero(&ss, sizeof(ss));
|
||||||
ss.ss_flags = 0;
|
ss.ss_flags = 0;
|
||||||
ss.ss_size = SIGSTKSZ;
|
ss.ss_size = SIGSTKSZ;
|
||||||
|
// FreeBSD sigaltstack() will EFAULT if we use MAP_STACK here
|
||||||
|
// OpenBSD sigaltstack() auto-applies MAP_STACK to the memory
|
||||||
if ((ss.ss_sp = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE,
|
if ((ss.ss_sp = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE,
|
||||||
MAP_STACK | MAP_ANONYMOUS, -1, 0))) {
|
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0))) {
|
||||||
if (!sigaltstack(&ss, &g_oldsigaltstack)) {
|
if (!sigaltstack(&ss, &g_oldsigaltstack)) {
|
||||||
__cxa_atexit(FreeSigAltStack, ss.ss_sp, 0);
|
__cxa_atexit(FreeSigAltStack, ss.ss_sp, 0);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -51,6 +51,9 @@ char *GetInterpreterExecutableName(char *p, size_t n) {
|
||||||
if (n < 2) {
|
if (n < 2) {
|
||||||
errno = ENAMETOOLONG;
|
errno = ENAMETOOLONG;
|
||||||
} else if (IsWindows() || IsXnu()) {
|
} else if (IsWindows() || IsXnu()) {
|
||||||
|
// TODO(jart): Does XNU guarantee argv[0] is legit?
|
||||||
|
// Otherwise we should return NULL.
|
||||||
|
// What about OpenBSD?
|
||||||
if (strlen(GetProgramExecutableName()) < n) {
|
if (strlen(GetProgramExecutableName()) < n) {
|
||||||
strcpy(p, GetProgramExecutableName());
|
strcpy(p, GetProgramExecutableName());
|
||||||
return p;
|
return p;
|
||||||
|
|
|
@ -96,7 +96,13 @@ static struct SymbolTable *GetSymbolTableFromZip(struct Zipos *zipos) {
|
||||||
* @note This code can't depend on dlmalloc()
|
* @note This code can't depend on dlmalloc()
|
||||||
*/
|
*/
|
||||||
static struct SymbolTable *GetSymbolTableFromElf(void) {
|
static struct SymbolTable *GetSymbolTableFromElf(void) {
|
||||||
return OpenSymbolTable(FindDebugBinary());
|
int e;
|
||||||
|
const char *s;
|
||||||
|
if ((s = FindDebugBinary())) {
|
||||||
|
return OpenSymbolTable(s);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -117,7 +123,7 @@ static struct SymbolTable *GetSymbolTableFromElf(void) {
|
||||||
* Function tracing is disabled throughout the duration of this call.
|
* Function tracing is disabled throughout the duration of this call.
|
||||||
* Backtraces and other core runtime functionality depend on this.
|
* Backtraces and other core runtime functionality depend on this.
|
||||||
*
|
*
|
||||||
* @return symbol table, or NULL w/ errno on first call
|
* @return symbol table, or NULL if not found
|
||||||
*/
|
*/
|
||||||
struct SymbolTable *GetSymbolTable(void) {
|
struct SymbolTable *GetSymbolTable(void) {
|
||||||
struct Zipos *z;
|
struct Zipos *z;
|
||||||
|
|
|
@ -323,7 +323,7 @@ static noasan inline void *Mmap(void *addr, size_t size, int prot, int flags,
|
||||||
|
|
||||||
clashes = OverlapsImageSpace(p, size) || OverlapsExistingMapping(p, size);
|
clashes = OverlapsImageSpace(p, size) || OverlapsExistingMapping(p, size);
|
||||||
|
|
||||||
if ((flags & MAP_FIXED_NOREPLACE) && clashes) {
|
if ((flags & MAP_FIXED_NOREPLACE) == MAP_FIXED_NOREPLACE && clashes) {
|
||||||
STRACE("noreplace overlaps existing");
|
STRACE("noreplace overlaps existing");
|
||||||
return VIP(eexist());
|
return VIP(eexist());
|
||||||
}
|
}
|
||||||
|
@ -464,14 +464,21 @@ static noasan inline void *Mmap(void *addr, size_t size, int prot, int flags,
|
||||||
* compile-time checks to ensure some char[8192] vars will not
|
* compile-time checks to ensure some char[8192] vars will not
|
||||||
* create an undetectable overflow into another thread's stack
|
* create an undetectable overflow into another thread's stack
|
||||||
* Your `flags` may optionally bitwise or any of the following:
|
* Your `flags` may optionally bitwise or any of the following:
|
||||||
* - `MAP_FIXED` in which case `addr` becomes more than a hint
|
|
||||||
* - `MAP_FIXED_NOREPLACE` to protect existing maps (Linux-only)
|
|
||||||
* - `MAP_ANONYMOUS` in which case `fd == -1` should be the case
|
* - `MAP_ANONYMOUS` in which case `fd == -1` should be the case
|
||||||
|
* - `MAP_FIXED` in which case `addr` becomes more than a hint
|
||||||
|
* - `MAP_FIXED_NOREPLACE` to protect existing mappings; this is
|
||||||
|
* always polyfilled by mmap() which tracks its own memory and
|
||||||
|
* removed before passing to the kernel, in order to support
|
||||||
|
* old versions; if you believe mappings exist which only the
|
||||||
|
* kernel knows, then this flag may be passed to sys_mmap() on
|
||||||
|
* Linux 4.17+ and FreeBSD (where it has multiple bits)
|
||||||
* - `MAP_CONCEAL` is FreeBSD/NetBSD/OpenBSD-only
|
* - `MAP_CONCEAL` is FreeBSD/NetBSD/OpenBSD-only
|
||||||
* - `MAP_NORESERVE` is Linux/XNU/NetBSD-only
|
* - `MAP_NORESERVE` is Linux/XNU/NetBSD-only
|
||||||
* - `MAP_LOCKED` is Linux-only
|
* - `MAP_POPULATE` is Linux/FreeBSD-only
|
||||||
* - `MAP_POPULATE` is Linux-only
|
|
||||||
* - `MAP_NONBLOCK` is Linux-only
|
* - `MAP_NONBLOCK` is Linux-only
|
||||||
|
* - `MAP_NOSYNC` is FreeBSD-only
|
||||||
|
* - `MAP_INHERIT` is NetBSD-only
|
||||||
|
* - `MAP_LOCKED` is Linux-only
|
||||||
* @param fd is an open()'d file descriptor, whose contents shall be
|
* @param fd is an open()'d file descriptor, whose contents shall be
|
||||||
* made available w/ automatic reading at the chosen address and
|
* made available w/ automatic reading at the chosen address and
|
||||||
* must be -1 if MAP_ANONYMOUS is specified
|
* must be -1 if MAP_ANONYMOUS is specified
|
||||||
|
|
|
@ -224,22 +224,25 @@ syscon mmap MAP_PRIVATE 2 2 2 2 2 2 # forced consensus & faked nt
|
||||||
syscon mmap MAP_STACK 6 6 6 6 6 6 # our definition
|
syscon mmap MAP_STACK 6 6 6 6 6 6 # our definition
|
||||||
syscon mmap MAP_TYPE 15 15 15 15 15 15 # mask for type of mapping
|
syscon mmap MAP_TYPE 15 15 15 15 15 15 # mask for type of mapping
|
||||||
syscon mmap MAP_FIXED 0x00000010 0x00000010 0x00000010 0x00000010 0x00000010 0x00000010 # unix consensus; openbsd appears to forbid; faked nt
|
syscon mmap MAP_FIXED 0x00000010 0x00000010 0x00000010 0x00000010 0x00000010 0x00000010 # unix consensus; openbsd appears to forbid; faked nt
|
||||||
syscon mmap MAP_FIXED_NOREPLACE 0x08000000 0x08000000 0x08000000 0x08000000 0x08000000 0x08000000 # handled and defined by cosmo runtime; 0x100000 on linux 4.7+
|
syscon mmap MAP_FIXED_NOREPLACE 0x08000000 0x00004010 0x08000000 0x08000000 0x08000000 0x08000000 # handled and defined by cosmo runtime; 0x100000 on linux 4.7+; MAP_FIXED|MAP_EXCL on FreeBSD
|
||||||
syscon mmap MAP_ANONYMOUS 0x00000020 0x00001000 0x00001000 0x00001000 0x00001000 0x00000020 # bsd consensus; faked nt
|
syscon mmap MAP_ANONYMOUS 0x00000020 0x00001000 0x00001000 0x00001000 0x00001000 0x00000020 # bsd consensus; faked nt
|
||||||
syscon mmap MAP_GROWSDOWN 0x00000100 0 0 0 0 0 # use MAP_STACK; abstracted by MAP_STACK; may be passed to __sys_mmap() for low-level Linux fiddling
|
syscon mmap MAP_GROWSDOWN 0x00000100 0 0 0 0 0 # use MAP_STACK; abstracted by MAP_STACK; may be passed to __sys_mmap() for low-level Linux fiddling
|
||||||
syscon mmap MAP_CONCEAL 0 0 0x00020000 0x00008000 0x00008000 0 # omit from core dumps; MAP_NOCORE on FreeBSD
|
|
||||||
syscon mmap MAP_LOCKED 0x00002000 0 0 0 0 0
|
syscon mmap MAP_LOCKED 0x00002000 0 0 0 0 0
|
||||||
syscon mmap MAP_NORESERVE 0x00004000 0x00000040 0 0 0x00000040 0 # Linux calls it "reserve"; NT calls it "commit"? which is default?
|
syscon mmap MAP_NORESERVE 0x00004000 0x00000040 0 0 0x00000040 0 # Linux calls it "reserve"; NT calls it "commit"? which is default?
|
||||||
syscon mmap MAP_POPULATE 0x00008000 0 0 0 0 0 # can avoid madvise(MADV_WILLNEED) on private file mapping
|
syscon mmap MAP_POPULATE 0x00008000 0 0x00040000 0 0 0 # MAP_PREFAULT_READ on FreeBSD; can avoid madvise(MADV_WILLNEED) on private file mapping
|
||||||
syscon mmap MAP_NONBLOCK 0x00010000 0 0 0 0 0
|
syscon mmap MAP_NONBLOCK 0x00010000 0 0 0 0 0
|
||||||
syscon mmap MAP_HUGETLB 0x00040000 0 0 0 0 0x80000000 # kNtSecLargePages
|
syscon mmap MAP_HUGETLB 0x00040000 0 0 0 0 0x80000000 # kNtSecLargePages
|
||||||
|
syscon mmap MAP_INHERIT -1 -1 -1 -1 0x00000080 -1 # make it inherit across execve()
|
||||||
|
syscon mmap MAP_HASSEMAPHORE 0 0x00000200 0x00000200 0 0x00000200 0 # does it matter on x86?
|
||||||
|
syscon mmap MAP_NOSYNC 0 0 0x00000800 0 0 0 # flush to physical media only when necessary rather than gratuitously; be sure to use write() rather than ftruncate() with this!
|
||||||
|
syscon mmap MAP_CONCEAL 0 0 0x00020000 0x00008000 0x00008000 0 # omit from core dumps; MAP_NOCORE on FreeBSD
|
||||||
syscon mmap MAP_HUGE_MASK 63 0 0 0 0 0
|
syscon mmap MAP_HUGE_MASK 63 0 0 0 0 0
|
||||||
syscon mmap MAP_HUGE_SHIFT 26 0 0 0 0 0
|
syscon mmap MAP_HUGE_SHIFT 26 0 0 0 0 0
|
||||||
syscon compat MAP_NOCORE 0 0 0x0020000 0x8000 0x8000 0 # use MAP_CONCEAL
|
syscon compat MAP_NOCORE 0 0 0x00020000 0x00008000 0x00008000 0 # use MAP_CONCEAL
|
||||||
syscon compat MAP_ANON 0x20 0x1000 0x0001000 0x1000 0x1000 0x20 # bsd consensus; faked nt
|
syscon compat MAP_ANON 0x00000020 0x00001000 0x00001000 0x00001000 0x00001000 0x00000020 # bsd consensus; faked nt
|
||||||
syscon compat MAP_EXECUTABLE 0x1000 0 0 0 0 0 # ignored
|
syscon compat MAP_EXECUTABLE 0x00001000 0 0 0 0 0 # ignored
|
||||||
syscon compat MAP_DENYWRITE 0x0800 0 0 0 0 0
|
syscon compat MAP_DENYWRITE 0x00000800 0 0 0 0 0
|
||||||
syscon compat MAP_32BIT 0x40 0 0x080000 0 0 0 # iffy
|
syscon compat MAP_32BIT 0x00000040 0 0x00080000 0 0 0 # iffy
|
||||||
|
|
||||||
# madvise() flags
|
# madvise() flags
|
||||||
#
|
#
|
||||||
|
@ -337,36 +340,6 @@ syscon waitid WEXITED 4 4 0x10 0 32 0
|
||||||
syscon waitid WSTOPPED 2 8 2 0 2 0
|
syscon waitid WSTOPPED 2 8 2 0 2 0
|
||||||
syscon waitid WNOWAIT 0x01000000 0x20 8 0 0x10000 0
|
syscon waitid WNOWAIT 0x01000000 0x20 8 0 0x10000 0
|
||||||
|
|
||||||
# stat::st_mode constants
|
|
||||||
#
|
|
||||||
# group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary
|
|
||||||
syscon stat S_IFREG 0100000 0100000 0100000 0100000 0100000 0100000 # regular file (unix consensus; faked nt)
|
|
||||||
syscon stat S_IFBLK 0060000 0060000 0060000 0060000 0060000 0060000 # block device (unix consensus; faked nt)
|
|
||||||
syscon stat S_IFCHR 0020000 0020000 0020000 0020000 0020000 0020000 # character device (unix consensus; faked nt)
|
|
||||||
syscon stat S_IFDIR 0040000 0040000 0040000 0040000 0040000 0040000 # directory (unix consensus; faked nt)
|
|
||||||
syscon stat S_IFIFO 0010000 0010000 0010000 0010000 0010000 0010000 # pipe (unix consensus; faked nt)
|
|
||||||
syscon stat S_IFLNK 0120000 0120000 0120000 0120000 0120000 0120000 # symbolic link (unix consensus; faked nt)
|
|
||||||
syscon stat S_IFSOCK 0140000 0140000 0140000 0140000 0140000 0140000 # socket (unix consensus; faked nt)
|
|
||||||
syscon stat S_IFMT 0170000 0170000 0170000 0170000 0170000 0170000 # FILE TYPE MASK (unix consensus; faked nt)
|
|
||||||
syscon stat S_ISVTX 0001000 0001000 0001000 0001000 0001000 0001000 # THE STICKY BIT (unix consensus; faked nt)
|
|
||||||
syscon stat S_ISGID 0002000 0002000 0002000 0002000 0002000 0002000 # the setgid bit (unix consensus; faked nt)
|
|
||||||
syscon stat S_ISUID 0004000 0004000 0004000 0004000 0004000 0004000 # the setuid bit (unix consensus; faked nt)
|
|
||||||
syscon stat S_IEXEC 0000100 0000100 0000100 0000100 0000100 0000100 # just use octal (unix consensus; faked nt)
|
|
||||||
syscon stat S_IWRITE 0000200 0000200 0000200 0000200 0000200 0000200 # just use octal (unix consensus; faked nt)
|
|
||||||
syscon stat S_IREAD 0000400 0000400 0000400 0000400 0000400 0000400 # just use octal (unix consensus; faked nt)
|
|
||||||
syscon stat S_IXUSR 0000100 0000100 0000100 0000100 0000100 0000100 # just use octal (unix consensus; faked nt)
|
|
||||||
syscon stat S_IWUSR 0000200 0000200 0000200 0000200 0000200 0000200 # just use octal (unix consensus; faked nt)
|
|
||||||
syscon stat S_IRUSR 0000400 0000400 0000400 0000400 0000400 0000400 # just use octal (unix consensus; faked nt)
|
|
||||||
syscon stat S_IRWXU 0000700 0000700 0000700 0000700 0000700 0000700 # just use octal (unix consensus; faked nt)
|
|
||||||
syscon stat S_IXGRP 0000010 0000010 0000010 0000010 0000010 0000010 # just use octal (unix consensus; faked nt)
|
|
||||||
syscon stat S_IWGRP 0000020 0000020 0000020 0000020 0000020 0000020 # just use octal (unix consensus; faked nt)
|
|
||||||
syscon stat S_IRGRP 0000040 0000040 0000040 0000040 0000040 0000040 # just use octal (unix consensus; faked nt)
|
|
||||||
syscon stat S_IRWXG 0000070 0000070 0000070 0000070 0000070 0000070 # just use octal (unix consensus; faked nt)
|
|
||||||
syscon stat S_IXOTH 0000001 0000001 0000001 0000001 0000001 0000001 # just use octal (unix consensus; faked nt)
|
|
||||||
syscon stat S_IWOTH 0000002 0000002 0000002 0000002 0000002 0000002 # just use octal (unix consensus; faked nt)
|
|
||||||
syscon stat S_IROTH 0000004 0000004 0000004 0000004 0000004 0000004 # just use octal (unix consensus; faked nt)
|
|
||||||
syscon stat S_IRWXO 0000007 0000007 0000007 0000007 0000007 0000007 # just use octal (unix consensus; faked nt)
|
|
||||||
|
|
||||||
# fcntl()
|
# fcntl()
|
||||||
#
|
#
|
||||||
# group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary
|
# group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary
|
||||||
|
@ -605,7 +578,8 @@ syscon sicode SYS_USER_DISPATCH 2 -1 -1 -1 -1 -1 # SIGSYS; syscall
|
||||||
# sigaltstack() values
|
# sigaltstack() values
|
||||||
#
|
#
|
||||||
# group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary
|
# group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary
|
||||||
syscon ss SIGSTKSZ 0x2000 0x020000 0x8800 0x7000 0x7000 0x2000
|
syscon ss SIGSTKSZ 8192 131072 34816 28672 28672 8192 # overlayed with STACKSIZE; you need to #undef SIGSTKSZ to access this symbol
|
||||||
|
syscon ss MINSIGSTKSZ 2048 32768 2048 12288 8192 2048 # overlayed with 32768; you need to #undef MINSIGSTKSZ to access this symbol
|
||||||
syscon ss SS_ONSTACK 1 1 1 1 1 1 # unix consensus
|
syscon ss SS_ONSTACK 1 1 1 1 1 1 # unix consensus
|
||||||
syscon ss SS_DISABLE 2 4 4 4 4 2 # bsd consensus
|
syscon ss SS_DISABLE 2 4 4 4 4 2 # bsd consensus
|
||||||
|
|
||||||
|
@ -3131,7 +3105,6 @@ syscon misc CSTATUS 0 20 20 255 255 0
|
||||||
syscon misc DEAD_PROCESS 8 8 7 0 0 0
|
syscon misc DEAD_PROCESS 8 8 7 0 0 0
|
||||||
syscon misc FNM_NOSYS -1 -1 -1 2 2 0
|
syscon misc FNM_NOSYS -1 -1 -1 2 2 0
|
||||||
syscon misc INIT_PROCESS 5 5 5 0 0 0
|
syscon misc INIT_PROCESS 5 5 5 0 0 0
|
||||||
syscon misc MINSIGSTKSZ 0x0800 0x8000 0x0800 0x3000 0x2000 0
|
|
||||||
syscon misc MQ_PRIO_MAX 0x8000 0 0x40 0 0 0
|
syscon misc MQ_PRIO_MAX 0x8000 0 0x40 0 0 0
|
||||||
syscon misc MTERASE 13 0 12 9 9 0
|
syscon misc MTERASE 13 0 12 9 9 0
|
||||||
syscon misc MTLOAD 30 0 19 0 0 0
|
syscon misc MTLOAD 30 0 19 0 0 0
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
#include "libc/sysv/consts/syscon.internal.h"
|
||||||
.syscon compat,MAP_32BIT,0x40,0,0x080000,0,0,0
|
.syscon compat,MAP_32BIT,0x00000040,0,0x00080000,0,0,0
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
#include "libc/sysv/consts/syscon.internal.h"
|
||||||
.syscon compat,MAP_ANON,0x20,0x1000,0x0001000,0x1000,0x1000,0x20
|
.syscon compat,MAP_ANON,0x00000020,0x00001000,0x00001000,0x00001000,0x00001000,0x00000020
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
#include "libc/sysv/consts/syscon.internal.h"
|
||||||
.syscon compat,MAP_DENYWRITE,0x0800,0,0,0,0,0
|
.syscon compat,MAP_DENYWRITE,0x00000800,0,0,0,0,0
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
#include "libc/sysv/consts/syscon.internal.h"
|
||||||
.syscon compat,MAP_EXECUTABLE,0x1000,0,0,0,0,0
|
.syscon compat,MAP_EXECUTABLE,0x00001000,0,0,0,0,0
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
#include "libc/sysv/consts/syscon.internal.h"
|
||||||
.syscon compat,MAP_FILE,0,0,0,0,0,0
|
.syscon mmap,MAP_FILE,0,0,0,0,0,0
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
#include "libc/sysv/consts/syscon.internal.h"
|
||||||
.syscon mmap,MAP_FIXED_NOREPLACE,0x08000000,0x08000000,0x08000000,0x08000000,0x08000000,0x08000000
|
.syscon mmap,MAP_FIXED_NOREPLACE,0x08000000,0x00004010,0x08000000,0x08000000,0x08000000,0x08000000
|
||||||
|
|
2
libc/sysv/consts/MAP_HASSEMAPHORE.S
Normal file
2
libc/sysv/consts/MAP_HASSEMAPHORE.S
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
#include "libc/sysv/consts/syscon.internal.h"
|
||||||
|
.syscon mmap,MAP_HASSEMAPHORE,0,0x00000200,0x00000200,0,0x00000200,0
|
2
libc/sysv/consts/MAP_INHERIT.S
Normal file
2
libc/sysv/consts/MAP_INHERIT.S
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
#include "libc/sysv/consts/syscon.internal.h"
|
||||||
|
.syscon mmap,MAP_INHERIT,-1,-1,-1,-1,0x00000080,-1
|
|
@ -1,2 +1,2 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
#include "libc/sysv/consts/syscon.internal.h"
|
||||||
.syscon compat,MAP_NOCORE,0,0,0x0020000,0x8000,0x8000,0
|
.syscon compat,MAP_NOCORE,0,0,0x00020000,0x00008000,0x00008000,0
|
||||||
|
|
2
libc/sysv/consts/MAP_NOSYNC.S
Normal file
2
libc/sysv/consts/MAP_NOSYNC.S
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
#include "libc/sysv/consts/syscon.internal.h"
|
||||||
|
.syscon mmap,MAP_NOSYNC,0,0,0x00000800,0,0,0
|
|
@ -1,2 +1,2 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
#include "libc/sysv/consts/syscon.internal.h"
|
||||||
.syscon mmap,MAP_POPULATE,0x00008000,0,0,0,0,0
|
.syscon mmap,MAP_POPULATE,0x00008000,0,0x00040000,0,0,0
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
#include "libc/sysv/consts/syscon.internal.h"
|
||||||
.syscon misc,MINSIGSTKSZ,0x0800,0x8000,0x0800,0x3000,0x2000,0
|
.syscon ss,MINSIGSTKSZ,2048,32768,2048,12288,8192,2048
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
#include "libc/sysv/consts/syscon.internal.h"
|
||||||
.syscon ss,SIGSTKSZ,0x2000,0x020000,0x8800,0x7000,0x7000,0x2000
|
.syscon ss,SIGSTKSZ,8192,131072,34816,28672,28672,8192
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
#include "libc/sysv/consts/syscon.internal.h"
|
||||||
.syscon statvfs,ST_MANDLOCK,0x40,0,0,0,0,0
|
.syscon statvfs,ST_MANDLOCK,0x0040,0,0,0,0,0
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
#include "libc/sysv/consts/syscon.internal.h"
|
||||||
.syscon statvfs,ST_SYNCHRONOUS,0x10,0,0,0,2,0
|
.syscon statvfs,ST_SYNCHRONOUS,16,0,0,0,2,0
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
#include "libc/sysv/consts/syscon.internal.h"
|
||||||
.syscon statvfs,ST_WRITE,0x80,0,0,0,0,0
|
.syscon statvfs,ST_WRITE,0x0080,0,0,0,0,0
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon stat,S_IEXEC,0000100,0000100,0000100,0000100,0000100,0000100
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon stat,S_IFBLK,0060000,0060000,0060000,0060000,0060000,0060000
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon stat,S_IFCHR,0020000,0020000,0020000,0020000,0020000,0020000
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon stat,S_IFDIR,0040000,0040000,0040000,0040000,0040000,0040000
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon stat,S_IFIFO,0010000,0010000,0010000,0010000,0010000,0010000
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon stat,S_IFLNK,0120000,0120000,0120000,0120000,0120000,0120000
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon stat,S_IFMT,0170000,0170000,0170000,0170000,0170000,0170000
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon stat,S_IFREG,0100000,0100000,0100000,0100000,0100000,0100000
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon stat,S_IFSOCK,0140000,0140000,0140000,0140000,0140000,0140000
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon stat,S_IREAD,0000400,0000400,0000400,0000400,0000400,0000400
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon stat,S_IRGRP,0000040,0000040,0000040,0000040,0000040,0000040
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon stat,S_IROTH,0000004,0000004,0000004,0000004,0000004,0000004
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon stat,S_IRUSR,0000400,0000400,0000400,0000400,0000400,0000400
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon stat,S_IRWXG,0000070,0000070,0000070,0000070,0000070,0000070
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon stat,S_IRWXO,0000007,0000007,0000007,0000007,0000007,0000007
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon stat,S_IRWXU,0000700,0000700,0000700,0000700,0000700,0000700
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon stat,S_ISGID,0002000,0002000,0002000,0002000,0002000,0002000
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon stat,S_ISUID,0004000,0004000,0004000,0004000,0004000,0004000
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon stat,S_ISVTX,0001000,0001000,0001000,0001000,0001000,0001000
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon stat,S_IWGRP,0000020,0000020,0000020,0000020,0000020,0000020
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon stat,S_IWOTH,0000002,0000002,0000002,0000002,0000002,0000002
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon stat,S_IWRITE,0000200,0000200,0000200,0000200,0000200,0000200
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon stat,S_IWUSR,0000200,0000200,0000200,0000200,0000200,0000200
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon stat,S_IXGRP,0000010,0000010,0000010,0000010,0000010,0000010
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon stat,S_IXOTH,0000001,0000001,0000001,0000001,0000001,0000001
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon stat,S_IXUSR,0000100,0000100,0000100,0000100,0000100,0000100
|
|
|
@ -12,13 +12,17 @@ extern const long MAP_DENYWRITE;
|
||||||
extern const long MAP_EXECUTABLE;
|
extern const long MAP_EXECUTABLE;
|
||||||
extern const long MAP_FILE;
|
extern const long MAP_FILE;
|
||||||
extern const long MAP_FIXED;
|
extern const long MAP_FIXED;
|
||||||
|
extern const long MAP_FIXED_NOREPLACE;
|
||||||
extern const long MAP_GROWSDOWN;
|
extern const long MAP_GROWSDOWN;
|
||||||
|
extern const long MAP_HASSEMAPHORE;
|
||||||
extern const long MAP_HUGETLB;
|
extern const long MAP_HUGETLB;
|
||||||
extern const long MAP_HUGE_MASK;
|
extern const long MAP_HUGE_MASK;
|
||||||
extern const long MAP_HUGE_SHIFT;
|
extern const long MAP_HUGE_SHIFT;
|
||||||
|
extern const long MAP_INHERIT;
|
||||||
extern const long MAP_LOCKED;
|
extern const long MAP_LOCKED;
|
||||||
extern const long MAP_NONBLOCK;
|
extern const long MAP_NONBLOCK;
|
||||||
extern const long MAP_NORESERVE;
|
extern const long MAP_NORESERVE;
|
||||||
|
extern const long MAP_NOSYNC;
|
||||||
extern const long MAP_POPULATE;
|
extern const long MAP_POPULATE;
|
||||||
extern const long MAP_PRIVATE;
|
extern const long MAP_PRIVATE;
|
||||||
extern const long MAP_SHARED;
|
extern const long MAP_SHARED;
|
||||||
|
@ -26,28 +30,30 @@ extern const long MAP_SHARED;
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
|
||||||
#define MAP_FILE 0
|
#define MAP_FILE 0
|
||||||
#define MAP_SHARED 1
|
#define MAP_SHARED 1
|
||||||
#define MAP_PRIVATE 2
|
#define MAP_PRIVATE 2
|
||||||
#define MAP_STACK 6
|
#define MAP_STACK 6
|
||||||
#define MAP_TYPE 15
|
#define MAP_TYPE 15
|
||||||
#define MAP_FIXED 16
|
#define MAP_FIXED 16
|
||||||
#define MAP_FIXED_NOREPLACE 0x8000000
|
|
||||||
|
|
||||||
#define MAP_32BIT SYMBOLIC(MAP_32BIT)
|
#define MAP_32BIT SYMBOLIC(MAP_32BIT)
|
||||||
#define MAP_ANONYMOUS SYMBOLIC(MAP_ANONYMOUS)
|
#define MAP_ANONYMOUS SYMBOLIC(MAP_ANONYMOUS)
|
||||||
#define MAP_CONCEAL SYMBOLIC(MAP_CONCEAL)
|
#define MAP_CONCEAL SYMBOLIC(MAP_CONCEAL)
|
||||||
#define MAP_CONCEAL SYMBOLIC(MAP_CONCEAL)
|
#define MAP_DENYWRITE SYMBOLIC(MAP_DENYWRITE)
|
||||||
#define MAP_DENYWRITE SYMBOLIC(MAP_DENYWRITE)
|
#define MAP_EXECUTABLE SYMBOLIC(MAP_EXECUTABLE)
|
||||||
#define MAP_EXECUTABLE SYMBOLIC(MAP_EXECUTABLE)
|
#define MAP_FIXED_NOREPLACE SYMBOLIC(MAP_FIXED_NOREPLACE)
|
||||||
#define MAP_GROWSDOWN SYMBOLIC(MAP_GROWSDOWN)
|
#define MAP_GROWSDOWN SYMBOLIC(MAP_GROWSDOWN)
|
||||||
#define MAP_HUGETLB SYMBOLIC(MAP_HUGETLB)
|
#define MAP_HASSEMAPHORE SYMBOLIC(MAP_HASSEMAPHORE)
|
||||||
#define MAP_HUGE_MASK SYMBOLIC(MAP_HUGE_MASK)
|
#define MAP_HUGETLB SYMBOLIC(MAP_HUGETLB)
|
||||||
#define MAP_HUGE_SHIFT SYMBOLIC(MAP_HUGE_SHIFT)
|
#define MAP_HUGE_MASK SYMBOLIC(MAP_HUGE_MASK)
|
||||||
#define MAP_LOCKED SYMBOLIC(MAP_LOCKED)
|
#define MAP_HUGE_SHIFT SYMBOLIC(MAP_HUGE_SHIFT)
|
||||||
#define MAP_NONBLOCK SYMBOLIC(MAP_NONBLOCK)
|
#define MAP_INHERIT SYMBOLIC(MAP_INHERIT)
|
||||||
#define MAP_NORESERVE SYMBOLIC(MAP_NORESERVE)
|
#define MAP_LOCKED SYMBOLIC(MAP_LOCKED)
|
||||||
#define MAP_POPULATE SYMBOLIC(MAP_POPULATE)
|
#define MAP_NONBLOCK SYMBOLIC(MAP_NONBLOCK)
|
||||||
|
#define MAP_NORESERVE SYMBOLIC(MAP_NORESERVE)
|
||||||
|
#define MAP_NOSYNC SYMBOLIC(MAP_NOSYNC)
|
||||||
|
#define MAP_POPULATE SYMBOLIC(MAP_POPULATE)
|
||||||
|
|
||||||
#define MAP_ANON MAP_ANONYMOUS
|
#define MAP_ANON MAP_ANONYMOUS
|
||||||
#define MAP_NOCORE MAP_CONCEAL
|
#define MAP_NOCORE MAP_CONCEAL
|
||||||
|
|
|
@ -3,13 +3,16 @@
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
|
extern const long SIGSTKSZ;
|
||||||
|
extern const long MINSIGSTKSZ;
|
||||||
extern const long SS_DISABLE;
|
extern const long SS_DISABLE;
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
|
||||||
#define SIGSTKSZ STACKSIZE
|
#define SIGSTKSZ STACKSIZE
|
||||||
#define SS_ONSTACK 1
|
#define MINSIGSTKSZ 32768
|
||||||
#define SS_DISABLE SS_DISABLE
|
#define SS_ONSTACK 1
|
||||||
|
#define SS_DISABLE SS_DISABLE
|
||||||
|
|
||||||
#endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_SS_H_ */
|
#endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_SS_H_ */
|
||||||
|
|
|
@ -9,7 +9,15 @@ o/$(MODE)/test/libc/release/cosmopolitan.zip: \
|
||||||
o/$(MODE)/ape/ape-no-modify-self.o \
|
o/$(MODE)/ape/ape-no-modify-self.o \
|
||||||
o/$(MODE)/cosmopolitan.a \
|
o/$(MODE)/cosmopolitan.a \
|
||||||
o/$(MODE)/third_party/zip/zip.com
|
o/$(MODE)/third_party/zip/zip.com
|
||||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -qj $@ o/cosmopolitan.h o/$(MODE)/ape/ape.lds o/$(MODE)/libc/crt/crt.o o/$(MODE)/ape/ape.o o/$(MODE)/ape/ape-no-modify-self.o o/$(MODE)/cosmopolitan.a
|
@$(COMPILE) -AZIP -T$@ \
|
||||||
|
o/$(MODE)/third_party/zip/zip.com \
|
||||||
|
-qj $@ \
|
||||||
|
o/cosmopolitan.h \
|
||||||
|
o/$(MODE)/ape/ape.lds \
|
||||||
|
o/$(MODE)/libc/crt/crt.o \
|
||||||
|
o/$(MODE)/ape/ape.o \
|
||||||
|
o/$(MODE)/ape/ape-no-modify-self.o \
|
||||||
|
o/$(MODE)/cosmopolitan.a
|
||||||
|
|
||||||
o/$(MODE)/test/libc/release/smoke.com: \
|
o/$(MODE)/test/libc/release/smoke.com: \
|
||||||
o/$(MODE)/test/libc/release/smoke.com.dbg
|
o/$(MODE)/test/libc/release/smoke.com.dbg
|
||||||
|
|
107
test/libc/runtime/ape_test.c
Normal file
107
test/libc/runtime/ape_test.c
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
|
│ Copyright 2022 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 "libc/calls/calls.h"
|
||||||
|
#include "libc/calls/sigbits.h"
|
||||||
|
#include "libc/calls/struct/sigaction.h"
|
||||||
|
#include "libc/errno.h"
|
||||||
|
#include "libc/mem/io.h"
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/sysv/consts/o.h"
|
||||||
|
#include "libc/sysv/consts/sig.h"
|
||||||
|
#include "libc/testlib/testlib.h"
|
||||||
|
|
||||||
|
STATIC_YOINK("zip_uri_support");
|
||||||
|
STATIC_YOINK("apetest.com");
|
||||||
|
STATIC_YOINK("apetest2.com");
|
||||||
|
|
||||||
|
char testlib_enable_tmp_setup_teardown_once;
|
||||||
|
|
||||||
|
void Extract(const char *from, const char *to, int mode) {
|
||||||
|
ASSERT_SYS(0, 3, open(from, O_RDONLY));
|
||||||
|
ASSERT_SYS(0, 4, creat(to, mode));
|
||||||
|
ASSERT_NE(-1, _copyfd(3, 4, -1));
|
||||||
|
EXPECT_SYS(0, 0, close(4));
|
||||||
|
EXPECT_SYS(0, 0, close(3));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetUpOnce(void) {
|
||||||
|
ASSERT_SYS(0, 0, mkdir("bin", 0755));
|
||||||
|
Extract("/zip/apetest.com", "bin/apetest.com", 0755);
|
||||||
|
Extract("/zip/apetest2.com", "bin/apetest2.com", 0755);
|
||||||
|
|
||||||
|
// force the extraction of ape payload
|
||||||
|
// if system does not have binfmt_misc
|
||||||
|
ASSERT_SYS(0, 0, mkdir("tmp", 0755));
|
||||||
|
setenv("TMPDIR", "tmp", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RunApeTest(const char *path) {
|
||||||
|
size_t n;
|
||||||
|
ssize_t rc, got;
|
||||||
|
char buf[512] = {0};
|
||||||
|
sigset_t chldmask, savemask;
|
||||||
|
int i, pid, fdin, wstatus, pfds[2];
|
||||||
|
struct sigaction ignore, saveint, savequit, savepipe;
|
||||||
|
ignore.sa_flags = 0;
|
||||||
|
ignore.sa_handler = SIG_IGN;
|
||||||
|
sigemptyset(&ignore.sa_mask);
|
||||||
|
sigaction(SIGINT, &ignore, &saveint);
|
||||||
|
sigaction(SIGQUIT, &ignore, &savequit);
|
||||||
|
sigaction(SIGPIPE, &ignore, &savepipe);
|
||||||
|
sigemptyset(&chldmask);
|
||||||
|
sigaddset(&chldmask, SIGCHLD);
|
||||||
|
sigprocmask(SIG_BLOCK, &chldmask, &savemask);
|
||||||
|
ASSERT_SYS(0, 0, pipe2(pfds, O_CLOEXEC));
|
||||||
|
ASSERT_NE(-1, (pid = fork()));
|
||||||
|
if (!pid) {
|
||||||
|
__strace = 0;
|
||||||
|
__ftrace = 0;
|
||||||
|
close(1);
|
||||||
|
dup(pfds[1]);
|
||||||
|
sigaction(SIGINT, &saveint, 0);
|
||||||
|
sigaction(SIGQUIT, &savequit, 0);
|
||||||
|
sigaction(SIGPIPE, &savepipe, 0);
|
||||||
|
sigprocmask(SIG_SETMASK, &savemask, 0);
|
||||||
|
execv(path, (char *const[]){path, 0});
|
||||||
|
_Exit(127);
|
||||||
|
}
|
||||||
|
close(pfds[1]);
|
||||||
|
EXPECT_SYS(0, 8, read(pfds[0], buf, sizeof(buf)));
|
||||||
|
EXPECT_STREQ("success\n", buf);
|
||||||
|
close(pfds[0]);
|
||||||
|
EXPECT_NE(-1, wait(&wstatus));
|
||||||
|
EXPECT_TRUE(WIFEXITED(wstatus));
|
||||||
|
EXPECT_EQ(0, WEXITSTATUS(wstatus));
|
||||||
|
sigaction(SIGINT, &saveint, 0);
|
||||||
|
sigaction(SIGQUIT, &savequit, 0);
|
||||||
|
sigaction(SIGPIPE, &savepipe, 0);
|
||||||
|
sigprocmask(SIG_SETMASK, &savemask, 0);
|
||||||
|
EXPECT_SYS(0, 3, open(path, O_RDONLY));
|
||||||
|
EXPECT_SYS(0, 6, read(3, buf, 6));
|
||||||
|
EXPECT_SYS(0, 0, close(3));
|
||||||
|
EXPECT_STREQN("MZqFpD", buf, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(apeNoModifySelf, runsWithoutModifyingSelf) {
|
||||||
|
RunApeTest("bin/apetest.com");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(apeCopySelf, runsWithoutModifyingSelf) {
|
||||||
|
RunApeTest("bin/apetest2.com");
|
||||||
|
}
|
|
@ -41,6 +41,8 @@ TEST_LIBC_RUNTIME_DIRECTDEPS = \
|
||||||
LIBC_TINYMATH \
|
LIBC_TINYMATH \
|
||||||
LIBC_UNICODE \
|
LIBC_UNICODE \
|
||||||
LIBC_X \
|
LIBC_X \
|
||||||
|
LIBC_ZIPOS \
|
||||||
|
TOOL_BUILD_LIB \
|
||||||
THIRD_PARTY_XED
|
THIRD_PARTY_XED
|
||||||
|
|
||||||
TEST_LIBC_RUNTIME_DEPS := \
|
TEST_LIBC_RUNTIME_DEPS := \
|
||||||
|
@ -59,6 +61,15 @@ o/$(MODE)/test/libc/runtime/%.com.dbg: \
|
||||||
$(APE)
|
$(APE)
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
|
o/$(MODE)/test/libc/runtime/ape_test.com.dbg: \
|
||||||
|
$(TEST_LIBC_RUNTIME_DEPS) \
|
||||||
|
o/$(MODE)/test/libc/runtime/ape_test.o \
|
||||||
|
o/$(MODE)/test/libc/runtime/runtime.pkg \
|
||||||
|
$(LIBC_TESTMAIN) \
|
||||||
|
$(CRT) \
|
||||||
|
$(APE)
|
||||||
|
@$(APELINK)
|
||||||
|
|
||||||
$(TEST_LIBC_RUNTIME_OBJS): \
|
$(TEST_LIBC_RUNTIME_OBJS): \
|
||||||
DEFAULT_CCFLAGS += \
|
DEFAULT_CCFLAGS += \
|
||||||
-fno-builtin
|
-fno-builtin
|
||||||
|
@ -67,7 +78,6 @@ o/$(MODE)/test/libc/runtime/getenv_test.com.runs: \
|
||||||
o/$(MODE)/test/libc/runtime/getenv_test.com
|
o/$(MODE)/test/libc/runtime/getenv_test.com
|
||||||
@HELLO=THERE build/runit $@ $<
|
@HELLO=THERE build/runit $@ $<
|
||||||
|
|
||||||
o/$(MODE)/test/libc/runtime/fun_test.o \
|
|
||||||
o/$(MODE)/test/libc/runtime/itsatrap_test.o: \
|
o/$(MODE)/test/libc/runtime/itsatrap_test.o: \
|
||||||
OVERRIDE_CFLAGS += \
|
OVERRIDE_CFLAGS += \
|
||||||
-fno-sanitize=all \
|
-fno-sanitize=all \
|
||||||
|
|
|
@ -72,13 +72,13 @@ TEST(plinko, worksOrPrintsNiceError) {
|
||||||
struct sigaction ignore, saveint, savequit, savepipe;
|
struct sigaction ignore, saveint, savequit, savepipe;
|
||||||
ignore.sa_flags = 0;
|
ignore.sa_flags = 0;
|
||||||
ignore.sa_handler = SIG_IGN;
|
ignore.sa_handler = SIG_IGN;
|
||||||
EXPECT_EQ(0, sigemptyset(&ignore.sa_mask));
|
sigemptyset(&ignore.sa_mask);
|
||||||
EXPECT_EQ(0, sigaction(SIGINT, &ignore, &saveint));
|
sigaction(SIGINT, &ignore, &saveint);
|
||||||
EXPECT_EQ(0, sigaction(SIGQUIT, &ignore, &savequit));
|
sigaction(SIGQUIT, &ignore, &savequit);
|
||||||
EXPECT_EQ(0, sigaction(SIGPIPE, &ignore, &savepipe));
|
sigaction(SIGPIPE, &ignore, &savepipe);
|
||||||
EXPECT_EQ(0, sigemptyset(&chldmask));
|
sigemptyset(&chldmask);
|
||||||
EXPECT_EQ(0, sigaddset(&chldmask, SIGCHLD));
|
sigaddset(&chldmask, SIGCHLD);
|
||||||
EXPECT_EQ(0, sigprocmask(SIG_BLOCK, &chldmask, &savemask));
|
sigprocmask(SIG_BLOCK, &chldmask, &savemask);
|
||||||
ASSERT_NE(-1, pipe2(pfds[0], O_CLOEXEC));
|
ASSERT_NE(-1, pipe2(pfds[0], O_CLOEXEC));
|
||||||
ASSERT_NE(-1, pipe2(pfds[1], O_CLOEXEC));
|
ASSERT_NE(-1, pipe2(pfds[1], O_CLOEXEC));
|
||||||
ASSERT_NE(-1, (pid = fork()));
|
ASSERT_NE(-1, (pid = fork()));
|
||||||
|
@ -90,14 +90,14 @@ TEST(plinko, worksOrPrintsNiceError) {
|
||||||
close(2), dup(pfds[1][1]);
|
close(2), dup(pfds[1][1]);
|
||||||
sigaction(SIGINT, &saveint, 0);
|
sigaction(SIGINT, &saveint, 0);
|
||||||
sigaction(SIGQUIT, &savequit, 0);
|
sigaction(SIGQUIT, &savequit, 0);
|
||||||
sigaction(SIGQUIT, &savepipe, 0);
|
sigaction(SIGPIPE, &savepipe, 0);
|
||||||
sigprocmask(SIG_SETMASK, &savemask, 0);
|
sigprocmask(SIG_SETMASK, &savemask, 0);
|
||||||
execve("bin/plinko.com", (char *const[]){"bin/plinko.com", 0},
|
execve("bin/plinko.com", (char *const[]){"bin/plinko.com", 0},
|
||||||
(char *const[]){0});
|
(char *const[]){0});
|
||||||
_exit(127);
|
_exit(127);
|
||||||
}
|
}
|
||||||
EXPECT_NE(-1, close(pfds[0][0]));
|
close(pfds[0][0]);
|
||||||
EXPECT_NE(-1, close(pfds[1][1]));
|
close(pfds[1][1]);
|
||||||
for (i = 0; i < ARRAYLEN(kSauces); ++i) {
|
for (i = 0; i < ARRAYLEN(kSauces); ++i) {
|
||||||
EXPECT_NE(-1, (fdin = open(kSauces[i], O_RDONLY)));
|
EXPECT_NE(-1, (fdin = open(kSauces[i], O_RDONLY)));
|
||||||
rc = _copyfd(fdin, pfds[0][1], -1);
|
rc = _copyfd(fdin, pfds[0][1], -1);
|
||||||
|
@ -118,10 +118,10 @@ TEST(plinko, worksOrPrintsNiceError) {
|
||||||
} else {
|
} else {
|
||||||
EXPECT_EQ(1, WEXITSTATUS(wstatus));
|
EXPECT_EQ(1, WEXITSTATUS(wstatus));
|
||||||
}
|
}
|
||||||
EXPECT_EQ(0, sigaction(SIGINT, &saveint, 0));
|
sigaction(SIGINT, &saveint, 0);
|
||||||
EXPECT_EQ(0, sigaction(SIGQUIT, &savequit, 0));
|
sigaction(SIGQUIT, &savequit, 0);
|
||||||
EXPECT_EQ(0, sigaction(SIGPIPE, &savepipe, 0));
|
sigaction(SIGPIPE, &savepipe, 0);
|
||||||
EXPECT_EQ(0, sigprocmask(SIG_SETMASK, &savemask, 0));
|
sigprocmask(SIG_SETMASK, &savemask, 0);
|
||||||
if (g_testlib_failed) {
|
if (g_testlib_failed) {
|
||||||
kprintf("note: got the following in pipe: %s%n", buf);
|
kprintf("note: got the following in pipe: %s%n", buf);
|
||||||
}
|
}
|
||||||
|
|
23
tool/build/lib/apetest.c
Normal file
23
tool/build/lib/apetest.c
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
|
│ Copyright 2022 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 "libc/calls/calls.h"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
write(1, "success\n", 8);
|
||||||
|
}
|
|
@ -9,7 +9,9 @@ TOOL_BUILD_LIB_A = o/$(MODE)/tool/build/lib/buildlib.a
|
||||||
TOOL_BUILD_LIB_A_FILES := $(wildcard tool/build/lib/*)
|
TOOL_BUILD_LIB_A_FILES := $(wildcard tool/build/lib/*)
|
||||||
TOOL_BUILD_LIB_A_HDRS = $(filter %.h,$(TOOL_BUILD_LIB_A_FILES))
|
TOOL_BUILD_LIB_A_HDRS = $(filter %.h,$(TOOL_BUILD_LIB_A_FILES))
|
||||||
TOOL_BUILD_LIB_A_SRCS_S = $(filter %.S,$(TOOL_BUILD_LIB_A_FILES))
|
TOOL_BUILD_LIB_A_SRCS_S = $(filter %.S,$(TOOL_BUILD_LIB_A_FILES))
|
||||||
TOOL_BUILD_LIB_A_SRCS_C = $(filter %.c,$(TOOL_BUILD_LIB_A_FILES))
|
|
||||||
|
TOOL_BUILD_LIB_A_SRCS_C = \
|
||||||
|
$(filter-out tool/build/lib/apetest.c,$(filter %.c,$(TOOL_BUILD_LIB_A_FILES)))
|
||||||
|
|
||||||
TOOL_BUILD_LIB_A_CHECKS = \
|
TOOL_BUILD_LIB_A_CHECKS = \
|
||||||
$(TOOL_BUILD_LIB_A_HDRS:%=o/$(MODE)/%.ok) \
|
$(TOOL_BUILD_LIB_A_HDRS:%=o/$(MODE)/%.ok) \
|
||||||
|
@ -19,9 +21,15 @@ TOOL_BUILD_LIB_A_SRCS = \
|
||||||
$(TOOL_BUILD_LIB_A_SRCS_S) \
|
$(TOOL_BUILD_LIB_A_SRCS_S) \
|
||||||
$(TOOL_BUILD_LIB_A_SRCS_C)
|
$(TOOL_BUILD_LIB_A_SRCS_C)
|
||||||
|
|
||||||
|
TOOL_BUILD_LIB_COMS = \
|
||||||
|
o/$(MODE)/tool/build/lib/apetest.com \
|
||||||
|
o/$(MODE)/tool/build/lib/apetest2.com
|
||||||
|
|
||||||
TOOL_BUILD_LIB_A_OBJS = \
|
TOOL_BUILD_LIB_A_OBJS = \
|
||||||
$(TOOL_BUILD_LIB_A_SRCS_S:%.S=o/$(MODE)/%.o) \
|
$(TOOL_BUILD_LIB_A_SRCS_S:%.S=o/$(MODE)/%.o) \
|
||||||
$(TOOL_BUILD_LIB_A_SRCS_C:%.c=o/$(MODE)/%.o)
|
$(TOOL_BUILD_LIB_A_SRCS_C:%.c=o/$(MODE)/%.o) \
|
||||||
|
o/$(MODE)/tool/build/lib/apetest.com.zip.o \
|
||||||
|
o/$(MODE)/tool/build/lib/apetest2.com.zip.o
|
||||||
|
|
||||||
TOOL_BUILD_LIB_A_DIRECTDEPS = \
|
TOOL_BUILD_LIB_A_DIRECTDEPS = \
|
||||||
LIBC_ALG \
|
LIBC_ALG \
|
||||||
|
@ -67,6 +75,25 @@ o/$(MODE)/tool/build/lib/ssefloat.o: \
|
||||||
TARGET_ARCH += \
|
TARGET_ARCH += \
|
||||||
-msse3
|
-msse3
|
||||||
|
|
||||||
|
o/$(MODE)/tool/build/lib/apetest.com.dbg: \
|
||||||
|
$(TOOL_BUILD_LIB_A_DEPS) \
|
||||||
|
o/$(MODE)/tool/build/lib/apetest.o \
|
||||||
|
$(CRT) \
|
||||||
|
$(APE_NO_MODIFY_SELF)
|
||||||
|
@$(APELINK)
|
||||||
|
|
||||||
|
o/$(MODE)/tool/build/lib/apetest2.com.dbg: \
|
||||||
|
$(TOOL_BUILD_LIB_A_DEPS) \
|
||||||
|
o/$(MODE)/tool/build/lib/apetest.o \
|
||||||
|
$(CRT) \
|
||||||
|
$(APE_COPY_SELF)
|
||||||
|
@$(APELINK)
|
||||||
|
|
||||||
|
o/$(MODE)/tool/build/lib/apetest.com.zip.o \
|
||||||
|
o/$(MODE)/tool/build/lib/apetest2.com.zip.o: \
|
||||||
|
ZIPOBJ_FLAGS += \
|
||||||
|
-B
|
||||||
|
|
||||||
TOOL_BUILD_LIB_LIBS = $(foreach x,$(TOOL_BUILD_LIB_ARTIFACTS),$($(x)))
|
TOOL_BUILD_LIB_LIBS = $(foreach x,$(TOOL_BUILD_LIB_ARTIFACTS),$($(x)))
|
||||||
TOOL_BUILD_LIB_SRCS = $(foreach x,$(TOOL_BUILD_LIB_ARTIFACTS),$($(x)_SRCS))
|
TOOL_BUILD_LIB_SRCS = $(foreach x,$(TOOL_BUILD_LIB_ARTIFACTS),$($(x)_SRCS))
|
||||||
TOOL_BUILD_LIB_HDRS = $(foreach x,$(TOOL_BUILD_LIB_ARTIFACTS),$($(x)_HDRS))
|
TOOL_BUILD_LIB_HDRS = $(foreach x,$(TOOL_BUILD_LIB_ARTIFACTS),$($(x)_HDRS))
|
||||||
|
@ -76,4 +103,6 @@ TOOL_BUILD_LIB_OBJS = $(foreach x,$(TOOL_BUILD_LIB_ARTIFACTS),$($(x)_OBJS))
|
||||||
TOOL_BUILD_LIB_TESTS = $(foreach x,$(TOOL_BUILD_LIB_ARTIFACTS),$($(x)_TESTS))
|
TOOL_BUILD_LIB_TESTS = $(foreach x,$(TOOL_BUILD_LIB_ARTIFACTS),$($(x)_TESTS))
|
||||||
|
|
||||||
.PHONY: o/$(MODE)/tool/build/lib
|
.PHONY: o/$(MODE)/tool/build/lib
|
||||||
o/$(MODE)/tool/build/lib: $(TOOL_BUILD_LIB_CHECKS)
|
o/$(MODE)/tool/build/lib: \
|
||||||
|
$(TOOL_BUILD_LIB_COMS) \
|
||||||
|
$(TOOL_BUILD_LIB_CHECKS)
|
||||||
|
|
|
@ -7305,7 +7305,6 @@ void RedBean(int argc, char *argv[]) {
|
||||||
#else
|
#else
|
||||||
GetHostsTxt(); // for effect
|
GetHostsTxt(); // for effect
|
||||||
GetResolvConf(); // for effect
|
GetResolvConf(); // for effect
|
||||||
__print_maps();
|
|
||||||
if (daemonize || uniprocess || !linenoiseIsTerminal()) {
|
if (daemonize || uniprocess || !linenoiseIsTerminal()) {
|
||||||
EventLoop(HEARTBEAT);
|
EventLoop(HEARTBEAT);
|
||||||
} else if (IsWindows()) {
|
} else if (IsWindows()) {
|
||||||
|
|
Loading…
Reference in a new issue