tech-toolchain archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

static linking vs. __attribute__((constructor)) et al



So, as you all probably know I build static-linked NetBSD systems.

I'm now in the process of doing this for -current (amd64).  I've got far
enough to build an install (and live) image and install it and boot it
and run it in a VM.

Previously my most recent successful builds, which I've used in
production since, have been with an old -current from, I think,
2021/03/10.  sys/param.h says 9.99.81

Since then some key libraries, notably libisc, have gained the use of
__attribute__((contructor)) functions.

So, for example. /usr/bin/host won't work static-linked as-is.

# host more.local
/Volumes/work/woods/g-NetBSD-src/external/mpl/bind/lib/libisc/../../dist/lib/isc/mem.c:475:mem_create(): fatal error: pthread_mutex_init(): Invalid argument (22)
Abort (core dumped)

The problem facing successful static-linking is that the objects
containing those constructor functions (i.e. from libraries)
often/usually won't get linked into the final binary, and so of course
they can never be run, usually leaving key data structures
uninitialised.

One trick often used in this situation is to simply ask the linker to
pull in the whole archive (i.e. using -Wl,-whole-archive, as if it were
one massive .o -- and indeed that's another related trick, i.e. convert
such libraries to single .o's).

This works, and it does produce working binaries.  I tested with host:

# ./host more.local
more.local has address 10.0.1.129

That can be pretty wasteful though, e.g. host blows up by about 140kb:

$ size host host- /usr/bin/host
   text    data     bss     dec     hex filename
6664304  486320 2211289 9361913  8ed9f9 /usr/bin/host
6803032  487776 2211353 9502161  90fdd1 ./host

Another trick is to explicitly reference the constructor (and
destructor) function(s) from some other primary object that's always
loaded, but then one needs to know all their symbol names, and to modify
all the programs that use any such libraries.

I think the right solution is to ask the linker to pull in any and all
objects from any and all mentioned libraries if they have a .ctors
section.  I don't see any obvious way to do this, but my understanding
of GNU ld linker scripts is very limited.

Does anyone have any ideas of how to achieve successful static linking
of libraries with constructors without -whole-archive and without
using explicit references to all constructors?


Luckily in NetBSD it appears only a relatively few libraries have .o's
with .ctors where those won't get pulled in by normal static linking
(e.g. libc.a(initfini.o) gets pulled in because crt0.c refers explicitly
to _libc_init).  I still have to do a bit more careful audit though.

--
					Greg A. Woods <gwoods%acm.org@localhost>

Kelowna, BC     +1 250 762-7675           RoboHack <woods%robohack.ca@localhost>
Planix, Inc. <woods%planix.com@localhost>     Avoncote Farms <woods%avoncote.ca@localhost>

Attachment: pgpZCwbbsnGtD.pgp
Description: OpenPGP Digital Signature



Home | Main Index | Thread Index | Old Index