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