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

Reply via email to