assemblyx86x86-16osdevstack-pointer

Can we set the SP register to 0 in x86 assembly real mode?


I was following a tutorial on operating system development, and as a bit of a fanatic, I came across a line in the code that caught my attention:

bits 16

section _ENTRY CLASS=CODE

extern _cstart_

global entry

entry:
    cli
    mov ax, ds
    mov ss, ax
    mov sp, 0
    mov bp, sp
    sti

    call _cstart_

    cli
    hlt

The stack pointer (SP) is initialized to 0. Won't there be a problem when we make a call (which is essentially a push, so SP would decrement to -1)?

The code runs fine, but I don't get why the stack pointer can be a negative number.


Solution

  • Yes, setting sp to 0 works fine and is fairly common.

    Remember that computers don't inherently see register values as "positive" or "negative"; they're just bits. When sp = 0 and you execute a near call or a push, then sp is decremented by 2 (not 1 - remember that we are pushing 2-byte words), and the resulting value in sp is the address for the store.

    Under the normal rules of 16-bit two's complement arithmetic, 0 - 2 = 0xfffe; i.e. it wraps around mod 2^16. A borrow occurs, but it is ignored here. (sub sp, 2 would set the carry flag CF to indicate the borrow, but the arithmetic done by stack manipulation instructions doesn't touch FLAGS.)

    If you think of 0xfffe as a signed quantity, then yes, it is the number -2, but we think of addresses as unsigned.

    So, the effect of mov sp, 0 is to locate the stack at the very top of the ss segment.