mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +00:00
Add APE interpreter example (#263)
This commit is contained in:
parent
5b60e5a37d
commit
969174e155
7 changed files with 210 additions and 14 deletions
|
@ -30,7 +30,8 @@ EXAMPLES_COMS = \
|
|||
|
||||
EXAMPLES_BINS = \
|
||||
$(EXAMPLES_COMS) \
|
||||
$(EXAMPLES_COMS:%=%.dbg)
|
||||
$(EXAMPLES_COMS:%=%.dbg) \
|
||||
o/$(MODE)/examples/loader.elf
|
||||
|
||||
EXAMPLES_DIRECTDEPS = \
|
||||
DSP_CORE \
|
||||
|
@ -130,6 +131,15 @@ o/$(MODE)/examples/nesemu1.com.dbg: \
|
|||
$(APE)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/examples/loader.o: \
|
||||
OVERRIDE_CCFLAGS += \
|
||||
-fno-record-gcc-switches
|
||||
|
||||
o/$(MODE)/examples/loader.elf: \
|
||||
o/$(MODE)/examples/loader.o \
|
||||
examples/loader.lds
|
||||
@$(ELFLINK) -s -z max-page-size=0x10
|
||||
|
||||
$(EXAMPLES_OBJS): examples/examples.mk
|
||||
|
||||
usr/share/dict/words: usr/share/dict/words.gz
|
||||
|
|
98
examples/loader.c
Normal file
98
examples/loader.c
Normal file
|
@ -0,0 +1,98 @@
|
|||
#if 0
|
||||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/elf/def.h"
|
||||
#include "libc/elf/struct/ehdr.h"
|
||||
#include "libc/elf/struct/phdr.h"
|
||||
#include "libc/linux/close.h"
|
||||
#include "libc/linux/exit.h"
|
||||
#include "libc/linux/fstat.h"
|
||||
#include "libc/linux/mmap.h"
|
||||
#include "libc/linux/open.h"
|
||||
|
||||
/**
|
||||
* @fileoverview 704-byte APE executing payload for Linux, e.g.
|
||||
*
|
||||
* m=tiny
|
||||
* make -j8 MODE=$m o/$m/examples
|
||||
* o/$m/examples/loader.elf o/$m/examples/printargs.com
|
||||
*
|
||||
* @note this can probably be used as a binfmt_misc interpreter
|
||||
*/
|
||||
|
||||
#define O_RDONLY 0
|
||||
#define PROT_READ 1
|
||||
#define PROT_WRITE 2
|
||||
#define PROT_EXEC 4
|
||||
#define MAP_SHARED 1
|
||||
#define MAP_PRIVATE 2
|
||||
#define MAP_FIXED 16
|
||||
#define MAP_ANONYMOUS 32
|
||||
|
||||
asm(".globl\t_start\n\t"
|
||||
"_start:\n\t"
|
||||
"mov\t%rsp,%rdi\n\t"
|
||||
"jmp\tloader");
|
||||
|
||||
static noasan noubsan void spawn(long *sp, char *b) {
|
||||
struct Elf64_Ehdr *e;
|
||||
struct Elf64_Phdr *h;
|
||||
e = (void *)b;
|
||||
h = (void *)(b + e->e_phoff);
|
||||
if (LinuxMmap((void *)(h[1].p_vaddr + h[1].p_filesz),
|
||||
h[1].p_memsz - h[1].p_filesz, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0) > 0) {
|
||||
sp[1] = sp[0] - 1;
|
||||
asm volatile("mov\t%2,%%rsp\n\t"
|
||||
"jmpq\t*%1"
|
||||
: /* no outputs */
|
||||
: "D"(0), "S"((void *)e->e_entry), "d"(sp + 1)
|
||||
: "memory");
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
noasan noubsan void loader(long *sp) {
|
||||
struct stat st;
|
||||
int c, i, fd, argc;
|
||||
char *b, *p, *q, **argv;
|
||||
argc = *sp;
|
||||
argv = (char **)(sp + 1);
|
||||
if (argc > 1 && (fd = LinuxOpen(argv[1], O_RDONLY, 0)) >= 0 &&
|
||||
!LinuxFstat(fd, &st) &&
|
||||
(b = (char *)LinuxMmap((void *)0x400000, st.st_size,
|
||||
PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
MAP_PRIVATE | MAP_FIXED, fd, 0)) > 0) {
|
||||
LinuxClose(fd);
|
||||
if (READ32LE(b) == READ32LE("\177ELF")) {
|
||||
spawn(sp, b);
|
||||
} else {
|
||||
for (p = b; p < b + st.st_size; ++p) {
|
||||
if (READ64LE(p) == READ64LE("printf '")) {
|
||||
for (q = b, p += 8; (c = *p++) != '\'';) {
|
||||
if (c == '\\') {
|
||||
c = *p++ - '0';
|
||||
if ('0' <= *p && *p <= '7') c *= 8, c += *p++ - '0';
|
||||
if ('0' <= *p && *p <= '7') c *= 8, c += *p++ - '0';
|
||||
}
|
||||
*q++ = c;
|
||||
}
|
||||
if (READ32LE(b) == READ32LE("\177ELF")) {
|
||||
spawn(sp, b);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
LinuxExit(127);
|
||||
}
|
66
examples/loader.lds
Normal file
66
examples/loader.lds
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*-*- mode: ld-script; indent-tabs-mode: nil; tab-width: 2; coding: utf-8 -*-│
|
||||
│vi: set et sts=2 tw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
|
||||
ENTRY(_start)
|
||||
|
||||
SECTIONS {
|
||||
|
||||
. = 0x200000 + SIZEOF_HEADERS;
|
||||
|
||||
.text : {
|
||||
*(.text .text.*)
|
||||
*(.rodata .rodata.*)
|
||||
*(.data .data.*)
|
||||
*(.bss .bss.*)
|
||||
}
|
||||
|
||||
.gnu_debuglink 0 : { *(.gnu_debuglink) }
|
||||
.stab 0 : { *(.stab) }
|
||||
.stabstr 0 : { *(.stabstr) }
|
||||
.stab.excl 0 : { *(.stab.excl) }
|
||||
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||
.stab.index 0 : { *(.stab.index) }
|
||||
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||
.debug 0 : { *(.debug) }
|
||||
.line 0 : { *(.line) }
|
||||
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||
.debug_typenames 0 : { *(.debug_typenames) }
|
||||
.debug_varnames 0 : { *(.debug_varnames) }
|
||||
.debug_pubtypes 0 : { *(.debug_pubtypes) }
|
||||
.debug_ranges 0 : { *(.debug_ranges) }
|
||||
.debug_macro 0 : { *(.debug_macro) }
|
||||
.debug_addr 0 : { *(.debug_addr) }
|
||||
.gnu.attributes 0 : { KEEP(*(.gnu.attributes)) }
|
||||
|
||||
/DISCARD/ : {
|
||||
*(.*)
|
||||
}
|
||||
}
|
|
@ -123,9 +123,9 @@
|
|||
|
||||
#define PN_XNUM 0xffff
|
||||
|
||||
#define PF_X (1 << 0)
|
||||
#define PF_W (1 << 1)
|
||||
#define PF_R (1 << 2)
|
||||
#define PF_X 1
|
||||
#define PF_W 2
|
||||
#define PF_R 4
|
||||
#define PF_MASKOS 0x0ff00000
|
||||
#define PF_MASKPROC 0xf0000000
|
||||
|
||||
|
|
16
libc/linux/execve.h
Normal file
16
libc/linux/execve.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_LINUX_EXECVE_H_
|
||||
#define COSMOPOLITAN_LIBC_LINUX_EXECVE_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
forceinline long LinuxExecve(const char *program, char *const argv[],
|
||||
char *const envp[]) {
|
||||
long rc;
|
||||
asm volatile("syscall"
|
||||
: "=a"(rc)
|
||||
: "0"(59), "D"(program), "S"(argv), "d"(envp)
|
||||
: "rcx", "r11", "memory");
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_LINUX_EXECVE_H_ */
|
|
@ -5,14 +5,14 @@
|
|||
forceinline long LinuxMmap(void *addr, size_t size, long prot, long flags,
|
||||
long fd, long off) {
|
||||
long rc;
|
||||
asm volatile("mov\t%5,%%r10\n\t"
|
||||
"mov\t%6,%%r8\n\t"
|
||||
"mov\t%7,%%r9\n\t"
|
||||
"syscall"
|
||||
register long flags_ asm("r10") = flags;
|
||||
register long fd_ asm("r8") = fd;
|
||||
register long off_ asm("r9") = off;
|
||||
asm volatile("syscall"
|
||||
: "=a"(rc)
|
||||
: "0"(9), "D"(addr), "S"(size), "d"(prot), "g"(flags), "g"(fd),
|
||||
"g"(off)
|
||||
: "rcx", "r8", "r9", "r10", "r11", "memory");
|
||||
: "0"(9), "D"(addr), "S"(size), "d"(prot), "r"(flags_), "r"(fd_),
|
||||
"r"(off_)
|
||||
: "rcx", "r11", "memory");
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,9 +23,15 @@
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
wchar_t *wmemset(wchar_t *p, wchar_t c, size_t n) {
|
||||
size_t i;
|
||||
for (i = 0; i < n; ++i) {
|
||||
p[i] = c;
|
||||
size_t i = 0;
|
||||
if (n >= 4) {
|
||||
wchar_t v __attribute__((__vector_size__(16))) = {c, c, c, c};
|
||||
do {
|
||||
__builtin_memcpy(p + i, &v, 16);
|
||||
} while ((i += 4) + 4 <= n);
|
||||
}
|
||||
while (i < n) {
|
||||
p[i++] = c;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue