This is the mail archive of the binutils@sources.redhat.com 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]

got relocs


More infrastructure for ppc64 tls, well, really for fixing the
brain-damaged got relocs.  Currently (x+8)@got is treated as x@got+8
ie. generate an entry in the got for x, and resolve to the address of
the entry + 8.  Not very useful since the got is typically generated
by a hash table traversal, making the entry after the one for x
something seemingly random.  On occasions though, it would be useful
to have a got entry for x+offset when x is eg. a struct.  Also, for
ppc64 tls, we might need more than one got entry per symbol.

I realize this change will break the ppc64 ABI (when I commit the
ppc64 patch), however I feel the impact will be minimal because
a) the ppc64 code base is relatively new.
b) ppc64 gcc manages the GOT (TOC) itself, and thus hasn't ever used
   the got relocs.
c) the useless nature of x@got+offset.

	* elf-bfd.h (struct got_entry, struct plt_entry): Forward declare.
	(struct elf_link_hash_entry): Add "glist" and "plist" fields to
	"got" union, and declare as gotplt_union.  Use gotplt_uinion for
	"plt" field.
	(struct elf_link_hash_table): Make "init_refcount" a gotplt_union.
	Add "init_offset" field.
	(struct elf_obj_tdata <local_got>): Add "struct got_entry **" to union.
	(elf_local_got_ents): Declare.
	* elf.c (_bfd_elf_link_hash_newfunc): Adjust initialization of "got"
	and "plt".
	(_bfd_elf_link_hash_hide_symbol): Use "init_offset".
	(_bfd_elf_link_hash_table_init): Set "init_offset".
	* elflink.h (NAME(bfd_elf,size_dynamic_sections)): Set init_refcount
	from init_offset.
	(elf_adjust_dynamic_symbol): Set plt and got offsets using init_offset.

	* elf.c (bfd_elf_local_sym_name): Split out from..
	(group_signature): ..here.
	* elf-bfd.h (bfd_elf_local_sym_name): Declare.

Index: bfd/elf-bfd.h
===================================================================
RCS file: /cvs/src/src/bfd/elf-bfd.h,v
retrieving revision 1.92
diff -u -p -r1.92 elf-bfd.h
--- bfd/elf-bfd.h	4 Feb 2003 12:34:07 -0000	1.92
+++ bfd/elf-bfd.h	4 Feb 2003 12:42:06 -0000
@@ -80,6 +80,8 @@ typedef struct
 } elf_symbol_type;
 
 struct elf_strtab_hash;
+struct got_entry;
+struct plt_entry;
 
 /* ELF linker hash table entries.  */
 
@@ -146,23 +148,23 @@ struct elf_link_hash_entry
 
   /* If this symbol requires an entry in the global offset table, the
      processor specific backend uses this field to track usage and
-     final offset.  We use a union and two names primarily to document
-     the intent of any particular piece of code.  The field should be
-     used as a count until size_dynamic_sections, at which point the
-     contents of the .got is fixed.  Afterward, if this field is -1,
-     then the symbol does not require a global offset table entry.  */
-  union
+     final offset.  Two schemes are supported:  The first assumes that
+     a symbol may only have one GOT entry, and uses REFCOUNT until
+     size_dynamic_sections, at which point the contents of the .got is
+     fixed.  Afterward, if OFFSET is -1, then the symbol does not
+     require a global offset table entry.  The second scheme allows
+     multiple GOT entries per symbol, managed via a linked list
+     pointed to by GLIST.  */
+  union gotplt_union
     {
       bfd_signed_vma refcount;
       bfd_vma offset;
+      struct got_entry *glist;
+      struct plt_entry *plist;
     } got;
 
   /* Same, but tracks a procedure linkage table entry.  */
-  union
-    {
-      bfd_signed_vma refcount;
-      bfd_vma offset;
-    } plt;
+  union gotplt_union plt;
 
   /* Symbol size.  */
   bfd_size_type size;
@@ -323,9 +325,13 @@ struct elf_link_hash_table
 
   /* The value to use when initialising got.refcount/offset and
      plt.refcount/offset in an elf_link_hash_entry.  Set to zero when
-     the values are refcounts.  Set to -1 in size_dynamic_sections
-     when the values may be offsets.  */
-  bfd_signed_vma init_refcount;
+     the values are refcounts.  Set to init_offset in
+     size_dynamic_sections when the values may be offsets.  */
+  union gotplt_union init_refcount;
+
+  /* The value to use for got.refcount/offset and plt.refcount/offset
+     when the values may be offsets.  Normally (bfd_vma) -1.  */
+  union gotplt_union init_offset;
 
   /* The number of symbols found in the link which must be put into
      the .dynsym section.  */
@@ -1099,17 +1105,14 @@ struct elf_obj_tdata
      minus the sh_info field of the symbol table header.  */
   struct elf_link_hash_entry **sym_hashes;
 
-  /* A mapping from local symbols to offsets into the global offset
-     table, used when linking.  This is indexed by the symbol index.
-     Like for the globals, we use a union and two names primarily to
-     document the intent of any particular piece of code.  The field
-     should be used as a count until size_dynamic_sections, at which
-     point the contents of the .got is fixed.  Afterward, if an entry
-     is -1, then the symbol does not require a global offset table entry.  */
+  /* Track usage and final offsets of GOT entries for local symbols.
+     This array is indexed by symbol index.  Elements are used
+     identically to "got" in struct elf_link_hash_entry.  */
   union
     {
       bfd_signed_vma *refcounts;
       bfd_vma *offsets;
+      struct got_entry **ents;
     } local_got;
 
   /* A mapping from local symbols to offsets into the various linker
@@ -1216,6 +1219,7 @@ struct elf_obj_tdata
 #define elf_sym_hashes(bfd)	(elf_tdata(bfd) -> sym_hashes)
 #define elf_local_got_refcounts(bfd) (elf_tdata(bfd) -> local_got.refcounts)
 #define elf_local_got_offsets(bfd) (elf_tdata(bfd) -> local_got.offsets)
+#define elf_local_got_ents(bfd) (elf_tdata(bfd) -> local_got.ents)
 #define elf_local_ptr_offsets(bfd) (elf_tdata(bfd) -> linker_section_pointers)
 #define elf_dt_name(bfd)	(elf_tdata(bfd) -> dt_name)
 #define elf_dt_soname(bfd)	(elf_tdata(bfd) -> dt_soname)
@@ -1253,6 +1257,8 @@ extern char *bfd_elf_get_str_section
 extern Elf_Internal_Sym *bfd_elf_get_elf_syms
   PARAMS ((bfd *, Elf_Internal_Shdr *, size_t, size_t,
 	   Elf_Internal_Sym *, PTR, Elf_External_Sym_Shndx *));
+extern const char *bfd_elf_local_sym_name
+  PARAMS ((bfd *, Elf_Internal_Sym *));
 
 extern bfd_boolean _bfd_elf_copy_private_bfd_data
   PARAMS ((bfd *, bfd *));
Index: bfd/elf.c
===================================================================
RCS file: /cvs/src/src/bfd/elf.c,v
retrieving revision 1.176
diff -u -p -r1.176 elf.c
--- bfd/elf.c	4 Feb 2003 12:34:08 -0000	1.176
+++ bfd/elf.c	4 Feb 2003 12:42:09 -0000
@@ -476,6 +476,23 @@ bfd_elf_get_elf_syms (ibfd, symtab_hdr, 
   return intsym_buf;
 }
 
+/* Look up a symbol name.  */
+const char *
+bfd_elf_local_sym_name (abfd, isym)
+     bfd *abfd;
+     Elf_Internal_Sym *isym;
+{
+  unsigned int iname = isym->st_name;
+  unsigned int shindex = elf_tdata (abfd)->symtab_hdr.sh_link;
+  if (iname == 0 && ELF_ST_TYPE (isym->st_info) == STT_SECTION)
+    {
+      iname = elf_elfsections (abfd)[isym->st_shndx]->sh_name;
+      shindex = elf_elfheader (abfd)->e_shstrndx;
+    }
+
+  return bfd_elf_string_from_elf_section (abfd, shindex, iname);
+}
+
 /* Elf_Internal_Shdr->contents is an array of these for SHT_GROUP
    sections.  The first element is the flags, the rest are section
    pointers.  */
@@ -497,8 +514,6 @@ group_signature (abfd, ghdr)
   unsigned char esym[sizeof (Elf64_External_Sym)];
   Elf_External_Sym_Shndx eshndx;
   Elf_Internal_Sym isym;
-  unsigned int iname;
-  unsigned int shindex;
 
   /* First we need to ensure the symbol table is available.  */
   if (! bfd_section_from_shdr (abfd, ghdr->sh_link))
@@ -510,16 +525,7 @@ group_signature (abfd, ghdr)
 			    &isym, esym, &eshndx) == NULL)
     return NULL;
 
-  /* Look up the symbol name.  */
-  iname = isym.st_name;
-  shindex = hdr->sh_link;
-  if (iname == 0 && ELF_ST_TYPE (isym.st_info) == STT_SECTION)
-    {
-      iname = elf_elfsections (abfd)[isym.st_shndx]->sh_name;
-      shindex = elf_elfheader (abfd)->e_shstrndx;
-    }
-
-  return bfd_elf_string_from_elf_section (abfd, shindex, iname);
+  return bfd_elf_local_sym_name (abfd, &isym);
 }
 
 /* Set next_in_group list pointer, and group name for NEWSECT.  */
@@ -1420,8 +1426,8 @@ _bfd_elf_link_hash_newfunc (entry, table
       ret->vtable_entries_size = 0;
       ret->vtable_entries_used = NULL;
       ret->vtable_parent = NULL;
-      ret->got.refcount = htab->init_refcount;
-      ret->plt.refcount = htab->init_refcount;
+      ret->got = htab->init_refcount;
+      ret->plt = htab->init_refcount;
       ret->size = 0;
       ret->type = STT_NOTYPE;
       ret->other = 0;
@@ -1496,7 +1502,7 @@ _bfd_elf_link_hash_hide_symbol (info, h,
      struct elf_link_hash_entry *h;
      bfd_boolean force_local;
 {
-  h->plt.offset = (bfd_vma) -1;
+  h->plt = elf_hash_table (info)->init_offset;
   h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
   if (force_local)
     {
@@ -1526,8 +1532,9 @@ _bfd_elf_link_hash_table_init (table, ab
   table->dynobj = NULL;
   /* Make sure can_refcount is extended to the width and signedness of
      init_refcount before we subtract one from it.  */
-  table->init_refcount = get_elf_backend_data (abfd)->can_refcount;
-  --table->init_refcount;
+  table->init_refcount.refcount = get_elf_backend_data (abfd)->can_refcount;
+  table->init_refcount.refcount -= 1;
+  table->init_offset.offset = -(bfd_vma) 1;
   /* The first dynamic symbol is a dummy.  */
   table->dynsymcount = 1;
   table->dynstr = NULL;
Index: bfd/elflink.h
===================================================================
RCS file: /cvs/src/src/bfd/elflink.h,v
retrieving revision 1.203
diff -u -p -r1.203 elflink.h
--- bfd/elflink.h	4 Feb 2003 12:34:08 -0000	1.203
+++ bfd/elflink.h	4 Feb 2003 12:42:14 -0000
@@ -2902,7 +2902,7 @@ NAME(bfd_elf,size_dynamic_sections) (out
 
   /* Any syms created from now on start with -1 in
      got.refcount/offset and plt.refcount/offset.  */
-  elf_hash_table (info)->init_refcount = -1;
+  elf_hash_table (info)->init_refcount = elf_hash_table (info)->init_offset;
 
   /* The backend may have to create some sections regardless of whether
      we're dynamic or not.  */
@@ -3909,10 +3909,13 @@ elf_adjust_dynamic_symbol (h, data)
   bfd *dynobj;
   struct elf_backend_data *bed;
 
+  if (! is_elf_hash_table (eif->info))
+    return FALSE;
+
   if (h->root.type == bfd_link_hash_warning)
     {
-      h->plt.offset = (bfd_vma) -1;
-      h->got.offset = (bfd_vma) -1;
+      h->plt = elf_hash_table (eif->info)->init_offset;
+      h->got = elf_hash_table (eif->info)->init_offset;
 
       /* When warning symbols are created, they **replace** the "real"
 	 entry in the hash table, thus we never get to see the real
@@ -3924,9 +3927,6 @@ elf_adjust_dynamic_symbol (h, data)
   if (h->root.type == bfd_link_hash_indirect)
     return TRUE;
 
-  if (! is_elf_hash_table (eif->info))
-    return FALSE;
-
   /* Fix the symbol flags.  */
   if (! elf_fix_symbol_flags (h, eif))
     return FALSE;
@@ -3944,7 +3944,7 @@ elf_adjust_dynamic_symbol (h, data)
 	  || ((h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0
 	      && (h->weakdef == NULL || h->weakdef->dynindx == -1))))
     {
-      h->plt.offset = (bfd_vma) -1;
+      h->plt = elf_hash_table (eif->info)->init_offset;
       return TRUE;
     }
 

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre


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