[HN Gopher] Rules of static linking: libstdc++, Libc, libgcc (2012)
___________________________________________________________________
Rules of static linking: libstdc++, Libc, libgcc (2012)
Author : optimalsolver
Score : 44 points
Date : 2021-11-12 13:17 UTC (9 hours ago)
(HTM) web link (micro.nicholaswilson.me.uk)
(TXT) w3m dump (micro.nicholaswilson.me.uk)
| michaelhoffman wrote:
| Would be nice if there were some explanation of why.
| matheusmoreira wrote:
| > Google if you need an explanation for any of the above.
|
| Can anyone explain? Why can't libc and libgcc be statically
| linked? I'm not surprised, just curious.
| [deleted]
| jcelerier wrote:
| they absolutely can. Glibc's NSS
| (https://venam.nixers.net/blog/unix/2020/11/01/resolving-a-
| ho...) won't work and that's a good thing because putting
| domain name resolution in libc was a braindead idead from the
| very beginning.
|
| Domain name resolution behaviour should be program-
| controllable, not system-controllable (and thankfully we are
| starting to see a bit of sanity with web browsers which do
| bypass libc's domain name resolution) and especially not plug-
| in based which causes BS like things working differently
| whether avahi is installed or not.
|
| Note however that this will only work for simple non-gui apps.
| GUI apps generally need to load opengl drivers (which are
| shared objects) - thus you'd need to choose at link time which
| GL driver you want to use... which is not a practical thing to
| do.
| rfoo wrote:
| I'd argue that libgcc is safe to statically link though.
|
| The only downside of statically linking libgcc, as long as
| you keep your symbol visibility sane, i.e. not re-exporting
| everything which is unfortunately the default :(, is C++
| exception across shared library boundary is not guaranteed to
| work. But if you are trying to make your library portable
| across different distro, having C++ thing in your external
| interface is never a good idea. Especially when you
| statically link libstdc++.
| twic wrote:
| > Domain name resolution behaviour should be program-
| controllable, not system-controllable
|
| This is pure insanity, of course, but i'm sure i'd be
| entertained by you trying to justify it, if you're inclined.
| nybble41 wrote:
| Not the GP, but I would at least agree that the C library
| should not be handling domain name resolution or requiring
| any dynamically-loaded plugins. However, I am strongly
| opposed to having each application implement its own
| resolver and ignoring system settings. There should be a
| single system resolver where applications submit their
| requests. Something like the DBUS API presented by systemd-
| resolved, for example. Or the older NSCD protocol which
| permits out-of-process implementation of the NSS APIs,
| ostensibly for caching.
|
| systemd-resolved offers a nice compromise since, in
| addition to the rich DBUS API, it also acts as a recursive
| resolver on 127.0.0.53. So any applications that do
| implement their own resolution can be pointed there.
| orra wrote:
| Somebody else replied to you about the technical feasibility.
|
| It's also worth noting that if you statically link Glibc,
| you'll need to make more of an effort to comply with the LGPL.
| If you dynamically link, you automatically comply with 4(d).
| billconan wrote:
| I have a question,
|
| I'm creating a python binding (on linux). The company tool chain
| uses clang/llvm/libc++ , whereas python is built with gcc.
|
| what should I do? is it ok to statically link libc++ ?
| tyingq wrote:
| How to deal with the DNS resolver is probably also worth throwing
| in as an issue. If you fully statically link a binary, and it
| needs to resolve an IP address, you can have issues. Because
| you're guessing what the local resolver setup might be. Do some
| google searches for "--enable-static-nss" to see some of the
| issues.
| aidanhs wrote:
| This is missing a lot of detail around libc (can't comment on the
| others), but was published ~1.5 years after musl was first
| released - I can imagine the subtleties being missed in a glibc
| monoculture.
|
| To expand a bit:
|
| 1. dlopen has interactions with static linking that you should
| understand if you use both at the same time. Different libcs
| expose different symbols for libc functions, so building your
| dynamic library against one libc may make it incompatible with
| another. And two libcs in the same program (one from the dylib,
| one from the binary) is a recipe for a very bad time - imagine
| freeing a pointer allocated with a different malloc
| implementation, or a different layout of libc structs
|
| 2. the complexity with _glibc_ is it invokes dlopen as part of
| NSS, a feature that gets used as part of looking up users, among
| other things (it does this to allow integration with LDAP etc).
| You can actually see warnings at link time if you statically link
| glibc but pull in symbols that use NSS. You can disable NSS if
| you like at build time _of glibc itself_ [0] (i.e. not your
| binary)
|
| 3. musl doesn't have the complexities of NSS and can be
| statically linked happily by default (I suspect that's probably
| what musl is most used for)
|
| [0]
| https://sourceware.org/glibc/wiki/FAQ#Even_statically_linked...
| Joker_vD wrote:
| > And two libcs in the same program (one from the dylib, one
| from the binary) is a recipe for a very bad time - imagine
| freeing a pointer allocated with a different malloc
| implementation, or a different layout of libc structs
|
| Depends on the exact architecture of the program, y'know. I
| remember a Windows app written in Delphi (so no libc whatever)
| that supported loading plugins written it whatever; and I've
| seen it load simultaneously plugins that linked against
| msvcrt90.dll and msvcrt100.dll with no problem. But that worked
| because plugins were required to export a FreeObject function
| that is supposed to be used to free whatever structures a
| plugin returned from its other functions. The main program
| tracked what piece of data came from where and called proper
| deallocation functions.
|
| But that requires acknowledgement of a fact that there is no
| "single, global C runtime".
| pjmlp wrote:
| As info for others, Windows, some UNIX clones like Aix, and I
| guess mainframes/micros, do use namespaces for the dynamic
| libraries.
|
| So funcA() from a.dll and funcB from b.dll, are actually
| resolved as a!funcA and b!funcB, hence why linking against
| msvcrt90.dll and msvcrt100.dll works without major issues.
| aardvark179 wrote:
| Yes. In TruffleRuby we have to ensure that we free memory
| returned by FFI calls using the correct free implementation,
| because that's not necessarily the one being used internally
| by our runtime.
|
| It's annoying but it's something you have to handle.
|
| As for supporting multiple DLLs using different run time
| libs, I'd guess that only works because they are slightly
| more complex than simple shared libs and can sort out thread
| local storage and the like during thread attach. Without that
| I can imagine things going badly wrong.
| st_goliath wrote:
| > But that requires acknowledgement of a fact that there is
| no "single, global C runtime".
|
| On _Windows_ , yes, giving rise to situations where you have
| a dynamic library and the program using it, linked against
| two different C runtimes. On a Unix like OS you usually have
| a single, global libc. You would have to _deliberately_ link
| it statically into a shared library, or a program that uses a
| shared library, to create a similar situation.
|
| For the standard C use case, if the library malloc()s
| something and passes the result pointer to the program, the
| program itself has no way to free it. The two have their own,
| independent copies of the allocation code that don't share
| the allocation arena. If the program calls free(), the _best
| case_ scenario is that the libc of the program realizies it
| doesn 't recognize the pointer, yells "double free" and
| abort()s.
|
| That's a bit of a portability pit-fall and definitely
| something one has to consider when designing a library ABI.
| Pointers returned from the library have to be passed back
| into the library to free the underlying memory. A solution
| like the one used by Delphi is required. (For polymorphic
| objects being passed around, you would typically have
| something like a destroy() hook anyway).
|
| I'm a bit hesitant to make a guess on what happens in the
| case of a C++ smart pointer. Technically they can have an
| allocator, but does that cross the ABI bounds? Is there a
| template specialization for optimizing it away if you are
| using the default delete operator? I guess the compiler of
| the program could also end up instantaiting _the programs_
| allocator when inserting the template parameters?
| my123 wrote:
| > 1. dlopen has interactions with static linking that you
| should understand if you use both at the same time.
|
| Using dlopen when static linking is used is deprecated in
| glibc.
| matheusmoreira wrote:
| > imagine freeing a pointer allocated with a different malloc
| implementation, or a different layout of libc structs
|
| Should libraries be allocating memory to begin with? They
| should simply provide the data structures. The main program
| should decide whether to allocate on the stack, statically or
| dynamically.
| Joker_vD wrote:
| Wait until you learn about (dynamically-loaded) libraries
| that start up worker threads and stuff without any
| notification. You do your stuff with them, then call
| FreeLibrary and suddenly some random thread crashes because
| its text is no longer mapped and brings your whole program
| down. Fun stuff!
| matheusmoreira wrote:
| Jesus. I wonder how much time it took to debug that...
|
| Libaries shouldn't do anything unless called explicitly.
| Even when called, they should cede as much control as
| possible. They should probably be exposing the concurrent
| functions so the caller can decide how to thread them...
| Every time a library decides to make things easy for the
| user it leads to insane problems like these.
| Joker_vD wrote:
| Nah, it's a rather basic problem and the solution is well
| known: do another LoadLibrary on the already loaded
| library. Of course, then you need a
| FreeLibraryAndExitThread... [0] And the posts following
| [0] (you can see them at the bottom of the page in the
| "Read Next" section) explain more of the context.
|
| All this stuff is there because of the built-in threading
| support in COM which, arguably, was pretty convoluted for
| some rather strange reasons -- what's the point of such
| precise RAII-ing of the DLLs? I guess the address space
| was really precious back then or something.
|
| [0] https://devblogs.microsoft.com/oldnewthing/20131105-0
| 0/?p=27...
| pjmlp wrote:
| I guess strdup() kind of answers that.
___________________________________________________________________
(page generated 2021-11-12 23:02 UTC)