Re: -z preinitarray

From: Dan Koren (dankoren_at_yahoo.com)
Date: 04/30/05


Date: Sat, 30 Apr 2005 03:39:06 -0400


"Jonathan Adams" <jwadams@gmail.com> wrote in message
news:jwadams-0BD266.15453329042005@news1nwk.sfbay.sun.com...
> In article <42728e0e@news.meer.net>, "Dan Koren" <dankoren@yahoo.com>
> wrote:
>
>> OK, thanks.
>>
>> Does this imply, in effect, that there is no way for an
>> interposer shared library (e.g. a memory allocator) to
>> arrange to always initialize itself first, before any
>> other library or code in the main executable, and
>> regardless of how the main executable may have
>> been built?
>
> It generally can't, anyway; relying on init sections to
> set everything up is a bad idea. It's much better to set
> everything up in static data,

Which may or may not be possible depending on what the code
is intended/designed to do.

> and arrange for any additional initialization to happen
> at the first call to malloc/calloc/realloc/etc.

While this would certainly work, it would also require each
and every routine in the library to check if the library has
already been initialized on every call. If I decide to follow
such an approach, I would rather start with a statically
initialized call table in which every entry points to the
initialization section. Maybe I should simply patch the GOT! ;-)

However, a more serious problem may be that by the time
the first call to malloc occurs it may already be too
late for the allocator to configure itself in the way
it is intended/designed.

> With a bit of care, this can be done without impacting
> the fast path.

In theory.

In practice, this would add at least 25% overhead, or
more if the test for initialization misses in the TLB
or the cache. In my case, the fast path is two loads
and one store. An extra load would be too expensive.

> The problem is that init section ordering is not
> guaranteed, especially when cyclic dependencies
> happen. The classic problem is LD_BIND_NOW=1
> plus C++; libCrun.so.1, libc.so.1, and libmymalloc.so
> form a cyclic dependency group, the linker calls
> libCrun's initializer first,

Even if I set -z initfirst when building the library?

> the C++ runtime initialization calls malloc(), but
> libmymalloc.so's init section has not fired. Chaos
> ensues.

While quite plausible, this example is also contrived.

A correctly designed memory allocator does not (should
not) depend on any other library. All it needs to do is
make one system call to allocate a slab to get rolling.
Unless of course it happens to have been written in C++,
in which case its author should be defrocked and sent
to work in support for the rest of his/her life ;-)

> Summary: init sections are evil and unreliable; avoid
> them if you possibly can.

Init sections do not have to be evil and unreliable, if
correctly designed and implemented. Unfortunately, most
systems currently available in the marketplace seem to
have resulted from quiltwork.

Also worth mentioning is the fact that most (if not all)
of this trouble could be avoided if one links the library
with the executable and assign its initializer to the
.preinit_array. Unfortunately, that would render the
allocator useless for existing applications.

dk


Quantcast