public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* Re: Bug in dynamic linker
@ 2000-07-19 17:52 Nick Clifton
  0 siblings, 0 replies; 18+ messages in thread
From: Nick Clifton @ 2000-07-19 17:52 UTC (permalink / raw)
  To: hjl; +Cc: p.a.barros, binutils

Hi H.J.

: 2000-07-18  H.J. Lu  <hjl@gnu.org>
: 
: 	* bfd-in.h (bfd_elf_set_dt_needed_soname): New.
: 	* bfd-in2.h: Rebuild.
: 
: 	* elf-bfd.h (elf_obj_tdata): Add dt_soname.
: 	(elf_dt_soname): New.
: 
: 	* elf.c (bfd_elf_set_dt_needed_soname): New.
: 
: 	* elflink.h (elf_link_add_object_symbols): Add the DT_NEEDED
: 	entry if the shared object loaded by DT_NEEDED is used to
: 	resolve the reference in a regular object.
  
: 2000-07-18  H.J. Lu  <hjl@gnu.org>
: 
: 	* emultempl/elf32.em (gld${EMULATION_NAME}_try_needed): Call
: 	bfd_elf_set_dt_needed_soname ().

Approved.

Cheers
	Nick

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Bug in dynamic linker
  2000-07-27 16:56 Nick Clifton
@ 2000-07-27 17:49 ` H . J . Lu
  0 siblings, 0 replies; 18+ messages in thread
From: H . J . Lu @ 2000-07-27 17:49 UTC (permalink / raw)
  To: Nick Clifton; +Cc: binutils

On Thu, Jul 27, 2000 at 04:56:27PM -0700, Nick Clifton wrote:
> Hi HJ,
> 
> 2000-07-20  H.J. Lu  <hjl@gnu.org>
> 
>         * elflink.h (elf_merge_symbol): Take one more argument,
>         dt_needed, to indicate if the symbol comes from a DT_NEEDED
>         entry. Don't overide the existing weak definition if dt_needed
>         is true.
>         (elf_link_add_object_symbols): Pass dt_needed to
>         elf_merge_symbol ().
> 
> 
> Approved.
> 

Done. Thanks.

-- 
H.J. Lu (hjl@gnu.org)

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Bug in dynamic linker
@ 2000-07-27 16:56 Nick Clifton
  2000-07-27 17:49 ` H . J . Lu
  0 siblings, 1 reply; 18+ messages in thread
From: Nick Clifton @ 2000-07-27 16:56 UTC (permalink / raw)
  To: hjl; +Cc: binutils

Hi HJ,

2000-07-20  H.J. Lu  <hjl@gnu.org>

        * elflink.h (elf_merge_symbol): Take one more argument,
        dt_needed, to indicate if the symbol comes from a DT_NEEDED
        entry. Don't overide the existing weak definition if dt_needed
        is true.
        (elf_link_add_object_symbols): Pass dt_needed to
        elf_merge_symbol ().


Approved.

Sorry it took so long.  :-)

Cheers
	Nick

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Bug in dynamic linker
  2000-07-20 11:04         ` H . J . Lu
@ 2000-07-20 15:23           ` H . J . Lu
  0 siblings, 0 replies; 18+ messages in thread
From: H . J . Lu @ 2000-07-20 15:23 UTC (permalink / raw)
  To: Mark Kettenis; +Cc: nickc, binutils, Ian Lance Taylor

On Thu, Jul 20, 2000 at 11:04:16AM -0700, H . J . Lu wrote:
> On Thu, Jul 20, 2000 at 07:56:08PM +0200, Mark Kettenis wrote:
> > 
> > Here it is (thanks for including the shar target :-)).  By the way,
> 
> Sure.
> 
> > looks like there's something wrong with the linker.  I get the
> 
> Yes, I fixed it and checked my fix into CVS :-). BTW, that is the
> one we are discussing now.
> 
> > following output (with glibc 2.1.3):
> > 
> > delius:~/tmp/needed$ make
> > for f in threadtest test; do echo "Running: $f"; ./$f; \
> >   if [ $? != 0 ]; then echo Failed; fi; done
> > Running: threadtest
> > BUG IN DYNAMIC LINKER ld.so: dynamic-link.h: 57: elf_get_dynamic_info: Assertion `! "bad dynamic tag"' failed!
> > Failed
> > Running: test
> > ./test: error in loading shared libraries: libthreadlib.so: cannot open shared object file: No such file or directory
> > Failed
> > for f in threadtest test; do echo "Running: ldd $f"; ldd ./$f; \
> >   if [ $? != 0 ]; then echo Failed; fi; done
> > Running: ldd threadtest
> > BUG IN DYNAMIC LINKER ld.so: dynamic-link.h: 57: elf_get_dynamic_info: Assertion `! "bad dynamic tag"' failed!
> > ldd: /lib/ld-linux.so.2 exited with unknown exit code (127)
> > Failed
> > Running: ldd test
> >        libthreadlib.so => not found
> >        libc.so.6 => /lib/libc.so.6 (0x40015000)
> >        libpthread.so.0 => /lib/libpthread.so.0 (0x400f8000)
> >        /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
> > delius:~/tmp/needed$ make
> > 
> 
> With the current linker from CVS,
> 
> # make
> ....
> Running: ldd threadtest
>         libthreadlib.so => ./libthreadlib.so (0x40019000)
>         libc.so.6 => /lib/libc.so.6 (0x4002a000)
>         libpthread.so.0 => /lib/libpthread.so.0 (0x4013e000)
>         /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
> Running: ldd test
>         libthreadlib.so => not found
>         libc.so.6 => /lib/libc.so.6 (0x40028000)
>         /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
> 
> If you think there still is a problem, please send me a testcase
> to show it.
> 

I did find a problem under glibc 2.1.3 since close is not weak in
libpthread.so. In glibc 2.2, close is weak in libpthread.so. Here
is a patch for that case. Any comments?

BTW, this patch has some interesting impacts on the testcase. I don't
know for sure if it will break anything although I think it is ok.

Thanks.


H.J.
----
2000-07-20  H.J. Lu  <hjl@gnu.org>

	* elflink.h (elf_merge_symbol): Take one more argument,
	dt_needed, to indicate if the symbol comes from a DT_NEEDED
	entry. Don't overide the existing weak definition if dt_needed
	is true.
	(elf_link_add_object_symbols): Pass dt_needed to
	elf_merge_symbol ().

--- /home/is/sourceware/src/bfd/elflink.h	Thu Jul 20 14:15:05 2000
+++ elflink.h	Thu Jul 20 15:08:35 2000
@@ -35,7 +35,7 @@ static boolean elf_link_add_archive_symb
 static boolean elf_merge_symbol
   PARAMS ((bfd *, struct bfd_link_info *, const char *, Elf_Internal_Sym *,
 	   asection **, bfd_vma *, struct elf_link_hash_entry **,
-	   boolean *, boolean *, boolean *));
+	   boolean *, boolean *, boolean *, boolean));
 static boolean elf_export_symbol
   PARAMS ((struct elf_link_hash_entry *, PTR));
 static boolean elf_fix_symbol_flags
@@ -433,11 +433,12 @@ elf_link_add_archive_symbols (abfd, info
    TYPE_CHANGE_OK if it is OK for the type to change.  We set
    SIZE_CHANGE_OK if it is OK for the size to change.  By OK to
    change, we mean that we shouldn't warn if the type or size does
-   change.  */
+   change. DT_NEEDED indicates if it comes from a DT_NEEDED entry of
+   a shared object.  */
 
 static boolean
 elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
-		  override, type_change_ok, size_change_ok)
+		  override, type_change_ok, size_change_ok, dt_needed)
      bfd *abfd;
      struct bfd_link_info *info;
      const char *name;
@@ -448,6 +449,7 @@ elf_merge_symbol (abfd, info, name, sym,
      boolean *override;
      boolean *type_change_ok;
      boolean *size_change_ok;
+     boolean dt_needed;
 {
   asection *sec;
   struct elf_link_hash_entry *h;
@@ -624,9 +626,11 @@ elf_merge_symbol (abfd, info, name, sym,
     olddyncommon = false;
 
   /* It's OK to change the type if either the existing symbol or the
-     new symbol is weak.  */
+     new symbol is weak unless it comes from a DT_NEEDED entry of
+     a shared object, in which case, the DT_NEEDED entry may not be
+     required at the run time. */
 
-  if (h->root.type == bfd_link_hash_defweak
+  if ((! dt_needed && h->root.type == bfd_link_hash_defweak)
       || h->root.type == bfd_link_hash_undefweak
       || bind == STB_WEAK)
     *type_change_ok = true;
@@ -678,7 +682,9 @@ elf_merge_symbol (abfd, info, name, sym,
      object to override a weak symbol in a shared object.
 
      We prefer a non-weak definition in a shared library to a weak
-     definition in the executable.  */
+     definition in the executable unless it comes from a DT_NEEDED
+     entry of a shared object, in which case, the DT_NEEDED entry
+     may not be required at the run time. */
 
   if (newdyn
       && newdef
@@ -686,7 +692,8 @@ elf_merge_symbol (abfd, info, name, sym,
 	  || (h->root.type == bfd_link_hash_common
 	      && (bind == STB_WEAK
 		  || ELF_ST_TYPE (sym->st_info) == STT_FUNC)))
-      && (h->root.type != bfd_link_hash_defweak
+      && (h->root.type != bfd_link_hash_defweak 
+	  || dt_needed
 	  || bind == STB_WEAK))
     {
       *override = true;
@@ -821,8 +828,11 @@ elf_merge_symbol (abfd, info, name, sym,
 
   /* Handle the special case of a weak definition in a regular object
      followed by a non-weak definition in a shared object.  In this
-     case, we prefer the definition in the shared object.  */
+     case, we prefer the definition in the shared object unless it
+     comes from a DT_NEEDED entry of a shared object, in which case,
+     the DT_NEEDED entry may not be required at the run time. */
   if (olddef
+      && ! dt_needed
       && h->root.type == bfd_link_hash_defweak
       && newdef
       && newdyn
@@ -1465,7 +1475,7 @@ elf_link_add_object_symbols (abfd, info)
 
 	  if (! elf_merge_symbol (abfd, info, name, &sym, &sec, &value,
 				  sym_hash, &override, &type_change_ok,
-				  &size_change_ok))
+				  &size_change_ok, dt_needed))
 	    goto error_return;
 
 	  if (override)
@@ -1668,7 +1678,8 @@ elf_link_add_object_symbols (abfd, info)
 		  size_change_ok = false;
 		  if (! elf_merge_symbol (abfd, info, shortname, &sym, &sec,
 					  &value, &hi, &override,
-					  &type_change_ok, &size_change_ok))
+					  &type_change_ok,
+					  &size_change_ok, dt_needed))
 		    goto error_return;
 
 		  if (! override)
@@ -1785,7 +1796,8 @@ elf_link_add_object_symbols (abfd, info)
 		  size_change_ok = false;
 		  if (! elf_merge_symbol (abfd, info, shortname, &sym, &sec,
 					  &value, &hi, &override,
-					  &type_change_ok, &size_change_ok))
+					  &type_change_ok,
+					  &size_change_ok, dt_needed))
 		    goto error_return;
 
 		  if (override)

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Bug in dynamic linker
  2000-07-20 10:56       ` Mark Kettenis
@ 2000-07-20 11:04         ` H . J . Lu
  2000-07-20 15:23           ` H . J . Lu
  0 siblings, 1 reply; 18+ messages in thread
From: H . J . Lu @ 2000-07-20 11:04 UTC (permalink / raw)
  To: Mark Kettenis; +Cc: nickc, binutils

On Thu, Jul 20, 2000 at 07:56:08PM +0200, Mark Kettenis wrote:
> 
> Here it is (thanks for including the shar target :-)).  By the way,

Sure.

> looks like there's something wrong with the linker.  I get the

Yes, I fixed it and checked my fix into CVS :-). BTW, that is the
one we are discussing now.

> following output (with glibc 2.1.3):
> 
> delius:~/tmp/needed$ make
> for f in threadtest test; do echo "Running: $f"; ./$f; \
>   if [ $? != 0 ]; then echo Failed; fi; done
> Running: threadtest
> BUG IN DYNAMIC LINKER ld.so: dynamic-link.h: 57: elf_get_dynamic_info: Assertion `! "bad dynamic tag"' failed!
> Failed
> Running: test
> ./test: error in loading shared libraries: libthreadlib.so: cannot open shared object file: No such file or directory
> Failed
> for f in threadtest test; do echo "Running: ldd $f"; ldd ./$f; \
>   if [ $? != 0 ]; then echo Failed; fi; done
> Running: ldd threadtest
> BUG IN DYNAMIC LINKER ld.so: dynamic-link.h: 57: elf_get_dynamic_info: Assertion `! "bad dynamic tag"' failed!
> ldd: /lib/ld-linux.so.2 exited with unknown exit code (127)
> Failed
> Running: ldd test
>        libthreadlib.so => not found
>        libc.so.6 => /lib/libc.so.6 (0x40015000)
>        libpthread.so.0 => /lib/libpthread.so.0 (0x400f8000)
>        /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
> delius:~/tmp/needed$ make
> 

With the current linker from CVS,

# make
....
Running: ldd threadtest
        libthreadlib.so => ./libthreadlib.so (0x40019000)
        libc.so.6 => /lib/libc.so.6 (0x4002a000)
        libpthread.so.0 => /lib/libpthread.so.0 (0x4013e000)
        /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
Running: ldd test
        libthreadlib.so => not found
        libc.so.6 => /lib/libc.so.6 (0x40028000)
        /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

If you think there still is a problem, please send me a testcase
to show it.

Thanks.


H.J.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Bug in dynamic linker
  2000-07-20 10:16     ` H . J . Lu
@ 2000-07-20 10:56       ` Mark Kettenis
  2000-07-20 11:04         ` H . J . Lu
  0 siblings, 1 reply; 18+ messages in thread
From: Mark Kettenis @ 2000-07-20 10:56 UTC (permalink / raw)
  To: hjl; +Cc: nickc, binutils

   Date: Thu, 20 Jul 2000 10:16:12 -0700
   From: "H . J . Lu" <hjl@lucon.org>

   On Thu, Jul 20, 2000 at 07:10:48PM +0200, Mark Kettenis wrote:
   > symbol in libpthread.  That means that by walking the DT_NEEDED chain,
   > ld will prefer the definition in libpthread.  I believe that with your
   > patch foo will get a DT_NEEDED for libpthread.  The reason I believe
   > this is true, is that right now ld records the version information for
   > close in libpthread.  This was the exact scenario causing the
   > origional "bug".
   > 
   > So you see that there are cases where a program doesn't explicitly
   > reference a symbol in a particular library, it will nevertheless get
   > a DT_NEEDED for that library.

   Could you please spend a few minutes creating a testcase and sending
   to me? Call me dumb. I need to see it to really believe it. I really
   appreciate it.

Here it is (thanks for including the shar target :-)).  By the way,
looks like there's something wrong with the linker.  I get the
following output (with glibc 2.1.3):

delius:~/tmp/needed$ make
for f in threadtest test; do echo "Running: $f"; ./$f; \
  if [ $? != 0 ]; then echo Failed; fi; done
Running: threadtest
BUG IN DYNAMIC LINKER ld.so: dynamic-link.h: 57: elf_get_dynamic_info: Assertion `! "bad dynamic tag"' failed!
Failed
Running: test
./test: error in loading shared libraries: libthreadlib.so: cannot open shared object file: No such file or directory
Failed
for f in threadtest test; do echo "Running: ldd $f"; ldd ./$f; \
  if [ $? != 0 ]; then echo Failed; fi; done
Running: ldd threadtest
BUG IN DYNAMIC LINKER ld.so: dynamic-link.h: 57: elf_get_dynamic_info: Assertion `! "bad dynamic tag"' failed!
ldd: /lib/ld-linux.so.2 exited with unknown exit code (127)
Failed
Running: ldd test
       libthreadlib.so => not found
       libc.so.6 => /lib/libc.so.6 (0x40015000)
       libpthread.so.0 => /lib/libpthread.so.0 (0x400f8000)
       /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
delius:~/tmp/needed$ make

Mark


#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.2).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `!/bin/sh' line above, then type `sh FILE'.
#
# Made on 2000-07-20 19:46 CEST by <kettenis@delius.kettenis.local>.
# Source directory was `/home/kettenis/tmp/needed'.
#
# Existing files will *not* be overwritten unless `-c' is specified.
#
# This shar contains:
# length mode       name
# ------ ---------- ------------------------------------------
#    143 -rw-r--r-- test.c
#    218 -rw-r--r-- threadlib.c
#    207 -rw-r--r-- threadtest.c
#    696 -rw-r--r-- Makefile
#
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=FAILED
locale_dir=FAILED
first_param="$1"
for dir in $PATH
do
  if test "$gettext_dir" = FAILED && test -f $dir/gettext \
     && ($dir/gettext --version >/dev/null 2>&1)
  then
    set `$dir/gettext --version 2>&1`
    if test "$3" = GNU
    then
      gettext_dir=$dir
    fi
  fi
  if test "$locale_dir" = FAILED && test -f $dir/shar \
     && ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
  then
    locale_dir=`$dir/shar --print-text-domain-dir`
  fi
done
IFS="$save_IFS"
if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED
then
  echo=echo
else
  TEXTDOMAINDIR=$locale_dir
  export TEXTDOMAINDIR
  TEXTDOMAIN=sharutils
  export TEXTDOMAIN
  echo="$gettext_dir/gettext -s"
fi
touch -am 1231235999 $$.touch >/dev/null 2>&1
if test ! -f 1231235999 && test -f $$.touch; then
  shar_touch=touch
else
  shar_touch=:
  echo
  $echo 'WARNING: not restoring timestamps.  Consider getting and'
  $echo "installing GNU \`touch', distributed in GNU File Utilities..."
  echo
fi
rm -f 1231235999 $$.touch
#
if mkdir _sh18434; then
  $echo 'x -' 'creating lock directory'
else
  $echo 'failed to create lock directory'
  exit 1
fi
# ============= test.c ==============
if test -f 'test.c' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'test.c' '(file already exists)'
else
  $echo 'x -' extracting 'test.c' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'test.c' &&
#include <stdio.h>
X  
extern int dummy(void);
X  
int main(int argc, char **argv) {
X  printf("spec = %d\n", dummy());
X  close(0);
X  return 0;
}
SHAR_EOF
  $shar_touch -am 07201943100 'test.c' &&
  chmod 0644 'test.c' ||
  $echo 'restore of' 'test.c' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'test.c:' 'MD5 check failed'
eb8457ae81efd570cd91b1550570132d  test.c
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'test.c'`"
    test 143 -eq "$shar_count" ||
    $echo 'test.c:' 'original size' '143,' 'current size' "$shar_count!"
  fi
fi
# ============= threadlib.c ==============
if test -f 'threadlib.c' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'threadlib.c' '(file already exists)'
else
  $echo 'x -' extracting 'threadlib.c' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'threadlib.c' &&
#include <pthread.h>
X  
pthread_key_t mykey;
X  
int dummy(void) {
X  int spec;
X  
X  pthread_key_create(&mykey, NULL);
X  pthread_setspecific(mykey, (void *)10);
X  spec = (int)pthread_getspecific(mykey);
X  return spec;
}
SHAR_EOF
  $shar_touch -am 07181133100 'threadlib.c' &&
  chmod 0644 'threadlib.c' ||
  $echo 'restore of' 'threadlib.c' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'threadlib.c:' 'MD5 check failed'
19ecddd05773202c443a249d7583bc47  threadlib.c
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'threadlib.c'`"
    test 218 -eq "$shar_count" ||
    $echo 'threadlib.c:' 'original size' '218,' 'current size' "$shar_count!"
  fi
fi
# ============= threadtest.c ==============
if test -f 'threadtest.c' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'threadtest.c' '(file already exists)'
else
  $echo 'x -' extracting 'threadtest.c' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'threadtest.c' &&
#include <pthread.h>
#include <stdio.h>
X  
extern int dummy(void);
X  
pthread_t *me;
X  
int main(int argc, char **argv) {
X  printf("spec = %d\n", dummy());
X  me = (pthread_t *) pthread_self();
X  return 0;
}
SHAR_EOF
  $shar_touch -am 07181136100 'threadtest.c' &&
  chmod 0644 'threadtest.c' ||
  $echo 'restore of' 'threadtest.c' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'threadtest.c:' 'MD5 check failed'
b9df452c72adac53de184bc4effa931a  threadtest.c
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'threadtest.c'`"
    test 207 -eq "$shar_count" ||
    $echo 'threadtest.c:' 'original size' '207,' 'current size' "$shar_count!"
  fi
fi
# ============= Makefile ==============
if test -f 'Makefile' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'Makefile' '(file already exists)'
else
  $echo 'x -' extracting 'Makefile' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'Makefile' &&
CFLAGS=-O -B./
PIC=-fPIC
NODELETE=-Wl,-z,nodelete
X
PROGS= threadtest test
X
all: $(PROGS)
X	for f in $(PROGS); do echo "Running: $$f"; ./$$f; \
X	  if [ $$? != 0 ]; then echo Failed; fi; done
X	for f in $(PROGS); do echo "Running: ldd $$f"; ldd ./$$f; \
X	  if [ $$? != 0 ]; then echo Failed; fi; done
X
threadtest: threadtest.o libthreadlib.so
X	$(CC) -o $@ $(CFLAGS) threadtest.o -L. -lthreadlib -Wl,-rpath,.
X
test: test.o libthreadlib.so
X	$(CC) -o $@ $(CFLAGS) test.o -L. -lthreadlib #-Wl,-rpath,.
X
libthreadlib.so: threadlib.c
X	$(CC) $(NODELETE) -shared -o $@ $(CFLAGS) $(PIC) $^ -lpthread
X
X.c.o:
X	$(CC) $(CFLAGS) -c $<
X
clean:
X	rm -f $(PROGS) *.so* *.o *.s *.a
X
shar:
X	shar *.c Makefile > bug.shar
SHAR_EOF
  $shar_touch -am 07191433100 'Makefile' &&
  chmod 0644 'Makefile' ||
  $echo 'restore of' 'Makefile' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'Makefile:' 'MD5 check failed'
2b653f2c654e24704696aa1416274039  Makefile
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'Makefile'`"
    test 696 -eq "$shar_count" ||
    $echo 'Makefile:' 'original size' '696,' 'current size' "$shar_count!"
  fi
fi
rm -fr _sh18434
exit 0

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Bug in dynamic linker
  2000-07-20 10:11   ` Mark Kettenis
@ 2000-07-20 10:16     ` H . J . Lu
  2000-07-20 10:56       ` Mark Kettenis
  0 siblings, 1 reply; 18+ messages in thread
From: H . J . Lu @ 2000-07-20 10:16 UTC (permalink / raw)
  To: Mark Kettenis; +Cc: nickc, binutils

On Thu, Jul 20, 2000 at 07:10:48PM +0200, Mark Kettenis wrote:
>    Date: Thu, 20 Jul 2000 09:04:11 -0700
>    From: "H . J . Lu" <hjl@lucon.org>
> 
>    On Thu, Jul 20, 2000 at 03:06:29PM +0200, Mark Kettenis wrote:
>    > 
>    > IMHO, this patch needs some more discussion.  This isn't a simple
>    > bugfix.  It changes the way the linker behaves from the user
>    > standpoint considerably, since it will now silently add DT_NEEDED
>    > entries for libraries that are not explicitly mentioned on the
>    > command-line.  I also wonder if this patch could change the order of
>    > the DT_NEEDED entries, e.g. can a DT_NEEDED generated by HJ's patch
>    > come before a DT_NEEDED for a library mentioned on the command line?
>    > 
>    > Suppose I have an implementation of libfoo.so.1 that depends on
>    > libbar.so.  I know link a program with libfoo.so.1.  Before HJ's patch
>    > it would only get a DT_NEEDED entry for libfoo.so.1.  Now it will also
>    > get one for libbar.so.
> 
>    Are you just guessing or do you have a testcase? If you have a
>    testcase, please send it to me. I have verified your case won't
>    happen unless your program uses libbar.so. Try it yourself. If ld
>    adds libbar.so to DT_NEEDED, it is a bug and you should report
>    it to me.
> 
> Admittedly the problem scenario is a little more complicated than
> what I wrote before, and perhaps Linux-specific, but here it is:
> 
> Suppose you have a libfoo that is linked agains libpthread.  Suppose
> you have a program foo that references close, and is linked with
> libfoo.  Remember that close is a weak symbol in libc and a normal

Thanks for bringing this up.

> symbol in libpthread.  That means that by walking the DT_NEEDED chain,
> ld will prefer the definition in libpthread.  I believe that with your
> patch foo will get a DT_NEEDED for libpthread.  The reason I believe
> this is true, is that right now ld records the version information for
> close in libpthread.  This was the exact scenario causing the
> origional "bug".
> 
> So you see that there are cases where a program doesn't explicitly
> reference a symbol in a particular library, it will nevertheless get
> a DT_NEEDED for that library.

Could you please spend a few minutes creating a testcase and sending
to me? Call me dumb. I need to see it to really believe it. I really
appreciate it.

Thanks.


H.J.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Bug in dynamic linker
  2000-07-20  9:04 ` H . J . Lu
@ 2000-07-20 10:11   ` Mark Kettenis
  2000-07-20 10:16     ` H . J . Lu
  0 siblings, 1 reply; 18+ messages in thread
From: Mark Kettenis @ 2000-07-20 10:11 UTC (permalink / raw)
  To: hjl; +Cc: nickc, binutils

   Date: Thu, 20 Jul 2000 09:04:11 -0700
   From: "H . J . Lu" <hjl@lucon.org>

   On Thu, Jul 20, 2000 at 03:06:29PM +0200, Mark Kettenis wrote:
   > 
   > IMHO, this patch needs some more discussion.  This isn't a simple
   > bugfix.  It changes the way the linker behaves from the user
   > standpoint considerably, since it will now silently add DT_NEEDED
   > entries for libraries that are not explicitly mentioned on the
   > command-line.  I also wonder if this patch could change the order of
   > the DT_NEEDED entries, e.g. can a DT_NEEDED generated by HJ's patch
   > come before a DT_NEEDED for a library mentioned on the command line?
   > 
   > Suppose I have an implementation of libfoo.so.1 that depends on
   > libbar.so.  I know link a program with libfoo.so.1.  Before HJ's patch
   > it would only get a DT_NEEDED entry for libfoo.so.1.  Now it will also
   > get one for libbar.so.

   Are you just guessing or do you have a testcase? If you have a
   testcase, please send it to me. I have verified your case won't
   happen unless your program uses libbar.so. Try it yourself. If ld
   adds libbar.so to DT_NEEDED, it is a bug and you should report
   it to me.

Admittedly the problem scenario is a little more complicated than
what I wrote before, and perhaps Linux-specific, but here it is:

Suppose you have a libfoo that is linked agains libpthread.  Suppose
you have a program foo that references close, and is linked with
libfoo.  Remember that close is a weak symbol in libc and a normal
symbol in libpthread.  That means that by walking the DT_NEEDED chain,
ld will prefer the definition in libpthread.  I believe that with your
patch foo will get a DT_NEEDED for libpthread.  The reason I believe
this is true, is that right now ld records the version information for
close in libpthread.  This was the exact scenario causing the
origional "bug".

So you see that there are cases where a program doesn't explicitly
reference a symbol in a particular library, it will nevertheless get
a DT_NEEDED for that library.

   > IMHO, the *correct* solution is implementing what the Solaris linker
   > does: refusing to link if a symbol in the program cannot be resolved
   > in one of the libraries mentioned on the command line (printing a
   > message if it can be found in one of those libraries dependencies to
   > help the user).
   > 
   > If the Solaris behaviour was implemented as the default behaviour, and

   The Solaris behavior won't some runtime symbol version mismatch. We
   do.

Sorry, I cannot parse that sentence.  What do you mean?

Mark

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Bug in dynamic linker
  2000-07-20  9:56     ` Ulrich Drepper
@ 2000-07-20 10:02       ` H . J . Lu
  0 siblings, 0 replies; 18+ messages in thread
From: H . J . Lu @ 2000-07-20 10:02 UTC (permalink / raw)
  To: Ulrich Drepper; +Cc: Mark Kettenis, nickc, binutils

On Thu, Jul 20, 2000 at 09:56:32AM -0700, Ulrich Drepper wrote:
> "H . J . Lu" <hjl@lucon.org> writes:
> 
> > > I agree with Mark.  The proposed change is creating much more severe
> > > problems than it's solving.
> > 
> > Please show me the problem. A testcase will be very nice.
> 
> Mark described it:
> 
> - liba.so is built using libb.so (i.e., has a DT_NEEDED entry)
> 
> - program foo is linked with liba.so
> 
> - new version of liba.so out; same interface, but does not use libb.so
>   anymore; libb.so is removed
> 

Have you tried binutils from CVS today to see what it does? As I
have said, I have verified that program foo WON'T have a DT_NEEDED
entry for libb.so unless program foo uses symbols from libb.so
directly. As I said before, please send me a testcase to show it
is not the case.

BTW, I am enclosing my testcase here.

Thanks.


H.J.
--
#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.2.1).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `!/bin/sh' line above, then type `sh FILE'.
#
# Made on 2000-07-20 10:00 PDT by <hjl@osmium.su.varesearch.com>.
# Source directory was `/home/hjl/bugs/gas/needed'.
#
# Existing files will *not* be overwritten unless `-c' is specified.
#
# This shar contains:
# length mode       name
# ------ ---------- ------------------------------------------
#    131 -rw-r--r-- test.c
#    218 -rw-r--r-- threadlib.c
#    207 -rw-r--r-- threadtest.c
#    696 -rw-r--r-- Makefile
#
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=FAILED
locale_dir=FAILED
first_param="$1"
for dir in $PATH
do
  if test "$gettext_dir" = FAILED && test -f $dir/gettext \
     && ($dir/gettext --version >/dev/null 2>&1)
  then
    set `$dir/gettext --version 2>&1`
    if test "$3" = GNU
    then
      gettext_dir=$dir
    fi
  fi
  if test "$locale_dir" = FAILED && test -f $dir/shar \
     && ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
  then
    locale_dir=`$dir/shar --print-text-domain-dir`
  fi
done
IFS="$save_IFS"
if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED
then
  echo=echo
else
  TEXTDOMAINDIR=$locale_dir
  export TEXTDOMAINDIR
  TEXTDOMAIN=sharutils
  export TEXTDOMAIN
  echo="$gettext_dir/gettext -s"
fi
if touch -am -t 200112312359.59 $$.touch >/dev/null 2>&1 && test ! -f 200112312359.59 -a -f $$.touch; then
  shar_touch='touch -am -t $1$2$3$4$5$6.$7 "$8"'
elif touch -am 123123592001.59 $$.touch >/dev/null 2>&1 && test ! -f 123123592001.59 -a ! -f 123123592001.5 -a -f $$.touch; then
  shar_touch='touch -am $3$4$5$6$1$2.$7 "$8"'
elif touch -am 1231235901 $$.touch >/dev/null 2>&1 && test ! -f 1231235901 -a -f $$.touch; then
  shar_touch='touch -am $3$4$5$6$2 "$8"'
else
  shar_touch=:
  echo
  $echo 'WARNING: not restoring timestamps.  Consider getting and'
  $echo "installing GNU \`touch', distributed in GNU File Utilities..."
  echo
fi
rm -f 200112312359.59 123123592001.59 123123592001.5 1231235901 $$.touch
#
if mkdir _sh31904; then
  $echo 'x -' 'creating lock directory'
else
  $echo 'failed to create lock directory'
  exit 1
fi
# ============= test.c ==============
if test -f 'test.c' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'test.c' '(file already exists)'
else
  $echo 'x -' extracting 'test.c' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'test.c' &&
#include <stdio.h>
X  
extern int dummy(void);
X  
int main(int argc, char **argv) {
X  printf("spec = %d\n", dummy());
X  return 0;
}
SHAR_EOF
  (set 20 00 07 18 14 15 54 'test.c'; eval "$shar_touch") &&
  chmod 0644 'test.c' ||
  $echo 'restore of' 'test.c' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'test.c:' 'MD5 check failed'
4b6bed819d069a08ecdba10903aac6b2  test.c
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'test.c'`"
    test 131 -eq "$shar_count" ||
    $echo 'test.c:' 'original size' '131,' 'current size' "$shar_count!"
  fi
fi
# ============= threadlib.c ==============
if test -f 'threadlib.c' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'threadlib.c' '(file already exists)'
else
  $echo 'x -' extracting 'threadlib.c' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'threadlib.c' &&
#include <pthread.h>
X  
pthread_key_t mykey;
X  
int dummy(void) {
X  int spec;
X  
X  pthread_key_create(&mykey, NULL);
X  pthread_setspecific(mykey, (void *)10);
X  spec = (int)pthread_getspecific(mykey);
X  return spec;
}
SHAR_EOF
  (set 20 00 07 18 11 33 03 'threadlib.c'; eval "$shar_touch") &&
  chmod 0644 'threadlib.c' ||
  $echo 'restore of' 'threadlib.c' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'threadlib.c:' 'MD5 check failed'
19ecddd05773202c443a249d7583bc47  threadlib.c
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'threadlib.c'`"
    test 218 -eq "$shar_count" ||
    $echo 'threadlib.c:' 'original size' '218,' 'current size' "$shar_count!"
  fi
fi
# ============= threadtest.c ==============
if test -f 'threadtest.c' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'threadtest.c' '(file already exists)'
else
  $echo 'x -' extracting 'threadtest.c' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'threadtest.c' &&
#include <pthread.h>
#include <stdio.h>
X  
extern int dummy(void);
X  
pthread_t *me;
X  
int main(int argc, char **argv) {
X  printf("spec = %d\n", dummy());
X  me = (pthread_t *) pthread_self();
X  return 0;
}
SHAR_EOF
  (set 20 00 07 18 11 36 40 'threadtest.c'; eval "$shar_touch") &&
  chmod 0644 'threadtest.c' ||
  $echo 'restore of' 'threadtest.c' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'threadtest.c:' 'MD5 check failed'
b9df452c72adac53de184bc4effa931a  threadtest.c
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'threadtest.c'`"
    test 207 -eq "$shar_count" ||
    $echo 'threadtest.c:' 'original size' '207,' 'current size' "$shar_count!"
  fi
fi
# ============= Makefile ==============
if test -f 'Makefile' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'Makefile' '(file already exists)'
else
  $echo 'x -' extracting 'Makefile' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'Makefile' &&
CFLAGS=-O -B./
PIC=-fPIC
NODELETE=-Wl,-z,nodelete
X
PROGS= threadtest test
X
all: $(PROGS)
X	for f in $(PROGS); do echo "Running: $$f"; ./$$f; \
X	  if [ $$? != 0 ]; then echo Failed; fi; done
X	for f in $(PROGS); do echo "Running: ldd $$f"; ldd ./$$f; \
X	  if [ $$? != 0 ]; then echo Failed; fi; done
X
threadtest: threadtest.o libthreadlib.so
X	$(CC) -o $@ $(CFLAGS) threadtest.o -L. -lthreadlib -Wl,-rpath,.
X
test: test.o libthreadlib.so
X	$(CC) -o $@ $(CFLAGS) test.o -L. -lthreadlib #-Wl,-rpath,.
X
libthreadlib.so: threadlib.c
X	$(CC) $(NODELETE) -shared -o $@ $(CFLAGS) $(PIC) $^ -lpthread
X
X.c.o:
X	$(CC) $(CFLAGS) -c $<
X
clean:
X	rm -f $(PROGS) *.so* *.o *.s *.a
X
shar:
X	shar *.c Makefile > bug.shar
SHAR_EOF
  (set 20 00 07 19 14 33 41 'Makefile'; eval "$shar_touch") &&
  chmod 0644 'Makefile' ||
  $echo 'restore of' 'Makefile' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'Makefile:' 'MD5 check failed'
2b653f2c654e24704696aa1416274039  Makefile
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'Makefile'`"
    test 696 -eq "$shar_count" ||
    $echo 'Makefile:' 'original size' '696,' 'current size' "$shar_count!"
  fi
fi
rm -fr _sh31904
exit 0

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Bug in dynamic linker
  2000-07-20  9:51   ` H . J . Lu
@ 2000-07-20  9:56     ` Ulrich Drepper
  2000-07-20 10:02       ` H . J . Lu
  0 siblings, 1 reply; 18+ messages in thread
From: Ulrich Drepper @ 2000-07-20  9:56 UTC (permalink / raw)
  To: H . J . Lu; +Cc: Mark Kettenis, nickc, binutils

"H . J . Lu" <hjl@lucon.org> writes:

> > I agree with Mark.  The proposed change is creating much more severe
> > problems than it's solving.
> 
> Please show me the problem. A testcase will be very nice.

Mark described it:

- liba.so is built using libb.so (i.e., has a DT_NEEDED entry)

- program foo is linked with liba.so

- new version of liba.so out; same interface, but does not use libb.so
  anymore; libb.so is removed


The program will not run anymore despite the fact that the author of
liba.so took care of keeping the interface.


This is not an uncommon situation.  More often unintentional then
intentional, people are linking libs with unnecessary others libs
(e.g., packages using autoconf often link against libelf even though
it's not needed).  Since ld is always adding these libs ad DT_NEEDED
(not only if they are actually used) you'll get the situation
described above.


-- 
---------------.                          ,-.   1325 Chesapeake Terrace
Ulrich Drepper  \    ,-------------------'   \  Sunnyvale, CA 94089 USA
Red Hat          `--' drepper at redhat.com   `------------------------

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Bug in dynamic linker
  2000-07-20  9:23 ` Ulrich Drepper
@ 2000-07-20  9:51   ` H . J . Lu
  2000-07-20  9:56     ` Ulrich Drepper
  0 siblings, 1 reply; 18+ messages in thread
From: H . J . Lu @ 2000-07-20  9:51 UTC (permalink / raw)
  To: Ulrich Drepper; +Cc: Mark Kettenis, nickc, binutils

On Thu, Jul 20, 2000 at 09:23:27AM -0700, Ulrich Drepper wrote:
> Mark Kettenis <kettenis@wins.uva.nl> writes:
> 
> > IMHO, the *correct* solution is implementing what the Solaris linker
> > does:
> 
> I agree with Mark.  The proposed change is creating much more severe
> problems than it's solving.

Please show me the problem. A testcase will be very nice.


H.J.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Bug in dynamic linker
  2000-07-20  6:06 Mark Kettenis
  2000-07-20  9:04 ` H . J . Lu
@ 2000-07-20  9:23 ` Ulrich Drepper
  2000-07-20  9:51   ` H . J . Lu
  1 sibling, 1 reply; 18+ messages in thread
From: Ulrich Drepper @ 2000-07-20  9:23 UTC (permalink / raw)
  To: Mark Kettenis; +Cc: nickc, binutils, hjl

Mark Kettenis <kettenis@wins.uva.nl> writes:

> IMHO, the *correct* solution is implementing what the Solaris linker
> does:

I agree with Mark.  The proposed change is creating much more severe
problems than it's solving.

-- 
---------------.                          ,-.   1325 Chesapeake Terrace
Ulrich Drepper  \    ,-------------------'   \  Sunnyvale, CA 94089 USA
Red Hat          `--' drepper at redhat.com   `------------------------

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Bug in dynamic linker
  2000-07-20  6:06 Mark Kettenis
@ 2000-07-20  9:04 ` H . J . Lu
  2000-07-20 10:11   ` Mark Kettenis
  2000-07-20  9:23 ` Ulrich Drepper
  1 sibling, 1 reply; 18+ messages in thread
From: H . J . Lu @ 2000-07-20  9:04 UTC (permalink / raw)
  To: Mark Kettenis; +Cc: nickc, binutils

On Thu, Jul 20, 2000 at 03:06:29PM +0200, Mark Kettenis wrote:
> 
> IMHO, this patch needs some more discussion.  This isn't a simple
> bugfix.  It changes the way the linker behaves from the user
> standpoint considerably, since it will now silently add DT_NEEDED
> entries for libraries that are not explicitly mentioned on the
> command-line.  I also wonder if this patch could change the order of
> the DT_NEEDED entries, e.g. can a DT_NEEDED generated by HJ's patch
> come before a DT_NEEDED for a library mentioned on the command line?
> 
> Suppose I have an implementation of libfoo.so.1 that depends on
> libbar.so.  I know link a program with libfoo.so.1.  Before HJ's patch
> it would only get a DT_NEEDED entry for libfoo.so.1.  Now it will also
> get one for libbar.so.

Are you just guessing or do you have a testcase? If you have a
testcase, please send it to me. I have verified your case won't
happen unless your program uses libbar.so. Try it yourself. If ld
adds libbar.so to DT_NEEDED, it is a bug and you should report
it to me.

> 
> Now suppose that libfoo.so.1 is reimplemented such that it doesn't
> depend on libbar.so.1, or even worse, depends on libbar.so.2 instead.
> It is very likely that the program mentioned above won't work anymore
> (either because libbar.so.1 is no longer present, or because there is
> a conflict between libbar.so.1 and libbar.so.2).  Even if the program
> itself doesn't use any symbols from libbar.so.1.
> 
> The current situation has its problems too (the "Bug in dynamic
> linker" from the subject line[1]).  If your program does reference a
> symbol from libbar.so.1, the link will succeed, but the dependency
> will not be recorded as a DT_NEEDED (but version dependecies will be
> recorded).  This can obvously result in obscure problems if the
> implementation of libfoo.so.1 is changed as described above.
> 
> IMHO, the *correct* solution is implementing what the Solaris linker
> does: refusing to link if a symbol in the program cannot be resolved
> in one of the libraries mentioned on the command line (printing a
> message if it can be found in one of those libraries dependencies to
> help the user).
> 
> If the Solaris behaviour was implemented as the default behaviour, and

The Solaris behavior won't some runtime symbol version mismatch. We
do.

> it has been verified that the library ordering issue doesn't occur, I
> wouldn't have any objections against this patch.  However, right now
> I'm not sure if it's a really good idea :-(.
> 

Send me a testase if you still believe you are right.


H.J.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Bug in dynamic linker
@ 2000-07-20  6:06 Mark Kettenis
  2000-07-20  9:04 ` H . J . Lu
  2000-07-20  9:23 ` Ulrich Drepper
  0 siblings, 2 replies; 18+ messages in thread
From: Mark Kettenis @ 2000-07-20  6:06 UTC (permalink / raw)
  To: nickc; +Cc: binutils, hjl

   Hi H.J.

   : 2000-07-18  H.J. Lu  <hjl@gnu.org>
   : 
   :       * bfd-in.h (bfd_elf_set_dt_needed_soname): New.
   :       * bfd-in2.h: Rebuild.
   : 
   :       * elf-bfd.h (elf_obj_tdata): Add dt_soname.
   :       (elf_dt_soname): New.
   : 
   :       * elf.c (bfd_elf_set_dt_needed_soname): New.
   : 
   :       * elflink.h (elf_link_add_object_symbols): Add the DT_NEEDED
   :       entry if the shared object loaded by DT_NEEDED is used to
   :       resolve the reference in a regular object.

   : 2000-07-18  H.J. Lu  <hjl@gnu.org>
   : 
   :       * emultempl/elf32.em (gld${EMULATION_NAME}_try_needed): Call
   :       bfd_elf_set_dt_needed_soname ().

   Approved.

IMHO, this patch needs some more discussion.  This isn't a simple
bugfix.  It changes the way the linker behaves from the user
standpoint considerably, since it will now silently add DT_NEEDED
entries for libraries that are not explicitly mentioned on the
command-line.  I also wonder if this patch could change the order of
the DT_NEEDED entries, e.g. can a DT_NEEDED generated by HJ's patch
come before a DT_NEEDED for a library mentioned on the command line?

Suppose I have an implementation of libfoo.so.1 that depends on
libbar.so.  I know link a program with libfoo.so.1.  Before HJ's patch
it would only get a DT_NEEDED entry for libfoo.so.1.  Now it will also
get one for libbar.so.

Now suppose that libfoo.so.1 is reimplemented such that it doesn't
depend on libbar.so.1, or even worse, depends on libbar.so.2 instead.
It is very likely that the program mentioned above won't work anymore
(either because libbar.so.1 is no longer present, or because there is
a conflict between libbar.so.1 and libbar.so.2).  Even if the program
itself doesn't use any symbols from libbar.so.1.

The current situation has its problems too (the "Bug in dynamic
linker" from the subject line[1]).  If your program does reference a
symbol from libbar.so.1, the link will succeed, but the dependency
will not be recorded as a DT_NEEDED (but version dependecies will be
recorded).  This can obvously result in obscure problems if the
implementation of libfoo.so.1 is changed as described above.

IMHO, the *correct* solution is implementing what the Solaris linker
does: refusing to link if a symbol in the program cannot be resolved
in one of the libraries mentioned on the command line (printing a
message if it can be found in one of those libraries dependencies to
help the user).

If the Solaris behaviour was implemented as the default behaviour, and
it has been verified that the library ordering issue doesn't occur, I
wouldn't have any objections against this patch.  However, right now
I'm not sure if it's a really good idea :-(.

Mark

[1] It isn't really a bug in the dynamic linker, but more a
case of the dynamic linker not spitting out a more appropriate error
message telling the user that it couldn't find the right version
information.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Bug in dynamic linker
  2000-07-17  7:12 ` Peter A Barros
@ 2000-07-18 15:24   ` H . J . Lu
  0 siblings, 0 replies; 18+ messages in thread
From: H . J . Lu @ 2000-07-18 15:24 UTC (permalink / raw)
  To: Peter A Barros; +Cc: binutils

On Mon, Jul 17, 2000 at 10:12:10AM -0400, Peter A Barros wrote:
> 
> 
> 
>  Hi, I wrote a couple of days ago about an error message I was getting,
>  concerinng the dynamic linker.  This website probably explains the problem
>  better than I can:
>  http://x40.deja.com/getdoc.xp?AN=545891503&CONTEXT=958448712.1788280849&hitnum=29
>  
>  For my part, I don't really understand the problem.
>  If someone could explain a solution to be i would be very appreciative.
>  
> 

Here is a patch for the DT_NEEDED handling. At present, we don't add
files from DT_NEEDED to the DT_NEEDED list in the resulting binary.
That causes the problem if the resulting binary references the symbols
in files from DT_NEEDED and they are not passed to the linker at the
comand line. This patch tries to add those files to the DT_NEEDED list
if they are used by the regular files during the link. Any comments?



H.J.
---
2000-07-18  H.J. Lu  <hjl@gnu.org>

	* bfd-in.h (bfd_elf_set_dt_needed_soname): New.
	* bfd-in2.h: Rebuild.

	* elf-bfd.h (elf_obj_tdata): Add dt_soname.
	(elf_dt_soname): New.

	* elf.c (bfd_elf_set_dt_needed_soname): New.

	* elflink.h (elf_link_add_object_symbols): Add the DT_NEEDED
	entry if the shared object loaded by DT_NEEDED is used to
	resolve the reference in a regular object.

Index: bfd/bfd-in.h
===================================================================
RCS file: /work/cvs/gnu/binutils/bfd/bfd-in.h,v
retrieving revision 1.11
diff -u -p -r1.11 bfd-in.h
--- bfd/bfd-in.h	2000/07/13 16:00:33	1.11
+++ bfd/bfd-in.h	2000/07/18 19:32:33
@@ -627,6 +627,7 @@ extern boolean bfd_elf64_size_dynamic_se
 	   const char * const *, struct bfd_link_info *, struct sec **,
 	   struct bfd_elf_version_tree *));
 extern void bfd_elf_set_dt_needed_name PARAMS ((bfd *, const char *));
+extern void bfd_elf_set_dt_needed_soname PARAMS ((bfd *, const char *));
 extern const char *bfd_elf_get_dt_soname PARAMS ((bfd *));
 
 /* Return an upper bound on the number of bytes required to store a
Index: bfd/bfd-in2.h
===================================================================
RCS file: /work/cvs/gnu/binutils/bfd/bfd-in2.h,v
retrieving revision 1.35
diff -u -p -r1.35 bfd-in2.h
--- bfd/bfd-in2.h	2000/07/13 16:00:33	1.35
+++ bfd/bfd-in2.h	2000/07/18 19:34:06
@@ -627,6 +627,7 @@ extern boolean bfd_elf64_size_dynamic_se
 	   const char * const *, struct bfd_link_info *, struct sec **,
 	   struct bfd_elf_version_tree *));
 extern void bfd_elf_set_dt_needed_name PARAMS ((bfd *, const char *));
+extern void bfd_elf_set_dt_needed_soname PARAMS ((bfd *, const char *));
 extern const char *bfd_elf_get_dt_soname PARAMS ((bfd *));
 
 /* Return an upper bound on the number of bytes required to store a
Index: bfd/elf-bfd.h
===================================================================
RCS file: /work/cvs/gnu/binutils/bfd/elf-bfd.h,v
retrieving revision 1.1.1.15
diff -u -p -r1.1.1.15 elf-bfd.h
--- bfd/elf-bfd.h	2000/07/09 23:37:28	1.1.1.15
+++ bfd/elf-bfd.h	2000/07/18 21:13:49
@@ -838,6 +838,14 @@ struct elf_obj_tdata
      one.  */
   const char *dt_name;
 
+  /* When a reference in a regular object is resolved by a shared
+     object is loaded into via the DT_NEEDED entries by the linker
+     ELF emulation code, we need to add the shared object to the
+     DT_NEEDED list of the resulting binary to indicate the dependency
+     as if the -l option is passed to the linker. This field holds the
+     name of the loaded shared object. */
+  const char *dt_soname;
+
   /* Irix 5 often screws up the symbol table, sorting local symbols
      after global symbols.  This flag is set if the symbol table in
      this BFD appears to be screwed up.  If it is, we ignore the
@@ -915,6 +923,7 @@ struct elf_obj_tdata
 #define elf_local_got_offsets(bfd) (elf_tdata(bfd) -> local_got.offsets)
 #define elf_local_ptr_offsets(bfd) (elf_tdata(bfd) -> linker_section_pointers)
 #define elf_dt_name(bfd)	(elf_tdata(bfd) -> dt_name)
+#define elf_dt_soname(bfd)	(elf_tdata(bfd) -> dt_soname)
 #define elf_bad_symtab(bfd)	(elf_tdata(bfd) -> bad_symtab)
 #define elf_flags_init(bfd)	(elf_tdata(bfd) -> flags_init)
 #define elf_linker_section(bfd,n) (elf_tdata(bfd) -> linker_section[(int)n])
Index: bfd/elf.c
===================================================================
RCS file: /work/cvs/gnu/binutils/bfd/elf.c,v
retrieving revision 1.23
diff -u -p -r1.23 elf.c
--- bfd/elf.c	2000/07/13 16:00:33	1.23
+++ bfd/elf.c	2000/07/18 20:26:45
@@ -1023,6 +1023,16 @@ bfd_elf_set_dt_needed_name (abfd, name)
     elf_dt_name (abfd) = name;
 }
 
+void
+bfd_elf_set_dt_needed_soname (abfd, name)
+     bfd *abfd;
+     const char *name;
+{
+  if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
+      && bfd_get_format (abfd) == bfd_object)
+    elf_dt_soname (abfd) = name;
+}
+
 /* Get the list of DT_NEEDED entries for a link.  This is a hook for
    the linker ELF emulation code.  */
 
Index: bfd/elflink.h
===================================================================
RCS file: /work/cvs/gnu/binutils/bfd/elflink.h,v
retrieving revision 1.33
diff -u -p -r1.33 elflink.h
--- bfd/elflink.h	2000/06/20 17:47:42	1.33
+++ bfd/elflink.h	2000/07/18 21:57:20
@@ -890,6 +890,7 @@ elf_link_add_object_symbols (abfd, info)
   Elf_External_Sym *esym;
   Elf_External_Sym *esymend;
   struct elf_backend_data *bed;
+  boolean dt_needed;
 
   bed = get_elf_backend_data (abfd);
   add_symbol_hook = bed->elf_add_symbol_hook;
@@ -1049,6 +1050,8 @@ elf_link_add_object_symbols (abfd, info)
     goto error_return;
   elf_sym_hashes (abfd) = sym_hash;
 
+  dt_needed = false;
+
   if (! dynamic)
     {
       /* If we are creating a shared library, create all the dynamic
@@ -1085,7 +1088,12 @@ elf_link_add_object_symbols (abfd, info)
 	{
 	  name = elf_dt_name (abfd);
 	  if (*name == '\0')
-	    add_needed = false;
+	    {
+	      if (elf_dt_soname (abfd) != NULL)
+	        dt_needed = true;
+
+	      add_needed = false;
+	    }
 	}
       s = bfd_get_section_by_name (abfd, ".dynamic");
       if (s != NULL)
@@ -1863,6 +1871,53 @@ elf_link_add_object_symbols (abfd, info)
 		(*bed->elf_backend_hide_symbol) (info, h);
 		break;
 	      }
+
+	  if (dt_needed && definition
+	      && (h->elf_link_hash_flags
+		  & ELF_LINK_HASH_REF_REGULAR) != 0)
+	    {
+	      bfd_size_type oldsize;
+	      bfd_size_type strindex;
+
+	      /* The symbol from a DT_NEEDED object is referenced from
+	         the regular object to create a dynamic executable. We
+		 have to make sure there is a DT_NEEDED entry for it. */
+
+	      dt_needed = false;
+	      oldsize = _bfd_stringtab_size (elf_hash_table (info)->dynstr);
+	      strindex = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
+	      				     elf_dt_soname (abfd),
+					     true, false);
+	      if (strindex == (bfd_size_type) -1)
+		goto error_return;
+
+	      if (oldsize
+		  == _bfd_stringtab_size (elf_hash_table (info)->dynstr))
+		{
+		  asection *sdyn;
+		  Elf_External_Dyn *dyncon, *dynconend;
+
+		  sdyn = bfd_get_section_by_name (elf_hash_table (info)->dynobj,
+						  ".dynamic");
+		  BFD_ASSERT (sdyn != NULL);
+
+		  dyncon = (Elf_External_Dyn *) sdyn->contents;
+		  dynconend = (Elf_External_Dyn *) (sdyn->contents +
+						    sdyn->_raw_size);
+		  for (; dyncon < dynconend; dyncon++)
+		    {
+		      Elf_Internal_Dyn dyn;
+
+		      elf_swap_dyn_in (elf_hash_table (info)->dynobj,
+				       dyncon, &dyn);
+		      BFD_ASSERT (dyn.d_tag != DT_NEEDED ||
+				  dyn.d_un.d_val != strindex);
+		    }
+		}
+
+	      if (! elf_add_dynamic_entry (info, DT_NEEDED, strindex))
+		goto error_return;
+	    }
 	}
     }
 
 
2000-07-18  H.J. Lu  <hjl@gnu.org>

	* emultempl/elf32.em (gld${EMULATION_NAME}_try_needed): Call
	bfd_elf_set_dt_needed_soname ().

Index: ld/emultempl/elf32.em
===================================================================
RCS file: /work/cvs/gnu/binutils/ld/emultempl/elf32.em,v
retrieving revision 1.17
diff -u -p -r1.17 elf32.em
--- ld/emultempl/elf32.em	2000/07/13 16:00:36	1.17
+++ ld/emultempl/elf32.em	2000/07/18 21:13:41
@@ -532,6 +532,18 @@ cat >>e${EMULATION_NAME}.c <<EOF
      DT_NEEDED entry for this file.  */
   bfd_elf_set_dt_needed_name (abfd, "");
 
+  /* First strip off everything before the last '/'.  */
+  name = strrchr (abfd->filename, '/');
+  if (name)
+    name++;
+  else
+    name = abfd->filename;
+
+  /* Tell the ELF backend that the output file needs a DT_NEEDED
+     entry for this file if it is used to resolve the reference in
+     a regular object.  */
+  bfd_elf_set_dt_needed_soname (abfd, name);
+
   /* Add this file into the symbol table.  */
   if (! bfd_link_add_symbols (abfd, &link_info))
     einfo ("%F%B: could not read symbols: %E\n", abfd);

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Bug in dynamic linker
       [not found] <Pine.GS4.4.10.10007171002550.7771-100000@express.larc.nasa.gov>
@ 2000-07-17  7:12 ` Peter A Barros
  2000-07-18 15:24   ` H . J . Lu
  0 siblings, 1 reply; 18+ messages in thread
From: Peter A Barros @ 2000-07-17  7:12 UTC (permalink / raw)
  To: binutils

 Hi, I wrote a couple of days ago about an error message I was getting,
 concerinng the dynamic linker.  This website probably explains the problem
 better than I can:
 http://x40.deja.com/getdoc.xp?AN=545891503&CONTEXT=958448712.1788280849&hitnum=29
 
 For my part, I don't really understand the problem.
 If someone could explain a solution to be i would be very appreciative.
 
 Thanks
 

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: bug in dynamic linker
  2000-07-14 13:35 ` bug " Peter A Barros
@ 2000-07-14 23:27   ` Alan Modra
  0 siblings, 0 replies; 18+ messages in thread
From: Alan Modra @ 2000-07-14 23:27 UTC (permalink / raw)
  To: Peter A Barros; +Cc: binutils

On Fri, 14 Jul 2000, Peter A Barros wrote:

> BUG IN DYNAMIC LINKER ld.so: dl-version.c: 210: _dl_check_map_versions:
> Assertion 'needed != ((void *)0)' failed!

Try re-installing glibc.

-- 
Linuxcare.  Support for the Revolution.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* bug in dynamic linker
       [not found] <963602772.24226.ezmlm@sources.redhat.com>
@ 2000-07-14 13:35 ` Peter A Barros
  2000-07-14 23:27   ` Alan Modra
  0 siblings, 1 reply; 18+ messages in thread
From: Peter A Barros @ 2000-07-14 13:35 UTC (permalink / raw)
  To: binutils

I have been getting this error message when i try to do an ldd on certain
files.  I upgraded from binutils 2.95 to 2.10 hoping it would solve the
problem, but it did not. Here's what it looks like:

BUG IN DYNAMIC LINKER ld.so: dl-version.c: 210: _dl_check_map_versions:
Assertion 'needed != ((void *)0)' failed!

I recently installed RedHat 6.2, XFree 4.0.1, on a i686 pentium II w 400
MHz

I realize there's already been alot of discussion about this particular
error, but i swear I could not find the *solution* to it.
Its probably out there, but I just can't find it.

If someone would be so kind as to spell it out for me, I would be very
grateful

Thanks a bunch

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2000-07-27 17:49 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2000-07-19 17:52 Bug in dynamic linker Nick Clifton
  -- strict thread matches above, loose matches on Subject: below --
2000-07-27 16:56 Nick Clifton
2000-07-27 17:49 ` H . J . Lu
2000-07-20  6:06 Mark Kettenis
2000-07-20  9:04 ` H . J . Lu
2000-07-20 10:11   ` Mark Kettenis
2000-07-20 10:16     ` H . J . Lu
2000-07-20 10:56       ` Mark Kettenis
2000-07-20 11:04         ` H . J . Lu
2000-07-20 15:23           ` H . J . Lu
2000-07-20  9:23 ` Ulrich Drepper
2000-07-20  9:51   ` H . J . Lu
2000-07-20  9:56     ` Ulrich Drepper
2000-07-20 10:02       ` H . J . Lu
     [not found] <Pine.GS4.4.10.10007171002550.7771-100000@express.larc.nasa.gov>
2000-07-17  7:12 ` Peter A Barros
2000-07-18 15:24   ` H . J . Lu
     [not found] <963602772.24226.ezmlm@sources.redhat.com>
2000-07-14 13:35 ` bug " Peter A Barros
2000-07-14 23:27   ` Alan Modra

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).