boot2

Playing with the boostrap
git clone https://git.ryansepassi.com/git/boot2.git
Log | Files | Refs

commit 04e5c663480809c351cc3e9668c4b72900aa4d89
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Mon, 20 Apr 2026 11:59:53 -0700

Initial commit: aarch64 hello-world via M1 + hex2

Sets up the lispcc project skeleton: PLAN.md outlining the alternative
bootstrap path (Lisp-in-M1 + C compiler in Lisp, replacing M2-Planet/
Mes/MesCC/nyacc), a hand-written aarch64 hello.M1, and a podman-driven
Makefile that builds M1/hex2 statically in an alpine+gcc builder and
runs them inside a pristine alpine:latest.

Diffstat:
A.gitignore | 1+
AContainerfile | 6++++++
AELF-aarch64.hex2 | 75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AMakefile | 85+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
APLAN.md | 115+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AREADME.md | 47+++++++++++++++++++++++++++++++++++++++++++++++
Aaarch64_defs.M1 | 229+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ahello.M1 | 27+++++++++++++++++++++++++++
8 files changed, 585 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/Containerfile b/Containerfile @@ -0,0 +1,6 @@ +# Builder image: alpine + gcc, used only to compile M1 and hex2 statically. +# The compiled binaries are then run inside a pristine alpine:latest with +# nothing else added. +FROM alpine:latest +RUN apk add --no-cache gcc musl-dev +WORKDIR /work diff --git a/ELF-aarch64.hex2 b/ELF-aarch64.hex2 @@ -0,0 +1,75 @@ +### Copyright (C) 2016 Jeremiah Orians +### Copyright (C) 2017 Jan Nieuwenhuizen <janneke@gnu.org> +### Copyright (C) 2020 deesix <deesix@tuta.io> +### This file is part of M2-Planet. +### +### M2-Planet is free software: you can redistribute it and/or modify +### it under the terms of the GNU General Public License as published by +### the Free Software Foundation, either version 3 of the License, or +### (at your option) any later version. +### +### M2-Planet is distributed in the hope that it will be useful, +### but WITHOUT ANY WARRANTY; without even the implied warranty of +### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +### GNU General Public License for more details. +### +### You should have received a copy of the GNU General Public License +### along with M2-Planet. If not, see <http://www.gnu.org/licenses/>. + +### stage0's hex2 format +### !<label> 1 byte relative +### $<label> 2 byte address +### @<label> 2 byte relative +### &<label> 4 byte address +### %<label> 4 byte relative + +### if you wish to use this header, you need to add :ELF_end to the end of your +### M1 or hex2 files. + +## ELF Header + +:ELF_base +7F 45 4C 46 # e_ident[EI_MAG0-3] ELF's magic number + +02 # e_ident[EI_CLASS] Indicating 64 bit +01 # e_ident[EI_DATA] Indicating little endianness +01 # e_ident[EI_VERSION] Indicating original elf + +03 # e_ident[EI_OSABI] Set at 3 because FreeBSD is strict +00 # e_ident[EI_ABIVERSION] See above + +00 00 00 00 00 00 00 # e_ident[EI_PAD] + +02 00 # e_type Indicating Executable +B7 00 # e_machine Indicating AArch64 +01 00 00 00 # e_version Indicating original elf + +&_start 00 00 00 00 # e_entry Address of the entry point +%ELF_program_headers>ELF_base 00 00 00 00 # e_phoff Address of program header table +00 00 00 00 00 00 00 00 # e_shoff Address of section header table + +00 00 00 00 # e_flags + +40 00 # e_ehsize Indicating our 64 Byte header + +38 00 # e_phentsize size of a program header table +01 00 # e_phnum number of entries in program table + +00 00 # e_shentsize size of a section header table +00 00 # e_shnum number of entries in section table + +00 00 # e_shstrndx index of the section names + + +:ELF_program_headers +:ELF_program_header__text +01 00 00 00 # ph_type: PT-LOAD = 1 +07 00 00 00 # ph_flags: PF-X|PF-W|PF-R = 7 +00 00 00 00 00 00 00 00 # ph_offset +&ELF_base 00 00 00 00 # ph_vaddr +&ELF_base 00 00 00 00 # ph_physaddr +%ELF_end>ELF_base 00 00 00 00 # ph_filesz +%ELF_end>ELF_base 00 00 00 00 # ph_memsz +01 00 00 00 00 00 00 00 # ph_align + +:ELF_text diff --git a/Makefile b/Makefile @@ -0,0 +1,85 @@ +# lispcc — alternative bootstrap path: aarch64 Lisp-in-M1 → C compiler in +# Lisp → tcc-boot. See PLAN.md. +# +# Two-image setup: +# - lispcc-builder (alpine + gcc): builds M1 and hex2 statically +# - alpine:latest (pristine): runs M1, hex2, and the assembled output +# +# Usage: +# make image Build the builder image (one-time, idempotent) +# make Build toolchain + assemble hello.M1 → build/hello +# make run Run build/hello in pristine alpine +# make clean Remove build/ artifacts + +# --- Configuration --------------------------------------------------------- + +HOST_ROOT := $(abspath $(CURDIR)/..) +TOOLCHAIN_SRC := /work/live-bootstrap/seed/stage0-posix/mescc-tools +BUILDER_IMAGE := lispcc-builder:latest +RUNTIME_IMAGE := docker.io/library/alpine:latest + +# Builder: alpine + gcc, mounts the bootstrap-explore parent dir at /work +# so we can reach upstream mescc-tools C source. +PODMAN_BUILD := podman run --rm \ + -v $(HOST_ROOT):/work \ + -w /work/lispcc \ + $(BUILDER_IMAGE) + +# Runtime: pristine alpine, mounts only this project dir at /work. +PODMAN_RUN := podman run --rm \ + -v $(CURDIR):/work \ + -w /work \ + $(RUNTIME_IMAGE) + +# Static linking so M1/hex2 have no libc dep at runtime. +CFLAGS := -D_GNU_SOURCE -std=c99 -ggdb -fno-common -static + +# --- Targets --------------------------------------------------------------- + +.PHONY: all image toolchain run clean + +all: build/hello + +image: + podman build -t $(BUILDER_IMAGE) . + +toolchain: build/M1 build/hex2 + +build: + mkdir -p build + +build/M1: | build + $(PODMAN_BUILD) gcc $(CFLAGS) \ + $(TOOLCHAIN_SRC)/M1-macro.c \ + $(TOOLCHAIN_SRC)/stringify.c \ + $(TOOLCHAIN_SRC)/M2libc/bootstrappable.c \ + -o build/M1 + +build/hex2: | build + $(PODMAN_BUILD) gcc $(CFLAGS) \ + $(TOOLCHAIN_SRC)/hex2.c \ + $(TOOLCHAIN_SRC)/hex2_linker.c \ + $(TOOLCHAIN_SRC)/hex2_word.c \ + $(TOOLCHAIN_SRC)/M2libc/bootstrappable.c \ + -o build/hex2 + +build/hello.hex2: hello.M1 aarch64_defs.M1 build/M1 + $(PODMAN_RUN) ./build/M1 \ + -f aarch64_defs.M1 \ + -f hello.M1 \ + --little-endian --architecture aarch64 \ + -o build/hello.hex2 + +build/hello: build/hello.hex2 ELF-aarch64.hex2 build/hex2 + $(PODMAN_RUN) ./build/hex2 \ + -f ELF-aarch64.hex2 \ + -f build/hello.hex2 \ + --little-endian --architecture aarch64 \ + --base-address 0x400000 \ + -o build/hello + +run: build/hello + $(PODMAN_RUN) ./build/hello + +clean: + rm -rf build/ diff --git a/PLAN.md b/PLAN.md @@ -0,0 +1,115 @@ +# Alternative bootstrap path: Lisp-in-M1 → C compiler in Lisp → tcc-boot + +## Goal + +Shrink the auditable LOC between M1 assembly and tcc-boot by replacing the +current `M2-Planet → mes → MesCC → nyacc` stack with a small Lisp written +directly in M1 asm and a C compiler written in that Lisp. + +## Current chain (validated counts) + +| Layer | Lang | Lines | +|---|---|---| +| `cc_amd64.M1` (subset-C compiler in M1 asm) | M1 | 5,413 (~3,152 actual instructions) | +| M2-Planet (`*.c`, compiles mes) | C | 8,140 | +| Mes interpreter (`src/*.c`) | C | 7,033 | +| Mes headers (`include/mes/*.h`) | C | 6,145 | +| MesCC + mes Scheme (`module/`) | Scheme | 8,271 | +| Bundled mes runtime (SRFI/ice-9/rnrs shims) | Scheme | 9,191 | +| nyacc (LALR engine + C99 parser/grammar/cpp) | Scheme | ~10,000 (essentials of 12,868) | +| **Total auditable** | mixed | **~54,000** | + +## Proposed chain + +``` +M1 asm → Lisp interpreter (in M1 asm) → C compiler (in Lisp) → tcc-boot +``` + +Two languages, one new interpreter, one new compiler. No M2-Planet, no Mes +core, no MesCC, no nyacc. + +## Asm Lisp — feature floor + +Justification: empirical audit of MesCC's actual Scheme usage. MesCC barely +exercises Scheme. + +**Required:** +- Special forms: `define`, `lambda`, `if`, `cond`, `let`, `let*`, `letrec`, + `quote`, `quasiquote`/`unquote`, `set!`, `begin` +- Data: pairs, fixnums, vectors, immutable ASCII strings, symbols +- Primitives (~40): `cons/car/cdr`, list ops (`map/filter/fold/append/reverse/member/assoc`), + arithmetic (`+ - * / %`), bitwise (`and or xor << >>`), string ops + (`string-append/string-ref/substring/string-length`), type predicates, + `display`/`write`, basic `format` (`~a ~s ~d ~%` only), `apply`, `error` +- Mark-sweep GC over tagged cells +- Built-in `pmatch` macro (otherwise hand-expanding 57 call sites in the + C compiler costs ~1k extra LOC) +- A records-via-vectors layer (replaces SRFI-9 `define-immutable-record-type`) +- File I/O: `read-file path → string` and `write-file path string`. No port + type at all. The C lexer indexes into the source string with an integer + cursor (gives `read-char`/`peek-char` semantics for free); CPP keeps + `#include` context as a stack of (string, cursor) pairs. Codegen + accumulates output as a reversed list of chunks and concatenates once + via a one-pass variadic `string-append` (or a `string-concat list → + string` primitive). Output for tcc-boot is single-digit MB — well within + the existing mes 20MB arena budget. + +**Deliberately omitted:** +- `call/cc`, `dynamic-wind`, `parameterize`, exception system +- Mutable strings, Unicode +- Bignums, rationals, floats +- `syntax-rules` / `define-syntax` (only `pmatch` macro is needed) +- First-class modules (single-file load in dependency order) +- `do` loops, `delay`/`force` + +Tail calls: convenient for AST recursion; not strictly required if stack is +generous (≥1MB). + +## C subset to support + +Start from MesCC's already-reduced subset; consider further reductions if +they justify patching tcc-boot. + +**Must support (used by tcc-boot):** +- Types: `char/short/int/long/long long`, signed/unsigned, pointers, arrays, + structs, unions, enums, **bitfields**, typedefs, `void` +- Storage: `static`, `extern`, `register`; `const`/`volatile` parsed and + ignored +- Operators: full arithmetic/bitwise/relational/logical, compound + assignment, ternary, `sizeof` (types and expressions), casts, comma +- Statements: all loops, switch/case, goto/labels, `&&`/`||` short-circuit +- Function declarations: ANSI only + +**Not supported (and not needed):** +- `float`/`double` (errors at parse time) +- `inline` (parsed and stripped, like MesCC) +- Variadic functions (tcc-boot already works around this) +- K&R declarations +- C99 mid-block declarations +- Statement expressions, nested functions, compound literals, + designated initializers + +**Candidate further reductions (require tcc-boot patches):** +- Drop bitfields (significant tcc-boot rework — probably not worth it) +- Drop compound assignment (modest tcc-boot patches) + +**Preprocessor:** target full `#define`/`#include`/`#if`/`#ifdef`/`#elif`/ +`#else`/`#endif` with function-like macros and stringification. tcc's source +uses these heavily. + +## Backend + +Emit **text M1 assembly** for x86_64. Reuse the existing M1 macro assembler ++ hex2 linker downstream (no change there). Single architecture only. + +## Estimated budget + +| Component | Lines | +|---|---| +| Lisp interpreter in M1 (reader, eval, GC, primitives, I/O, pmatch) | 4,000–6,000 M1 | +| C lexer + recursive-descent parser + CPP (in Lisp) | 2,000–3,000 | +| Type checker + IR (slimmed compile.scm + info.scm) | 2,000–3,000 | +| x86_64 codegen + M1 emit | 800–1,200 | +| **Total** | **~9,000–13,000 LOC** | + +vs. **~54,000 LOC** current = **~4–6× shrink**. diff --git a/README.md b/README.md @@ -0,0 +1,47 @@ +# lispcc + +Experimental alternative bootstrap path: a small Lisp written directly in +M1 assembly + a C compiler written in that Lisp, replacing the +`M2-Planet → mes → MesCC → nyacc` stack between M1 asm and tcc-boot. +Goal is a 4–6× shrink in auditable LOC. See [PLAN.md](PLAN.md). + +## Status + +Stage 0: aarch64 hello-world in hand-written M1, assembled and run inside +a pristine alpine container. Toolchain (M1, hex2) builds statically from +the upstream mescc-tools C source. + +## Layout + +``` +PLAN.md design doc +hello.M1 hand-written aarch64 hello +aarch64_defs.M1 vendored instruction macros (from M2libc) +ELF-aarch64.hex2 vendored ELF header (from M2libc) +Containerfile builder image: alpine + gcc + musl-dev +Makefile podman-driven build +build/ outputs (M1, hex2, hello.hex2, hello) +``` + +## Build & run + +Requires podman with an arm64 Linux machine (e.g. `podman machine init` +on Apple Silicon). + +``` +make image # one-time: build the alpine+gcc builder image +make # build M1/hex2 statically + assemble hello.M1 → build/hello +make run # run build/hello in pristine alpine, prints "Hello, world!" +make clean # wipe build/ +``` + +Two images are used: `lispcc-builder` (alpine+gcc, ~184 MB) only compiles +M1/hex2; `alpine:latest` (~9 MB) runs everything, with the static binaries +mounted in. + +## Source layout assumption + +The Makefile reaches the upstream mescc-tools C source via the parent dir +mount (`HOST_ROOT := $(abspath $(CURDIR)/..)`), expecting +`../live-bootstrap/seed/stage0-posix/mescc-tools/`. Override `TOOLCHAIN_SRC` +in the Makefile if your layout differs. diff --git a/aarch64_defs.M1 b/aarch64_defs.M1 @@ -0,0 +1,229 @@ +## Copyright (C) 2020 deesix <deesix@tuta.io> +## Copyright (C) 2020 Sanne Wouda +## This file is part of M2-Planet. +## +## M2-Planet is free software: you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## M2-Planet is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with M2-Planet. If not, see <http://www.gnu.org/licenses/>. + +DEFINE NULL 0000000000000000 + +# Stack (x18 as SP, 64 bits per element) +DEFINE PUSH_X0 408e1ff8 +DEFINE PUSH_X1 418e1ff8 +DEFINE PUSH_X13 4d8e1ff8 # str x13, [x18,-8]! +DEFINE PUSH_X14 4e8e1ff8 # str x14, [x18,-8]! +DEFINE PUSH_X15 4f8e1ff8 # str x15, [x18,-8]! +DEFINE PUSH_X16 508e1ff8 +DEFINE PUSH_BP 518e1ff8 +DEFINE PUSH_LR 5e8e1ff8 + +DEFINE POP_X0 408640f8 +DEFINE POP_X1 418640f8 +DEFINE POP_X13 4d8640f8 # ldr x13, [x18],8 +DEFINE POP_X14 4e8640f8 # ldr x14, [x18],8 +DEFINE POP_X15 4f8640f8 # ldr x15, [x18],8 +DEFINE POP_X16 508640f8 +DEFINE POP_BP 518640f8 +DEFINE POP_LR 5e8640f8 + +DEFINE INIT_SP f2030091 # mov x18, sp + + +# Jump/branch/call/return +DEFINE BR_X16 00021fd6 +DEFINE BLR_X16 00023fd6 +DEFINE RETURN c0035fd6 + +DEFINE CBZ_X0_PAST_BR a00000b4 +DEFINE CBNZ_X0_PAST_BR a00000b5 + +DEFINE SKIP_INST_EQ 40000054 +DEFINE SKIP_INST_NE 41000054 +DEFINE SKIP_INST_LT 4b000054 +DEFINE SKIP_INST_LE 4d000054 +DEFINE SKIP_INST_GT 4c000054 +DEFINE SKIP_INST_GE 4a000054 + +DEFINE SKIP_INST_LO 43000054 +DEFINE SKIP_INST_LS 49000054 +DEFINE SKIP_INST_HS 42000054 +DEFINE SKIP_INST_HI 48000054 + +DEFINE SKIP_32_DATA 02000014 + + +# Load literals (PC-relative) +DEFINE LOAD_W0_AHEAD 40000098 +DEFINE LOAD_W1_AHEAD 41000018 +DEFINE LOAD_W2_AHEAD 42000018 +DEFINE LOAD_W13_AHEAD 4d000018 ; ldr w13, 8 +DEFINE LOAD_W14_AHEAD 4e000018 ; ldr w14, 8 +DEFINE LOAD_W15_AHEAD 4f000018 ; ldr w15, 8 +DEFINE LOAD_W16_AHEAD 50000018 + + +# Load/store/dereference +DEFINE LDR_X0_[SP] 400240f9 +DEFINE STR_X0_[X1] 200000f9 +DEFINE STR_W0_[X1] 200000B9 +DEFINE STRH_W0_[X1] 20000079 +DEFINE STR_BYTE_W0_[X1] 20000039 +DEFINE DEREF_X0 000040f9 +DEFINE DEREF_X1 210040f9 +DEFINE LDRH_W0_[X0] 00004079 +DEFINE LDRSB_X0_[X0] 00008039 +DEFINE LDRSH_X0_[X0] 00008079 +DEFINE LDR_W0_[X0] 000040B9 +DEFINE DEREF_X0_BYTE 00004039 +DEFINE DEREF_X1_BYTE 21004039 + + +# Move data between registers +DEFINE SET_X0_FROM_BP e00311aa +DEFINE SET_X0_FROM_X13 e0030daa # mov x0, x13 +DEFINE SET_X0_FROM_X14 e0030eaa # mov x0, x14 +DEFINE SET_X0_FROM_X15 e0030faa # mov x0, x15 +DEFINE SET_X0_FROM_X16 e00310aa # mov x0, x16 +DEFINE SET_X1_FROM_X0 e10300aa +DEFINE SET_X1_FROM_X13 e1030daa # mov x1, x13 +DEFINE SET_X1_FROM_X14 e1030eaa # mov x1, x14 +DEFINE SET_X1_FROM_X15 e1030faa # mov x1, x15 +DEFINE SET_X1_FROM_X16 e10310aa # mov x1, x16 +DEFINE SET_X1_FROM_SP e10312aa +DEFINE SET_X2_FROM_X0 e20300aa +DEFINE SET_X2_FROM_X1 e20301aa +DEFINE SET_X13_FROM_SP ed0312aa # mov x13, x18 +DEFINE SET_X14_FROM_X0 ee0300aa # mov x14, x0 +DEFINE SET_X15_FROM_X0 ef0300aa # mov x15, x0 +DEFINE SET_X3_FROM_X0 e30300aa +DEFINE SET_X3_FROM_X1 e30301aa +DEFINE SET_X3_FROM_X2 e30302aa +DEFINE SET_X4_FROM_X0 e40300aa +DEFINE SET_X5_FROM_X0 e50300aa +DEFINE SET_X6_FROM_X0 e60300aa +DEFINE SET_X16_FROM_X0 f00300aa +DEFINE SET_X16_FROM_SP f00312aa +DEFINE SET_BP_FROM_X16 f10310aa +DEFINE SET_BP_FROM_SP f10312aa +DEFINE SET_SP_FROM_X13 f2030daa # mov x18, x13 +DEFINE SET_SP_FROM_BP f20311aa # mov x18, x17 + + +# Move constant to register +DEFINE SET_X0_TO_0 000080d2 +DEFINE SET_X0_TO_1 200080d2 +DEFINE SET_X0_TO_17 200280d2 +DEFINE SET_X0_TO_MINUS_1 00008092 +DEFINE SET_W0_TO_MINUS_1 00008012 +DEFINE SET_X1_TO_0 010080d2 +DEFINE SET_X1_TO_2 410080d2 +DEFINE SET_X1_TO_8 010180d2 +DEFINE SET_X2_TO_0 020080d2 +DEFINE SET_X2_TO_1 220080d2 +DEFINE SET_X0_TO_FCNTL_H_AT_FDCWD 600c8092 +DEFINE SET_X1_TO_FCNTL_H_AT_FDCWD 610c8092 + + +# Arith/logic/relational +DEFINE ADD_X0_X1_X0 2000008b +DEFINE ADD_X0_X14_X0 c001008b ; add x0, x14, x0 +DEFINE ADD_X0_X15_X0 e001008b ; add x0, x15, x0 +DEFINE ADD_X0_X16_X0 0020008b ; add x0, x16, x0 +DEFINE ADD_X0_BP_X0 2002008b +DEFINE ADD_X1_SP_8 41220091 +DEFINE ADD_X1_X14_X1 c101018b ; add x1, x14, x1 +DEFINE ADD_X1_X15_X1 e101018b ; add x1, x15, x1 +DEFINE ADD_X1_X16_X1 0102018b ; add x1, x16, x1 +DEFINE ADD_SP_X14_SP d201128b ; add x18, x14, x18 +DEFINE ADD_SP_X15_SP f201128b ; add x18, x15, x18 +DEFINE ADD_SP_X16_SP 1201128b ; add x18, x16, x18 + +DEFINE SUB_X0_X1_X0 200000cb +DEFINE SUB_X0_X14_X0 c00100cb ; sub x0, x14, x0 +DEFINE SUB_X0_X15_X0 e00100cb ; sub x0, x15, x0 +DEFINE SUB_X0_X16_X0 000200cb ; sub x0, x16, x0 +DEFINE SUB_X0_X0_X14 00000ecb ; sub x0, x0, x14 +DEFINE SUB_X0_X0_X15 00000fcb ; sub x0, x0, x15 +DEFINE SUB_X0_X0_X16 000010cb ; sub x0, x0, x16 +DEFINE SUB_X0_X0_X1 000001cb +DEFINE SUB_X1_X1_X14 21000ecb ; sub x1, x1, x14 +DEFINE SUB_X1_X1_X15 21000fcb ; sub x1, x1, x15 +DEFINE SUB_X1_X1_X16 210010cb ; sub x1, x1, x16 +DEFINE SUB_X1_X14_X1 c10101cb ; sub x1, x14, x1 +DEFINE SUB_X1_X15_X1 e10101cb ; sub x1, x15, x1 +DEFINE SUB_X1_X16_X1 010201cb ; sub x1, x16, x1 +DEFINE SUB_SP_X1_SP 320012cb +DEFINE SUB_SP_X14_SP d20112cb ; sub x18, x14, x18 +DEFINE SUB_SP_X15_SP f20112cb ; sub x18, x15, x18 +DEFINE SUB_SP_X16_SP 120112cb ; sub x18, x16, x18 +DEFINE SUB_SP_SP_X14 52020ecb ; sub x18, x18, x14 +DEFINE SUB_SP_SP_X15 52020fcb ; sub x18, x18, x15 +DEFINE SUB_SP_SP_X16 520210cb ; sub x18, x18, x16 +DEFINE SUB_X0_8 002000d1 +DEFINE SUB_X0_16 004000d1 +DEFINE SUB_X0_24 006000d1 +DEFINE SUB_X0_32 008000d1 +DEFINE SUB_X0_40 00A000d1 +DEFINE MSUB_X0_X0_X2_X1 0084029b + +DEFINE MUL_X0_X1_X0 207c009b +DEFINE MUL_X0_X14_X0 c07d009b +DEFINE MUL_X0_X15_X0 e07d009b +DEFINE MUL_X0_X16_X0 007e009b +DEFINE SDIV_X0_X1_X0 200cc09a +DEFINE SDIV_X2_X1_X0 220cc09a +DEFINE UDIV_X0_X1_X0 2008c09a +DEFINE UDIV_X2_X1_X0 2208c09a + +DEFINE LSHIFT_X0_X0_X2 0020c29a +DEFINE LSHIFT_X0_X1_X0 2020c09a +DEFINE LOGICAL_RSHIFT_X0_X1_X0 2024c09a +DEFINE ARITH_RSHIFT_X0_X1_X0 2028c09a + +DEFINE MVN_X0 e00320aa +DEFINE AND_X0_X1_X0 2000008a +DEFINE OR_X0_X1_X0 200000aa +DEFINE XOR_X0_X1_X0 000001ca + +DEFINE CMP_X1_X0 3f0000eb + + +# Syscall +DEFINE SET_X8_TO_SYS_BRK c81a80d2 +DEFINE SET_X8_TO_SYS_CHDIR 280680d2 +DEFINE SET_X8_TO_SYS_CLONE 881b80d2 +DEFINE SET_X8_TO_SYS_CLOSE 280780d2 +DEFINE SET_X8_TO_SYS_EXECVE a81b80d2 +DEFINE SET_X8_TO_SYS_EXIT a80b80d2 +DEFINE SET_X8_TO_SYS_FACCESSAT 080680d2 +DEFINE SET_X8_TO_SYS_FCHDIR 480680d2 +DEFINE SET_X8_TO_SYS_FCHMOD 880680d2 +DEFINE SET_X8_TO_SYS_FCHMODAT a80680d2 +DEFINE SET_X8_TO_SYS_GETCWD 280280d2 +DEFINE SET_X8_TO_SYS_LSEEK c80780d2 +DEFINE SET_X8_TO_SYS_MKDIRAT 480480d2 +DEFINE SET_X8_TO_SYS_MKNODAT 280480d2 +DEFINE SET_X8_TO_SYS_OPENAT 080780d2 +DEFINE SET_X8_TO_SYS_READ e80780d2 +DEFINE SET_X8_TO_SYS_UNAME 081480d2 +DEFINE SET_X8_TO_SYS_WAIT4 882080d2 +DEFINE SET_X8_TO_SYS_WRITE 080880d2 +DEFINE SET_X8_TO_SYS_UNLINKAT 680480d2 +DEFINE SET_X8_TO_SYS_SYMLINKAT 880480d2 +DEFINE SET_X8_TO_SYS_UMASK c81480d2 +DEFINE SET_X8_TO_SYS_UNSHARE 280c80d2 +DEFINE SET_X8_TO_SYS_GETEUID e81580d2 +DEFINE SET_X8_TO_SYS_GETEGID 081680d2 +DEFINE SET_X8_TO_SYS_CHROOT 680680d2 +DEFINE SET_X8_TO_SYS_MOUNT 080580d2 +DEFINE SYSCALL 010000d4 diff --git a/hello.M1 b/hello.M1 @@ -0,0 +1,27 @@ +## aarch64 Linux hello world in M1 + +:_start + ;; write(1, msg, 14) + SET_X0_TO_1 ; x0 = 1 (stdout) + + LOAD_W1_AHEAD ; ldr w1, [pc+8] + SKIP_32_DATA ; b +8 (over inline data) + &msg ; <-- 4-byte msg address loaded into w1/x1 + + LOAD_W2_AHEAD ; ldr w2, [pc+8] + SKIP_32_DATA + '0E000000' ; <-- length 14, little-endian, loaded into w2/x2 + + SET_X8_TO_SYS_WRITE ; x8 = 64 + SYSCALL ; svc 0 + + ;; exit(0) + SET_X0_TO_0 ; x0 = 0 + SET_X8_TO_SYS_EXIT ; x8 = 93 + SYSCALL ; svc 0 + +:msg +"Hello, world! +" + +:ELF_end