2

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

Christian Kuhl
  • 63
  • 1
  • 10
  • I'm guessing that you are mixing 32 and 64 bit architectures. Can you show your compile & link commands? – rodrigo Aug 15 '21 at 17:07
  • 1
    Side-note: I'd recommend always using `.balign` or `.p2align` so there's no ambiguity between 16-byte alignment vs. 2^16 byte. Are you sure the multiboot loader respects alignment the amount of section/segment alignment you're asking for? 16-byte isn't much so I'd hope that would be fine though. – Peter Cordes Aug 15 '21 at 17:45
  • 2
    `mov esp, stack_top` is a load from that address in GAS `.intel_syntax noprefix`, so you're loading whatever garbage was in RAM. It looks like you want `mov esp, OFFSET stack_top`. A debugger should show you that you're getting a totally different ESP value than your symbol addresses. – Peter Cordes Aug 15 '21 at 17:45
  • That is indeed the solution, thank you! That is as embarassing as I'd feared. But if mov esp, stack_top reads from stack_top, and the immediate operand stack_top is designated by the prefix OFFSET, what is the reasoning for mov esp, [stack_top]? – Christian Kuhl Aug 15 '21 at 18:06
  • 1
    Never mind, I just now saw the linked answer, I understood that now. Many thanks! – Christian Kuhl Aug 15 '21 at 18:10

0 Answers0