← Back to context

Comment by musicale

3 days ago

The PL/I stack growing up rather than down reduced potential impact of stack overflows in Multics (and PL/I already had better memory safety, with bounded strings, etc.) TFA's author would probably have appreciated the segmented memory architecture as well.

There is no reason why the C/C++ stack can't grow up rather than down. On paged hardware, both the stack and heap could (and probably should) grow up. "C's stack should grow up", one might say.

> There is no reason why the C/C++ stack can't grow up rather than down.

Historical accident. Imagine if PDP-7/PDP-11 easily allowed for the following memory layout:

    FFFF +---------------+
         |     text      |  X
         +---------------+
         |    rodata     |  R
         +---------------+
         |  data + bss   |  RW
         +---------------+
         |     heap      |
         |      ||       |  RW
         |      \/       |
         +---------------+
         |  empty space  |  unmapped
         +---------------+
         |      /\       |
         |      ||       |  RW
         |     stack     |
    0000 +---------------+

Things could have turned out very differently than they have. Oh well.

  • Nice diagram. I might put read-only pages on both sides of 0 though to mitigate null pointer effects.

Is there anything stopping us from doing this today on modern hardware? Why do we grow the stack down?

  • x86-64 call instruction decrements the stack pointer to push the return address. x86-64 push instructions decrement the stack pointer. The push instructions are easy to work around because most compilers already just push the entire stack frame at once and then do offset accesses, but the call instruction would be kind of annoying.

    ARM does not suffer from that problem due to the usage of link registers and generic pre/post-modify. RISC-V is probably also safe, but I have not looked specifically.

    • > [x86] call instruction would be kind of annoying

      I wonder what the best way to do it (on current x86) would be. The stupid simple way might be to adjust SP before the call instruction, and that seems to me like something that would be relatively efficient (simple addition instruction, issued very early).

      1 reply →

  • Nothing stops you from having upward growing stacks in RISC-V, for example, as there are no dedicated stack instructions.

    Instead of

      addi sp, sp, -16
      sd a0, 0(sp)
      sd a1, 8(sp)
    

    Do:

      addi sp, sp, 16
      sd a0, -8(sp)
      sd a1, -16(sp)