kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

commit fcdfd6add1105d14982e257898aae2672d94cfbf
parent b2ebc0984197454989a89dea2ea161ae00896d4f
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Tue, 16 Jun 2026 11:24:06 -0700

Document kernel image build roadmap

Diffstat:
Adoc/plan/KERNEL.md | 373+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdoc/plan/README.md | 1+
2 files changed, 374 insertions(+), 0 deletions(-)

diff --git a/doc/plan/KERNEL.md b/doc/plan/KERNEL.md @@ -0,0 +1,373 @@ +# Kernel build and image pipeline + +This roadmap tracks the work needed for kit to build freestanding kernels from +C and assembly sources and emit kernel images that can be passed to QEMU's +direct loaders. It deliberately does not cover VM execution, bootloader +generation, UEFI application layout, or kit-provided startup code. Kernel +startup, privilege-mode entry, page-table setup, stack setup, TLS setup, and +boot-protocol compliance are the kernel author's responsibility. + +Related: [../DRIVER.md](../DRIVER.md), [../LINK.md](../LINK.md), +[../OBJ.md](../OBJ.md), [../RUNTIME.md](../RUNTIME.md), +[LINKER-COMPAT.md](LINKER-COMPAT.md), [PORT.md](PORT.md). + +## Scope + +The supported path is: + +``` +C / asm sources + objects + archives + -> kit build-obj / build-exe + -> freestanding static kernel ELF + -> kit image / objcopy + -> ELF / flat binary / ROM-style payload / section-concatenated payload +``` + +The first targets are freestanding ELF: + +- `x86_64-none-elf` +- `aarch64-none-elf` +- `riscv64-none-elf` +- `riscv32-none-elf` + +The output artifacts should be usable with QEMU features such as `-kernel`, +`-bios`, or `-device loader,file=...`, depending on the target machine and the +kernel's own entry contract. Kit should not decide or implement the boot +protocol. + +## Current baseline + +Useful pieces already exist: + +- `build-obj` compiles C / asm / toy / wasm sources into objects, and can combine + multiple source objects with `ld -r`. +- `build-exe` compiles a source set and links it with object/archive inputs. +- Freestanding triples resolve to non-PIE ELF/WASM targets by default. +- `build-*` already accepts common freestanding and link flags such as + `-ffreestanding`, `-nostdinc`, `-nostdlib`, `-nodefaultlibs`, + `-nostartfiles`, `-static`, `-pie`, `-no-pie`, `-mcmodel=...`, `-T`, `-e`, + `-Wl,...`, `--build-id=...`, `-ffunction-sections`, and `-fdata-sections`. +- The linker has a structured linker-script subset with section placement, + symbol assignment, `/DISCARD/`, and `KEEP` roots for `--gc-sections`. +- The runtime provides freestanding headers and compiler-runtime-style support, + but no `crt0`. +- `objcopy` can transform object files and rewrite sections/symbols, but does + not yet expose raw binary image output. + +The desired user-facing build shape stays on the existing tools: + +``` +kit build-exe -target x86_64-none-elf \ + -ffreestanding -nostdlib -static -no-pie \ + -mcmodel=kernel -mno-red-zone \ + -ffunction-sections -fdata-sections \ + -T kernel.ld -e _start \ + -Wl,--gc-sections \ + --map kernel.map \ + --symbols kernel.sym \ + -o kernel.elf \ + boot.S kernel.c mm.c +``` + +## Compile and build-driver support + +Do not add a separate `kit kernel compile` command. Keep `build-obj` and +`build-exe` as the compile/link front doors, and make their flag surface complete +enough for kernel authors. + +Required flag support and behavior: + +- `-ffreestanding` / `-fhosted`: select freestanding vs hosted assumptions, + including whether sysroot-hosted profiles may be engaged. +- `-nostdinc`: suppress all implicit non-resource include paths while still + allowing explicit `-I` / `-isystem`. +- `-nostdlib`, `-nodefaultlibs`, `-nostartfiles`: precisely control runtime + archive and hosted CRT/libc insertion. No startup object is ever invented by + kit for a freestanding kernel. +- `-static`, `-no-pie`, `-fno-pic`, `-fno-pie`: produce static non-PIE kernel + code and an ET_EXEC-style image unless the user deliberately opts into PIC/PIE. +- `-mcmodel=...`: keep existing model selection and add kernel-relevant aliases + where the target backend has meaningful behavior. +- `-mno-red-zone`: disable the x86_64 SysV red zone for kernel code. This must + affect backend frame selection, not merely be accepted as syntax. +- `-mgeneral-regs-only` or equivalent target-feature spelling: give kernels a + straightforward way to prevent accidental SIMD/FP codegen where an ABI or + privilege-mode context does not save those registers. +- `-fno-builtin`: accept in `build-*` and ensure the C frontend does not turn + freestanding source into calls or assumptions the kernel did not request. +- `-fno-stack-protector` / `-fstack-protector*`: either implement the supported + subset or reject unsupported modes explicitly. Silently ignoring stack + protector policy is not acceptable for kernels. +- `-ffunction-sections` and `-fdata-sections`: compose with linker + `--gc-sections` and script `KEEP`. +- `--group`: continue to scope include/define/language/frontend flags to source + subsets; do not let link-wide kernel policy drift into per-source groups. + +Driver parity to improve: + +- Accept common direct linker flags in `build-exe` where `ld` already accepts + them, instead of requiring every flag to pass through `-Wl,`. +- Keep `cc`, `ld`, and `build-exe` behavior aligned by routing shared policy + through `driver/lib/link_flags.*` and `driver/lib/target.*`. +- For freestanding executable links, default diagnostics should be strict: + unresolved symbols and dynamic-link artifacts should be errors unless the user + explicitly requests an escape hatch. + +## Linker work + +### Linker-script subset + +Kernel links need a larger structured GNU-ld-compatible subset. The goal is not +to interpret arbitrary linker scripts blindly, but to support the constructs +needed for deterministic kernel memory layouts with precise diagnostics. + +Add support for: + +- `MEMORY` with `ORIGIN`, `LENGTH`, attributes, and region-overflow diagnostics. +- Output section placement into memory regions with `> REGION`. +- Load-memory placement with `AT(expr)` and `AT> REGION`, so VMA/LMA split + kernels can be represented. +- `PHDRS`, `:phdr`, `FLAGS(...)`, and `FILEHDR` / `PHDRS` segment attributes, + so kernels can control program headers and segment permissions. +- `PROVIDE`, `PROVIDE_HIDDEN`, and `HIDDEN`. +- `ASSERT(expr, "message")`. +- `EXTERN(symbol)` as a GC root and undefined-symbol declaration. +- Richer input section patterns: `*(.text .text.*)`, file-qualified patterns, + and `EXCLUDE_FILE`. +- Section fills: `=0x...` and `FILL(...)`. +- Alignment and address helpers: `ALIGN`, `SUBALIGN`, `BLOCK`, `ADDR`, + `LOADADDR`, `SIZEOF`, `SIZEOF_HEADERS`, `DEFINED`, and `ABSOLUTE`. +- `OUTPUT_ARCH` and `OUTPUT_FORMAT` as validation directives initially. They do + not need to drive target selection in the first pass, but mismatches should be + reported clearly. + +Existing `KEEP(...)` support must continue to interact correctly with +`--gc-sections`. + +### Link output side files + +Add linker-produced side outputs, available from both `ld` and `build-exe`: + +- `--map FILE`: write a deterministic link map. +- `--symbols FILE`: write post-link absolute symbols. +- `--symbols-format=nm|json`: start with an nm-like text format; JSON can land + once the data model is stable. +- `--cref FILE`: optional cross-reference table. +- `--print-memory-usage`: summarize `MEMORY` regions once linker-script memory + regions exist. + +The link map should include: + +- target triple and output kind, +- entry symbol and address, +- memory regions and usage, +- program headers / segments, +- output sections with VMA, LMA, file offset, size, and alignment, +- input object/archive-member contributions, +- linker-defined symbols, +- discarded sections, +- unresolved symbols, +- section-GC roots and discarded-reason details where practical. + +### Linker flags and policy + +Add or normalize: + +- `--no-undefined`: reject unresolved symbols for executable/freestanding links, + not only shared-library output. +- `--allow-undefined`: explicit escape hatch. +- `--defsym name=expr`. +- `--section-start=.name=addr`. +- `-Ttext`, `-Tdata`, and `-Tbss` through `build-exe` as well as `ld`. +- `--orphan-handling=place|warn|error|discard`. +- `--fatal-warnings`. + +Freestanding kernel validation should reject, by default: + +- DSO inputs, +- dynamic interpreter paths, +- dynamic sections and PLT/GOT imports, +- unresolved relocations, +- missing entry symbols when `-e` or `ENTRY(...)` names one, +- target/object-format mismatches across inputs. + +## Image command + +Add a new `kit image` command for kernel-image emission. Also add a minimal +`objcopy -O binary` path for compatibility, backed by the same lower-level image +emitter. + +`objcopy` should remain an object transformer: + +``` +kit objcopy -O binary kernel.elf kernel.bin +``` + +`kit image` should own image-building policy: + +``` +kit image --format bin kernel.elf -o kernel.bin + +kit image --format bin --from segments --segment PT_LOAD \ + --addr paddr --base 0x80000000 --fill 0x00 --align 4096 \ + --pad-to 2M --max-size 8M \ + --metadata kernel.image.json \ + kernel.elf -o kernel.bin +``` + +### Image formats + +- `elf`: copy, normalize, strip, or split-debug an existing linked ELF. +- `bin`: flat binary derived from loadable segments or selected sections. +- `rom`: flat fixed-size binary with fill, padding, max-size checks, and later + optional checksum hooks. +- `sections`: concatenate explicitly named sections in user-specified order. + +Optional later embedded formats, such as Intel HEX, S-record, or UF2, are out of +the first kernel-focused pass. + +### Image flags + +Selection: + +- `--from=segments|sections` +- `--segment=PT_LOAD` (repeatable) +- `--only-section NAME` (repeatable) +- `--remove-section NAME` (repeatable) +- `--section NAME` (repeatable; explicit order for `--format sections`) + +Addressing: + +- `--addr=vaddr|paddr|lma` +- `--base ADDR` +- `--bias N` + +Holes and layout: + +- `--fill BYTE` +- `--fail-on-holes` +- `--max-hole SIZE` +- `--align N` +- `--pad-to SIZE` +- `--max-size SIZE` + +ELF/debug: + +- `--strip-debug` +- `--split-debug FILE` +- `--keep-symbols` + +Validation: + +- `--require-entry` +- `--require-symbol NAME` (repeatable) +- `--require-section NAME` (repeatable) +- `--no-dynamic` + +Reporting: + +- `--metadata FILE`: write a deterministic JSON sidecar containing target, + object format, entry, build id, selected segments/sections, source ranges, + output ranges, base/bias/fill policy, and warnings. + +### Image semantics + +Segment-based flat image emission should: + +- read loadable ranges from program headers, +- sort by selected address kind, +- detect overlaps, +- fill or reject holes according to policy, +- derive output offsets from `base` / lowest selected address, +- preserve bytes exactly as they would be loaded, +- include NOBITS memory ranges in metadata but not necessarily in output bytes + unless a selected format requires padding. + +Section-based emission should: + +- operate on named sections in declared order, +- reject missing sections unless a permissive option is added later, +- concatenate section bytes exactly, +- make address metadata explicit so users do not confuse section concatenation + with a loadable memory image. + +ROM-style emission should: + +- require an explicit size or `--pad-to`, +- fill unused bytes deterministically, +- fail when selected payload bytes exceed the requested size, +- leave target-specific checksums or reset-vector conventions as future, + explicit options. + +## Implementation shape + +Add a shared image-emission layer rather than burying policy in `objcopy`: + +``` +driver/cmd/image.c CLI policy for kit image +driver/cmd/objcopy.c simple -O binary compatibility path +include/kit/image.h public image-emission API, if we want embedders to use it +src/api/image.c public wrapper +src/obj/image.c object/ELF-to-image implementation +``` + +The image API should consume already-read object bytes or an opened `KitObjFile` +view, plus explicit options. It should not read the filesystem directly and +should not run QEMU or inspect host bootloader installs. + +Map/symbol side outputs should be linker-owned rather than image-owned. The +image metadata file can reference link-map facts, but it should be a report about +the image transform, not a replacement for `--map`. + +## Phasing + +1. **Raw binary baseline** + - Add `objcopy -O binary`. + - Add `kit image --format bin --from segments`. + - Support `--base`, `--fill`, `--fail-on-holes`, `--pad-to`, `--max-size`. + - Add focused ELF fixtures for x64, aa64, rv64, and rv32. + +2. **Build/link parity for kernels** + - Add missing `build-exe` direct flag parity with `ld`. + - Add `-mno-red-zone`, `-mgeneral-regs-only`, builtin policy, and stack + protector policy. + - Add strict freestanding undefined/dynamic-artifact diagnostics. + +3. **Link map and symbols** + - Add `--map FILE`. + - Add `--symbols FILE`. + - Add deterministic tests for section layout, symbols, and discarded + sections. + +4. **Script growth** + - Add `MEMORY`, region placement, VMA/LMA split, and region overflow checks. + - Add `PHDRS` once memory regions are stable. + - Add `ASSERT`, `PROVIDE`, `EXTERN`, richer input patterns, and orphan + handling. + +5. **Image formats beyond bin** + - Add `--format sections`. + - Add `--format rom`. + - Add `--metadata FILE`. + - Add `--format elf` normalization/strip/split-debug behavior if it proves + cleaner than routing those cases through `objcopy` and `strip`. + +## Acceptance criteria + +For each first-pass freestanding target, kit should be able to: + +- compile a kernel source set containing C and assembly with `build-exe`, +- link it with a kernel-owned startup object and linker script, +- emit a static freestanding ELF with a deterministic layout, +- produce a link map and absolute-symbol side file, +- convert the ELF to a flat binary image, +- validate that the ELF/image has no accidental dynamic-loader dependencies, +- reproduce byte-identical outputs from identical inputs and options. + +The validation suite should stay targeted: + +- one small kernel-link fixture per architecture, +- one script-layout fixture per linker-script feature, +- one image-conversion fixture per image format and hole policy, +- negative tests for unresolved symbols, region overflow, dynamic artifacts, and + overlapping image ranges. diff --git a/doc/plan/README.md b/doc/plan/README.md @@ -18,6 +18,7 @@ shrinks to whatever remains open. | [LEX-PP-API.md](LEX-PP-API.md) | Redesigning the lexer -> preprocessor -> parser boundary around lean tokens, lazy spelling/location materialization, and slot-based handoffs for a high-performance lexer/preprocessor rewrite without frontend layer fusion. | [../FRONTENDS.md](../FRONTENDS.md) | | [LINKER.md](LINKER.md) | Incremental linking: the file-based object-link redesign and remaining non-ELF format coverage. | [../LINK.md](../LINK.md) | | [LINKER-COMPAT.md](LINKER-COMPAT.md) | Completing system-linker compatibility across the support set: ordered DSO selection, ELF TLS/TLSDESC, shared libraries, relocatable links, runtime/sysroot interoperability, and Rust/toolchain validation. | [../LINK.md](../LINK.md), [../OBJ.md](../OBJ.md), [../DRIVER.md](../DRIVER.md) | +| [KERNEL.md](KERNEL.md) | Freestanding kernel build and image pipeline: build-obj/build-exe support, linker-script growth, map/symbol side outputs, and image emission via kit image / objcopy -O binary. | [../DRIVER.md](../DRIVER.md), [../LINK.md](../LINK.md), [../OBJ.md](../OBJ.md), [../RUNTIME.md](../RUNTIME.md) | | [JIT.md](JIT.md) | Function-level hot reload, Go-runtime-style codegen support, and remaining JIT host-portability work. | [../JIT.md](../JIT.md) | | [DEBUG.md](DEBUG.md) | The Windows debugger host adapter, x64/rv64 displaced single-step, profiling, and DWARF gaps. | [../DBG.md](../DBG.md), [../DWARF.md](../DWARF.md) | | [INSTRUMENT.md](INSTRUMENT.md) | Debugging/profiling tools in the Valgrind/callgrind/asan/ubsan tradition: the emulator as a dynamic-binary-instrumentation substrate (the `EmuToolHooks` ABI, shadow planes, the memory seam, a guest debugger), plus the cross-frontend compiler-sanitizer story. | [../EMU.md](../EMU.md) |