Properly handle common symbol and weak function
authorH.J. Lu <hjl.tools@gmail.com>
Wed, 19 Sep 2012 00:53:30 +0000 (00:53 +0000)
committerH.J. Lu <hjl.tools@gmail.com>
Wed, 19 Sep 2012 00:53:30 +0000 (00:53 +0000)
bfd/

PR ld/14591
* elf-bfd.h (_bfd_elf_merge_symbol): Add an argument to return
if the old symbol is weak.

* elf32-sh-symbian.c (sh_symbian_relocate_section): Update
_bfd_elf_merge_symbol call.

* elflink.c (_bfd_elf_merge_symbol): Add an argument to return
if the old symbol is weak.
(_bfd_elf_add_default_symbol): Update _bfd_elf_merge_symbol
call.
(elf_link_add_object_symbols): Don't update symbol type from a
weak definition.  Update symbol type from a common symbol when
overriding a weak symbol.

ld/testsuite/

PR ld/14591
* ld-elf/comm-data.exp (run_ld_link_tests): Add comm-data3a and
comm-data3b tests.

* ld-ifunc/ifunc.exp (run_ld_link_exec_tests): New.

* ld-elf/comm-data3.sd: New file.
* ld-elf/comm-data3a.s: Likewise.
* ld-elf/comm-data3b.s: Likewise.
* ld-ifunc/ifunc-17a-i386.d: Likewise.
* ld-ifunc/ifunc-17a-x86-64.d: Likewise.
* ld-ifunc/ifunc-17a.s: Likewise.
* ld-ifunc/ifunc-17b-i386.d: Likewise.
* ld-ifunc/ifunc-17b-x86-64.d: Likewise.
* ld-ifunc/ifunc-17b.s: Likewise.
* ld-ifunc/ifunc-common-1.out: Likewise.
* ld-ifunc/ifunc-common-1a.c: Likewise.
* ld-ifunc/ifunc-common-1b.c: Likewise.

19 files changed:
bfd/ChangeLog
bfd/elf-bfd.h
bfd/elf32-sh-symbian.c
bfd/elflink.c
ld/testsuite/ChangeLog
ld/testsuite/ld-elf/comm-data.exp
ld/testsuite/ld-elf/comm-data3.sd [new file with mode: 0644]
ld/testsuite/ld-elf/comm-data3a.s [new file with mode: 0644]
ld/testsuite/ld-elf/comm-data3b.s [new file with mode: 0644]
ld/testsuite/ld-ifunc/ifunc-17a-i386.d [new file with mode: 0644]
ld/testsuite/ld-ifunc/ifunc-17a-x86-64.d [new file with mode: 0644]
ld/testsuite/ld-ifunc/ifunc-17a.s [new file with mode: 0644]
ld/testsuite/ld-ifunc/ifunc-17b-i386.d [new file with mode: 0644]
ld/testsuite/ld-ifunc/ifunc-17b-x86-64.d [new file with mode: 0644]
ld/testsuite/ld-ifunc/ifunc-17b.s [new file with mode: 0644]
ld/testsuite/ld-ifunc/ifunc-common-1.out [new file with mode: 0644]
ld/testsuite/ld-ifunc/ifunc-common-1a.c [new file with mode: 0644]
ld/testsuite/ld-ifunc/ifunc-common-1b.c [new file with mode: 0644]
ld/testsuite/ld-ifunc/ifunc.exp

index 7a4334f51ed52249c09e5333059928eed7c1e76c..f38d4ccb4be764e2b76a0d2193903fd2afe056c9 100644 (file)
@@ -1,3 +1,20 @@
+2012-09-18  H.J. Lu  <hongjiu.lu@intel.com>
+
+       PR ld/14591
+       * elf-bfd.h (_bfd_elf_merge_symbol): Add an argument to return 
+       if the old symbol is weak.
+
+       * elf32-sh-symbian.c (sh_symbian_relocate_section): Update
+       _bfd_elf_merge_symbol call.
+
+       * elflink.c (_bfd_elf_merge_symbol): Add an argument to return
+       if the old symbol is weak.
+       (_bfd_elf_add_default_symbol): Update _bfd_elf_merge_symbol
+       call.
+       (elf_link_add_object_symbols): Don't update symbol type from a
+       weak definition.  Update symbol type from a common symbol when
+       overriding a weak symbol.
+
 2012-09-17  H.J. Lu  <hongjiu.lu@intel.com>
 
        * elf32-i386.c (elf_i386_convert_mov_to_lea): Ignore discarded
index 12250365a4b62070a0c19da7eb39a588d3f32cf3..3709af9f9c9674fc1e1b0acf2759e4ba58055828 100644 (file)
@@ -1970,7 +1970,7 @@ extern bfd_boolean _bfd_elf_maybe_strip_eh_frame_hdr
 
 extern bfd_boolean _bfd_elf_merge_symbol
   (bfd *, struct bfd_link_info *, const char *, Elf_Internal_Sym *,
-   asection **, bfd_vma *, unsigned int *,
+   asection **, bfd_vma *, bfd_boolean *, unsigned int *,
    struct elf_link_hash_entry **, bfd_boolean *,
    bfd_boolean *, bfd_boolean *, bfd_boolean *);
 
index 0882d52b9a4e1df3f17dd2bfea27e2941599437a..1f03dbc40e5d3c252707058c40f186780d4ff206 100644 (file)
@@ -497,7 +497,7 @@ sh_symbian_relocate_section (bfd *                  output_bfd,
              if (! _bfd_elf_merge_symbol (input_bfd, info,
                                           ptr->new_name, & new_sym,
                                           & psec, & new_value, NULL,
-                                          & new_hash, & skip,
+                                          NULL, & new_hash, & skip,
                                           & override, & type_change_ok,
                                           & size_change_ok))
                {
index 9446e7d2ead72507b49d0400aabd8f7caa65f67c..232c0b13c5aacfbd55074098634815f7a0385443 100644 (file)
@@ -941,6 +941,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
                       Elf_Internal_Sym *sym,
                       asection **psec,
                       bfd_vma *pvalue,
+                      bfd_boolean *pold_weak,
                       unsigned int *pold_alignment,
                       struct elf_link_hash_entry **sym_hash,
                       bfd_boolean *skip,
@@ -1043,6 +1044,8 @@ _bfd_elf_merge_symbol (bfd *abfd,
   newweak = bind == STB_WEAK;
   oldweak = (h->root.type == bfd_link_hash_defweak
             || h->root.type == bfd_link_hash_undefweak);
+  if (pold_weak)
+    *pold_weak = oldweak;
 
   /* In cases involving weak versioned symbols, we may wind up trying
      to merge a symbol with itself.  Catch that here, to avoid the
@@ -1665,7 +1668,7 @@ _bfd_elf_add_default_symbol (bfd *abfd,
   size_change_ok = FALSE;
   sec = *psec;
   if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &sec, value,
-                             NULL, &hi, &skip, &override,
+                             NULL, NULL, &hi, &skip, &override,
                              &type_change_ok, &size_change_ok))
     return FALSE;
 
@@ -1774,7 +1777,7 @@ nondefault:
   size_change_ok = FALSE;
   sec = *psec;
   if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &sec, value,
-                             NULL, &hi, &skip, &override,
+                             NULL, NULL, &hi, &skip, &override,
                              &type_change_ok, &size_change_ok))
     return FALSE;
 
@@ -3868,6 +3871,8 @@ error_free_dyn:
       bfd_boolean size_change_ok;
       bfd_boolean type_change_ok;
       bfd_boolean new_weakdef;
+      bfd_boolean new_weak;
+      bfd_boolean old_weak;
       bfd_boolean override;
       bfd_boolean common;
       unsigned int old_alignment;
@@ -4000,6 +4005,7 @@ error_free_dyn:
 
       size_change_ok = FALSE;
       type_change_ok = bed->type_change_ok;
+      old_weak = FALSE;
       old_alignment = 0;
       old_bfd = NULL;
       new_sec = sec;
@@ -4145,7 +4151,7 @@ error_free_dyn:
            }
 
          if (!_bfd_elf_merge_symbol (abfd, info, name, isym, &sec,
-                                     &value, &old_alignment,
+                                     &value, &old_weak, &old_alignment,
                                      sym_hash, &skip, &override,
                                      &type_change_ok, &size_change_ok))
            goto error_free_vers;
@@ -4207,10 +4213,11 @@ error_free_dyn:
       if (is_elf_hash_table (htab))
        h->unique_global = (flags & BSF_GNU_UNIQUE) != 0;
 
+      new_weak = (flags & BSF_WEAK) != 0;
       new_weakdef = FALSE;
       if (dynamic
          && definition
-         && (flags & BSF_WEAK) != 0
+         && new_weak
          && !bed->is_function_type (ELF_ST_TYPE (isym->st_info))
          && is_elf_hash_table (htab)
          && h->u.weakdef == NULL)
@@ -4339,7 +4346,9 @@ error_free_dyn:
            h->size = h->root.u.c.size;
 
          if (ELF_ST_TYPE (isym->st_info) != STT_NOTYPE
-             && (definition || h->type == STT_NOTYPE))
+             && ((definition && !new_weak)
+                 || (old_weak && h->root.type == bfd_link_hash_common)
+                 || h->type == STT_NOTYPE))
            {
              unsigned int type = ELF_ST_TYPE (isym->st_info);
 
index c969379bdbd3ca928fd82725f02b90efda1c3e1c..bca8bbb8efbe29a3169fc173f2662e89d4ab4812 100644 (file)
@@ -1,3 +1,24 @@
+2012-09-18  H.J. Lu  <hongjiu.lu@intel.com>
+
+       PR ld/14591
+       * ld-elf/comm-data.exp (run_ld_link_tests): Add comm-data3a and
+       comm-data3b tests.
+
+       * ld-ifunc/ifunc.exp (run_ld_link_exec_tests): New.
+
+       * ld-elf/comm-data3.sd: New file.
+       * ld-elf/comm-data3a.s: Likewise.
+       * ld-elf/comm-data3b.s: Likewise.
+       * ld-ifunc/ifunc-17a-i386.d: Likewise.
+       * ld-ifunc/ifunc-17a-x86-64.d: Likewise.
+       * ld-ifunc/ifunc-17a.s: Likewise.
+       * ld-ifunc/ifunc-17b-i386.d: Likewise.
+       * ld-ifunc/ifunc-17b-x86-64.d: Likewise.
+       * ld-ifunc/ifunc-17b.s: Likewise.
+       * ld-ifunc/ifunc-common-1.out: Likewise.
+       * ld-ifunc/ifunc-common-1a.c: Likewise.
+       * ld-ifunc/ifunc-common-1b.c: Likewise.
+
 2012-09-17  H.J. Lu  <hongjiu.lu@intel.com>
 
        * ld-elf/shared.exp (build_cxx_tests): Move out the commented out
index 2258afb5f4df68bd07b426f6b2d4c89f459caf3f..1c75f552160b0e8253f2a78ddd8d82aebab3fd93 100644 (file)
@@ -75,4 +75,24 @@ run_ld_link_tests [list \
        } \
        "comm-data" \
     ] \
+    [list \
+       "$testname 3a" \
+       "-static" \
+       "" \
+       { comm-data3a.s comm-data3b.s } \
+       { \
+           { readelf -s comm-data3.sd } \
+       } \
+       "comm-data3a" \
+    ] \
+    [list \
+       "$testname 3b" \
+       "-static" \
+       "" \
+       { comm-data3b.s comm-data3a.s } \
+       { \
+           { readelf -s comm-data3.sd } \
+       } \
+       "comm-data3b" \
+    ] \
 ]
diff --git a/ld/testsuite/ld-elf/comm-data3.sd b/ld/testsuite/ld-elf/comm-data3.sd
new file mode 100644 (file)
index 0000000..5a96ed7
--- /dev/null
@@ -0,0 +1,3 @@
+#...
+ +[0-9]+: +[0-9a-f]+ +4 +OBJECT +GLOBAL +DEFAULT +[1-9] foo
+#pass
diff --git a/ld/testsuite/ld-elf/comm-data3a.s b/ld/testsuite/ld-elf/comm-data3a.s
new file mode 100644 (file)
index 0000000..e0bde49
--- /dev/null
@@ -0,0 +1,11 @@
+       .globl main
+       .globl start
+       .globl _start
+       .globl __start
+       .text
+main:
+start:
+_start:
+__start:
+       .byte 0
+       .common foo,4,4
diff --git a/ld/testsuite/ld-elf/comm-data3b.s b/ld/testsuite/ld-elf/comm-data3b.s
new file mode 100644 (file)
index 0000000..837a099
--- /dev/null
@@ -0,0 +1,6 @@
+       .weak   foo
+       .type   foo,%function
+       .size   foo,1
+       .text
+foo:
+       .byte   1
diff --git a/ld/testsuite/ld-ifunc/ifunc-17a-i386.d b/ld/testsuite/ld-ifunc/ifunc-17a-i386.d
new file mode 100644 (file)
index 0000000..303b54e
--- /dev/null
@@ -0,0 +1,10 @@
+#source: ifunc-17a.s
+#source: ifunc-17b.s
+#ld: -static -m elf_i386
+#as: --32
+#readelf: -s --wide
+#target: x86_64-*-* i?86-*-*
+
+#...
+ +[0-9]+: +[0-9a-f]+ +4 +OBJECT +GLOBAL +DEFAULT +[1-9] foo
+#pass
diff --git a/ld/testsuite/ld-ifunc/ifunc-17a-x86-64.d b/ld/testsuite/ld-ifunc/ifunc-17a-x86-64.d
new file mode 100644 (file)
index 0000000..965ef63
--- /dev/null
@@ -0,0 +1,10 @@
+#source: ifunc-17a.s
+#source: ifunc-17b.s
+#ld: -static -m elf_x86_64
+#as: --64
+#readelf: -s --wide
+#target: x86_64-*-*
+
+#...
+ +[0-9]+: +[0-9a-f]+ +4 +OBJECT +GLOBAL +DEFAULT +[1-9] foo
+#pass
diff --git a/ld/testsuite/ld-ifunc/ifunc-17a.s b/ld/testsuite/ld-ifunc/ifunc-17a.s
new file mode 100644 (file)
index 0000000..e0bde49
--- /dev/null
@@ -0,0 +1,11 @@
+       .globl main
+       .globl start
+       .globl _start
+       .globl __start
+       .text
+main:
+start:
+_start:
+__start:
+       .byte 0
+       .common foo,4,4
diff --git a/ld/testsuite/ld-ifunc/ifunc-17b-i386.d b/ld/testsuite/ld-ifunc/ifunc-17b-i386.d
new file mode 100644 (file)
index 0000000..82ccac2
--- /dev/null
@@ -0,0 +1,10 @@
+#source: ifunc-17b.s
+#source: ifunc-17a.s
+#ld: -static -m elf_i386
+#as: --32
+#readelf: -s --wide
+#target: x86_64-*-* i?86-*-*
+
+#...
+ +[0-9]+: +[0-9a-f]+ +4 +OBJECT +GLOBAL +DEFAULT +[1-9] foo
+#pass
diff --git a/ld/testsuite/ld-ifunc/ifunc-17b-x86-64.d b/ld/testsuite/ld-ifunc/ifunc-17b-x86-64.d
new file mode 100644 (file)
index 0000000..7527eae
--- /dev/null
@@ -0,0 +1,10 @@
+#source: ifunc-17b.s
+#source: ifunc-17a.s
+#ld: -static -m elf_x86_64
+#as: --64
+#readelf: -s --wide
+#target: x86_64-*-*
+
+#...
+ +[0-9]+: +[0-9a-f]+ +4 +OBJECT +GLOBAL +DEFAULT +[1-9] foo
+#pass
diff --git a/ld/testsuite/ld-ifunc/ifunc-17b.s b/ld/testsuite/ld-ifunc/ifunc-17b.s
new file mode 100644 (file)
index 0000000..66abe04
--- /dev/null
@@ -0,0 +1,6 @@
+       .weak   foo
+       .type foo, %gnu_indirect_function
+       .size   foo,1
+       .text
+foo:
+       .byte   1
diff --git a/ld/testsuite/ld-ifunc/ifunc-common-1.out b/ld/testsuite/ld-ifunc/ifunc-common-1.out
new file mode 100644 (file)
index 0000000..31a3ce2
--- /dev/null
@@ -0,0 +1 @@
+PASSED: 0
diff --git a/ld/testsuite/ld-ifunc/ifunc-common-1a.c b/ld/testsuite/ld-ifunc/ifunc-common-1a.c
new file mode 100644 (file)
index 0000000..794ca45
--- /dev/null
@@ -0,0 +1,9 @@
+#include <stdio.h>
+
+int foo;
+int
+main ()
+{
+  printf ("PASSED: %d\n", foo);
+  return 0;
+}
diff --git a/ld/testsuite/ld-ifunc/ifunc-common-1b.c b/ld/testsuite/ld-ifunc/ifunc-common-1b.c
new file mode 100644 (file)
index 0000000..1235942
--- /dev/null
@@ -0,0 +1,12 @@
+void alt (void) { }
+
+void foo (void);
+void * foo_ifunc (void) __asm__ ("foo");
+__asm__(".type foo, %gnu_indirect_function");
+__asm__(".weak foo");
+
+void *
+foo_ifunc (void)
+{
+  return alt;
+}
index 3eef3a9e03afbc8c6ba60fb8ec966243f52f8aed..df913d89bdb6bcdf8989afded778dc34feef6ccc 100644 (file)
@@ -347,6 +347,27 @@ if { $verbose < 1 } {
     remote_file host delete "tmpdir/static_nonifunc_prog"
 }
 
+run_ld_link_exec_tests [] [list \
+    [list \
+       "Common symbol override ifunc test 1a" \
+       "-static" \
+       "" \
+       { ifunc-common-1a.c ifunc-common-1b.c } \
+       "ifunc-common-1a" \
+       "ifunc-common-1.out" \
+       "-g" \
+    ] \
+    [list \
+       "Common symbol override ifunc test 1b" \
+       "-static" \
+       "" \
+       { ifunc-common-1b.c ifunc-common-1a.c } \
+       "ifunc-common-1b" \
+       "ifunc-common-1.out" \
+       "-g" \
+    ] \
+]
+
 set test_list [lsort [glob -nocomplain $srcdir/$subdir/*.d]]
 foreach t $test_list {
     # We need to strip the ".d", but can leave the dirname.