2 ms·
How would it complicate the prologue/epilogue? It would still be push RBP mov RBP, RDSP ; DSP stands for "data-stack pointer" sub RDSP,
by Joker_vD 2y ago
How would it complicate the prologue/epilogue? It would still be
push RBP
mov RBP, RDSP ; DSP stands for "data-stack pointer"
sub RDSP, <frame-size>
... ; locals are [RBP-n], args are [RBP+n]
add RDSP, <frame-size>
pop RBP
ret ; pops address from [RCSP], where CSP stands for "call-stack pointer"
or even, if you don't want a specific base pointer, like this:
sub RDSP, <frame-size>
... ; locals are [RBP+n], args are [RBP+frame_size+n]
add RDSP, <frame-size>
ret
In fact, you can do this even now on x86-64: make a second stack segment, point RBP there, and use RBP as if it were that hypothetical RDSP register. The return addresses naturally go into the RSP-pointed area, as they always did. The only tricky part is when you need to call the code that uses SysV x64 ABI, you'll need to conditionally re-align that RSP-pointed area to be 16-bytes aligned which is a bit annoying (in your own code, having RBP always aligned at 16 bytes is trivial since function calls don't break that alignment).
There are two main benefits of this layout, as I see it: first, smashing the return address is now way harder that it normally is; second, "the act of traversing all call frames on the stack and collecting the return addresses that are stored inside of them" is now trivial, since the call stack at RSP is now just a dense array of just the return addresses, no pointer chasing needed.
- jerf 2y agoAnd Go is already using a non-standard ABI and has to take real action to convert back to standard ABIs if you want to call external code. That's part of why cgo calls are expensive, the other major bit relating to having to interact with OS threads differently than native Go code does.