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]

Re: combreloc


Hi Jakub,
  This patch fixes the "pessimisation" you mentioned re. DT_TEXTREL for
x86.  Setting DF_TEXTREL in check_relocs is pessimistic because

a) If dynamic relocs are garbage collected, or removed due to symbol
   visibility or -Bsymbolic actions, we may not end up with any relocs
   against read-only sections.
b) Testing whether the input section is read-only isn't reliable. (*)
   A read-only input section can easily be mapped to a read-write output
   section;  When check_relocs is called, the linker has not yet
   mapped input sections to output sections.  Fortunately, I don't
   think a read-write input section can be mapped to a read-only output
   section.  If this is possible, then trying to set DF_TEXTREL in
   check relocs could result in omitting DT_TEXTREL when it's needed.

I've also implemented garbage collection of dyn_relocs, something I've
been meaning to do for quite some time.

(*) Yeah, I use this test for copy relocs, which is wrong...

bfd/ChangeLog
	* elf32-i386.c (struct elf_i386_dyn_relocs): Add "sec", and
	"pc_count" fields.  Rename "section" field to "sreloc".
	(check_relocs): Don't set DF_TEXTREL here.  Instead, record all
	dynamic relocations via dyn_relocs.
	(elf_i386_gc_sweep_hook): Sweep dyn_relocs too.
	(allocate_plt_and_got_and_discard_relocs): For the shared case we
	now track all dynamic relocs, not just pc-relative ones, so use
	pc_count when removing unneeded relocs.  Discard eh->dyn_relocs
	entries if the count drops to zero.
	(readonly_dynrelocs): New function.
	(elf_i386_size_dynamic_sections): Call it.  Rename "i" to "ibfd".

-- 
Alan Modra

Index: bfd/elf32-i386.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-i386.c,v
retrieving revision 1.46
diff -u -p -r1.46 elf32-i386.c
--- elf32-i386.c	2001/09/24 01:38:31	1.46
+++ elf32-i386.c	2001/09/24 13:42:53
@@ -51,6 +51,8 @@ static boolean elf_i386_adjust_dynamic_s
   PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
 static boolean allocate_plt_and_got_and_discard_relocs
   PARAMS ((struct elf_link_hash_entry *, PTR));
+static boolean readonly_dynrelocs
+  PARAMS ((struct elf_link_hash_entry *, PTR));
 static boolean elf_i386_size_dynamic_sections
   PARAMS ((bfd *, struct bfd_link_info *));
 static boolean elf_i386_relocate_section
@@ -378,12 +380,19 @@ static const bfd_byte elf_i386_pic_plt_e
 
 struct elf_i386_dyn_relocs
 {
-  /* Next section.  */
   struct elf_i386_dyn_relocs *next;
-  /* A section in dynobj.  */
-  asection *section;
-  /* Number of relocs copied in this section.  */
+
+  /* The input section of the reloc.  */
+  asection *sec;
+
+  /* A section in dynobj for the reloc.  */
+  asection *sreloc;
+
+  /* Total number of relocs copied in the input section.  */
   bfd_size_type count;
+
+  /* Number of pc-relative relocs copied in the input section.  */
+  bfd_size_type pc_count;
 };
 
 /* i386 ELF linker hash entry.  */
@@ -392,7 +401,7 @@ struct elf_i386_link_hash_entry
 {
   struct elf_link_hash_entry root;
 
-  /* Number of PC relative relocs copied for this symbol.  */
+  /* Track dynamic relocs copied for this symbol.  */
   struct elf_i386_dyn_relocs *dyn_relocs;
 };
 
@@ -743,9 +752,9 @@ elf_i386_check_relocs (abfd, info, sec, 
 		      || strcmp (bfd_get_section_name (abfd, sec),
 				 name + 4) != 0)
 		    {
-		      (*_bfd_error_handler) (_("%s: bad relocation section name `%s\'"),
-					     bfd_archive_filename (abfd),
-					     name);
+		      (*_bfd_error_handler)
+			(_("%s: bad relocation section name `%s\'"),
+			 bfd_archive_filename (abfd), name);
 		    }
 
 		  sreloc = bfd_get_section_by_name (dynobj, name);
@@ -763,32 +772,22 @@ elf_i386_check_relocs (abfd, info, sec, 
 			  || ! bfd_set_section_alignment (dynobj, sreloc, 2))
 			return false;
 		    }
-		  if (sec->flags & SEC_READONLY)
-		    info->flags |= DF_TEXTREL;
 		}
 
 	      sreloc->_raw_size += sizeof (Elf32_External_Rel);
 
-	      /* If this is a global symbol, we count the number of PC
-		 relative relocations we have entered for this symbol,
-		 so that we can discard them later as necessary.  Note
-		 that this function is only called if we are using an
-		 elf_i386 linker hash table, which means that h is
-		 really a pointer to an elf_i386_link_hash_entry.  */
-	      if (!info->shared
-		  || (h != NULL
-		      && ELF32_R_TYPE (rel->r_info) == R_386_PC32))
+	      /* If this is a global symbol, we count the number of
+		 relocations we have entered for this symbol, so that
+		 we can discard them later as necessary.  */
+	      if (h != NULL)
 		{
 		  struct elf_i386_link_hash_entry *eh;
 		  struct elf_i386_dyn_relocs *p;
 
 		  eh = (struct elf_i386_link_hash_entry *) h;
-
-		  for (p = eh->dyn_relocs; p != NULL; p = p->next)
-		    if (p->section == sreloc)
-		      break;
+		  p = eh->dyn_relocs;
 
-		  if (p == NULL)
+		  if (p == NULL || p->sec != sec)
 		    {
 		      p = ((struct elf_i386_dyn_relocs *)
 			   bfd_alloc (dynobj, (bfd_size_type) sizeof *p));
@@ -796,11 +795,15 @@ elf_i386_check_relocs (abfd, info, sec, 
 			return false;
 		      p->next = eh->dyn_relocs;
 		      eh->dyn_relocs = p;
-		      p->section = sreloc;
+		      p->sec = sec;
+		      p->sreloc = sreloc;
 		      p->count = 0;
+		      p->pc_count = 0;
 		    }
 
-		  ++p->count;
+		  p->count += 1;
+		  if (ELF32_R_TYPE (rel->r_info) == R_386_PC32)
+		    p->pc_count += 1;
 		}
 	    }
 
@@ -924,9 +927,33 @@ elf_i386_gc_sweep_hook (abfd, info, sec,
 
       case R_386_32:
       case R_386_PC32:
-	if (info->shared)
-	  break;
-	/* Fall through.  */
+	r_symndx = ELF32_R_SYM (rel->r_info);
+	if (r_symndx >= symtab_hdr->sh_info)
+	  {
+	    struct elf_i386_link_hash_entry *eh;
+	    struct elf_i386_dyn_relocs **pp;
+	    struct elf_i386_dyn_relocs *p;
+
+	    h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+
+	    if (!info->shared && h->plt.refcount > 0)
+	      h->plt.refcount -= 1;
+
+	    eh = (struct elf_i386_link_hash_entry *) h;
+
+	    for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next)
+	      if (p->sec == sec)
+		{
+		  p->sreloc->_raw_size -= sizeof (Elf32_External_Rel);
+		  if (ELF32_R_TYPE (rel->r_info) == R_386_PC32)
+		    p->pc_count -= 1;
+		  p->count -= 1;
+		  if (p->count == 0)
+		    *pp = p->next;
+		  break;
+		}
+	  }
+	break;
 
       case R_386_PLT32:
 	r_symndx = ELF32_R_SYM (rel->r_info);
@@ -1100,6 +1127,7 @@ allocate_plt_and_got_and_discard_relocs 
   struct elf_i386_link_hash_table *htab;
   asection *s;
   struct elf_i386_link_hash_entry *eh;
+  struct elf_i386_dyn_relocs *p;
 
   if (h->root.type == bfd_link_hash_indirect
       || h->root.type == bfd_link_hash_warning)
@@ -1191,19 +1219,40 @@ allocate_plt_and_got_and_discard_relocs 
   else
     h->got.offset = (bfd_vma) -1;
 
-  /* In the shared -Bsymbolic case, discard space allocated for
-     dynamic relocs against symbols which turn out to be defined
-     in regular objects.  For the normal shared case, discard space
-     for relocs that have become local due to symbol visibility
-     changes.  For the non-shared case, discard space for symbols
-     which turn out to need copy relocs or are not dynamic.  */
-
   eh = (struct elf_i386_link_hash_entry *) h;
   if (eh->dyn_relocs == NULL)
     return true;
+
+  /* In the shared -Bsymbolic case, discard space allocated for
+     dynamic pc-relative relocs against symbols which turn out to be
+     defined in regular objects.  For the normal shared case, discard
+     space for relocs that have become local due to symbol visibility
+     changes.  */
+
+  if (info->shared)
+    {
+      struct elf_i386_dyn_relocs **pp;
 
-  if (!info->shared
-      && (h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0
+      if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0
+	  && ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0
+	      || info->symbolic))
+	for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
+	  {
+	    p->sreloc->_raw_size -= p->pc_count * sizeof (Elf32_External_Rel);
+	    p->count -= p->pc_count;
+	    p->pc_count = 0;
+	    if (p->count == 0)
+	      *pp = p->next;
+	    else
+	      pp = &p->next;
+	  }
+      return true;
+    }
+
+  /* For the non-shared case, discard space for relocs against symbols
+     which turn out to need copy relocs or are not dynamic.  */
+
+  if ((h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0
       && (((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
 	   && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
 	  || (htab->root.dynamic_sections_created
@@ -1224,17 +1273,39 @@ allocate_plt_and_got_and_discard_relocs 
 	return true;
     }
 
-  if (!info->shared
-      || ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0
-	  && ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0
-	      || info->symbolic)))
+  for (p = eh->dyn_relocs; p != NULL; p = p->next)
+    p->sreloc->_raw_size -= p->count * sizeof (Elf32_External_Rel);
+
+  eh->dyn_relocs = NULL;
+
+  return true;
+}
+
+/* Find any dynamic relocs that apply to read-only sections.  */
+
+static boolean
+readonly_dynrelocs (h, inf)
+     struct elf_link_hash_entry *h;
+     PTR inf;
+{
+  struct elf_i386_link_hash_entry *eh;
+  struct elf_i386_dyn_relocs *p;
+
+  eh = (struct elf_i386_link_hash_entry *) h;
+  for (p = eh->dyn_relocs; p != NULL; p = p->next)
     {
-      struct elf_i386_dyn_relocs *c;
+      asection *s = p->sec->output_section;
 
-      for (c = eh->dyn_relocs; c != NULL; c = c->next)
-	c->section->_raw_size -= c->count * sizeof (Elf32_External_Rel);
-    }
+      if (s != NULL && (s->flags & SEC_READONLY) != 0)
+	{
+	  struct bfd_link_info *info = (struct bfd_link_info *) inf;
 
+	  info->flags |= DF_TEXTREL;
+
+	  /* Not an error, just cut short the traversal.  */
+	  return false;
+	}
+    }
   return true;
 }
 
@@ -1249,7 +1320,7 @@ elf_i386_size_dynamic_sections (output_b
   bfd *dynobj;
   asection *s;
   boolean relocs;
-  bfd *i;
+  bfd *ibfd;
 
   htab = elf_i386_hash_table (info);
   dynobj = htab->root.dynobj;
@@ -1270,7 +1341,7 @@ elf_i386_size_dynamic_sections (output_b
     }
 
   /* Set up .got offsets for local syms.  */
-  for (i = info->input_bfds; i; i = i->link_next)
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
     {
       bfd_signed_vma *local_got;
       bfd_signed_vma *end_local_got;
@@ -1278,14 +1349,14 @@ elf_i386_size_dynamic_sections (output_b
       Elf_Internal_Shdr *symtab_hdr;
       asection *srel;
 
-      if (bfd_get_flavour (i) != bfd_target_elf_flavour)
+      if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
 	continue;
 
-      local_got = elf_local_got_refcounts (i);
+      local_got = elf_local_got_refcounts (ibfd);
       if (!local_got)
 	continue;
 
-      symtab_hdr = &elf_tdata (i)->symtab_hdr;
+      symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
       locsymcount = symtab_hdr->sh_info;
       end_local_got = local_got + locsymcount;
       s = htab->sgot;
@@ -1402,12 +1473,16 @@ elf_i386_size_dynamic_sections (output_b
 	      || !add_dynamic_entry (DT_RELSZ, 0)
 	      || !add_dynamic_entry (DT_RELENT, sizeof (Elf32_External_Rel)))
 	    return false;
-	}
 
-      if ((info->flags & DF_TEXTREL) != 0)
-	{
-	  if (!add_dynamic_entry (DT_TEXTREL, 0))
-	    return false;
+	  /* If any dynamic relocs apply to a read-only section,
+	     then we need a DT_TEXTREL entry.  */
+	  elf_link_hash_traverse (&htab->root, readonly_dynrelocs, (PTR) info);
+
+	  if ((info->flags & DF_TEXTREL) != 0)
+	    {
+	      if (!add_dynamic_entry (DT_TEXTREL, 0))
+		return false;
+	    }
 	}
     }
 #undef add_dynamic_entry


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