Hi!
This question has been floating around a bit over the years and
addressed vaguely, maybe implied. I hope that this thread will be like a
final discourse so we're all clear. Thank you in advance for giving a
hand clarifying it.
If this understanding is messed up, there could be SIGSEGV:s and other
nasty behavior, that's why I wish to get to clarity about it.
Question at the bottom.
-> Warmup: more than one=sigsegv, task of loading only one put on ld.so,
C++ runtime library backward compatibility
Unlike (GNU) C, (GNU) C++ has a runtime library that each OS process
with C++-compiled code must load.
On OpenBSD, for the OS-bundled g++ 4.2.1, its name is libstdc++ , and
for g++ packages of any version (4.8, 4.9 etc.) [1], the name is
libestdc++ .
GNU C++ has a convention that its runtime library is BACKWARD-COMPATIBLE
for *all binaries* compiled by any compiler back to version 3.4.0 . [2]
Its only requirement for that to function is that IF you have MULTIPLE
runtime library versions on the same system, then ONLY ONE should be
loaded ["concurrently"/by the same OS process], and that one should be
"the newest one" (i.e. for a compiler version at least as new as the one
the binary which was compiled by the newest one was compiled with).
GNU C++ then goes on to ENFORCE both that only ONE runtime library
version is loaded [in the same process], and enforcing that the version
loaded is the NEWEST (relevant as defined above) version, and both these
enforcements are done via the ld.so dynamic library loading mechanism!
-> Sidetrack: Potential dlopen() trouble
If more than one version is loaded concurrently, you're in undefined
territory e.g. on your way to a SIGSEGV or other form of chaos.
This means that there is a constraint that the executable must have
dynamic object dependency linkage to the NEWEST version of the runtime
that will ever be used - which has interesting applications for
dlopen(), as in, if the executable file links to the 4.2.1. runtime and
you load a 4.8-compiled shared library using dlopen(), you're in
undefined territory;
I guess the library loader simply would load the 4.8-series runtime,
which would prime the process for crashing.
So for such a particular case, functionality would be ensured by somehow
making the host binary load the 4.8-series runtime in the first place
(via "-l" or LD_PRELOAD).
-> How other OS:es ensure only one version to be loaded and what I don't
see on OpenBSD
Apparently some other OS such as Linux tends to enforce that only one
C++ runtime version is loaded concurrently, via the "SONAME" ELF header
field - the library loader traverses the different runtime library files
available and uses it to load only the very newest one. [3]
On OpenBSD however, the C++ runtime library files don't have any
"SONAME" field [4] and also the file naming scheme is different (the use
of "libstdc++" AND "libEstdc++" and the numbers in the .so filename do
not reflect the GNU C++ version, not sure if that is of any relevance).
-> More runtime library loading specifics
From talking to GNU C++ people, it seems to me that the runtime library
file in itself NOT has any magic to "not accept to be loaded" if a newer
(or other, for that sake) version of the runtime already has been
loaded, that is, if the library loader would load more runtime library
versions, then they would get loaded (incorrectly), set up
(incorrectly), and the process would be silently primed for undefined
behavior (crash).
So the runtime version loading matter is all in the hands of ld.so, at
least on Linux.
All this looks fairly intricate to me and I'd like to understand how
this works out on OpenBSD. Therefore, I kindly ask you to inform about,
-> The question
What is OpenBSD's mechanism for ensuring that only ONE lib[e]stdc++
version is loaded by an OS process concurrently and that that version
loaded is the NEWEST relevant version?
-> Contextual remarks
I guess maybe somehow an OpenBSD installation actually could be made to
host an arbitrary number of G++ and libstdc++ versions, however, I guess
also generally the relevant upper limit would be *2*, that is,
* The OS-bundled 4.2.1 which also pretty much.. or literally?? **ALL**
packages are compiled with (no OpenBSD packages depend on C++11 or alike
standard which is not supported by 4.2.1?), and
* A newer one, that is 4.8.X or 4.9.X, which a user would use for
instance to compile C++11 code -
and probably you don't need 4.8 and 4.9 concurrently.
I also guess a lot of violence would be needed to have 4.8.X and 4.9.X
installed concurrently as the packages have overlapping filenames.
Thanks!
Tinker
[1]
http://cvsweb.openbsd.org/cgi-bin/cvsweb/ports/lang/gcc/
[2]
This was said by redi@#gcc, and he refered to the document listed in [2]
below here which shows the exact runtime library backward compatibility
situation, per exact individual released version.
The 3.4.0 number may not have been totally exact, would need to look
into that additionally, but anyhow that is far behind 4.2.1. which is
the oldest version OpenBSD works with so makes no difference.
[2], [3]
"Binaries with equivalent DT_SONAMEs are forward-compatibile: in the
table below, releases incompatible with the previous one are explicitly
noted."
https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html
[3]
SONAME:s in general are discussed at is discussed at
https://gcc.gnu.org/onlinedocs/libstdc++/faq.html#faq.how_to_set_paths
https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dynamic_or_shared.html#manual.intro.using.linkage.dynamic
http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html#AEN95
[4]
No SONAME anywhere here.
Is there any other parameter in here which carries the meaning to ld.so
to only load the newer one??
$ readelf -d /usr/lib/libstdc++.so.57.0
Dynamic section at offset 0x100548 contains 17 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libm.so.9.0]
0x000000000000000c (INIT) 0x541b0
0x000000000000000d (FINI) 0xd71b0
0x0000000000000004 (HASH) 0x2a8
0x0000000000000005 (STRTAB) 0x1b318
0x0000000000000006 (SYMTAB) 0x5bf8
0x000000000000000a (STRSZ) 160292 (bytes)
0x000000000000000b (SYMENT) 24 (bytes)
0x0000000000000003 (PLTGOT) 0x400698
0x0000000000000002 (PLTRELSZ) 13776 (bytes)
0x0000000000000014 (PLTREL) RELA
0x0000000000000017 (JMPREL) 0x50be0
0x0000000000000007 (RELA) 0x42540
0x0000000000000008 (RELASZ) 59040 (bytes)
0x0000000000000009 (RELAENT) 24 (bytes)
0x000000006ffffff9 (RELACOUNT) 268
0x0000000000000000 (NULL) 0x0
$ readelf -d /usr/local/lib/libestdc++.so.16.0
Dynamic section at offset 0x109838 contains 17 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libm.so.9.0]
0x000000000000000c (INIT) 0x625a0
0x000000000000000d (FINI) 0xd5bc0
0x0000000000000004 (HASH) 0x2a8
0x0000000000000005 (STRTAB) 0x211b8
0x0000000000000006 (SYMTAB) 0x84e0
0x000000000000000a (STRSZ) 185388 (bytes)
0x000000000000000b (SYMENT) 24 (bytes)
0x0000000000000003 (PLTGOT) 0x409988
0x0000000000000002 (PLTRELSZ) 17640 (bytes)
0x0000000000000014 (PLTREL) RELA
0x0000000000000017 (JMPREL) 0x5e0b0
0x0000000000000007 (RELA) 0x4e5e8
0x0000000000000008 (RELASZ) 64200 (bytes)
0x0000000000000009 (RELAENT) 24 (bytes)
0x000000006ffffff9 (RELACOUNT) 387
0x0000000000000000 (NULL) 0x0