Real mode stack

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Lighttec
Posts: 4
Joined: Thu Jun 27, 2013 3:31 am

Real mode stack

Post by Lighttec »

Hi there,

I'm currently following the Babysteps series and have some questions about the stack.
First, in this tutorial (http://wiki.osdev.org/Babystep4) the stack pointer (sp) is initialized with 0x9c00, leaving the stack at 0000:9c00 and the code at 0x7c00.
So far so good, but then it's said, that the stack starts 0x200 (=512) Bytes past the code.
But since the code is 512 Bytes long (bootloader, ends at 0000:7e00), shouldn't the stack pointer be set to 0x8000? (stack size should be 512 Bytes then).
Am I missing something? And is the stack used by the call instruction? (the tutorial says it is left unused)
Is the following stack setup correct (stack size 512 Bytes).

Code: Select all

start:
    ; set up data segment
    mov ax, 0x07c0
    mov ds, ax

    ; set up stack segment and stack pointer
    cli
    mov ss, ax
    mov sp, 0x400
    sti
This should give me the stack at 07c0:0400, right?
Do I have to set up the code segment and base pointer as well?

- Lightec
madanra
Member
Member
Posts: 149
Joined: Mon Sep 07, 2009 12:01 pm

Re: Real mode stack

Post by madanra »

0x9c00 is 2000h past code start - so I expect it's just a typo, and a 0 is missing.
User avatar
Bender
Member
Member
Posts: 449
Joined: Wed Aug 21, 2013 3:53 am
Libera.chat IRC: bender|
Location: Asia, Singapore

Re: Real mode stack

Post by Bender »

The stack is possibly one of the worst (if not the worst) thing in x86. The way it's designed is awkward.
Rants aside, you can place the stack anywhere you want. Provided that it does not collide with your code,
and doesn't interfere with stuff like EBDA, BDA, ROM Area, Video Memory (LOL!) etc. you should be fine.
I recommend to have a stack like this: (Note: Since You're writing a boot sector, you only have 512 bytes, This is my recommendation if you ever develop a future kernel)

Code: Select all

;; Start of Kernel Code
jmp init
;; Reserve 16KB of Stack
EMPTY_SPACE: resb/rb (NASM/FASM Syntax respectively) 1024 * 16
KERNEL_STACK_BUFFER:
init:
;; Initialization Code...
mov e/sp, KERNEL_STACK_BUFFER
.....
It's a safer method as we have 16KB of stack so it'll take some large amount of code to bring it down, even if we have a stack overflow (no pun intended), it won't collide with any important code as all our code is higher than the stack buffer in memory (as stack always goes down).
@mandra: Isn't 0x9C000 greater than 0xFFFF? The OP is in Real Mode. I think *not sure* SS should be 0x9C00 and SP should be 0xFFFF, so the stack will be at 0x9C00:0xFFFF which is a safe place I guess.
"In a time of universal deceit - telling the truth is a revolutionary act." -- George Orwell
(R3X Runtime VM)(CHIP8 Interpreter OS)
tom9876543
Member
Member
Posts: 170
Joined: Wed Jul 18, 2007 5:51 am

Re: Real mode stack

Post by tom9876543 »

Bender wrote:The stack is possibly one of the worst (if not the worst) thing in x86. The way it's designed is awkward.
Really? Why do you say the stack is awkward?????
I am fairly certain the ARM CPUs also have a stack, PUSH, POP. The ARM CPU stack is very similar to the x86 stack.
If x86 and ARM both agree on the stack design (and I also guess other CPUs have similar design), you would have to be wrong.
User avatar
Bender
Member
Member
Posts: 449
Joined: Wed Aug 21, 2013 3:53 am
Libera.chat IRC: bender|
Location: Asia, Singapore

Re: Real mode stack

Post by Bender »

tom9876543 wrote:
Bender wrote:The stack is possibly one of the worst (if not the worst) thing in x86. The way it's designed is awkward.
Really? Why do you say the stack is awkward?????
I am fairly certain the ARM CPUs also have a stack, PUSH, POP. The ARM CPU stack is very similar to the x86 stack.
If x86 and ARM both agree on the stack design (and I also guess other CPUs have similar design), you would have to be wrong.
I have had a lot of bad experiences with the stack during the early stages of my kernel.
I personally don't like the way it's designed, there are security problems like there is no end of stack so it keeps going down, down and down until it collides with something really important and we have a crash.
I also don't like the way it goes down.
I am aware that ARM and other CPUs also have a similar kind of stack.
These are my personal opinions, let's end it here, or we are going to have another
locked thread.
"In a time of universal deceit - telling the truth is a revolutionary act." -- George Orwell
(R3X Runtime VM)(CHIP8 Interpreter OS)
Lighttec
Posts: 4
Joined: Thu Jun 27, 2013 3:31 am

Re: Real mode stack

Post by Lighttec »

okay, thanks.
Bender wrote:
(Note: Since You're writing a boot sector, you only have 512 bytes, This is my recommendation if you ever develop a future kernel)
I thought, although having 512 Bytes for the actual code, I could still use 1MB of RAM (via segment:offset addressing).
(not quite sure if you're refering to the reserved bytes in the kernel file to use for the stack?)

- Lighttec
User avatar
Bender
Member
Member
Posts: 449
Joined: Wed Aug 21, 2013 3:53 am
Libera.chat IRC: bender|
Location: Asia, Singapore

Re: Real mode stack

Post by Bender »

Lighttec wrote:okay, thanks.
Bender wrote:
(Note: Since You're writing a boot sector, you only have 512 bytes, This is my recommendation if you ever develop a future kernel)
I thought, although having 512 Bytes for the actual code, I could still use 1MB of RAM (via segment:offset addressing).
(not quite sure if you're refering to the reserved bytes in the kernel file to use for the stack?)

- Lighttec
Problem is that BIOS only loads 512-bytes of your code in memory.
So if the total size of the binary is 16KB (stack space) + Something (your code), then only the first
512-bytes will be loaded. And the first 3 bytes are a jump to `init` but init is after 16KB, so you'll be jumping
to the address of init, but there will be garbage as the code isn't present.
EDIT: Yes you may use more than 512 bytes of memory, but remember that you must load the rest of the code yourself.
"In a time of universal deceit - telling the truth is a revolutionary act." -- George Orwell
(R3X Runtime VM)(CHIP8 Interpreter OS)
Lighttec
Posts: 4
Joined: Thu Jun 27, 2013 3:31 am

Re: Real mode stack

Post by Lighttec »

Bender wrote: Problem is that BIOS only loads 512-bytes of your code in memory.
So if the total size of the binary is 16KB (stack space) + Something (your code), then only the first
512-bytes will be loaded.
Yeah, I understood that. My question was, if there are any downs on setting the stack up at, say, 16KB past the code (except from overflow).
So something like that:

Code: Select all

mov ss, 0x07c0
mov sp, 0x4000
If I understand the concept correctly, a push instruction would decrease the stack pointer by 4 (2, in 16 bit mode??) and put the value at (now) 07c0:3ffc (07c0:3ffe) and so on.

- Lighttec
alexfru
Member
Member
Posts: 1112
Joined: Tue Mar 04, 2014 5:27 am

Re: Real mode stack

Post by alexfru »

Bender wrote:I think *not sure* SS should be 0x9C00 and SP should be 0xFFFF, so the stack will be at 0x9C00:0xFFFF which is a safe place I guess.
SP should not be 0xFFFF. Make it 0xFFFC, 0xFFFE, or 0 (yep, 0, remember than PUSH first decrements SP and only then writes to memory? So, 0 is good). Make it aligned.
User avatar
Bender
Member
Member
Posts: 449
Joined: Wed Aug 21, 2013 3:53 am
Libera.chat IRC: bender|
Location: Asia, Singapore

Re: Real mode stack

Post by Bender »

Lighttec wrote:
Bender wrote: Problem is that BIOS only loads 512-bytes of your code in memory.
So if the total size of the binary is 16KB (stack space) + Something (your code), then only the first
512-bytes will be loaded.
Yeah, I understood that. My question was, if there are any downs on setting the stack up at, say, 16KB past the code (except from overflow).
So something like that:

Code: Select all

mov ss, 0x07c0
mov sp, 0x4000
If I understand the concept correctly, a push instruction would decrease the stack pointer by 4 (2, in 16 bit mode??) and put the value at (now) 07c0:3ffc (07c0:3ffe) and so on.

- Lighttec
I think the best way to understand how something works is by doing and seeing it yourself:
This DOS program first sets SS to 0x9C00, SP to 0xFFFC (aligned) and then pushes AX, and then pops AX and pushes EAX again.
Image
Since AX is 2-bytes the current stack pointer is decreased by 2, hence 0xFFFF - 2 which is 65533 or 0xFFFD.
When AX is popped the stack pointer is restored to 0xFFFF, and when EAX is pushed the stack pointer is decreased by 4-bytes. (which is 65531)
@alexfru:
SP should not be 0xFFFF. Make it 0xFFFC, 0xFFFE, or 0
Are there any problems with the stack pointer being set to 0xFFFF? Maybe I have overlooked something.
EDIT: As iansjack and alexfru pointed out that using a misaligned stack is not recommended i have updated my example.
Last edited by Bender on Sat Apr 05, 2014 6:54 am, edited 2 times in total.
"In a time of universal deceit - telling the truth is a revolutionary act." -- George Orwell
(R3X Runtime VM)(CHIP8 Interpreter OS)
User avatar
iansjack
Member
Member
Posts: 4711
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Real mode stack

Post by iansjack »

alexfru wrote:
Bender wrote:I think *not sure* SS should be 0x9C00 and SP should be 0xFFFF, so the stack will be at 0x9C00:0xFFFF which is a safe place I guess.
SP should not be 0xFFFF. Make it 0xFFFC, 0xFFFE, or 0 (yep, 0, remember than PUSH first decrements SP and only then writes to memory? So, 0 is good). Make it aligned.
Even allowing for your correction to align the stack correctly, I'm not convinced that it is a good idea to let the stack intrude on the UMA in this way.

In reality you should only need a very minimal stack in real mode, and life gets easier once you get to protected and long modes. There is no problem with the design of the stack in the x86 processors (it's difficult to see how else it could be designed and still retain the same efficiency and functionality); that is not to say that some programmers don't have difficulty in using that design correctly.
User avatar
iansjack
Member
Member
Posts: 4711
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Real mode stack

Post by iansjack »

Bender wrote:
Lighttec wrote:
Bender wrote: Problem is that BIOS only loads 512-bytes of your code in memory.
So if the total size of the binary is 16KB (stack space) + Something (your code), then only the first
512-bytes will be loaded.
Yeah, I understood that. My question was, if there are any downs on setting the stack up at, say, 16KB past the code (except from overflow).
So something like that:

Code: Select all

mov ss, 0x07c0
mov sp, 0x4000
If I understand the concept correctly, a push instruction would decrease the stack pointer by 4 (2, in 16 bit mode??) and put the value at (now) 07c0:3ffc (07c0:3ffe) and so on.

- Lighttec
I think the best way to understand how something works is by doing and seeing it yourself:
This DOS program first sets SS to 0x9C00, SP to 0xFFFF and then pushes AX, and then pops AX and pushes EAX again.
Image
Since AX is 2-bytes the current stack pointer is decreased by 2, hence 0xFFFF - 2 which is 65533 or 0xFFFD.
When AX is popped the stack pointer is restored to 0xFFFF, and when EAX is pushed the stack pointer is decreased by 4-bytes. (which is 65531)
Unfortunately, your example doesn't actually demonstrate where in memory the pushed value is stored; this is important in this context. And you are still using a misaligned stack, which is not good practice.
madanra
Member
Member
Posts: 149
Joined: Mon Sep 07, 2009 12:01 pm

Re: Real mode stack

Post by madanra »

Bender wrote:@mandra: Isn't 0x9C000 greater than 0xFFFF? The OP is in Real Mode. I think *not sure* SS should be 0x9C00 and SP should be 0xFFFF, so the stack will be at 0x9C00:0xFFFF which is a safe place I guess.
In Babystep4 it sets ss:sp to 0000:9c00, which is 2000h above the start of code at 0000:7c00 - ie. there's a missing 0 from the comment (which said 200h), not the code. Sorry, I wasn't completely clear on that!
Lighttec
Posts: 4
Joined: Thu Jun 27, 2013 3:31 am

Re: Real mode stack

Post by Lighttec »

Alright, thank you all!
So basically one has to remember what was pushed onto the stack and what size it was?

As alexfru wrote, one should make it 'align'. What does that mean? Align it to the start of a new segment?

- Lightte
alexfru
Member
Member
Posts: 1112
Joined: Tue Mar 04, 2014 5:27 am

Re: Real mode stack

Post by alexfru »

Bender wrote:I personally don't like the way it's designed, there are security problems like there is no end of stack so it keeps going down, down and down until it collides with something really important and we have a crash.
I also don't like the way it goes down.
Most of hobby code and lots of more serious code (e.g. large commercial software) is bug and security bug ridden, and stack overflows (as in running into heap/static data/code) is only a small part here. Web has given us more things to worry about in terms of security.

Up or down, there isn't that much difference.

You are not required to check for stack overflows, but some compilers offer you options here. You can also use guard pages as a cheap solution that would catch most overflows. You can also use segmentation to limit the range for the PUSH and POP instructions. You can even relocate the whole stack segment when it fills up and expand it. There's a price for every solution/workaround. They cost performance and development time. But you could perhaps just as well write better code (and test it better!) in the first place. If for whatever reason you aren't doing any of the above, who's there to blame? Stack designers? You can overrun buffers in the heap too. Blame heap designers? If you eliminate the entire concept, you're probably going to lose recursion, re-entrant subroutines and a few other things along the way and introduce other problems and bugs. Not a good solution, getting in the way of design of other things. You could also use a VM of sorts. Either way, you need to do something about it, if it is a real problem that you can't just pretend isn't there.
Post Reply