Search code examples
assemblynasmx86-16stack-memory

Popping from stack base


I'm making an operating system for fun, whilist learning more Assembly on the way. I learned about pushing and popping, as I understand, pop takes the value that is on top of any other value on the stack, so it gets the last pushed one. But I wonder, can we actually directly pop the value at the stack base (i.e. the first pushed one)?

Like:

push 'A'
push 'B'
push 'C'

pop bx ; Gets C

Instead of C, I want to get A as an example. (I'm in 16-bit mode, and the assembler is NASM, specified in the tags as well.)


Solution

  • Try to write down the layout of the stack in memory. You'll see that “popping” any element in the middle of the stack would entail shuffling a lot stack elements around in memory. Processors don't have support for that. You can however load any element on the stack into a register at any time without popping it (i.e. it'll still be on the stack afterwards).

    To do so, first copy the stack pointer into some register that can be used for addressing memory (bp is the canonical choice), then access the stack from that.

    mov bp, sp      ; make the stack accessible
    mov bx, [bp+4]  ; load stack element A into bx
    

    Usually, bp is set up as a part of establishing a stack frame for the current function, so you have it always available for accessing the stack. You can also use the registers bx, si, and di, but keep in mind that a ss segment override is needed in that case (it's implicit for bp).

    Now, why do we have to add 4 to get item A? Recall that the stack grows towards lower addresses in memory (i.e. with each push, sp is decreased) and each stack slot occupies 2 bytes of memory in 16 bit mode. So assuming sp = 1000h after your sequence of pushes, we have the following memory layout:

    1004h  A
    1002h  B
    1000h  C  <-- SP
    

    so by simple arithmetic, SP + 4 points at stack slot A and SP + 2 at stack slot B.