This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: A shared version of libgcc


   From: Mark Mitchell <mark at codesourcery dot com> 
   Date: Sat, 29 Apr 2000 19:03:24 -0700 

   I've decided that we have no choice but to bite the bullet and do this
   in the new release.  Users will be no worse off: they can always
   choose to link statically with libgcc.a, and accept the consequences
   (i.e., that simultaneously linking with shared libraries probably
   won't work right.)

   [...]

   I appreciate everyone's input on this issue.  

   I don't consider my decision final -- if there are serious new issues
   raised, we should certainly consider them.

I think simply converting the current libgcc into a shared library is
a bad idea.  Introducing a shared library of some sort, is probably
inevitable, but it should be done with the greates possible care since
it has the possibility of great disruption on systems where GCC is the
system compiler.  In the worst, case bad choices made by the GCC team
could mean that people will be forced to recompile every single binary
on their system.  Therefore, I think that before starting any coding,
a more detailed investigation is needed.  I also haven't heard from
Ulrich Drepper (the GNU C Library maintainer) yet.  I think his input
in the discussion would be very important.

Anyhow, here's my attempt to sum up the current problems that prompted
the whole shared libgcc idea, and possible solutions.  I included a
section about issues specifically related to the GNU C Library, since
that's used on the systems I care about.  Comments are welcome, and if
people think it is useful, I'll improve the document to take those
comments into account.

Mark


----------------------------------------------------------------------


First, let me say that I'm not convinced that a shared libgcc is the
right thing to do for GCC 3.0.  I think for instance that it is
possible to avoid using a shared libgcc for standard C programs.  This
would be a great win since it reduces depencies between different
components.

The solutions are a bit ELF and i386 centered, but most of the issues
are relevant for other targets too.

Symbols in libgcc and their problems
====================================

1. Simple utility functions without interdependencies or access to
   global variables[1].  Examples are __ashldi3, __udivmoddi4.

   The problem with these functions is that code used to build a
   shared library might need one of these functions.  Therefore shared
   libraries are linked with libgcc.  However, if no measures are
   taken, these functions are re-exported from the shared library.
   This means that they have become part of that library's ABI, often
   without the author/builder actually knowing it.  Even worse, the
   functions that are re-exported might depend on the GCC release used
   to compile the code.  The particular functions that are now
   provided by the shared library are left out from programs linked
   against this shared library.

   The problem doesn't actually surface until the shared library is
   recompiled and somehow loses a dependency on one of the functions
   in libgcc (perhaps because the actual implemantation changed, or a
   different compiler was used).  Or in a binary-only setting, when a
   program linked against a "standard" library is distributed and the
   developer used a shared library that contained a different set of
   symbols from libgcc than the actual shared library installed on the
   user's system.

   Assuming that these functions contain no serious bugs, it is
   absolutely no problem if more than one (potentially different) copy
   of these functions is used in one program.  Most of these functions
   are small, so a slight increase in the size of binaries won't be
   noticed.  Therefore these functions can stay in a static library if
   we can control re-exporting these functions from shared libraries.

2. More complex utility functions, that depend on other functions or
   access global variables.  Examples are the functions for profiling
   basic blocks, for example __bb_init_func, and the frame functions,
   that is __deregister_frame, __deregister_frame_info,
   __frame_state_for, __register_frame, __register_frame_info,
   __register_frame_info_table and __register_frame_table.  A third
   group of functions in this class are the interfaces that implement
   the actual exception handling mechanism, for example __throw.

   The profiling functions are probably not really important; they're
   only used in specially prepared code for debugging purposes that's
   not widely distributed in binary form.

   The frame functions are a PITA.  We had serious problems with those
   in the past on Linux.  If we don't think carefully, and plan ahead
   we will have serious problems with these functions again!  Let's
   look a bit closer at them.

   The problem with re-exporting symbols from libgcc is still present,
   but it is worsened by the fact that there must be only one copy of
   these functions that's actually used.  In fact, it is the copy that
   comes from the most recent libgcc that must be used.  This probably
   means that on systems that support shared libraries, these
   functions must live in a shared library too.

   Note that these functions are only needed for code compiled with
   -fexceptions.  Or perhaps it is better to say that these functions
   are only needed if exception handling is actually used, that is, if
   the program or one of the libraries it uses references
   __frame_state_for.  The registration of frame unwind info is
   registered by calling __register_frame_info in crtbegin.o (or
   crtbeginS.o).  But if the target supports it the current code uses
   weak references to avoid sucking the frame code in if it's not needed.

   It worries me quite a bit to see that the module containing the
   frame functions references several of the pthreads functions.  This
   means that libgcc is tied to a particular implementation of those
   functions.  This isn't too bad while libgcc is a static library,
   but could lead to all kinds of badness if libgcc is turned into a
   shared library, and used in multithreaded libraries.

   Concerning the other exception handling functions: It is probably
   the easiest thing to put these functions together with the frame
   functions in the same shared library.

3. Language specific symbols.

   Right now if the C++ compiler is built, some C++ code is added to
   libgcc.  So those parts of libgcc introduce a dependency on the C++
   ABI.  While the intention is that the GCC 3.0 C++ ABI will be
   stable, it is always possible that it might be needed to tweak it a
   bit to fix a bug.  Keeping the C++ ABI specific parts in a
   different (shared) library gives you the freedom to do that without
   forcing everyone to recompile every single program on their Linux
   system.

--------
[1] Some functions in libgcc call standard ISO C functions.  Calling
    abort() is probably fine since its ABI is in principle entirely
    defined by function calling conventions.  A function calling
    abort() would still classify as a simple utility function.  But if
    a function in libgcc calls more complex ISO C functions they
    probably wouldn't.


Adressing those problems
========================

Let's first look at the problem of re-exporting symbols in class 1 from
shared libraries.  Here's a list of possible options:

 * Do nothing about it and leave the current status quo, that has been
   present ever since people have produced shared libraries using
   GCC.  This places a burden on people building shared libraries to
   make sure that they keep re-exporting the same set of symbols from
   libgcc.

 * Put those symbols in a shared library, and link all shared
   libraries and programs that use any of those symbols against this
   library.  Finding out whether to link with the shared libgcc or not
   might be tricky.  Leaving that up to the link-editor doesn't work
   for sure.  On systems where GCC isn't the system compiler we can
   probably link programs that are only linked against shared
   libraries that come with the system with a static libgcc.

 * Make use of some special magic to prevent shared libraries from
   re-exporting symbols from libgcc.a.  On ELF systems using the GNU
   linker-editor or systems using a modern Solaris linker this can be
   done with version maps (note that this can be done without actually
   versioning the symbols).  On ELF systems that support it,
   STV_HIDDEN coult be used.  Other systems might have other
   possibilities to give these symbols only local scope.  Of course
   this means that shared libraries that are already re-exporting
   symbols from libgcc will no longer do that by default.  Programs
   linked against that shared library might have to be relinked, or
   people might build shared library with a special GCC option that
   makes the shared library in question re-export the symbols in
   question.  Forcing people to think about the re-exporting problem
   might not be such a bad idea.

 * Perhaps it is possibly to make symbols invisible to the
   link-editor, but still visible to the dynamic linker?  I believe I
   managed to do that in the past on Linux, but I may have been
   exploiting a bug in the link-editor and/or dynamic linker.  If this
   is really possible, I think this would be the preferred option.


Now what are the options for the problem with the frame functions?

 * Put those functions in a shared library, and link all shared
   libraries and programs that use any of those functions against this
   library.  Since __register_frame_info is referenced by crtbegin.o
   this effectively means everything will be linked against the shared
   libgcc.  Again on systems where GCC isn't the system compiler, we
   can use the static libgcc if a program is only linked against
   system libraries.

 * On ELF systems we can put those functions in a shared library, and
   link only shared libraries and programs that use __frame_state_for
   against this library.  This means that only programs that actually
   use exception handling (or where one of the loaded shared libraries
   use exception handling) will depend on the shared libgcc.

 * On ELF systems, we might include the frame functions in shared
   libraries that need them (i.e. those that actually use exception
   handling), but set DT_AUXILIARY to a shared library containing the
   frame functions.  This will allow things to work if the shared
   libgcc isn't found, but it only works if those libraries re-export
   the frame functions and if programs linked with that library do not
   contain the frame functions.

 * On ELF systems where we have some control over libc, we can put the
   frame functions in libc, and set DT_AUXILIARY for libc to a shared
   libgcc.  That way programs and shared libraries that are linked
   against libc do not have to be explicitly linked against a shared
   libgcc, whereas we leave the option open to install a shared libgcc
   if the frame functions will ever need to be changed.


And what about the C++ specific symbols?  Since we control libstdc++,
we have some additional flexibility here:

 * Keep those in a static library.  If they're also included in
   libstdc++ this static library will only be used for C++ programs
   that don't use the standard C++ library.

 * Include those symbols in libstdc++ and link all C++ programs
   against libstdc++.

 * Include those symbols in a special C++ runtime shared library.

 * Include those symbols in both libstdc++ and the special C++ runtime
   shared library.  That way one doesn't have to distribute two
   libraries for C++ programs that use the standard C++ library.


Systems that use the GNU C Library
==================================

Since I am somewhat involved with the Hurd, I'd like to stress that
the GNU C Library is used on Linux and the Hurd!  On both systems, GCC
is the system compiler which means that there are additional issues to
take into account.  In order to avoid GCC 3.0 to depend on an
unreleased version of the GNU C Library, planning ahead is probably
essential.

Because of the problems mentioned above, the GNU C Library contains
the following symbols from class 1:

   __divdi3; __moddi3; __udivdi3; __umoddi3;

These symbols were present in glibc-2.0, which was released before
symbol version was available to prevent re-exporting these symbols.

The library also contains the following symbols from class 2:

   __register_frame; __register_frame_table; __deregister_frame;
   __register_frame_info; __deregister_frame_info; __frame_state_for;
   __register_frame_info_table;

These symbols are present to ensure that a single copy is used.  The
idea is that every program is linked with -lc, and therefore will use
these symbols from libc.so instead of picking them up from libgcc.a.

Since glibc-2.1, all these symbols are versioned (their version name
is GLIBC_2.0).  It is not possible to remove those symbols from libc.
However, it might be possible to (ab)use symbol versioning to make
sure that new programs don't pick them up from libc.so[2].  But I don't
think it is worth the trouble doing this for the symbols in class 1.

The frame functions pose a bigger problem, since their presece in libc
will make it difficult to make sure that the newest version of those
functions is used at all times.

Possible solutions for this problem:

 * Force people to recompile libc if the frame functions are changed.
   This should be avoided, since recompiling libc isn't really easy,
   and therefore this would restrict the freedom of people to install
   a different version of GCC.

 * Make the definitions of the frame functions included in libc weak.
   This will make sure that they will be overridden by copies included
   in programs or other shared libraries.  This means that once these
   functions are really changed one needs to start linking programs
   against a shared libgcc that provides appropriately versioned symbols.

 * Use the DT_AUXILIARY trick mentioned above.  This means that that
   the shared libgcc should provide appropriately versioned symbols.
   Since this ties libc to libgcc, this probably means that you cannot
   change libgcc's soname without bumping libc's soname.  Of course
   you can use symbol versioning to avoid that.

 * It might be possible to make the link-editor ignore the frame
   symbols in libc[2].

-----
[2] However, as I said before I might be fooled by a bug in the
    link-editor and/or dynamic linker.


Conclusions
===========

Simply turning the complete libgcc as we know it into a shared library
is not a good idea.  We should at least separate out bits that depend
on additional programming language dependent ABI's (such as the C++
parts).  Moreover, I think we should do our very best to avoid a
needless dependency on an additional shared library.  I think this
should be possible for plain C code, and that it is worth the trouble
to try to achieve this.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]