Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Program won't run because of small difference in version of LIBC

2,543 views
Skip to first unread message

Kenny McCormack

unread,
Dec 2, 2014, 6:00:54 AM12/2/14
to
I have a program that I compiled on one x64 (Ubuntu) system that won't run
on another x64 (Debian) system. I'd like to avoid recompiling it on the
new system.

When I run it (on the new system), I get:

myprog: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.14' not found
(required by myprog)
myprog: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.15' not found
(required by myprog)

And, indeed, on the original system (the one where myprog was compiled), I
have:

$ ls -lsa /lib/x86_64-linux-gnu/libc.so.6
0 lrwxrwxrwx 1 root root 12 Aug 28 00:03 /lib/x86_64-linux-gnu/libc.so.6 -> libc-2.15.so*
$

But on the new system, the same command reveals it to be "2.13".

And so the question is: Is there any (reasonably painless) way to get the
program to work on the new system?

Things I've tried:

1) Did "apt-get upgrade" on the new system, which upgraded a lot of
things, but didn't change the libc version.

2) Tried to recompile the program statically (using -static on the
final compile line). This "almost worked", but generated several
messages to the effect of "this program can't be compiled
statically".

Anyway, so as you can see, I don't mind recompiling it (although I'd prefer
not to) if the recompile can be done on the development system. But it
would be very inconvenient to have to put all the development stuff on the
new system.

--
The motto of the GOP "base": You can't *be* a billionaire, but at least you
can vote like one.

Richard Kettlewell

unread,
Dec 2, 2014, 6:39:47 AM12/2/14
to
gaz...@shell.xmission.com (Kenny McCormack) writes:
> I have a program that I compiled on one x64 (Ubuntu) system that won't run
> on another x64 (Debian) system. I'd like to avoid recompiling it on the
> new system.
[...]
> Anyway, so as you can see, I don't mind recompiling it (although I'd prefer
> not to) if the recompile can be done on the development system. But it
> would be very inconvenient to have to put all the development stuff on the
> new system.

If static linking won’t work then you will have to compile against the
oldest glibc you plan to run against. There’s no way around this
requirement, but there’s more than one way to meet it. For instance, you
could create a Debian install of suitable version in a chroot or VM on
the dev system.

--
http://www.greenend.org.uk/rjk/

Kenny McCormack

unread,
Dec 2, 2014, 6:55:51 AM12/2/14
to
In article <wwvbnnm...@l1AntVDjLrnP7Td3DQJ8ynzIq3lJMueXf87AxnpFoA.invalid>,
There isn't any way to "upgrade" the new system to the right version?

--
Debating creationists on the topic of evolution is rather like trying to
play chess with a pigeon --- it knocks the pieces over, craps on the
board, and flies back to its flock to claim victory.

Richard Kettlewell

unread,
Dec 2, 2014, 7:09:37 AM12/2/14
to
gaz...@shell.xmission.com (Kenny McCormack) writes:
> Richard Kettlewell <r...@greenend.org.uk> wrote:
>> If static linking won’t work then you will have to compile against
>> the oldest glibc you plan to run against. There’s no way around
>> this requirement, but there’s more than one way to meet it. For
>> instance, you could create a Debian install of suitable version in a
>> chroot or VM on the dev system.
>
> There isn't any way to "upgrade" the new system to the right version?

Glibc 2.13 suggests you have Debian stable.

testing and unstable have more recent Glibc (2.19) so you could use one
of those, if their weaker stability guarantees are acceptable.

You could attempt to install unstable’s Glibc in a system otherwise
running stable but nobody is making any promises that that will work or
even be installable.

--
http://www.greenend.org.uk/rjk/

Noob

unread,
Dec 2, 2014, 7:17:26 AM12/2/14
to
Hello Dr. Jekyll,

Kenny McCormack wrote:

> I have a program that I compiled on one x64 (Ubuntu) system that won't run
> on another x64 (Debian) system. I'd like to avoid recompiling it on the
> new system.
>
> When I run it (on the new system), I get:
>
> myprog: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.14' not found
> (required by myprog)
> myprog: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.15' not found
> (required by myprog)

(Not quite the answer you're looking for, but I thought I'd mention it
for completeness.) Have a look at this article:

"Creating portable Linux binaries"
http://insanecoding.blogspot.com/2012/07/creating-portable-linux-binaries.html

Then find which symbols bump your requirements to GLIBC 2.15
$ objdump -T myapp | grep GLIBC_2

Maybe there's an easy way to work around this/these symbols?

Regards.

James K. Lowden

unread,
Dec 2, 2014, 8:38:11 PM12/2/14
to
On Tue, 02 Dec 2014 12:09:34 +0000
Richard Kettlewell <r...@greenend.org.uk> wrote:

> You could attempt to install unstable?s Glibc in a system otherwise
> running stable but nobody is making any promises that that will work
> or even be installable.

This is crazy, right? glibc is just a library. Park it somewhere,
point to it with RPATH in the executable, job done. Why shouldn't it
be installable, and why shouldn't it work?

> > 2) Tried to recompile the program statically (using -static on
> > the final compile line). This "almost worked", but generated
> > several messages to the effect of "this program can't be compiled
> > statically".

I think I would be tempted to put glibc.a on the linker command
line, and skip -static as an option. I would expect that to work, and
for ldd to subsequently report no runtime dependency on glibc.

--jkl



Forsythe

unread,
Dec 3, 2014, 12:10:40 AM12/3/14
to
Richard Kettlewell <r...@greenend.org.uk> wrote:
> gaz...@shell.xmission.com (Kenny McCormack) writes:
>> I have a program that I compiled on one x64 (Ubuntu) system that won't run
>> on another x64 (Debian) system. I'd like to avoid recompiling it on the
>> new system.
> [...]
>> Anyway, so as you can see, I don't mind recompiling it (although I'd prefer
>> not to) if the recompile can be done on the development system. But it
>> would be very inconvenient to have to put all the development stuff on the
>> new system.
>
> If static linking won’t work then you will have to compile against the
> oldest glibc you plan to run against.

To add to this, if static linking against glibc is painful you might
try another libc. I know the musl team makes static compiling a
selling point: see option 1 of http://www.musl-libc.org/how.html .

Jorgen Grahn

unread,
Dec 3, 2014, 2:36:01 AM12/3/14
to
On Wed, 2014-12-03, James K. Lowden wrote:
> On Tue, 02 Dec 2014 12:09:34 +0000
> Richard Kettlewell <r...@greenend.org.uk> wrote:
>
>> You could attempt to install unstable?s Glibc in a system otherwise
>> running stable but nobody is making any promises that that will work
>> or even be installable.
>
> This is crazy, right? glibc is just a library.

It's not just printf() and stuff -- it's a very special library deeply
rooted in the system ...

> Park it somewhere,
> point to it with RPATH in the executable, job done. Why shouldn't it
> be installable, and why shouldn't it work?

I can't give specific warnings, but doing that would make me rather
nervous ...

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

Nicolas George

unread,
Dec 3, 2014, 3:31:11 AM12/3/14
to
"James K. Lowden" , dans le message
<20141202203806.c...@speakeasy.net>, a écrit :
> This is crazy, right? glibc is just a library.

Absolutely not, it is not just a library.

For starters, it is the library that provides the dynamic loader: you can
not just drop it somewhere and point RPATH or LD_LIBRARY_PATH to it, because
it is its job to understand what RPATH and LD_LIBRARY_PATH mean.

And if that alone was not enough, it also contains dynamically loaded parts,
such as the NSS system and iconv converters, and complex data files (the
locales database), which reside at a specific place that makes the whole
package not relocatable.

Richard Kettlewell

unread,
Dec 3, 2014, 4:24:16 AM12/3/14
to
"James K. Lowden" <jklo...@speakeasy.net> writes:
> Richard Kettlewell <r...@greenend.org.uk> wrote:

>> You could attempt to install unstable’s Glibc in a system otherwise
>> running stable but nobody is making any promises that that will work
>> or even be installable.
>
> This is crazy, right? glibc is just a library. Park it somewhere,
> point to it with RPATH in the executable, job done. Why shouldn't it
> be installable, and why shouldn't it work?

No, job not done. Software periodically needs security updates and
Glibc is not immune to this. Static linking has the same serious
problem.

>>> 2) Tried to recompile the program statically (using -static on the
>>> final compile line). This "almost worked", but generated several
>>> messages to the effect of "this program can't be compiled
>>> statically".
>
> I think I would be tempted to put glibc.a on the linker command
> line, and skip -static as an option. I would expect that to work, and
> for ldd to subsequently report no runtime dependency on glibc.

-static actively prevents use of dynamic linking. Just mentioning a
static library does no such thing. So the outcome is likely to still be
dynamically linked. Even if it isn’t, see above.

The answer that will _actually work_ is to compile against the correct
Glibc. Anything else just makes life harder.

--
http://www.greenend.org.uk/rjk/

Kenny McCormack

unread,
Dec 3, 2014, 7:12:19 AM12/3/14
to
In article <wwvwq69...@l1AntVDjLrnP7Td3DQJ8ynzIq3lJMueXf87AxnpFoA.invalid>,
Richard Kettlewell <r...@greenend.org.uk> wrote:
...
>-static actively prevents use of dynamic linking. Just mentioning a
>static library does no such thing. So the outcome is likely to still be
>dynamically linked. Even if it isn’t, see above.

I might try the "including glibc.a on the link line" method at some point.
Or read the "Producing portable Linux binaries" link/article.

>The answer that will _actually work_ is to compile against the correct
>Glibc. Anything else just makes life harder.

Or, I might just end up installing Ubuntu on the target system. That
should solve it (even more forcefully)...

Anyway, this is all for educational purposes; I assume I'll end up learning
something in any case.

--
Faith doesn't give you the answers; it just stops you from asking the questions.

Nicolas George

unread,
Dec 3, 2014, 7:56:47 AM12/3/14
to
Kenny McCormack, dans le message <m5mun0$cnr$1...@news.xmission.com>, a
écrit :
> Anyway, this is all for educational purposes; I assume I'll end up learning
> something in any case.

If you purposefully decide to ignore the good advice and take the bad, you
will learn something, but not something good.

Kenny McCormack

unread,
Dec 3, 2014, 9:27:17 AM12/3/14
to
In article <547f088c$0$2890$426a...@news.free.fr>,
Is this comment supposed to mean something?

To what (if anything) do you refer?

--
The scent of awk programmers is a lot more attractive to women than
the scent of perl programmers.

(Mike Brennan, quoted in the "GAWK" manual)

Rainer Weikusat

unread,
Dec 3, 2014, 10:22:49 AM12/3/14
to
Jorgen Grahn <grahn...@snipabacken.se> writes:
> On Wed, 2014-12-03, James K. Lowden wrote:
>> Richard Kettlewell <r...@greenend.org.uk> wrote:
>>> You could attempt to install unstable?s Glibc in a system otherwise
>>> running stable but nobody is making any promises that that will work
>>> or even be installable.

[...]

>> Park it somewhere,
>> point to it with RPATH in the executable, job done. Why shouldn't it
>> be installable, and why shouldn't it work?
>
> I can't give specific warnings, but doing that would make me rather
> nervous ...

It's not that simple because 'other libraries' also depend on the C
library and one will rather want to avoid a situation where different
parts of a program use different versions of the same routines but
perfectly doable. Example script which can be used to compile/ link code
for a different C library (as the version should communicate, this is a
couple of years old):

---------
#!/bin/sh
#
BASE=/usr/local/glibc-2.11
exec gcc -isystem $BASE/include -isystem $BASE/usr/include -Wl,-dynamic-linker -Wl,$BASE/lib/ld-linux.so.2 -L $BASE/lib -Wl,-rpath -Wl,$BASE/lib "$@"
---------

Nobody

unread,
Dec 3, 2014, 11:52:41 AM12/3/14
to
On Tue, 02 Dec 2014 11:00:51 +0000, Kenny McCormack wrote:

> And so the question is: Is there any (reasonably painless) way to get the
> program to work on the new system?

The easiest way is to install the target version of glibc (2.13) on the
build system (preferably with a non-standard prefix so that it doesn't
interfere with the rest of the system), and use that.

An alternative involves using __asm__(".symver ...") directives to force
specific symbol versions. These have to appear in each translation unit
before any code which uses the symbol.

Jorgen Grahn

unread,
Dec 3, 2014, 2:50:39 PM12/3/14
to
On Wed, 2014-12-03, Kenny McCormack wrote:
> In article <wwvwq69...@l1AntVDjLrnP7Td3DQJ8ynzIq3lJMueXf87AxnpFoA.invalid>,
> Richard Kettlewell <r...@greenend.org.uk> wrote:
> ...
>>-static actively prevents use of dynamic linking. Just mentioning a
>>static library does no such thing. So the outcome is likely to still be
>>dynamically linked. Even if it isn???t, see above.
>
> I might try the "including glibc.a on the link line" method at some point.
> Or read the "Producing portable Linux binaries" link/article.
>
>>The answer that will _actually work_ is to compile against the correct
>>Glibc. Anything else just makes life harder.
>
> Or, I might just end up installing Ubuntu on the target system. That
> should solve it (even more forcefully)...
>
> Anyway, this is all for educational purposes; I assume I'll end up learning
> something in any case.

One thing I never understood from the original posting: you don't
/want/ to recompile your software on the target machine, but what's
the big issue with doing that? It is after all the normal way of
doing it, on Linux.

(Is the target very poor on resources? Not connected to the
Internet so it's hard to install the tools?)

James K. Lowden

unread,
Dec 3, 2014, 10:33:47 PM12/3/14
to
On Wed, 03 Dec 2014 15:22:44 +0000
Rainer Weikusat <rwei...@mobileactivedefense.com> wrote:

> >> Park it somewhere, point to it with RPATH in the executable, job
> >> done. Why shouldn't it be installable, and why shouldn't it
> >> work?
> >
> > I can't give specific warnings, but doing that would make me rather
> > nervous ...
>
> It's not that simple because 'other libraries' also depend on the C
> library and one will rather want to avoid a situation where different
> parts of a program use different versions of the same routines but
> perfectly doable.

Yes, there's no denying that's a risk, but it's easy to overstate.

I confess I don't know how it comes to pass that "different parts of a
program use different versions of the same routines". The linker
resolves symbols, i.e. assigns addresses to named pieces of code. All
references to, say, memcpy should resolve to one address. As the
linker proceeds with the work of resolving each symbol, surely it can't
dispose of the mapping? Surely it must memoize the address and resolve
all subsequent references the same way?

(Unless we're talking about versioned symbols, in which case I get it.
But it should be possible for a mere mortal to check for such things.
It's all knowable before execution begins.)

I can see, sort of, how the problem would arise if two major versions
were specified for the same soname (by different libraries, of
course). The linker loads foo.so.1 for library and A and resolves all
its symbols, then moves on to load foo.so.2 for library B, treating
them as distinct namespaces. It's not clear that's the best policy,
though. I think I would argue either that the later version wins (and
so all prior references have to be updated) or that the program has
violated the one-definition rule and cannot continue.

But I find myself puzzled by the OP's message:

> myprog: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.14' not
> found

AFAIK glib 2.13 to present are all libc.so.6. What part of the system
is insisting that libc.so.6 -- major version 6 -- be of some particular
vintage of glibc, namely 2.14?

I'm guessing it's our old friend ld.so, but I don't understand the
rationale. If GLIBC_2.14 is incompatible with GLIBC_2.13 such that a
program depending one cannot use the other, then they should not both
be called libc.so.6.

ISTM the policy of requiring "a newer version of version 6" is
convenient to developers and not to users (where the terms "developer"
and "user" are necessarily fluid). It surely runs counter to the
convention of respecting the major version number, which makes me
wonder why we still bother with it.

--jkl

James K. Lowden

unread,
Dec 3, 2014, 10:36:41 PM12/3/14
to
On 03 Dec 2014 08:31:08 GMT
Nicolas George <nicolas$geo...@salle-s.org> wrote:

> "James K. Lowden" , dans le message
> <20141202203806.c...@speakeasy.net>, a écrit :
> > This is crazy, right? glibc is just a library.
>
> Absolutely not, it is not just a library.
>
> For starters, it is the library that provides the dynamic loader: you
> can not just drop it somewhere and point RPATH or LD_LIBRARY_PATH to
> it, because it is its job to understand what RPATH and
> LD_LIBRARY_PATH mean.

I don't buy it. glibc knows nothing of RPATH and provides no interface
to the runtime linker.

$ nm -D $(ldd $(which ls) | awk '/libc/ {print $3}') | grep dlopen
0000000000130670 T __libc_dlopen_mode

Of dlopen(3), my NetBSD manual says:

"(These functions are not in a library. They are included in
every dynamically linked program automatically.)"

My Ubuntu manual says the functions are provided by libdl.

ISTM you're describing a chicken-and-egg problem: the loaded program
loads libc to load itself. Since we know that's not true, we must
assume something else loads the program. There is no reason to assume
that the loaded program must use the same library as its loader to
interface with the dynamic linker. It isn't even required that the
loaded program link to libc at all. That leaves me with "it's just a
library".

> And if that alone was not enough, it also contains dynamically loaded
> parts, such as the NSS system and iconv converters, and complex data
> files (the locales database), which reside at a specific place that
> makes the whole package not relocatable.

Heavens to Murgatroid, *complex* data files!

First of all, it certainly should be possible to have more than one
version of glibc installed in /usr/lib or whatever FHS prescribes.
That's the whole point of dynamic libraries, right?

If I'm not mistaken, the files you refer to reside at a fixed location,
not relative to that of glibc. Probably sharing them is fine; probably
their format is consistent between versions. If not, they have no
business sharing major versions.

I don't know what you mean by "whole package". Are you saying half
of /etc comes with glibc?

Simplest is probably to install the newer version of glibc on the
target machine, with or without the help of the package manager.
Alternatively, install the older version on the build machine, and
build against it.

--jkl

Nicolas George

unread,
Dec 4, 2014, 3:44:37 AM12/4/14
to
"James K. Lowden" , dans le message
<20141203223638.9...@speakeasy.net>, a écrit :
> I don't buy it.

It's not to sell.

> My Ubuntu manual says the functions are provided by libdl.

For your information, libdl is part of glibc, same as the dynamic loader,
which is not libdl.

> ISTM you're describing a chicken-and-egg problem

ISTM you do not understand how share libraries work.

> Simplest is probably to install the newer version of glibc on the
> target machine

Well, please try it, and come back tell us when you have failed and
reinstalled your system.

Richard Kettlewell

unread,
Dec 4, 2014, 5:52:10 AM12/4/14
to
"James K. Lowden" <jklo...@speakeasy.net> writes:
> But I find myself puzzled by the OP's message:
>
>> myprog: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.14' not
>> found
>
> AFAIK glib 2.13 to present are all libc.so.6. What part of the system
> is insisting that libc.so.6 -- major version 6 -- be of some particular
> vintage of glibc, namely 2.14?

If you compile against Glibc 2.x then (in general) the result will only
run against Gilbc 2.y, for y >= x. New functions are added, structure
layouts change, etc. This shouldn’t be surprising. The question is how
that’s managed.

> I'm guessing it's our old friend ld.so, but I don't understand the
> rationale. If GLIBC_2.14 is incompatible with GLIBC_2.13 such that a
> program depending one cannot use the other, then they should not both
> be called libc.so.6.

Your description isn’t correct. A program built against Glibc 2.13 can
use Glibc 2.14 at runtime. The thing that doesn’t work is running
against an older library than you built against.

--
http://www.greenend.org.uk/rjk/

Richard Kettlewell

unread,
Dec 4, 2014, 5:54:25 AM12/4/14
to
"James K. Lowden" <jklo...@speakeasy.net> writes:
> If I'm not mistaken, the files you refer to reside at a fixed location,
> not relative to that of glibc. Probably sharing them is fine; probably
> their format is consistent between versions. If not, they have no
> business sharing major versions.

Major versions in sonames are there to control the behavior of the
runtime linker, not to describe the syntax of external files.

--
http://www.greenend.org.uk/rjk/

Nicolas George

unread,
Dec 4, 2014, 6:51:56 AM12/4/14
to
Richard Kettlewell , dans le message
<wwvfvcv...@l1AntVDjLrnP7Td3DQJ8ynzIq3lJMueXf87AxnpFoA.invalid>, a
écrit :
> Your description isn't correct. A program built against Glibc 2.13 can
> use Glibc 2.14 at runtime. The thing that doesn't work is running
> against an older library than you built against.

This is a bit of an exaggeration: hello_world.c linked with 2.19 runs fine
2.13. The statement could be moderated as: it is not guaranteed to work, and
will indeed not work when some non-trivial APIs are used.

Richard Kettlewell

unread,
Dec 4, 2014, 8:38:07 AM12/4/14
to
Nicolas George <nicolas$geo...@salle-s.org> writes:
> Richard Kettlewell:
>> Your description isn't correct. A program built against Glibc 2.13 can
>> use Glibc 2.14 at runtime. The thing that doesn't work is running
>> against an older library than you built against.
>
> This is a bit of an exaggeration: hello_world.c linked with 2.19 runs fine
> 2.13. The statement could be moderated as: it is not guaranteed to work, and
> will indeed not work when some non-trivial APIs are used.

Fair point, though I thought I caveated it adequately in the other
paragraph?

--
http://www.greenend.org.uk/rjk/

Rainer Weikusat

unread,
Dec 4, 2014, 2:03:13 PM12/4/14
to
"James K. Lowden" <jklo...@speakeasy.net> writes:
> On Wed, 03 Dec 2014 15:22:44 +0000
> Rainer Weikusat <rwei...@mobileactivedefense.com> wrote:
>
>> >> Park it somewhere, point to it with RPATH in the executable, job
>> >> done. Why shouldn't it be installable, and why shouldn't it
>> >> work?
>> >
>> > I can't give specific warnings, but doing that would make me rather
>> > nervous ...
>>
>> It's not that simple because 'other libraries' also depend on the C
>> library and one will rather want to avoid a situation where different
>> parts of a program use different versions of the same routines but
>> perfectly doable.
>
> Yes, there's no denying that's a risk, but it's easy to overstate.
>
> I confess I don't know how it comes to pass that "different parts of a
> program use different versions of the same routines". The linker
> resolves symbols, i.e. assigns addresses to named pieces of code. All
> references to, say, memcpy should resolve to one address. As the
> linker proceeds with the work of resolving each symbol, surely it can't
> dispose of the mapping? Surely it must memoize the address and resolve
> all subsequent references the same way?

Sorry, I was being imprecise and/or my memory failed me. According to
some quick test I made

- just using -rpath but without also changing the runtime
linker yields an executable which immediately segfaults

- changing the linker and not using rpath, linking fails because
of a missing smybol

- changing linker and rpath and linking with some library
compiled against the other libc succeeds and 'works' for simple
case, however ...

... looking at this:

[rw@torch]/tmp $ldd a.out
linux-gate.so.1 => (0xb7886000)
libcrypto.so.0.9.8 => /usr/lib/libcrypto.so.0.9.8 (0xb7723000)
libc.so.6 => /usr/local/glibc-2.11/lib/libc.so.6 (0xb75d3000)
libdl.so.2 => /usr/local/glibc-2.11/lib/libdl.so.2 (0xb75cf000)
libz.so.1 => /usr/lib/libz.so.1 (0xb75b9000)
/usr/local/glibc-2.11/lib/ld-linux.so.2 (0xb7887000)

communicates that code compiled agains different versions of libc ends
up in the same address space. And this is a recipe for disaster because
the code in the 'system' libcrypto has been compiled with the
information from the headers of the old libc. This means its idea of
'structure size/ layouts' may differ from that of the code in the used
libc version.

Kaz Kylheku

unread,
Dec 4, 2014, 4:36:30 PM12/4/14
to
On 2014-12-02, Kenny McCormack <gaz...@shell.xmission.com> wrote:
> I have a program that I compiled on one x64 (Ubuntu) system that won't run
> on another x64 (Debian) system. I'd like to avoid recompiling it on the
> new system.
>
> When I run it (on the new system), I get:
>
> myprog: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.14' not found
> (required by myprog)
> myprog: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.15' not found
> (required by myprog)

The program is failing the version node check here: a cheap, early test
which tells the linker that the executable contains symbol references
that cannot be satisfied (because it depends on version nodes that
don't exist in the library).

There are no general hacks to fix this. The best way is to set up a less
"avant garde" compilation environment whose sysroot has an older glibc:
at least as old as that on any target you want your binaries to run on.

The newer glibc you have does have the old versions of functions there.
Programs compiled for an older glibc will run on your system. So,
darn it, why can't you just build programs that way too?

A mechanism could be provided for that in the linker: say, a command line
option to say "link the following/preceding library as if it only had the
following version nodes, ignoring the newer ones".

The problem would be that it's not general. It's not general because
the program depends not only on the .so file but also on header files.
Header files define structures, as well macros and inline functions
which peek at those structures directly. The available header files
you're compiling with are the current ones, and not those of the old
library version.

If you compile with the current header files, you are getting the current
structure layouts, and the current macros and inline functions which work with
them. But if you override the symbols in the library executable, you
are then passing these structures to old functions, which expect the
old layout (which was defined by the old header files).

Symbol versioning exists, in large part, to handle these changes.

Old binaries work properly with a newer library, because they not only select
the old versions of functions from the library, but their compiled code matches
that version, because it was based on the header files.

A hack (force old functions with new library headers) could work, sometimes,
for some functions. But in general it would break. So it is a bad idea to make
it easy to do as a sweeping linker "all in one fell swoop" option. You're
forced to add declarations to your program to specify, symbol by symbol,
each version you want.

Rainer Weikusat

unread,
Dec 4, 2014, 7:12:01 PM12/4/14
to
Kaz Kylheku <k...@kylheku.com> writes:
> On 2014-12-02, Kenny McCormack <gaz...@shell.xmission.com> wrote:

[...]

> If you compile with the current header files, you are getting the current
> structure layouts, and the current macros and inline functions which work with
> them. But if you override the symbols in the library executable, you
> are then passing these structures to old functions, which expect the
> old layout (which was defined by the old header files).
>
> Symbol versioning exists, in large part, to handle these changes.
>
> Old binaries work properly with a newer library, because they not only select
> the old versions of functions from the library, but their compiled code matches
> that version, because it was based on the header files.

A scenario where this possibly fails would be: A pointer to a structure
created by the old binary is passed to a library function of a shared
library which was compiled for the newer libc and passes the pointer on
to that.


James K. Lowden

unread,
Dec 4, 2014, 11:53:41 PM12/4/14
to
Thanks for that illustration; I agree it's an ugly state of affairs.
The questions in my mind are: how ugly, and what to do?

I still don't understand why the linker created the image you're
showing. AFAIK, both copies of libc have one soname: libc.so.6. (Can
you confirm?) I don't understand why they're both linked in, because as
far as the linker is concerned, one is redundant: same soname, same
functions, ergo same definitions. Choose one, discard the other.

If the "'structure size/ layouts' may differ" in the two versions of
libc, they are not binary compatible. Libraries that are not binary
compatible should have different major versions. Libraries that are
not binary compatible and claim the same major version subvert
the linker's opportunity to prevent invalid linkages.

As you know, the linker routinely encounters more than one definition
for a symbol and applies them in a priority order (letting us replace
malloc, for example). It reasonably assumes that two versions of equal
priority are equivalent. I think it's fair to assume that two versions
of structs used by libcrypto -- and supplied by two libraries both
calling themselves by the soname "libc.so.6" -- are interchangable.
I don't know what else the linker can be expected to do.

If two libraries with the same soname both have a function F, then
surely it's OK use either one (not both) for every reference to F. If
they have different sonames, then by convention we have two
(potentially) incompatible definitions of the same function. By the
rules of C, each function can have one and only one definition in an
executable image, and thus the link must be rejected.

I am left with the following:

1. Why are two libraries with one soname in the same executable
image? Is that not an error on the part of the linker?

2. Why are two libraries with the same soname feared to have
"'structure size/ layouts' [that] may differ"? Is it not the role of
the major version to signal such differences?

--jkl

James K. Lowden

unread,
Dec 4, 2014, 11:56:11 PM12/4/14
to
On 04 Dec 2014 08:44:34 GMT
Nicolas George <nicolas$geo...@salle-s.org> wrote:

> ISTM you do not understand how share libraries work.

It may be that I don't. I did maintain one used by many thousands of
programmers on a variety of hardware and software platforms. I am
relying on that experience.

> Well, please try it, and come back tell us when you have failed and
> reinstalled your system.

You and I are saying different, orthogonal things. You are saying libc
is special, and that I don't realize how special it is. You don't
necessarily mean it *should* be special (or you don't care), but just
that's the way things are in the GNU world in 2014.

I'm saying it's not special. It can be swapped out, just like any
other part of the system. I don't have to link to it. I don't have to
use dlopen(3) to provoke ld.so into action. I don't have to go through
malloc to allocate memory to my address space. There's a kernel, and
the services it provides drive the userspace experience. libc is
strictly a convenience, albeit a welcome one. Any specialness it's
allowed to acquire impedes that freedom and is therefore a mistake.

Moreover, if I understand the state of affairs correctly, there's a
tacit, unstated consensus that specialness in glibc is OK. That, as I
said at the outset, is crazy.

--jkl

James K. Lowden

unread,
Dec 4, 2014, 11:56:22 PM12/4/14
to
On Thu, 04 Dec 2014 10:52:07 +0000
Richard Kettlewell <r...@greenend.org.uk> wrote:

Richard, your messages on this list are unfailingly polite. We
disagree in this case about the role of the major version and the
meaning of the minor. I hope you won't hold it against me.

> New functions are added, structure layouts change, etc. This
> shouldn?t be surprising. The question is how that?s managed.

Yes, change is the only constant, for sure. :-)

I'm saying "how that's managed" is with the major version number.
What's happening instead is that glibc is flying under the radar,
flouting convention, and creating binary incompatibility without
bumping the major version.

Why? I should be able to examine my system and know from the metadata
whether things are supposed to work together. If an application says
it needs libc.so.6, and I have a (valid) libc.so.6, it should run. If
the library has been unable to achieve backward compatibilty, the major
version is where that fact should be announced, not by the creation of
a new, required symbol.

If some application has some particular constraint that it requires the
"2.14 version" of libc.so.6, OK, but it has to say so in the release
notes and perform its own test at runtime. Just because something is
binary *compatibile* doesn't mean behavior is identical or satisfactory
in all regards. Subtle changes are not the in purview of ld.so.

> Your description isn?t correct. A program built against Glibc 2.13
> can use Glibc 2.14 at runtime. The thing that doesn?t work is running
> against an older library than you built against.

Were that the case, no developer could build against the "next" version
until all downstream clients had been upgraded.

That's not how it's meant to be. My copy of The Linux Programming
Interface says (section 41.6, page 844):

"By convention, the major version identifier takes the form of
a number that is sequentially incremented with each incompatible
release of the library. In addition to the major version identifier,
the real name also includes a minor version identifier, which
distinguishes compatible minor versions within the library major
version. The real name employs the format convention
libname.so.major-id.minor-id."

I also read the libtool documentation ~10 years ago, and it said the
same thing: minor versions exist to distinguish versions. 2.14 might
be better than 2.13, but the data structures and functions are the
same. Building with 2.14 and running with 2.13 is valid; you're just
saddled with the behavior of the older version.

This is absolutely reasonable, exactly what you want. Developers
always have newer software than users do. Of course you'd want to
accrete changes in the library without imposing an upgrade on the users
until it's really needed.

glibc is the only library I know that works this way. I would bet that
of the 170 .so files in my /lib tree, a great many are older than those
used by the developers of the applications that build them. glibc is
the only one saying version is 6 is not version 6.

And the community is ill-served. Google claims "GLIBC_2.14 major
version" returns 343,000 results, all problems. The message,

> myprog: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.14' not
> found

is incomprehensible because it's produced at too low a level. The very
fact that the OP's question arose on this list is prima facia evidence.
If it said "glibc.so.7 not found", it would both be more correct and
easier for the user to understand.

What the OP did was perfectly OK, and should be supported. When things
go wrong, it is not always the user's fault. Often it's the developer
taking the easy way out, or failing to stick to the protocol.

--jkl

Nobody

unread,
Dec 5, 2014, 7:15:10 AM12/5/14
to
On Thu, 04 Dec 2014 19:03:09 +0000, Rainer Weikusat wrote:

> communicates that code compiled agains different versions of libc ends up
> in the same address space. And this is a recipe for disaster because the
> code in the 'system' libcrypto has been compiled with the information from
> the headers of the old libc. This means its idea of 'structure size/
> layouts' may differ from that of the code in the used libc version.

This shouldn't be a problem, because if the structure layout changes,
any function which takes a pointer to such a structure will get a new
symbol version.

Where structure changes actually become problematic is if one library uses
another library's structures in its public API, and passes pointers to
these structures from the client to the library.

There are other reasons why such "pass-through" is problematic. A
common one is large file support (LFS) on 32-bit systems. By default,
open() will refuse to open a file larger than 2 GiB because it cannot
robustly implement lseek() (the returned offset being a signed 32-bit
value). Instead, you have to either pass O_LARGEFILE to open() or use
open64().

Rather than requiring programmers to litter their code with non-standard
flags and/or functions, libc provides the _FILE_OFFSET_BITS macro. If
this is pre-defined to 64, the POSIX API is transparently mapped to the
large file API: off_t is an alias for off64_t, open() for open64(),
lseek() for lseek64(), etc. This allows code which can handle large files
(e.g. doesn't try to store file offsets in a "long") to access them with
minimal changes, without making legacy code unsafe.

Unfortunately, this approach falls down if you pass descriptors between
LFS-aware and LFS-unaware modules (libraries and executable). An LFS-aware
module may pass descriptors for large files to LFS-unaware code which
isn't expecting a simple lseek() to fail with EOVERFLOW.

Nicolas George

unread,
Dec 5, 2014, 7:26:29 AM12/5/14
to
"James K. Lowden" , dans le message
<20141204235619.9...@speakeasy.net>, a écrit :
> I'm saying "how that's managed" is with the major version number.

And you are wrong. This is only true in the simplest cases.

First, it is only true when doing incompatible changes: removing symbols,
changing public structures layouts, etc. Projects never bump the SONAME when
they do compatible changes such as adding new functions.

Your second error is to neglect the burden of maintaining the libraries with
regard to SONAME.

If you bump the SONAME of the libc, you have to upgrade ALL THE LIBRAIRES of
the system, because all the libraries use the libc. You also have to bump
all their SONAMEs. If you do not do that, you end up with several versions
of the libc indirectly loaded by different libraries, and all hell break
loose. I remember an old FreeBSD install where some programs loaded four
different libcs: version 4, version 4 with threads, version 5, version 5
with threads.

The GLibc has solved this issue a long time ago by using a more fine-grained
mechanism: ELF symbols versionning.

> Why? I should be able to examine my system and know from the metadata
> whether things are supposed to work together.

That is achieved; you are just not looking at the right metadata.

Nobody

unread,
Dec 5, 2014, 7:28:23 AM12/5/14
to
On Thu, 04 Dec 2014 23:56:05 -0500, James K. Lowden wrote:

> I'm saying it's not special. It can be swapped out, just like any other
> part of the system. I don't have to link to it. I don't have to use
> dlopen(3) to provoke ld.so into action. I don't have to go through malloc
> to allocate memory to my address space. There's a kernel, and the
> services it provides drive the userspace experience. libc is strictly a
> convenience, albeit a welcome one.

This is only true at the most superficial level. libc provides the public
API on which userspace depends. Some of those functions are trivial
wrappers around system calls. Some of them aren't.

E.g. the interfaces to the system database (users, groups, hosts,
services, etc) are backed by a fair amount of machinery to support
centralised databases on networks. Trying to bypass the <pwd.h> interfaces
and obtaining user information using open("/etc/passwd",...) will fail on
systems where the user database uses NIS or LDAP.

So while you could theoretically bypass libc (unlike the kernel, which is
running in a privileged context), that doesn't really mean very much in
practice. The interfaces on which libc is built are far less stable than
those which it exposes.

Nicolas George

unread,
Dec 5, 2014, 8:56:16 AM12/5/14
to
"James K. Lowden" , dans le message
<20141204235605.d...@speakeasy.net>, a écrit :
> It may be that I don't. I did maintain one used by many thousands of
> programmers on a variety of hardware and software platforms.

The number of platforms has little to do with understanding how shared
libraries work, and the number of users even less. For example, libz is very
widely used, but as a library, it is completely trivial.

> You and I are saying different, orthogonal things. You are saying libc
> is special, and that I don't realize how special it is. You don't
> necessarily mean it *should* be special (or you don't care), but just
> that's the way things are in the GNU world in 2014.

I already explained why it MUST be special. You missed it.

> I don't have to
> use dlopen(3) to provoke ld.so into action.

But you fail to realize that ld.so IS PART OF THE LIBC.

Richard Kettlewell

unread,
Dec 5, 2014, 11:26:50 AM12/5/14
to
"James K. Lowden" <jklo...@speakeasy.net> writes:
> Richard Kettlewell <r...@greenend.org.uk> wrote:
>
> Richard, your messages on this list are unfailingly polite. We
> disagree in this case about the role of the major version and the
> meaning of the minor. I hope you won't hold it against me.

No problem!

>> New functions are added, structure layouts change, etc. This
>> shouldn’t be surprising. The question is how that’s managed.
>
> Yes, change is the only constant, for sure. :-)
>
> I'm saying "how that's managed" is with the major version number.
> What's happening instead is that glibc is flying under the radar,
> flouting convention, and creating binary incompatibility without
> bumping the major version.

Glibc isn’t unique in this respect. GTK+ does it too, for instance. It
doesn’t use symbol versioning, but it does add new symbols without
changing soname.

> Why? I should be able to examine my system and know from the metadata
> whether things are supposed to work together. If an application says
> it needs libc.so.6, and I have a (valid) libc.so.6, it should run. If
> the library has been unable to achieve backward compatibilty, the major
> version is where that fact should be announced, not by the creation of
> a new, required symbol.
>
> If some application has some particular constraint that it requires the
> "2.14 version" of libc.so.6, OK, but it has to say so in the release
> notes and perform its own test at runtime. Just because something is
> binary *compatibile* doesn't mean behavior is identical or satisfactory
> in all regards. Subtle changes are not the in purview of ld.so.

Within an OS distribution, dependency tracking solves this problem quite
adequately. 1990s technology in action!

Outside it, software distributors who want to ship object code have to
build for the oldest platform they want to support.

But the same would be true whatever approach was taken to shared library
versioning: if they build against a hypothetical libc.so.25 and the
customer only has libc.so.24, the customer is likely to be disappointed.

As such I must be missing what your alternative proposal is, given that
the only one I’ve so far imagined doesn’t solve any of today’s unsolved
problems, and has serious drawbacks of its own. Nineteen copies of
libc? (Twenty next year?) And nineteen copies of every library that
depends on it? And I don’t know how many copies of every library that
depends on GTK+? I can’t see how you avoid a combinatoric explosion of
library versions.

>> Your description isn’t correct. A program built against Glibc 2.13
>> can use Glibc 2.14 at runtime. The thing that doesn?t work is running
>> against an older library than you built against.
>
> Were that the case, no developer could build against the "next" version
> until all downstream clients had been upgraded.

It really is the case. The thread started with a demonstration of it
(built against 2.15, tried to run against 2.13, disappointment).

> That's not how it's meant to be. My copy of The Linux Programming
> Interface says (section 41.6, page 844):
>
> "By convention, the major version identifier takes the form of
> a number that is sequentially incremented with each incompatible
> release of the library. In addition to the major version identifier,
> the real name also includes a minor version identifier, which
> distinguishes compatible minor versions within the library major
> version. The real name employs the format convention
> libname.so.major-id.minor-id."

(That’s not a work I know.) The meaning of that text hinges on the
meaning of ‘incompatible’. If it only refers to backward-compatibility
then it describes the scheme actually used by Glibc and GTK+. If it
means forward- and backward-compatibility - i.e. complete
substitutability - then it doesn’t reflect what happens in practice.

> I also read the libtool documentation ~10 years ago, and it said the
> same thing: minor versions exist to distinguish versions.
> 2.14 might be better than 2.13, but the data structures and functions
> are the same. Building with 2.14 and running with 2.13 is valid;
> you're just saddled with the behavior of the older version.

Where does it say that? The only reference I can find in the current
manual to minor numbers is in the -version-number option, which isn’t
the normal way to specify shared object versions in Libtool, and it
doesn’t seem to have any discussion of what the components of its
argument are really for.

http://www.gnu.org/software/libtool/manual/html_node/Link-mode.html

At any rate, Libtool today implements the policy I’ve described. The
primary way to supply it with version information is -version-info. If
you use this option to tell it you’ve made a backwards-compatible change
- i.e. added new interfaces but not removed or changed any, so the
version info string goes from C:R:A to C+1:0:A+1 - then the version in
the soname is unchanged.

http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html


$ libtool --mode=link gcc -version-info=0:0:0 -rpath `pwd`/inst -o libfoo.la foo.lo
libtool: link: rm -fr .libs/libfoo.a .libs/libfoo.la .libs/libfoo.lai .libs/libfoo.so .libs/libfoo.so.0 .libs/libfoo.so.0.0.0
libtool: link: gcc -shared -fPIC -DPIC .libs/foo.o -Wl,-soname -Wl,libfoo.so.0 -o .libs/libfoo.so.0.0.0
libtool: link: (cd ".libs" && rm -f "libfoo.so.0" && ln -s "libfoo.so.0.0.0" "libfoo.so.0")
libtool: link: (cd ".libs" && rm -f "libfoo.so" && ln -s "libfoo.so.0.0.0" "libfoo.so")
libtool: link: ar cru .libs/libfoo.a foo.o
libtool: link: ranlib .libs/libfoo.a
libtool: link: ( cd ".libs" && rm -f "libfoo.la" && ln -s "../libfoo.la" "libfoo.la" )

$ libtool --mode=link gcc -version-info=1:0:1 -rpath `pwd`/inst -o libfoo2.la foo2.lo
libtool: link: rm -fr .libs/libfoo2.a .libs/libfoo2.la .libs/libfoo2.lai .libs/libfoo2.so .libs/libfoo2.so.0 .libs/libfoo2.so.0.0.0
libtool: link: gcc -shared -fPIC -DPIC .libs/foo2.o -Wl,-soname -Wl,libfoo2.so.0 -o .libs/libfoo2.so.0.0.0
libtool: link: (cd ".libs" && rm -f "libfoo2.so.0" && ln -s "libfoo2.so.0.0.0" "libfoo2.so.0")
libtool: link: (cd ".libs" && rm -f "libfoo2.so" && ln -s "libfoo2.so.0.0.0" "libfoo2.so")
libtool: link: ar cru .libs/libfoo2.a foo2.o
libtool: link: ranlib .libs/libfoo2.a
libtool: link: ( cd ".libs" && rm -f "libfoo2.la" && ln -s "../libfoo2.la" "libfoo2.la" )

> This is absolutely reasonable, exactly what you want. Developers
> always have newer software than users do. Of course you'd want to
> accrete changes in the library without imposing an upgrade on the users
> until it's really needed.

Do we? Outside Usenet I’m part of a hardware/software vendor, and
earlier this year we got our product management team to express an
opinion about what should be supported in future releases, so that we
can correctly choose ‘old enough’ release build platforms (some of the
current ones are genuinely too old to build what we want to publish
next).

> glibc is the only library I know that works this way. I would bet that
> of the 170 .so files in my /lib tree, a great many are older than those
> used by the developers of the applications that build them. glibc is
> the only one saying version is 6 is not version 6.

I don’t know what platform you’re referring to here, but: how carefuly
have you checked?

> And the community is ill-served. Google claims "GLIBC_2.14 major
> version" returns 343,000 results, all problems. The message,
>
>> myprog: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.14' not
>> found
>
> is incomprehensible because it's produced at too low a level. The very
> fact that the OP's question arose on this list is prima facia evidence.
> If it said "glibc.so.7 not found", it would both be more correct and
> easier for the user to understand.

I don’t think that’s the case. The version numbers of the package are
2.13, 2.14, etc. So the error message quoted does actually tell you
what to look for in the version column of a package manager, a release
announcement or download page.

$ dpkg -l libc6
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name Version Architecture Description
+++-==============-============-============-=================================
ii libc6:amd64 2.19-13 amd64 GNU C Library: Shared libraries
ii libc6:i386 2.19-13 i386 GNU C Library: Shared libraries

Finally, and this may be a bit tangential but: the choice of 6 is a
historical accident following from the early years of x86 Linux. The
jump from 5 to 6 was completely incompatible in both directions - a
program compiled against libc.so.5 will not work with libc.so.6. For
much the same reason the soname isn’t the same on other kernels or CPUs:

$ dpkg-deb -x libc0.3_2.19-12_hurd-i386.deb .
$ objdump -p lib/i386-gnu/libc.so.0.3|grep SONAME
SONAME libc.so.0.3

$ dpkg-deb -x libc6.1_2.19-13_alpha.deb .
$ objdump -p lib/alpha-linux-gnu/libc.so.6.1 | grep SONAME
SONAME libc.so.6.1

--
http://www.greenend.org.uk/rjk/

Kaz Kylheku

unread,
Dec 5, 2014, 12:20:07 PM12/5/14
to
Ah, but it can, because the compatibility depends on the exact set of symbols
used by the program!

If the program compiled against 2.14 does not actually use any symbol that is
tied to the GLIBC_2.14 version node, then the executable will actually run
against 2.13.

ELF versioning does not compare numbers. The version nodes are just string
labels that mean nothing. GLIBC_2.14 isn't "greater" than GLIBC_2.13.
The nodes are basically namespaces that collect symbols and provide an
inheritance mechanism to simplify the organization of the version script.

It's up to the user of the versioning to use some sane naming scheme,
so that FOO_BAR_1_3 is derived from FOO_BAR_1_2 in a logical way that
provides backward compatibility.

GLIBC could as well use the names of rivers in the USA or whatever for the
version nodes; it wouldn't make any difference. You would then just have to
know that MISSISSIPI is the newest, and the one before that was RIOGRANDE,
so that stuff compiled against MISSISSIPI might not work on RIOGRANDE
if it uses memcpy because memcpy is now specifically memcpy@@MISSISSIPI.

For instance, I have a program here which I'm building against glibc 2.13.

$ readelf --version-info ./txr

Version symbols section '.gnu.version' contains 145 entries:
[ ... snip ... ]

Version needs section '.gnu.version_r' contains 2 entries:
Addr: 0x00000000080490f0 Offset: 0x0010f0 Link: 6 (.dynstr)
000000: Version: 1 File: libm.so.6 Cnt: 2
0x0010: Name: GLIBC_2.1 Flags: none Version: 9
0x0020: Name: GLIBC_2.0 Flags: none Version: 4
0x0030: Version: 1 File: libc.so.6 Cnt: 7
0x0040: Name: GLIBC_2.11 Flags: none Version: 10
0x0050: Name: GLIBC_2.7 Flags: none Version: 8
0x0060: Name: GLIBC_2.4 Flags: none Version: 7
0x0070: Name: GLIBC_2.1 Flags: none Version: 6
0x0080: Name: GLIBC_2.0 Flags: none Version: 5
0x0090: Name: GLIBC_2.3.4 Flags: none Version: 3
0x00a0: Name: GLIBC_2.3 Flags: none Version: 2

Look, my program needs two version nodes from "libm.so.6" and seven version
nodes from "libc.so.6".

The highest version node it needs from libc is GLIBC_2.11.

So, in fact, though this program is compiled against 2.13, it will run
on 2.12 and 2.11!

The libm side is quite conservative. Doh, of course, this is because
the math function API's are brain dead simple, and if, say, a fix is made in
the behavior of something like sqrt(), they just let old programs run with that
behavior.

What is the culprit in my program that requires 2.11?

$ nm txr | grep 2.11
U __longjmp_chk@@GLIBC_2.11

So if I didn't use setjmp and longjmp in this program, I would be down
to glibc 2.7 compatibility.

(Assuming nothing is screwed up, of course! The symbol versioning doesn't
*assure* that it is validated on 2.11 or any other version, only that the
dynamic linker will accept it!)

The problem is that with Ulrich Drepper gone, the glibc developers are now
starting to pull stupid stunts like taking a simple, old C function like memcpy
which has no dependencies on anything, and making it a 2.15 function. Thus any
program which uses memcpy, compiled with 2.15, will not run on 2.14 or lower.

When I worked with Drepper in around 2000-2001 on some threading stuff
in glibc, I remember he loathed introducing new versions of functions and
worked to avoid it if possible. Now it's just a done-at-the-drop-of-a-hat kind
of thing, evidently.

If you run into this, you and your users will never save enough nanoseconds
from the faster memcpy to make up for your lost time.

Richard Kettlewell

unread,
Dec 5, 2014, 1:14:33 PM12/5/14
to
Kaz Kylheku <k...@kylheku.com> writes:
> On 2014-12-04, Richard Kettlewell <r...@greenend.org.uk> wrote:
>> If you compile against Glibc 2.x then (in general) the result will only
>> run against Gilbc 2.y, for y >= x. New functions are added, structure
>> layouts change, etc. This shouldn’t be surprising. The question is how
>> that’s managed.
>>
>>> I'm guessing it's our old friend ld.so, but I don't understand the
>>> rationale. If GLIBC_2.14 is incompatible with GLIBC_2.13 such that a
>>> program depending one cannot use the other, then they should not both
>>> be called libc.so.6.
>>
>> Your description isn’t correct. A program built against Glibc 2.13 can
>> use Glibc 2.14 at runtime. The thing that doesn’t work is running
>> against an older library than you built against.
>
> Ah, but it can, because the compatibility depends on the exact set of symbols
> used by the program!

That’s all true; but I’m talking about the compatibility goals the
system is designed to satisfy, not what you can get away with if you’re
lucky.

--
http://www.greenend.org.uk/rjk/

Rainer Weikusat

unread,
Dec 5, 2014, 5:34:12 PM12/5/14
to
"James K. Lowden" <jklo...@speakeasy.net> writes:
> On Thu, 04 Dec 2014 10:52:07 +0000

[...]

>> Your description isn?t correct. A program built against Glibc 2.13
>> can use Glibc 2.14 at runtime. The thing that doesn?t work is running
>> against an older library than you built against.
>
> Were that the case, no developer could build against the "next" version
> until all downstream clients had been upgraded.
>
> That's not how it's meant to be. My copy of The Linux Programming
> Interface says (section 41.6, page 844):
>
> "By convention, the major version identifier takes the form of
> a number that is sequentially incremented with each incompatible
> release of the library. In addition to the major version identifier,
> the real name also includes a minor version identifier, which
> distinguishes compatible minor versions within the library major
> version. The real name employs the format convention
> libname.so.major-id.minor-id."
>
> I also read the libtool documentation ~10 years ago, and it said the
> same thing: minor versions exist to distinguish versions. 2.14 might
> be better than 2.13, but the data structures and functions are the
> same. Building with 2.14 and running with 2.13 is valid; you're just
> saddled with the behavior of the older version.
>
> This is absolutely reasonable, exactly what you want.

That's the beautiful theory. The ugly practice is that the glibc major
version has been fixed at 6 for political reasons around 1998/ 1999 and
that 'symbol versioning' is supposed to serve as a replacement.

Rainer Weikusat

unread,
Dec 5, 2014, 5:45:30 PM12/5/14
to
"James K. Lowden" <jklo...@speakeasy.net> writes:
> On Thu, 04 Dec 2014 19:03:09 +0000
> Rainer Weikusat <rwei...@mobileactivedefense.com> wrote:
>
>> [rw@torch]/tmp $ldd a.out
>> linux-gate.so.1 => (0xb7886000)
>> libcrypto.so.0.9.8 => /usr/lib/libcrypto.so.0.9.8 (0xb7723000)
>> libc.so.6 => /usr/local/glibc-2.11/lib/libc.so.6 (0xb75d3000)
>> libdl.so.2 => /usr/local/glibc-2.11/lib/libdl.so.2
>> (0xb75cf000) libz.so.1 => /usr/lib/libz.so.1 (0xb75b9000)
>> /usr/local/glibc-2.11/lib/ld-linux.so.2 (0xb7887000)
>>
>> communicates that code compiled agains different versions of libc ends
>> up in the same address space. And this is a recipe for disaster
>> because the code in the 'system' libcrypto has been compiled with the
>> information from the headers of the old libc. This means its idea of
>> 'structure size/ layouts' may differ from that of the code in the used
>> libc version.
>
> Thanks for that illustration; I agree it's an ugly state of affairs.
> The questions in my mind are: how ugly, and what to do?
>
> I still don't understand why the linker created the image you're
> showing. AFAIK, both copies of libc have one soname: libc.so.6. (Can
> you confirm?) I don't understand why they're both linked in,

[...]

They aren't. I was wrong about that. But the libcrypto version which is
linked in was compiled against glibc 2.7 and the main program against
glibc 2.11. While there also isn't a problem with libcrypto accidentally
calling new functions with old data structures (I was wrong about that,
too) there is a potential problem when the main program passes pointers
to glibc data structure it created to the OpenSSL library. Eg, OpenSSL
provides a function

i2d_X509_fp(FILE *, X509 *)

which is supposed to write the DER-encoded equivalent of the 'internal'
X509-structure the second argument points to to the stream passed as
first argument. If the main program used that function, it would call
the glibc 2.11 fopen to get a FILE * it would then pass to i2d_X509_fp
which would, in turn, pass it to some glibc 2.7 output routines.

This may not be a problem in practice and in fact, I've been running
some 40 'production racoons' (the IKE server) with exactly this set of
libraries for a while, but I knew that no code with possibly
problematic behaviour existed for this case.

Rainer Weikusat

unread,
Dec 5, 2014, 5:46:20 PM12/5/14
to
"James K. Lowden" <jklo...@speakeasy.net> writes:
> On Thu, 04 Dec 2014 10:52:07 +0000

[...]

>> Your description isn?t correct. A program built against Glibc 2.13
>> can use Glibc 2.14 at runtime. The thing that doesn?t work is running
>> against an older library than you built against.
>
> Were that the case, no developer could build against the "next" version
> until all downstream clients had been upgraded.
>
> That's not how it's meant to be. My copy of The Linux Programming
> Interface says (section 41.6, page 844):
>
> "By convention, the major version identifier takes the form of
> a number that is sequentially incremented with each incompatible
> release of the library. In addition to the major version identifier,
> the real name also includes a minor version identifier, which
> distinguishes compatible minor versions within the library major
> version. The real name employs the format convention
> libname.so.major-id.minor-id."
>
> I also read the libtool documentation ~10 years ago, and it said the
> same thing: minor versions exist to distinguish versions. 2.14 might
> be better than 2.13, but the data structures and functions are the
> same. Building with 2.14 and running with 2.13 is valid; you're just
> saddled with the behavior of the older version.
>
> This is absolutely reasonable, exactly what you want.

That's the beautiful theory. The ugly practice is that the glibc major
version has been fixed at 2 for political reasons around 1998/ 1999 and

James K. Lowden

unread,
Dec 5, 2014, 11:04:54 PM12/5/14
to
On Fri, 05 Dec 2014 12:28:23 +0000
Nobody <nob...@nowhere.invalid> wrote:

> So while you could theoretically bypass libc (unlike the kernel,
> which is running in a privileged context), that doesn't really mean
> very much in practice. The interfaces on which libc is built are far
> less stable than those which it exposes.

Quite so. Nicolas is arguing it's special, and I'm saying it's just
code. Important code, to be sure, but not privileged.

--jkl

James K. Lowden

unread,
Dec 5, 2014, 11:07:42 PM12/5/14
to
On 05 Dec 2014 13:56:13 GMT
Nicolas George <nicolas$geo...@salle-s.org> wrote:

> I already explained why it MUST be special. You missed it.

Did I say something to offend you, Nicolas, or am I being singled out
for special treatment this holiday season?

> But you fail to realize that ld.so IS PART OF THE LIBC.

I simply don't know what you're talking about.

You have claimed libld.so and ld.so are part of libc. I don't know
what you mean by "part of". As far as I'm concerned, whatever is part
of libc is in the library, not standing next to it.

If you mean they're developed by the same people and released at the
same time, or whatever, that's not what "part of" means where I come
from. libc isn't a package; it's a library. The things it interfaces
with aren't part of it any more than the kernel is.

No need to shout. I can hear you. Saying it louder won't make it
any clearer.

--jkl

James K. Lowden

unread,
Dec 5, 2014, 11:07:45 PM12/5/14
to
On Fri, 5 Dec 2014 17:19:59 +0000 (UTC)
Kaz Kylheku <k...@kylheku.com> wrote:

> What is the culprit in my program that requires 2.11?
>
> $ nm txr | grep 2.11
> U __longjmp_chk@@GLIBC_2.11
>
> So if I didn't use setjmp and longjmp in this program, I would be down
> to glibc 2.7 compatibility.

That's very illuminating, thanks. I know there's a thing called "symbol
versioning" that's used to manage binary compatibility, but that's
about it. Because of you, I just read

http://www.akkadia.org/drepper/symbol-versioning
http://harmful.cat-v.org/software/dynamic-linking/versioned-symbols

and a few others. On the one hand, it would *seem* like symbol
versioning would have made this entire thread unnecessary, because 2.14
would supply a 2.13 version of any changed symbols. But the practice
is the opposite, to pretend that all symbols have changed and upgrading
is necessary.

I don't find the case for versioned symbols compelling. We already
have a perfectly good way (as you know) to signal version expectations:
define a version-constant in the header, and switch on it in the
library.

> The problem is that with Ulrich Drepper gone, the glibc developers
> are now starting to pull stupid stunts like taking a simple, old C
> function like memcpy which has no dependencies on anything, and
> making it a 2.15 function. Thus any program which uses memcpy,
> compiled with 2.15, will not run on 2.14 or lower.

Say it isn't so, Kaz! O tempora! O mores!

> When I worked with Drepper in around 2000-2001 on some threading stuff
> in glibc, I remember he loathed introducing new versions of functions
> and worked to avoid it if possible. Now it's just a
> done-at-the-drop-of-a-hat kind of thing, evidently.

So it would seem. :-(

--jkl

James K. Lowden

unread,
Dec 5, 2014, 11:07:47 PM12/5/14
to
On Fri, 05 Dec 2014 16:26:46 +0000
Richard Kettlewell <r...@greenend.org.uk> wrote:

> No problem!

:-)

> >> myprog: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.14' not
> >> found
> >
> > is incomprehensible because it's produced at too low a level.
>
> I don?t think that?s the case. The version numbers of the package are
> 2.13, 2.14, etc. So the error message quoted does actually tell you
> what to look for in the version column of a package manager

"It's easy if you know how". The message doesn't mention the package
manager. What it says is that the existing library -- valid in every
way from external inspection -- lacks a required symbol. The first
time I encountered it, I thought the system was misconfigured. (I
suppose I still do!) The OP didn't recognize it as a versioning issue,
either.

> Software distributors who want to ship object code have to build for
> the oldest platform they want to support.

Agreed, but that's not the same as saying they must link against the
oldest libraries they want to support when building. There is no
reason, fundamentally, that if I link against version N of a library
that you can't use N-1 instead at runtime.

http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html

As they say over there at libtool, "programs using the new version can
also work with the previous one".

(IMO libtool's version-number algorithm is too strict. Adding a new
function ("interface", step #4) shouldn't result in a new major
version.)

> But the same would be true whatever approach was taken to shared
> library versioning: if they build against a hypothetical libc.so.25
> and the customer only has libc.so.24, the customer is likely to be
> disappointed.

Yes, because in your example you're using different *major* version
numbers. By definition, they are not binary compatible. Because in
2014 our symbols bear no semantics, the linker cannot know what
function X means; it depends on the major version's claim that it is
or isn't the same.

In the OP's case, both libraries are version 6.

> As such I must be missing what your alternative proposal is, given
> that the only one I?ve so far imagined doesn?t solve any of today?s
> unsolved problems, and has serious drawbacks of its own. Nineteen
> copies of libc? (Twenty next year?)

Actually, no, I'm not proposing anything, except to use the major
version number for its intended purpose.

Let's go back to 2.13 and 2.14 again. If 2.14 has all the same
functions and structures and semantics as 2.13, and my application
relies on none of the additions offered in 2.14, then I can link
against 2.14, ship it to you, and you can use 2.13 with no problem at
all. The soname will be libfoo.so.2. As long as that remains true, as
long as I continue to rely on the 2.13 interface, I can keep upgrading
-- 2.15, 2.16, 2.17 -- and you have no need to upgrade. You may start
to feel a need for pipe an slippers, but my software will run on your
machine.

The day may come when a new feature of 2.19 is irresistable. If I use
it, I can continue make my application compatible by checking that
dependency at runtime and falling back to the 2.13 behavior if that's
what the runtime environment supplies. Or, if I'm a meanie, I can link
to it and require you do, too. I can post a little item in the News
section of my website saying New & Improved version 10.5 of Zeebob
requires version 2.19 of the library. Change or be changed!

If you fail to take proper note of my scintillating announcment -- Yo!
Richard! Aren't you paying attention? -- then you'll get a linker
error and call my helpdesk, whose phone no one answers because it's
2014. But a little searching will uncover the requirement, and you'll
know what to do.

Note that the requirement to upgrade is under the developer's control,
and affects only one application. And the user is left mostly
unmolested.

What's going on with glibc is very different, so I've learned here.
Every release bumps a symbol inside the library that the linker
conspires to examine and throw you out on your ear if it's not recent
enough. I doubt very much the OP really, really needed whatever is
uniquely associated with GLIBC_2.14. I'm absolutely sure that the
linker cannot know, nor can the glibc authors. But they took the
*entire* interface and said "Oh, no, 2.13 is sooo last week. You need
to upgrade, dude, because memcpy might have changed again."

(That's my impression. I haven't found any documentation at all on the
glib website or man page indicating the significance of
GLIBC_2.14 symbol or the policy. The FAQ has a whole paragraph on
symbol versioning, and nary a word on the project's idiosyncratic
library versioning policy. I would venture to say that's part of the
problem.)

In such an regime, the developer has to maintain a build environment
flash-frozen in time of the oldest version he supports. He may build
daily against N, but for releasing he has to schroot to N-9 and build
there. No wonder virtual environments are so popular.

This is not a service to users. It's careless engineering, and
costly besides. Although, granted, the costs are borne by the users.

> Finally, and this may be a bit tangential but: the choice of 6 is a
> historical accident following from the early years of x86 Linux. The
> jump from 5 to 6 was completely incompatible in both directions - a
> program compiled against libc.so.5 will not work with libc.so.6.

It's not tangental at all; it illustrates what I've been saying all
along. The bump from 5 to 6 would have signified a change in binary
compatibility. You can't use 6 if you linked against 5 and you can't
use 5 if you linked against 6. That's what binary compatibility means,
and that fact *is* reflected in the soname of the library and the NEEDS
section of the elf headers.

However, there's no reason /lib can't have two versions of libc.
Currently I have:

$ pwd && file libc.so*
/lib/x86_64-linux-gnu
libc.so.6: symbolic link to `libc-2.15.so'

and the library declares itself as "libc.so.6":

$ readelf -d libc.so.6 | sed -Ene 's/0{9}/0/; /SONAME/p'
0x0000000e (SONAME) Library soname: [libc.so.6]

and applications indicate that's the libc they need:

$ readelf -d $(which ls) | sed -Ene 's/0{9}/0/; /libc/p'
0x00000001 (NEEDED) Shared library: [libc.so.6]

When the 5->6 move happened, old utilities would have been linked
to 5. Installing version 6 wouldn't upset any applecarts. No reason
they can't be co-resident, and no reason for a wholesale upgrade.
Linking some things to 5 and others to 6 causes no problems. Linking
something to both 5 and 6 (Hi, Rainer!) can cause problems. Simple
answer: don't do that.

Does it cause a headache for package management? It does. As
was pointed out upthread, if the application is linked against 5 and
also against a library that was linked against 6, it's a problem. So
the major version ripples thoughout the packaging system, even though
the packages and libraries themselves are unchanged. But, again,
there's no reason you can't have a whole set of libraries side by side,
one reliant on 5 and the other 6.

My NetBSD machine looks like this:

$ ls /usr/lib/libc.* | xargs file
/usr/lib/libc.a: current ar archive
/usr/lib/libc.so: symbolic link to `../../lib/libc.so.12.164'
/usr/lib/libc.so.12: symbolic link to `../../lib/libc.so.12.164'
/usr/lib/libc.so.12.164: symbolic link to `../../lib/libc.so.12.164'

In 2002, according to CVS, the major version was 7: that's 5
binary-incompatible changes in 12 years. It's normal, and it works.

http://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libc/shlib_version

I don't know the history of the 5->6 migration on Linux (and I don't
consider c.u.p a Linux-only forum). I have the impression the X11R7
migration was poorly handled; what I read showed misunderstandings up
and down the line. So it wouldn't suprise if me if bumping the major
libc version in that environment led to something of a cacophony.

The resulting policy -- to freeze the major version -- has effects that
are beyone dispute. It put users on the same upgrade treadmill that
Microsoft & Apple have their users on. Instead of carefully avoiding
incompatibility and leaving upgrade choices to users and developers,
the effect is to require everyone to "stay up to date", whether or not
that makes economic or technical sense. Instead of human intelligence,
we put the linker in charge. I'm sure the fact that that's convenient
for the developers is just a coincidence.

--jkl

Jorgen Grahn

unread,
Dec 6, 2014, 2:02:59 AM12/6/14
to
On Fri, 2014-12-05, Kaz Kylheku wrote:

[glibc]

> The problem is that with Ulrich Drepper gone, the glibc developers are now
> starting to pull stupid stunts like taking a simple, old C function like memcpy
> which has no dependencies on anything, and making it a 2.15 function. Thus any
> program which uses memcpy, compiled with 2.15, will not run on 2.14 or lower.

Well, /without/ him gone, a lot of sensible people (most Linux
distributions?) refused to use glibc, so it seems to me it doesn't
make that much of a difference.

> When I worked with Drepper in around 2000-2001 on some threading stuff
> in glibc, I remember he loathed introducing new versions of functions and
> worked to avoid it if possible. Now it's just a done-at-the-drop-of-a-hat
> kind of thing, evidently.

Conservatism is good if you're maintaining a libc. Up to a point, at
least.

I figure memcpy might be special because it's also a gcc builtin
function. Calls can be generated behind the scenes for things like
struct assignment; it can be used to copy things of a fixed length or
a fixed alignment ...

That's the only reason for changes I can think of. memcpy(3) as
documented doesn't deserve to change.

> If you run into this, you and your users will never save enough nanoseconds
> from the faster memcpy to make up for your lost time.

I /have/ run into it, but it was my own fault: having no strategy for
cross-compilation. We compiled both target code and unit tests in a
cross-compilation environment, and when both the target and the build
environment had gone through a few upgrades, binary compatibility was
lost and I couldn't run my unit tests. Not the ones that pulled in
memcpy, anyway.

(Partly it was the build environment peoples' fault: providing no
decent compiler for the host environment.)

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

Richard Kettlewell

unread,
Dec 6, 2014, 8:09:31 AM12/6/14
to
"James K. Lowden" <jklo...@speakeasy.net> writes:
> Richard Kettlewell <r...@greenend.org.uk> wrote:
>> Software distributors who want to ship object code have to build for
>> the oldest platform they want to support.
>
> Agreed, but that's not the same as saying they must link against the
> oldest libraries they want to support when building. There is no
> reason, fundamentally, that if I link against version N of a library
> that you can't use N-1 instead at runtime.

It’s not a law of physics, indeed. But the chances are you probably use
something from version N, possibly in a way that you’re not aware of.
So in practice that’s what the rule is.

> http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
>
> As they say over there at libtool, "programs using the new version can
> also work with the previous one".

That only covers the case where there has been no interface change.

> (IMO libtool's version-number algorithm is too strict. Adding a new
> function ("interface", step #4) shouldn't result in a new major
> version.)

It doesn’t. See my previous posting!

>> As such I must be missing what your alternative proposal is, given
>> that the only one I?ve so far imagined doesn?t solve any of today?s
>> unsolved problems, and has serious drawbacks of its own. Nineteen
>> copies of libc? (Twenty next year?)
>
> Actually, no, I'm not proposing anything, except to use the major
> version number for its intended purpose.
>
> Let's go back to 2.13 and 2.14 again. If 2.14 has all the same
> functions and structures and semantics as 2.13, and my application
> relies on none of the additions offered in 2.14, then I can link
> against 2.14, ship it to you, and you can use 2.13 with no problem at
> all.

If you’re lucky enough to avoid the changes between 2.13 and 2.14 then
that will work just fine with the system actually implemented.

But _in general_ you aren’t that lucky, and in the case of 2.14, the
changes are sufficiently fundamental (memcpy) that only very simple
programs are likely to get away with it. In other words it is safe to
assume backwards compatibility but unsafe to assume forwards
compatibility.

(I’d thought it was clear that I was talking about the general
compatibility guarantees the system offered. But at least three people
have misunderstood now, so apparently not.)

[...]
> In such an regime, the developer has to maintain a build environment
> flash-frozen in time of the oldest version he supports. He may build
> daily against N, but for releasing he has to schroot to N-9 and build
> there. No wonder virtual environments are so popular.

No, that’s not necessary, and I’ve no idea why you think it is. One
old-enough environment is sufficient for releasing. Compiling against
N-9 and running against any of N-9 to N will work (or should do;
obviously it’s possible that there may be bugs in library or
application).

> However, there's no reason /lib can't have two versions of libc.
[...]
> Does it cause a headache for package management? It does. As
> was pointed out upthread, if the application is linked against 5 and
> also against a library that was linked against 6, it's a problem. So
> the major version ripples thoughout the packaging system, even though
> the packages and libraries themselves are unchanged. But, again,
> there's no reason you can't have a whole set of libraries side by side,
> one reliant on 5 and the other 6.

When it was just 5 and 6 that’s what happened (although I suspect that
the runtime linker technology accompanying libc.so.5 didn’t offer any
other possibilities).

But now there are up to 35 distinct versions[1] to worry about, not just
2. So there are overwhelming practical reasons not to adopt the “lots
of copies of libc” solution. Mirror capacity is finite. Download
bandwidth is expensive. Build server CPU time is limited.

[1] based on searching the Glibc source.

--
http://www.greenend.org.uk/rjk/

James K. Lowden

unread,
Dec 6, 2014, 12:00:15 PM12/6/14
to
On Sat, 06 Dec 2014 13:09:28 +0000
Richard Kettlewell <r...@greenend.org.uk> wrote:

> If you?re lucky enough to avoid the changes between 2.13 and 2.14 then
> that will work just fine with the system actually implemented.
>
> But _in general_ you aren?t that lucky, and in the case of 2.14, the
> changes are sufficiently fundamental (memcpy) that only very simple
> programs are likely to get away with it. In other words it is safe to
> assume backwards compatibility but unsafe to assume forwards
> compatibility.

It has nothing to do with luck! You're not acknowledging that the "2"
is 2.14 is the major version number. It signifies binary compatibility.
Not forward, not backward, but equivalence: 2.14 must be a superset of
the functionality -- structures, signatures, and semantics -- of
2.13. If that's not the case, it's misnumbered, and should by 3.0.

Let's make this very, very simple, to see if we can isolate where our
disagreement lies. I write an application that uses function A
in library foo. I use libfoo.so.1.1. You use my application and
install the libfoo.so.1.1, too. Later the foo author adds B, not
changing A, and releases libfoo.so.1.2, which I use and you don't. The
guarantee is that if I mention only A in my application, you can use
1.1 or 1.2. He can continue adding C, D, and E, and I can build
against each new version, and you can continue using 1.1, because my
application uses only A, which has not changed. The moment I mention
B, your old libfoo.so.1.1 won't satisfy it, and you'll have to
upgrade.

On this we agree, right? The ABI has grown, but not changed from my
perspective. All versions are equivalent, and the major is still "1".

The next thing that happens is the author *changes* B, and releases
libfoo.so.2.0. The part of the ABI I depend on -- function A -- is
unchanged. But the soname has changed, and if I link against it,
you'll have to upgrade libfoo to version 2.0, else your runtime linker
will complain. (And it will complain about a missing *library*, not a
missing symbol!)

That was the impetus for adopting symbol versioning in glibc. For a
widely used library, a major version bump has a large ripple effect,
and very often many more applications are affected than need be,
because the part of the interface they use hasn't changed, cf. Kaz's
message regarding longjmp.

Symbol versioning was invented to supply two binary interfaces (for a
symbol) in one major version. If all parties use it, in principle it's
possible never to change the library's version, and always to supply
unlimited backwards compatibility by only adding symbols and never
changing the semantics of the old ones.

That's not what glib is doing, though. The glibc policy -- as inferred,
because not published -- is a kind of a middle ground and, yes, it
works as you say. Applications linked against 2.15 automatically
reference a global symbol GLIBC_2.15, and thus require glibc-2.15.so be
installed. They take the sting out of that by guaranteeing (AIUI) that
2.15 is a superset of 2.14, and that anything linked to 2.14 will
continue to work unchanged with 2.15. That lets installed applications
remain in place unchanged.

You asked me what I'd do instead, and despaired of having N versions of
the library installed. I suggest that's what's happening anyway.

Most libraries have a 1:1 map of soname to major version, and all elf
systems support installation of more than one major version of a
library. In glibc this is disguised: instead of keeping N copies in N
files, it keeps N copies in 1 file. Instead of looking at the NEEDED
section of the application to see what version it needs, you have to
run it and see if GLIBC_m.nn resolves.

The policy protects the interest of the library developers and
distribution vendors at the expense of complexity for the developer and
busywork for a lot of hamsters to ensure their systems are updated.
The wonder is that so many people think that's a good thing.

--jkl

Richard Kettlewell

unread,
Dec 6, 2014, 12:46:15 PM12/6/14
to
"James K. Lowden" <jklo...@speakeasy.net> writes:
> It has nothing to do with luck! You're not acknowledging that the "2"
> is 2.14 is the major version number. It signifies binary compatibility.
> Not forward, not backward, but equivalence: 2.14 must be a superset of
> the functionality -- structures, signatures, and semantics -- of
> 2.13. If that's not the case, it's misnumbered, and should by 3.0.

I think you’re confusing the version number of the package and the
number in the soname. They’ve not the same thing.

> Symbol versioning was invented to supply two binary interfaces (for a
> symbol) in one major version. If all parties use it, in principle it's
> possible never to change the library's version, and always to supply
> unlimited backwards compatibility by only adding symbols and never
> changing the semantics of the old ones.

That’s what Glibc is doing.

> That's not what glib is doing, though. The glibc policy -- as
> inferred, because not published -- is a kind of a middle ground and,
> yes, it works as you say. Applications linked against 2.15
> automatically reference a global symbol GLIBC_2.15, and thus require
> glibc-2.15.so be installed.

That’s not what Glibc is doing. Counterexample, built with Glibc 2.19:

$ cat t.c
int main() {
return 0;
}
$ dpkg -l libc6|tail -2
ii libc6:amd64 2.19-13 amd64 GNU C Library: Shared lib
ii libc6:i386 2.19-13 i386 GNU C Library: Shared lib
$ gcc -o t t.c
$ objdump -p t | grep GLIBC
0x09691a75 0x00 02 GLIBC_2.2.5

and running on another install with Glibc 2.13:

$ dpkg -l libc6|tail -2
ii libc6:amd64 2.13-38+deb7u6 amd64 Embedded GNU C Library: Shared lib
ii libc6:i386 2.13-38+deb7u6 i386 Embedded GNU C Library: Shared lib
$ ./t
$

When built against 2.19, this program doesn’t use any symbols later than
2.2.5, so it can be expected to run with everything from 2.2.5 onwards.

But this is ‘by luck’. Nobody is promising that arbitrary programs will
achieve that kind of forward compatibility - obviously it would be
impossible.

> You asked me what I'd do instead, and despaired of having N versions of
> the library installed. I suggest that's what's happening anyway.

Sort of, but with the practical difference that it’s 1/35th of the size
of the strict soname policy you seem to be proposing, doesn’t have as
much impact on downstream libraries, etc.

--
http://www.greenend.org.uk/rjk/

Kaz Kylheku

unread,
Dec 6, 2014, 12:51:40 PM12/6/14
to
On 2014-12-06, James K. Lowden <jklo...@speakeasy.net> wrote:
> On Fri, 5 Dec 2014 17:19:59 +0000 (UTC)
> Kaz Kylheku <k...@kylheku.com> wrote:
>
>> What is the culprit in my program that requires 2.11?
>>
>> $ nm txr | grep 2.11
>> U __longjmp_chk@@GLIBC_2.11
>>
>> So if I didn't use setjmp and longjmp in this program, I would be down
>> to glibc 2.7 compatibility.
>
> That's very illuminating, thanks. I know there's a thing called "symbol
> versioning" that's used to manage binary compatibility, but that's
> about it. Because of you, I just read
>
> http://www.akkadia.org/drepper/symbol-versioning
> http://harmful.cat-v.org/software/dynamic-linking/versioned-symbols
>
> and a few others. On the one hand, it would *seem* like symbol
> versioning would have made this entire thread unnecessary, because 2.14
> would supply a 2.13 version of any changed symbols.

It does, but only to clients that were compiled against 2.13.

> But the practice
> is the opposite, to pretend that all symbols have changed and upgrading
> is necessary.
>
> I don't find the case for versioned symbols compelling. We already
> have a perfectly good way (as you know) to signal version expectations:
> define a version-constant in the header, and switch on it in the
> library.

Yes; as recently as a year ago I designed a library this way, with a "version
handshake" call that must be used by clients. This is to keep things portable.
In fact in a "Rationale:" sentence in the document, I explain that it
isolates the software from a platform-specific mechanism, like ELF symbol
versioning.

In the version handshake API call, you pass in the three version numbers
obtained from the header, so it knows how the client was compiled. It can all
be done without symbol versioning in this obtuse, Microsoft-DLL-like way.

Rainer Weikusat

unread,
Dec 7, 2014, 10:21:29 AM12/7/14
to
Kaz Kylheku <k...@kylheku.com> writes:
> On 2014-12-04, Richard Kettlewell <r...@greenend.org.uk> wrote:

[...]

> The problem is that with Ulrich Drepper gone, the glibc developers are now
> starting to pull stupid stunts like taking a simple, old C function like memcpy
> which has no dependencies on anything, and making it a 2.15 function. Thus any
> program which uses memcpy, compiled with 2.15, will not run on 2.14 or
> lower.

That's not as silly as it appears on the first sight: While memcpy has
had the documented requirement that the ranges must not overlap since
ever, this doesn't necessarily mean anybody ever cared for that,
especially not 'anybodies' who don't run the risk of someone ever
looking at their code and who are pressured to put as little effort into
writing some code as humanly possible (if they don't do this
voluntarily, anyway :->). I remember the 'real story how flash for
Linux suddenly stopped working' here. Creating a new memcpy version when
changing the algorithm means binaries which relied on the behaviour of
the previous one despite they shouldn't do this continue to work.

[...]

> If you run into this, you and your users will never save enough
> nanoseconds from the faster memcpy to make up for your lost time.

"Only give us enough time and we'll replace all this ugly 'high-level
code' with beautiful, hand-written x86 machine code" is not something
particularly sensible to strive for, OTOH, programmers tend to be wedded
to a particular programming language and strongly resent all others so
'damage control' (see above) is the only realistic option.

Rainer Weikusat

unread,
Dec 7, 2014, 3:43:40 PM12/7/14
to
"James K. Lowden" <jklo...@speakeasy.net> writes:
> Kaz Kylheku <k...@kylheku.com> wrote:

[...]

>> The problem is that with Ulrich Drepper gone, the glibc developers
>> are now starting to pull stupid stunts like taking a simple, old C
>> function like memcpy which has no dependencies on anything, and
>> making it a 2.15 function. Thus any program which uses memcpy,
>> compiled with 2.15, will not run on 2.14 or lower.
>
> Say it isn't so, Kaz! O tempora! O mores!

While I have a deep respect for him, although mainly because of the
extraordinary amount of effort he put into teaching people things
because of the many texts he wrote (I'm not so much fond of his code, as
glibc excels at the "C++ disease" of solving fairly simple problems in
hideously complicated and seriously overgeneralized ways) and also
appreciate the irony of 'certain people' experiencing how it feels to be
treated like they treat others without realizing that, I had one
personal exchange with the man (also "around 2000 or 2001") which wasn't
exactly constructive: To this date, glibc documents that

In the GNU C library, `stdin', `stdout', and `stderr' are
normal variables which you can set just like any others. For
example, to redirect the standard output to a file, you could
do:

fclose (stdout);
stdout = fopen ("standard-output-file", "w");

Note however, that in other systems `stdin', `stdout', and
`stderr' are macros that you cannot assign to in the normal way.
But you can use `freopen' to get the effect of closing one and
reopening it.
(section 12.2 of the info documentation)

I tried to use this around the time, IIRC, to add SSL encryption to the
command channel of an ftp client. This didn't work because while stdout
was assignable, the glibc routines weren't using its value but a copy of
that made 'during initialization'. I reported this as a bug and got a
two word reply may "Use freopen" (aka "you're surely an idiot who can't
even come up with obvious, alternate approaches") to which I also
replied with two words, namely "With sockets?".


Jorgen Grahn

unread,
Dec 7, 2014, 4:39:59 PM12/7/14
to
On Sun, 2014-12-07, Rainer Weikusat wrote:
...
> glibc excels at the "C++ disease" of solving fairly simple problems in
> hideously complicated and seriously overgeneralized ways

We C++ programmers had it alright, but some of us got well again and
are now immune. I hear scientists are working on a vaccine.

James K. Lowden

unread,
Dec 7, 2014, 4:56:16 PM12/7/14
to
On Sat, 06 Dec 2014 17:46:12 +0000
Richard Kettlewell <r...@greenend.org.uk> wrote:

> "James K. Lowden" <jklo...@speakeasy.net> writes:
> > It has nothing to do with luck! You're not acknowledging that the
> > "2" is 2.14 is the major version number. It signifies binary
> > compatibility.
>
> I think you?re confusing the version number of the package and the
> number in the soname. They?ve not the same thing.

$ readelf -d libc-2.15.so | grep SONAME
0x0000000e (SONAME) Library soname: [libc.so.6]

Not confused. The soname hasn't changed in a long, long time, across
many binary-incompatible changes. The assertion is that there's no
longer any need to change it, because there's no such thing as a
binary-incompatible change in glib anymore, thanks to symbol
versioning. The glibc soname is a meaningless, obsolete string.

> Counterexample, built with Glibc 2.19

Thank you. It was my understanding from eariler exchanges that the
developer was required to build against the oldest version that he
guaranteed would be useful at runtime. Your example shows that
building with a later version creates runtime-linker requirements only
as late as the latest symbol used.

Two questions, if I may:

1. Where is the glibc versioning policy documented?
2. To what do you attribute the OP's problem?

I ask because the advice given the OP as to either (a) compile against
the client's version or (b) upgrade the client's glibc. If he looked
carefully through the symbols, could he find which function/structure
was versioned up? IIUC correctly, he could avoid a client
upgrade by explicitly linking to the old version using a linker script
or somesuch.

> But this is ?by luck?. Nobody is promising that arbitrary programs
> will achieve that kind of forward compatibility - obviously it would
> be impossible.

Not obvious to me, no more so than any other software promise.
Infeasible with current tools, perhaps. Any feasible "guarantee" might
be too conservative and prompt more major-version bumps than actually
(but unprovably) required. That's why we have release engineering.

> with the practical difference that it?s 1/35th of the size of the
> strict soname policy you seem to be proposing, doesn?t have as much
> impact on downstream libraries, etc.

What I'm "proposing" is SOP for almost every other library, as you
know. :-) NetBSD, to name just one, continues to use the major
version to signify binary compatibility for libc.

But let us grant that libc is the most widely used shared object in the
world, and grant ad argumentum that its sheer distribution size
warrants use of the special services afforded by symbol versioning.
Then I suggest we need better tools to protect against and investigate
the problems that symbol-versioning introduced.

I guess I value external, static inspection, and care less about
"extra" copies and symbolic links that you do. My complaint, along with
hundreds of thousands of others, if Google is to be believed and if
they could articulate it, is that symbol satisfaction cannot be
established without running the application. When it is run, it says,

> myprog: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.14' not
> found

which is nowhere near as clear as,

myprog: library not found: /lib/x86_64-linux-gnu/libc.so.7

--jkl

Ian Collins

unread,
Dec 7, 2014, 6:20:18 PM12/7/14
to
Rainer Weikusat wrote:
>
> While I have a deep respect for him, although mainly because of the
> extraordinary amount of effort he put into teaching people things
> because of the many texts he wrote (I'm not so much fond of his code, as
> glibc excels at the "C++ disease" of solving fairly simple problems in
> hideously complicated and seriously overgeneralized ways)

I always have a chuckle when people post general statements about
overgeneralisation...

--
Ian Collins

Kaz Kylheku

unread,
Dec 7, 2014, 8:31:05 PM12/7/14
to
On 2014-12-07, Rainer Weikusat <rwei...@mobileactivedefense.com> wrote:
> I tried to use this around the time, IIRC, to add SSL encryption to the
> command channel of an ftp client. This didn't work because while stdout
> was assignable, the glibc routines weren't using its value but a copy of
> that made 'during initialization'.

Haha, that is useless. Sure, assign to stdout but, say, puts will use
the original.

> I reported this as a bug and got a
> two word reply may "Use freopen" (aka "you're surely an idiot who can't
> even come up with obvious, alternate approaches") to which I also
> replied with two words, namely "With sockets?".

That advice should, of course, have been: use dup2 to replace the STDOUT_FILENO
file descriptor.

freopen is of limited use. I can probably count on one ... finger the
number of times I have ever used it.

Richard Kettlewell

unread,
Dec 8, 2014, 4:20:54 AM12/8/14
to
"James K. Lowden" <jklo...@speakeasy.net> writes:
> Richard Kettlewell <r...@greenend.org.uk> wrote:
>> "James K. Lowden" <jklo...@speakeasy.net> writes:
>>> It has nothing to do with luck! You're not acknowledging that the
>>> "2" is 2.14 is the major version number. It signifies binary
>>> compatibility.
>>
>> I think you?re confusing the version number of the package and the
>> number in the soname. They?ve not the same thing.
>
> $ readelf -d libc-2.15.so | grep SONAME
> 0x0000000e (SONAME) Library soname: [libc.so.6]
>
> Not confused. The soname hasn't changed in a long, long time, across
> many binary-incompatible changes. The assertion is that there's no
> longer any need to change it, because there's no such thing as a
> binary-incompatible change in glib anymore, thanks to symbol
> versioning. The glibc soname is a meaningless, obsolete string.

Then why do you think the 2 in 2.14 “signifies binary compatibility”?

>> Counterexample, built with Glibc 2.19
>
> Thank you. It was my understanding from eariler exchanges that the
> developer was required to build against the oldest version that he
> guaranteed would be useful at runtime. Your example shows that
> building with a later version creates runtime-linker requirements only
> as late as the latest symbol used.
>
> Two questions, if I may:
>
> 1. Where is the glibc versioning policy documented?

No idea.

> 2. To what do you attribute the OP's problem?

He compiled against 2.19 and his program ended up depending on something
present only in some later version than the one he tried to run against
(which was 2.13).

> I ask because the advice given the OP as to either (a) compile against
> the client's version or (b) upgrade the client's glibc. If he looked
> carefully through the symbols, could he find which function/structure
> was versioned up? IIUC correctly, he could avoid a client
> upgrade by explicitly linking to the old version using a linker script
> or somesuch.

Possibly he could, but why would anyone go through such a rigmarole when
there’s an easier way (i.e. build against an older Glibc)?

> I guess I value external, static inspection, and care less about
> "extra" copies and symbolic links that you do. My complaint, along with
> hundreds of thousands of others, if Google is to be believed and if
> they could articulate it, is that symbol satisfaction cannot be
> established without running the application. When it is run, it says,
>
>> myprog: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.14' not
>> found
>
> which is nowhere near as clear as,
>
> myprog: library not found: /lib/x86_64-linux-gnu/libc.so.7

We’ve been over that detail. I’ve seen nothing that changes my opinion.
glibc-2.14.tar.gz (and .deb etc) exists, glibc-7.tar.gz does not. The
current diagnostic contains the information the user actually needs,
yours does not.

--
http://www.greenend.org.uk/rjk/

Rainer Weikusat

unread,
Dec 8, 2014, 11:48:32 AM12/8/14
to
A remarkably meaningless statement. You could have a look at how the
glibc NSS (name service switch) code employs (preprocessor) macros in
order to avoid 'text duplication' if you rather want an example. The C
preprocessor is a poor facility for metaprogramming and should only be
used sparingly, if at all, for anything more complicated than

#define THE_MESSAGE "Lasciate ogne speranza, voi ch'intrate"

The code isn't really doing anything complicated, it's just glue for
tieing the C library 'getpw*-style lookup routines' to various 'database
backends', yet, it is seriously difficult to detemine its behaviour by
examining it as there isn't really any code, just building blocks/
bricks the preprocessor will use to create the code during compilation.

Ian Collins

unread,
Dec 8, 2014, 1:29:18 PM12/8/14
to
Rainer Weikusat wrote:
> Ian Collins <ian-...@hotmail.com> writes:
>> Rainer Weikusat wrote:
>>> While I have a deep respect for him, although mainly because of the
>>> extraordinary amount of effort he put into teaching people things
>>> because of the many texts he wrote (I'm not so much fond of his code, as
>>> glibc excels at the "C++ disease" of solving fairly simple problems in
>>> hideously complicated and seriously overgeneralized ways)
>>
>> I always have a chuckle when people post general statements about
>> overgeneralisation...
>
> A remarkably meaningless statement.

Just like your "C++ disease" comment above. It's people who write
unnecessarily complex code, not the language.

> You could have a look at how the
> glibc NSS (name service switch) code employs (preprocessor) macros in
> order to avoid 'text duplication' if you rather want an example. The C
> preprocessor is a poor facility for metaprogramming and should only be
> used sparingly, if at all, for anything more complicated than
>
> #define THE_MESSAGE "Lasciate ogne speranza, voi ch'intrate"
>
> The code isn't really doing anything complicated, it's just glue for
> tieing the C library 'getpw*-style lookup routines' to various 'database
> backends', yet, it is seriously difficult to detemine its behaviour by
> examining it as there isn't really any code, just building blocks/
> bricks the preprocessor will use to create the code during compilation.

So the code is overgeneralised. Which just goes to show this is a
process issue, nothing to do with the language used.

--
Ian Collins

Rainer Weikusat

unread,
Dec 8, 2014, 2:43:26 PM12/8/14
to
Ian Collins <ian-...@hotmail.com> writes:
> Rainer Weikusat wrote:
>> Ian Collins <ian-...@hotmail.com> writes:
>>> Rainer Weikusat wrote:
>>>> While I have a deep respect for him, although mainly because of the
>>>> extraordinary amount of effort he put into teaching people things
>>>> because of the many texts he wrote (I'm not so much fond of his code, as
>>>> glibc excels at the "C++ disease" of solving fairly simple problems in
>>>> hideously complicated and seriously overgeneralized ways)
>>>
>>> I always have a chuckle when people post general statements about
>>> overgeneralisation...
>>
>> A remarkably meaningless statement.
>
> Just like your "C++ disease" comment above.

Considering that 'general statement' and 'generalized/ generic code'
have absolutely nothing in common, a similarly designed witticism could
be

"I always have a chuckle when someone named Balls contacts syphilis"

This may be regardes as funny (or tasteless) but it doesn't really
communicate anything about the cause for 'the chuckle'.

[...]

>> You could have a look at how the glibc NSS (name service switch) code
>> employs (preprocessor) macros in order to avoid 'text duplication' if
>> you rather want an example. The C preprocessor is a poor facility for
>> metaprogramming and should only be used sparingly, if at all, for
>> anything more complicated than
>>
>> #define THE_MESSAGE "Lasciate ogne speranza, voi ch'intrate"
>>
>> The code isn't really doing anything complicated, it's just glue for
>> tieing the C library 'getpw*-style lookup routines' to various 'database
>> backends', yet, it is seriously difficult to detemine its behaviour by
>> examining it as there isn't really any code, just building blocks/
>> bricks the preprocessor will use to create the code during compilation.
>
> So the code is overgeneralised. Which just goes to show this is a
> process issue, nothing to do with the language used.

Well, someone who liked using (pseudo-)C++ in example code wrote the
getXXbyYY.c file defining the

LOOKUP_TYPE *FUNCTION_NAME (ADD_PARAMS)

function whose implementation ultimatively calls

INTERNAL (REENTRANT_NAME) (ADD_VARIABLES, &resbuf, buffer,
buffer_size, &result H_ERRNO_VAR)

Ian Collins

unread,
Dec 8, 2014, 3:18:00 PM12/8/14
to
Such awful code would never get written in C++ because the language
provides better tools to do the job.

--
Ian Collins

Marc Haber

unread,
Dec 18, 2014, 3:39:49 AM12/18/14
to
Richard Kettlewell <r...@greenend.org.uk> wrote:
>testing and unstable have more recent Glibc (2.19) so you could use one
>of those, if their weaker stability guarantees are acceptable.
>
>You could attempt to install unstable’s Glibc in a system otherwise
>running stable but nobody is making any promises that that will work or
>even be installable.

Don't. This will bring you the disadvantages of new bugs and old
software and a wildly untested combination of libs and code.

Greetigns
Marc
--
-------------------------------------- !! No courtesy copies, please !! -----
Marc Haber | " Questions are the | Mailadresse im Header
Mannheim, Germany | Beginning of Wisdom " | http://www.zugschlus.de/
Nordisch by Nature | Lt. Worf, TNG "Rightful Heir" | Fon: *49 621 72739834

Michael Press

unread,
Feb 5, 2015, 11:46:36 PM2/5/15
to
In article <slrnm89i9a.1...@frailea.sa.invalid>,
Jorgen Grahn <grahn...@snipabacken.se> wrote:

> On Sun, 2014-12-07, Rainer Weikusat wrote:
> ...
> > glibc excels at the "C++ disease" of solving fairly simple problems in
> > hideously complicated and seriously overgeneralized ways
>
> We C++ programmers had it alright, but some of us got well again and
> are now immune. I hear scientists are working on a vaccine.

Hello. Thanks for mentioning this.
I looked at but never learned C++ because it is contrary
to my aesthetic. In the spirit of full disclosure
I have been employed productively as a programmer
though at a level not nearly matching the competence
extant in this forum.

--
Michael Press
0 new messages