Skip to content
ALB Wiki

ALB FASM backend

This is an old revision of this page — revision 2 (2026-10-10 20:12:43 UTC). It may differ from the current revision.

The ALB FASM backend is AdaLogic BASIC's flagship native emitter: it turns an ALB program into x86-64 assembly source for the Flat Assembler, which then assembles — in a single pass, in milliseconds — into a real Windows PE64 executable with no linker and no C runtime requirement beyond what ALB brings itself.

It is one of only three backends — with C and FASM16 — where --build is supported end to end: the compiler emits the file and drives the assembler.

What it produces

Every generated file opens the same way — a comment banner, then the PE64 header:

; ==========================================================
; GENERATED BY ADALOGIC BASIC (ALB) TRANSPILER
; TARGET: x64 FASM (Bare-Metal PE Executable)
; ==========================================================
format PE64 Console
stack 1000000h
heap 1000000h
entry start
include 'win64a.inc'

The emitter supports three output formats, switched by flags such as --dll:

FormatEmitted headerResult
Consoleformat PE64 ConsoleCommand-line .exe — the default
GUIformat PE64 GUIWindowed .exe — no console
DLLformat PE64 DLL at 10000000hShared library with an ALB export entry

Console and GUI builds reserve a 16 MiB stack and 16 MiB heap (stack 1000000h / heap 1000000h) — generous headroom for recursion and the temporal-state system, at zero runtime cost since Windows commits the pages lazily.

The file anatomy

A FASM output is organized into the classic PE sections:

  • .text — code: the runtime library, then your program under start:
  • .data — initialized writable data: string literals, buffers, the GC grid
  • .bss — zero-initialized storage
  • .idata — imports: only the Win32 functions actually used (printf, ExitProcess, GDI, winsock…)
  • .reloc — relocations, emitted for DLL builds

The macro layer — FASM as co-optimizer

Here is the part that surprises people. The emitter writes expressions in a deliberately simple infix-looking style — mov rax, a + mov rax, b — and then defines an ALB_LET macro that uses FASM's match directive to rewrite those patterns into optimized code at assembly time:

match =0 =mov =rax, dest, =mov =rax, a + =mov =rax, b, matched line {
    mov rax, a
    add rax, b
    mov dest, rax
    define matched 1
  }

The assembler itself pattern-matches each emitted statement and fuses the verbose three-instruction form into a tight mov/add/mov. The compiler stays simple; the assembler does the peephole optimization. Two tools, each doing what it's best at.

Alongside it, ALB_MASK_OP provides branchless selection — a conditional computed as a bitmask (neg / and / not / and / or) instead of a jump, for the constant-time code paths where a branch would be unpredictable or unsafe.

The hardened runtime

ALB does not trust the machine blindly — the emitted program carries a safety runtime:

ALB_Runtime_Trap_DivZero:
  sub rsp, 40
  invoke printf, ALB_Runtime_DivZero
  invoke ExitProcess, 1

Divide by zero, index out of bounds, or leave a declared range and the program reports and halts rather than corrupting onward — the Ada philosophy showing through the BASIC surface. Every runtime routine is wrapped in FASM's if used … end if, so the assembler strips everything your program never calls: a hello world links in almost none of the library below.

And the library is large:

  • Strings — ALB_Str_Eq, Mid/Left/Right, ALB_Hash, length/copy/concat with fixed-capacity vaults
  • Console — prompts, buffered input with a hand-rolled S64 parser (ALB_Input_Try_Parse_S64, whitespace and sign handled in raw asm)
  • Files — open/read/write/close/len/seek, plus ALB_OS_Load/ALB_OS_Flush whole-file vaults
  • Logic — a real Prolog-style knowledge base: ALB_Assert, ALB_Query, ALB_Find, ALB_Retract — the Prolog half of ALB's ancestry, implemented in machine code
  • Math — sqrt/sine/cosine/abs, random, and the PURE engine (ALB_Pure_Add/Sub/Mul/Div/Pow) — exact rational arithmetic with numerator and denominator kept separate, so ⅓ + ⅓ stays exactly ⅓
  • Graphics & sound — Win32 window creation, message loop, put-pixel, BGR colors, key and mouse state, music buffer streaming
  • Data formats — a complete FITS astronomy file reader (card loop, BITPIX parsing, NAXIS) and an INI parser — emitted only if used
  • FFI — ALB_Load_Foreign_Symbol loads DLL functions at runtime; ALB's IMPORT_DLL lowers to direct calls

The learning runtime — forged by the compiler

MARKOV MODEL, PREDICT MARKOV, NEURAL TOPOLOGY, INFER NETWORK, and TRAIN NETWORK aren't library calls — they're language-level statements with their own AST node kinds. When albt sees one, it registers the model in compile-time tables (up to 128 Markov models and 32,768 transition weights; up to 64 neural topologies sharing 512 layer slots), bakes the declared matrices straight into .data, and flips a Runtime_Used flag. Then the compiler's own Phase 4.5 — "Forging FASM Extended Runtime" — appends only the runtimes that were actually requested:

  • ALB_Markov_Predict: — a ~30-instruction argmax: index the transition-matrix row for the current state, walk it once, return the likeliest next state
  • ALB_NN_Apply_Activation: — activation by code: linear, ReLU, step, and a clamped ±128→×8 scaled tanh — all integers
  • ALB_NN_Infer: — a pure-integer forward pass over a meta-descriptor of layer sizes, offsets, weights, and biases
  • ALB_NN_Train: — a perceptron-style delta rule (delta ∈ {-1, 0, +1}: nudge the bias, nudge each weight where the input fired) refining the output layer per epoch

And the weights themselves are seeded by the compiler: Seed_Neural_Weight in albt assigns deterministic structured guesses — identity patterns for same-size layers (weight 256 = 1.0 at ¹⁄₂₅₆ scale), +256/−256 split-pairs when a layer halves, wrap-around when it grows. No RNG; the same program always starts from the same brain.

Concurrency, honestly stated

SPAWN on this backend is documented in the emitter's own words as "synchronous on FASM (same-core call)" — and SYNC/ATOMIC lower to mfence. The honesty matters: the multi-core dispatch is real on the ALB C backend, deliberately sequential here.

The blackbox

--embed-blackbox installs a VEH crash reporter — a vectored exception handler and a heap-free append-only dump path (ALB_BB_Append_Z, ALB_Blackbox_Handler) that writes a forensic record when a native fault would otherwise vanish silently. A flight recorder for the generated executable, compiled in only when asked for.

Under the hood — the emitter itself

The backend is the Ada package Emit_Native_FASM (~7,300 lines, SPARK-annotated). Its design is a small lesson in compiler construction:

  • Two text buffers — Buffer_Global (lands in .data/.bss) and Buffer_Main (lands in .text) — so declarations and code accumulate independently and merge at flush time
  • **A stable Emit_* API** — Emit_If_Start, Emit_For_Start, Emit_BinOp… The same call surface every backend implements, which is how one front end drives ~23 targets
  • Expression scrubbing — before emitting an operator the emitter backspaces trailing newlines so infix text lands on one line, which is what makes the ALB_LET match-macro possible

See also

Categories: AdaLogic BASIC · Backends
This page was last edited 2026-10-10 20:12:43 UTC by Anonymous. What links here