When booting OpenOS with GRUB via ISO, the following errors occurred:
error: no multiboot header found.
error: you need to load the kernel first.
The Multiboot v1 specification (used by GRUB) requires:
Before the fix:
$ readelf -S openos.bin (BEFORE)
[Nr] Name Type Addr Off Size
[ 1] .multiboot PROGBITS 00100000 002720 00000c
[ 2] .text PROGBITS 00000000 000080 0018b6
Problems identified:
.multiboot section was at file offset 0x2720 (10016 bytes) - far beyond the 8KB limit.multiboot had VMA 0x00100000, while .text had VMA 0x00000000ALIGN(4K) between sections, creating a large gap.multiboot was NOT included in any LOAD segment (not loaded into memory)The original linker script:
SECTIONS
{
. = 1M;
.multiboot :
{
*(.multiboot)
}
.text ALIGN(4K) : /* <-- This ALIGN creates a gap! */
{
*(.text*)
}
}
When the linker processes this:
.multiboot at 1M (VMA 0x100000).text to start at a different address (0x0).multiboot has no following sections at 0x100000, it’s not loadedFile: Kernel2.0/linker.ld
SECTIONS
{
. = 1M;
/* Place multiboot header FIRST in .text section */
.text :
{
*(.multiboot) /* Multiboot header comes first */
*(.text*) /* Then all code */
}
.rodata ALIGN(4K) :
{
*(.rodata*)
}
/* ... rest of sections ... */
}
.multiboot section - it’s now part of .text*(.multiboot) before *(.text*)$ readelf -S openos.bin (AFTER)
[Nr] Name Type Addr Off Size
[ 0] .text PROGBITS 00100000 000080 0018c6
[ 1] .rodata PROGBITS 00102000 002080 0006a0
$ readelf -l openos.bin (AFTER)
LOAD 0x000080 0x00100000 0x00100000 0x026a0 0x1079b0
Section to Segment mapping:
00 .text .rodata .bss <-- .text (with multiboot) is now in LOAD segment!
Results:
grub-file --is-x86-multiboot openos.bin returns success ✓An ELF file has this structure:
[ELF Header (52 bytes @ 0x00)]
[Program Headers (LOAD segments)]
[.text section @ 0x80] <-- Multiboot header is here now!
- Multiboot header (12 bytes)
- _start code
- Rest of code
[.rodata section]
[.data section]
[Section Headers]
/* In boot.S */
.set MAGIC, 0x1BADB002 /* Multiboot magic number */
.set FLAGS, ALIGN | MEMINFO /* 0x00000003 */
.set CHECKSUM, -(MAGIC + FLAGS) /* 0xE4524FFB */
.section .multiboot
.align 4
.long MAGIC /* 0x1BADB002 */
.long FLAGS /* 0x00000003 */
.long CHECKSUM /* 0xE4524FFB */
GRUB scans the first 8KB for this pattern:
Offset: 0x80
Bytes: 02 b0 ad 1b 03 00 00 00 fb 4f 52 e4
[ MAGIC ] [ FLAGS ] [CHECKSUM ]
$ grub-file --is-x86-multiboot Kernel2.0/openos.bin
$ echo $?
0 # Success!
$ objdump -h Kernel2.0/openos.bin
Idx Name Size VMA LMA File off Algn
0 .text 000018c6 00100000 00100000 00000080 2**4
$ readelf -l Kernel2.0/openos.bin
LOAD 0x000080 0x00100000 0x00100000 0x026a0 0x1079b0 RWE 0x20
$ hexdump -C Kernel2.0/openos.bin -s 0x80 -n 12
00000080 02 b0 ad 1b 03 00 00 00 fb 4f 52 e4 |.........OR.|
import struct
with open('Kernel2.0/openos.bin', 'rb') as f:
f.seek(0x80)
magic, flags, checksum = struct.unpack('<III', f.read(12))
assert magic == 0x1BADB002, "Wrong magic"
assert flags == 0x00000003, "Wrong flags"
assert checksum == (-(magic + flags) & 0xFFFFFFFF), "Wrong checksum"
assert 0x80 < 8192, "Not within 8KB"
print("✓ All checks passed!")
$ make iso
$ qemu-system-i386 -cdrom openos.iso
# Should boot without "no multiboot header found" error
ALIGN() between multiboot and text sections - it breaks GRUB detectiongrub-file --is-x86-multiboot to verify before testingreadelf -l to ensure section is in LOAD segment❌ Separate .multiboot section with ALIGN(4K) after it
❌ Placing .multiboot at different VMA than .text
❌ Not including .multiboot in any LOAD segment
❌ Assuming linker will “figure it out”
✅ Include .multiboot as first part of .text section
✅ No alignment gap between multiboot and code
✅ Verify with proper tools before testing
The Makefile already uses the correct command:
gcc -T linker.ld -o openos.bin -m32 \
-ffreestanding -nostdlib -static \
-Wl,--nmagic -Wl,-z,noexecstack \
boot.o kernel.o [other objects...]
Key flags:
-T linker.ld: Use our custom linker script-m32: 32-bit x86 target-ffreestanding: Kernel environment-nostdlib: No standard library--nmagic: Don’t align data segments to page boundaries (keeps multiboot close to start)This fix demonstrates why low-level systems programming requires precise understanding of:
Always verify assumptions with tools before assuming the build is correct!