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
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