setjmp,longjmp, sigsetjmp implementation

B

Borneq

Where I can find setjmp,longjmp, sigsetjmp implementation? In GCC source I
can't find.
 
B

Borneq

Uzytkownik "Noob said:

This call low level functions, longjmp.c :

#include <setjmp.h>
void
__libc_siglongjmp (sigjmp_buf env, int val)
{
/* Perform any cleanups needed by the frames being unwound. */
_longjmp_unwind (env, val);

if (env[0].__mask_was_saved)
/* Restore the saved signal mask. */
(void) __sigprocmask (SIG_SETMASK, &env[0].__saved_mask,
(sigset_t *) NULL);

/* Call the machine-dependent function to restore machine state. */
__longjmp (env[0].__jmpbuf, val ?: 1);
}

longjmp_unwind ,__sigprocmask, __longjmp are in other library? In assembly?
 
J

Johann Klammer

BartC said:
Noob said:
1) tar xjf glibc-2.16.0.tar.bz2
2) grep -rn __longjmp glibc-2.16.0

e.g.
http://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/i386/__longjmp.S

This is not C. In that case why does it need to be that complicated? I
used to do this in just 3 instructions:

mov esp,[spsave]
mov ebp,[bpsave]
jmp [....]

It worked.

Doesn't the whole machine state have to be
saved/restored(registers/Fp/SSE/flags etc)? What if the calling function
was using some regs for local vars etc ?!...
 
N

Nobody

Doesn't the whole machine state have to be
saved/restored(registers/Fp/SSE/flags etc)?
No.

What if the calling function was using some regs for local vars etc ?!...

7.13.2.1p3:

All accessible objects have values as of the time longjmp was
called, except that the values of objects of automatic storage
duration that are local to the function containing the
invocation of the corresponding setjmp macro that do not have
volatile-qualified type and have been changed between the
setjmp invocation and longjmp call are indeterminate.

gcc will warn about such cases with e.g.:

warning: variable ‘foo’ might be clobbered by ‘longjmp’ or ‘vfork’

Typically, only the "essential" registers (program counter, stack pointer,
frame pointer) are preserved. Registers holding local variables or
intermediate results aren't required to be preserved (and usually aren't).
"Global" state isn't modified by longjmp and, AIUI, that includes the FP
environment (<fenv.h>).
 
J

Johann Klammer

Nobody said:
7.13.2.1p3:

All accessible objects have values as of the time longjmp was
called, except that the values of objects of automatic storage
duration that are local to the function containing the
invocation of the corresponding setjmp macro that do not have
volatile-qualified type and have been changed between the
setjmp invocation and longjmp call are indeterminate.

gcc will warn about such cases with e.g.:

warning: variable ‘foo’ might be clobbered by ‘longjmp’ or ‘vfork’

Typically, only the "essential" registers (program counter, stack pointer,
frame pointer) are preserved. Registers holding local variables or
intermediate results aren't required to be preserved (and usually aren't).
"Global" state isn't modified by longjmp and, AIUI, that includes the FP
environment (<fenv.h>).

That is Interesting, as I do remember that the gcc variant for atmel's
avr uCs _did_ save/restore all 32 general purpose registers in addition
to SP/PC. At that time I was wondering why the jmp_buf thingy would take
up so much memory. But then, avr-gcc does allow the user to reserve
registers for global variables which would make this behavior necessary
to preserve global objects...
 
E

Eric Sosman

s/No/Maybe/


7.13.2.1p3:

All accessible objects have values as of the time longjmp was
called, except that the values of objects of automatic storage
duration that are local to the function containing the
invocation of the corresponding setjmp macro that do not have
volatile-qualified type and have been changed between the
setjmp invocation and longjmp call are indeterminate.

gcc will warn about such cases with e.g.:

warning: variable ‘foo’ might be clobbered by ‘longjmp’ or ‘vfork’

Typically, only the "essential" registers (program counter, stack pointer,
frame pointer) are preserved. Registers holding local variables or
intermediate results aren't required to be preserved (and usually aren't).
"Global" state isn't modified by longjmp and, AIUI, that includes the FP
environment (<fenv.h>).

The "essential" state may also include "general-purpose"
registers designated by function linkage conventions. For example,
if the rule is that a function is free to clobber R0-R7 but must
return with R8-RF unchanged (i.e., it must save and restore R8-RF
if it wants to use them), then R8-RF are "essential" from the point
of view of the calling convention:

f1(): Saves R8, puts 42 in it, calls f2()

f2(): Doesn't use R8, calls setjmp(), calls f3()

f3(): Saves R8, puts -137 in it, calls longjmp()

f2(): On setjmp()'s second return, returns to f1()

f1(): "Gee, I hope R8 still holds 42 ..."

f3() would have restored R8, but longjmp() blew right past that
code. f2() never touched R8, and so has no reason to restore it.
The upshot is that f1() -- a function that never called either
setjmp() or longjmp(), nor even knew anybody else was using
them! -- gets trashed if setjmp()/longjmp() fail to save and
restore R8-RF.
 
B

BartC

Johann Klammer said:
BartC wrote:

This is not C. In that case why does it need to be that complicated? I
used to do this in just 3 instructions:

mov esp,[spsave]
mov ebp,[bpsave]
jmp [....]

It worked.

Doesn't the whole machine state have to be
saved/restored(registers/Fp/SSE/flags etc)? What if the calling function
was using some regs for local vars etc ?!...

I assume by 'calling function' you mean the one executing the 'longjmp'.

That function will have just bailed out (due to an exception, error
condition, whatever). Would it really be expected to resume exactly where it
left off later on? This isn't implementing an interrupt handler.

If you mean the function executing the 'setjmp': how many of those things
you mentioned are actually saved and restored during a routine function
call? Possibly the registers if in the middle of a calculation. But when you
come back after longjmp, you're no longer in the middle of that calculation!
Anyway I knew exactly what was going on in my hardware, and presumably the
OP will know his.

(I've never used C's setjmp/longjmp; this inline code was what I sometimes
used to achieve the same thing. This only implements one exception level,
but I can't see it being difficult to do several levels. It would be set up
like this.

mov [spsave],esp
mov [bpsave],ebp
mov dword [irecovery],recoverypoint

....Start doing stuff
....Normal termination

recoverypoint: # somewhere in the same function
.... only get to here when something's gone wrong (unless you want to
fall-through to here from a normal finish)

Code used to return from an error (as shown above):
mov esp,[spsave]
mov ebp,[bpsave]
jmp [irecovery] )
 
J

Johann Klammer

BartC wrote:
[snip]
If you mean the function executing the 'setjmp': how many of those things
you mentioned are actually saved and restored during a routine function
call? Possibly the registers if in the middle of a calculation. But when
you
come back after longjmp, you're no longer in the middle of that
calculation!
Yes, I meant the latter... to the compiler the setjmp is just a function
call, nothing else. It has been some time since I read up on calling
conventions, but I believe that the compiler is _not_ required to save
and restore _all_ of the registers on entry/exit of every function
call...? How does the compiler know you're not in 'the middle' of a
calculation anymore. Are you in 'the middle' if you are using some local
further down again after the return from setjmp?
Anyway I knew exactly what was going on in my hardware, and presumably the
OP will know his.

He might not know what his compiler does with it..(no one really does)
They do funny things for speed gain.
 
G

glen herrmannsfeldt

Johann Klammer said:
BartC wrote: [snip]
If you mean the function executing the 'setjmp': how many of those
things you mentioned are actually saved and restored during a
routine function call?
Possibly the registers if in the middle of a calculation. But when
you come back after longjmp, you're no longer in the middle of that
calculation!
Yes, I meant the latter... to the compiler the setjmp is just a function
call, nothing else.

Is that really true? Seems to me that compilers can optimize stdlib
functions anyway they want, and that might include special case for
setjmp if needed.
It has been some time since I read up on calling conventions,
but I believe that the compiler is _not_ required to save
and restore _all_ of the registers on entry/exit of every function
call...? How does the compiler know you're not in 'the middle' of a
calculation anymore. Are you in 'the middle' if you are using some local
further down again after the return from setjmp?

Register save convention is pretty much system (usually OS) dependent.
Seems to me that setjmp() has to follow the system convention.
He might not know what his compiler does with it..(no one really does)
They do funny things for speed gain.

They do.

Also, on some the caller saves registers that it needs saved, and
others the callee saves registers that it will change.

-- glen
 
L

luser- -droog

BartC wrote:

[snip]
If you mean the function executing the 'setjmp': how many of those things
you mentioned are actually saved and restored during a routine function
call? Possibly the registers if in the middle of a calculation. But when

come back after longjmp, you're no longer in the middle of that
calculation!

Yes, I meant the latter... to the compiler the setjmp is just a function

call, nothing else. It has been some time since I read up on calling

conventions, but I believe that the compiler is _not_ required to save

and restore _all_ of the registers on entry/exit of every function

call...? How does the compiler know you're not in 'the middle' of a

calculation anymore. Are you in 'the middle' if you are using some local

further down again after the return from setjmp?

But isn't setjmp() only allowed within a condition (if, switch, etc.)? It's *not* just a function call.
 
N

Noob

luser- -droog said:
But isn't setjmp() only allowed within a condition (if, switch, etc.)?
It's *not* just a function call.

For C89

4.6.1.1 The setjmp macro

Synopsis

#include <setjmp.h>
int setjmp(jmp_buf env);

Description

The setjmp macro saves its calling environment in its jmp_buf
argument for later use by the longjmp function.

Returns

If the return is from a direct invocation, the setjmp macro returns
the value zero. If the return is from a call to the longjmp function,
the setjmp macro returns a nonzero value.

"Environmental constraint"

An invocation of the setjmp macro shall appear only in one of the
following contexts:

* the entire controlling expression of a selection or iteration statement;

* one operand of a relational or equality operator with the other
operand an integral constant expression, with the resulting expression
being the entire controlling expression of a selection or iteration
statement;

* the operand of a unary ! operator with the resulting expression
being the entire controlling expression of a selection or iteration
statement; or

* the entire expression of an expression statement (possibly cast to void).
 
N

Nobody

Yes, I meant the latter... to the compiler the setjmp is just a function
call, nothing else.

7.13p3:
It is unspecified whether setjmp is a macro or an identifier
declared with external linkage. If a macro definition is
suppressed in order to access an actual function, or a program
defines an external identifier with the name setjmp, the
behavior is undefined.
 
H

Heikki Kallasjoki

7.13.2.1p3:

All accessible objects have values as of the time longjmp was
called, except that the values of objects of automatic storage
duration that are local to the function containing the
invocation of the corresponding setjmp macro that do not have
volatile-qualified type and have been changed between the
setjmp invocation and longjmp call are indeterminate.

Note the "have been changed" constraint. By my reading, that means that
in code such as

void f(void) {
int i;
...;
i = g(); /* [1] */
if (setjmp(...)) { /* [2] */
h(i); /* [3] */
...
}
...
}

the value of "i", assuming the assignment [1] is the only statement
modifying it, when passed to h on line [3], must be the value that was
returned by g(), even after a later longjmp back to line [2]: the
variable is local to the function and does not have volatile-qualified
type, but it has not been changed between the setjmp and longjmp. To me
this does seem to imply that the implementation needs to either restore
also any caller-saved registers on longjmp, or handle setjmp(...) with
rather more care than a regular function call, and not expect a
caller-saved register to be able to hold g()'s result across the setjmp
call.

(Elsewhere in this thread there is also a different argument about
having to restore any caller-saved registers in any case.)
 
E

Eric Sosman

Johann Klammer said:
BartC wrote: [snip]
If you mean the function executing the 'setjmp': how many of those
things you mentioned are actually saved and restored during a
routine function call?
Possibly the registers if in the middle of a calculation. But when
you come back after longjmp, you're no longer in the middle of that
calculation!
Yes, I meant the latter... to the compiler the setjmp is just a function
call, nothing else.

Is that really true? Seems to me that compilers can optimize stdlib
functions anyway they want, and that might include special case for
setjmp if needed.

Yes, indeed. In the first place, compilers are just part
of "the implementation," along with the library and other stuff,
and the various parts of the implementation are allowed to have
and use private knowledge about each other. That's why sqrt()
might produce an in-line FSQRT instruction instead of a function
call, for example.

In the second place, setjmp() is specifically described as
a macro, not as a function (although a setjmp() function may
lurk somewhere in the background). The <setjmp.h> header might
well use something like

#define setjmp(x) __builtin_compiler_magic__(x)

as its implementation, and this could open an easy route for
all manner of special-casing.
Register save convention is pretty much system (usually OS) dependent.
Seems to me that setjmp() has to follow the system convention.

The system will surely define conventions to be used when
calling upon the system's services, and when the system calls
back into the program (signal handlers, for example). However,
these conventions need not obtain within the program, when it's
calling its own code. Things like gcc's -fomit-frame-pointer
ask the compiler to take un-conventional shortcuts when it can
see that they're safe.

Even if the system's conventions are followed faithfully,
it may be the case that they just don't cover all the cases C
needs. For example, how should a struct-valued function return
its value? The compiler may well need to establish conventions
of its own for matters the system's conventions don't touch on.
[...]
Also, on some the caller saves registers that it needs saved, and
others the callee saves registers that it will change.

And on yet others, there's a hardware assist in the form
of a "register window turn" or similar mechanism.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,479
Members
44,899
Latest member
RodneyMcAu

Latest Threads

Top