Native Compilation
The subc compiler is SUB's native code generator. It compiles .sb source directly to x86-64 machine code and writes a complete ELF64 executable — no assembler, no linker, no libc required.
Usage
$ subc program.sb -o program
$ ./program
The output is a self-contained static ELF binary, typically a few kilobytes in size.
The Native x86-64 Backend
Unlike traditional compilers that emit assembly text and delegate to an assembler and linker, subc emits machine code bytes directly into memory buffers. The entire compilation pipeline runs in a single process:
- Parse — build the AST from source
- Codegen — walk the AST and emit x86-64 machine code bytes
- ELF emit — write the ELF64 header, program headers, sections, and raw code to disk
Why no assembler? Emitting machine code directly eliminates toolchain dependencies. The resulting binary has zero runtime dependencies — no libc, no dynamic linker, nothing. It just runs.
ELF64 Output Format
The compiler writes a valid ELF64 executable that the Linux kernel can load directly. The ELF structure includes:
| Component | Description |
|---|---|
| ELF header | 64-byte header identifying the file as an x86-64 ELF executable |
| Program headers | LOAD segments for code (text) and data (BSS) |
| Text section | Executable machine code |
| Data section | Read-only data (string literals, constants) |
| BSS section | Uninitialized data (heap, variables) |
| Entry point | Address of the _start routine |
Memory Layout
The compiled binary uses a fixed memory layout:
┌─────────────────────────────────┐ 0x400000
│ .text (code) │ Machine code, read-only, executable
├─────────────────────────────────┤ 0x500000
│ .bss (data) │ Heap + static variables
│ (64 MB bump heap) │
└─────────────────────────────────┘
| Region | Base address | Description |
|---|---|---|
| Text | 0x400000 | Machine code. Loaded as read-only + executable. |
| BSS | 0x500000 | Data segment. Contains the bump-allocator heap. |
| Heap | 0x500000 | 64 MB bump heap for dynamic allocations (strings, arrays, objects). |
Limitation: The 64 MB bump heap is a simple allocator — it does not free memory. This is fine for small programs but means long-running programs with heavy allocation may exhaust the heap. A garbage collector is planned for a future release.
Runtime Routines
Since the compiled binary has no libc, the compiler emits small runtime routines directly into the text section. These handle:
- System calls —
write,read,exit,mmapvia Linuxsyscallinstruction - String operations — concatenation, comparison, length, conversion
- Print routines — integer-to-string, float-to-string, newline output
- Memory management — bump allocator for the heap
- Array/object operations — push, pop, indexing, key lookup
These routines are written in x86-64 machine code and linked directly into every binary. They add only a few hundred bytes to the output.
C Fallback Backend
For platforms where the native x86-64 backend is not available (macOS, Windows, FreeBSD, non-x86 architectures), subc provides a C fallback:
$ subc program.sb --via-c -o program
This mode generates C source code, then invokes the system C compiler (GCC or Clang) to produce the final binary. The C backend is portable and works on any platform with a C compiler.
Tip: The --via-c flag is automatically selected on non-Linux-x86-64 platforms. You only need to specify it explicitly if you want C output on Linux.
How the C fallback works
- Parse the
.sbsource into the AST - Walk the AST and emit C source code to a temporary file
- Invoke
cc(or the compiler specified by$CC) to compile the C file - Link the result into a native binary
- Clean up the temporary C file
Platform Support
| Platform | Native backend | C fallback |
|---|---|---|
| x86-64 Linux | ✓ (direct ELF emission) | ✓ |
| x86-64 macOS | — | ✓ |
| ARM64 macOS | — | ✓ |
| x86-64 Windows | — | ✓ |
| x86-64 FreeBSD | — | ✓ |
| Other | — | ✓ (if C compiler available) |
Binary Size
Compiled SUB binaries are remarkably small because they include only the runtime routines they actually use:
$ subc hello.sb -o hello
$ ls -la hello
-rwxr-xr-x 1 user user 3842 Jan 15 10:30 hello
$ file hello
hello: ELF 64-bit LSB executable, x86-64, statically linked, stripped
A "Hello, World!" program compiles to under 4 KB.
Next Steps
- Transpilation — generate code in 13 languages instead
- Contributing — help add native backends for more architectures