Forge

x86_64 Linux (ELF64)

Primary target for native 64-bit Linux applications.

Target Triple

x86_64-unknown-linux-gnu

Rust toolchain: x86_64-unknown-linux-gnu (native)

Build

# Native build
cargo build --release

# Or using forgec
./target/release/forgec input.dev -o output --target x86_64-unknown-linux-gnu

Architecture Details

Property Value
Architecture x86-64 (AMD64)
Format ELF64
Endianness Little
Pointer Size 64-bit
Page Size 4 KiB
Calling Convention System V AMD64 ABI

Registers

Register Purpose Saved
RAX Return value / syscall # Volatile
RDI Arg 1 Volatile
RSI Arg 2 Volatile
RDX Arg 3 Volatile
RCX Arg 4 Volatile
R8 Arg 5 Volatile
R9 Arg 6 Volatile
RBX Callee-saved Preserved
RBP Frame pointer Preserved
R12-R15 Callee-saved Preserved
RSP Stack pointer Preserved
RIP Instruction pointer N/A

Calling Convention

System V AMD64 ABI:

Stack Layout

High Address
├── Arguments (if > 6)
├── Return Address
├── Saved RBP
├── Local Variables
├── Red Zone (128 bytes)
└── RSP
Low Address

Syscalls

Linux syscalls via syscall instruction:

Syscall Number Registers
read 0 RDI=fd, RSI=buf, RDX=count
write 1 RDI=fd, RSI=buf, RDX=count
exit 60 RDI=code
mmap 9 RDI=addr, RSI=len, RDX=prot, R10=flags, R8=fd, R9=off
munmap 11 RDI=addr, RSI=len
socket 41 RDI=domain, RSI=type, RDX=protocol
connect 42 RDI=fd, RSI=addr, RDX=addrlen

Bare binary (raw) kernel

A flat x86_64 binary — not an ELF — for freestanding / boot scenarios loaded by a stage-1 boot sector + stage-2 loader that switches the CPU to long mode (see examples/os64). Build it with a custom linker descriptor rather than the --target preset:

./target/release/forgec kernel.dev -o kernel.raw \
    --linker examples/os64/os64-kernel.fld

examples/os64/os64-kernel.fld contains:

ARCH x86_64
FORMAT raw
HOSTED false
ENTRY _start
LOAD 0x100000

Memory model: the image is linked at LOAD (default 0x100000); the stage-2 loader is responsible for placing the bytes there and jumping to ENTRY _start. String literals and other absolute references are fixed up against LOAD, so keep LOAD in sync with where your loader actually maps the image.

The x86_16 stage-2 loader uses the _dev_enter_long_mode builtin to run the whole 16→32→64 switch: A20, GDTs, a 32-bit trampoline that relocates the kernel staging buffer (0x8000→0x100000), 4-level identity page tables, PAE/EFER.LME, and the final jump into long mode — probing CPUID first and printing No 64-bit CPU over COM1 on a 32-bit-only CPU. The freestanding runtime is reference-driven: only the _dev_* helpers the image actually references are emitted (_dev_outb, _dev_inb, _dev_outw, _dev_inw, _dev_outl, _dev_inl, _dev_iret, _dev_sti, _dev_cli, _dev_halt), exposed through std.hal.

Object Format

ELF64 with sections:

Entry Point

Hosted mode: _start (runtime) → calls main(argc, argv)

Freestanding: Custom entry via @freestanding + --freestanding flag

Memory Layout

0x0000000000000000 - 0x00007FFFFFFFFFFF  User space (canonical)
0x00007FFFFFFFFFFF - 0xFFFF800000000000  Non-canonical (hole)
0xFFFF800000000000 - 0xFFFFFFFFFFFFFFFF  Kernel space

Typical process layout:

0x0000000000400000  .text (executable)
0x0000000000600000  .data/.bss
0x00007FFFFFFFxxxx  Stack (grows down)
0x00007FFFF7xxxxxx  Shared libraries

Runtime

Hosted runtime provides:

Standard Library Support

Full support for all modules:

Float Support

Full x87/SSE2 support:

Debugging

# GDB
gdb ./output

# LLDB
lldb ./output

# objdump
objdump -d output | less

# strace
strace ./output

Performance