There are still too many people out there who think (or even
insist) that static linking has benefits. This has never been the
case and never will be the case. Here are a few reasons why
dynamic linking is superior:

  • fixes (either security or only bug) have to be applied to
    only one place: the new DSO(s). If various applications are
    linked statically, all of them would have to be relinked. By the
    time the problem is discovered the sysadmin usually forgot which
    apps are built with the problematic library. I
    consider this alone (together with the next one) to be the
    killer arguments.

  • Security measures like load address randomization cannot
    be used. With statically linked applications, only the stack and
    heap address can be randomized. All text has a fixed address in
    all invocations. With dynamically linked applications, the kernel
    has the ability to load all DSOs at arbitrary addresses, independent
    from each other. In case the application is built as a position
    independent executable (PIE) even this code can be loaded at
    random addresses. Fixed addresses (or even only fixed offsets)
    are the dreams of attackers. And no, it is not possible in
    general to generate PIEs with static linking. On IA-32 it is
    possible to use code compiled without -fpic and
    -fpie in PIEs (although with a cost) but this is not true
    for other architectures, including x86-64.

  • more efficient use of physical memory. All processes
    share the same physical pages for the code in the DSOs. With
    prelinking startup times for dynamically linked code is as good
    as that of statically linked code.

  • all kinds of features in the libc (locale (through
    iconv), NSS, IDN, …) require dynamic linking to load the
    appropriate external code. We have very limited support for
    doing this in statically linked code. But it requires that the
    dynamically loaded modules available at runtime must come from
    the same glibc version as the code linked into the application.
    And it is completely unsupported to dynamically load DSOs this
    way which are not part of glibc. Shipping all the dependencies
    goes completely against the advantage of static linking
    people site: that shipping one binary is enough to make it work
    everywhere.

  • Related, trivial NSS modules can be used from statically
    linked apps directly. If they require extensive dependencies
    (like the LDAP NSS module, not part of glibc proper) this will
    likely not work. And since the selection of the NSS modules is
    up the the person deploying the code (not the developer), it is
    not possible to make the assumption that these kind of modules
    are not used.

  • no accidental violation of the (L)GPL. Should a program
    which is statically linked be given to a third party, it is
    necessary to provide the possibility to regenerate the program
    code.

  • tools and hacks like ltrace, LD_PRELOAD, LD_PROFILE,
    LD_AUDIT don’t work. These can be effective debugging and
    profiling, especially for remote debugging where the user cannot
    be trusted with doing complex debugging work.

There are certainly more reasons. The often used argument
about statically linked apps being more portable (i.e., can be
copied to other systems and simply used since there are no
dependencies) is not true since every non-trivial program needs
dynamic linking at least for one of the reasons mentioned above.
And dynamic linking kills the portability of statically linked
apps.

Conclusion: Never use static linking!

There is one aspect where people decide to misinterpret these
recommendations. I do not say that everything should be
stuffed into its own DSO. I would never say this. To the contrary.
Code which belongs together because of the development
process should be kept in the same object. The reason is that the
fewer DSOs are needed the faster everything works (loading, symbol
resolution, …).

One example where this still isn’t done right is
OpenOffice.org. If you look at the dependencies of the binaries
(swriter.bin etc) you’ll see lots of files from the OO.org
project. Almost all of them are used in all the OO.org programs
and none is used outside the project. Especially there is
libsoffice.so which itself pulls in a huge number of
DSOs. This is done in all OO.org programs!

During deployment there is no reason to do this. All
the DSOs pulled in by libsoffice.so and probably some of
the others used in the various programs should all be part of one
mega-DSO. Yes, this DSO would be big, but it would be smaller
than sum of all the loaded dependencies. And more: the export
lists can be further restricted making a lot of calls inside the
new DSO much faster.

There is a good reason to have all the separate DSOs during
development. This makes it possible to rebuild only a small part
of the source tree to test out some changes. But this is
development. When the binaries are shipped to users (e.g., as
part of a distribution) this need falls away and so does the
justification.

So, combine all the sources from the same project which are
used or at least loaded in all or most situations in one single
DSO. It will be smaller and faster. Just don’t get overzealous
and add 3rd party code as well. E.g., even if you ship
a copy of, say, libxml don’t add it to your DSO. Only
the code which is written as part of the project.

Read More

ترك الرد

من فضلك ادخل تعليقك
من فضلك ادخل اسمك هنا