This is the mail archive of the libc-alpha@sources.redhat.com mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Why we need the libc-base patch


If I've followed the threads on this list correctly
(http://sources.redhat.com/ml/libc-alpha/2003-06/msg00124.html),
then it appears that H.J. Lu's libc-base patch has not been
accepted.  H.J. created this patch in response to what I reported as
broken behavior.

Ulrich Drepper commented:

> I've never seen an adequate description of the problem and the way it is
> thought it should be.  The test case is wrong since this basemodnew.c
> file defines symbols with empty version names but the version map
> doesn't export them.  Empty version names are obviously not possible.
> If there are only problems with such invalid input this is a user
> problem and needs no changes in glibc.

I hope that this message suffices to describe the problem and how
(I believe) things should be.

The remainder of this message is broken into the following parts:

1. For the benefit of readers not familiar with the topic, I'll
briefly explain some background: i.e., what is the problem that this
patch (or something equivalent) allows us to solve.

2. I'll outline possible solutions to the problem.  The last of
these is what I believe is, and the ld manual documents as, the
correct solution to the problem.  Unfortunately this feature has
broken.  Ulrich has said of the feature:

> I don't know who came up with this.  It is not the right way.
> Supporting this might very well cause problems for the correct
> way do handle newly versioned DSOs.

but as far as I can see, Ulrich hasn't mentioned what the preferred
solution is -- it may be one of the other methods I outline -- if
that is so, could you please tell us which one is the right way
Ulrich.  Alternatively, could we please have H.J.'s patch applied.

3. I'll show a test case that demonstrate the problem.

Cheers,

Michael



1. BACKGROUND

glibc 2.1 introduced the concept of symbol versioning, which allows
a shared library to export multiple versions of the same symbol.
Each program uses the version of the function that was current when
the program was (statically) linked against the shared library.  As
a result, we can make an incompatible change to a shared library
without having to increase the library's major version number.  In
effect symbol versioning replaces much of the functionality of
shared library major and minor version numbers.  For example, this
allows a single file, /lib/libc.so.6, to export different symbol
definitions for applications linked against glibc 2.0, 2.1, 2.2, and
2.3 (and beyond).

To distinguish the various versions of a symbol, we make use of
linker version scripts and .symver assembler directives.  Some
examples appear below.

There is however one question to be faced by library maintainers who
want to use symbol versioning: if we make the transition from an
 unversioned shared library (for example, glibc 2.0 did not employ
symbol versioning) to a symbol-versioned library, how can we do this
transparently to applications that were linked against the old
(unversioned) library?  (In other words we should not need to
perform any re-linking, etc, of old applications.  They should
continue to use the "original" symbol definition.)


2. SOLUTIONS TO THE PROBLEM OF TRANSPARENTLY MAKING THE TRANSITION
FROM AN UNVERSIONED SHARED LIBRARY TO A LIBRARY WITH SYMBOL
VERSIONING

I see three possible solutions to the problem.  The last of these is
the one that is documented in the glibc manual.  It is also the
method which appears to be broken, and which H.J. Lu's patch fixes.

a) We create a new (incompatible) major version of the shared
library, built using a version script, and deploy that in parallel
with the previous version of the shared library.  We then carry on
creating new versions of symbols (as required) in the new major
library version.  The advantage of this approach is simplicity.  The
disadvantage is the need to deploy two shared libraries.  Clearly
this is not optimal.

b) We continue to use the same major library major version, but
rebuild the library using a version script.  In this case,
applications that were linked against the earlier non-versioned
library will make use of the symbols corresponding to the first
(i.e., oldest) version tag in the version script.

According to my tests, this method seems to work, and this
appears to be the approach taken in glibc 2.1 (though I'm not sure
of this).  However, the behaviour described here is not documented
in the glibc manual (I diescovered it by experimentation).

c) The ld manual says that we should make use of the "unspecified
base version" to solve this problem:

[[
   To do this, you must use multiple `.symver' directives in the
source file.  Here is an example:

     __asm__(".symver original_foo,foo@");
     __asm__(".symver old_foo,foo@VERS_1.1");
     __asm__(".symver old_foo1,foo@VERS_1.2");
     __asm__(".symver new_foo,foo@@VERS_2.0");

   In this example, `foo@' represents the symbol `foo' bound to the
unspecified base version of the symbol.  The source file that
contains this example would define 4 C functions: `original_foo',
`old_foo', `old_foo1', and `new_foo'.
]]

In other words, if we create a new edition of a shared library
employing symbol versioning, then applications that were linked
against the old unversioned library will make use of the symbol
("original_foo" in this case) corresponding to the first of the
.symver directive above.

Unfortunately, this feature does not work.


3. DEMONSTRATION OF BROKEN 'UNSPECIFIED BASE VERSION' FEATURE

[This demonstration comes from a modified version of some code that
H.J. and I exchanged when I initially reported the problem.  The
attached tarball contains all of this code, and a makefile to
automate things.]

We begin by creating an unversioned library:

    $ cat old.c
    void xyz () { printf ("%s\n", __FUNCTION__); }
    $ cc -fPIC   -c -o old.o old.c
    $ cc -Wl,-soname,libfoo.so -shared -o libold.so old.o

Now we create a program, 'olp', linked against that version of the
library:

    $ cat main.c
    int
    main ()
    {
      xyz ();
      return 0;
    }
    $ cc -o oldp libold.so main.c

When we run 'olpd', we see the expected output:

    $ ln -sf libold.so libfoo.so
    $ LD_LIBRARY_PATH=. ./oldp
    xyz

Now we create a new edition of the shared library.  This version
exports two versions of the function 'xyz'.  The 'original_xyz'
function is the unspecified base version, i.e., the one that
according to the ld documentation should be used by 'oldp'.  The
'new_xyz' function is the one that will be used by new programs
lined against this library:

    $ cat new.c
    void original_xyz () { printf ("%s\n", __FUNCTION__); }

    void new_xyz () { printf ("%s\n", __FUNCTION__); }

    __asm__(".symver original_xyz,xyz@");
    __asm__(".symver new_xyz,xyz@@VERS_2.0");
    $ cc    -c -o new.o new.c
    $ cat foo.v
    VERS_2.0 {
      global: xyz;
      local: *;
    } ;
    $ cc -Wl,-soname,libfoo.so,--version-script=foo.v -shared \
            -o libnew.so new.o

Now we create 'newp', a new program linked against the new edition
of the shared library.  When we run the program, we see the expected
result.

    $ cc -o newp libnew.so main.c
    $ ln -sf libnew.so libfoo.so
    $ LD_LIBRARY_PATH=. ./newp
    new_xyz

However, when we run 'oldp', things go wrong:

    $ LD_LIBRARY_PATH=. ./oldp
    new_xyz

We should of course see the output: "original_xyz".

One final note, which was the source of some grief when I initially
tried to isolate this problem: the visibility of this bug is
influenced by the choice of function name.  For example, after my
initial problem report, H.J. sent me a "working" version of the code
which used the name 'foo' for the test function instead of 'xyz'.
However, when I substituted all occurrences of 'foo' for 'xyz', the
breakage was once more revealed.

-- 
+++ GMX - Mail, Messaging & more  http://www.gmx.net +++
Bitte lächeln! Fotogalerie online mit GMX ohne eigene Homepage!

Attachment: test.tar.gz
Description: application/gzip-compressed


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