I'm writing a toy operating system (just for the fun of learning), where I loosely follow the OSDev bare bones tutorial as well as the first edition of "Writing an OS in Rust", but now I seem to have hit a brick wall. The bootimage I'm creating with GRUB is starting up in QEMU successfully, but I then encounter random bugs.
After chasing my own tail for a bit, I realized that the stack pointer I set up is not properly aligned (in fact, in below assembly code, all page table symbols as well as stack_bottom and stack_top end up on the same odd address), so all ret
instructions end up somewhere in Nirvana. This is probably something elementary, but I cannot for the life of me figure out what I'm missing here.
This is my assembly:
.intel_syntax noprefix
.code32
.set ALIGN, 1<<0 /* align loaded modules on page boundaries */
.set MEMINFO, 1<<1 /* provide memory map */
.set FLAGS, ALIGN | MEMINFO /* this is the Multiboot 'flag' field */
.set MAGIC, 0x1BADB002 /* 'magic number' lets bootloader find the header */
.set CHECKSUM, -(MAGIC + FLAGS) /* checksum of above, to prove we are multiboot */
.section .multiboot
.align 4
.long MAGIC
.long FLAGS
.long CHECKSUM
.section .bss
.align 16
p4_table:
.skip 4096
p3_table:
.skip 4096
p2_table:
.skip 4096
stack_bottom:
.skip 4*4096
stack_top:
.section .text
.global _start
.type _start, @function
_start:
mov esp, stack_top
call check_multiboot
[...]
which gets linked with the soon-to-be but momentarily empty Rust kernel via the linker script
ENTRY(_start)
SECTIONS
{
. = 1M;
.text : ALIGN(4K)
{
*(.multiboot)
*(.text)
}
.rodata : ALIGN(4K)
{
*(.rodata*)
}
.data : ALIGN(4K)
{
*(.data)
}
.bss : ALIGN(4K)
{
*(.bss)
*(COMMON)
}
}
The wrong stack pointer alignment is indeed responsible for the bugs I'm encountering, since the call check_multiboot
successfully returns if I nudge esp
to a multiple of 16 in gdb.
But since I'm a noob when it comes to assembly (and linker script for that matter), I'd really appreciate a pointer as to why the alignment is failing here.
Best regards
Christian
EDIT: The solution to this is that mov esp, stack_top
is a read from the address of the label stack_top
in GAS .intel_syntax. What is really needed is mov esp, OFFSET stack_top
.
This is also comprehensively explained here