[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: How to downgrade libc6 ?



On Fri, Nov 11, 2005 at 04:14:07PM +0100, Markus.Grunwald@pruftechnik.com wrote:
> today, I aptitude installed apache2, which took a new libc6 with it.
> Now I can't link against one of my libs anymore:
> 
> /usr/local/lib/libcpdbg.a(cpdebug.o)(.text+0x374): In function 
> `dbgSprintx':
> : undefined reference to `__ctype_b'
> ./lib_x86/libtabe.a(tabe_zuyin.o)(.text+0x7c): In function 
> `tabeZozyKeyToZuYinIndex':
> : undefined reference to `__ctype_tolower'
> 
> I might be able to recompile it, but this could take a long time so I may 
> be forced to go back to the elder libc6 - unfortunately, I don't know 
> how...

Instead of downgrading your system's libc, you could simply fetch the
appropriate old version, and then explicitly link against that libc.

It's probably easiest to get the .deb from http://packages.debian.org,
e.g. for stable

http://packages.debian.org/stable/libdevel/libc6-dev

Then, once you've downloaded the package, extract the file you need.
For static linking that would be just libc.a:

$ dpkg-deb --fsys-tarfile libc6-dev_2.3.2.ds1-22_i386.deb | tar x -O ./usr/lib/libc.a >libc-2.3.2.a

(Even though it's unusual to statically link libc, I'd recommend to do
so in this particular case -- it might save you from some hair-pulling...)

Then use the option -nodefaultlibs and link with the old libc-2.3.2.a.
As -nodefaultlibs removes -lc, -lgcc, -lgcc_eh from gcc's internal
linker commandline, you might want to re-add -lgcc and -lgcc_eh (but
not -lc), if you need them.

A simple example probably demonstrates it best.  Lacking any better
ideas, I'll use a slightly modifed variant of that dreadfully overused
"hello world" program:

/*--- hello.c ---*/
#include <stdio.h>
#include <ctype.h>

void print_hello_world() {
    char *s = "HELLO WORLD!\n";
    int c;
    /* deliberately use one of the problematic symbols... */
    while (c = *s++) printf("%c", __ctype_tolower[c]);
}

That represents your old lib, which you don't want to rebuild.
Let's assume you had once done something like

$ gcc -c hello.c
$ ar -r libhello.a hello.o

and now still have that old libhello.a.  Naturally, you also have an
associated header file:

/*--- hello.h ---*/
void print_hello_world();

Now, you've created some new code you need to link against that lib:

/*--- hellomain.c ---*/
#include "hello.h"

int main() {
    print_hello_world();
    return 0;
}

But when you try to do so on a system with a new libc you get

$ gcc -o hello hellomain.c libhello.a
libhello.a(libhello.o): In function `print_hello_world':
libhello.o(.text+0x34): undefined reference to `__ctype_tolower'
collect2: ld returned 1 exit status

However, when you link against the old libc-2.3.2 you fetched above,
things should be fine

$ gcc -o hello_static -nodefaultlibs hellomain.c libhello.a libc-2.3.2.a -lgcc

(to document what you're doing, you can also add the switch -static,
but in this particular case the result should be no different...)

And you get, as expected

$ ./hello_static
hello world!

Also, ldd should confirm that no dynamic libs are required:

$ ldd ./hello-static
        not a dynamic executable


OK, if you're feeling adventurous, or have many small programs to link
against your old lib, you can of course also link them dynamically,
which is somewhat more involved:

You need libc-2.3.2.so, ld-2.3.2.so (i.e. the dynamic loader/linker)
and libc_nonshared.a.  The latter is from libc6-dev, the other two
are in the package libc6.
Decide on where you want to keep them - preferably in some seperate
directory, e.g. /usr/local/lib/libc-old - then extract them there

$ cd /usr/local/lib/libc-old
$ dpkg-deb --fsys-tarfile /tmp/libc6-dev_2.3.2.ds1-22_i386.deb | tar x -O ./usr/lib/libc_nonshared.a >libc_nonshared
$ dpkg-deb --fsys-tarfile /tmp/libc6_2.3.2.ds1-22_i386.deb | tar x -O ./lib/libc-2.3.2.so >libc-2.3.2.so
$ dpkg-deb --fsys-tarfile /tmp/libc6_2.3.2.ds1-22_i386.deb | tar x -O ./lib/ld-2.3.2.so >ld-2.3.2.so

(the libc_nonshared.a is required during linking only, the other two
are needed both at compiletime and when you run the program)

$ ln -s libc-2.3.2.so libc.so.6
$ chmod +x ld-2.3.2.so
$ ls -l
-rwxr-xr-x    1 ab       ab          90248 12. Nov 11:30 ld-2.3.2.so
-rw-r--r--    1 ab       ab        1244688 12. Nov 11:29 libc-2.3.2.so
-rw-r--r--    1 ab       ab          10400 12. Nov 11:29 libc_nonshared.a
lrwxrwxrwx    1 ab       ab             13 12. Nov 11:31 libc.so.6 -> libc-2.3.2.so

Now, you should be able to link the stuff:

$ LIBPATH=/usr/local/lib/libc_old
$ gcc -o hello \
    -nodefaultlibs \
    -Wl,-rpath $LIBPATH \
    -Wl,--dynamic-linker $LIBPATH/ld-2.3.2.so \
    hellomain.c libhello.a \
    $LIBPATH/libc.so.6 \
    $LIBPATH/libc_nonshared.a \
    $LIBPATH/ld-2.3.2.so

$ ./hello
hello world!

and ldd should show

$ ldd ./hello
        libc.so.6 => /usr/local/lib/libc_old/libc.so.6 (0x40018000)
        /usr/local/lib/libc_old/ld-2.3.2.so => /usr/local/lib/libc_old/ld-2.3.2.so (0x40000000)

You'll probably have to tweak things somewhat to integrate this in your
specific build environment, but this should give you the basic idea...
Also, if you're planning to use the old libc for more than just some
occasional re-linking, you'll probably also want to install the correct
include files somewhere, and make that location known via -I.

Cheers,
Almut



Reply to: