Bug in elf_i386_adjust_dynamic_symbol ?

Martin Schwidefsky schwidefsky@de.ibm.com
Mon Jan 28 11:44:00 GMT 2002


Hi,
I think I have found a bug in elf_i386_adjust_dynamic_symbol. Since I
use the i386 bfd as a blue print for s390 and s390x the same bug is
present for these two architectures. The problem hit us on s390x in
the upgrade process from glibc 2.2.4 to 2.2.5. After we identified
the cause I created a small test case that shows the effect on an
intel as well (the glibc upgrade problem does not show up on i386).

Here we go:

weakcaller.c:
--- cut here ---
#include <stdio.h>
#include <dlfcn.h>

extern void weak_function(void) __attribute__((weak));

int main(void)
{
  if (weak_function != NULL)
    weak_function();
  else
    printf("weak_function is NULL\n");
  return 0;
}
--- cut here ---

weakfunc.c:
--- cut here ---
#include <stdio.h>

void weak_function(void)
{
  printf("weak_function was called\n");
}
--- cut here ---

To see the effect you'll have to do the following:
# gcc -o weakcaller weakcaller.c -O2 -fpic -ldl
# gcc -o weakfunc.so weakfunc.c -O2 -fpic -shared
# ./weakcaller
weak_function_is NULL
# LD_PRELOAD=./weakfunc.so ./weakcaller
zsh: segmentation fault  LD_PRELOAD=./weakfunc.so ./weakcaller

This happens on my Intel system with binutils-2.11.92.0.12.3 and
gcc 2.95.4. The important piece of code from main() is translated
by gcc as follows:

     call .L21
.L21:
     popl %ebx
     addl $_GLOBAL_OFFSET_TABLE_+[.-.L21],%ebx
     cmpl $0,weak_function@GOT(%ebx)
     je .L18
     call weak_function@PLT
     jmp .L19

The compare is done using the GOT and the call is done using a PLT. Fine.
But after the final link is done it looks like this:

 8048467:       e8 00 00 00 00          call   804846c <main+0xc>
 804846c:       5b                      pop    %ebx
 804846d:       81 c3 8c 11 00 00       add    $0x118c,%ebx
 8048473:       83 bb 1c 00 00 00 00    cmpl   $0x0,0x1c(%ebx)
 804847a:       74 07                   je     8048483 <main+0x23>
 804847c:       e8 7f 7b fb f7          call   0 <_init-0x8048308>
 8048481:       eb 0f                   jmp    8048492 <main+0x32>

The call to the PLT has been replaced by a call to 0!

I fixed this with the following patch:

--- elf32-i386.c.orig    Fri Nov 16 22:05:51 2001
+++ elf32-i386.c    Mon Jan 28 18:52:18 2002
@@ -1114,7 +1114,9 @@
       if (h->plt.refcount <= 0
       || (! info->shared
           && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0
-          && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) == 0))
+          && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) == 0
+          && h->root.type != bfd_link_hash_undefweak
+          && h->root.type != bfd_link_hash_undefined))
     {
       /* This case can occur if we saw a PLT32 reloc in an input
          file, but the symbol was never referred to by a dynamic

Big question now is: does this sound reasonable ?

blue skies,
   Martin

Linux/390 Design & Development, IBM Deutschland Entwicklung GmbH
Schönaicherstr. 220, D-71032 Böblingen, Telefon: 49 - (0)7031 - 16-2247
E-Mail: schwidefsky@de.ibm.com




More information about the Binutils mailing list