Search code examples
assemblyx86real-mode

Stack memory layout in 16 bit real mode


I'm playing with real mode bare metal programming using NASM and qemu. I'm trying to understand how stack works and in particular how it's stored in memory.

My code is in a 512 byte boot sector with "magic byte" 0xaa55 at the end and it is loaded at memory address 0x7c00.

I've set the stack base pointer at 0x7cfe. I'm aware that I have to pay attention to not override my code with the stack, but this is not the case. My code only occupies few bytes. This is my code:

[BITS 16]
org 0x7c00

mov bp, 0x7cfe
mov sp, bp

push 'A'

jmp $

times 510-($-$$) db 0
dw 0xaa55

The program sets the stack pointer, pushes the char 'A' into the stack and then it start and infinite loop. I assemble and tun it with the following command:

nasm -f bin boot.asm -o boot.bin
&& qemu-system-i386 -drive file=boot.bin,index=0,media=disk,format=raw -monitor stdio

While the emulator is running I dump the memory in the following way:

qemu> pmemsave 0x7c00 512 medump.bin

When I open the file memdump.bin I see the character 'A' (41 00 since is little endian) at the base address and before (of on top if we think in term of stack) I see a lot of "junk", i.e.:

200: 00 00 00 00 C5 EF 00 00 00 00 00 00 02 02 00 DF 00 00 FE F7
220: 00 00 FE 7C 00 00 BC 93 00 00 00 DF 00 00 60 F8 00 00 00 00
240: 00 00 55 AA 00 00 08 7C 00 00 02 02 41 00 00 00 00 00 00 00

What are those bytes?

If I do not set the stack pointer base all the bytes after the code and before the byte 0xaa55 are zeros.

Could you give any information or at least some pointers?

Thanks


Solution

  • In order to process interrupts the CPU need a properly set stack.
    Just for serving the interrupt by passing control to the ISR (Interrupt Service Routing) the CPU pushes FLAGS, CS and IP.

    The ISR then may, and usually do, need more stack.

    The basic assumption behind the stack is that everything below SS:SP is considered free, available, memory.
    When you set SP to 7cfeh you are just saying that every memory location below 7cfeh is free for other to use as stack memory by others.
    That's the garbage you see.
    Note that the addresses listed as 200, 220 and 240 are below the stack pointer, in my opinion using "on top" for such addresses, while figuratively correct, is a bit confusing.

    If you want to ensure to be the only one messing with the stack, issue a cli as early as possible (and absolutely before setting the stack).
    That suffices in an UP system.


    Edit

    Don't assume SS is zero, set it explicitly, initialize the stack with

    mov ax, <ss_value>
    
    ;cli                    Decomment for very old 8088 compatibility
    
    ;Use these instructions in this order in pair
    ;Interrupts are disabled for 1 inst after mov ss, ...
    mov ss, ax
    mov sp, <sp_value>
    
    ;sti                    Decomment for very old 8088 compatibility