bfd/
authorH.J. Lu <hjl.tools@gmail.com>
Wed, 12 Jul 2006 15:45:33 +0000 (15:45 +0000)
committerH.J. Lu <hjl.tools@gmail.com>
Wed, 12 Jul 2006 15:45:33 +0000 (15:45 +0000)
2006-07-12  H.J. Lu  <hongjiu.lu@intel.com>

PR ld/2884
* elflink.c (_bfd_elf_merge_symbol): Copy the symbol info from
the old versioned dynamic definition to the new one with
non-default visibility.  Hide the symbol if it is hidden or
internal.

ld/testsuite/

2006-07-12  H.J. Lu  <hongjiu.lu@intel.com>

PR ld/2884
* ld-elf/begin.c: New file.
* ld-elf/end.c: Likewise.
* ld-elf/endhidden.c: Likewise.
* ld-elf/endprotected.c: Likewise.
* ld-elf/foo.c: Likewise.
* ld-elf/foo.map: Likewise.
* ld-elf/hidden.out: Likewise.
* ld-elf/main.c: Likewise.
* ld-elf/normal.out: Likewise.
* ld-elf/shared.exp: Likewise.

* lib/ld-lib.exp (run_cc_link_tests): New.

14 files changed:
bfd/ChangeLog
bfd/elflink.c
ld/testsuite/ChangeLog
ld/testsuite/ld-elf/begin.c [new file with mode: 0644]
ld/testsuite/ld-elf/end.c [new file with mode: 0644]
ld/testsuite/ld-elf/endhidden.c [new file with mode: 0644]
ld/testsuite/ld-elf/endprotected.c [new file with mode: 0644]
ld/testsuite/ld-elf/foo.c [new file with mode: 0644]
ld/testsuite/ld-elf/foo.map [new file with mode: 0644]
ld/testsuite/ld-elf/hidden.out [new file with mode: 0644]
ld/testsuite/ld-elf/main.c [new file with mode: 0644]
ld/testsuite/ld-elf/normal.out [new file with mode: 0644]
ld/testsuite/ld-elf/shared.exp [new file with mode: 0644]
ld/testsuite/lib/ld-lib.exp

index e9a5dba..411f704 100644 (file)
@@ -1,3 +1,11 @@
+2006-07-12  H.J. Lu  <hongjiu.lu@intel.com>
+
+       PR ld/2884
+       * elflink.c (_bfd_elf_merge_symbol): Copy the symbol info from
+       the old versioned dynamic definition to the new one with
+       non-default visibility.  Hide the symbol if it is hidden or
+       internal.
+
 2006-07-12  Matthew R. Dempsky  <mrd@alkemio.org>
 
        * cpu-m68k.c (bfd_m68k_compatible): Handle CPU32.
index 9d65b5f..84d9d1f 100644 (file)
@@ -1025,7 +1025,41 @@ _bfd_elf_merge_symbol (bfd *abfd,
         relocatable file and the old definition comes from a dynamic
         object, we remove the old definition.  */
       if ((*sym_hash)->root.type == bfd_link_hash_indirect)
-       h = *sym_hash;
+       {
+         /* Handle the case where the old dynamic definition is
+            default versioned.  We need to copy the symbol info from
+            the symbol with default version to the normal one if it
+            was referenced before.  */
+         if (h->ref_regular)
+           {
+             const struct elf_backend_data *bed
+               = get_elf_backend_data (abfd);
+             struct elf_link_hash_entry *vh = *sym_hash;
+             vh->root.type = h->root.type;
+             h->root.type = bfd_link_hash_indirect;
+             (*bed->elf_backend_copy_indirect_symbol) (info, vh, h);
+             /* Protected symbols will override the dynamic definition
+                with default version.  */
+             if (ELF_ST_VISIBILITY (sym->st_other) == STV_PROTECTED)
+               {
+                 h->root.u.i.link = (struct bfd_link_hash_entry *) vh;
+                 vh->dynamic_def = 1;
+                 vh->ref_dynamic = 1;
+               }
+             else
+               {
+                 h->root.type = vh->root.type;
+                 vh->ref_dynamic = 0;
+                 /* We have to hide it here since it was made dynamic
+                    global with extra bits when the symbol info was
+                    copied from the old dynamic definition.  */
+                 (*bed->elf_backend_hide_symbol) (info, vh, TRUE);
+               }
+             h = vh;
+           }
+         else
+           h = *sym_hash;
+       }
 
       if ((h->root.u.undef.next || info->hash->undefs_tail == &h->root)
          && bfd_is_und_section (sec))
index 575da33..eb5535e 100644 (file)
@@ -1,3 +1,19 @@
+2006-07-12  H.J. Lu  <hongjiu.lu@intel.com>
+
+       PR ld/2884
+       * ld-elf/begin.c: New file.
+       * ld-elf/end.c: Likewise.
+       * ld-elf/endhidden.c: Likewise.
+       * ld-elf/endprotected.c: Likewise.
+       * ld-elf/foo.c: Likewise.
+       * ld-elf/foo.map: Likewise.
+       * ld-elf/hidden.out: Likewise.
+       * ld-elf/main.c: Likewise.
+       * ld-elf/normal.out: Likewise.
+       * ld-elf/shared.exp: Likewise.
+
+       * lib/ld-lib.exp (run_cc_link_tests): New.
+
 2006-07-12  Richard Sandiford  <richard@codesourcery.com>
 
        * ld-m68k/merge-ok-1c.d: New test.
diff --git a/ld/testsuite/ld-elf/begin.c b/ld/testsuite/ld-elf/begin.c
new file mode 100644 (file)
index 0000000..ccc47d4
--- /dev/null
@@ -0,0 +1,5 @@
+extern void foo (void);
+
+static void (*const init_array []) (void)
+  __attribute__ ((used, section (".init_array"), aligned (sizeof (void *))))
+  = { foo };
diff --git a/ld/testsuite/ld-elf/end.c b/ld/testsuite/ld-elf/end.c
new file mode 100644 (file)
index 0000000..f7b681a
--- /dev/null
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+void
+foo ()
+{
+  printf ("TEST1\n");
+}
diff --git a/ld/testsuite/ld-elf/endhidden.c b/ld/testsuite/ld-elf/endhidden.c
new file mode 100644 (file)
index 0000000..2cab97a
--- /dev/null
@@ -0,0 +1,8 @@
+#include <stdio.h>
+
+__attribute__ ((visibility ("hidden")))
+void
+foo ()
+{
+  printf ("TEST1\n");
+}
diff --git a/ld/testsuite/ld-elf/endprotected.c b/ld/testsuite/ld-elf/endprotected.c
new file mode 100644 (file)
index 0000000..b6b39ea
--- /dev/null
@@ -0,0 +1,8 @@
+#include <stdio.h>
+
+__attribute__ ((visibility ("protected")))
+void
+foo ()
+{
+  printf ("TEST1\n");
+}
diff --git a/ld/testsuite/ld-elf/foo.c b/ld/testsuite/ld-elf/foo.c
new file mode 100644 (file)
index 0000000..c84baee
--- /dev/null
@@ -0,0 +1,11 @@
+#include <stdio.h>
+
+void
+foo (void)
+{
+  printf ("TEST2\n");
+}
+
+static void (*const init_array []) (void)
+  __attribute__ ((used, section (".init_array"), aligned (sizeof (void *))))
+  = { foo };
diff --git a/ld/testsuite/ld-elf/foo.map b/ld/testsuite/ld-elf/foo.map
new file mode 100644 (file)
index 0000000..6b993de
--- /dev/null
@@ -0,0 +1,4 @@
+FOO {
+  global: foo;
+  local: *;
+};
diff --git a/ld/testsuite/ld-elf/hidden.out b/ld/testsuite/ld-elf/hidden.out
new file mode 100644 (file)
index 0000000..7ad7cbe
--- /dev/null
@@ -0,0 +1,3 @@
+TEST2
+TEST1
+MAIN
diff --git a/ld/testsuite/ld-elf/main.c b/ld/testsuite/ld-elf/main.c
new file mode 100644 (file)
index 0000000..24f9dcc
--- /dev/null
@@ -0,0 +1,8 @@
+#include <stdio.h>
+
+int
+main (void)
+{
+  printf ("MAIN\n");
+  return 0;
+}
diff --git a/ld/testsuite/ld-elf/normal.out b/ld/testsuite/ld-elf/normal.out
new file mode 100644 (file)
index 0000000..3b721f0
--- /dev/null
@@ -0,0 +1,3 @@
+TEST1
+TEST1
+MAIN
diff --git a/ld/testsuite/ld-elf/shared.exp b/ld/testsuite/ld-elf/shared.exp
new file mode 100644 (file)
index 0000000..9222358
--- /dev/null
@@ -0,0 +1,112 @@
+# Expect script for various ELF tests.
+#   Copyright 2006 Free Software Foundation, Inc.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+#
+
+# Exclude non-ELF targets.
+
+if ![is_elf_format] {
+    return
+}
+
+# The following tests require running the executable generated by ld.
+if ![isnative] {
+    return
+}
+
+# Check if compiler works
+if { [which $CC] == 0 } {
+    return
+}
+
+set build_tests {
+  {"Build libfoo.so"
+   "-shared" "-fPIC"
+   {foo.c} {} "libfoo.so"}
+  {"Build versioned libfoo.so"
+   "-shared -Wl,--version-script=foo.map" "-fPIC"
+   {foo.c} {} "libfoov.so" "-fPIC"}
+  {"Build libbar.so"
+   "-shared" "-fPIC"
+   {begin.c end.c} {} "libbar.so"}
+  {"Build hidden libbar.so"
+   "-shared" "-fPIC"
+   {begin.c endhidden.c} {} "libbarh.so"}
+  {"Build protected libbar.so"
+   "-shared" "-fPIC"
+   {begin.c endprotected.c} {} "libbarp.so"}
+  {"Build libbar.so with libfoo.so"
+   "-shared tmpdir/begin.o tmpdir/libfoo.so" "-fPIC"
+   {end.c} {} "libbarfoo.so"}
+  {"Build libar.so with versioned libfoo.so"
+   "-shared tmpdir/begin.o tmpdir/libfoov.so" "-fPIC"
+   {end.c} {} "libbarfoov.so"}
+  {"Build hidden libbar.so with libfoo.so"
+   "-shared tmpdir/begin.o tmpdir/libfoo.so" "-fPIC"
+   {endhidden.c} {} "libbarhfoo.so"}
+  {"Build hidden libar.so with versioned libfoo.so"
+   "-shared tmpdir/begin.o tmpdir/libfoov.so" "-fPIC"
+   {endhidden.c} {} "libbarhfoov.so"}
+  {"Build protected libbar.so with libfoo.so"
+   "-shared tmpdir/begin.o tmpdir/libfoo.so" "-fPIC"
+   {endprotected.c} {} "libbarpfoo.so"}
+  {"Build protected libbar.so with versioned libfoo.so"
+   "-shared tmpdir/begin.o tmpdir/libfoov.so" "-fPIC"
+   {endprotected.c} {} "libbarpfoov.so"}
+}
+
+set run_tests {
+    {"Run normal with libfoo.so"
+     "tmpdir/begin.o tmpdir/libfoo.so tmpdir/end.o" ""
+     {main.c} "normal" "normal.out"}
+    {"Run protected with libfoo.so"
+     "tmpdir/begin.o tmpdir/libfoo.so tmpdir/endprotected.o" ""
+     {main.c} "protected" "normal.out"}
+    {"Run hidden with libfoo.so"
+     "tmpdir/begin.o tmpdir/libfoo.so tmpdir/endhidden.o" ""
+     {main.c} "hidden" "hidden.out"}
+    {"Run normal with versioned libfoo.so"
+     "tmpdir/begin.o tmpdir/libfoov.so tmpdir/end.o" ""
+     {main.c} "normalv" "normal.out"}
+    {"Run protected with versioned libfoo.so"
+     "tmpdir/begin.o tmpdir/libfoov.so tmpdir/endprotected.o" ""
+     {main.c} "protected" "normal.out"}
+    {"Run hidden with versioned libfoo.so"
+     "tmpdir/begin.o tmpdir/libfoov.so tmpdir/endhidden.o" ""
+     {main.c} "hiddenv" "hidden.out"}
+    {"Run normal libbar.so with libfoo.so"
+     "tmpdir/libbarfoo.so tmpdir/libfoo.so" ""
+     {main.c} "normal" "normal.out"}
+    {"Run protected libbar.so with libfoo.so"
+     "tmpdir/libbarpfoo.so tmpdir/libfoo.so" ""
+     {main.c} "protected" "normal.out"}
+    {"Run hidden libbar.so with libfoo.so"
+     "tmpdir/libbarhfoo.so tmpdir/libfoo.so" ""
+     {main.c} "hidden" "hidden.out"}
+    {"Run normal libbar.so with versioned libfoo.so"
+     "tmpdir/libbarfoov.so tmpdir/libfoov.so" ""
+     {main.c} "normal" "normal.out"}
+    {"Run protected libbar.so with versioned libfoo.so"
+     "tmpdir/libbarpfoov.so tmpdir/libfoov.so" ""
+     {main.c} "protected" "normal.out"}
+    {"Run hidden libbar.so with versioned libfoo.so"
+     "tmpdir/libbarhfoov.so tmpdir/libfoov.so" ""
+     {main.c} "hidden" "hidden.out"}
+}
+
+run_cc_link_tests $build_tests
+# NetBSD ELF systems do not currently support the .*_array sections.
+run_ld_link_exec_tests [list "*-*-netbsdelf*"] $run_tests
index a0e734e..4b69428 100644 (file)
@@ -1341,3 +1341,123 @@ proc run_ld_link_exec_tests { targets_to_xfail ldtests } {
        }
     }
 }
+
+# List contains test-items with 3 items followed by 2 lists, one item and
+# one optional item:
+# 0:name 1:link options 2:compile options
+# 3:filenames of assembler files 4: action and options. 5: name of output file
+#
+# Actions:
+# objdump: Apply objdump options on result.  Compare with regex (last arg).
+# nm: Apply nm options on result.  Compare with regex (last arg).
+# readelf: Apply readelf options on result.  Compare with regex (last arg).
+#
+proc run_cc_link_tests { ldtests } {
+    global nm
+    global objdump
+    global READELF
+    global srcdir
+    global subdir
+    global env
+    global CC
+    global CFLAGS
+
+    foreach testitem $ldtests {
+       set testname [lindex $testitem 0]
+       set ldflags [lindex $testitem 1]
+       set cflags [lindex $testitem 2]
+       set src_files  [lindex $testitem 3]
+       set actions [lindex $testitem 4]
+       set binfile tmpdir/[lindex $testitem 5]
+       set objfiles {}
+       set is_unresolved 0
+       set failed 0
+
+       # Compile each file in the test.
+       foreach src_file $src_files {
+           set objfile "tmpdir/[file rootname $src_file].o"
+           lappend objfiles $objfile
+
+           # We ignore warnings since some compilers may generate
+           # incorrect section attributes and the assembler will warn
+           # them.
+           ld_compile "$CC -c $CFLAGS $cflags" $srcdir/$subdir/$src_file $objfile
+       }
+
+       # Clear error and warning counts.
+       reset_vars
+
+       if ![ld_simple_link $CC $binfile "-L$srcdir/$subdir $ldflags $objfiles"] {
+           fail $testname
+       } else {
+           set failed 0
+           foreach actionlist $actions {
+               set action [lindex $actionlist 0]
+               set progopts [lindex $actionlist 1]
+
+               # There are actions where we run regexp_diff on the
+               # output, and there are other actions (presumably).
+               # Handling of the former look the same.
+               set dump_prog ""
+               switch -- $action {
+                   objdump
+                       { set dump_prog $objdump }
+                   nm
+                       { set dump_prog $nm }
+                   readelf
+                       { set dump_prog $READELF }
+                   default
+                       {
+                           perror "Unrecognized action $action"
+                           set is_unresolved 1
+                           break
+                       }
+                   }
+
+               if { $dump_prog != "" } {
+                   set dumpfile [lindex $actionlist 2]
+                   set binary $dump_prog
+
+                   # Ensure consistent sorting of symbols
+                   if {[info exists env(LC_ALL)]} {
+                       set old_lc_all $env(LC_ALL)
+                   }
+                   set env(LC_ALL) "C"
+                   set cmd "$binary $progopts $binfile > dump.out"
+                   send_log "$cmd\n"
+                   catch "exec $cmd" comp_output
+                   if {[info exists old_lc_all]} {
+                       set env(LC_ALL) $old_lc_all
+                   } else {
+                       unset env(LC_ALL)
+                   }
+                   set comp_output [prune_warnings $comp_output]
+
+                   if ![string match "" $comp_output] then {
+                       send_log "$comp_output\n"
+                       set failed 1
+                       break
+                   }
+
+                   if { [regexp_diff "dump.out" "$srcdir/$subdir/$dumpfile"] } then {
+                       verbose "output is [file_contents "dump.out"]" 2
+                       set failed 1
+                       break
+                   }
+               }
+           }
+
+           if { $failed != 0 } {
+               fail $testname
+           } else { if { $is_unresolved == 0 } {
+               pass $testname
+           } }
+       }
+
+       # Catch action errors.
+       if { $is_unresolved != 0 } {
+           unresolved $testname
+           continue
+       }
+    }
+}