2009-06-03 H.J. Lu <hongjiu.lu@intel.com>
authorH.J. Lu <hjl.tools@gmail.com>
Wed, 3 Jun 2009 12:35:18 +0000 (12:35 +0000)
committerH.J. Lu <hjl.tools@gmail.com>
Wed, 3 Jun 2009 12:35:18 +0000 (12:35 +0000)
* elf32-i386.c (elf_i386_allocate_dynrelocs): Allocate
GOT entry for STT_GNU_IFUNC symbol with pointer equality.
(elf_i386_relocate_section): Adjust R_386_GOT32 relocation
against STT_GNU_IFUNC symbols for static executables.
(elf_i386_finish_dynamic_symbol): Load GOT entry with
PLT entry for STT_GNU_IFUNC symbol with pointer equality.

* elf64-x86-64.c (elf64_x86_64_allocate_dynrelocs): Allocate
GOT entry for STT_GNU_IFUNC symbol with pointer equality.
(elf64_x86_64_finish_dynamic_symbol): Load GOT entry with
PLT entry for STT_GNU_IFUNC symbol with pointer equality.

bfd/ChangeLog
bfd/elf32-i386.c
bfd/elf64-x86-64.c

index b43f595..ef39b35 100644 (file)
@@ -1,3 +1,17 @@
+2009-06-03  H.J. Lu  <hongjiu.lu@intel.com>
+
+       * elf32-i386.c (elf_i386_allocate_dynrelocs): Allocate
+       GOT entry for STT_GNU_IFUNC symbol with pointer equality.
+       (elf_i386_relocate_section): Adjust R_386_GOT32 relocation
+       against STT_GNU_IFUNC symbols for static executables.
+       (elf_i386_finish_dynamic_symbol): Load GOT entry with
+       PLT entry for STT_GNU_IFUNC symbol with pointer equality.
+
+       * elf64-x86-64.c (elf64_x86_64_allocate_dynrelocs): Allocate
+       GOT entry for STT_GNU_IFUNC symbol with pointer equality.
+       (elf64_x86_64_finish_dynamic_symbol): Load GOT entry with
+       PLT entry for STT_GNU_IFUNC symbol with pointer equality.
+
 2009-06-02  Richard Sandiford  <r.sandiford@uk.ibm.com>
 
        * coff-rs6000.c (xcoff_ppc_relocate_section): Allow undefined
index ade5aa8..81b5093 100644 (file)
@@ -2003,10 +2003,26 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
       /* STT_GNU_IFUNC symbol uses .got.plt, not .got.  But for
         shared library, we must go through GOT and we can't
         use R_386_IRELATIVE unless it is forced local.   */
-      if (!info->shared 
+      if (info->executable
          || info->symbolic
          || h->forced_local)
-       h->got.refcount = 0;
+       {
+         if (h->pointer_equality_needed
+             && htab->sgot != NULL)
+           {
+             /* We can't use .got.plt, which contains the real
+                function addres, since we need pointer equality.
+                We will load the GOT entry with the PLT entry
+                in elf_i386_finish_dynamic_symbol and don't
+                need GOT relocation.  */
+             h->got.offset = htab->sgot->size;
+             htab->sgot->size += 4;
+             eh->tlsdesc_got = (bfd_vma) -1;
+             goto skip_relgot;
+           }
+         else
+           h->got.refcount = 0;
+       }
     }
   else if (htab->elf.dynamic_sections_created
           && h->plt.refcount > 0)
@@ -2153,6 +2169,7 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
   else
     h->got.offset = (bfd_vma) -1;
 
+skip_relgot:
   if (eh->dyn_relocs == NULL)
     return TRUE;
 
@@ -2966,11 +2983,16 @@ elf_i386_relocate_section (bfd *output_bfd,
                    relocation += gotplt->output_offset;
                }
              else
-               relocation = (base_got->output_section->vma
-                             + base_got->output_offset + off
-                             - gotplt->output_section->vma
-                             - gotplt->output_offset);
-            
+               {
+                 relocation = (base_got->output_section->vma
+                               + base_got->output_offset + off
+                               - gotplt->output_section->vma
+                               - gotplt->output_offset);
+                 /* Adjust for static executables.  */
+                 if (htab->splt == NULL)
+                   relocation += gotplt->output_offset;
+               }
+
              goto do_relocation;
 
            case R_386_GOTOFF:
@@ -4113,8 +4135,28 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
         of a version file, we just want to emit a RELATIVE reloc.
         The entry in the global offset table will already have been
         initialized in the relocate_section function.  */
-      if (info->shared
-         && SYMBOL_REFERENCES_LOCAL (info, h))
+      if ((info->executable
+          || info->symbolic
+          || h->forced_local)
+         && h->def_regular
+         && h->pointer_equality_needed
+         && h->type == STT_GNU_IFUNC)
+       {
+         /* The STT_GNU_IFUNC symbol is locally defined.  But we can't
+            use .got.plt, which contains the real function addres,
+            since we need pointer equality.  We load the GOT entry
+            with the PLT entry without relocation.  */
+         asection *plt = htab->splt ? htab->splt : htab->iplt;
+         if (htab->sgot == NULL
+             || h->plt.offset == (bfd_vma) -1)
+           abort ();
+         bfd_put_32 (output_bfd, (plt->output_section->vma
+                                  + plt->output_offset + h->plt.offset),
+                     htab->sgot->contents + h->got.offset);
+         return TRUE;
+       }
+      else if (info->shared
+              && SYMBOL_REFERENCES_LOCAL (info, h))
        {
          BFD_ASSERT((h->got.offset & 1) != 0);
          rel.r_info = ELF32_R_INFO (0, R_386_RELATIVE);
index e858325..1dec3c3 100644 (file)
@@ -1841,10 +1841,26 @@ elf64_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
       /* STT_GNU_IFUNC symbol uses .got.plt, not .got.  But for
         shared library, we must go through GOT and we can't
         use R_X86_64_IRELATIVE unless it is forced local.   */
-      if (!info->shared 
+      if (info->executable
          || info->symbolic
          || h->forced_local)
-       h->got.refcount = 0;
+       {
+         if (h->pointer_equality_needed
+             && htab->sgot != NULL)
+           {
+             /* We can't use .got.plt, which contains the real
+                function addres, since we need pointer equality.
+                We will load the GOT entry with the PLT entry
+                in elf64_x86_64_finish_dynamic_symbol and don't
+                need GOT relocation.  */
+             h->got.offset = htab->sgot->size;
+             htab->sgot->size += GOT_ENTRY_SIZE;
+             eh->tlsdesc_got = (bfd_vma) -1;
+             goto skip_relgot;
+           }
+         else
+           h->got.refcount = 0;
+       }
     }
   else if (htab->elf.dynamic_sections_created
           && h->plt.refcount > 0)
@@ -1971,6 +1987,7 @@ elf64_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
   else
     h->got.offset = (bfd_vma) -1;
 
+skip_relgot:
   if (eh->dyn_relocs == NULL)
     return TRUE;
 
@@ -3727,8 +3744,28 @@ elf64_x86_64_finish_dynamic_symbol (bfd *output_bfd,
         of a version file, we just want to emit a RELATIVE reloc.
         The entry in the global offset table will already have been
         initialized in the relocate_section function.  */
-      if (info->shared
-         && SYMBOL_REFERENCES_LOCAL (info, h))
+      if ((info->executable
+          || info->symbolic
+          || h->forced_local)
+         && h->def_regular
+         && h->pointer_equality_needed
+         && h->type == STT_GNU_IFUNC)
+       {
+         /* The STT_GNU_IFUNC symbol is locally defined.  But we can't
+            use .got.plt, which contains the real function addres,
+            since we need pointer equality.  We load the GOT entry
+            with the PLT entry without relocation.  */
+         asection *plt = htab->splt ? htab->splt : htab->iplt;
+         if (htab->sgot == NULL
+             || h->plt.offset == (bfd_vma) -1)
+           abort ();
+         bfd_put_64 (output_bfd, (plt->output_section->vma
+                                  + plt->output_offset + h->plt.offset),
+                     htab->sgot->contents + h->got.offset);
+         return TRUE;
+       }
+      else if (info->shared
+              && SYMBOL_REFERENCES_LOCAL (info, h))
        {
          if (!h->def_regular)
            return FALSE;