Mert Karabulut
Mert Karabulut

Reputation: 13

How to check if the stack is empty on 8086

I am working on a study in Assembler 8086 that checks the balance of the parenthesis in a mathematical expression. The algorithm is as follows:

I have figured out all the parts except the part that I need to check if the stack is empty. How can I check if the stack is empty or how can I create an empty stack in the code? When there is nothing left to pop in the stack, I try to pop it and some value comes out. What does that value mean?

Upvotes: 1

Views: 4361

Answers (1)

Peter Cordes
Peter Cordes

Reputation: 365267

So you want to use the call-stack to implement your stack data structure. This is normal and often a good idea in asm.

You don't want to "empty" the call stack, you just want to set up a way to tell when you've popped all the data you pushed in this function. i.e. that your stack data structure is empty.

Either push a sentinel value that your code doesn't otherwise generate, or use a register (or memory location) to save the current value of SP. Especially in 16-bit code, it's very common to use mov bp,sp to make a stack frame, so you are already dedicating a register to remembering an old value of SP. You can use cmp sp,bp in later code to see if you've emptied your stack data structure.

If you need any space for locals on the stack, you could set up your stack frame with space for locals above BP, and your variable sized stack data below BP.

 my_func:
    ; push  si   ; save whatever other register you want
    sub   sp, 28      ; reserve 28 bytes for locals
    push  bp
    mov   bp, sp

  .my_loop:
    ...                ; use locals from [bp+2] to [bp+26]
    cmp  bp, sp
    jne   .my_loop
    ; else fall through: stack empty

    leave
    add   sp, 28
    ret

If you don't need to spill any local variables to memory at all, then you don't need to make a stack frame and can use bp as an extra scratch register. But if you do, then you can use bp as the top of your stack data structure for free.

Note that it's not quite a traditional stack frame: normally [bp+2] is the return address, so debugger stack backtraces might show bogus results. But [bp+0] is still pointing at the caller's saved bp value, so only that entry will be wrong, and it won't break backtracing through this function.


What would it mean for the call stack to be empty?

There's always memory above ss:sp unless sp = 0xFFFE (2 byte aligned at the top of a segment). pop doesn't even fault if sp wraps around from 0xFFFE to 0x0000. pop [mem] can #GP if popping into memory outside the segment limit of CS, DS, ES, FS, or GS, according to the manual, but I think that's only possible in unreal mode.

push in real-mode does fault with #SS if the new value of sp or esp is outside the stack segment limit (impossible in pure x86-16 without using unreal mode cached segment descriptors loaded in protected mode). Actually I think you could maybe get a #SS in pure real-mode with SP=1 / push ax. The store address would be ss:0xFFFF, and thus the 2-byte store would include memory 1 byte outside the 64k segment starting at ss<<4

Upvotes: 3

Related Questions