afs-as
(noun): a barrel of shifted registers
Standalone ARM64 assembler for macOS. Reads .s assembly text, encodes ARM64 instructions, and emits Mach-O object files linkable with Apple's ld.
Part of ARMFORTAS, a bespoke ARM64 Fortran compiler.
Usage
# Assemble
afs-as hello.s -o hello.o
# Or let afs-as derive hello.o automatically
afs-as hello.s
# Assemble from stdin to stdout
cat hello.s | afs-as - -o - > hello.o
# Inspect CLI help
afs-as --help
# Link and run
ld hello.o -o hello -lSystem -syslibroot $(xcrun --show-sdk-path) -e _main
./hello
CLI behavior is intentionally small and explicit:
--helpand--versionprint to stdout and exit0- usage errors exit
2 - parse / assembly failures exit
1with file, line, column, source line, and caret diagnostics --stops option parsing-can be used for stdin input or stdout output- stdin input requires explicit
-o <output.o>or-o -
Standalone Support Matrix
The public standalone surface is intentionally small and explicit.
CLI:
- one input file
- default
.oderivation from the input path --stops option parsing-may be used for stdin input or stdout output- stdin requires explicit
-o <path>or-o - - usage errors exit
2; parse or assembly failures exit1
Supported section surface:
__TEXT,__text__TEXT,__cstring__TEXT,__literal16__TEXT,__const__DATA,__data__DATA,__thread_data__DATA,__thread_vars__DATA,__thread_bss__DATA,__bss
Supported directive families include:
- symbol directives:
.global/.globl,.extern,.private_extern,.weak_reference,.weak_definition,.set,.equ - data/layout directives:
.byte,.short,.word,.long,.quad,.ascii,.asciz,.string,.space,.skip,.zero,.fill,.align,.p2align,.comm,.zerofill,.tbss - section-selection directives:
.text,.data,.cstring, and.sectionfor the supported section set - metadata directives:
.subsections_via_symbols,.build_versionformacos - linker-optimization hints:
.loh AdrpAdd,.loh AdrpLdr,.loh AdrpLdrGot,.loh AdrpLdrGotLdr - CFI subset:
.cfi_startproc,.cfi_endproc,.cfi_def_cfa,.cfi_def_cfa_offset,.cfi_def_cfa_register,.cfi_offset,.cfi_restore,.cfi_adjust_cfa_offset
Unsupported forms are expected to fail explicitly rather than assemble silently.
Release gates for a standalone claim:
cargo test -p afs-ascargo clippy -p afs-as --all-targets -- -D warnings- green differential, corpus, CLI, diagnostic, dashboard, stress, fuzz, malformed-input, and perf suites in CI
Library API
use afs_as::assemble;
use afs_as::encode::Inst;
use afs_as::reg::*;
// From source text
let obj = assemble::assemble_source(".global _main\n_main:\nret\n").unwrap();
// From pre-built instructions (no parsing)
let obj = assemble::assemble_instructions(
&[Inst::Ret { rn: X30 }],
&["_main"],
);
assemble_instructions is the compiler-facing fast path. It assumes callers build valid
Inst values; source-level validation and diagnostics live in assemble_source. Passing an
Inst that fails encoder preconditions (for example, a logical-immediate AndImm with an
unencodable bit pattern) will panic rather than return an error — the contract is that
the compiler is responsible for emitting only valid instructions on this path.
Tests
afs-as is validated through layered coverage rather than a single golden path:
- unit tests for parsing, encoding, expression classification, Mach-O writing, and diagnostics
- differential tests against Apple
as - raw-object parity corpus tests
- linker / runtime end-to-end tests
- CLI smoke tests for user-facing behavior
cargo test -p afs-as
Building
cargo build -p afs-as # build
cargo test -p afs-as # test
cargo clippy -p afs-as # lint
Requires macOS on ARM64 (Apple Silicon) for integration tests that invoke the system assembler and linker.
License
GPL-3.0
View source
| 1 | # afs-as |
| 2 | |
| 3 | *(noun): a barrel of shifted registers* |
| 4 | |
| 5 | Standalone ARM64 assembler for macOS. Reads `.s` assembly text, encodes ARM64 instructions, and emits Mach-O object files linkable with Apple's `ld`. |
| 6 | |
| 7 | Part of [ARMFORTAS](https://github.com/FortranGoingOnForty/armfortas), a bespoke ARM64 Fortran compiler. |
| 8 | |
| 9 | ## Usage |
| 10 | |
| 11 | ```bash |
| 12 | # Assemble |
| 13 | afs-as hello.s -o hello.o |
| 14 | |
| 15 | # Or let afs-as derive hello.o automatically |
| 16 | afs-as hello.s |
| 17 | |
| 18 | # Assemble from stdin to stdout |
| 19 | cat hello.s | afs-as - -o - > hello.o |
| 20 | |
| 21 | # Inspect CLI help |
| 22 | afs-as --help |
| 23 | |
| 24 | # Link and run |
| 25 | ld hello.o -o hello -lSystem -syslibroot $(xcrun --show-sdk-path) -e _main |
| 26 | ./hello |
| 27 | ``` |
| 28 | |
| 29 | CLI behavior is intentionally small and explicit: |
| 30 | |
| 31 | - `--help` and `--version` print to stdout and exit `0` |
| 32 | - usage errors exit `2` |
| 33 | - parse / assembly failures exit `1` with file, line, column, source line, and caret diagnostics |
| 34 | - `--` stops option parsing |
| 35 | - `-` can be used for stdin input or stdout output |
| 36 | - stdin input requires explicit `-o <output.o>` or `-o -` |
| 37 | |
| 38 | ## Standalone Support Matrix |
| 39 | |
| 40 | The public standalone surface is intentionally small and explicit. |
| 41 | |
| 42 | CLI: |
| 43 | |
| 44 | - one input file |
| 45 | - default `.o` derivation from the input path |
| 46 | - `--` stops option parsing |
| 47 | - `-` may be used for stdin input or stdout output |
| 48 | - stdin requires explicit `-o <path>` or `-o -` |
| 49 | - usage errors exit `2`; parse or assembly failures exit `1` |
| 50 | |
| 51 | Supported section surface: |
| 52 | |
| 53 | - `__TEXT,__text` |
| 54 | - `__TEXT,__cstring` |
| 55 | - `__TEXT,__literal16` |
| 56 | - `__TEXT,__const` |
| 57 | - `__DATA,__data` |
| 58 | - `__DATA,__thread_data` |
| 59 | - `__DATA,__thread_vars` |
| 60 | - `__DATA,__thread_bss` |
| 61 | - `__DATA,__bss` |
| 62 | |
| 63 | Supported directive families include: |
| 64 | |
| 65 | - symbol directives: `.global` / `.globl`, `.extern`, `.private_extern`, `.weak_reference`, `.weak_definition`, `.set`, `.equ` |
| 66 | - data/layout directives: `.byte`, `.short`, `.word`, `.long`, `.quad`, `.ascii`, `.asciz`, `.string`, `.space`, `.skip`, `.zero`, `.fill`, `.align`, `.p2align`, `.comm`, `.zerofill`, `.tbss` |
| 67 | - section-selection directives: `.text`, `.data`, `.cstring`, and `.section` for the supported section set |
| 68 | - metadata directives: `.subsections_via_symbols`, `.build_version` for `macos` |
| 69 | - linker-optimization hints: `.loh AdrpAdd`, `.loh AdrpLdr`, `.loh AdrpLdrGot`, `.loh AdrpLdrGotLdr` |
| 70 | - CFI subset: `.cfi_startproc`, `.cfi_endproc`, `.cfi_def_cfa`, `.cfi_def_cfa_offset`, `.cfi_def_cfa_register`, `.cfi_offset`, `.cfi_restore`, `.cfi_adjust_cfa_offset` |
| 71 | |
| 72 | Unsupported forms are expected to fail explicitly rather than assemble silently. |
| 73 | |
| 74 | Release gates for a standalone claim: |
| 75 | |
| 76 | - `cargo test -p afs-as` |
| 77 | - `cargo clippy -p afs-as --all-targets -- -D warnings` |
| 78 | - green differential, corpus, CLI, diagnostic, dashboard, stress, fuzz, malformed-input, and perf suites in CI |
| 79 | |
| 80 | ## Library API |
| 81 | |
| 82 | ```rust |
| 83 | use afs_as::assemble; |
| 84 | use afs_as::encode::Inst; |
| 85 | use afs_as::reg::*; |
| 86 | |
| 87 | // From source text |
| 88 | let obj = assemble::assemble_source(".global _main\n_main:\nret\n").unwrap(); |
| 89 | |
| 90 | // From pre-built instructions (no parsing) |
| 91 | let obj = assemble::assemble_instructions( |
| 92 | &[Inst::Ret { rn: X30 }], |
| 93 | &["_main"], |
| 94 | ); |
| 95 | ``` |
| 96 | |
| 97 | `assemble_instructions` is the compiler-facing fast path. It assumes callers build valid |
| 98 | `Inst` values; source-level validation and diagnostics live in `assemble_source`. Passing an |
| 99 | `Inst` that fails encoder preconditions (for example, a logical-immediate `AndImm` with an |
| 100 | unencodable bit pattern) will **panic** rather than return an error — the contract is that |
| 101 | the compiler is responsible for emitting only valid instructions on this path. |
| 102 | |
| 103 | ## Tests |
| 104 | |
| 105 | `afs-as` is validated through layered coverage rather than a single golden path: |
| 106 | |
| 107 | - unit tests for parsing, encoding, expression classification, Mach-O writing, and diagnostics |
| 108 | - differential tests against Apple `as` |
| 109 | - raw-object parity corpus tests |
| 110 | - linker / runtime end-to-end tests |
| 111 | - CLI smoke tests for user-facing behavior |
| 112 | |
| 113 | ```bash |
| 114 | cargo test -p afs-as |
| 115 | ``` |
| 116 | |
| 117 | ## Building |
| 118 | |
| 119 | ```bash |
| 120 | cargo build -p afs-as # build |
| 121 | cargo test -p afs-as # test |
| 122 | cargo clippy -p afs-as # lint |
| 123 | ``` |
| 124 | |
| 125 | Requires macOS on ARM64 (Apple Silicon) for integration tests that invoke the system assembler and linker. |
| 126 | |
| 127 | ## License |
| 128 | |
| 129 | GPL-3.0 |