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]

[RFA:] support different(-sized) GOT entries in bfd_elf_gc_common_final_link


There are three files using bfd_elf_gc_common_final_link for
their bfd_elf32_bfd_final_link (allocating GOT offsets), namely
elf32-vax.c, elf32-bfin.c and elf32-cris.c.  With the following
change, maybe more targets can use it.  Without it, for the TLS
changes in the CRIS port, I'd have to replicate
bfd_elf_gc_common_final_link in elf32-cris.c.

With this change, different GOT entries are supported.
Trivially, just different-sized GOT entries are supported.  With
a little help from the target, multiple different-sized GOT
entries for the same symbol can be handled; they're then
supposed to be exposed through the callback-function as one big
GOT entry.  (The back-end returns the sum of their sizes and is
required to keep the sum in h->got.refcount and
elf_local_got_refcounts() and to keep track of their individual
positions.)  Maybe the extract from the elf32-cris.c patch for
TLS below helps as a showcase.

Intended use: for TLS (for most N-bit targets), you have a
relocation that affects a two-N-bit-sized structure in the GOT,
requiring 2*N-bit "entries".  This doesn't match the hardcoded
(bed->s->arch_size / 8).  A bed->s entry that is just a variable
doesn't quite fit the bill either, it has to be a function, as
below.

Also, you get entries with *different contents validly referring
to the same symbol*: if you've compiled one file for the
global-dynamic (GD) model and one with initial-exec (IE), you'll
need two different GOT entries.  You can't use the same GOT
entry for that (unless of course, your target *requires*
link-time optimization from GD to IE so you'll get just one
dynamic TLS entry).

The new callback takes three arguments (see the elf-bfd.h patch
and elf_cris_got_elt_size), but the last two are only used when
the first one is NULL ("global" symbol vs. local symbol without
a elf_link_hash_entry).  Not sure how to do that cleaner, but it
doesn't seem a big enough deal to worry about.

Tested crosses to cris-axis-elf, cris-axis-linux-gnu,
bfin-uclinux and vax-linux, and native i686-pc-linux-gnu for
good measure, no regressions.

Ok to commit?

bfd:
	* elf-bfd.h (struct elf_backend_data): New member got_elt_size.
	(_bfd_elf_default_got_elt_size): Declare.
	* elflink.c (struct alloc_got_off_arg): Replace member got_elt_size
	by new member info.
	(elf_gc_allocate_got_offsets): Adjust for calling bed->got_elt_size
	to get the element size instead of using a gofarg entry.
	(bfd_elf_gc_common_finalize_got_offsets): Similar.
	(_bfd_elf_default_got_elt_size): New function.
	* elfxx-target.h: New macro elf_backend_got_elt_size.
	(elfNN_bed): Use it.

Index: elf-bfd.h
===================================================================
RCS file: /cvs/src/src/bfd/elf-bfd.h,v
retrieving revision 1.268
diff -p -u -r1.268 elf-bfd.h
--- elf-bfd.h	20 Oct 2008 10:57:33 -0000	1.268
+++ elf-bfd.h	19 Nov 2008 12:31:39 -0000
@@ -1147,6 +1147,12 @@ struct elf_backend_data
      so-called reserved entries on some systems.  */
   bfd_vma got_header_size;
 
+  /* The size of the GOT entry for the symbol pointed to by H if non-NULL,
+     otherwise by the local symbol with index SYMNDX in IBFD.  */
+  bfd_vma (*got_elt_size) (bfd *, struct bfd_link_info *,
+			   struct elf_link_hash_entry *h,
+			   bfd *ibfd, unsigned long symndx);
+
   /* The vendor name to use for a processor-standard attributes section.  */
   const char *obj_attrs_vendor;
 
@@ -2070,6 +2076,10 @@ extern asection *_bfd_elf_common_section
 extern void _bfd_dwarf2_cleanup_debug_info
   (bfd *);
 
+extern bfd_vma _bfd_elf_default_got_elt_size
+(bfd *, struct bfd_link_info *, struct elf_link_hash_entry *, bfd *,
+ unsigned long);
+
 extern bfd_reloc_status_type _bfd_elf_rel_vtable_reloc_fn
   (bfd *, arelent *, struct bfd_symbol *, void *,
    asection *, bfd *, char **);
Index: elflink.c
===================================================================
RCS file: /cvs/src/src/bfd/elflink.c,v
retrieving revision 1.315
diff -p -u -r1.315 elflink.c
--- elflink.c	20 Oct 2008 10:57:33 -0000	1.315
+++ elflink.c	19 Nov 2008 12:31:42 -0000
@@ -11786,7 +11786,7 @@ bfd_elf_gc_record_vtentry (bfd *abfd ATT
 
 struct alloc_got_off_arg {
   bfd_vma gotoff;
-  unsigned int got_elt_size;
+  struct bfd_link_info *info;
 };
 
 /* We need a special top-level link routine to convert got reference counts
@@ -11796,6 +11796,8 @@ static bfd_boolean
 elf_gc_allocate_got_offsets (struct elf_link_hash_entry *h, void *arg)
 {
   struct alloc_got_off_arg *gofarg = arg;
+  bfd *obfd = gofarg->info->output_bfd;
+  const struct elf_backend_data *bed = get_elf_backend_data (obfd);
 
   if (h->root.type == bfd_link_hash_warning)
     h = (struct elf_link_hash_entry *) h->root.u.i.link;
@@ -11803,7 +11805,7 @@ elf_gc_allocate_got_offsets (struct elf_
   if (h->got.refcount > 0)
     {
       h->got.offset = gofarg->gotoff;
-      gofarg->gotoff += gofarg->got_elt_size;
+      gofarg->gotoff += bed->got_elt_size (obfd, gofarg->info, h, NULL, 0);
     }
   else
     h->got.offset = (bfd_vma) -1;
@@ -11821,9 +11823,10 @@ bfd_elf_gc_common_finalize_got_offsets (
   bfd *i;
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
   bfd_vma gotoff;
-  unsigned int got_elt_size = bed->s->arch_size / 8;
   struct alloc_got_off_arg gofarg;
 
+  BFD_ASSERT (abfd == info->output_bfd);
+
   if (! is_elf_hash_table (info->hash))
     return FALSE;
 
@@ -11859,7 +11862,7 @@ bfd_elf_gc_common_finalize_got_offsets (
 	  if (local_got[j] > 0)
 	    {
 	      local_got[j] = gotoff;
-	      gotoff += got_elt_size;
+	      gotoff += bed->got_elt_size (abfd, info, NULL, i, j);
 	    }
 	  else
 	    local_got[j] = (bfd_vma) -1;
@@ -11869,7 +11872,7 @@ bfd_elf_gc_common_finalize_got_offsets (
   /* Then the global .got entries.  .plt refcounts are handled by
      adjust_dynamic_symbol  */
   gofarg.gotoff = gotoff;
-  gofarg.got_elt_size = got_elt_size;
+  gofarg.info = info;
   elf_link_hash_traverse (elf_hash_table (info),
 			  elf_gc_allocate_got_offsets,
 			  &gofarg);
@@ -12255,3 +12258,14 @@ _bfd_elf_common_section (asection *sec A
 {
   return bfd_com_section_ptr;
 }
+
+bfd_vma
+_bfd_elf_default_got_elt_size (bfd *abfd,
+			       struct bfd_link_info *info ATTRIBUTE_UNUSED,
+			       struct elf_link_hash_entry *h ATTRIBUTE_UNUSED,
+			       bfd *ibfd ATTRIBUTE_UNUSED,
+			       unsigned long symndx ATTRIBUTE_UNUSED)
+{
+  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  return bed->s->arch_size / 8;
+}
Index: elfxx-target.h
===================================================================
RCS file: /cvs/src/src/bfd/elfxx-target.h,v
retrieving revision 1.115
diff -p -u -r1.115 elfxx-target.h
--- elfxx-target.h	7 Aug 2008 20:04:32 -0000	1.115
+++ elfxx-target.h	19 Nov 2008 12:31:42 -0000
@@ -446,6 +446,9 @@
 #ifndef elf_backend_got_header_size
 #define elf_backend_got_header_size	0
 #endif
+#ifndef elf_backend_got_elt_size
+#define elf_backend_got_elt_size _bfd_elf_default_got_elt_size
+#endif
 #ifndef elf_backend_obj_attrs_vendor
 #define elf_backend_obj_attrs_vendor		NULL
 #endif
@@ -712,6 +715,7 @@ static struct elf_backend_data elfNN_bed
   &elf_backend_size_info,
   elf_backend_special_sections,
   elf_backend_got_header_size,
+  elf_backend_got_elt_size,
   elf_backend_obj_attrs_vendor,
   elf_backend_obj_attrs_section,
   elf_backend_obj_attrs_arg_type,
Index: elf32-cris.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-cris.c,v
retrieving revision 1.86
diff -p -u -r1.86 elf32-cris.c
--- elf32-cris.c	4 Oct 2008 17:18:36 -0000	1.86
+++ elf32-cris.c	19 Nov 2008 12:31:40 -0000
(TLS-part elided ...PATCH EXTRACT, DO NOT APPLY...)
@@ -3400,6 +4092,64 @@ elf_cris_reloc_type_class (rela)
       return reloc_class_normal;
     }
 }
+
+/* The elf_backend_got_elt_size worker.  For one symbol, we can have
+   up to two GOT entries from three different-sized types.  We fake it
+   as a single entry, so we can use the regular offset-calculation
+   machinery.  */
+
+static bfd_vma
+elf_cris_got_elt_size (bfd *abfd ATTRIBUTE_UNUSED,
+		       struct bfd_link_info *info ATTRIBUTE_UNUSED,
+		       struct elf_link_hash_entry *hr,
+		       bfd *ibfd,
+		       unsigned long symndx)
+{
+  struct elf_link_hash_entry *h = (struct elf_link_hash_entry *) hr;
+  bfd_vma eltsiz = 0;
+
+  /* We may have one regular GOT entry or up to two TLS GOT
+     entries.  */
+  if (h == NULL)
+    {
+      bfd_signed_vma *local_got_refcounts = elf_local_got_refcounts (ibfd);
+
+      BFD_ASSERT (local_got_refcounts != NULL);
+
+      if (local_got_refcounts[LGOT_REG_NDX (symndx)] > 0)
+	{
+	  /* We can't have a variable referred to both as a regular
+	     variable and through TLS relocs.  */
+	  BFD_ASSERT (local_got_refcounts[LGOT_DTP_NDX (symndx)] == 0
+		      && local_got_refcounts[LGOT_TPREL_NDX (symndx)] == 0);
+	  return 4;
+	}
+
+      if (local_got_refcounts[LGOT_DTP_NDX (symndx)] > 0)
+	eltsiz += 8;
+
+      if (local_got_refcounts[LGOT_TPREL_NDX (symndx)] > 0)
+	eltsiz += 4;
+    }
+  else
+    {
+      struct elf_cris_link_hash_entry *hh = elf_cris_hash_entry (h);
+      if (hh->reg_got_refcount > 0)
+	{
+	  /* The actual error-on-input is emitted elsewhere.  */
+	  BFD_ASSERT (hh->dtp_refcount == 0 && hh->tprel_refcount == 0);
+	  return 4;
+	}
+
+      if (hh->dtp_refcount > 0)
+	eltsiz += 8;
+
+      if (hh->tprel_refcount > 0)
+	eltsiz += 4;
+    }
+
+  return eltsiz;
+}
 
 #define ELF_ARCH		bfd_arch_cris
 #define ELF_MACHINE_CODE	EM_CRIS
@@ -3456,6 +4206,7 @@ elf_cris_reloc_type_class (rela)
 #define elf_backend_plt_readonly	1
 #define elf_backend_want_plt_sym	0
 #define elf_backend_got_header_size	12
+#define elf_backend_got_elt_size elf_cris_got_elt_size
 
 /* Later, we my want to optimize RELA entries into REL entries for dynamic
    linking and libraries (if it's a win of any significance).  Until then,

brgds, H-P


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