Skip to content

Commit 969174e

Browse files
committed
Add APE interpreter example (#263)
1 parent 5b60e5a commit 969174e

File tree

7 files changed

+210
-14
lines changed

7 files changed

+210
-14
lines changed

examples/examples.mk

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ EXAMPLES_COMS = \
3030

3131
EXAMPLES_BINS = \
3232
$(EXAMPLES_COMS) \
33-
$(EXAMPLES_COMS:%=%.dbg)
33+
$(EXAMPLES_COMS:%=%.dbg) \
34+
o/$(MODE)/examples/loader.elf
3435

3536
EXAMPLES_DIRECTDEPS = \
3637
DSP_CORE \
@@ -130,6 +131,15 @@ o/$(MODE)/examples/nesemu1.com.dbg: \
130131
$(APE)
131132
@$(APELINK)
132133

134+
o/$(MODE)/examples/loader.o: \
135+
OVERRIDE_CCFLAGS += \
136+
-fno-record-gcc-switches
137+
138+
o/$(MODE)/examples/loader.elf: \
139+
o/$(MODE)/examples/loader.o \
140+
examples/loader.lds
141+
@$(ELFLINK) -s -z max-page-size=0x10
142+
133143
$(EXAMPLES_OBJS): examples/examples.mk
134144

135145
usr/share/dict/words: usr/share/dict/words.gz

examples/loader.c

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
#if 0
2+
/*─────────────────────────────────────────────────────────────────╗
3+
│ To the extent possible under law, Justine Tunney has waived │
4+
│ all copyright and related or neighboring rights to this file, │
5+
│ as it is written in the following disclaimers: │
6+
│ • http://unlicense.org/ │
7+
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
8+
╚─────────────────────────────────────────────────────────────────*/
9+
#endif
10+
#include "libc/bits/bits.h"
11+
#include "libc/calls/calls.h"
12+
#include "libc/calls/struct/stat.h"
13+
#include "libc/elf/def.h"
14+
#include "libc/elf/struct/ehdr.h"
15+
#include "libc/elf/struct/phdr.h"
16+
#include "libc/linux/close.h"
17+
#include "libc/linux/exit.h"
18+
#include "libc/linux/fstat.h"
19+
#include "libc/linux/mmap.h"
20+
#include "libc/linux/open.h"
21+
22+
/**
23+
* @fileoverview 704-byte APE executing payload for Linux, e.g.
24+
*
25+
* m=tiny
26+
* make -j8 MODE=$m o/$m/examples
27+
* o/$m/examples/loader.elf o/$m/examples/printargs.com
28+
*
29+
* @note this can probably be used as a binfmt_misc interpreter
30+
*/
31+
32+
#define O_RDONLY 0
33+
#define PROT_READ 1
34+
#define PROT_WRITE 2
35+
#define PROT_EXEC 4
36+
#define MAP_SHARED 1
37+
#define MAP_PRIVATE 2
38+
#define MAP_FIXED 16
39+
#define MAP_ANONYMOUS 32
40+
41+
asm(".globl\t_start\n\t"
42+
"_start:\n\t"
43+
"mov\t%rsp,%rdi\n\t"
44+
"jmp\tloader");
45+
46+
static noasan noubsan void spawn(long *sp, char *b) {
47+
struct Elf64_Ehdr *e;
48+
struct Elf64_Phdr *h;
49+
e = (void *)b;
50+
h = (void *)(b + e->e_phoff);
51+
if (LinuxMmap((void *)(h[1].p_vaddr + h[1].p_filesz),
52+
h[1].p_memsz - h[1].p_filesz, PROT_READ | PROT_WRITE,
53+
MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0) > 0) {
54+
sp[1] = sp[0] - 1;
55+
asm volatile("mov\t%2,%%rsp\n\t"
56+
"jmpq\t*%1"
57+
: /* no outputs */
58+
: "D"(0), "S"((void *)e->e_entry), "d"(sp + 1)
59+
: "memory");
60+
unreachable;
61+
}
62+
}
63+
64+
noasan noubsan void loader(long *sp) {
65+
struct stat st;
66+
int c, i, fd, argc;
67+
char *b, *p, *q, **argv;
68+
argc = *sp;
69+
argv = (char **)(sp + 1);
70+
if (argc > 1 && (fd = LinuxOpen(argv[1], O_RDONLY, 0)) >= 0 &&
71+
!LinuxFstat(fd, &st) &&
72+
(b = (char *)LinuxMmap((void *)0x400000, st.st_size,
73+
PROT_READ | PROT_WRITE | PROT_EXEC,
74+
MAP_PRIVATE | MAP_FIXED, fd, 0)) > 0) {
75+
LinuxClose(fd);
76+
if (READ32LE(b) == READ32LE("\177ELF")) {
77+
spawn(sp, b);
78+
} else {
79+
for (p = b; p < b + st.st_size; ++p) {
80+
if (READ64LE(p) == READ64LE("printf '")) {
81+
for (q = b, p += 8; (c = *p++) != '\'';) {
82+
if (c == '\\') {
83+
c = *p++ - '0';
84+
if ('0' <= *p && *p <= '7') c *= 8, c += *p++ - '0';
85+
if ('0' <= *p && *p <= '7') c *= 8, c += *p++ - '0';
86+
}
87+
*q++ = c;
88+
}
89+
if (READ32LE(b) == READ32LE("\177ELF")) {
90+
spawn(sp, b);
91+
}
92+
break;
93+
}
94+
}
95+
}
96+
}
97+
LinuxExit(127);
98+
}

examples/loader.lds

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*-*- mode: ld-script; indent-tabs-mode: nil; tab-width: 2; coding: utf-8 -*-│
2+
│vi: set et sts=2 tw=2 fenc=utf-8 :vi│
3+
╞══════════════════════════════════════════════════════════════════════════════╡
4+
│ Copyright 2021 Justine Alexandra Roberts Tunney │
5+
│ │
6+
│ Permission to use, copy, modify, and/or distribute this software for │
7+
│ any purpose with or without fee is hereby granted, provided that the │
8+
│ above copyright notice and this permission notice appear in all copies. │
9+
│ │
10+
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
11+
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
12+
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
13+
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
14+
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
15+
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
16+
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
17+
│ PERFORMANCE OF THIS SOFTWARE. │
18+
╚─────────────────────────────────────────────────────────────────────────────*/
19+
20+
ENTRY(_start)
21+
22+
SECTIONS {
23+
24+
. = 0x200000 + SIZEOF_HEADERS;
25+
26+
.text : {
27+
*(.text .text.*)
28+
*(.rodata .rodata.*)
29+
*(.data .data.*)
30+
*(.bss .bss.*)
31+
}
32+
33+
.gnu_debuglink 0 : { *(.gnu_debuglink) }
34+
.stab 0 : { *(.stab) }
35+
.stabstr 0 : { *(.stabstr) }
36+
.stab.excl 0 : { *(.stab.excl) }
37+
.stab.exclstr 0 : { *(.stab.exclstr) }
38+
.stab.index 0 : { *(.stab.index) }
39+
.stab.indexstr 0 : { *(.stab.indexstr) }
40+
.debug 0 : { *(.debug) }
41+
.line 0 : { *(.line) }
42+
.debug_srcinfo 0 : { *(.debug_srcinfo) }
43+
.debug_sfnames 0 : { *(.debug_sfnames) }
44+
.debug_aranges 0 : { *(.debug_aranges) }
45+
.debug_pubnames 0 : { *(.debug_pubnames) }
46+
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
47+
.debug_abbrev 0 : { *(.debug_abbrev) }
48+
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) }
49+
.debug_frame 0 : { *(.debug_frame) }
50+
.debug_str 0 : { *(.debug_str) }
51+
.debug_loc 0 : { *(.debug_loc) }
52+
.debug_macinfo 0 : { *(.debug_macinfo) }
53+
.debug_weaknames 0 : { *(.debug_weaknames) }
54+
.debug_funcnames 0 : { *(.debug_funcnames) }
55+
.debug_typenames 0 : { *(.debug_typenames) }
56+
.debug_varnames 0 : { *(.debug_varnames) }
57+
.debug_pubtypes 0 : { *(.debug_pubtypes) }
58+
.debug_ranges 0 : { *(.debug_ranges) }
59+
.debug_macro 0 : { *(.debug_macro) }
60+
.debug_addr 0 : { *(.debug_addr) }
61+
.gnu.attributes 0 : { KEEP(*(.gnu.attributes)) }
62+
63+
/DISCARD/ : {
64+
*(.*)
65+
}
66+
}

libc/elf/def.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,9 @@
123123

124124
#define PN_XNUM 0xffff
125125

126-
#define PF_X (1 << 0)
127-
#define PF_W (1 << 1)
128-
#define PF_R (1 << 2)
126+
#define PF_X 1
127+
#define PF_W 2
128+
#define PF_R 4
129129
#define PF_MASKOS 0x0ff00000
130130
#define PF_MASKPROC 0xf0000000
131131

libc/linux/execve.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#ifndef COSMOPOLITAN_LIBC_LINUX_EXECVE_H_
2+
#define COSMOPOLITAN_LIBC_LINUX_EXECVE_H_
3+
#if !(__ASSEMBLER__ + __LINKER__ + 0)
4+
5+
forceinline long LinuxExecve(const char *program, char *const argv[],
6+
char *const envp[]) {
7+
long rc;
8+
asm volatile("syscall"
9+
: "=a"(rc)
10+
: "0"(59), "D"(program), "S"(argv), "d"(envp)
11+
: "rcx", "r11", "memory");
12+
return rc;
13+
}
14+
15+
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
16+
#endif /* COSMOPOLITAN_LIBC_LINUX_EXECVE_H_ */

libc/linux/mmap.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@
55
forceinline long LinuxMmap(void *addr, size_t size, long prot, long flags,
66
long fd, long off) {
77
long rc;
8-
asm volatile("mov\t%5,%%r10\n\t"
9-
"mov\t%6,%%r8\n\t"
10-
"mov\t%7,%%r9\n\t"
11-
"syscall"
8+
register long flags_ asm("r10") = flags;
9+
register long fd_ asm("r8") = fd;
10+
register long off_ asm("r9") = off;
11+
asm volatile("syscall"
1212
: "=a"(rc)
13-
: "0"(9), "D"(addr), "S"(size), "d"(prot), "g"(flags), "g"(fd),
14-
"g"(off)
15-
: "rcx", "r8", "r9", "r10", "r11", "memory");
13+
: "0"(9), "D"(addr), "S"(size), "d"(prot), "r"(flags_), "r"(fd_),
14+
"r"(off_)
15+
: "rcx", "r11", "memory");
1616
return rc;
1717
}
1818

libc/str/wmemset.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,15 @@
2323
* @asyncsignalsafe
2424
*/
2525
wchar_t *wmemset(wchar_t *p, wchar_t c, size_t n) {
26-
size_t i;
27-
for (i = 0; i < n; ++i) {
28-
p[i] = c;
26+
size_t i = 0;
27+
if (n >= 4) {
28+
wchar_t v __attribute__((__vector_size__(16))) = {c, c, c, c};
29+
do {
30+
__builtin_memcpy(p + i, &v, 16);
31+
} while ((i += 4) + 4 <= n);
32+
}
33+
while (i < n) {
34+
p[i++] = c;
2935
}
3036
return p;
3137
}

0 commit comments

Comments
 (0)