x86_64 Target (Linux / QEMU)
The x86_64 target compiles Yog programs to Linux ELF64 executables that make raw syscalls.
- On Linux x86_64: run the binary directly — no emulator, no VM.
- On macOS (Apple Silicon or Intel): run via
qemu-x86_64(user-mode QEMU — translates Linux syscalls to the host OS without a full VM). - On Windows (WSL): run natively inside the WSL2 environment.
This is the fastest target for iterating on Yog programs during development: compile, run, see output — all in your terminal.
Entry Point
x86_64 programs define a single main() function, same as the ARM64 target:
function main(): void {
uart_init(); // no-op on x86_64
uart_print("Hello!\n"); // → write(stdout, ...) syscall
}uart_print maps to the Linux write(2) syscall (fd=1, stdout). uart_init is a no-op — no UART to initialise, stdout is already open.
Compile
yogc --target x86_64 examples/x86_64-hello/main.yog app.elfOutput:
[yogc] OK examples/x86_64-hello/main.yog → app.elf (target: x86_64)
[yogc] 312 bytesRun
Linux x86_64 (native)
chmod +x app.elf
./app.elfmacOS or ARM (user-mode QEMU)
Install QEMU (if not already):
brew install qemuRun the Linux binary:
qemu-x86_64 app.elfqemu-x86_64 intercepts Linux syscalls and forwards them to the macOS kernel — no full VM, no boot time, near-native speed.
Technical Details
Output Format
| Property | Value |
|---|---|
| Format | ELF64 (ET_EXEC) |
| Architecture | EM_X86_64 (0x3E) |
| Load address | 0x400000 |
| Code starts at | 0x400078 (file offset 120 = 64 ELF header + 56 PT_LOAD phdr) |
| Segment | Single PT_LOAD (R|X) from file offset 0 |
Boot Sequence
The Linux kernel loads and maps the ELF file, then jumps to _start:
_start:
call main ; call user's main()
mov edi, 0 ; exit code = 0
mov eax, 60 ; SYS_exit
syscall ; exit(0)Stack Frame Convention
The System V AMD64 ABI requires RSP to be 16-byte aligned before any CALL. Each compiled function follows this pattern:
main:
push rbp ; re-aligns RSP to 16 bytes (CALL pushed return addr)
mov rbp, rsp
; ... body ...
pop rbp
retuart_print Encoding
; uart_print("Hello!\n") expands to:
lea rsi, [rip + <str_offset>] ; 7 bytes — RIP-relative address of string
mov edx, 8 ; 5 bytes — string length
mov edi, 1 ; 5 bytes — stdout fd
mov eax, 1 ; 5 bytes — SYS_write
syscall ; 2 bytesString literals are stored after the code section in the same LOAD segment. LEA RSI, [RIP+disp32] is used to address them position-independently.
Instructions Used
| Instruction | Encoding | Purpose |
|---|---|---|
CALL rel32 | E8 [rel32] (5 bytes) | Call function |
PUSH RBP | 55 (1 byte) | Save frame pointer |
MOV RBP, RSP | 48 89 E5 (3 bytes) | Set up frame |
POP RBP | 5D (1 byte) | Restore frame |
RET | C3 (1 byte) | Return |
MOV EAX, imm32 | B8 [imm32] (5 bytes) | Syscall number |
MOV EDI, imm32 | BF [imm32] (5 bytes) | First argument |
MOV EDX, imm32 | BA [imm32] (5 bytes) | Third argument |
LEA RSI, [RIP+disp32] | 48 8D 35 [disp32] (7 bytes) | String address |
SYSCALL | 0F 05 (2 bytes) | Enter kernel |
Roadmap
- Phase 5+: macOS native target (Mach-O format, BSD syscalls)
- Phase 5+: Windows native target (PE32+ format, Win32 API or NT syscalls)
- Phase 8: LLVM IR backend — delegate to LLVM for full optimisation and all platforms