This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: ld fix for STB_GNU_UNIQUE PR10549


On Sun, 2011-04-10 at 13:01 +0930, Alan Modra wrote:
> On Sat, Apr 09, 2011 at 05:24:41PM -0400, Mark Wielaard wrote: 
> > I did that deliberately thinking that, unlike the IFUNC case,
> > when a program links against something that uses UNIQUE
> > semantics it will need/depend on that. Do you think it should
> > only be done for symbols coming from non-dynamic objects
> > (making it identical to the IFUNC case)?
> 
> Yes, because as I said, a symbol in a shared library may not even be
> referenced by the executable or shared library being produced by the
> linker.  The output file may not even mark the shared library as
> DT_NEEDED.

Aha, I see what you mean. OK, I changed my patch to do it that way and
added some extra testcases for this scenario (fails with my previous
patch, succeeds with this one, no other test result changed).
If this variant is OK could someone please commit it for me?

> Ulrich's reply didn't exactly answer my question, but does point out
> another deficiency in ld.  We ought to only accept STB_GNU_UNIQUE in
> object files that are ELFOSABI_LINUX.

I didn't try to address this issue with this patch yet. I assume this
could be done in elf_link_add_object_symbols in some kind of strict mode
(assuming there is an ld strict mode).

Thanks,

Mark
>From 014ed1a47a200b6e1a062c6d21e9702be766d7e5 Mon Sep 17 00:00:00 2001
From: Mark Wielaard <mjw@redhat.com>
Date: Thu, 7 Apr 2011 23:28:29 +0200
Subject: [PATCH] ld unique support.

---
 bfd/ChangeLog                          |   15 ++
 bfd/elf-bfd.h                          |    6 +-
 bfd/elf.c                              |    4 +-
 bfd/elf32-arm.c                        |    5 +-
 bfd/elf32-i386.c                       |    5 +-
 bfd/elf32-ppc.c                        |    5 +-
 bfd/elf32-sparc.c                      |    5 +-
 bfd/elf64-ppc.c                        |    6 +-
 bfd/elf64-sparc.c                      |    5 +-
 bfd/elf64-x86-64.c                     |    5 +-
 ld/testsuite/ChangeLog                 |    9 +
 ld/testsuite/ld-unique/unique.exp      |  251 ++++++++++++++++++++++++++++++++
 ld/testsuite/ld-unique/unique.s        |    8 +
 ld/testsuite/ld-unique/unique_empty.s  |    4 +
 ld/testsuite/ld-unique/unique_shared.s |    3 +
 15 files changed, 318 insertions(+), 18 deletions(-)
 create mode 100644 ld/testsuite/ld-unique/unique.exp
 create mode 100644 ld/testsuite/ld-unique/unique.s
 create mode 100644 ld/testsuite/ld-unique/unique_empty.s
 create mode 100644 ld/testsuite/ld-unique/unique_shared.s

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 596612e..727d39f 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,18 @@
+2011-04-10  Mark Wielaard  <mjw@redhat.com>
+
+	PR 10549
+	* elf-bfd.h (has_ifunc_symbols): Renamed to has_gnu_symbols.
+	(has_gnu_symbols): Renamed from has_ifunc_symbols.
+	* bfd/elf.c (_bfd_elf_set_osabi): Use new has_gnu_symbols name.
+	* bfd/elf32-arm.c (elf32_arm_add_symbol_hook): Set has_gnu_symbols
+	also if STB_GNU_UNIQUE symbol binding was seen.
+	* bfd/elf32-i386.c (elf_i386_add_symbol_hook): Likewise.
+	* bfd/elf32-ppc.c (ppc_elf_add_symbol_hook): Likewise.
+	* bfd/elf32-sparc.c (elf32_sparc_add_symbol_hook): Likewise.
+	* bfd/elf64-ppc.c (ppc64_elf_add_symbol_hook): Likewise.
+	* bfd/elf64-sparc.c (elf64_sparc_add_symbol_hook): Likewise.
+	* bfd/elf64-x86-64.c (elf_x86_64_add_symbol_hook): Likewise.
+
 2011-04-09  H.J. Lu  <hongjiu.lu@intel.com>
 
 	* elf32-i386.c: Update copyright year.
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 21ec38f..844610d 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -1634,9 +1634,9 @@ struct elf_obj_tdata
   bfd_byte *build_id;
 
   /* True if the bfd contains symbols that have the STT_GNU_IFUNC
-     symbol type.  Used to set the osabi field in the ELF header
-     structure.  */
-  bfd_boolean has_ifunc_symbols;
+     symbol type or STB_GNU_UNIQUE binding.  Used to set the osabi
+     field in the ELF header structure.  */
+  bfd_boolean has_gnu_symbols;
 
   /* An identifier used to distinguish different target
      specific extensions to this structure.  */
diff --git a/bfd/elf.c b/bfd/elf.c
index f69abf2..0bb0c5a 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -9506,9 +9506,9 @@ _bfd_elf_set_osabi (bfd * abfd,
 
   /* To make things simpler for the loader on Linux systems we set the
      osabi field to ELFOSABI_LINUX if the binary contains symbols of
-     the STT_GNU_IFUNC type.  */
+     the STT_GNU_IFUNC type or STB_GNU_UNIQUE binding.  */
   if (i_ehdrp->e_ident[EI_OSABI] == ELFOSABI_NONE
-      && elf_tdata (abfd)->has_ifunc_symbols)
+      && elf_tdata (abfd)->has_gnu_symbols)
     i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_LINUX;
 }
 
diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c
index 6b69fd6..035d584 100644
--- a/bfd/elf32-arm.c
+++ b/bfd/elf32-arm.c
@@ -15230,8 +15230,9 @@ elf32_arm_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
 			   flagword *flagsp, asection **secp, bfd_vma *valp)
 {
   if ((abfd->flags & DYNAMIC) == 0
-      && ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
-    elf_tdata (info->output_bfd)->has_ifunc_symbols = TRUE;
+      && (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
+	  || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE))
+    elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
 
   if (elf32_arm_hash_table (info)->vxworks_p
       && !elf_vxworks_add_symbol_hook (abfd, info, sym, namep,
diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c
index 3d8e2df..1896881 100644
--- a/bfd/elf32-i386.c
+++ b/bfd/elf32-i386.c
@@ -4705,8 +4705,9 @@ elf_i386_add_symbol_hook (bfd * abfd,
 			  bfd_vma * valp ATTRIBUTE_UNUSED)
 {
   if ((abfd->flags & DYNAMIC) == 0
-      && ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
-    elf_tdata (info->output_bfd)->has_ifunc_symbols = TRUE;
+      && (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
+	  || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE))
+    elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
 
   return TRUE;
 }
diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c
index 9e097ad..c736375 100644
--- a/bfd/elf32-ppc.c
+++ b/bfd/elf32-ppc.c
@@ -3113,8 +3113,9 @@ ppc_elf_add_symbol_hook (bfd *abfd,
     }
 
   if ((abfd->flags & DYNAMIC) == 0
-      && ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
-    elf_tdata (info->output_bfd)->has_ifunc_symbols = TRUE;
+      && (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
+	  || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE))
+    elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
 
   return TRUE;
 }
diff --git a/bfd/elf32-sparc.c b/bfd/elf32-sparc.c
index 187d466..2d9deab 100644
--- a/bfd/elf32-sparc.c
+++ b/bfd/elf32-sparc.c
@@ -180,8 +180,9 @@ elf32_sparc_add_symbol_hook (bfd * abfd,
 			     bfd_vma * valp ATTRIBUTE_UNUSED)
 {
   if ((abfd->flags & DYNAMIC) == 0
-      && ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
-    elf_tdata (info->output_bfd)->has_ifunc_symbols = TRUE;
+      && (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
+	  || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE))
+    elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
   return TRUE;
 }
 
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index 4cbd941..eb07b1f 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -4569,10 +4569,14 @@ ppc64_elf_add_symbol_hook (bfd *ibfd,
 			   asection **sec,
 			   bfd_vma *value ATTRIBUTE_UNUSED)
 {
+  if ((ibfd->flags & DYNAMIC) == 0
+      && ELF_ST_BIND (isym->st_info) == STB_GNU_UNIQUE)
+    elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
+
   if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
     {
       if ((ibfd->flags & DYNAMIC) == 0)
-	elf_tdata (info->output_bfd)->has_ifunc_symbols = TRUE;
+	elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
     }
   else if (ELF_ST_TYPE (isym->st_info) == STT_FUNC)
     ;
diff --git a/bfd/elf64-sparc.c b/bfd/elf64-sparc.c
index 6bb2389..c4e97a7 100644
--- a/bfd/elf64-sparc.c
+++ b/bfd/elf64-sparc.c
@@ -426,8 +426,9 @@ elf64_sparc_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
   static const char *const stt_types[] = { "NOTYPE", "OBJECT", "FUNCTION" };
 
   if ((abfd->flags & DYNAMIC) == 0
-      && ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
-    elf_tdata (info->output_bfd)->has_ifunc_symbols = TRUE;
+      && (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
+	  || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE))
+    elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
 
   if (ELF_ST_TYPE (sym->st_info) == STT_REGISTER)
     {
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index 89a5ab0..84ee101 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -4457,8 +4457,9 @@ elf_x86_64_add_symbol_hook (bfd *abfd,
     }
 
   if ((abfd->flags & DYNAMIC) == 0
-      && ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
-    elf_tdata (info->output_bfd)->has_ifunc_symbols = TRUE;
+      && (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
+	  || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE))
+    elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
 
   return TRUE;
 }
diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog
index f6081e1..497e680 100644
--- a/ld/testsuite/ChangeLog
+++ b/ld/testsuite/ChangeLog
@@ -1,3 +1,12 @@
+2011-04-10  Mark Wielaard  <mjw@redhat.com>
+
+	PR 10549
+	* ld-unique: New directory.
+	* ld-unique/unique.exp: New file: Run the UNIQUE tests.
+	* ld-ifunc/unique.s: New test file.
+	* ld/testsuite/ld-unique/unique_empty.s: Likewise.
+	* ld/testsuite/ld-unique/unique_shared.s: Likewise.
+
 2011-04-08  H.J. Lu  <hongjiu.lu@intel.com>
 
 	PR ld/12654
diff --git a/ld/testsuite/ld-unique/unique.exp b/ld/testsuite/ld-unique/unique.exp
new file mode 100644
index 0000000..105b9a0
--- /dev/null
+++ b/ld/testsuite/ld-unique/unique.exp
@@ -0,0 +1,251 @@
+# Expect script for linker support of STB_GNU_UNIQUE symbols
+#
+#   Copyright 2009, 2010, 2011 Free Software Foundation, Inc.
+#   Contributed by Red Hat.
+#
+# This file is part of the GNU Binutils.
+#
+# This program 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 3 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.
+#
+# Written by Nick Clifton <nickc@redhat.com>
+# Adapted for unique checking by Mark J. Wielaard <mjw@redhat.com>
+
+
+# STB_GNU_UNIQUE support has only been implemented for the ix86, x86_64,
+# arm, powerpc, and sparc so far.
+if {!(([istarget "i?86-*-*"]
+       || [istarget "x86_64-*-*"]
+       || [istarget "arm-*-*"]
+       || [istarget "powerpc*-*-*"]
+       || [istarget "sparc*-*-*"])
+      && ([istarget "*-*-elf*"]
+	  || (([istarget "*-*-linux*"]
+	       || [istarget "*-*-gnu*"])
+	      && ![istarget "*-*-*aout*"]
+	      && ![istarget "*-*-*oldld*"]))) } {
+    verbose "UNIQUE tests not run - target does not support UNIQUE"
+    return
+}
+
+# We need a native system.  FIXME: Strictly speaking this
+# is not true, we just need to know how to create a fully
+# linked executable, including the C and Z libraries, using
+# the linker that is under test.
+if ![isnative] {
+    verbose "UNIQUE tests not run - not a native toolchain"
+    return
+}
+
+# We need a working compiler.  (Strictly speaking this is
+# not true, we could use target specific assembler files).
+if { [which $CC] == 0 } {
+    verbose "UNIQUE tests not run - no compiler available"
+    return
+}
+
+# A procedure to check the OS/ABI field in the ELF header of a binary file.
+proc check_osabi { binary_file expected_osabi } {
+    global READELF
+    global READELFFLAGS
+
+    catch "exec $READELF $READELFFLAGS --file-header $binary_file > readelf.out" got
+
+    if ![string match "" $got] then {
+	verbose "proc check_osabi: Readelf produced unexpected out processing $binary_file: $got"
+	return 0
+    }
+
+    if { ![regexp "\n\[ \]*OS/ABI:\[ \]*(.+)\n\[ \]*ABI" \
+	   [file_contents readelf.out] nil osabi] } {
+	verbose "proc check_osabi: Readelf failed to extract an ELF header from $binary_file"
+	return 0
+    }
+
+    if { $osabi == $expected_osabi } {
+	return 1
+    }
+
+    verbose "Expected OSABI: $expected_osabi, Obtained osabi: $osabi"
+
+    return 0
+}
+
+# A procedure to confirm that a file contains the UNIQUE symbol.
+# Returns -1 upon error, 0 if the symbol was not found and 1 if it was found.
+proc contains_unique_symbol { binary_file } {
+    global READELF
+    global READELFFLAGS
+
+    catch "exec $READELF $READELFFLAGS --symbols $binary_file > readelf.out" got
+
+    if ![string match "" $got] then {
+	verbose "proc contains_unique_symbol: Readelf produced unexpected out processing $binary_file: $got"
+	return -1
+    }
+
+    # Look for a line like this:
+    #    54: 0000000000400474     4 OBJECT  UNIQUE DEFAULT   13 a
+
+    if { ![regexp ".*\[ \]*OBJECT\[ \]+UNIQUE\[ \]+DEFAULT\[ \]+\[UND0-9\]+\[ \]+\[ab\]\n" [file_contents readelf.out]] } {
+	return 0
+    }
+
+    return 1
+}
+
+set fails 0
+
+# create object file containing unique symbol
+if ![ld_compile "$CC -c" "$srcdir/$subdir/unique.s" "tmpdir/unique.o"] {
+    fail "Could not create a unique object"
+    set fails [expr $fails + 1]
+}
+
+# create object file NOT containing unique symbol
+if ![ld_compile "$CC -c" "$srcdir/$subdir/unique_empty.s" "tmpdir/unique_empty.o"] {
+    fail "Could not create a non-unique object"
+    set fails [expr $fails + 1]
+}
+
+# create pic object file containing unique symbol
+if ![ld_compile "$CC -c -fPIC" "$srcdir/$subdir/unique_shared.s" "tmpdir/unique_shared.o"] {
+    fail "Could not create a pic unique object"
+    set fails [expr $fails + 1]
+}
+
+# create executable containing unique symbol
+if ![default_ld_link $ld "tmpdir/unique_prog" "tmpdir/unique.o"] {
+    fail "Could not link a unique executable"
+    set fails [expr $fails + 1]
+}
+
+# create shared library containing unique symbol
+if ![ld_simple_link $ld "tmpdir/libunique_shared.so" "-shared tmpdir/unique_shared.o"] {
+    fail "Could not create a shared library containing an unique symbol"
+    set fails [expr $fails + 1]
+}
+
+# create executable NOT containing unique symbol linked against library
+if ![default_ld_link $ld "tmpdir/unique_shared_prog" "-Ltmpdir tmpdir/unique_empty.o -Bdynamic -lunique_shared -rpath ./tmpdir"] {
+    fail "Could not link a dynamic executable"
+    set fails [expr $fails + 1]
+}
+
+if { $fails != 0 } {
+    return
+}
+
+# check the object file
+if {! [check_osabi tmpdir/unique.o {UNIX - Linux}]} {
+    fail "Object containing unique does not have an OS/ABI field of LINUX"
+    set fails [expr $fails + 1]
+}
+
+if {[contains_unique_symbol tmpdir/unique.o] != 1} {
+    fail "Object containing unique does not contain an UNIQUE symbol"
+    set fails [expr $fails + 1]
+}
+
+if { $fails == 0 } {
+  pass "Checking unique object"
+}
+
+# check the executable
+if {! [check_osabi tmpdir/unique_prog {UNIX - Linux}]} {
+    fail "Executable containing unique does not have an OS/ABI field of LINUX"
+    set fails [expr $fails + 1]
+}
+
+if {[contains_unique_symbol tmpdir/unique_prog] != 1} {
+    fail "Executable containing unique does not contain an UNIQUE symbol"
+    set fails [expr $fails + 1]
+}
+
+if { $fails == 0 } {
+  pass "Checking unique executable"
+}
+
+# check the empty object file
+if {! [check_osabi tmpdir/unique_empty.o {UNIX - System V}]} {
+    fail "Object NOT containing unique does not have an OS/ABI field of System V"
+    set fails [expr $fails + 1]
+}
+
+if {[contains_unique_symbol tmpdir/unique_empty.o] == 1} {
+    fail "Object NOT containing unique does contain an UNIQUE symbol"
+    set fails [expr $fails + 1]
+}
+
+if { $fails == 0 } {
+  pass "Checking empty unique object"
+}
+
+# check the unique PIC file
+if {! [check_osabi tmpdir/unique_shared.o {UNIX - Linux}]} {
+    fail "PIC Object containing unique does not have an OS/ABI field of LINUX"
+    set fails [expr $fails + 1]
+}
+
+if {[contains_unique_symbol tmpdir/unique_shared.o] != 1} {
+    fail "PIC Object containing unique does not contain an UNIQUE symbol"
+    set fails [expr $fails + 1]
+}
+
+if { $fails == 0 } {
+  pass "Checking unique PIC object"
+}
+
+# check the unique shared library
+if {! [check_osabi tmpdir/libunique_shared.so {UNIX - Linux}]} {
+    fail "Shared library containing unique does not have an OS/ABI field of LINUX"
+    set fails [expr $fails + 1]
+}
+
+if {[contains_unique_symbol tmpdir/libunique_shared.so] != 1} {
+    fail "Shared library containing unique does not contain an UNIQUE symbol"
+    set fails [expr $fails + 1]
+}
+
+if { $fails == 0 } {
+  pass "Checking unique PIC object"
+}
+
+# check the empty executable linked against unique shared library
+if {! [check_osabi tmpdir/unique_shared_prog {UNIX - System V}]} {
+    fail "Executable NOT containing unique does not have an OS/ABI field of System V"
+    set fails [expr $fails + 1]
+}
+
+if {[contains_unique_symbol tmpdir/unique_shared_prog] == 1} {
+    fail "Executable NOT containing unique does contain an UNIQUE symbol"
+    set fails [expr $fails + 1]
+}
+
+if { $fails == 0 } {
+  pass "Checking shared empty executable"
+}
+
+
+
+# Clean up, unless we are being verbose, in which case we leave the files available.
+if { $verbose < 1 } {
+    remote_file host delete "tmpdir/unique_empty.o"
+    remote_file host delete "tmpdir/unique.o"
+    remote_file host delete "tmpdir/unique_shared.o"
+    remote_file host delete "tmpdir/libunique_shared.so"
+    remote_file host delete "tmpdir/unique_prog"
+    remote_file host delete "tmpdir/unique_shared_prog"
+}
diff --git a/ld/testsuite/ld-unique/unique.s b/ld/testsuite/ld-unique/unique.s
new file mode 100644
index 0000000..9b0593c
--- /dev/null
+++ b/ld/testsuite/ld-unique/unique.s
@@ -0,0 +1,8 @@
+	.type a, @gnu_unique_object
+a:	.long 0
+	.size a, .-a
+
+        .type main,"function"
+        .global main
+main:
+        .long 0
diff --git a/ld/testsuite/ld-unique/unique_empty.s b/ld/testsuite/ld-unique/unique_empty.s
new file mode 100644
index 0000000..efd6683
--- /dev/null
+++ b/ld/testsuite/ld-unique/unique_empty.s
@@ -0,0 +1,4 @@
+        .type main,"function"
+        .global main
+main:
+        .long 0
diff --git a/ld/testsuite/ld-unique/unique_shared.s b/ld/testsuite/ld-unique/unique_shared.s
new file mode 100644
index 0000000..b18a5b1
--- /dev/null
+++ b/ld/testsuite/ld-unique/unique_shared.s
@@ -0,0 +1,3 @@
+	.type b, @gnu_unique_object
+b:	.long 0
+	.size b, .-b
-- 
1.7.4.2


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]