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]

PATCH: More generic STT_GNU_IFUNC support


Hi,

I am checking this generic STT_GNU_IFUNC support.


H.J.
---
2009-06-17  H.J. Lu  <hongjiu.lu@intel.com>

	* elf-bfd.h (_bfd_elf_allocate_ifunc_dyn_relocs): New.
	* elf-ifunc.c (_bfd_elf_allocate_ifunc_dyn_relocs): Likewise.
	* elf32-i386.c (elf_i386_allocate_dynrelocs): Use it.
	* elf64-x86-64.c (elf64_x86_64_allocate_dynrelocs): Likewise.

2009-06-17  H.J. Lu  <hongjiu.lu@intel.com>

	* elf-bfd.h (_bfd_elf_create_ifunc_dyn_reloc): New.
	* elf-ifunc.c (_bfd_elf_create_ifunc_dyn_reloc): Likewise.
	* elf32-i386.c (elf_i386_check_relocs): Use it.
	* elf64-x86-64.c (elf64_x86_64_check_relocs): Likewise.

2009-06-17  H.J. Lu  <hongjiu.lu@intel.com>

	* elf-bfd.h (elf_dyn_relocs): New.

	* elf32-i386.c (elf_i386_dyn_relocs): Removed.
	(elf_i386_link_hash_entry): Replace elf_i386_dyn_relocs with
	elf_dyn_relocs.
	(elf_i386_copy_indirect_symbol): Likewise.
	(elf_i386_check_relocs): Likewise.
	(elf_i386_gc_sweep_hook): Likewise.
	(elf_i386_allocate_dynrelocs): Likewise.
	(elf_i386_readonly_dynrelocs): Likewise.
	(elf_i386_size_dynamic_sections): Likewise.

	* elf64-x86-64.c (elf64_x86_64_dyn_relocs): Removed.
	(elf64_x86_64_link_hash_entry): Replace elf64_x86_64_dyn_relocs
	with elf_dyn_relocs.
	(elf64_x86_64_copy_indirect_symbol): Updated.
	(elf64_x86_64_check_relocs): Likewise.
	(elf64_x86_64_gc_sweep_hook): Likewise.
	(elf64_x86_64_adjust_dynamic_symbol): Likewise.
	(elf64_x86_64_allocate_dynrelocs): Likewise.
	(elf64_x86_64_readonly_dynrelocs): Likewise.
	(elf64_x86_64_size_dynamic_sections): Likewise.

diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc \
		../binutils/src binutils
diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/bfd/elf32-i386.c binutils/bfd/elf32-i386.c
--- ../binutils/src/bfd/elf32-i386.c	2009-06-16 10:45:43.000000000 -0700
+++ binutils/bfd/elf32-i386.c	2009-06-17 17:39:40.000000000 -0700
@@ -577,26 +577,6 @@ static const bfd_byte elf_i386_pic_plt_e
 #define PLTRESOLVE_RELOCS 2
 #define PLT_NON_JUMP_SLOT_RELOCS 2
 
-/* The i386 linker needs to keep track of the number of relocs that it
-   decides to copy as dynamic relocs in check_relocs for each symbol.
-   This is so that it can later discard them if they are found to be
-   unnecessary.  We store the information in a field extending the
-   regular ELF linker hash table.  */
-
-struct elf_i386_dyn_relocs
-{
-  struct elf_i386_dyn_relocs *next;
-
-  /* The input section of the reloc.  */
-  asection *sec;
-
-  /* Total number of relocs copied for the input section.  */
-  bfd_size_type count;
-
-  /* Number of pc-relative relocs copied for the input section.  */
-  bfd_size_type pc_count;
-};
-
 /* i386 ELF linker hash entry.  */
 
 struct elf_i386_link_hash_entry
@@ -604,7 +584,7 @@ struct elf_i386_link_hash_entry
   struct elf_link_hash_entry elf;
 
   /* Track dynamic relocs copied for this symbol.  */
-  struct elf_i386_dyn_relocs *dyn_relocs;
+  struct elf_dyn_relocs *dyn_relocs;
 
 #define GOT_UNKNOWN	0
 #define GOT_NORMAL	1
@@ -919,14 +899,14 @@ elf_i386_copy_indirect_symbol (struct bf
     {
       if (edir->dyn_relocs != NULL)
 	{
-	  struct elf_i386_dyn_relocs **pp;
-	  struct elf_i386_dyn_relocs *p;
+	  struct elf_dyn_relocs **pp;
+	  struct elf_dyn_relocs *p;
 
 	  /* Add reloc counts against the indirect sym to the direct sym
 	     list.  Merge any entries against the same section.  */
 	  for (pp = &eind->dyn_relocs; (p = *pp) != NULL; )
 	    {
-	      struct elf_i386_dyn_relocs *q;
+	      struct elf_dyn_relocs *q;
 
 	      for (q = edir->dyn_relocs; q != NULL; q = q->next)
 		if (q->sec == p->sec)
@@ -1407,39 +1387,14 @@ elf_i386_check_relocs (bfd *abfd,
 		  h->pointer_equality_needed = 1;
 		  if (info->shared)
 		    {
-		      struct elf_i386_dyn_relocs *p;
-		      struct elf_i386_dyn_relocs **head;
-
 		      /* We must copy these reloc types into the
 			 output file.  Create a reloc section in
 			 dynobj and make room for this reloc.  */
+		      sreloc = _bfd_elf_create_ifunc_dyn_reloc
+			(abfd, info, sec, sreloc,
+			 &((struct elf_i386_link_hash_entry *) h)->dyn_relocs);
 		      if (sreloc == NULL)
-			{
-			  if (htab->elf.dynobj == NULL)
-			    htab->elf.dynobj = abfd;
-
-			  sreloc = _bfd_elf_make_dynamic_reloc_section
-			    (sec, htab->elf.dynobj, 2, abfd, FALSE);
-
-			  if (sreloc == NULL)
-			    return FALSE;
-			}
-
-		      head = &((struct elf_i386_link_hash_entry *) h)->dyn_relocs;
-		      p = *head;
-		      if (p == NULL || p->sec != sec)
-			{
-			  bfd_size_type amt = sizeof *p;
-			  p = bfd_alloc (htab->elf.dynobj, amt);
-			  if (p == NULL)
-			    return FALSE;
-			  p->next = *head;
-			  *head = p;
-			  p->sec = sec;
-			  p->count = 0;
-			  p->pc_count = 0;
-			}
-		      p->count += 1;
+			return FALSE;
 		    }
 		  break;
 
@@ -1669,8 +1624,8 @@ elf_i386_check_relocs (bfd *abfd,
 		  && (h->root.type == bfd_link_hash_defweak
 		      || !h->def_regular)))
 	    {
-	      struct elf_i386_dyn_relocs *p;
-	      struct elf_i386_dyn_relocs **head;
+	      struct elf_dyn_relocs *p;
+	      struct elf_dyn_relocs **head;
 
 	      /* We must copy these reloc types into the output file.
 		 Create a reloc section in dynobj and make room for
@@ -1707,7 +1662,7 @@ elf_i386_check_relocs (bfd *abfd,
 		    return FALSE;
 
 		  vpp = &elf_section_data (s)->local_dynrel;
-		  head = (struct elf_i386_dyn_relocs **)vpp;
+		  head = (struct elf_dyn_relocs **)vpp;
 		}
 
 	      p = *head;
@@ -1808,8 +1763,8 @@ elf_i386_gc_sweep_hook (bfd *abfd,
       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;
+	  struct elf_dyn_relocs **pp;
+	  struct elf_dyn_relocs *p;
 
 	  h = sym_hashes[r_symndx - symtab_hdr->sh_info];
 	  while (h->root.type == bfd_link_hash_indirect
@@ -1980,7 +1935,7 @@ elf_i386_adjust_dynamic_symbol (struct b
   if (ELIMINATE_COPY_RELOCS && !htab->is_vxworks)
     {
       struct elf_i386_link_hash_entry * eh;
-      struct elf_i386_dyn_relocs *p;
+      struct elf_dyn_relocs *p;
 
       eh = (struct elf_i386_link_hash_entry *) h;
       for (p = eh->dyn_relocs; p != NULL; p = p->next)
@@ -2037,7 +1992,7 @@ elf_i386_allocate_dynrelocs (struct elf_
   struct bfd_link_info *info;
   struct elf_i386_link_hash_table *htab;
   struct elf_i386_link_hash_entry *eh;
-  struct elf_i386_dyn_relocs *p;
+  struct elf_dyn_relocs *p;
 
   if (h->root.type == bfd_link_hash_indirect)
     return TRUE;
@@ -2056,123 +2011,9 @@ elf_i386_allocate_dynrelocs (struct elf_
      here if it is defined and referenced in a non-shared object.  */
   if (h->type == STT_GNU_IFUNC
       && h->def_regular)
-    {
-      asection *plt, *gotplt, *relplt;
-
-      /* When a shared library references a STT_GNU_IFUNC symbol
-	 defined in executable, the address of the resolved function
-	 may be used.  But in non-shared executable, the address of
-	 its .plt slot may be used.  Pointer equality may not work
-	 correctly.  PIE should be used if pointer equality is
-	 required here.  */
-      if (!info->shared
-	  && (h->dynindx != -1
-	      || info->export_dynamic)
-	  && h->pointer_equality_needed)
-	{
-	  info->callbacks->einfo 
-	    (_("%F%P: dynamic STT_GNU_IFUNC symbol `%s' with pointer "
-	       "equality in `%B' can not be used when making an "
-	       "executable; recompile with -fPIE and relink with -pie\n"),
-	     h->root.root.string,
-	     h->root.u.def.section->owner);
-	  bfd_set_error (bfd_error_bad_value);
-	  return FALSE;
-	}
-
-      /* Return and discard space for dynamic relocations against it if
-	 it is never referenced in a non-shared object.  */
-      if (!h->ref_regular)
-	{
-	  if (h->plt.refcount > 0
-	      || h->got.refcount > 0)
-	    abort ();
-	  h->got.offset = (bfd_vma) -1;
-	  eh->dyn_relocs = NULL;
-	  return TRUE;
-	}
-
-      /* When building a static executable, use .iplt, .igot.plt and
-	 .rel.iplt sections for STT_GNU_IFUNC symbols.  */
-      if (htab->elf.splt != NULL)
-	{
-	  plt = htab->elf.splt;
-	  gotplt = htab->elf.sgotplt;
-	  relplt = htab->elf.srelplt;
-	  
-	  /* If this is the first .plt entry, make room for the special
-	     first entry.  */
-	  if (plt->size == 0)
-	    plt->size += PLT_ENTRY_SIZE;
-	}
-      else
-	{
-	  plt = htab->elf.iplt;
-	  gotplt = htab->elf.igotplt;
-	  relplt = htab->elf.irelplt;
-	}
-
-      /* Don't update value of STT_GNU_IFUNC symbol to PLT.  We need
-	 the original value for R_386_IRELATIVE.  */  
-      h->plt.offset = plt->size;
-
-      /* Make room for this entry in the .plt/.iplt section.  */
-      plt->size += PLT_ENTRY_SIZE;
-
-      /* We also need to make an entry in the .got.plt/.got.iplt
-	 section, which will be placed in the .got section by the
-	 linker script.  */
-      gotplt->size += 4;
-
-      /* We also need to make an entry in the .rela.plt/.rela.iplt
-	 section.  */
-      relplt->size += sizeof (Elf32_External_Rel);
-      relplt->reloc_count++;
-
-      /* We need dynamic relocation for STT_GNU_IFUNC symbol only
-	 when there is a non-GOT reference in a shared object.  */
-      if (!info->shared
-	  || !h->non_got_ref)
-	eh->dyn_relocs = NULL;
-
-      /* Finally, allocate space.  */
-      for (p = eh->dyn_relocs; p != NULL; p = p->next)
-	htab->elf.irelifunc->size += p->count * sizeof (Elf32_External_Rel);
-
-      /* For STT_GNU_IFUNC symbol, .got.plt has the real function
-	 addres and .got has the PLT entry adddress.  We will load
-	 the GOT entry with the PLT entry in finish_dynamic_symbol if
-	 it is used.  For branch, it uses .got.plt.  For symbol value,
-	 1. Use .got.plt in a shared object if it is forced local or
-	 not dynamic.
-	 2. Use .got.plt in a non-shared object if pointer equality 
-	 isn't needed.
-	 3. Use .got.plt in PIE.
-	 4. Use .got.plt if .got isn't used.
-	 5. Otherwise use .got so that it can be shared among different
-	 objects at run-time.
-	 We only need to relocate .got entry in shared object.  */
-      if ((info->shared
-	   && (h->dynindx == -1
-	       || h->forced_local))
-	  || (!info->shared
-	      && !h->pointer_equality_needed)
-	  || (info->executable && info->shared)
-	  || htab->elf.sgot == NULL)
-	{
-	  /* Use .got.plt.  */
-	  h->got.offset = (bfd_vma) -1;
-	}
-      else
-	{
-	  h->got.offset = htab->elf.sgot->size;
-	  htab->elf.sgot->size += 4;
-	  if (info->shared)
-	    htab->elf.srelgot->size += sizeof (Elf32_External_Rel);
-	}
-
-      return TRUE;
-    }
+    return _bfd_elf_allocate_ifunc_dyn_relocs (info, h,
+					       &eh->dyn_relocs,
+					       PLT_ENTRY_SIZE, 4);
   else if (htab->elf.dynamic_sections_created
 	   && h->plt.refcount > 0)
     {
@@ -2337,7 +2178,7 @@ elf_i386_allocate_dynrelocs (struct elf_
 	 should avoid writing assembly like ".long foo - .".  */
       if (SYMBOL_CALLS_LOCAL (info, h))
 	{
-	  struct elf_i386_dyn_relocs **pp;
+	  struct elf_dyn_relocs **pp;
 
 	  for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
 	    {
@@ -2352,7 +2193,7 @@ elf_i386_allocate_dynrelocs (struct elf_
 
       if (htab->is_vxworks)
 	{
-	  struct elf_i386_dyn_relocs **pp;
+	  struct elf_dyn_relocs **pp;
 	  for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
 	    {
 	      if (strcmp (p->sec->output_section->name, ".tls_vars") == 0)
@@ -2452,7 +2293,7 @@ static bfd_boolean
 elf_i386_readonly_dynrelocs (struct elf_link_hash_entry *h, void *inf)
 {
   struct elf_i386_link_hash_entry *eh;
-  struct elf_i386_dyn_relocs *p;
+  struct elf_dyn_relocs *p;
 
   if (h->root.type == bfd_link_hash_warning)
     h = (struct elf_link_hash_entry *) h->root.u.i.link;
@@ -2522,9 +2363,9 @@ elf_i386_size_dynamic_sections (bfd *out
 
       for (s = ibfd->sections; s != NULL; s = s->next)
 	{
-	  struct elf_i386_dyn_relocs *p;
+	  struct elf_dyn_relocs *p;
 
-	  for (p = ((struct elf_i386_dyn_relocs *)
+	  for (p = ((struct elf_dyn_relocs *)
 		     elf_section_data (s)->local_dynrel);
 	       p != NULL;
 	       p = p->next)
diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/bfd/elf64-x86-64.c binutils/bfd/elf64-x86-64.c
--- ../binutils/src/bfd/elf64-x86-64.c	2009-06-16 10:45:46.000000000 -0700
+++ binutils/bfd/elf64-x86-64.c	2009-06-17 17:39:40.000000000 -0700
@@ -396,27 +396,6 @@ static const bfd_byte elf64_x86_64_plt_e
   0, 0, 0, 0	/* replaced with offset to start of .plt0.  */
 };
 
-/* The x86-64 linker needs to keep track of the number of relocs that
-   it decides to copy as dynamic relocs in check_relocs for each symbol.
-   This is so that it can later discard them if they are found to be
-   unnecessary.  We store the information in a field extending the
-   regular ELF linker hash table.  */
-
-struct elf64_x86_64_dyn_relocs
-{
-  /* Next section.  */
-  struct elf64_x86_64_dyn_relocs *next;
-
-  /* The input section of the reloc.  */
-  asection *sec;
-
-  /* Total number of relocs copied for the input section.  */
-  bfd_size_type count;
-
-  /* Number of pc-relative relocs copied for the input section.  */
-  bfd_size_type pc_count;
-};
-
 /* x86-64 ELF linker hash entry.  */
 
 struct elf64_x86_64_link_hash_entry
@@ -424,7 +403,7 @@ struct elf64_x86_64_link_hash_entry
   struct elf_link_hash_entry elf;
 
   /* Track dynamic relocs copied for this symbol.  */
-  struct elf64_x86_64_dyn_relocs *dyn_relocs;
+  struct elf_dyn_relocs *dyn_relocs;
 
 #define GOT_UNKNOWN	0
 #define GOT_NORMAL	1
@@ -726,14 +705,14 @@ elf64_x86_64_copy_indirect_symbol (struc
     {
       if (edir->dyn_relocs != NULL)
 	{
-	  struct elf64_x86_64_dyn_relocs **pp;
-	  struct elf64_x86_64_dyn_relocs *p;
+	  struct elf_dyn_relocs **pp;
+	  struct elf_dyn_relocs *p;
 
 	  /* Add reloc counts against the indirect sym to the direct sym
 	     list.  Merge any entries against the same section.  */
 	  for (pp = &eind->dyn_relocs; (p = *pp) != NULL; )
 	    {
-	      struct elf64_x86_64_dyn_relocs *q;
+	      struct elf_dyn_relocs *q;
 
 	      for (q = edir->dyn_relocs; q != NULL; q = q->next)
 		if (q->sec == p->sec)
@@ -1192,41 +1171,14 @@ elf64_x86_64_check_relocs (bfd *abfd, st
 		  h->pointer_equality_needed = 1;
 		  if (info->shared)
 		    {
-		      struct elf64_x86_64_dyn_relocs *p;
-		      struct elf64_x86_64_dyn_relocs **head;
-
 		      /* We must copy these reloc types into the output
 			 file.  Create a reloc section in dynobj and
 			 make room for this reloc.  */
+		      sreloc = _bfd_elf_create_ifunc_dyn_reloc
+			(abfd, info, sec, sreloc,
+			 &((struct elf64_x86_64_link_hash_entry *) h)->dyn_relocs);
 		      if (sreloc == NULL)
-			{
-			  if (htab->elf.dynobj == NULL)
-			    htab->elf.dynobj = abfd;
-
-			  sreloc = _bfd_elf_make_dynamic_reloc_section
-			    (sec, htab->elf.dynobj, 3, abfd, TRUE);
-
-			  if (sreloc == NULL)
-			    return FALSE;
-			}
-		      
-		      head = &((struct elf64_x86_64_link_hash_entry *) h)->dyn_relocs;
-		      p = *head;
-		      if (p == NULL || p->sec != sec)
-			{
-			  bfd_size_type amt = sizeof *p;
-
-			  p = ((struct elf64_x86_64_dyn_relocs *)
-			       bfd_alloc (htab->elf.dynobj, amt));
-			  if (p == NULL)
-			    return FALSE;
-			  p->next = *head;
-			  *head = p;
-			  p->sec = sec;
-			  p->count = 0;
-			  p->pc_count = 0;
-			}
-		      p->count += 1;
+			return FALSE;
 		    }
 		  break;
 
@@ -1500,8 +1452,8 @@ elf64_x86_64_check_relocs (bfd *abfd, st
 		  && (h->root.type == bfd_link_hash_defweak
 		      || !h->def_regular)))
 	    {
-	      struct elf64_x86_64_dyn_relocs *p;
-	      struct elf64_x86_64_dyn_relocs **head;
+	      struct elf_dyn_relocs *p;
+	      struct elf_dyn_relocs **head;
 
 	      /* We must copy these reloc types into the output file.
 		 Create a reloc section in dynobj and make room for
@@ -1540,7 +1492,7 @@ elf64_x86_64_check_relocs (bfd *abfd, st
 		  /* Beware of type punned pointers vs strict aliasing
 		     rules.  */
 		  vpp = &(elf_section_data (s)->local_dynrel);
-		  head = (struct elf64_x86_64_dyn_relocs **)vpp;
+		  head = (struct elf_dyn_relocs **)vpp;
 		}
 
 	      p = *head;
@@ -1548,7 +1500,7 @@ elf64_x86_64_check_relocs (bfd *abfd, st
 		{
 		  bfd_size_type amt = sizeof *p;
 
-		  p = ((struct elf64_x86_64_dyn_relocs *)
+		  p = ((struct elf_dyn_relocs *)
 		       bfd_alloc (htab->elf.dynobj, amt));
 		  if (p == NULL)
 		    return FALSE;
@@ -1642,8 +1594,8 @@ elf64_x86_64_gc_sweep_hook (bfd *abfd, s
       if (r_symndx >= symtab_hdr->sh_info)
 	{
 	  struct elf64_x86_64_link_hash_entry *eh;
-	  struct elf64_x86_64_dyn_relocs **pp;
-	  struct elf64_x86_64_dyn_relocs *p;
+	  struct elf_dyn_relocs **pp;
+	  struct elf_dyn_relocs *p;
 
 	  h = sym_hashes[r_symndx - symtab_hdr->sh_info];
 	  while (h->root.type == bfd_link_hash_indirect
@@ -1820,7 +1772,7 @@ elf64_x86_64_adjust_dynamic_symbol (stru
   if (ELIMINATE_COPY_RELOCS)
     {
       struct elf64_x86_64_link_hash_entry * eh;
-      struct elf64_x86_64_dyn_relocs *p;
+      struct elf_dyn_relocs *p;
 
       eh = (struct elf64_x86_64_link_hash_entry *) h;
       for (p = eh->dyn_relocs; p != NULL; p = p->next)
@@ -1881,7 +1833,7 @@ elf64_x86_64_allocate_dynrelocs (struct 
   struct bfd_link_info *info;
   struct elf64_x86_64_link_hash_table *htab;
   struct elf64_x86_64_link_hash_entry *eh;
-  struct elf64_x86_64_dyn_relocs *p;
+  struct elf_dyn_relocs *p;
 
   if (h->root.type == bfd_link_hash_indirect)
     return TRUE;
@@ -1897,124 +1849,10 @@ elf64_x86_64_allocate_dynrelocs (struct 
      here if it is defined and referenced in a non-shared object.  */
   if (h->type == STT_GNU_IFUNC
       && h->def_regular)
-    {
-      asection *plt, *gotplt, *relplt;
-
-      /* When a shared library references a STT_GNU_IFUNC symbol
-	 defined in executable, the address of the resolved function
-	 may be used.  But in non-shared executable, the address of
-	 its .plt slot may be used.  Pointer equality may not work
-	 correctly.  PIE should be used if pointer equality is
-	 required here.  */
-      if (!info->shared
-	  && (h->dynindx != -1
-	      || info->export_dynamic)
-	  && h->pointer_equality_needed)
-	{
-	  info->callbacks->einfo 
-	    (_("%F%P: dynamic STT_GNU_IFUNC symbol `%s' with pointer "
-	       "equality in `%B' can not be used when making an "
-	       "executable; recompile with -fPIE and relink with -pie\n"),
-	     h->root.root.string,
-	     h->root.u.def.section->owner);
-	  bfd_set_error (bfd_error_bad_value);
-	  return FALSE;
-	}
-
-      /* Return and discard space for dynamic relocations against it if
-	 it is never referenced in a non-shared object.  */
-      if (!h->ref_regular)
-	{
-	  if (h->plt.refcount > 0
-	      || h->got.refcount > 0)
-	    abort ();
-	  h->got.offset = (bfd_vma) -1;
-	  eh->dyn_relocs = NULL;
-	  return TRUE;
-	}
-
-      /* When building a static executable, use .iplt, .igot.plt and
-	 .rela.iplt sections for STT_GNU_IFUNC symbols.  */
-      if (htab->elf.splt != NULL)
-	{
-	  plt = htab->elf.splt;
-	  gotplt = htab->elf.sgotplt;
-	  relplt = htab->elf.srelplt;
-	  
-	  /* If this is the first .plt entry, make room for the special
-	     first entry.  */
-	  if (plt->size == 0)
-	    plt->size += PLT_ENTRY_SIZE;
-	}
-      else
-	{
-	  plt = htab->elf.iplt;
-	  gotplt = htab->elf.igotplt;
-	  relplt = htab->elf.irelplt;
-	}
-
-      /* Don't update value of STT_GNU_IFUNC symbol to PLT.  We need
-	 the original value for R_X86_64_IRELATIVE.  */  
-      h->plt.offset = plt->size;
-
-      /* Make room for this entry in the .plt/.iplt section.  */
-      plt->size += PLT_ENTRY_SIZE;
-
-      /* We also need to make an entry in the .got.plt/.got.iplt
-	 section, which will be placed in the .got section by the
-	 linker script.  */
-      gotplt->size += GOT_ENTRY_SIZE;
-
-      /* We also need to make an entry in the .rela.plt/.rela.iplt
-	 section.  */
-      relplt->size += sizeof (Elf64_External_Rela);
-      relplt->reloc_count++;
-
-      /* We need dynamic relocation for STT_GNU_IFUNC symbol only
-	 when there is a non-GOT reference in a shared object.  */
-      if (!info->shared
-	  || !h->non_got_ref)
-	eh->dyn_relocs = NULL;
-
-      /* Finally, allocate space.  */
-      for (p = eh->dyn_relocs; p != NULL; p = p->next)
-	htab->elf.irelifunc->size
-	  += p->count * sizeof (Elf64_External_Rela);
-
-      /* For STT_GNU_IFUNC symbol, .got.plt has the real function
-	 addres and .got has the PLT entry adddress.  We will load
-	 the GOT entry with the PLT entry in finish_dynamic_symbol if
-	 it is used.  For branch, it uses .got.plt.  For symbol value,
-	 1. Use .got.plt in a shared object if it is forced local or
-	 not dynamic.
-	 2. Use .got.plt in a non-shared object if pointer equality 
-	 isn't needed.
-	 3. Use .got.plt in PIE.
-	 4. Use .got.plt if .got isn't used.
-	 5. Otherwise use .got so that it can be shared among different
-	 objects at run-time.
-	 We only need to relocate .got entry in shared object.  */
-      if ((info->shared
-	   && (h->dynindx == -1
-	       || h->forced_local))
-	  || (!info->shared
-	      && !h->pointer_equality_needed)
-	  || (info->executable && info->shared)
-	  || htab->elf.sgot == NULL)
-	{
-	  /* Use .got.plt.  */
-	  h->got.offset = (bfd_vma) -1;
-	}
-      else
-	{
-	  h->got.offset = htab->elf.sgot->size;
-	  htab->elf.sgot->size += GOT_ENTRY_SIZE;
-	  if (info->shared)
-	    htab->elf.srelgot->size += sizeof (Elf64_External_Rela);
-	}
-
-      return TRUE;
-    }
+    return _bfd_elf_allocate_ifunc_dyn_relocs (info, h,
+					       &eh->dyn_relocs,
+					       PLT_ENTRY_SIZE,
+					       GOT_ENTRY_SIZE);
   else if (htab->elf.dynamic_sections_created
 	   && h->plt.refcount > 0)
     {
@@ -2159,7 +1997,7 @@ elf64_x86_64_allocate_dynrelocs (struct 
 	 should avoid writing weird assembly.  */
       if (SYMBOL_CALLS_LOCAL (info, h))
 	{
-	  struct elf64_x86_64_dyn_relocs **pp;
+	  struct elf_dyn_relocs **pp;
 
 	  for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
 	    {
@@ -2260,7 +2098,7 @@ static bfd_boolean
 elf64_x86_64_readonly_dynrelocs (struct elf_link_hash_entry *h, void * inf)
 {
   struct elf64_x86_64_link_hash_entry *eh;
-  struct elf64_x86_64_dyn_relocs *p;
+  struct elf_dyn_relocs *p;
 
   if (h->root.type == bfd_link_hash_warning)
     h = (struct elf_link_hash_entry *) h->root.u.i.link;
@@ -2330,9 +2168,9 @@ elf64_x86_64_size_dynamic_sections (bfd 
 
       for (s = ibfd->sections; s != NULL; s = s->next)
 	{
-	  struct elf64_x86_64_dyn_relocs *p;
+	  struct elf_dyn_relocs *p;
 
-	  for (p = (struct elf64_x86_64_dyn_relocs *)
+	  for (p = (struct elf_dyn_relocs *)
 		    (elf_section_data (s)->local_dynrel);
 	       p != NULL;
 	       p = p->next)
diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/bfd/elf-bfd.h binutils/bfd/elf-bfd.h
--- ../binutils/src/bfd/elf-bfd.h	2009-06-16 10:45:42.000000000 -0700
+++ binutils/bfd/elf-bfd.h	2009-06-17 17:39:40.000000000 -0700
@@ -2157,8 +2157,34 @@ extern int _bfd_elf_obj_attrs_arg_type (
 extern void _bfd_elf_parse_attributes (bfd *, Elf_Internal_Shdr *);
 extern bfd_boolean _bfd_elf_merge_object_attributes (bfd *, bfd *);
 
+/* The linker may needs to keep track of the number of relocs that it
+   decides to copy as dynamic relocs in check_relocs for each symbol.
+   This is so that it can later discard them if they are found to be
+   unnecessary.  We can store the information in a field extending the
+   regular ELF linker hash table.  */
+
+struct elf_dyn_relocs
+{
+  struct elf_dyn_relocs *next;
+
+  /* The input section of the reloc.  */
+  asection *sec;
+
+  /* Total number of relocs copied for the input section.  */
+  bfd_size_type count;
+
+  /* Number of pc-relative relocs copied for the input section.  */
+  bfd_size_type pc_count;
+};
+
 extern bfd_boolean _bfd_elf_create_ifunc_sections
   (bfd *, struct bfd_link_info *);
+extern asection * _bfd_elf_create_ifunc_dyn_reloc
+  (bfd *, struct bfd_link_info *, asection *sec, asection *sreloc,
+   struct elf_dyn_relocs **);
+extern bfd_boolean _bfd_elf_allocate_ifunc_dyn_relocs
+  (struct bfd_link_info *, struct elf_link_hash_entry *,
+   struct elf_dyn_relocs **, unsigned int, unsigned int);
 
 /* Large common section.  */
 extern asection _bfd_elf_large_com_section;
diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/bfd/elf-ifunc.c binutils/bfd/elf-ifunc.c
--- ../binutils/src/bfd/elf-ifunc.c	2009-06-16 06:41:10.000000000 -0700
+++ binutils/bfd/elf-ifunc.c	2009-06-17 17:39:40.000000000 -0700
@@ -103,3 +103,185 @@ _bfd_elf_create_ifunc_sections (bfd *abf
 
   return TRUE;
 }
+
+/* For a STT_GNU_IFUNC symbol, create a dynamic reloc section, SRELOC,
+   for the input section, SEC, and append this reloc to HEAD.  */
+
+asection *
+_bfd_elf_create_ifunc_dyn_reloc (bfd *abfd, struct bfd_link_info *info,
+				 asection *sec, asection *sreloc,
+				 struct elf_dyn_relocs **head)
+{
+  struct elf_dyn_relocs *p;
+  struct elf_link_hash_table *htab = elf_hash_table (info);
+
+  if (sreloc == NULL)
+    {
+      const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+
+      if (htab->dynobj == NULL)
+	htab->dynobj = abfd;
+
+      sreloc = _bfd_elf_make_dynamic_reloc_section (sec, htab->dynobj,
+						    bed->s->log_file_align,
+						    abfd,
+						    bed->rela_plts_and_copies_p); 
+      if (sreloc == NULL)
+	return NULL;
+    }
+		      
+  p = *head;
+  if (p == NULL || p->sec != sec)
+    {
+      bfd_size_type amt = sizeof *p;
+
+      p = ((struct elf_dyn_relocs *) bfd_alloc (htab->dynobj, amt));
+      if (p == NULL)
+	return NULL;
+      p->next = *head;
+      *head = p;
+      p->sec = sec;
+      p->count = 0;
+      p->pc_count = 0;
+    }
+  p->count += 1;
+
+  return sreloc;
+}
+
+/* Allocate space in .plt, .got and associated reloc sections for
+   dynamic relocs against a STT_GNU_IFUNC symbol definition.  */
+
+bfd_boolean
+_bfd_elf_allocate_ifunc_dyn_relocs (struct bfd_link_info *info,
+				    struct elf_link_hash_entry *h,
+				    struct elf_dyn_relocs **head,
+				    unsigned int plt_entry_size,
+				    unsigned int got_entry_size)
+{
+  asection *plt, *gotplt, *relplt;
+  struct elf_dyn_relocs *p;
+  unsigned int sizeof_reloc;
+  const struct elf_backend_data *bed;
+  struct elf_link_hash_table *htab;
+
+  /* When a shared library references a STT_GNU_IFUNC symbol defined
+     in executable, the address of the resolved function may be used.
+     But in non-shared executable, the address of its .plt slot may
+     be used.  Pointer equality may not work correctly.  PIE should
+     be used if pointer equality is required here.  */
+  if (!info->shared
+      && (h->dynindx != -1
+	  || info->export_dynamic)
+      && h->pointer_equality_needed)
+    {
+      info->callbacks->einfo 
+	(_("%F%P: dynamic STT_GNU_IFUNC symbol `%s' with pointer "
+	   "equality in `%B' can not be used when making an "
+	   "executable; recompile with -fPIE and relink with -pie\n"),
+	 h->root.root.string,
+	 h->root.u.def.section->owner);
+      bfd_set_error (bfd_error_bad_value);
+      return FALSE;
+    }
+
+  /* Return and discard space for dynamic relocations against it if
+     it is never referenced in a non-shared object.  */
+  if (!h->ref_regular)
+    {
+      if (h->plt.refcount > 0
+	  || h->got.refcount > 0)
+	abort ();
+      h->got.offset = (bfd_vma) -1;
+      *head = NULL;
+      return TRUE;
+    }
+
+  bed = get_elf_backend_data (info->output_bfd);
+  if (bed->rela_plts_and_copies_p)
+    sizeof_reloc = bed->s->sizeof_rela;
+  else
+    sizeof_reloc = bed->s->sizeof_rel;
+
+  htab = elf_hash_table (info);
+
+  /* When building a static executable, use .iplt, .igot.plt and
+     .rel[a].iplt sections for STT_GNU_IFUNC symbols.  */
+  if (htab->splt != NULL)
+    {
+      plt = htab->splt;
+      gotplt = htab->sgotplt;
+      relplt = htab->srelplt;
+
+      /* If this is the first .plt entry, make room for the special
+	 first entry.  */
+      if (plt->size == 0)
+	plt->size += plt_entry_size;
+    }
+  else
+    {
+      plt = htab->iplt;
+      gotplt = htab->igotplt;
+      relplt = htab->irelplt;
+    }
+
+  /* Don't update value of STT_GNU_IFUNC symbol to PLT.  We need
+     the original value for R_*_IRELATIVE.  */  
+  h->plt.offset = plt->size;
+
+  /* Make room for this entry in the .plt/.iplt section.  */
+  plt->size += plt_entry_size;
+
+  /* We also need to make an entry in the .got.plt/.got.iplt section,
+     which will be placed in the .got section by the linker script.  */
+  gotplt->size += got_entry_size;
+
+  /* We also need to make an entry in the .rel[a].plt/.rel[a].iplt
+     section.  */
+  relplt->size += sizeof_reloc;
+  relplt->reloc_count++;
+
+  /* We need dynamic relocation for STT_GNU_IFUNC symbol only when
+     there is a non-GOT reference in a shared object.  */
+  if (!info->shared
+      || !h->non_got_ref)
+    *head = NULL;
+
+  /* Finally, allocate space.  */
+  for (p = *head; p != NULL; p = p->next)
+    htab->irelifunc->size += p->count * sizeof_reloc;
+
+  /* For STT_GNU_IFUNC symbol, .got.plt has the real function addres
+     and .got has the PLT entry adddress.  We will load the GOT entry
+     with the PLT entry in finish_dynamic_symbol if it is used.  For
+     branch, it uses .got.plt.  For symbol value,
+     1. Use .got.plt in a shared object if it is forced local or not
+     dynamic.
+     2. Use .got.plt in a non-shared object if pointer equality isn't
+     needed.
+     3. Use .got.plt in PIE.
+     4. Use .got.plt if .got isn't used.
+     5. Otherwise use .got so that it can be shared among different
+     objects at run-time.
+     We only need to relocate .got entry in shared object.  */
+  if ((info->shared
+       && (h->dynindx == -1
+	   || h->forced_local))
+      || (!info->shared
+	  && !h->pointer_equality_needed)
+      || (info->executable && info->shared)
+      || htab->sgot == NULL)
+    {
+      /* Use .got.plt.  */
+      h->got.offset = (bfd_vma) -1;
+    }
+  else
+    {
+      h->got.offset = htab->sgot->size;
+      htab->sgot->size += got_entry_size;
+      if (info->shared)
+	htab->srelgot->size += sizeof_reloc;
+    }
+
+  return TRUE;
+}


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