Scope: the source-header directives that may appear at the top of current Machine
.mnefiles.This guide explains when to use each directive, when not to use it, how directives combine, and what kind of code each combination is meant for.
Machine header directives control different layers of the build pipeline:
-
bin.runtime- controls where runtime support comes from
- tells the compiler to auto-discover Machine runtime files instead of requiring manual runtime copies
-
unsafe.enable- controls whether low-level and dangerous operations are allowed
- allows
unsafe:blocks and unsafe builtins
-
backend.c- selects the C backend
-
backend.x86_64-asm- selects the x86_64 assembly backend
-
target.linux-hosted- selects a normal Linux user-space program
-
target.freestanding-x86_64- selects a freestanding x86_64 target with a lighter runtime model
-
target.baremetal-x86_64- selects a baremetal x86_64 target for boot or kernel-style outputs
Put these directives at the very top of the source file, before normal code.
Recommended order:
bin.runtime
unsafe.enable
backend.x86_64-asm
target.baremetal-x86_64
main:
...
Do not treat them as mandatory boilerplate. Only include the directives the program actually needs.
Use bin.runtime when the program relies on the standard Machine runtime and you want the compiler to find it automatically.
Typical cases:
printalloc_bytesfree_memload_*/store_*mmap_anonfd_open_*,fd_read,fd_write- terminal, time, window, image, or other hosted runtime features
Example:
bin.runtime
main:
print "Hello, Machine"
ret 0
Usually do not rely on bin.runtime for baremetal targets, because baremetal uses its own target-specific runtime sources and linker script.
Use unsafe.enable as soon as the program starts performing raw or dangerous operations.
Typical unsafe builtins include:
ptr_offsetptr_to_i64ptr_from_i64load_u8/u16/u32/u64store_u8/u16/u32/u64volatile_load_*volatile_store_*syscall*mmap_anonioctl_i64- selected CPU, asm, and port-I/O builtins
Example:
bin.runtime
unsafe.enable
main:
unsafe:
var mem: ptr = alloc_bytes(16)
store_u32(mem, 111)
store_u32(ptr_offset(mem, 4), 222)
store_u32(ptr_offset(mem, 8), 333)
print load_u32(mem)
print load_u32(ptr_offset(mem, 4))
print load_u32(ptr_offset(mem, 8))
free_mem(mem)
ret 0
If the program only prints text or uses ordinary high-level features, unsafe.enable is not needed.
Use backend.c when you want to make the backend choice explicit in the source, even though the C backend is usually the default.
Example:
bin.runtime
backend.c
main:
print "use c backend"
ret 0
Use backend.x86_64-asm when you explicitly want the x86_64 assembly backend.
Typical cases:
- backend experimentation
- lower-level runtime work
- freestanding experiments
- baremetal outputs
Example:
bin.runtime
unsafe.enable
backend.x86_64-asm
main:
unsafe:
var pid: i64 = syscall0(39)
print pid
ret 0
For ordinary application programs, the C backend is usually still the simpler default choice.
Use target.linux-hosted when you want to state explicitly that the program is a normal Linux user-space program.
Example:
bin.runtime
backend.c
target.linux-hosted
main:
print "linux hosted"
ret 0
This directive is optional for normal Linux programs because that remains the default target in common workflows.
Use target.freestanding-x86_64 for lower-level x86_64 programs that should avoid the full hosted runtime model.
Example:
unsafe.enable
backend.x86_64-asm
target.freestanding-x86_64
main:
unsafe:
var pid: i64 = syscall0(39)
print pid > 0
print pid
ret 0
Good fit for:
- syscall-focused experiments
- freestanding runtime validation
- lower-level code that is not yet baremetal
Use target.baremetal-x86_64 only when the program is meant for baremetal boot or kernel-style execution.
Typical cases:
- baremetal hello-world outputs
- VGA memory experiments
- paging, GDT, IDT, and interrupt experiments
- QEMU, GRUB, or real boot-chain tests
Example:
unsafe.enable
backend.x86_64-asm
target.baremetal-x86_64
main:
print "Machine baremetal hello"
ret 0
Example with fixed VGA memory writes:
unsafe.enable
backend.x86_64-asm
target.baremetal-x86_64
main:
print "Machine baremetal hello"
unsafe:
var text: ptr = ptr_from_i64(753664)
volatile_store_u16(text, 8013)
volatile_store_u16(ptr_offset(text, 2), 8014)
volatile_store_u16(ptr_offset(text, 4), 8015)
ret 0
Important: do not expect a baremetal target to run as a normal Linux user program with ./program. A baremetal build is not a normal hosted executable.
bin.runtime
main:
print "hello"
ret 0
bin.runtime
unsafe.enable
main:
unsafe:
var mem: ptr = mmap_anon(16)
store_u32(mem, 123)
print load_u32(mem)
munmap_mem(mem, 16)
ret 0
bin.runtime
unsafe.enable
backend.x86_64-asm
main:
unsafe:
var pid: i64 = syscall0(39)
print pid
ret 0
unsafe.enable
backend.x86_64-asm
target.freestanding-x86_64
main:
unsafe:
var pid: i64 = syscall0(39)
print pid > 0
ret 0
unsafe.enable
backend.x86_64-asm
target.baremetal-x86_64
main:
print "baremetal hello"
ret 0
If you just want a normal Linux program, start with:
bin.runtime
If you start using pointers, raw memory, mmap, syscall, volatile, or other low-level builtins, add:
unsafe.enable
If you explicitly want assembly output, add:
backend.x86_64-asm
If the program is not meant for normal Linux execution and should instead target a freestanding or baremetal environment, switch to the matching target.* directive.
They are not. Use the smallest correct set for the current program.
A baremetal build is not a normal Linux hosted executable.
Many raw pointer and memory builtins are intentionally gated behind the unsafe mode.
The C backend is still the simpler and more complete path for many ordinary programs.
Machine now provides two pointer-formatting builtins for address display:
-
ptr_hex(pointer_value)- returns the pointer address as a hexadecimal string
- example output:
0x00007ffd1c2a4b80
-
ptr_bin(pointer_value)- returns the pointer address as a binary string
- example output:
0b000000000000000001111111...
These builtins are meant for low-level inspection, memory-layout experiments, and address tracing.
Use these builtins when you want to:
- inspect stack variable addresses
- inspect heap or
mmapaddresses - compare address spacing in bytes
- display an address in a readable base without manually converting decimal output
Because they expose raw pointer information, they are treated as unsafe builtins.
Use them with:
bin.runtime
unsafe.enable
and place the actual calls inside an unsafe: block.
bin.runtime
unsafe.enable
main:
var x: i64 = 123
unsafe:
print ptr_hex(@x)
ret 0
bin.runtime
unsafe.enable
main:
var x: i64 = 123
unsafe:
print ptr_bin(@x)
ret 0
bin.runtime
unsafe.enable
main:
unsafe:
var mem: ptr = alloc_bytes(16)
print ptr_hex(mem)
print ptr_hex(ptr_offset(mem, 4))
print ptr_hex(ptr_offset(mem, 8))
free_mem(mem)
ret 0
ptr_hex(...)andptr_bin(...)return strings, so they are meant to be used directly withprint.- They do not change the address itself; they only change how the address is presented.
- If you still need the numeric decimal form, continue to use
ptr_to_i64(...).