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

Re: What hack in ld.so?



   Date: Sat, 30 Jan 1999 16:06:04 -0700 (MST)
   From: Jason Gunthorpe <jgg@ualberta.ca>

   On 30 Jan 1999, Alexandre Oliva wrote:

   > Obviously, this would have never been needed if old libraries had not
   > been replaced with (in)compatible versions, but the maintainers of
   > Debian have already taken this step, despite the fact that this would

   Look, it was not us that decided to do this. It was the upstream
   maintainers, other dists and a huge combination of factors. It is not in
   our power to choose a different direction to solve these problems, we must
   have libc6 xlib called libX11.so.6 and we must have libc5 called
   libX11.so.6 - that is what all the other dists did, that is the default
   and expected compilation behavoir of xlib and it is what all the new glibc
   binary-only programs are using (ie netscape)

   If you want to say that is a dumb way then fine, but you have not proposed
   an alternative to solving the versioning problem and you have not proposed
   an alternative way to handle the requirement of identical sonames and
   libtool continues to perpetuate this 'bad' behavoir and makes it worse by
   providing no way to get around it with the standard linux ld.so

What you are saying, I think, is that you have two programs with
    A) DT_NEEDED libc.so.5, DT_NEEDED libX11.so.6
    B) DT_NEEDED libc.so.6, DT_NEEDED libX11.so.6
Neither has DT_RPATH.  The system has four libraries:
    libc.so.5
    libc.so.6
    libX11.so.6 with DT_NEEDED libc.so.5
    libX11.so.6 with DT_NEEDED libc.so.6
You want programs A and B to both work, without modification.

This was done by modifying the search algorithm used by the dynamic
linker so that it chooses the version of libX11.so.6 which matches the
version of libc.so.N used by the program.  This was done by recording
in /etc/ld.so.cache the version of libc which the shared library uses.
The dynamic linker was modified to look in /etc/ld.so.cache for
libraries which were not found in DT_RPATH, but to only select
libraries listed in /etc/ld.so.cache which matched the version of the
dynamic linker being used.  Programs which are linked against
different versions of libc must then use different dynamic linkers.
There are in fact three different dynamic linkers which understand
this ld.so.cache algorithm: the old a.out dynamic linker, the libc5
dynamic linker, and the glibc dynamic linker.

I just spent some time looking at the ld.so sources.  Interestingly,
it seems to me that everything will work correctly in the sources I
was looking at.  That is because the libc5 dynamic linker on my system
(RedHat 5.2) was modified to search the library cache before using the
application's DT_RPATH.

I think that is a hack that Debian is missing: it is the final hack to
the libc5 dynamic linker to change the search path to account for the
moved shared libraries even when rpath is used.  I have appended the
RedHat patch below.  This is to ld.so-1.9.5.  Of course, this will
technically break the handling of DT_RPATH.  However, we've already
determined that DT_RPATH binaries will not work correctly anyhow,
because the shared libraries were moved.  So using this patch should
not make us any worse off.

   Indeed libtool causes such a severe problem that if you take a libtool
   program, compile it on a libc5 Slackware and try to run it on -any- glibc
   system IT WILL NOT WORK. 

This is not quite right.  As I described above, glibc and libc5
binaries use a different dynamic linker.  So the behaviour of your
libc5 binary depends upon the behaviour of your libc5 dynamic linker.
That linker does not come from glibc.  Although I can not test this, I
now believe that if you take a libtool program, compile it on a libc5
Slackware and try to run it on a RedHat 5.2 system, it will work.

Ian

--- ld.so-1.9.5/d-link/readelflib1.c.ewt	Mon Nov 17 10:04:15 1997
+++ ld.so-1.9.5/d-link/readelflib1.c	Mon Nov 17 10:23:15 1997
@@ -179,38 +179,10 @@
     goto goof;
   }
 
-  /*
-   * The ABI specifies that RPATH is searched before LD_*_PATH or
-   * the default path of /usr/lib.
-   * Check in rpath directories 
-   */
-  for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) {
-    if (tpnt->libtype == elf_executable) {
-      pnt1 = (char *)tpnt->dynamic_info[DT_RPATH];
-      if(pnt1) {
-	pnt1 += (unsigned int) tpnt->loadaddr + tpnt->dynamic_info[DT_STRTAB];
-	while(*pnt1){
-	  pnt2 = mylibname;
-	  while(*pnt1 && *pnt1 != ':') {
-	    if (pnt2 - mylibname < 1024)
-	      *pnt2++ = *pnt1++;
-	    else
-	      pnt1++;
-	  }
-	  if (pnt2 - mylibname >= 1024)
-	    break;
-	  if(pnt2[-1] != '/') *pnt2++ = '/';
-	  pnt = libname;
-	  while(*pnt) *pnt2++  = *pnt++;
-	  *pnt2++ = 0;
-	  tpnt1 = _dl_load_elf_shared_library(mylibname, 0);
-	  if(tpnt1) return tpnt1;
-	  if(*pnt1 == ':') pnt1++;
-	}
-      }
-    }
-  }
-  
+  /* EWT - change things around a bit... The RPATH is almost definitely
+     wrong for libc 5 apps as things got moved around so much. Rather
+     then checking it first, we'll check it last. While this could
+     cause major breakages, it probably won't. */
 
   /* Check in LD_{ELF_}LIBRARY_PATH, if specified and allowed */
   pnt1 = _dl_library_path;
@@ -259,6 +231,38 @@
     }
   }
 #endif
+
+  /*
+   * The ABI specifies that RPATH is searched before LD_*_PATH or
+   * the default path of /usr/lib.
+   * Check in rpath directories 
+   */
+  for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) {
+    if (tpnt->libtype == elf_executable) {
+      pnt1 = (char *)tpnt->dynamic_info[DT_RPATH];
+      if(pnt1) {
+	pnt1 += (unsigned int) tpnt->loadaddr + tpnt->dynamic_info[DT_STRTAB];
+	while(*pnt1){
+	  pnt2 = mylibname;
+	  while(*pnt1 && *pnt1 != ':') {
+	    if (pnt2 - mylibname < 1024)
+	      *pnt2++ = *pnt1++;
+	    else
+	      pnt1++;
+	  }
+	  if (pnt2 - mylibname >= 1024)
+	    break;
+	  if(pnt2[-1] != '/') *pnt2++ = '/';
+	  pnt = libname;
+	  while(*pnt) *pnt2++  = *pnt++;
+	  *pnt2++ = 0;
+	  tpnt1 = _dl_load_elf_shared_library(mylibname, 0);
+	  if(tpnt1) return tpnt1;
+	  if(*pnt1 == ':') pnt1++;
+	}
+      }
+    }
+  }
 
   /* Check in /usr/lib */
 #ifdef IBCS_COMPATIBLE


Reply to: