[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)