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]

New symbol binding to fix C++ ABI


The C++ ABI demands that certain data objects are unique in the entire
process.  This is the case static class members or static variables in
inline functions.  Jason can provide the necessary details, if needed.

I attach a patch which implements a new symbol binding, STB_GNU_UNIQUE.
 The compile will use this binding, instead of defining the variable as
a global variable.  Jason already has a patch for gcc which is using the
extension of the patch below.

There is one detail of the patch which is non-obvious.  The interface to
get to such an object is not implemented by providing a pseudo-op
similar to .global.  Instead, I've defined a new symbol type, to be used
with the .type pseudo-op.  The reason for this is that it is wrong to
apply the new symbol binding to anything but data object (no functions
in particular).  It makes no sense.  So, instead of opening the door for
misuse the compiler will emit

  .type name,%gnu_unique_object
  .global

instead of

  .type name,%object
  .global

At the assembler source level this isn't confusing at all.  It's only
the translation to what it means at the ELF level that might be a bit
confusing.  But not many people have to actually deal with this so I
don't consider it a problem.

The patch below applies on top of the RH binutils RPM.  It should also
apply with little fuzz to the normal sources.

-- 
â Ulrich Drepper â Red Hat, Inc. â 444 Castro St â Mountain View, CA â
diff -up binutils-2.19.51.0.7/bfd/bfd-in2.h.uobject binutils-2.19.51.0.7/bfd/bfd-in2.h
--- binutils-2.19.51.0.7/bfd/bfd-in2.h.uobject	2009-06-01 09:44:22.000000000 -0700
+++ binutils-2.19.51.0.7/bfd/bfd-in2.h	2009-06-01 12:50:59.130760158 -0700
@@ -4627,6 +4627,11 @@ typedef struct bfd_symbol
      also be also set.  */
 #define BSF_GNU_INDIRECT_FUNCTION (1 << 22)
 
+  /* This symbol is a globally unique data object.  The dynamic linker
+     will make sure that in the entire process there is one symbol with
+     this name and type in use.  BSF_OBJECT must also be set.  */
+#define BSF_GNU_UNIQUE		(1 << 23)
+
   flagword flags;
 
   /* A pointer to the section to which this symbol is
diff -up binutils-2.19.51.0.7/bfd/elf-bfd.h.uobject binutils-2.19.51.0.7/bfd/elf-bfd.h
--- binutils-2.19.51.0.7/bfd/elf-bfd.h.uobject	2009-06-01 09:44:22.000000000 -0700
+++ binutils-2.19.51.0.7/bfd/elf-bfd.h	2009-06-01 12:50:59.133989942 -0700
@@ -176,6 +176,8 @@ struct elf_link_hash_entry
   /* Symbol is referenced with a relocation where C/C++ pointer equality
      matters.  */
   unsigned int pointer_equality_needed : 1;
+  /* Symbol is a unique global symbol.  */
+  unsigned int unique_global : 1;
 
   /* String table index in .dynstr if this is a dynamic symbol.  */
   unsigned long dynstr_index;
diff -up binutils-2.19.51.0.7/bfd/elfcode.h.uobject binutils-2.19.51.0.7/bfd/elfcode.h
--- binutils-2.19.51.0.7/bfd/elfcode.h.uobject	2009-06-01 12:49:28.425987917 -0700
+++ binutils-2.19.51.0.7/bfd/elfcode.h	2009-06-01 12:50:59.136990644 -0700
@@ -1342,6 +1342,9 @@ elf_slurp_symbol_table (bfd *abfd, asymb
 	    case STB_WEAK:
 	      sym->symbol.flags |= BSF_WEAK;
 	      break;
+	    case STB_GNU_UNIQUE:
+	      sym->symbol.flags |= BSF_GNU_UNIQUE;
+	      break;
 	    }
 
 	  switch (ELF_ST_TYPE (isym->st_info))
diff -up binutils-2.19.51.0.7/bfd/elf.c.uobject binutils-2.19.51.0.7/bfd/elf.c
--- binutils-2.19.51.0.7/bfd/elf.c.uobject	2009-06-01 09:44:22.000000000 -0700
+++ binutils-2.19.51.0.7/bfd/elf.c	2009-06-01 12:50:59.143989883 -0700
@@ -6566,6 +6566,8 @@ Unable to find equivalent output section
 
 	  if (flags & BSF_LOCAL)
 	    bind = STB_LOCAL;
+	  else if (flags & BSF_GNU_UNIQUE)
+	    bind = STB_GNU_UNIQUE;
 	  else if (flags & BSF_WEAK)
 	    bind = STB_WEAK;
 	  else if (flags & BSF_GLOBAL)
diff -up binutils-2.19.51.0.7/bfd/elflink.c.uobject binutils-2.19.51.0.7/bfd/elflink.c
--- binutils-2.19.51.0.7/bfd/elflink.c.uobject	2009-06-01 09:44:22.000000000 -0700
+++ binutils-2.19.51.0.7/bfd/elflink.c	2009-06-01 12:50:59.153989614 -0700
@@ -1285,6 +1285,9 @@ _bfd_elf_merge_symbol (bfd *abfd,
   oldweak = (h->root.type == bfd_link_hash_defweak
 	     || h->root.type == bfd_link_hash_undefweak);
 
+  if (bind == STB_GNU_UNIQUE)
+    h->unique_global = 1;
+
   /* If a new weak symbol definition comes from a regular file and the
      old symbol comes from a dynamic library, we treat the new one as
      strong.  Similarly, an old weak symbol definition from a regular
@@ -3925,6 +3928,8 @@ elf_link_add_object_symbols (bfd *abfd, 
 	}
       else if (bind == STB_WEAK)
 	flags = BSF_WEAK;
+      else if (bind == STB_GNU_UNIQUE)
+	flags = BSF_GNU_UNIQUE;
       else
 	{
 	  /* Leave it up to the processor backend.  */
@@ -4183,6 +4188,7 @@ elf_link_add_object_symbols (bfd *abfd, 
 	     || h->root.type == bfd_link_hash_warning)
 	h = (struct elf_link_hash_entry *) h->root.u.i.link;
       *sym_hash = h;
+      h->unique_global = (flags & BSF_GNU_UNIQUE) != 0;
 
       new_weakdef = FALSE;
       if (dynamic
@@ -8633,6 +8639,8 @@ elf_link_output_extsym (struct elf_link_
   sym.st_other = h->other;
   if (h->forced_local)
     sym.st_info = ELF_ST_INFO (STB_LOCAL, h->type);
+  else if (h->unique_global)
+    sym.st_info = ELF_ST_INFO (STB_GNU_UNIQUE, h->type);
   else if (h->root.type == bfd_link_hash_undefweak
 	   || h->root.type == bfd_link_hash_defweak)
     sym.st_info = ELF_ST_INFO (STB_WEAK, h->type);
diff -up binutils-2.19.51.0.7/bfd/syms.c.uobject binutils-2.19.51.0.7/bfd/syms.c
--- binutils-2.19.51.0.7/bfd/syms.c.uobject	2009-05-25 07:02:20.000000000 -0700
+++ binutils-2.19.51.0.7/bfd/syms.c	2009-06-01 12:50:59.163990113 -0700
@@ -302,6 +302,10 @@ CODE_FRAGMENT
 .     calling the function that it points to.  BSF_FUNCTION must
 .     also be also set.  *}
 .#define BSF_GNU_INDIRECT_FUNCTION (1 << 22)
+.  {* This symbol is a globally unique data object.  The dynamic linker
+.     will make sure that in the entire process there is one symbol with
+.     this name and type in use.  BSF_OBJECT must also be set.  *}
+.#define BSF_GNU_UNIQUE		(1 << 23)
 .
 .  flagword flags;
 .
@@ -485,7 +489,8 @@ bfd_print_symbol_vandf (bfd *abfd, void 
   fprintf (file, " %c%c%c%c%c%c%c",
 	   ((type & BSF_LOCAL)
 	    ? (type & BSF_GLOBAL) ? '!' : 'l'
-	    : (type & BSF_GLOBAL) ? 'g' : ' '),
+	    : (type & BSF_GLOBAL) ? 'g'
+	    : (type & BSF_GNU_UNIQUE) ? 'u' : ' '),
 	   (type & BSF_WEAK) ? 'w' : ' ',
 	   (type & BSF_CONSTRUCTOR) ? 'C' : ' ',
 	   (type & BSF_WARNING) ? 'W' : ' ',
@@ -686,6 +691,8 @@ bfd_decode_symclass (asymbol *symbol)
       else
 	return 'W';
     }
+  if (symbol->flags & BSF_GNU_UNIQUE)
+    return 'u';
   if (!(symbol->flags & (BSF_GLOBAL | BSF_LOCAL)))
     return '?';
 
diff -up binutils-2.19.51.0.7/binutils/readelf.c.uobject binutils-2.19.51.0.7/binutils/readelf.c
--- binutils-2.19.51.0.7/binutils/readelf.c.uobject	2009-06-01 09:44:22.000000000 -0700
+++ binutils-2.19.51.0.7/binutils/readelf.c	2009-06-01 12:50:59.166987532 -0700
@@ -7035,7 +7035,14 @@ get_symbol_binding (unsigned int binding
 	snprintf (buff, sizeof (buff), _("<processor specific>: %d"),
 		  binding);
       else if (binding >= STB_LOOS && binding <= STB_HIOS)
-	snprintf (buff, sizeof (buff), _("<OS specific>: %d"), binding);
+	{
+	  if (binding == STB_GNU_UNIQUE
+	      && (elf_header.e_ident[EI_OSABI] == ELFOSABI_LINUX
+		  /* GNU/Linux is still using the default value 0.  */
+		  || elf_header.e_ident[EI_OSABI] == ELFOSABI_NONE))
+	    return "UNIQUE";
+	  snprintf (buff, sizeof (buff), _("<OS specific>: %d"), binding);
+	}
       else
 	snprintf (buff, sizeof (buff), _("<unknown>: %d"), binding);
       return buff;
diff -up binutils-2.19.51.0.7/elfcpp/elfcpp.h.uobject binutils-2.19.51.0.7/elfcpp/elfcpp.h
--- binutils-2.19.51.0.7/elfcpp/elfcpp.h.uobject	2009-05-29 14:08:38.000000000 -0700
+++ binutils-2.19.51.0.7/elfcpp/elfcpp.h	2009-06-01 12:50:59.167985368 -0700
@@ -476,6 +476,7 @@ enum STB
   STB_GLOBAL = 1,
   STB_WEAK = 2,
   STB_LOOS = 10,
+  STB_GNU_UNIQUE = 10,
   STB_HIOS = 12,
   STB_LOPROC = 13,
   STB_HIPROC = 15
diff -up binutils-2.19.51.0.7/gas/config/obj-elf.c.uobject binutils-2.19.51.0.7/gas/config/obj-elf.c
--- binutils-2.19.51.0.7/gas/config/obj-elf.c.uobject	2009-06-01 09:44:21.000000000 -0700
+++ binutils-2.19.51.0.7/gas/config/obj-elf.c	2009-06-01 12:50:59.168987604 -0700
@@ -1720,6 +1720,18 @@ obj_elf_type (int ignore ATTRIBUTE_UNUSE
 		typename);
       type = BSF_FUNCTION | BSF_GNU_INDIRECT_FUNCTION;
     }
+  else if (strcmp (typename, "gnu_unique_object") == 0)
+    {
+      const struct elf_backend_data *bed;
+
+      bed = get_elf_backend_data (stdoutput);
+      if (!(bed->elf_osabi == ELFOSABI_LINUX
+	    /* GNU/Linux is still using the default value 0.  */
+	    || bed->elf_osabi == ELFOSABI_NONE))
+	as_bad (_("symbol type \"%s\" is supported only by GNU targets"),
+		typename);
+      type = BSF_OBJECT | BSF_GNU_UNIQUE;
+    }
 #ifdef md_elf_symbol_type
   else if ((type = md_elf_symbol_type (typename, sym, elfsym)) != -1)
     ;
diff -up binutils-2.19.51.0.7/include/elf/common.h.uobject binutils-2.19.51.0.7/include/elf/common.h
--- binutils-2.19.51.0.7/include/elf/common.h.uobject	2009-06-01 09:44:21.000000000 -0700
+++ binutils-2.19.51.0.7/include/elf/common.h	2009-06-01 12:50:59.169985510 -0700
@@ -558,6 +558,7 @@
 #define STB_GLOBAL	1		/* Symbol visible outside obj */
 #define STB_WEAK	2		/* Like globals, lower precedence */
 #define STB_LOOS	10		/* OS-specific semantics */
+#define STB_GNU_UNIQUE	10		/* Symbol is unique in namespace */
 #define STB_HIOS	12		/* OS-specific semantics */
 #define STB_LOPROC	13		/* Processor-specific semantics */
 #define STB_HIPROC	15		/* Processor-specific semantics */

Attachment: signature.asc
Description: OpenPGP digital signature


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