4

I was told if I use rsp as a general purpose register the operating system may dump registers to where it points in the case of an interrupt, causing problematic behavior.

Is this true, and if not hence, if I don't need a stack, could I use rsp as a general purpose register?

Edit: Running in user space.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
kvanbere
  • 3,289
  • 3
  • 27
  • 52
  • I believe that is true. Also, where would you store the real rsp value that you need to restore before calling into or returning to the O/S? – 500 - Internal Server Error Mar 05 '14 at 23:00
  • Another register. I would like to be able to use `push`/`pop`/`ret` to interface with a buffer over a long period of time. – kvanbere Mar 05 '14 at 23:02
  • I've used the stack pointer as a data pointer on z80, but I don't see why you couldn't, nor why you should. – Jens Björnhager Mar 05 '14 at 23:24
  • `ret 04` for example has some better performance characteristics (like branch prediction) than `jmp dword ptr [eax+4]`. – kvanbere Mar 05 '14 at 23:49
  • Why do you need rsp as general purpose? It may be possible in some cases but I don't think having one more register help increasing performance much, and will possibly get you into trouble. – phuclv Mar 06 '14 at 00:46
  • It's a really really corner case scenario where the performance boost could be considerable enough to do it, but it's not in the scope of the question to try and explain it here :) – kvanbere Mar 06 '14 at 00:49
  • 1
    You need to clarify the context you're running in. Is it user space? Is it in a privileged or kernel mode? Even in user space, signal handlers may be a problem, as they use the stack space under the x86-64 red zone, requiring a valid rsp. – Brett Hale Mar 06 '14 at 01:28
  • Running in user space. By signal handlers, do you mean linux signal handlers? – kvanbere Mar 06 '14 at 01:44
  • it you use rsp as a GPR then where will you store it value? If you don't store rsp anywhere then how can you restore it when returning to the calling function? – phuclv Mar 06 '14 at 14:33
  • If you need 1 more register, did you try `-fomit-frame-pointer`? – phuclv Mar 06 '14 at 14:34
  • 1
    @BrettHale: Signals can be split into 2 categories - those that should never have existed (because they indicate that the program is buggy and should not be trusted to handle its crashes), and those that should never have existed (because it's better to use a polled approach, like "`get_next_queued_event()`", especially when multiple threads are involved and the signal can interrupt while threads are holding any number of locks/mutexes). ;-) – Brendan Oct 06 '20 at 16:17
  • 1
    @phuclv: store RSP in a global in a single-threaded program, or in a thread-local-storage variable in thread-safe code. (Or in any of XMM0..15 or mm0..7; x86-64 guarantees SSE2... But normally you should just *use* those vector regs alongside 15 integer regs, and leave RSP alone.) – Peter Cordes Oct 06 '20 at 19:32
  • Does this answer your question? [Is ESP as general-purpose as EAX?](https://stackoverflow.com/questions/39339443/is-esp-as-general-purpose-as-eax) – phuclv Oct 06 '20 at 23:32

2 Answers2

5

Aren't you screwed if an interrupt occurs?

Those of you who have programmed in DOS are likely squirming at this point about the possibility of interrupts. Ordinarily, reusing the stack pointer like this is a really bad idea because you have no idea when an interrupt might strike, and when one does, the CPU dutifully pushes the current program counter and flags onto the stack. If you have reused ESP, this would cause random data structures to be trashed. In this kind of environment, ESP must always point to valid and sufficient stack space to service an interrupt, and whenever this does not hold, interrupts must be disabled. Running with interrupts disabled for a long time lowers system responsiveness (lost interrupts and bad latency), and isn't practical for a big routine.

However, we're running in protected mode here.

When running in user space in Win32, interrupts do not push onto the user stack, but onto a kernel stack instead. If you think about it, it isn't possible for the user stack to be used. If the thread were out of stack space, or even just had an invalid stack, when the CPU tried to push EIP and EFLAGS, it would page fault, and you can't page fault in an interrupt handler. Thus, the scheduler can do any number of context switches while a no-stack routine is running, and any data structures that are being pointed to be ESP will not be affected.

From http://www.virtualdub.org/blog/pivot/entry.php?id=85

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
kvanbere
  • 3,289
  • 3
  • 27
  • 52
  • 2
    This is true, but also remember that a signal handler does use the user stack (as mentioned by Brett Hale on the question). Two options to take care of that are block all signals, or set up a custom stack for any unblocked signals. – ughoavgfhw Mar 06 '14 at 05:43
  • How might I setup a custom stack for unblocked signals? – kvanbere Mar 06 '14 at 11:10
  • 3
    Use `sigaltstack` to set up the stack, then when you install handlers use `sigaction` and specify `SA_ONSTACK` in the flags. – ughoavgfhw Mar 06 '14 at 17:16
0

Yes you could under very controlled circumstances, but in practice just use SSE2 and/or MMX instead.


Related: Is it valid to write below ESP? discusses things in Windows that can asynchronously use the stack pointer in 32-bit code. With an invalid stack pointer, those things would crash instead of stepping on space below it. (Or if pointing to writeable memory, use that as stack space.)

In GNU/Linux, signal handlers can asynchronously use the user-space stack pointer, but you can use sigaltstack / SA_ONSTACK to use an alternate stack for them.


Also note that x86-64 guarantees SSE2. You usually only need to consider using RSP as a 16th general-purpose register if you've already used all of xmm0..15 (SSE) and mm0..7 (MMX).

Using ESP as an 8th general-purpose register in 32-bit DSP code for CPUs without MMX made sense sometimes; that's why discussion about it can be found in the context of virtualdub filters.

It generally doesn't make sense in 64-bit code because you always have 16x 128-bit SIMD registers (and SIMD instructions to use on them), as well as more than twice as many non-stack-pointer integer registers. And 8x 64-bit mmx registers, or 8x 80-bit x87 registers, however you want to use them. In most calling conventions, most of these registers are call-clobbered, but you couldn't make function calls with RSP not pointing into the stack anyway.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847