Master the fundamental concepts of build a mini kernel through this focused micro-challenge.
Three hints are available for this task, revealed one at a time inside the code workspace so you can struggle productively before seeing them.
Every task includes starter code, theory, and hidden tests so you can implement and verify locally in the browser.
How it worksOS development targets a bare machine or QEMU, not your host libc. A cross compiler prefixed x86_64-elf-gcc emits freestanding code without linking glibc startup files.
You need:
For example, x86_64-elf-gcc -ffreestanding -c kernel.c avoids host headers while still emitting valid x86-64 objects.
Every real OS project starts with a cross-toolchain: the Linux kernel builds with dedicated cross-compilers for each of its 20+ architectures, and hobby kernels following the OSDev Bare Bones path all begin with i686-elf-gcc. The freestanding flags and linker-script discipline you set up here are the same machinery behind embedded firmware, U-Boot, and Rust's no_std targets.
Before you call the implementation done, walk failure modes on purpose. Test empty structures, single-element edge cases, maximum concurrency, and errno paths that must not crash the program. OS code usually fails in production when happy-path tests pass but invariants break under contention or memory pressure.
Keep structures small and name fields after kernel counterparts when possible. That lets you read man pages and kernel source side by side while you work. Print observable events during development; remove noisy logs once tests pass reliably.
You will verify the toolchain builds a minimal freestanding binary and boots under QEMU. This exercise requires documenting which flags prevent implicit libc linkage.
Every kernel build ends with a linker script that decides where each section lands in memory. A kernel loaded by GRUB must start at 1 MiB, keep its Multiboot header in the first 8 KiB of the file, and have a well-defined entry symbol. Build the part of ld that matters for this: given a small linker script and the section sizes of each object file, lay out the output sections, place every input section, resolve symbols, and print a link map like ld -Map, with the checks a bootloader will make.
cLoading…
. = ADDR; value, and output sections are laid out in script order. Each starts at the counter rounded up to its ALIGN (default 1).object line) order. Every input section starts 4-byte aligned.cLoading…
The discarded lines come after the map, in object/section order. The entry point line follows the symbol it names. bytes in file spans from the start address to the end of the last non-.bss section, since .bss occupies no file space. The remaining bytes up to the end address, including the alignment gap before .bss, are reported as bss.
Input:
cLoading…
Output:
cLoading…
unsigned long and print them with %08lx.Hidden tests cover a Multiboot header placed after a large .text (so it falls outside the first 8 KiB), a missing .multiboot section, an undefined symbol and a missing entry symbol, input sections from several objects interleaved by pattern order, and a load address given in hex.