From 8b76d35b0a045e0a3277be422513b938ef33dcce Mon Sep 17 00:00:00 2001 From: hachem Date: Wed, 9 Sep 2026 05:14:44 +0200 Subject: feat: fasm backend --- docs/language.md | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'docs/language.md') diff --git a/docs/language.md b/docs/language.md index 42b178e..79d7866 100644 --- a/docs/language.md +++ b/docs/language.md @@ -1,6 +1,6 @@ # hdass language reference -hdass emits NASM for x86-64; fasm and masm are planned. The compiler output itself isn't tied to an OS, but the examples and toolchain here target Linux (Linux syscall numbers, `nasm -f elf64`, `ld`). Pipeline: `lex → parse → analyze → emit`. +hdass emits NASM or FASM for x86-64 (`-t nasm` by default, `-t fasm`); masm is planned. The instruction bodies are the same Intel syntax for both — only the framing (headers, sections, constants, data) differs. The compiler output itself isn't tied to an OS, but the examples and toolchain here target Linux (Linux syscall numbers, ELF64, `ld`). Pipeline: `lex → parse → analyze → emit`. ## A first program @@ -154,6 +154,13 @@ while rcx > 0 } ``` +An optional `.name` right after `while` names the loop's generated labels, so they read as `.name` (top) and `.name_end` (exit) instead of the anonymous `.while_N` — handy for finding a loop in the emitted assembly. Give nested loops distinct names. + +```hdass +while .countdown rcx > 0 // emits `.countdown:` … `jmp .countdown` … `.countdown_end:` + rcx -= 1 +``` + ## Dereference (`^`) `^reg` is the memory at the address in `reg` — NASM's `[reg]`. On the left of `=` it stores there. The store width comes from the value operand, so a sized sub-register picks the size: @@ -262,14 +269,22 @@ See [examples/mandelbrot.hdass](../examples/mandelbrot.hdass) for a float progra ## Building a program ```bash -hdass program.hdass -o program.asm +hdass program.hdass -o program.asm # nasm (default) nasm -f elf64 program.asm -o program.o ld -e main program.o -o program ./program ``` +Or target fasm with `-t fasm`, which assembles in one step: + +```bash +hdass -t fasm program.hdass -o program.asm +fasm program.asm program.o +ld -e main program.o -o program +``` + The [README](../README.md) has a Docker setup with these tools. ## Some stinkies -Clobbering is your responsibility: `syscall` trashes `rcx` and `r11`, while a callee can trash any registers it touches, so nothing is saved automatically. `examples/fibonacci.hdass`, for example, keeps its counter in `r15` for this reason. Register widths must also match, meaning something like `rax = r1.8` would become `mov rax, al`, which will not assemble. Division clobbers extra registers: `/` `%` and their `=` forms use `idiv` through `rax:rdx`, so both are overwritten regardless of the destination. The divisor can be anything — a register, a constant, or an immediate — but an immediate or an `rax`/`rdx` divisor is first copied into `r11`, so those also clobber `r11`. Finally, the entry procedure has no `ret`; it should end with an exit syscall. +Clobbering is your responsibility: `syscall` trashes `rcx` and `r11`, while a callee can trash any registers it touches, so nothing is saved automatically. `examples/fibonacci.hdass`, for example, keeps its counter in `r15` for this reason. Register widths must also match, meaning something like `rax = r1.8` would become `mov rax, al`, which will not assemble. Division clobbers extra registers: `/` `%` and their `=` forms use `idiv` through `rax:rdx`, so both are overwritten regardless of the destination. The divisor can be anything — a register, a constant, or an immediate — but an immediate or an `rax`/`rdx` divisor is first copied into `r11`, so those also clobber `r11`. Labels and procedures become plain assembler symbols, so avoid names the target assembler reserves: `loop`, for instance, is an instruction mnemonic that fasm rejects as a label (nasm allows it). Finally, the entry procedure has no `ret`; it should end with an exit syscall. -- cgit v1.3