Breaking the crt1.o -> atexit() -> malloc() dependency
Kostik Belousov
kostikbel at gmail.com
Thu Mar 6 01:48:44 PST 2008
On Wed, Mar 05, 2008 at 05:12:32PM -0800, Tim Kientzle wrote:
> There was some recent discussion on the commit mailing
> list about how to disentangle crt1.o from malloc().
>
> Here's a design that I think addresses all of the
> issues people raised, including the POSIX requirement
> that atexit() always be able to support 32 registrations.
> It does it without using sbrk() or mmap(), either.
>
> The basic idea is to lift the malloc() call up into
> atexit() and have atexit_register() use statically-allocated
> storage if atexit() didn't provide dynamically-allocated
> storage.
>
> This basically changes atexit() to something like this pseudocode:
>
> int atexit(void (*function)(void))
> {
> struct atexit *storage = malloc(sizeof(struct atexit));
>
> /* Note: If malloc() fails, __atexit_register will try
> * to statically allocate, so we don't check here
> * for malloc() failure. */
> return __atexit_register(function, storage);
> }
>
> Then atexit_register either uses the block that was provided
> or grabs an item from a static pool if there wasn't one:
>
> /* 32 required by POSIX plus a few for crt1.o */
> static struct atexit pool[40];
>
> int atexit_register(void (*function)(void), struct atexit *storage)
> {
> if (storage == NULL) {
> storage = ... next item from static pool ...
> }
> storage.func = function;
> ... add storage block to linked list ...
> }
>
> Avoiding free() from the low-level code is a little trickier
> but I think it can be done by having the low-level code
> put (dynamically-allocated) blocks back onto a free list
> and having the higher-level atexit() release that list
> on the next registration. This should handle the case
> of a dynamic library being repeatedly loaded and unloaded.
> Of course, it's unnecessary to release the atexit storage
> on program exit.
>
> In particular, crt1.o can then call atexit_register(f, NULL)
> to register its exit functions without creating a dependency on
> malloc.
>
> This does require that atexit() and atexit_register() be in
> separate source files, but I think it addresses all of the other
> concerns people have raised.
I mostly agree with proposal, but there is also __cxa_atexit().
And, besides the issue of the size of the static linked executables,
there is more exposed problem of atexit() memory leaks. See
http://lists.freebsd.org/pipermail/freebsd-stable/2008-February/040644.html
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 195 bytes
Desc: not available
Url : http://lists.freebsd.org/pipermail/freebsd-current/attachments/20080306/47696eeb/attachment.pgp
More information about the freebsd-current
mailing list