-
Notifications
You must be signed in to change notification settings - Fork 0
toolchain and build
The exact tools, flags, and Make targets that turn source into a bootable disk image.
MyOS-Simple builds a freestanding 32-bit (i386) image with a small, standard toolchain
and no cross-compiler. This page is the authoritative reference for the tools, the exact
flags, the build pipeline, and every Make target. For step-by-step instructions see the
building-and-running guide.
| Tool | Role | Stage Makefile invocation |
|---|---|---|
nasm |
Assemble the boot sector (flat binary) and the 32-bit kernel entry stub |
nasm -f bin / nasm -f elf32
|
gcc |
Compile the freestanding C kernel (needs -m32 multilib) |
gcc $(CFLAGS) |
ld (binutils) |
Link the kernel to its fixed load address | ld -m elf_i386 -T linker.ld |
make |
Drive each stage's build | — |
| coreutils |
cat to concatenate, truncate to pad the image |
cat … > img; truncate -s … |
qemu-system-x86 |
Boot the raw disk image | qemu-system-x86_64 -drive … |
The tree is verified known-good against these versions; older/newer generally work.
| Component | Version tested |
|---|---|
| nasm | 2.16.01 |
| gcc | 13.3.0 (with -m32 multilib) |
| ld | 2.42 (GNU Binutils) |
| qemu | 8.2.2 (qemu-system-x86_64) |
| make | 4.3 |
From each C stage's Makefile:
-m32 -ffreestanding -fno-pic -fno-pie -nostdlib -nostdinc \
-fno-builtin -fno-stack-protector -nostartfiles -nodefaultlibs \
-Wall -Wextra -c| Flag | Why |
|---|---|
-m32 |
Emit 32-bit (i386) code, not 64-bit |
-ffreestanding |
No hosted C runtime; main is not special — see freestanding C
|
-fno-pic / -fno-pie
|
No position-independent code; the kernel runs at a fixed address |
-nostdlib / -nodefaultlibs
|
Do not link the standard library |
-nostdinc |
Do not search system include paths (no libc headers) |
-fno-builtin |
Do not assume libc semantics for memcpy, strlen, etc. |
-fno-stack-protector |
No __stack_chk_* symbols (there is no libc to provide them) |
-nostartfiles |
No crt0 startup objects; the asm stub is the entry |
-Wall -Wextra |
Maximum warnings |
-c |
Compile to object only; link separately |
| Step | Command | Output |
|---|---|---|
| Boot sector | nasm -f bin boot.asm -o boot.bin |
Flat binary (no headers) |
| Kernel entry stub | nasm -f elf32 kernel_entry.asm -o kernel_entry.o |
ELF32 object |
| C sources | gcc $(CFLAGS) file.c -o file.o |
ELF32 objects |
| Link | ld -m elf_i386 -T linker.ld -o kernel.bin *.o |
Kernel binary at load address |
The boot sector is -f bin (raw bytes the BIOS executes directly), while the kernel is
ELF32 so the linker script can place sections.
cat boot.bin kernel.bin > image.img # boot sector first, then kernel
truncate -s <SIZE> image.img # pad to a whole number of sectors| Stage | Directory | Sectors loaded by boot.asm
|
truncate -s |
|---|---|---|---|
| 2 | helloworld-os-c |
16 | 10240 (20 sectors) |
| 3 | os-c-with-shell |
15 | 10240 (20 sectors) |
| 4 | helloworld-os-c-v2 |
39 | 20480 (40 sectors) |
| 5 | helloworld-os-c-v3 |
39 | 20480 (40 sectors) |
The boot sector sits at 0x7C00; the kernel is read to 0x1000
starting at CHS sector 2 (sector numbering is
1-based, so the boot sector is sector 1 and the kernel begins at sector 2).
boot.asm --nasm -f bin--> boot.bin --+
|--cat--> image.img --truncate--> padded image
kernel_entry.asm --nasm -f elf32--+ |
*.c --gcc -m32 -c--> *.o -------+--ld--> kernel.bin --+
| Target | Effect | Stages |
|---|---|---|
make |
Build the bootable image(s) | All |
make run |
Boot the primary image: qemu-system-x86_64 -drive format=raw,file=IMG
|
All |
make run-simple |
Boot the pure-assembly "simple" image | C stages (2–5) |
make run-color |
Boot the color/keyboard variant | Stage 1 only |
make debug |
Boot under QEMU with a GDB stub: adds -s -S (TCP :1234, CPU halted at reset) |
C stages (2–5) |
make clean |
Remove build artifacts (*.bin *.o *.img) |
All |
make help |
List available targets | All |
| Flag | Meaning |
|---|---|
-s |
Shorthand for -gdb tcp::1234 — open a GDB stub on port 1234 |
-S |
Freeze the CPU at reset; do not start executing until a debugger says continue
|
Connect with gdb, then target remote :1234. See the
debugging guide.
MyOS-Simple is released under the MIT License (see LICENSE).
💡 Tidbit:
truncate -s 10240produces exactly 20 sectors of 512 bytes. The pad matters because the bootloader'sint 0x13read asks for a fixed sector count; if the image file is shorter than that, QEMU's emulated disk read can fail or return zeros for the missing tail.
⚠️ Caveat: On a 64-bit host, plaingcccannot produce a working-m32object without the 32-bit multilib (gcc-multilibon Debian/Ubuntu,glibc-devel.i686on Fedora,lib32-glibcon Arch). Missing it yields crypticbits/libc-header-start.hor linker errors — see troubleshooting.
💡 Tidbit: The boot sector is assembled with
-f bin, not ELF, because the BIOS loads and jumps to raw bytes — there is no loader to parse an ELF header at0x7C00. The kernel can afford ELF only becauseldresolves it into a flat layout first.
- Building and running — the how-to guide
-
Debugging with GDB — using
make debug - Troubleshooting — multilib and image-size errors
-
Linker scripts —
linker.ldand section placement - Freestanding C — why the flags above
- Disk loading via int 0x13 — sectors and CHS
- Memory map — where the loaded image lands
- Glossary
- Home
Stages
- 1 · Assembly boot
- 2 · C protected mode
- 3 · Interactive shell
- 4 · Clock / processes / calc
- 5 · Stabilized release
Concepts — boot
Concepts — protected mode
Concepts — hardware
Concepts — OS services
Reference
- Memory map
- I/O ports
- GDT descriptor format
- Scancode tables
- Command reference
- Toolchain & build
- Glossary
Guides