Cancelling atexit calls

Geoff Keating geoffk@ozemail.com.au
Tue Sep 8 04:31:00 GMT 1998


> Date: Sun, 6 Sep 1998 22:29:00 +0200
> From: Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>

> > Perhaps you could tell us precisely what problem you are trying to solve.
> 
> There is a number of problems; some of them need to be solved in g++,
> some might use C library support.
> 
> a) Destructors need to run in exact reverse order of construction;
>    this holds even for destructors of static block-locals (for which
>    the initialization order is not known at compile time).
> b) Destructors in C++ need to interleave with atexit functions:
>    If a call to atexit was made between the construction of two
>    globals, that function needs to be called between the destructors.
> c) When a shared library is unloaded using dlclose, the destructor
>    code is not available when exit is called. Calling destructors
>    inside dlclosed shared images at exit will lead to a crash.
>
> To implement the first two requirements, destructors cannot go into
> the .fini section, but must be registered with atexit.
> 
> To implement the third requirement, atexit must not be used as it will
> crash when calling functions that don't exist anymore - unless it is
> possible to cancel functions registered with atexit.
...
> > You can use _GLOBAL_OFFSET_TABLE_.
> > That symbol is magic and causes the assembler to produce a special reloc.
> > (At least I think it still works this way.)
> 
> I'm a bit worried about portability here. If I have gcc generate
> references to _GLOBAL_OFFSET_TABLE_, how do I know whether the
> assembler does the right thing? It seems that the special-reloc thing
> is performed only on i386.

This is really not a good idea.  It will not work on powerpc unless
what you're doing with _GLOBAL_OFFSET_TABLE_ is calling it:

extern void _GLOBAL_OFFSET_TABLE_(void);  /* does nothing visible to C.  */

You may have to make this machine-specific.  I think if you write

elf_machine_load_address() + elf_machine_dynamic()

(the functions are defined in sysdeps/*/dl-machine.h), you will get
the address of the dynamic section in the current shared object.
Well, probably.

> Also, under your proposed interface, how could I get a reference
> to a variable with exactly one copy per shared library?

Tricky.  Very tricky.

The obvious way to do this is to put, in crtbegin.o,

static variable = 0;

But then you can't easily access this outside crtbegin.o, unless you
want to use symbol versioning.  The whole design of ld.so is to
prevent this sort of thing happening.


It sounds like what you really want is a per-dynamic-object atexit().
So why not just implement that?  I think this will need some support
in glibc; you need a mapping from an address to the handle of the
dynamic object, which is not currently provided (dladdr isn't enough).
You know when an object is being destroyed because its .fini is run.

-- 
Geoffrey Keating <geoffk@ozemail.com.au>



More information about the Libc-alpha mailing list