Skip to content

Instantly share code, notes, and snippets.

@segin
Created March 1, 2026 21:19
Show Gist options
  • Select an option

  • Save segin/ac2fdb1f72ef56e5e7bee0218a6df6f6 to your computer and use it in GitHub Desktop.

Select an option

Save segin/ac2fdb1f72ef56e5e7bee0218a6df6f6 to your computer and use it in GitHub Desktop.

Substrate Assembler (as) — Specification

1. Purpose

The Substrate assembler (as) is a standalone, multi-architecture assembler that translates assembly language source files into relocatable ELF object files. It replaces the current GCC/GAS wrapper with a native implementation that has no external toolchain dependencies at runtime.

2. Scope

Attribute Value
Binary name as
Install path /usr/bin/as
Input Assembly source (.s, .S), AT&T or Intel syntax
Output ELF relocatable objects (.o), ET_REL
Architectures i386, x86-64 (v1–v4), ARMv7 (AArch32), AArch64 (v8.0–8.1)
Library deps libelfobj (ELF generation)
Host build NATIVE_BUILD=1 for development/test on Linux/BSD host

3. Definitions

Term Definition
EARS Easy Approach to Requirements Syntax (ISO/IEC/IEEE 29148 compatible)
Mnemonic Textual instruction name (e.g., MOV, ADD, LDR)
Directive Assembler pseudo-instruction (e.g., .byte, .section, .globl)
Relaxation Automatic promotion of short encoding to long encoding when target is out of range
Mapping symbol ARM ELF convention: $a (ARM code), $t (Thumb code), $d (data)
ISA level x86-64 psABI microarchitecture feature level (v1 baseline, v2–v4 extensions)

4. Functional Requirements

4.1 Input Processing

REQ-AS-010 (Ubiquitous) The assembler shall accept one or more assembly source files as positional arguments.

REQ-AS-011 (Ubiquitous) The assembler shall read source input as a stream of lines delimited by newline characters (\n).

REQ-AS-012 (Event-driven) When the -I dir option is specified, the assembler shall add dir to the include search path for .include directives.

REQ-AS-013 (Event-driven) When the input filename is -, the assembler shall read source from standard input.

REQ-AS-014 (Ubiquitous) The assembler shall support UTF-8 encoding in string literals and comments.

4.2 Lexical Analysis

REQ-AS-020 (Ubiquitous) The assembler shall tokenize input into mnemonics, register names, immediate values, labels, directives, operators, and string literals.

REQ-AS-021 (Ubiquitous) The assembler shall recognize integer literals in decimal, hexadecimal (0x prefix), octal (0 prefix), and binary (0b prefix) notation.

REQ-AS-022 (Ubiquitous) The assembler shall treat # and // as single-line comment initiators and /* ... */ as block comment delimiters.

REQ-AS-023 (Ubiquitous) The assembler shall recognize ; as an instruction separator on architectures where this is conventional.

REQ-AS-024 (Event-driven) When a line ends with \, the assembler shall treat the following line as a continuation of the current logical line.

REQ-AS-025 (Ubiquitous) The assembler shall recognize character literals in the form 'c' as integer immediates equal to the ASCII value of c.

4.3 Parsing

REQ-AS-030 (Ubiquitous) The assembler shall parse each logical line as one of: a label definition, a directive, an instruction, or a blank/comment-only line.

REQ-AS-031 (Ubiquitous) The assembler shall accept labels ending with : at the start of a line, optionally followed by an instruction or directive on the same line.

REQ-AS-032 (Ubiquitous) The assembler shall support local numeric labels (0:9:) with forward (Nf) and backward (Nb) references.

REQ-AS-033 (Ubiquitous) The assembler shall evaluate constant expressions containing +, -, *, /, %, |, &, ^, ~, <<, >>, and unary -.

REQ-AS-034 (Ubiquitous) The assembler shall resolve symbol references within expressions, deferring unresolved references to relocation emission.

REQ-AS-035 (Event-driven) When -msyntax=intel is specified for an x86 target, the assembler shall parse instructions in Intel syntax (destination-first, no % register prefix, no $ immediate prefix).

REQ-AS-036 (Ubiquitous) The assembler shall, by default, parse x86 instructions in AT&T syntax (source-first, % register prefix, $ immediate prefix).

4.4 Directives

REQ-AS-040 (Ubiquitous) The assembler shall implement the following data directives: .byte, .short/.hword, .long/.int, .quad/.8byte, .float, .double, .ascii, .asciz/.string, .zero/.space, .fill, .skip, .org, .incbin.

REQ-AS-041 (Ubiquitous) The assembler shall implement the following section directives: .text, .data, .bss, .rodata, .section, .pushsection, .popsection, .previous, .subsection.

REQ-AS-042 (Ubiquitous) The assembler shall implement the following symbol directives: .globl/.global, .local, .weak, .comm, .lcomm, .type, .size, .hidden, .protected, .internal, .symver.

REQ-AS-043 (Ubiquitous) The assembler shall implement the following alignment directives: .align, .balign, .p2align.

REQ-AS-044 (Ubiquitous) The assembler shall implement the following conditional directives: .if, .ifdef, .ifndef, .else, .elseif, .endif.

REQ-AS-045 (Ubiquitous) The assembler shall implement the following macro directives: .macro/.endm, .rept/.endr, .irp/.irpc.

REQ-AS-046 (Ubiquitous) The assembler shall implement the following debug directives: .file, .loc, .cfi_startproc, .cfi_endproc, .cfi_def_cfa, .cfi_def_cfa_offset, .cfi_def_cfa_register, .cfi_offset, .cfi_restore, .cfi_remember_state, .cfi_restore_state, .cfi_adjust_cfa_offset, .cfi_rel_offset, .cfi_register, .cfi_undefined, .cfi_same_value, .cfi_escape, .cfi_personality, .cfi_lsda, .cfi_return_column, .cfi_signal_frame.

REQ-AS-047 (Ubiquitous) The assembler shall implement .group for COMDAT section groups.

REQ-AS-048 (Event-driven) When the .include "file" directive is encountered, the assembler shall insert the contents of the named file at the current position, searching -I paths.

4.5 Architecture Selection

REQ-AS-050 (Ubiquitous) The assembler shall determine the target architecture from the -march option or the --32/--64 flags.

REQ-AS-051 (Event-driven) When --32 is specified, the assembler shall target i386 (ELF32, EM_386).

REQ-AS-052 (Event-driven) When --64 is specified, the assembler shall target x86-64 (ELF64, EM_X86_64).

REQ-AS-053 (Event-driven) When -march=armv7-a or similar ARMv7 variant is specified, the assembler shall target ARMv7 (ELF32, EM_ARM).

REQ-AS-054 (Event-driven) When -march=armv8-a or similar AArch64 variant is specified, the assembler shall target AArch64 (ELF64, EM_AARCH64).

REQ-AS-055 (Event-driven) When -march=x86-64-v2, -march=x86-64-v3, or -march=x86-64-v4 is specified, the assembler shall accept all instructions defined by that ISA level and all lower levels.

REQ-AS-056 (Unwanted behavior) If an instruction requires an ISA level higher than the selected -march, then the assembler shall emit a diagnostic error identifying the instruction, the required level, and the current level.

REQ-AS-057 (State-driven) While targeting an ARM architecture, the assembler shall accept .arm, .thumb, and .thumb_func directives to switch instruction encoding mode.

4.6 x86 Instruction Encoding

REQ-AS-060 (Ubiquitous) The assembler shall encode all i386 base ISA instructions using legacy prefix + opcode + ModR/M + SIB + displacement format.

REQ-AS-061 (State-driven) While targeting x86-64, the assembler shall emit REX prefixes for 64-bit operands, extended registers (R8–R15), and RIP-relative addressing.

REQ-AS-062 (State-driven) While targeting x86-64-v3 or higher, the assembler shall emit 2-byte or 3-byte VEX prefixes for AVX, AVX2, BMI, FMA, and F16C instructions.

REQ-AS-063 (State-driven) While targeting x86-64-v4, the assembler shall emit 4-byte EVEX prefixes for AVX-512 instructions, including opmask register encoding, zeroing-masking, embedded broadcast, and static rounding mode.

REQ-AS-064 (Ubiquitous) The assembler shall select the shortest valid encoding for each instruction (e.g., prefer 2-byte VEX over 3-byte VEX when possible).

REQ-AS-065 (Unwanted behavior) If an immediate value or displacement exceeds the encoding width of the instruction format, then the assembler shall emit a diagnostic error.

4.7 ARM Instruction Encoding

REQ-AS-070 (State-driven) While in ARM state (.arm), the assembler shall emit 32-bit ARM instruction encodings with condition code fields.

REQ-AS-071 (State-driven) While in Thumb state (.thumb), the assembler shall emit 16-bit narrow Thumb or 32-bit wide Thumb-2 encodings, selecting the narrowest valid encoding by default.

REQ-AS-072 (Event-driven) When a .w suffix is present on a Thumb instruction, the assembler shall force the wide (32-bit) encoding.

REQ-AS-073 (Event-driven) When a .n suffix is present on a Thumb instruction, the assembler shall force the narrow (16-bit) encoding or emit an error if the narrow form is not available.

REQ-AS-074 (Ubiquitous) The assembler shall encode barrel shifter operands (LSL, LSR, ASR, ROR, RRX) with both immediate and register shift amounts.

REQ-AS-075 (Ubiquitous) The assembler shall encode IT blocks for Thumb-2 with up to four conditionally-executed instructions.

REQ-AS-076 (Ubiquitous) The assembler shall encode all VFPv3/v4 floating-point and NEON Advanced SIMD instructions with correct coprocessor and element size fields.

4.8 AArch64 Instruction Encoding

REQ-AS-080 (Ubiquitous) The assembler shall emit fixed-width 32-bit A64 instruction encodings for all AArch64 instructions.

REQ-AS-081 (Ubiquitous) The assembler shall encode logical immediates using the AArch64 bitmask immediate format (N:immr:imms fields).

REQ-AS-082 (Unwanted behavior) If a logical immediate value cannot be represented in the AArch64 bitmask format, then the assembler shall emit a diagnostic error.

REQ-AS-083 (Ubiquitous) The assembler shall encode ARMv8.1 LSE atomic instructions (LDADD, LDCLR, LDEOR, LDSET, SWP, CAS, CASP and all ordering/size variants).

REQ-AS-084 (Ubiquitous) The assembler shall encode ARMv8.1 RDMA instructions (SQRDMLAH, SQRDMLSH).

4.9 Relaxation

REQ-AS-090 (Event-driven) When a branch target is not resolvable in the first pass, the assembler shall assume the shortest encoding and re-evaluate in subsequent passes.

REQ-AS-091 (Event-driven) When an x86 jmp rel8 or jcc rel8 target is out of ±127 byte range, the assembler shall promote the encoding to jmp rel32 or jcc rel32.

REQ-AS-092 (Event-driven) When an ARM B/BL target is out of ±32MB range, the assembler shall emit a diagnostic error (no veneer insertion at assembler level).

REQ-AS-093 (Event-driven) When a Thumb B.W/BL target is out of ±16MB range, the assembler shall emit a diagnostic error.

REQ-AS-094 (Ubiquitous) The assembler shall iterate relaxation passes until all instruction sizes stabilize or a maximum iteration count is reached.

REQ-AS-095 (Unwanted behavior) If relaxation does not converge within 100 iterations, then the assembler shall emit a diagnostic error and abort.

4.10 ELF Output

REQ-AS-100 (Ubiquitous) The assembler shall produce ET_REL ELF object files via libelfobj.

REQ-AS-101 (Ubiquitous) The assembler shall emit ELF32 for i386 and ARMv7 targets, and ELF64 for x86-64 and AArch64 targets.

REQ-AS-102 (Ubiquitous) The assembler shall emit .symtab, .strtab, and .shstrtab sections in every output.

REQ-AS-103 (State-driven) While targeting i386 or ARMv7, the assembler shall emit REL-format relocations (addend encoded in instruction).

REQ-AS-104 (State-driven) While targeting x86-64 or AArch64, the assembler shall emit RELA-format relocations (explicit addend field).

REQ-AS-105 (Event-driven) When the source contains .cfi_* directives, the assembler shall emit .eh_frame and optionally .eh_frame_hdr sections with correct CIE/FDE records.

REQ-AS-106 (Event-driven) When the source contains .file and .loc directives, the assembler shall emit .debug_line DWARF sections.

REQ-AS-107 (Event-driven) When targeting x86-64-v2 or higher, the assembler shall emit a .note.gnu.property section with GNU_PROPERTY_X86_ISA_1_NEEDED marking the highest ISA level used.

REQ-AS-108 (Ubiquitous) The assembler shall emit a .note.GNU-stack section to indicate non-executable stack by default.

REQ-AS-109 (State-driven) While targeting ARMv7, the assembler shall set e_flags with EF_ARM_ABI_VER5 and the appropriate float ABI flag.

REQ-AS-110 (State-driven) While targeting ARMv7, the assembler shall emit ARM mapping symbols ($a, $t, $d) at ARM/Thumb/data transitions.

REQ-AS-111 (State-driven) While targeting AArch64, the assembler shall emit mapping symbols ($x, $d) at code/data transitions.

4.11 Diagnostics

REQ-AS-120 (Ubiquitous) The assembler shall format error diagnostics as filename:line: error: message.

REQ-AS-121 (Ubiquitous) The assembler shall format warning diagnostics as filename:line: warning: message.

REQ-AS-122 (Event-driven) When --fatal-warnings is specified, the assembler shall treat all warnings as errors.

REQ-AS-123 (Event-driven) When --no-warn is specified, the assembler shall suppress all warning diagnostics.

REQ-AS-124 (Ubiquitous) The assembler shall exit with code 0 on success, code 1 on any error.

REQ-AS-125 (Unwanted behavior) If the output file cannot be written (permission denied, disk full), then the assembler shall emit a diagnostic error and exit with code 1 without leaving a partial output file.

REQ-AS-126 (Ubiquitous) The assembler shall report the total number of errors and warnings at the end of assembly if any were emitted.

4.12 CLI Interface

REQ-AS-130 (Ubiquitous) The assembler shall accept -o output.o to specify the output file path (default: a.out).

REQ-AS-131 (Ubiquitous) The assembler shall accept -march=ARCH to select the target architecture and ISA level.

REQ-AS-132 (Ubiquitous) The assembler shall accept -g to include debugging information in the output.

REQ-AS-133 (Ubiquitous) The assembler shall accept -al to produce an assembly listing to standard output.

REQ-AS-134 (Ubiquitous) The assembler shall accept --defsym sym=value to pre-define a symbol with the given integer value.

REQ-AS-135 (Ubiquitous) The assembler shall accept -D sym=value to pre-define a symbol for conditional assembly.

REQ-AS-136 (Ubiquitous) The assembler shall accept --statistics to print memory usage and timing information to standard error.

REQ-AS-137 (Ubiquitous) The assembler shall accept -W/--warn and --no-warn to control warning output.

REQ-AS-138 (Ubiquitous) The assembler shall accept -v/--version to print the assembler version and exit.

REQ-AS-139 (Ubiquitous) The assembler shall accept --help and --target-help to print usage and per-architecture help respectively.


5. Non-Functional Requirements

REQ-AS-200 (Ubiquitous) The assembler shall produce deterministic output: identical source with identical options shall produce byte-identical object files.

REQ-AS-201 (Ubiquitous) The assembler shall not depend on any external assembler, compiler, or linker at runtime.

REQ-AS-202 (Ubiquitous) The assembler shall not invoke any child processes during assembly.

REQ-AS-203 (Ubiquitous) The assembler shall handle source files of at least 10 million lines without crashing.

REQ-AS-204 (Ubiquitous) The assembler shall handle symbol tables of at least 1 million symbols without crashing.

REQ-AS-205 (Ubiquitous) The assembler shall exit cleanly on out-of-memory conditions with a diagnostic message.

REQ-AS-206 (Ubiquitous) The assembler shall produce output parseable by the Substrate linker (ld), GNU ld, and LLVM lld.

REQ-AS-207 (Ubiquitous) The assembler shall be buildable as a host tool (NATIVE_BUILD=1) on Linux and as a Substrate native binary.

REQ-AS-208 (Ubiquitous) The assembler shall not execute arbitrary code from the source input at assembly time.

REQ-AS-209 (Ubiquitous) The assembler shall be crash-free on any input, including malformed, truncated, or adversarial source files.


6. User Stories

US-01: Kernel Developer Assembling Boot Code

As a kernel developer, I want to assemble i386 boot code written in AT&T syntax so that I can produce object files linkable with my kernel build.

REQ-US-01-A (Event-driven) When the user invokes as --32 -o boot.o boot.S, the assembler shall produce an ELF32 EM_386 relocatable object.

REQ-US-01-B (Ubiquitous) The assembler shall encode all i386 instructions including privileged instructions (LGDT, LIDT, MOV CR0, WRMSR, HLT, CLI, STI, INVLPG).

REQ-US-01-C (Event-driven) When the source uses .code16 and .code32 directives, the assembler shall switch between 16-bit and 32-bit encoding modes within the same source file.

US-02: Application Developer Using SSE4/AVX

As an application developer, I want to write SIMD code using SSE4.2 and AVX2 intrinsics in inline assembly so that I can optimize hot loops.

REQ-US-02-A (Event-driven) When -march=x86-64-v2 is specified, the assembler shall accept all SSE3, SSSE3, SSE4.1, SSE4.2, and POPCNT instructions.

REQ-US-02-B (Event-driven) When -march=x86-64-v3 is specified, the assembler shall additionally accept all AVX, AVX2, FMA, BMI1, BMI2, F16C, LZCNT, and MOVBE instructions.

REQ-US-02-C (Unwanted behavior) If the user writes an AVX-512 instruction while -march=x86-64-v3 is active, then the assembler shall emit an error stating that the instruction requires x86-64-v4.

US-03: Embedded Developer Targeting ARMv7

As an embedded developer, I want to assemble ARMv7-A code with Thumb-2 and NEON instructions so that I can build firmware for a Cortex-A class processor.

REQ-US-03-A (Event-driven) When -march=armv7-a is specified, the assembler shall accept ARM state, Thumb state, Thumb-2, VFPv3, and NEON instructions.

REQ-US-03-B (State-driven) While in .thumb mode, the assembler shall select narrow 16-bit encodings where the operands allow and wide 32-bit encodings otherwise.

REQ-US-03-C (Ubiquitous) The assembler shall correctly encode IT blocks with up to four conditioned Thumb instructions.

REQ-US-03-D (Event-driven) When the source uses LDR Rn, =constant pseudo-instructions, the assembler shall generate a literal pool entry and a PC-relative load.

US-04: Systems Programmer Targeting AArch64

As a systems programmer, I want to assemble AArch64 code using ARMv8.1 atomic instructions so that I can implement lock-free data structures.

REQ-US-04-A (Event-driven) When -march=armv8.1-a is specified, the assembler shall accept all ARMv8.0 and ARMv8.1 instructions including LSE atomics (LDADD, SWP, CAS, CASP and all ordering/size variants).

REQ-US-04-B (Ubiquitous) The assembler shall encode AArch64 system instructions (MSR, MRS, DC, IC, AT, TLBI) with the correct system register encoding.

REQ-US-04-C (Ubiquitous) The assembler shall encode Advanced SIMD instructions with correct element size specifiers (e.g., FADD V0.4S, V1.4S, V2.4S).

US-05: Build System Integration

As a build system maintainer, I want as to be a drop-in replacement for GNU as so that existing Makefiles and build scripts work without modification.

REQ-US-05-A (Ubiquitous) The assembler shall accept all command-line options documented in this specification with semantics compatible with GNU as.

REQ-US-05-B (Event-driven) When an unrecognized option is encountered, the assembler shall emit a warning and continue rather than aborting (for forward-compatibility with new GAS options).

REQ-US-05-C (Ubiquitous) The assembler shall produce ELF output with section names, symbol names, and relocation types identical to those produced by GNU as for the same input.

US-06: Compiler Backend Developer

As a compiler backend developer, I want to programmatically generate assembly and have the assembler handle forward references, relaxation, and .cfi directives so that I can focus on code generation.

REQ-US-06-A (Ubiquitous) The assembler shall handle forward references to labels without requiring a separate declaration pass.

REQ-US-06-B (Ubiquitous) The assembler shall automatically relax short branches to long branches when the target is out of range.

REQ-US-06-C (Event-driven) When .cfi_startproc and .cfi_endproc bracket a function, the assembler shall emit a complete FDE record in .eh_frame.

REQ-US-06-D (Ubiquitous) The assembler shall process .file and .loc directives to emit DWARF .debug_line information usable by addr2line and debuggers.


7. Developer Stories

DS-01: Adding a New Instruction

As an assembler developer, I want the instruction encoding to be table-driven so that adding a new instruction requires only a table entry, not new code.

REQ-DS-01-A (Ubiquitous) The assembler shall define instruction encodings in declarative tables indexed by mnemonic, operand pattern, and architecture.

REQ-DS-01-B (Ubiquitous) The assembler shall derive the encoding (opcode bytes, ModR/M, prefix selection, VEX/EVEX fields) from the table entry and operand values at assembly time.

REQ-DS-01-C (Ubiquitous) The assembler shall validate that all table entries produce correct output via automated encoding tests.

DS-02: Adding a New Architecture

As an assembler developer, I want architecture-specific code to be isolated behind a clean backend interface so that adding a new architecture does not require modifying the core assembler.

REQ-DS-02-A (Ubiquitous) The assembler shall define an architecture backend interface that provides: instruction parsing, encoding, relocation emission, relaxation, and register name resolution.

REQ-DS-02-B (Ubiquitous) The assembler shall select the backend at startup based on the -march and --32/--64 options.

REQ-DS-02-C (Ubiquitous) The assembler shall share the lexer, directive handling, symbol table, section management, and ELF output across all backends.

DS-03: Testing an Instruction Encoding

As an assembler developer, I want to write a test that specifies an instruction string and the expected machine code bytes so that regressions are caught automatically.

REQ-DS-03-A (Ubiquitous) The assembler test framework shall support test cases in the format: { input: "movl %eax, %ebx", arch: "i386", expected: [0x89, 0xC3] }.

REQ-DS-03-B (Ubiquitous) The assembler test framework shall compare the assembled output byte-by-byte against the expected encoding and report mismatches with both expected and actual bytes.

REQ-DS-03-C (Ubiquitous) The assembler test suite shall contain at least one encoding test for every instruction mnemonic in the instruction tables.

DS-04: Debugging Relaxation Issues

As an assembler developer, I want the relaxation engine to log its decisions so that I can diagnose convergence failures and incorrect encoding selections.

REQ-DS-04-A (Event-driven) When --statistics is specified, the assembler shall print the number of relaxation passes performed and the number of instructions that changed size.

REQ-DS-04-B (Event-driven) When an internal debug flag is set, the assembler shall log each relaxation decision (instruction, old size, new size, target distance) to standard error.

DS-05: Maintaining ELF Compatibility

As an assembler developer, I want automated compatibility tests that compare our output against GNU as output so that interoperability regressions are caught.

REQ-DS-05-A (Ubiquitous) The assembler CI shall include tests that assemble a corpus of source files with both Substrate as and GNU as, then compare the resulting ELF structure using readelf -a.

REQ-DS-05-B (Ubiquitous) The assembler CI shall include tests that link Substrate as output with GNU ld and verify the resulting executable runs correctly.

REQ-DS-05-C (Ubiquitous) The assembler CI shall include tests that link GNU as output with Substrate ld and verify the resulting executable runs correctly.

DS-06: Fuzzing the Parser

As an assembler developer, I want a fuzz harness for the parser so that crashes on malformed input are discovered early.

REQ-DS-06-A (Ubiquitous) The assembler shall provide a fuzz harness entry point that accepts arbitrary byte buffers as assembly source.

REQ-DS-06-B (Ubiquitous) The fuzz harness shall exercise the full pipeline: lexer → parser → encoder → output, for each architecture backend.

REQ-DS-06-C (Ubiquitous) The assembler shall be crash-free for all inputs discovered by fuzzing (zero ASAN/UBSAN findings).


8. Traceability Matrix

Requirement User Story Developer Story Tasklist Section
REQ-AS-010–014 US-05 §1a (Lexer)
REQ-AS-020–025 US-06 DS-01 §1a (Lexer)
REQ-AS-030–036 US-01, US-02 DS-01 §1b (Parser)
REQ-AS-040–048 US-05, US-06 §1d–1f (Directives)
REQ-AS-050–057 US-02, US-03, US-04 DS-02 §1h (CLI)
REQ-AS-060–065 US-01, US-02 DS-01, DS-03 §2–5 (x86)
REQ-AS-070–076 US-03 DS-01, DS-02 §6 (ARMv7)
REQ-AS-080–084 US-04 DS-01, DS-02 §7 (AArch64)
REQ-AS-090–095 US-06 DS-04 §1g (Relaxation)
REQ-AS-100–111 US-01–US-06 DS-05 §1f (ELF Output)
REQ-AS-120–126 US-05 DS-04 §1h (CLI)
REQ-AS-130–139 US-05 §1h (CLI)
REQ-AS-200–209 US-05 DS-05, DS-06 §8–10 (Testing)

9. Acceptance Criteria

  1. as --32 -o test.o test.s produces a valid ELF32 EM_386 object linkable by Substrate ld and GNU ld.
  2. as --64 -march=x86-64-v4 -o test.o test.s accepts all AVX-512 instructions and produces a valid ELF64 object with .note.gnu.property.
  3. as -march=armv7-a -o test.o test.s produces a valid ELF32 EM_ARM object with correct e_flags, mapping symbols, and REL relocations.
  4. as -march=armv8.1-a -o test.o test.s produces a valid ELF64 EM_AARCH64 object with RELA relocations and correctly encoded LSE atomics.
  5. Assembly listing (-al) output matches instruction encoding in the object file.
  6. Two identical assembly runs produce byte-identical output.
  7. The fuzz harness runs for 24 hours without discovering any crashes.
  8. readelf -a structural validation passes on all outputs.
  9. Full toolchain path (asld → execution) works for all four architectures.

usr.bin/as — Standalone Assembler Tasklist

Goal: replace the current GCC/GAS wrapper with a native multi-architecture assembler producing ELF object files directly via libelfobj. Target architectures: i386, x86-64 (v1–v4), ARMv7, AArch64 (ARMv8.0–8.1).


1. Assembler Core Architecture

1a. Lexer

  • Tokenize mnemonics, registers, immediates (decimal/hex/octal/binary), labels, directives, strings.
  • AT&T syntax (default) and Intel syntax (-msyntax=intel).
  • Line comments (#, //, ;), block comments (/* */).
  • .include file inclusion with search path (-I).
  • Preprocessor integration: .if/.ifdef/.ifndef/.else/.endif, .macro/.endm, .rept/.endr, .irp/.irpc.
  • String escapes in .ascii/.asciz/.string directives.

1b. Parser

  • Instruction parsing: mnemonic + operand list.
  • Operand types: register, immediate, memory (base+index*scale+disp), label reference.
  • Expression parser: +, -, *, /, %, |, &, ^, ~, <<, >>, unary -.
  • Symbol references in expressions (forward/backward).
  • Local labels (0:9:, 0b/0f references).
  • Instruction prefixes: lock, rep/repe/repne, segment overrides, rex prefixes.
  • ARM: condition codes, shift operands, register lists, coprocessor operands.

1c. Symbol Table

  • Local, global, weak, common symbol types.
  • .globl/.global, .local, .weak, .comm, .lcomm.
  • .type (function/object/tls_object/common/notype), .size.
  • .hidden, .protected, .internal visibility.
  • .symver symbol versioning.
  • Forward reference resolution (two-pass or relaxation).

1d. Section Management

  • .text, .data, .bss, .rodata built-in sections.
  • .section name, "flags", @type with SHF_/SHT_ mapping.
  • .pushsection/.popsection, .previous.
  • .subsection ordering.
  • .group / COMDAT support.
  • Section alignment via .balign/.p2align/.align.

1e. Data Directives

  • .byte, .short/.hword, .long/.int, .quad/.8byte.
  • .float, .double.
  • .ascii, .asciz/.string.
  • .zero/.space, .fill.
  • .skip, .org.
  • .incbin for binary inclusion.

1f. ELF Output (via libelfobj)

  • Generate ET_REL ELF32 (i386, ARMv7) and ELF64 (x86-64, AArch64).
  • Emit section headers, symbol table (.symtab/.strtab), section name table (.shstrtab).
  • Emit relocations: REL (i386, ARM) and RELA (x86-64, AArch64).
  • .note.gnu.property for x86-64-v2/v3/v4 ISA level marking.
  • .note.GNU-stack for executable stack control.
  • Debug sections passthrough (.debug_*, .eh_frame).
  • DWARF .debug_line generation from .loc/.file directives.
  • .eh_frame / .eh_frame_hdr CFI via .cfi_* directives.

1g. Relaxation Engine

  • Branch relaxation: short→near→far jump promotion.
  • x86: jmp rel8jmp rel32 relaxation.
  • ARM: branch offset range checking; Thumb→ARM interwork veneer insertion.
  • Iterative relaxation until stable.

1h. CLI Interface

  • -o output.o, -c (ignored compat), -g (debug info).
  • -march=ARCH, -mtune=TUNE (validation per arch).
  • -32/-64 / --32/--64 mode selection.
  • -msyntax=att/-msyntax=intel.
  • -W/--warn, --fatal-warnings, --no-warn.
  • -I dir include path, -D sym=val defines.
  • -al listing output.
  • --defsym sym=val.
  • --statistics timing/memory report.
  • --target-help per-arch instruction summary.

2. x86 Encoding Engine (i386 + x86-64)

2a. Legacy Encoding (i386 baseline)

  • ModR/M + SIB + displacement encoding.
  • All addressing modes: [base], [base+disp], [base+idx*s+disp], [disp32].
  • Operand size prefix (0x66), address size prefix (0x67).
  • Segment override prefixes (CS/DS/ES/FS/GS/SS).
  • All i386 base instructions: data movement, arithmetic, logic, shifts, string ops, control flow, stack, flags, I/O, misc.

2b. x86-64 Extensions

  • REX prefix encoding (REX.W/R/X/B).
  • RIP-relative addressing (default for x86-64).
  • 64-bit register operands (R8–R15, RAX–RSP).
  • SYSCALL/SYSRET, SWAPGS, CMPXCHG16B.

2c. VEX Prefix Encoding (AVX/AVX2/BMI/FMA/F16C)

  • 2-byte VEX (C5), 3-byte VEX (C4) selection.
  • VEX.L (128 vs 256), VEX.vvvv (3rd operand), VEX.W, VEX.pp.
  • Non-destructive 3-operand form for all VEX instructions.

2d. EVEX Prefix Encoding (AVX-512)

  • 4-byte EVEX prefix: P0 (R/X/B/R'/mm), P1 (W/vvvv/pp), P2 (z/L'L/b/V'/aaa).
  • Opmask register selection ({k1}{k7}).
  • Zeroing-masking ({z}).
  • Embedded broadcast ({1to2}, {1to4}, {1to8}, {1to16}).
  • Static rounding mode ({rn-sae}, {rd-sae}, {ru-sae}, {rz-sae}).
  • Suppress-all-exceptions ({sae}).

2e. x86 Relocation Emission

  • R_386_32, R_386_PC32, R_386_GOT32, R_386_PLT32, R_386_GOTOFF, R_386_GOTPC.
  • R_386_TLS_GD, R_386_TLS_LDM, R_386_TLS_IE, R_386_TLS_LE.
  • R_X86_64_64, R_X86_64_PC32, R_X86_64_32, R_X86_64_32S.
  • R_X86_64_GOT32, R_X86_64_PLT32, R_X86_64_GOTPCREL, R_X86_64_GOTPCRELX.
  • R_X86_64_REX_GOTPCRELX.
  • R_X86_64_TLSGD, R_X86_64_TLSLD, R_X86_64_GOTTPOFF, R_X86_64_TPOFF32.

3. x86-64-v2 Instructions

CMPXCHG16B, LAHF/SAHF (long mode), POPCNT, SSE3, SSSE3, SSE4.1, SSE4.2.

3a. CMPXCHG16B / LAHF / SAHF / POPCNT

  • CMPXCHG16B m1280F C7 /1 + REX.W
  • LAHF9F, SAHF9E
  • POPCNT r16/r32/r64, r/m16/32/64F3 0F B8 /r

3b. SSE3

  • ADDSUBPD, ADDSUBPS, HADDPD, HADDPS, HSUBPD, HSUBPS
  • LDDQU, MOVDDUP, MOVSHDUP, MOVSLDUP
  • FISTTP (m16/m32/m64), MONITOR, MWAIT

3c. SSSE3

  • PABSB/W/D, PALIGNR, PHADDW/D/SW, PHSUBW/D/SW
  • PMADDUBSW, PMULHRSW, PSHUFB, PSIGNB/W/D

3d. SSE4.1

  • BLENDPD/PS, BLENDVPD/VPS, DPPD/DPPS
  • EXTRACTPS, INSERTPS, MOVNTDQA, MPSADBW, PACKUSDW
  • PBLENDVB, PBLENDW, PCMPEQQ
  • PEXTRB/D/Q/W (new forms), PINSRB/D/Q
  • PMAXSB/SD/UD/UW, PMINSB/SD/UD/UW
  • PMOVSXBW/BD/BQ/WD/WQ/DQ, PMOVZXBW/BD/BQ/WD/WQ/DQ
  • PMULDQ, PMULLD, PTEST
  • ROUNDPD/PS/SD/SS
  • PHMINPOSUW

3e. SSE4.2

  • CRC32 (r32/r64 × r/m8/16/32/64)
  • PCMPESTRI/M, PCMPISTRI/M, PCMPGTQ

4. x86-64-v3 Instructions

AVX, AVX2, BMI1, BMI2, F16C, FMA, LZCNT, MOVBE, XSAVE.

4a. AVX (VEX-encoded SSE promotion + new)

  • All SSE/SSE2/SSE3/SSSE3/SSE4 → VEX 128-bit + 256-bit forms
  • VBROADCASTSS/SD, VBROADCASTF128, VEXTRACTF128, VINSERTF128
  • VMASKMOVPS/PD (load/store), VPERM2F128, VPERMILPS/PD
  • VTESTPS/PD, VZEROALL, VZEROUPPER

4b. AVX2 (256-bit integer)

  • All SSE2 integer → 256-bit VEX forms
  • VBROADCASTI128, VEXTRACTI128, VINSERTI128, VPBLENDD
  • VPBROADCASTB/W/D/Q, VPERMD/PS/PD/Q, VPERM2I128
  • VPMASKMOVD/Q, VPSLLVD/Q, VPSRLVD/Q, VPSRAVD
  • VGATHERDPS/DPD/QPS/QPD, VPGATHERDD/DQ/QD/QQ (VSIB)

4c. BMI1

  • ANDN, BEXTR, BLSI, BLSMSK, BLSR, TZCNT (r32/r64)

4d. BMI2

  • BZHI, MULX, PDEP, PEXT, RORX, SARX, SHLX, SHRX (r32/r64)

4e. F16C

  • VCVTPH2PS, VCVTPS2PH

4f. FMA (132/213/231 × PS/PD/SS/SD)

  • VFMADD, VFMSUB, VFNMADD, VFNMSUB (all 12 forms each)
  • VFMADDSUB, VFMSUBADD (all 6 forms each)

4g. LZCNT / MOVBE / XSAVE

  • LZCNT r16/32/64, r/m16/32/64
  • MOVBE r16/32/64, m and MOVBE m, r16/32/64
  • XSAVE/XRSTOR/XGETBV/XSETBV/XSAVEOPT/XSAVEC/XSAVES + 64-bit forms

5. x86-64-v4 Instructions

AVX-512F, AVX-512BW, AVX-512CD, AVX-512DQ, AVX-512VL.

5a. AVX-512F (Foundation)

  • 512-bit arithmetic: VADDPS/PD, VSUB, VMUL, VDIV, VMAX, VMIN, VSQRT (zmm)
  • VRSQRT14, VRCP14, FMA 512-bit forms
  • Conversions: VCVT{PS,PD,DQ,UDQ,QQ,UQQ}2{PS,PD,DQ,UDQ} (all signed/unsigned)
  • Broadcasts: VBROADCASTSS/SD/F32X4/F64X4 (zmm)
  • Insert/Extract: VINSERTF32X4/F64X4, VEXTRACTF32X4/F64X4
  • Permutes: VPERMPS/PD/D/Q, VPERMI2{PS,PD,D,Q,W,B}, VPERMT2{PS,PD,D,Q,W,B}
  • Shuffles: VSHUFF32X4/F64X2, VSHUFI32X4/I64X2
  • Compress/Expand: VCOMPRESSPS/PD, VPCOMPRESSD/Q, VEXPANDPS/PD, VPEXPANDD/Q
  • FP special: VGETEXPPS/PD/SS/SD, VGETMANTPS/PD/SS/SD, VSCALEFPS/PD/SS/SD, VFIXUPIMMPS/PD/SS/SD, VRNDSCALEPS/PD/SS/SD
  • Compares-to-mask: VCMPPS/PD, VPCMPD/Q/UD/UQ
  • Blend/Logic: VPBLENDMD/MQ, VPTERNLOGD/Q
  • Down-converts: VPMOVDB/DW/QB/QD/QW (truncate/signed-sat/unsigned-sat)
  • Masked moves: VMOVDQA32/64, VMOVDQU8/16/32/64
  • Gather/Scatter: VGATHER{D,Q}{PS,PD}, VPGATHER{DD,DQ,QD,QQ}, VSCATTER{D,Q}{PS,PD}, VPSCATTER{DD,DQ,QD,QQ} (zmm)
  • Opmask: KMOV{B,W,D,Q}, KAND/OR/XOR/XNOR/NOT/ANDN{B,W,D,Q}, KORTEST/KTEST{B,W,D,Q}, KSHIFTL/R{B,W,D,Q}, KUNPCK{BW,WD,DQ}, KADD{W,D,Q}

5b. AVX-512BW (Byte/Word)

  • 512-bit byte/word arithmetic, pack, unpack, shuffle, shift, compare-to-mask
  • VPSLLVW, VPSRLVW, VPSRAVW, VDBPSADBW
  • VPCMPB/W/UB/UW → k, VPMOVB2M/W2M, VPMOVM2B/W
  • VPERMW, VPERMI2W, VPERMT2W, VPBLENDMB/MW
  • VPTESTNMB/MW

5c. AVX-512CD (Conflict Detection)

  • VPCONFLICTD/Q, VPLZCNTD/Q, VPBROADCASTMB2Q, VPBROADCASTMW2D

5d. AVX-512DQ (Doubleword/Quadword)

  • QQ conversions: VCVT{PS,PD}2{QQ,UQQ}, VCVT{QQ,UQQ}2{PS,PD} (truncating forms too)
  • VPMULLQ, VPMOVM2D/Q, VPMOVD2M/Q2M
  • Insert/Extract 64x2/32x8 forms
  • VRANGEPS/PD/SS/SD, VREDUCEPS/PD/SS/SD, VFPCLASSPS/PD/SS/SD → k
  • Bitwise FP: VANDPS/PD, VORPS/PD, VXORPS/PD, VANDNPS/PD (EVEX zmm)
  • VBROADCASTF32X2/F32X8/I32X2/I32X8

5e. AVX-512VL (Vector Length)

  • All 512-bit instructions also available at EVEX.128 (xmm) and EVEX.256 (ymm)
  • Opmask + zeroing on 128/256-bit forms
  • Embedded broadcast on 128/256-bit memory operands

6. ARMv7 (AArch32) Encoding Engine

6a. ARM State Encoding Infrastructure

  • 32-bit ARM instruction encoding (condition field, opcode classes).
  • Condition codes: EQ/NE/CS/CC/MI/PL/VS/VC/HI/LS/GE/LT/GT/LE/AL/NV.
  • Addressing modes: immediate, register, scaled register, pre/post-indexed, LDM/STM modes (IA/IB/DA/DB/FD/FA/ED/EA).
  • Barrel shifter operands: LSL/LSR/ASR/ROR/RRX (immediate and register).
  • S-suffix (set flags), conditional execution on all instructions.
  • ARM/Thumb interwork: .arm, .thumb, .thumb_func, BX/BLX interwork.
  • IT blocks (Thumb-2): IT{T,E}{T,E}{T,E} (up to 4 conditional instructions).

6b. Thumb / Thumb-2 Encoding

  • 16-bit narrow Thumb encoding for basic operations.
  • 32-bit wide Thumb-2 encoding for extended operations.
  • Automatic narrow/wide selection based on operand range.
  • .syntax unified (default): single mnemonic for ARM/Thumb with .w/.n suffixes.

6c. Data Processing Instructions

  • ADD, ADC, SUB, SBC, RSB, RSC (immediate, register, shifted register)
  • AND, ORR, EOR, BIC, ORN (Thumb-2)
  • MOV, MVN (immediate, register); MOVW, MOVT (16-bit immediate)
  • CMP, CMN, TST, TEQ
  • MUL, MLA, MLS, UMULL, UMLAL, SMULL, SMLAL
  • SMULBB/BT/TB/TT, SMLABB/BT/TB/TT, SMLALBB/BT/TB/TT
  • SMUAD/X, SMLAD/X, SMLALD/X, SMUSD/X, SMLSD/X, SMLSLD/X
  • UMAAL, SDIV, UDIV
  • CLZ, RBIT, REV, REV16, REVSH
  • PKH{BT,TB}, SSAT, USAT, SSAT16, USAT16
  • SBFX, UBFX, BFI, BFC
  • SXTB/H, UXTB/H, SXTAB/H, UXTAB/H, SXTB16, UXTB16, SXTAB16, UXTAB16
  • QADD, QDADD, QSUB, QDSUB
  • SADD8/16, UADD8/16, SSUB8/16, USUB8/16, SHADD8/16, UHADD8/16, SHSUB8/16, UHSUB8/16
  • QADD8/16, UQADD8/16, QSUB8/16, UQSUB8/16
  • SASX, UASX, SSAX, USAX, SHASX, UHASX, SHSAX, UHSAX, QASX, UQASX, QSAX, UQSAX
  • USAD8, USADA8, SEL

6d. Branch Instructions

  • B, BL (immediate offset, conditional)
  • BX, BLX (register, Thumb interwork)
  • CBZ, CBNZ (Thumb-2, compare-and-branch)
  • TBB, TBH (Thumb-2, table branch byte/halfword)

6e. Load/Store Instructions

  • LDR/STR (word, byte, halfword, signed byte, signed halfword, doubleword)
  • LDRB/STRB, LDRH/STRH, LDRSB, LDRSH, LDRD/STRD
  • Pre-indexed, post-indexed, offset addressing with immediate/register offsets
  • LDM/STM (IA/IB/DA/DB variants), PUSH/POP
  • LDREX/STREX, LDREXB/STREXB, LDREXH/STREXH, LDREXD/STREXD (exclusive)
  • LDR pseudo-instruction (literal pool generation)
  • LDRT/STRT, LDRBT/STRBT, LDRHT/STRHT (user-mode access)
  • PLD, PLDW, PLI (preload)

6f. Coprocessor and System

  • SVC/SWI, BKPT, HLT
  • MRS, MSR (CPSR/SPSR/APSR fields)
  • CPS{IE,ID} (interrupt enable/disable), SETEND
  • DMB, DSB, ISB (barriers)
  • WFI, WFE, SEV, YIELD, NOP, DBG
  • CDP, CDP2, MCR, MCR2, MRC, MRC2, MCRR, MCRR2, MRRC, MRRC2
  • LDC, LDC2, STC, STC2
  • CLREX

6g. VFPv3/v4 (Floating Point)

  • VADD.F32/F64, VSUB, VMUL, VDIV, VNMUL, VMLA, VMLS, VNMLA, VNMLS
  • VFMA.F32/F64, VFMS, VFNMA, VFNMS (VFPv4)
  • VMOV (imm, reg, between ARM/VFP), VMRS, VMSR
  • VCMP, VCMPE, VCVT (int↔float, float↔float, fixed-point), VCVT{T,B}.F16.F32 (half-precision)
  • VABS, VNEG, VSQRT
  • VLDR, VSTR, VLDM, VSTM, VPUSH, VPOP
  • VCVTA/M/N/P (ARMv8 rounding modes)

6h. NEON (Advanced SIMD)

  • Data types: .I8/.I16/.I32/.I64, .U8/.U16/.U32/.U64, .S8/.S16/.S32/.S64, .F16/.F32, .P8/.P16
  • Arithmetic: VADD, VSUB, VMUL, VMLA, VMLS, VABA, VABD, VPADD, VPMIN/MAX, VMAX/MIN, VHADD, VHSUB, VRHADD, VQADD, VQSUB, VMULL, VMLAL, VMLSL, VQDMULL, VQDMLAL, VQDMLSL, VQDMULH, VQRDMULH, VRSHL, VQRSHL, VSHL, VQSHL, VSHR, VRSHR, VSRA, VRSRA, VSLI, VSRI, VQSHLU, VSHLL, VSHRN, VQSHRN, VQRSHRN, VQSHRUN, VQRSHRUN, VMOVN, VQMOVN, VQMOVUN, VMOVL
  • Logical: VAND, VORR, VEOR, VBIC, VORN, VBIT, VBIF, VBSL, VMOV, VMVN
  • Compare: VCEQ, VCGE, VCGT, VCLE, VCLT, VACGE, VACGT, VTST
  • Table lookup: VTBL, VTBX
  • Transpose/Interleave: VTRN, VUZP, VZIP, VSWP, VEXT, VREV16/32/64
  • Load/Store: VLD1/2/3/4, VST1/2/3/4 (single/multi-element, all lane, one lane)
  • Duplicate: VDUP (scalar→vector, ARM reg→vector)
  • Convert: VCVT (integer↔float within NEON), VRECPE, VRECPS, VRSQRTE, VRSQRTS
  • Accumulate: VPADAL, VPADDL, VCNT, VCLZ, VCLS

6i. ARMv7 Relocations

  • R_ARM_ABS32, R_ARM_REL32, R_ARM_PC24, R_ARM_CALL, R_ARM_JUMP24
  • R_ARM_THM_CALL, R_ARM_THM_JUMP24, R_ARM_THM_JUMP11, R_ARM_THM_JUMP8
  • R_ARM_MOVW_ABS_NC, R_ARM_MOVT_ABS, R_ARM_THM_MOVW_ABS_NC, R_ARM_THM_MOVT_ABS
  • R_ARM_GOT_BREL, R_ARM_PLT32, R_ARM_GOTOFF32, R_ARM_GOTPC
  • R_ARM_TLS_GD32, R_ARM_TLS_LDM32, R_ARM_TLS_IE32, R_ARM_TLS_LE32
  • R_ARM_PREL31 (exception tables)

7. AArch64 (ARMv8.0 + ARMv8.1) Encoding Engine

7a. A64 Encoding Infrastructure

  • Fixed-width 32-bit instruction encoding.
  • Register file: X0–X30 (64-bit), W0–W30 (32-bit), SP, XZR/WZR, PC (not directly encodable).
  • Condition codes: EQ/NE/CS/CC/MI/PL/VS/VC/HI/LS/GE/LT/GT/LE/AL/NV.
  • Immediate encoding: logical immediates (bitmask), move-wide immediates, PC-relative (ADR/ADRP pages).

7b. Data Processing — Immediate

  • ADD/SUB{S} Xd, Xn, #imm{, shift} (12-bit immediate, optional LSL #12)
  • AND/ORR/EOR/ANDS Xd, Xn, #bitmask (logical immediate)
  • MOVN/MOVZ/MOVK Xd, #imm16{, LSL #shift} (16-bit wide move)
  • ADR Xd, label (PC-relative ±1MB), ADRP Xd, label (PC-relative ±4GB page)
  • BFM/SBFM/UBFM (bitfield move); aliases: BFI, BFXIL, SBFX, UBFX, SXTB/H/W, UXTB/H
  • EXTR Xd, Xn, Xm, #lsb (extract/rotate)

7c. Data Processing — Register

  • ADD/SUB{S} Xd, Xn, Xm{, shift #amount} (LSL/LSR/ASR/ROR)
  • ADD/SUB{S} Xd, Xn, Wm, extend{#amount} (UXTB/UXTH/UXTW/UXTX/SXTB/SXTH/SXTW/SXTX)
  • AND/ORR/EOR/ORN/EON/BIC/BICS/ANDS (shifted register)
  • ADC/SBC{S} (add/sub with carry)
  • MADD/MSUB (multiply-add); aliases: MUL, MNEG
  • SMADDL/SMSUBL/UMADDL/UMSUBL (widening multiply-add); aliases: SMULL, UMULL
  • SMULH, UMULH (high multiply)
  • SDIV, UDIV
  • CLS, CLZ, RBIT, REV, REV16, REV32
  • CSEL/CSINC/CSINV/CSNEG (conditional select); aliases: CINC, CINV, CNEG, CSET, CSETM
  • CCMN/CCMP (conditional compare)

7d. Branch Instructions

  • B label (±128MB), BL label (±128MB)
  • B.cond label (±1MB)
  • BR Xn, BLR Xn, RET {Xn}
  • CBZ/CBNZ Xt, label (±1MB)
  • TBZ/TBNZ Xt, #bit, label (±32KB)
  • SVC #imm16, HVC #imm16, SMC #imm16, BRK #imm16, HLT #imm16

7e. Load/Store Instructions

  • LDR/STR (byte/half/word/dword): immediate offset, pre/post-index, register offset
  • LDRB/STRB, LDRH/STRH, LDRSB/LDRSH, LDRSW
  • LDP/STP (pair load/store), LDPSW
  • LDNP/STNP (non-temporal pair)
  • LDR Xt, =value (literal pool), LDR Xt, label (PC-relative literal)
  • LDXR/STXR, LDXRB/STXRB, LDXRH/STXRH, LDXP/STXP (exclusive)
  • LDAR/STLR, LDARB/STLRB, LDARH/STLRH (acquire/release)
  • LDAXR/STLXR, LDAXRB/STLXRB, LDAXRH/STLXRH, LDAXP/STLXP (acquire-exclusive)
  • PRFM (prefetch memory)

7f. System Instructions

  • MSR/MRS (system register access)
  • NOP, YIELD, WFE, WFI, SEV, SEVL
  • DMB, DSB, ISB (barriers with domain: SY/ST/LD/ISH/ISHST/ISHLD/NSH/NSHST/NSHLD/OSH/OSHST/OSHLD)
  • CLREX
  • SYS, SYSL (generic system instruction)
  • DC, IC, AT, TLBI (cache/TLB maintenance aliases)
  • HINT #imm

7g. SIMD & FP (NEON / AArch64 Advanced SIMD)

  • Vector registers: V0–V31, Bn/Hn/Sn/Dn/Qn sub-register views
  • Element specifiers: V0.16B, V0.8H, V0.4S, V0.2D, V0.8B, V0.4H, V0.2S, V0.1D
  • Arithmetic: ADD/SUB, MUL/MLA/MLS, FADD/FSUB/FMUL/FDIV/FMLA/FMLS, FMADD/FMSUB/FNMADD/FNMSUB
  • ADDP, FADDP, SADDL/SADDW/UADDL/UADDW, SSUBL/SSUBW/USUBL/USUBW
  • SMULL/UMULL/SMLAL/UMLAL/SMLSL/UMLSL (widening)
  • SQDMULL/SQDMLAL/SQDMLSL, SQRDMULH, SQDMULH
  • SQADD/UQADD/SQSUB/UQSUB, SHADD/UHADD/SHSUB/UHSUB/SRHADD/URHADD
  • SMAX/UMAX/SMIN/UMIN, SMAXP/UMAXP/SMINP/UMINP, SMAXV/UMAXV/SMINV/UMINV
  • SABS/SQABS/SQNEG/NEG/ABS
  • Shifts: SHL/SSHL/USHL/SRSHL/URSHL, SQSHL/UQSHL/SQRSHL/UQRSHL, SSHR/USHR/SSRA/USRA/SRSHR/URSHR/SRSRA/URSRA, SRI/SLI, SHRN/RSHRN/SQSHRN/SQRSHRN/UQSHRN/UQRSHRN/SQSHRUN/SQRSHRUN, SSHLL/USHLL
  • Logical: AND/ORR/EOR/ORN/BIC/BIF/BIT/BSL, NOT/MVN
  • Compare: CMEQ/CMGE/CMGT/CMHI/CMHS/CMLE/CMLT/CMTST, FCMEQ/FCMGE/FCMGT/FCMLE/FCMLT/FACGE/FACGT
  • Permute: TBL/TBX, TRN1/TRN2, UZP1/UZP2, ZIP1/ZIP2, EXT, REV16/32/64, DUP, INS, SMOV/UMOV
  • Load/Store: LD1/LD2/LD3/LD4, ST1/ST2/ST3/ST4 (multi-struct), LD1R/LD2R/LD3R/LD4R (replicate)
  • FP: FCVT, FCVTZS/FCVTZU, SCVTF/UCVTF, FMOV, FABS, FNEG, FSQRT, FMAX/FMIN/FMAXNM/FMINNM, FRINTI/FRINTX/FRINTA/FRINTN/FRINTP/FRINTM/FRINTZ, FRECPE/FRECPS/FRSQRTE/FRSQRTS
  • Crypto (optional): AESE/AESD/AESMC/AESIMC, SHA1C/P/M/H/SU0/SU1, SHA256H/H2/SU0/SU1
  • CRC32 (optional): CRC32B/H/W/X/CB/CH/CW/CX

7h. ARMv8.1 Extensions

  • LSE (Large System Extensions) — Atomics:
    • LDADD{A,L,AL}{B,H,} — atomic add
    • LDCLR{A,L,AL}{B,H,} — atomic bit clear
    • LDEOR{A,L,AL}{B,H,} — atomic exclusive OR
    • LDSET{A,L,AL}{B,H,} — atomic bit set
    • LDSMAX/LDSMIN/LDUMAX/LDUMIN{A,L,AL}{B,H,} — atomic signed/unsigned max/min
    • SWP{A,L,AL}{B,H,} — atomic swap
    • CAS{A,L,AL}{B,H,} — compare and swap (single)
    • CASP{A,L,AL} — compare and swap pair
    • STADD{L}{B,H,}, STCLR{L}, STEOR{L}, STSET{L}, STSMAX{L}, STSMIN{L}, STUMAX{L}, STUMIN{L} — store-only atomics (aliases with XZR destination)
  • RDMA (Rounding Double Multiply Accumulate):
    • SQRDMLAH (vector/element) — signed saturating rounding doubling multiply accumulate high
    • SQRDMLSH (vector/element) — signed saturating rounding doubling multiply subtract high
  • LOR (Limited Ordering Regions):
    • LDLAR{B,H} — load LOAcquire
    • STLLR{B,H} — store LORelease
  • VHE (Virtualization Host Extensions):
    • New system register access patterns (EL2 registers)
  • PAN (Privileged Access Never):
    • LDTR/STTR unprivileged load/store (existing, but PAN makes them significant)
  • HPD/HPDS (Hierarchical Permission Disables):
    • System register configuration (TCR_EL1.HPD bits)

7i. AArch64 Relocations

  • R_AARCH64_ABS64, R_AARCH64_ABS32, R_AARCH64_ABS16
  • R_AARCH64_PREL64, R_AARCH64_PREL32, R_AARCH64_PREL16
  • R_AARCH64_ADR_PREL_PG_HI21, R_AARCH64_ADR_PREL_LO21
  • R_AARCH64_ADD_ABS_LO12_NC, R_AARCH64_LDST8/16/32/64/128_ABS_LO12_NC
  • R_AARCH64_MOVW_UABS_G0/G1/G2/G3{_NC}
  • R_AARCH64_JUMP26, R_AARCH64_CALL26, R_AARCH64_CONDBR19, R_AARCH64_TSTBR14
  • R_AARCH64_GOT_LD_PREL19, R_AARCH64_ADR_GOT_PAGE, R_AARCH64_LD64_GOT_LO12_NC
  • R_AARCH64_TLSGD_ADR_PAGE21, R_AARCH64_TLSGD_ADD_LO12_NC
  • R_AARCH64_TLSLE_ADD_TPREL_HI12, R_AARCH64_TLSLE_ADD_TPREL_LO12{_NC}
  • R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21, R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC
  • R_AARCH64_TLSLD_ADR_PAGE21, R_AARCH64_TLSLD_ADD_LO12_NC

8. Testing

8a. Unit Tests (per-arch)

  • Encode each instruction, verify machine code bytes match reference.
  • Operand range limits: reject out-of-range immediates.
  • Relocation emission: correct type and addend for each pattern.
  • Relaxation: verify short→long branch promotion.
  • Expression evaluation: arithmetic, forward references, absolute vs. relocatable.

8b. Integration Tests

  • as -o test.o test.sreadelf -a test.o validates headers/sections/symbols.
  • as + ld → running executable for each target arch.
  • Cross-arch rejection: x86 source fails cleanly under ARM mode.
  • Round-trip: disassemble with objdump → reassemble → bit-identical output.
  • Compatibility: Substrate as output linkable by GNU ld, and vice versa.

8c. Fuzz Testing

  • Grammar-aware fuzzer for instruction parser.
  • Byte-level fuzzer for ELF output validation.
  • Crash-free guarantee on arbitrary input.

9. Documentation

  • as.1 man page: all options, directives, per-arch syntax.
  • Per-arch instruction reference appendix.
  • .note.gnu.property x86-64 ISA level semantics.

10. Build System

  • Recursive Makefile, NATIVE_BUILD=1 for host testing.
  • install to $(DESTDIR)/usr/bin/as.
  • Arch-specific symlinks or multi-call binary (arm-as, aarch64-as).
  • libelfobj.a dependency.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment