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]

PATCH: Avoid unnecessary R_IA64_FPTR64LSB in executable


On Wed, Apr 27, 2005 at 04:43:04PM -0700, H. J. Lu wrote:
> The ia64 linker creates unnecessary R_IA64_FPTR64LSB relocations:
> 
> http://sources.redhat.com/bugzilla/show_bug.cgi?id=883
> 
> Basically, the ia64 linker creates R_IA64_FPTR64LSB relocations in
> executable when there is any reference in DSO even though it is only
> needed for dynamic R_IA64_FPTR64LSB relocations. I have 2 questions:
> 
> 1. When we export a function in executable, whose function pointer is
> used in executable and which is referenced by a DSO, can we create a
> R_IA64_FPTR64LSB in executable only when there is a dynamic
> R_IA64_FPTR64LSB reference? The only problem I can see is the different
> version of the DSO may have dynamic R_IA64_FPTR64LSB reference. But
> I think it is the same problem that the different version of the DSO 
> may reference functions in executable which weren't referenced and
> weren't exported before.
> 2. Assuming, we create a R_IA64_FPTR64LSB in executable only when
> there is a dynamic R_IA64_FPTR64LSB relocation, how does linker
> know there is a dynamic R_IA64_FPTR64LSB relocation? I am thinking to
> allow the backend to read dynamic relocations after all input files
> have been opened. The ia64 backend will have enough information to
> decide what to do.
> 

This is the patch I come up with. I added check_dynamic_relocs to
check dynamic relocations. R_IA64_FPTR64LSB is used for the offical
function descriptors, which can only be accessed by R_IA64_FPTR64LSB.
Before we generate R_IA64_FPTR64LSB in executable, we check if there
are any R_IA64_FPTR64LSB relocations in DSO on that symbol. If there
is none, R_IA64_FPTR64LSB isn't needed.


H.J.
----
2005-04-28  H.J. Lu  <hongjiu.lu@intel.com>

	PR 883
	* elf-bfd.h (elf_backend_data): Add check_dynamic_relocs.

	* elflink.c (elf_link_read_relocs_from_section): Handle dynamic
	relocation.
	(elf_link_add_object_symbols): Call check_dynamic_relocs on
	dynamic library if the backend has check_dynamic_relocs.

	* elfxx-ia64.c (elfNN_ia64_link_hash_entry): Add need_ofd.
	(NEED_OFD): New macro.
	(elfNN_ia64_new_elf_hash_entry): Initialize need_ofd.
	(elfNN_ia64_hash_copy_indirect): Handle need_ofd.
	(elfNN_ia64_check_relocs): Set need_ofd for R_IA64_FPTRXXXXX.
	(elfNN_ia64_check_dynamic_relocs): New function.
	(allocate_fptr): Allocate if NEED_OFD is FALSE.
	(allocate_dynrel_entries): Check NEED_OFD before allocate.
	(elfNN_ia64_relocate_section): Call set_fptr_entry for
	R_IA64_LTOFF_FPTRXXXXX if NEED_OFD is FALSE.
	(elf_backend_check_dynamic_relocs): Defined.

	* elfxx-target.h (elf_backend_check_relocs): New. Provide
	default.
	(elfNN_bed): Initialize check_dynamic_relocs to
	elf_backend_check_relocs.


--- bfd/elf-bfd.h.dyn	2005-04-28 16:03:46.000000000 -0700
+++ bfd/elf-bfd.h	2005-04-28 16:03:47.000000000 -0700
@@ -704,6 +704,17 @@ struct elf_backend_data
     (bfd *abfd, struct bfd_link_info *info, asection *o,
      const Elf_Internal_Rela *relocs);
 
+  /* The CHECK_DYNAMIC_RELOCS function is called by the add_symbols
+     phase of the ELF backend linker.  It is called once for each
+     relocation section of a dynamic library, just after the symbols
+     for the object file have been added to the global linker hash
+     table.  The function must look through the relocs and do any
+     special handling required.  This generally isn't needed.  */
+  bfd_boolean (*check_dynamic_relocs)
+    (bfd *abfd, struct bfd_link_info *info,
+     const Elf_Internal_Shdr *hdr,
+     const Elf_Internal_Rela *relocs);
+
   /* The CHECK_DIRECTIVES function is called once per input file by
      the add_symbols phase of the ELF backend linker.  The function
      must inspect the bfd and create any additional symbols according
--- bfd/elflink.c.dyn	2005-04-28 16:03:47.000000000 -0700
+++ bfd/elflink.c	2005-04-28 16:03:47.000000000 -0700
@@ -2003,6 +2003,7 @@ elf_link_read_relocs_from_section (bfd *
   Elf_Internal_Rela *irela;
   Elf_Internal_Shdr *symtab_hdr;
   size_t nsyms;
+  bfd_boolean dynamic = abfd->flags & DYNAMIC;
 
   /* Position ourselves at the start of the section.  */
   if (bfd_seek (abfd, shdr->sh_offset, SEEK_SET) != 0)
@@ -2012,7 +2013,10 @@ elf_link_read_relocs_from_section (bfd *
   if (bfd_bread (external_relocs, shdr->sh_size, abfd) != shdr->sh_size)
     return FALSE;
 
-  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  if (dynamic)
+    symtab_hdr = &elf_tdata (abfd)->dynsymtab_hdr;
+  else
+    symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
   nsyms = symtab_hdr->sh_size / symtab_hdr->sh_entsize;
 
   bed = get_elf_backend_data (abfd);
@@ -2041,11 +2045,18 @@ elf_link_read_relocs_from_section (bfd *
 	r_symndx >>= 24;
       if ((size_t) r_symndx >= nsyms)
 	{
-	  (*_bfd_error_handler)
-	    (_("%B: bad reloc symbol index (0x%lx >= 0x%lx)"
-	       " for offset 0x%lx in section `%A'"),
-	     abfd, sec,
-	     (unsigned long) r_symndx, (unsigned long) nsyms, irela->r_offset);
+	  if (dynamic)
+	    (*_bfd_error_handler)
+	      (_("%B: bad reloc symbol index (0x%lx >= 0x%lx)"
+		 " for address 0x%lx"),
+	       abfd, (unsigned long) r_symndx,
+	       (unsigned long) nsyms, irela->r_offset);
+	  else
+	    (*_bfd_error_handler)
+	      (_("%B: bad reloc symbol index (0x%lx >= 0x%lx)"
+		 " for offset 0x%lx in section `%A'"),
+	       abfd, sec, (unsigned long) r_symndx,
+	       (unsigned long) nsyms, irela->r_offset);
 	  bfd_set_error (bfd_error_bad_value);
 	  return FALSE;
 	}
@@ -3192,8 +3203,6 @@ elf_link_add_object_symbols (bfd *abfd, 
   bfd_boolean (*add_symbol_hook)
     (bfd *, struct bfd_link_info *, Elf_Internal_Sym *,
      const char **, flagword *, asection **, bfd_vma *);
-  bfd_boolean (*check_relocs)
-    (bfd *, struct bfd_link_info *, asection *, const Elf_Internal_Rela *);
   bfd_boolean (*check_directives)
     (bfd *, struct bfd_link_info *);
   bfd_boolean collect;
@@ -3215,6 +3224,7 @@ elf_link_add_object_symbols (bfd *abfd, 
   bfd_boolean add_needed;
   struct elf_link_hash_table * hash_table;
   bfd_size_type amt;
+  asection *section_list;
 
   hash_table = elf_hash_table (info);
 
@@ -3321,6 +3331,9 @@ elf_link_add_object_symbols (bfd *abfd, 
 	}
     }
 
+  /* Save the section list for check_dynamic_relocs.  */
+  section_list = abfd->sections;
+
   add_needed = TRUE;
   if (! dynamic)
     {
@@ -4437,38 +4450,102 @@ elf_link_add_object_symbols (bfd *abfd, 
 
      I have no idea how to handle linking PIC code into a file of a
      different format.  It probably can't be done.  */
-  check_relocs = get_elf_backend_data (abfd)->check_relocs;
-  if (! dynamic
-      && is_elf_hash_table (hash_table)
-      && hash_table->root.creator == abfd->xvec
-      && check_relocs != NULL)
+  if (is_elf_hash_table (hash_table)
+      && hash_table->root.creator == abfd->xvec)
     {
-      asection *o;
+      if (dynamic)
+	{
+	  bfd_boolean (*check_dynamic_relocs)
+	    (bfd *, struct bfd_link_info *,
+	     const Elf_Internal_Shdr *,
+	     const Elf_Internal_Rela *);
 
-      for (o = abfd->sections; o != NULL; o = o->next)
+	  check_dynamic_relocs
+	    = get_elf_backend_data (abfd)->check_dynamic_relocs;
+	  if (check_dynamic_relocs != NULL)
+	    {
+	      unsigned int i;
+
+	      for (i = 1; i < elf_numsections (abfd); i++)
+		{
+		  Elf_Internal_Shdr *hdr;
+		  Elf_Internal_Rela *internal_relocs;
+		  void *external_relocs;
+		  bfd_boolean ok;
+
+		  hdr = elf_elfsections (abfd)[i];
+		  if (hdr->sh_type != SHT_REL
+		      && hdr->sh_type != SHT_RELA)
+		    continue;
+
+		  internal_relocs = bfd_malloc (NUM_SHDR_ENTRIES (hdr)
+						* bed->s->int_rels_per_ext_rel
+						* sizeof (Elf_Internal_Rela));
+		  if (internal_relocs == NULL)
+		    goto error_return;
+
+		  external_relocs = bfd_malloc (hdr->sh_size);
+		  if (external_relocs == NULL)
+		    {
+		      free (internal_relocs);
+		      goto error_return;
+		    }
+
+		  if (!elf_link_read_relocs_from_section (abfd, NULL,
+							  hdr,
+							  external_relocs,
+							  internal_relocs))
+		    goto error_return;
+
+		  ok = (*check_dynamic_relocs) (abfd, info, hdr,
+						internal_relocs);
+
+		  free (internal_relocs);
+		  free (external_relocs);
+
+		  if (! ok)
+		    goto error_return;
+		}
+	    }
+	}
+      else
 	{
-	  Elf_Internal_Rela *internal_relocs;
-	  bfd_boolean ok;
+	  asection *o;
+	  bfd_boolean (*check_relocs)
+	    (bfd *, struct bfd_link_info *, asection *,
+	     const Elf_Internal_Rela *);
 
-	  if ((o->flags & SEC_RELOC) == 0
-	      || o->reloc_count == 0
-	      || ((info->strip == strip_all || info->strip == strip_debugger)
-		  && (o->flags & SEC_DEBUGGING) != 0)
-	      || bfd_is_abs_section (o->output_section))
-	    continue;
+	  check_relocs = get_elf_backend_data (abfd)->check_relocs;
+	  if (check_relocs != NULL)
+	    {
+	      for (o = section_list; o != NULL; o = o->next)
+		{
+		  Elf_Internal_Rela *internal_relocs;
+		  bfd_boolean ok;
 
-	  internal_relocs = _bfd_elf_link_read_relocs (abfd, o, NULL, NULL,
-						       info->keep_memory);
-	  if (internal_relocs == NULL)
-	    goto error_return;
+		  if ((o->flags & SEC_RELOC) == 0
+		      || o->reloc_count == 0
+		      || ((info->strip == strip_all
+			   || info->strip == strip_debugger)
+			  && (o->flags & SEC_DEBUGGING) != 0)
+		      || bfd_is_abs_section (o->output_section))
+		    continue;
 
-	  ok = (*check_relocs) (abfd, info, o, internal_relocs);
+		  internal_relocs
+		    = _bfd_elf_link_read_relocs (abfd, o, NULL, NULL,
+						 info->keep_memory);
+		  if (internal_relocs == NULL)
+		    goto error_return;
 
-	  if (elf_section_data (o)->relocs != internal_relocs)
-	    free (internal_relocs);
+		  ok = (*check_relocs) (abfd, info, o, internal_relocs);
 
-	  if (! ok)
-	    goto error_return;
+		  if (elf_section_data (o)->relocs != internal_relocs)
+		    free (internal_relocs);
+
+		  if (! ok)
+		    goto error_return;
+		}
+	    }
 	}
     }
 
--- bfd/elfxx-ia64.c.dyn	2005-04-28 16:03:46.000000000 -0700
+++ bfd/elfxx-ia64.c	2005-04-28 16:19:36.000000000 -0700
@@ -144,8 +144,15 @@ struct elfNN_ia64_link_hash_entry
 {
   struct elf_link_hash_entry root;
   struct elfNN_ia64_dyn_sym_info *info;
+  /* If this symbol needs the official function descriptor.  */
+  unsigned need_ofd : 1;
 };
 
+#define NEED_OFD(info, h) \
+   (((struct elfNN_ia64_link_hash_entry *)(h))->need_ofd	\
+    || !(info)->executable					\
+    || !SYMBOL_CALLS_LOCAL ((info), (h)))
+
 struct elfNN_ia64_link_hash_table
 {
   /* The main hash table.  */
@@ -1639,6 +1646,7 @@ elfNN_ia64_new_elf_hash_entry (entry, ta
 				     table, string));
 
   ret->info = NULL;
+  ret->need_ofd = 0;
   return (struct bfd_hash_entry *) ret;
 }
 
@@ -1689,6 +1697,8 @@ elfNN_ia64_hash_copy_indirect (bed, xdir
       ind->root.dynstr_index = 0;
     }
   BFD_ASSERT (ind->root.dynindx == -1);
+
+  dir->need_ofd |= ind->need_ofd;
 }
 
 static void
@@ -2321,7 +2331,11 @@ elfNN_ia64_check_relocs (abfd, info, sec
 	case R_IA64_FPTR64MSB:
 	case R_IA64_FPTR64LSB:
 	  if (info->shared || h)
-	    need_entry = NEED_FPTR | NEED_DYNREL;
+	    {
+	      need_entry = NEED_FPTR | NEED_DYNREL;
+	      if (h)
+		((struct elfNN_ia64_link_hash_entry *)h)->need_ofd = 1;
+	    }
 	  else
 	    need_entry = NEED_FPTR;
 	  dynrel_type = R_IA64_FPTRNNLSB;
@@ -2496,6 +2510,83 @@ elfNN_ia64_check_relocs (abfd, info, sec
   return TRUE;
 }
 
+static bfd_boolean
+elfNN_ia64_check_dynamic_relocs (bfd *abfd,
+				 struct bfd_link_info *info,
+				 const Elf_Internal_Shdr *hdr,
+				 const Elf_Internal_Rela *relocs)
+{
+  struct elfNN_ia64_link_hash_table *ia64_info;
+  const Elf_Internal_Rela *relend;
+  Elf_Internal_Shdr *symtab_hdr;
+  const Elf_Internal_Rela *rel;
+
+  if (info->relocatable)
+    return TRUE;
+
+  symtab_hdr = &elf_tdata (abfd)->dynsymtab_hdr;
+  ia64_info = elfNN_ia64_hash_table (info);
+
+  relend = relocs + NUM_SHDR_ENTRIES (hdr);
+  for (rel = relocs; rel < relend; ++rel)
+    {
+      unsigned long r_symndx = ELFNN_R_SYM (rel->r_info);
+      unsigned int r_type;
+      reloc_howto_type *howto;
+      long indx;
+
+      r_type = ELFNN_R_TYPE (rel->r_info);
+      switch (r_type)
+	{
+	case R_IA64_NONE:
+	case R_IA64_DIR32MSB:
+	case R_IA64_DIR32LSB:
+	case R_IA64_DIR64MSB:
+	case R_IA64_DIR64LSB:
+	case R_IA64_DTPMOD64MSB:
+	case R_IA64_DTPMOD64LSB:
+	case R_IA64_IPLTLSB:
+	case R_IA64_IPLTMSB:
+	case R_IA64_REL32MSB:
+	case R_IA64_REL32LSB:
+	case R_IA64_REL64MSB:
+	case R_IA64_REL64LSB:
+	case R_IA64_TPREL64MSB:
+	case R_IA64_TPREL64LSB:
+	  break;
+
+	case R_IA64_FPTR64I:
+	case R_IA64_FPTR32MSB:
+	case R_IA64_FPTR32LSB:
+	case R_IA64_FPTR64MSB:
+	case R_IA64_FPTR64LSB:
+	  indx = r_symndx - symtab_hdr->sh_info;
+
+	  if (indx >= 0)
+	    {
+	      struct elf_link_hash_entry *h;
+
+	      h = elf_sym_hashes (abfd)[indx];
+	      while (h->root.type == bfd_link_hash_indirect
+		     || h->root.type == bfd_link_hash_warning)
+		h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+	      ((struct elfNN_ia64_link_hash_entry *)h)->need_ofd = 1;
+	    }
+	  break;
+
+	default:
+	  howto = lookup_howto (r_type);
+	  (*_bfd_error_handler)
+	    (_("%B: unsupported dynamic relocation `%s' in `%A'."),
+	     abfd, hdr->bfd_section, howto->name);
+	  break;
+	}
+    }
+
+  return TRUE;
+}
+
 /* For cleanliness, and potentially faster dynamic loading, allocate
    external GOT entries first.  */
 
@@ -2639,7 +2730,7 @@ allocate_fptr (dyn_i, data)
 
 	  dyn_i->want_fptr = 0;
 	}
-      else if (h == NULL || h->dynindx == -1)
+      else if (h == NULL || h->dynindx == -1 || !NEED_OFD (x->info, h))
 	{
 	  dyn_i->fptr_offset = x->ofs;
 	  x->ofs += 16;
@@ -2811,7 +2902,8 @@ allocate_dynrel_entries (dyn_i, data)
        && (dyn_i->want_got || dyn_i->want_gotx))
       || (dyn_i->want_ltoff_fptr
 	  && dyn_i->h
-	  && dyn_i->h->dynindx != -1))
+	  && dyn_i->h->dynindx != -1
+	  && NEED_OFD (x->info, dyn_i->h)))
     {
       if (!dyn_i->want_ltoff_fptr
 	  || !x->info->pie
@@ -4224,7 +4316,9 @@ elfNN_ia64_relocate_section (output_bfd,
 	    dyn_i = get_dyn_sym_info (ia64_info, h, input_bfd, rel, FALSE);
 	    if (dyn_i->want_fptr)
 	      {
-		BFD_ASSERT (h == NULL || h->dynindx == -1);
+		BFD_ASSERT (h == NULL
+			    || h->dynindx == -1
+			    || !NEED_OFD (info, h));
 	        if (!undef_weak_ref)
 	          value = set_fptr_entry (output_bfd, info, dyn_i, value);
 		dynindx = -1;
@@ -5111,6 +5205,8 @@ elfNN_hpux_backend_symbol_processing (bf
 	elfNN_ia64_create_dynamic_sections
 #define elf_backend_check_relocs \
 	elfNN_ia64_check_relocs
+#define elf_backend_check_dynamic_relocs \
+	elfNN_ia64_check_dynamic_relocs
 #define elf_backend_adjust_dynamic_symbol \
 	elfNN_ia64_adjust_dynamic_symbol
 #define elf_backend_size_dynamic_sections \
--- bfd/elfxx-target.h.dyn	2005-03-02 11:54:22.000000000 -0800
+++ bfd/elfxx-target.h	2005-04-28 16:03:47.000000000 -0700
@@ -355,6 +355,9 @@
 #ifndef elf_backend_check_relocs
 #define elf_backend_check_relocs	0
 #endif
+#ifndef elf_backend_check_dynamic_relocs
+#define elf_backend_check_dynamic_relocs 0
+#endif
 #ifndef elf_backend_check_directives
 #define elf_backend_check_directives	0
 #endif
@@ -548,6 +551,7 @@ static const struct elf_backend_data elf
   elf_backend_create_dynamic_sections,
   elf_backend_omit_section_dynsym,
   elf_backend_check_relocs,
+  elf_backend_check_dynamic_relocs,
   elf_backend_check_directives,
   elf_backend_adjust_dynamic_symbol,
   elf_backend_always_size_sections,


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