Reputation: 113
As stated, what software-visible processor state needs to go in a jmp_buf
on an x86-64 processor when setjmp(jmp_buf env)
is called? What processor state does not?
I have been reading a lot about setjmp
and longjmp
but couldn't find a clear answer to my question. I know it is implementation dependent but I would like to know for the x86_64 architecture.
From the following implementation
it seems that on an x86-64 machine all the callee saved registers (%r12-%r15
, %rbp
, %rbx
) need to be saved as well as the stack pointer, program counter and all the saved arguments of the current environment. However I'm not sure about that, hope someone could clarify that for me.
Upvotes: 1
Views: 285
Reputation: 365217
For example, which x86-64 registers need to be saved? What about condition flags? For example, I think the floating point registers do not need to be saved because they don't contribute to the state of the program.
That's because of the calling convention. setjmp
is a function-call that can return multiple times (the first time when you actually call it, later times when a child function calls longjmp
), but it's still a function call. Like any function call, the compiler assumes that all call-clobbered registers have been clobbered, so longjmp
doesn't need to restore them.
So yes, they're not part of the "program state" on a function call boundary because the compiler-generated asm is definitely not keeping any values in them.
You're looking at glibc's implementation for the x86-64 System V ABI, where all vector / x87 registers are call-clobbered and thus don't have to be saved.
In the Windows x86-64 calling convention, xmm6-15 are call-preserved (just the low 128 bits, not the upper portions of y/zmm6-15), and would have to be part of the jmp_buf
.
i.e. it's not the CPU architecture that's relevant here, it's the software calling convention.
Besides the call-preserved registers, one key thing is that it's only legal to longjmp
to a jmp_buf
saved by a parent function, not from any arbitrary function after the function that called setjmp
has returned.
If setjmp
had to support that, it would have to save the entire stack frame, or actually (for the function to be able to return, and that parent to be able to return, etc.) the whole stack all the way up to the top. This is obviously insane, and thus it's clear why longjmp
has that restriction of only being able to jump to parent / (great) grandparent functions, so it just has to restore the stack pointer to point at the still-existing stack frame and restore whatever local variables in that function might have been modified since setjmp
.
(On C / C++ implementations on architectures / calling conventions that use something other than a normal call-stack, a similar argument about the jump-target function being able to return still applies.)
Upvotes: 3
Reputation: 6073
As the jmp_buf
is the only place that can be used to restore processor state on a longjmp
, it's generally everything that is needed to restore the full state of the machine as it was when setjmp
is called.
This obviously depends very much on the processor and the compiler (what exactly does it use of the CPU's features to store program state):
jmp_buff
would also need to store a copy of this zero page (certain 65xx CPUs or ATmel AVR MCUs and their compilers might use this feature)Upvotes: -1