* libbfd-in.h (bfd_malloc2, bfd_realloc2, bfd_zmalloc2, bfd_alloc2,
[deliverable/binutils-gdb.git] / bfd / elf64-x86-64.c
index 40e8b09a1450d05a709a4ddd37d828541a88652a..055f626566fc95d62d0bc9dee04d8b07316da3dc 100644 (file)
@@ -17,7 +17,7 @@
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02110-1301, USA.  */
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
 
 #include "bfd.h"
 #include "sysdep.h"
@@ -103,6 +103,15 @@ static reloc_howto_type x86_64_elf_howto_table[] =
   HOWTO(R_X86_64_TPOFF32, 0, 2, 32, FALSE, 0, complain_overflow_signed,
        bfd_elf_generic_reloc, "R_X86_64_TPOFF32", FALSE, 0xffffffff,
        0xffffffff, FALSE),
+  HOWTO(R_X86_64_PC64, 0, 4, 64, TRUE, 0, complain_overflow_bitfield,
+       bfd_elf_generic_reloc, "R_X86_64_PC64", FALSE, MINUS_ONE, MINUS_ONE,
+       TRUE),
+  HOWTO(R_X86_64_GOTOFF64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield,
+       bfd_elf_generic_reloc, "R_X86_64_GOTOFF64",
+       FALSE, MINUS_ONE, MINUS_ONE, FALSE),
+  HOWTO(R_X86_64_GOTPC32, 0, 2, 32, TRUE, 0, complain_overflow_signed,
+       bfd_elf_generic_reloc, "R_X86_64_GOTPC32",
+       FALSE, 0xffffffff, 0xffffffff, TRUE),
 
 /* GNU extension to record C++ vtable hierarchy.  */
   HOWTO (R_X86_64_GNU_VTINHERIT, 0, 4, 0, FALSE, 0, complain_overflow_dont,
@@ -147,6 +156,9 @@ static const struct elf_reloc_map x86_64_reloc_map[] =
   { BFD_RELOC_X86_64_DTPOFF32, R_X86_64_DTPOFF32, },
   { BFD_RELOC_X86_64_GOTTPOFF, R_X86_64_GOTTPOFF, },
   { BFD_RELOC_X86_64_TPOFF32,  R_X86_64_TPOFF32, },
+  { BFD_RELOC_64_PCREL,                R_X86_64_PC64, },
+  { BFD_RELOC_X86_64_GOTOFF64, R_X86_64_GOTOFF64, },
+  { BFD_RELOC_X86_64_GOTPC32,  R_X86_64_GOTPC32, },
   { BFD_RELOC_VTABLE_INHERIT,  R_X86_64_GNU_VTINHERIT, },
   { BFD_RELOC_VTABLE_ENTRY,    R_X86_64_GNU_VTENTRY, },
 };
@@ -177,16 +189,19 @@ elf64_x86_64_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr,
   unsigned r_type, i;
 
   r_type = ELF64_R_TYPE (dst->r_info);
-  if (r_type < (unsigned int) R_X86_64_GNU_VTINHERIT)
+  if (r_type < (unsigned int) R_X86_64_GNU_VTINHERIT
+      || r_type >= (unsigned int) R_X86_64_max)
     {
-      BFD_ASSERT (r_type <= (unsigned int) R_X86_64_TPOFF32);
+      if (r_type > (unsigned int) R_X86_64_GOTPC32)
+       {
+         (*_bfd_error_handler) (_("%B: invalid relocation type %d"),
+                                abfd, (int) r_type);
+         r_type = R_X86_64_NONE;
+       }
       i = r_type;
     }
   else
-    {
-      BFD_ASSERT (r_type < (unsigned int) R_X86_64_max);
-      i = r_type - ((unsigned int) R_X86_64_GNU_VTINHERIT - R_X86_64_TPOFF32 - 1);
-    }
+    i = r_type - ((unsigned int) R_X86_64_GNU_VTINHERIT - R_X86_64_GOTPC32 - 1);
   cache_ptr->howto = &x86_64_elf_howto_table[i];
   BFD_ASSERT (r_type == cache_ptr->howto->type);
 }
@@ -459,12 +474,13 @@ create_got_section (bfd *dynobj, struct bfd_link_info *info)
   if (!htab->sgot || !htab->sgotplt)
     abort ();
 
-  htab->srelgot = bfd_make_section (dynobj, ".rela.got");
+  htab->srelgot = bfd_make_section_with_flags (dynobj, ".rela.got",
+                                              (SEC_ALLOC | SEC_LOAD
+                                               | SEC_HAS_CONTENTS
+                                               | SEC_IN_MEMORY
+                                               | SEC_LINKER_CREATED
+                                               | SEC_READONLY));
   if (htab->srelgot == NULL
-      || ! bfd_set_section_flags (dynobj, htab->srelgot,
-                                 (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
-                                  | SEC_IN_MEMORY | SEC_LINKER_CREATED
-                                  | SEC_READONLY))
       || ! bfd_set_section_alignment (dynobj, htab->srelgot, 3))
     return FALSE;
   return TRUE;
@@ -651,7 +667,12 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec,
       if (r_symndx < symtab_hdr->sh_info)
        h = NULL;
       else
-       h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+       {
+         h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+         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;
+       }
 
       r_type = elf64_x86_64_tls_transition (info, r_type, h == NULL);
       switch (r_type)
@@ -748,7 +769,8 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec,
          }
          /* Fall through */
 
-         //case R_X86_64_GOTPCREL:
+       case R_X86_64_GOTOFF64:
+       case R_X86_64_GOTPC32:
        create_got:
          if (htab->sgot == NULL)
            {
@@ -801,6 +823,7 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec,
        case R_X86_64_PC8:
        case R_X86_64_PC16:
        case R_X86_64_PC32:
+       case R_X86_64_PC64:
        case R_X86_64_64:
          if (h != NULL && !info->shared)
            {
@@ -815,7 +838,7 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec,
              /* We may need a .plt entry if the function this reloc
                 refers to is in a shared lib.  */
              h->plt.refcount += 1;
-             if (r_type != R_X86_64_PC32)
+             if (r_type != R_X86_64_PC32 && r_type != R_X86_64_PC64)
                h->pointer_equality_needed = 1;
            }
 
@@ -844,7 +867,8 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec,
               && (sec->flags & SEC_ALLOC) != 0
               && (((r_type != R_X86_64_PC8)
                    && (r_type != R_X86_64_PC16)
-                   && (r_type != R_X86_64_PC32))
+                   && (r_type != R_X86_64_PC32)
+                   && (r_type != R_X86_64_PC64))
                   || (h != NULL
                       && (! info->symbolic
                           || h->root.type == bfd_link_hash_defweak
@@ -893,13 +917,14 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec,
                    {
                      flagword flags;
 
-                     sreloc = bfd_make_section (dynobj, name);
                      flags = (SEC_HAS_CONTENTS | SEC_READONLY
                               | SEC_IN_MEMORY | SEC_LINKER_CREATED);
                      if ((sec->flags & SEC_ALLOC) != 0)
                        flags |= SEC_ALLOC | SEC_LOAD;
+                     sreloc = bfd_make_section_with_flags (dynobj,
+                                                           name,
+                                                           flags);
                      if (sreloc == NULL
-                         || ! bfd_set_section_flags (dynobj, sreloc, flags)
                          || ! bfd_set_section_alignment (dynobj, sreloc, 3))
                        return FALSE;
                    }
@@ -946,7 +971,8 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec,
              p->count += 1;
              if (r_type == R_X86_64_PC8
                  || r_type == R_X86_64_PC16
-                 || r_type == R_X86_64_PC32)
+                 || r_type == R_X86_64_PC32
+                 || r_type == R_X86_64_PC64)
                p->pc_count += 1;
            }
          break;
@@ -1091,6 +1117,7 @@ elf64_x86_64_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
        case R_X86_64_PC8:
        case R_X86_64_PC16:
        case R_X86_64_PC32:
+       case R_X86_64_PC64:
          if (info->shared)
            break;
          /* Fall thru */
@@ -1622,7 +1649,8 @@ elf64_x86_64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
 
       if (s == htab->splt
          || s == htab->sgot
-         || s == htab->sgotplt)
+         || s == htab->sgotplt
+         || s == htab->sdynbss)
        {
          /* Strip this section if we don't need it; see the
             comment below.  */
@@ -1938,6 +1966,42 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 
          break;
 
+       case R_X86_64_GOTOFF64:
+         /* Relocation is relative to the start of the global offset
+            table.  */
+
+         /* Check to make sure it isn't a protected function symbol
+            for shared library since it may not be local when used
+            as function address.  */
+         if (info->shared
+             && h
+             && h->def_regular
+             && h->type == STT_FUNC
+             && ELF_ST_VISIBILITY (h->other) == STV_PROTECTED)
+           {
+             (*_bfd_error_handler)
+               (_("%B: relocation R_X86_64_GOTOFF64 against protected function `%s' can not be used when making a shared object"),
+                input_bfd, h->root.root.string);
+             bfd_set_error (bfd_error_bad_value);
+             return FALSE;
+           }
+
+         /* Note that sgot is not involved in this
+            calculation.  We always want the start of .got.plt.  If we
+            defined _GLOBAL_OFFSET_TABLE_ in a different way, as is
+            permitted by the ABI, we might have to change this
+            calculation.  */
+         relocation -= htab->sgotplt->output_section->vma
+                       + htab->sgotplt->output_offset;
+         break;
+
+       case R_X86_64_GOTPC32:
+         /* Use global offset table as symbol value.  */
+         relocation = htab->sgotplt->output_section->vma
+                      + htab->sgotplt->output_offset;
+         unresolved_reloc = FALSE;
+         break;
+
        case R_X86_64_PLT32:
          /* Relocation is to the entry for this symbol in the
             procedure linkage table.  */
@@ -1996,6 +2060,7 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
        case R_X86_64_8:
        case R_X86_64_16:
        case R_X86_64_32:
+       case R_X86_64_PC64:
        case R_X86_64_64:
          /* FIXME: The ABI says the linker should make sure the value is
             the same when it's zeroextended to 64 bit.  */
@@ -2013,7 +2078,8 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                   || h->root.type != bfd_link_hash_undefweak)
               && ((r_type != R_X86_64_PC8
                    && r_type != R_X86_64_PC16
-                   && r_type != R_X86_64_PC32)
+                   && r_type != R_X86_64_PC32
+                   && r_type != R_X86_64_PC64)
                   || !SYMBOL_CALLS_LOCAL (info, h)))
              || (ELIMINATE_COPY_RELOCS
                  && !info->shared
@@ -2057,6 +2123,7 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                       && (r_type == R_X86_64_PC8
                           || r_type == R_X86_64_PC16
                           || r_type == R_X86_64_PC32
+                          || r_type == R_X86_64_PC64
                           || !info->shared
                           || !info->symbolic
                           || !h->def_regular))
This page took 0.029648 seconds and 4 git commands to generate.