Touches most files in bfd/, so likely will be blamed for everything..
[deliverable/binutils-gdb.git] / bfd / elf64-x86-64.c
index 288377c734e31fd432c059ba009c7e35dbd981d5..24eb9f76a0b2fe4612ed60dff3bfe3b9669f05cd 100644 (file)
@@ -32,26 +32,63 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #define MINUS_ONE (~ (bfd_vma) 0)
 
 /* The relocation "howto" table.  Order of fields:
-   type, size, bitsize, pc_relative, complain_on_overflow, special_function,
-   name, partial_inplace, src_mask, dst_pack, pcrel_offset  */
+   type, size, bitsize, pc_relative, complain_on_overflow,
+   special_function, name, partial_inplace, src_mask, dst_pack, pcrel_offset.  */
 static reloc_howto_type x86_64_elf_howto_table[] =
 {
-  HOWTO(R_X86_64_NONE,          0,0, 0,false,0,complain_overflow_dont,    0, "R_X86_64_NONE",   false,0x00000000,0x00000000,false),
-  HOWTO(R_X86_64_64,    0,4,64,false,0,complain_overflow_bitfield,0, "R_X86_64_64",     false,MINUS_ONE ,MINUS_ONE ,false),
-  HOWTO(R_X86_64_PC32,          0,4,32,true ,0,complain_overflow_signed  ,0, "R_X86_64_PC32",   false,0xffffffff,0xffffffff,true),
-  HOWTO(R_X86_64_GOT32,         0,4,32,false,0,complain_overflow_signed  ,0, "R_X86_64_GOT32",  false,0xffffffff,0xffffffff,false),
-  HOWTO(R_X86_64_PLT32,         0,4,32,true ,0,complain_overflow_signed  ,0, "R_X86_64_PLT32",  false,0xffffffff,0xffffffff,true),
-  HOWTO(R_X86_64_COPY,     0,4,32,false,0,complain_overflow_bitfield,0, "R_X86_64_COPY",   false,0xffffffff,0xffffffff,false),
-  HOWTO(R_X86_64_GLOB_DAT, 0,4,64,false,0,complain_overflow_bitfield,0,"R_X86_64_GLOB_DAT",false,MINUS_ONE ,MINUS_ONE ,false),
-  HOWTO(R_X86_64_RELATIVE ,0,4,64,false,0,complain_overflow_bitfield,0,"R_X86_64_RELATIVE",false,MINUS_ONE ,MINUS_ONE ,false),
-  HOWTO(R_X86_64_JUMP_SLOT,0,4,64,false,0,complain_overflow_bitfield,0,"R_X86_64_JUMP_SLOT",false,MINUS_ONE,MINUS_ONE ,false),
-  HOWTO(R_X86_64_GOTPCREL, 0,4,32,true, 0,complain_overflow_signed  ,0, "R_X86_64_GOTPCREL",false,0xffffffff,0xffffffff,true),
-  HOWTO(R_X86_64_32,    0,4,32,false,0,complain_overflow_unsigned,0, "R_X86_64_32",     false,0xffffffff,0xffffffff,false),
-  HOWTO(R_X86_64_32S,   0,4,32,false,0,complain_overflow_signed,  0, "R_X86_64_32S",    false,0xffffffff,0xffffffff,false),
-  HOWTO(R_X86_64_16,    0,1,16,false,0,complain_overflow_bitfield,0, "R_X86_64_16",     false,0xffff    ,0xffff,    false),
-  HOWTO(R_X86_64_PC16,          0,1,16,true ,0,complain_overflow_bitfield,0, "R_X86_64_PC16",   false,0xffff    ,0xffff,    true),
-  HOWTO(R_X86_64_8,     0,0, 8,false,0,complain_overflow_signed  ,0, "R_X86_64_8",      false,0xff      ,0xff,      false),
-  HOWTO(R_X86_64_PC8,   0,0, 8,true ,0,complain_overflow_signed  ,0, "R_X86_64_PC8",    false,0xff      ,0xff,      true),
+  HOWTO(R_X86_64_NONE, 0, 0, 0, false, 0, complain_overflow_dont,
+       bfd_elf_generic_reloc, "R_X86_64_NONE", false, 0x00000000, 0x00000000,
+       false),
+  HOWTO(R_X86_64_64, 0, 4, 64, false, 0, complain_overflow_bitfield,
+       bfd_elf_generic_reloc, "R_X86_64_64", false, MINUS_ONE, MINUS_ONE,
+       false),
+  HOWTO(R_X86_64_PC32, 0, 4, 32, true, 0, complain_overflow_signed,
+       bfd_elf_generic_reloc, "R_X86_64_PC32", false, 0xffffffff, 0xffffffff,
+       true),
+  HOWTO(R_X86_64_GOT32, 0, 4, 32, false, 0, complain_overflow_signed,
+       bfd_elf_generic_reloc, "R_X86_64_GOT32", false, 0xffffffff, 0xffffffff,
+       false),
+  HOWTO(R_X86_64_PLT32, 0, 4, 32, true, 0, complain_overflow_signed,
+       bfd_elf_generic_reloc, "R_X86_64_PLT32", false, 0xffffffff, 0xffffffff,
+       true),
+  HOWTO(R_X86_64_COPY, 0, 4, 32, false, 0, complain_overflow_bitfield,
+       bfd_elf_generic_reloc, "R_X86_64_COPY", false, 0xffffffff, 0xffffffff,
+       false),
+  HOWTO(R_X86_64_GLOB_DAT, 0, 4, 64, false, 0, complain_overflow_bitfield,
+       bfd_elf_generic_reloc, "R_X86_64_GLOB_DAT", false, MINUS_ONE,
+       MINUS_ONE, false),
+  HOWTO(R_X86_64_JUMP_SLOT, 0, 4, 64, false, 0, complain_overflow_bitfield,
+       bfd_elf_generic_reloc, "R_X86_64_JUMP_SLOT", false, MINUS_ONE,
+       MINUS_ONE, false),
+  HOWTO(R_X86_64_RELATIVE, 0, 4, 64, false, 0, complain_overflow_bitfield,
+       bfd_elf_generic_reloc, "R_X86_64_RELATIVE", false, MINUS_ONE,
+       MINUS_ONE, false),
+  HOWTO(R_X86_64_GOTPCREL, 0, 4, 32, true,0 , complain_overflow_signed,
+       bfd_elf_generic_reloc, "R_X86_64_GOTPCREL", false, 0xffffffff,
+       0xffffffff, true),
+  HOWTO(R_X86_64_32, 0, 4, 32, false, 0, complain_overflow_unsigned,
+       bfd_elf_generic_reloc, "R_X86_64_32", false, 0xffffffff, 0xffffffff,
+       false),
+  HOWTO(R_X86_64_32S, 0, 4, 32, false, 0, complain_overflow_signed,
+       bfd_elf_generic_reloc, "R_X86_64_32S", false, 0xffffffff, 0xffffffff,
+       false),
+  HOWTO(R_X86_64_16, 0, 1, 16, false, 0, complain_overflow_bitfield,
+       bfd_elf_generic_reloc, "R_X86_64_16", false, 0xffff, 0xffff, false),
+  HOWTO(R_X86_64_PC16,0, 1, 16, true, 0, complain_overflow_bitfield,
+       bfd_elf_generic_reloc, "R_X86_64_PC16", false, 0xffff, 0xffff, true),
+  HOWTO(R_X86_64_8, 0, 0, 8, false, 0, complain_overflow_signed,
+       bfd_elf_generic_reloc, "R_X86_64_8", false, 0xff, 0xff, false),
+  HOWTO(R_X86_64_PC8, 0, 0, 8, true, 0, complain_overflow_signed,
+       bfd_elf_generic_reloc, "R_X86_64_PC8", false, 0xff, 0xff, true),
+
+/* GNU extension to record C++ vtable hierarchy.  */
+  HOWTO (R_X86_64_GNU_VTINHERIT, 0, 4, 0, false, 0, complain_overflow_dont,
+        NULL, "R_X86_64_GNU_VTINHERIT", false, 0, 0, false),
+
+/* GNU extension to record C++ vtable member usage.  */
+  HOWTO (R_X86_64_GNU_VTENTRY, 0, 4, 0, false, 0, complain_overflow_dont,
+        _bfd_elf_rel_vtable_reloc_fn, "R_X86_64_GNU_VTENTRY", false, 0, 0,
+        false)
 };
 
 /* Map BFD relocs to the x86_64 elf relocs.  */
@@ -61,7 +98,7 @@ struct elf_reloc_map
   unsigned char elf_reloc_val;
 };
 
-static CONST struct elf_reloc_map x86_64_reloc_map[] =
+static const struct elf_reloc_map x86_64_reloc_map[] =
 {
   { BFD_RELOC_NONE,            R_X86_64_NONE, },
   { BFD_RELOC_64,              R_X86_64_64,   },
@@ -79,6 +116,8 @@ static CONST struct elf_reloc_map x86_64_reloc_map[] =
   { BFD_RELOC_16_PCREL,                R_X86_64_PC16, },
   { BFD_RELOC_8,               R_X86_64_8, },
   { BFD_RELOC_8_PCREL,         R_X86_64_PC8, },
+  { BFD_RELOC_VTABLE_INHERIT,  R_X86_64_GNU_VTINHERIT, },
+  { BFD_RELOC_VTABLE_ENTRY,    R_X86_64_GNU_VTENTRY, },
 };
 
 static reloc_howto_type *elf64_x86_64_reloc_type_lookup
@@ -87,6 +126,17 @@ static void elf64_x86_64_info_to_howto
   PARAMS ((bfd *, arelent *, Elf64_Internal_Rela *));
 static struct bfd_link_hash_table *elf64_x86_64_link_hash_table_create
   PARAMS ((bfd *));
+static boolean elf64_x86_64_elf_object_p PARAMS ((bfd *abfd));
+static boolean elf64_x86_64_check_relocs
+  PARAMS ((bfd *, struct bfd_link_info *, asection *sec,
+          const Elf_Internal_Rela *));
+static asection *elf64_x86_64_gc_mark_hook
+  PARAMS ((bfd *, struct bfd_link_info *, Elf_Internal_Rela *,
+          struct elf_link_hash_entry *, Elf_Internal_Sym *));
+
+static boolean elf64_x86_64_gc_sweep_hook
+  PARAMS ((bfd *, struct bfd_link_info *, asection *,
+          const Elf_Internal_Rela *));
 
 static struct bfd_hash_entry *elf64_x86_64_link_hash_newfunc
   PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
@@ -97,12 +147,13 @@ static boolean elf64_x86_64_size_dynamic_sections
   PARAMS ((bfd *, struct bfd_link_info *));
 static boolean elf64_x86_64_relocate_section
   PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
-         Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
+        Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
 static boolean elf64_x86_64_finish_dynamic_symbol
   PARAMS ((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *,
           Elf_Internal_Sym *sym));
 static boolean elf64_x86_64_finish_dynamic_sections
   PARAMS ((bfd *, struct bfd_link_info *));
+static enum elf_reloc_type_class elf64_x86_64_reloc_type_class PARAMS ((int));
 
 /* Given a BFD reloc type, return a HOWTO structure.  */
 static reloc_howto_type *
@@ -129,20 +180,29 @@ elf64_x86_64_info_to_howto (abfd, cache_ptr, dst)
      arelent *cache_ptr;
      Elf64_Internal_Rela *dst;
 {
-  unsigned r_type;
+  unsigned r_type, i;
 
   r_type = ELF64_R_TYPE (dst->r_info);
-  BFD_ASSERT (r_type < (unsigned int) R_X86_64_max);
-  cache_ptr->howto = &x86_64_elf_howto_table[r_type];
+  if (r_type < (unsigned int) R_X86_64_GNU_VTINHERIT)
+    {
+      BFD_ASSERT (r_type <= (unsigned int) R_X86_64_PC8);
+      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_PC8 - 1);
+    }
+  cache_ptr->howto = &x86_64_elf_howto_table[i];
   BFD_ASSERT (r_type == cache_ptr->howto->type);
 }
 \f
-/* Functions for the x86-64 ELF linker.  */
+/* Functions for the x86-64 ELF linker.         */
 
-/* The name of the dynamic interpreter.  This is put in the .interp
+/* The name of the dynamic interpreter.         This is put in the .interp
    section.  */
 
-#define ELF_DYNAMIC_INTERPRETER "/lib/libd64.so.1"
+#define ELF_DYNAMIC_INTERPRETER "/lib/ld64.so.1"
 
 /* The size in bytes of an entry in the global offset table.  */
 
@@ -157,28 +217,28 @@ elf64_x86_64_info_to_howto (abfd, cache_ptr, dst)
 
 static const bfd_byte elf64_x86_64_plt0_entry[PLT_ENTRY_SIZE] =
 {
-  0xff, 0xb3, 8, 0, 0, 0,      /* pushq GOT+8(%rip) */
-  0xff, 0xa3, 16, 0, 0, 0,     /* jmp GOT+16(%rip) */
-  0, 0, 0, 0                   /* pad out to 16 bytes.  */
+  0xff, 0x35, 8, 0, 0, 0,      /* pushq GOT+8(%rip)  */
+  0xff, 0x25, 16, 0, 0, 0,     /* jmpq *GOT+16(%rip) */
+  0x90, 0x90, 0x90, 0x90       /* pad out to 16 bytes with nops.  */
 };
 
 /* Subsequent entries in a procedure linkage table look like this.  */
 
 static const bfd_byte elf64_x86_64_plt_entry[PLT_ENTRY_SIZE] =
 {
-  0xff, 0xa3,  /* jmp *name@GOTPC(%rip) */
-  0, 0, 0, 0,  /* replaced with offset to this symbol in .got.  */
-  0x68,        /* pushq immediate */
+  0xff, 0x25,  /* jmpq *name@GOTPC(%rip) */
+  0, 0, 0, 0,  /* replaced with offset to this symbol in .got.  */
+  0x68,                /* pushq immediate */
   0, 0, 0, 0,  /* replaced with index into relocation table.  */
   0xe9,                /* jmp relative */
   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 in check_relocs for each symbol.  This is so
+   it decides to copy in check_relocs for each symbol. This is so
    that it can discard PC relative relocs if it doesn't need them when
    linking with -Bsymbolic.  We store the information in a field
-   extending the regular ELF linker hash table.  */
+   extending the regular ELF linker hash table.         */
 
 /* This structure keeps track of the number of PC relative relocs we
    have copied for a given symbol.  */
@@ -205,7 +265,8 @@ struct elf64_x86_64_link_hash_entry
 
 /* x86-64  ELF linker hash table.  */
 
-struct elf64_x86_64_link_hash_table {
+struct elf64_x86_64_link_hash_table
+{
   struct elf_link_hash_table root;
 };
 
@@ -227,7 +288,7 @@ static boolean elf64_x86_64_discard_copies
 #define elf64_x86_64_hash_table(p) \
   ((struct elf64_x86_64_link_hash_table *) ((p)->hash))
 
-/* Create an entry in an x86-64 ELF linker hash table.  */
+/* Create an entry in an x86-64 ELF linker hash table. */
 
 static struct bfd_hash_entry *
 elf64_x86_64_link_hash_newfunc (entry, table, string)
@@ -239,7 +300,7 @@ elf64_x86_64_link_hash_newfunc (entry, table, string)
     (struct elf64_x86_64_link_hash_entry *) entry;
 
   /* Allocate the structure if it has not already been allocated by a
-     subclass.  */
+     subclass. */
   if (ret == (struct elf64_x86_64_link_hash_entry *) NULL)
     ret = ((struct elf64_x86_64_link_hash_entry *)
           bfd_hash_allocate (table,
@@ -266,9 +327,9 @@ elf64_x86_64_link_hash_table_create (abfd)
      bfd *abfd;
 {
   struct elf64_x86_64_link_hash_table *ret;
+  bfd_size_type amt = sizeof (struct elf64_x86_64_link_hash_table);
 
-  ret = ((struct elf64_x86_64_link_hash_table *)
-        bfd_alloc (abfd, sizeof (struct elf64_x86_64_link_hash_table)));
+  ret = ((struct elf64_x86_64_link_hash_table *) bfd_alloc (abfd, amt));
   if (ret == (struct elf64_x86_64_link_hash_table *) NULL)
     return NULL;
 
@@ -282,7 +343,7 @@ elf64_x86_64_link_hash_table_create (abfd)
   return &ret->root.root;
 }
 
-boolean
+static boolean
 elf64_x86_64_elf_object_p (abfd)
      bfd *abfd;
 {
@@ -351,7 +412,7 @@ elf64_x86_64_check_relocs (abfd, info, sec, relocs)
        {
        case R_X86_64_GOTPCREL:
        case R_X86_64_GOT32:
-         /* This symbol requires a global offset table entry.  */
+         /* This symbol requires a global offset table entry.  */
 
          if (sgot == NULL)
            {
@@ -402,15 +463,16 @@ elf64_x86_64_check_relocs (abfd, info, sec, relocs)
              /* This is a global offset table entry for a local symbol.  */
              if (local_got_refcounts == NULL)
                {
-                 size_t size;
+                 bfd_size_type size;
 
-                 size = symtab_hdr->sh_info * sizeof (bfd_signed_vma);
+                 size = symtab_hdr->sh_info;
+                 size *= sizeof (bfd_signed_vma);
                  local_got_refcounts = ((bfd_signed_vma *)
                                         bfd_alloc (abfd, size));
                  if (local_got_refcounts == NULL)
                    return false;
                  elf_local_got_refcounts (abfd) = local_got_refcounts;
-                 memset (local_got_refcounts, -1, size);
+                 memset (local_got_refcounts, -1, (size_t) size);
                }
              if (local_got_refcounts[r_symndx] == -1)
                {
@@ -432,27 +494,28 @@ elf64_x86_64_check_relocs (abfd, info, sec, relocs)
 
        case R_X86_64_PLT32:
          /* This symbol requires a procedure linkage table entry.  We
-             actually build the entry in adjust_dynamic_symbol,
-             because this might be a case of linking PIC code which is
-             never referenced by a dynamic object, in which case we
-             don't need to generate a procedure linkage table entry
-             after all.  */
+            actually build the entry in adjust_dynamic_symbol,
+            because this might be a case of linking PIC code which is
+            never referenced by a dynamic object, in which case we
+            don't need to generate a procedure linkage table entry
+            after all.  */
 
          /* If this is a local symbol, we resolve it directly without
-             creating a procedure linkage table entry.  */
+            creating a procedure linkage table entry.  */
          if (h == NULL)
            continue;
 
+         h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
          if (h->plt.refcount == -1)
-           {
-             h->plt.refcount = 1;
-             h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
-           }
+           h->plt.refcount = 1;
          else
            h->plt.refcount += 1;
          break;
 
+       case R_X86_64_8:
+       case R_X86_64_16:
        case R_X86_64_32:
+       case R_X86_64_64:
        case R_X86_64_32S:
        case R_X86_64_PC32:
          if (h != NULL)
@@ -464,7 +527,7 @@ elf64_x86_64_check_relocs (abfd, info, sec, relocs)
             into the shared library.  However, if we are linking with
             -Bsymbolic, we do not need to copy a reloc against a
             global symbol which is defined in an object we are
-            including in the link (i.e., DEF_REGULAR is set).  At
+            including in the link (i.e., DEF_REGULAR is set).  At
             this point we have not seen all the input files, so it is
             possible that DEF_REGULAR is not set now but will be set
             later (it is never cleared).  We account for that
@@ -474,7 +537,9 @@ elf64_x86_64_check_relocs (abfd, info, sec, relocs)
             and symbol visibility changes render the symbol local.  */
          if (info->shared
              && (sec->flags & SEC_ALLOC) != 0
-             && (ELF64_R_TYPE (rel->r_info) != R_X86_64_PC32
+             && (((ELF64_R_TYPE (rel->r_info) != R_X86_64_PC8)
+                 && (ELF64_R_TYPE (rel->r_info) != R_X86_64_PC16)
+                 && (ELF64_R_TYPE (rel->r_info) != R_X86_64_PC32))
                  || (h != NULL
                      && (! info->symbolic
                          || (h->elf_link_hash_flags
@@ -510,9 +575,11 @@ elf64_x86_64_check_relocs (abfd, info, sec, relocs)
                        flags |= SEC_ALLOC | SEC_LOAD;
                      if (sreloc == NULL
                          || ! bfd_set_section_flags (dynobj, sreloc, flags)
-                         || ! bfd_set_section_alignment (dynobj, sreloc, 2))
+                         || ! bfd_set_section_alignment (dynobj, sreloc, 3))
                        return false;
                    }
+                 if (sec->flags & SEC_READONLY)
+                   info->flags |= DF_TEXTREL;
                }
 
              sreloc->_raw_size += sizeof (Elf64_External_Rela);
@@ -524,7 +591,9 @@ elf64_x86_64_check_relocs (abfd, info, sec, relocs)
                 elf64_x86_64 linker hash table, which means that h is
                 really a pointer to an elf64_x86_64_link_hash_entry.  */
              if (h != NULL
-                 && ELF64_R_TYPE (rel->r_info) == R_X86_64_PC32)
+                 && ((ELF64_R_TYPE (rel->r_info) == R_X86_64_PC8)
+                     || (ELF64_R_TYPE (rel->r_info) == R_X86_64_PC16)
+                     || (ELF64_R_TYPE (rel->r_info) == R_X86_64_PC32)))
                {
                  struct elf64_x86_64_link_hash_entry *eh;
                  struct elf64_x86_64_pcrel_relocs_copied *p;
@@ -538,7 +607,7 @@ elf64_x86_64_check_relocs (abfd, info, sec, relocs)
                  if (p == NULL)
                    {
                      p = ((struct elf64_x86_64_pcrel_relocs_copied *)
-                          bfd_alloc (dynobj, sizeof *p));
+                          bfd_alloc (dynobj, (bfd_size_type) sizeof *p));
                      if (p == NULL)
                        return false;
                      p->next = eh->pcrel_relocs_copied;
@@ -551,6 +620,20 @@ elf64_x86_64_check_relocs (abfd, info, sec, relocs)
                }
            }
          break;
+
+         /* This relocation describes the C++ object vtable hierarchy.
+            Reconstruct it for later use during GC.  */
+       case R_X86_64_GNU_VTINHERIT:
+         if (!_bfd_elf64_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
+           return false;
+         break;
+
+         /* This relocation describes which C++ vtable entries are actually
+            used.  Record for later use during GC.  */
+       case R_X86_64_GNU_VTENTRY:
+         if (!_bfd_elf64_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+           return false;
+         break;
        }
     }
 
@@ -558,7 +641,7 @@ elf64_x86_64_check_relocs (abfd, info, sec, relocs)
 }
 
 /* Return the section that should be marked against GC for a given
-   relocation.  */
+   relocation. */
 
 static asection *
 elf64_x86_64_gc_mark_hook (abfd, info, rel, h, sym)
@@ -570,17 +653,25 @@ elf64_x86_64_gc_mark_hook (abfd, info, rel, h, sym)
 {
   if (h != NULL)
     {
-      switch (h->root.type)
+      switch (ELF64_R_TYPE (rel->r_info))
        {
-       case bfd_link_hash_defined:
-       case bfd_link_hash_defweak:
-         return h->root.u.def.section;
-
-       case bfd_link_hash_common:
-         return h->root.u.c.p->section;
+       case R_X86_64_GNU_VTINHERIT:
+       case R_X86_64_GNU_VTENTRY:
+         break;
 
        default:
-         break;
+         switch (h->root.type)
+           {
+           case bfd_link_hash_defined:
+           case bfd_link_hash_defweak:
+             return h->root.u.def.section;
+
+           case bfd_link_hash_common:
+             return h->root.u.c.p->section;
+
+           default:
+             break;
+           }
        }
     }
   else
@@ -597,7 +688,7 @@ elf64_x86_64_gc_mark_hook (abfd, info, rel, h, sym)
   return NULL;
 }
 
-/* Update the got entry reference counts for the section being removed.  */
+/* Update the got entry reference counts for the section being removed.         */
 
 static boolean
 elf64_x86_64_gc_sweep_hook (abfd, info, sec, relocs)
@@ -683,7 +774,7 @@ elf64_x86_64_gc_sweep_hook (abfd, info, sec, relocs)
    regular object.  The current definition is in some section of the
    dynamic object, but we're not including those sections.  We have to
    change the definition to something the rest of the link can
-   understand.  */
+   understand. */
 
 static boolean
 elf64_x86_64_adjust_dynamic_symbol (info, h)
@@ -713,21 +804,16 @@ elf64_x86_64_adjust_dynamic_symbol (info, h)
   if (h->type == STT_FUNC
       || (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
     {
-      if (! elf_hash_table (info)->dynamic_sections_created)
+      if ((! info->shared
+          && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0
+          && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) == 0)
+         || (info->shared && h->plt.refcount <= 0))
        {
-         /* FIXME: These are the sparc64 comment and then the i386 comment.
-            How we need to deal with this and why remains to be seen.  */
-         /* This case can occur if we saw a WPLT30 reloc in an input
-             file, but none of the input files were dynamic objects.
-             In such a case, we don't actually need to build a
-             procedure linkage table, and we can just do a WDISP30
-             reloc instead.  */
          /* This case can occur if we saw a PLT32 reloc in an input
             file, but the symbol was never referred to by a dynamic
             object, or if all references were garbage collected.  In
             such a case, we don't actually need to build a procedure
             linkage table, and we can just do a PC32 reloc instead.  */
-         /* i386 code: */
          h->plt.offset = (bfd_vma) -1;
          h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
          return true;
@@ -750,7 +836,7 @@ elf64_x86_64_adjust_dynamic_symbol (info, h)
 
       /* If this symbol is not defined in a regular file, and we are
         not generating a shared library, then set the symbol to this
-        location in the .plt.  This is required to make function
+        location in the .plt.  This is required to make function
         pointers compare as equal between the normal executable and
         the shared library.  */
       if (! info->shared
@@ -765,6 +851,12 @@ elf64_x86_64_adjust_dynamic_symbol (info, h)
       /* Make room for this entry.  */
       s->_raw_size += PLT_ENTRY_SIZE;
 
+      /* We also need to make an entry in the .got.plt section, which
+        will be placed in the .got section by the linker script.  */
+      s = bfd_get_section_by_name (dynobj, ".got.plt");
+      BFD_ASSERT (s != NULL);
+      s->_raw_size += GOT_ENTRY_SIZE;
+
       /* We also need to make an entry in the .rela.plt section.  */
       s = bfd_get_section_by_name (dynobj, ".rela.plt");
       BFD_ASSERT (s != NULL);
@@ -775,7 +867,7 @@ elf64_x86_64_adjust_dynamic_symbol (info, h)
 
   /* If this is a weak symbol, and there is a real definition, the
      processor independent code will have arranged for us to see the
-     real definition first, and we can just use the same value.  */
+     real definition first, and we can just use the same value.         */
   if (h->weakdef != NULL)
     {
       BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined
@@ -786,12 +878,12 @@ elf64_x86_64_adjust_dynamic_symbol (info, h)
     }
 
   /* This is a reference to a symbol defined by a dynamic object which
-     is not a function.  */
+     is not a function.         */
 
   /* If we are creating a shared library, we must presume that the
      only references to the symbol are via the global offset table.
      For such cases we need not do anything here; the relocations will
-     be handled correctly by relocate_section.  */
+     be handled correctly by relocate_section. */
   if (info->shared)
     return true;
 
@@ -801,7 +893,7 @@ elf64_x86_64_adjust_dynamic_symbol (info, h)
     return true;
 
   /* We must allocate the symbol in our .dynbss section, which will
-     become part of the .bss section of the executable.  There will be
+     become part of the .bss section of the executable.         There will be
      an entry for this symbol in the .dynsym section.  The dynamic
      object will contain position independent code, so all references
      from the dynamic object to this symbol will go through the global
@@ -828,7 +920,7 @@ elf64_x86_64_adjust_dynamic_symbol (info, h)
     }
 
   /* We need to figure out the alignment required for this symbol.  I
-     have no idea how ELF linkers handle this.  16-bytes is the size
+     have no idea how ELF linkers handle this. 16-bytes is the size
      of the largest type that requires hard alignment -- long double.  */
   /* FIXME: This is VERY ugly. Should be fixed for all architectures using
      this construct.  */
@@ -858,14 +950,13 @@ elf64_x86_64_adjust_dynamic_symbol (info, h)
 
 static boolean
 elf64_x86_64_size_dynamic_sections (output_bfd, info)
-     bfd *output_bfd;
+     bfd *output_bfd ATTRIBUTE_UNUSED;
      struct bfd_link_info *info;
 {
   bfd *dynobj;
   asection *s;
   boolean plt;
   boolean relocs;
-  boolean reltext;
 
   dynobj = elf_hash_table (info)->dynobj;
   BFD_ASSERT (dynobj != NULL);
@@ -884,10 +975,10 @@ elf64_x86_64_size_dynamic_sections (output_bfd, info)
   else
     {
       /* We may have created entries in the .rela.got section.
-         However, if we are not creating the dynamic sections, we will
-         not actually use these entries.  Reset the size of .rela.got,
-         which will cause it to get stripped from the output file
-         below.  */
+        However, if we are not creating the dynamic sections, we will
+        not actually use these entries.  Reset the size of .rela.got,
+        which will cause it to get stripped from the output file
+        below.  */
       s = bfd_get_section_by_name (dynobj, ".rela.got");
       if (s != NULL)
        s->_raw_size = 0;
@@ -905,7 +996,7 @@ elf64_x86_64_size_dynamic_sections (output_bfd, info)
   /* The check_relocs and adjust_dynamic_symbol entry points have
      determined the sizes of the various dynamic sections.  Allocate
      memory for them.  */
-  plt = relocs = reltext = false;
+  plt = relocs = false;
   for (s = dynobj->sections; s != NULL; s = s->next)
     {
       const char *name;
@@ -924,7 +1015,7 @@ elf64_x86_64_size_dynamic_sections (output_bfd, info)
          if (s->_raw_size == 0)
            {
              /* Strip this section if we don't need it; see the
-                 comment below.  */
+                comment below.  */
              strip = true;
            }
          else
@@ -950,29 +1041,8 @@ elf64_x86_64_size_dynamic_sections (output_bfd, info)
            }
          else
            {
-             asection *target;
-
-             /* Remember whether there are any reloc sections other
-                 than .rela.plt.  */
              if (strcmp (name, ".rela.plt") != 0)
-               {
-                 const char *outname;
-
-                 relocs = true;
-
-                 /* If this relocation section applies to a read only
-                    section, then we probably need a DT_TEXTREL
-                    entry.  The entries in the .rela.plt section
-                    really apply to the .got section, which we
-                    created ourselves and so know is not readonly.  */
-                 outname = bfd_get_section_name (output_bfd,
-                                                 s->output_section);
-                 target = bfd_get_section_by_name (output_bfd, outname + 5);
-                 if (target != NULL
-                     && (target->flags & SEC_READONLY) != 0
-                     && (target->flags & SEC_ALLOC) != 0)
-                   reltext = true;
-               }
+               relocs = true;
 
              /* We use the reloc_count field as a counter if we need
                 to copy relocs into the output file.  */
@@ -1006,40 +1076,41 @@ elf64_x86_64_size_dynamic_sections (output_bfd, info)
       /* Add some entries to the .dynamic section.  We fill in the
         values later, in elf64_x86_64_finish_dynamic_sections, but we
         must add the entries now so that we get the correct size for
-        the .dynamic section.  The DT_DEBUG entry is filled in by the
+        the .dynamic section.  The DT_DEBUG entry is filled in by the
         dynamic linker and used by the debugger.  */
+#define add_dynamic_entry(TAG, VAL) \
+  bfd_elf64_add_dynamic_entry (info, (bfd_vma) (TAG), (bfd_vma) (VAL))
+
       if (! info->shared)
        {
-         if (! bfd_elf64_add_dynamic_entry (info, DT_DEBUG, 0))
+         if (!add_dynamic_entry (DT_DEBUG, 0))
            return false;
        }
 
       if (plt)
        {
-         /* FIXME: Are all these needed?  */
-         if (! bfd_elf64_add_dynamic_entry (info, DT_PLTGOT, 0)
-             || ! bfd_elf64_add_dynamic_entry (info, DT_PLTRELSZ, 0)
-             || ! bfd_elf64_add_dynamic_entry (info, DT_PLTREL, DT_REL)
-             || ! bfd_elf64_add_dynamic_entry (info, DT_JMPREL, 0))
+         if (!add_dynamic_entry (DT_PLTGOT, 0)
+             || !add_dynamic_entry (DT_PLTRELSZ, 0)
+             || !add_dynamic_entry (DT_PLTREL, DT_RELA)
+             || !add_dynamic_entry (DT_JMPREL, 0))
            return false;
        }
 
       if (relocs)
        {
-         if (! bfd_elf64_add_dynamic_entry (info, DT_RELA, 0)
-             || ! bfd_elf64_add_dynamic_entry (info, DT_RELASZ, 0)
-             || ! bfd_elf64_add_dynamic_entry (info, DT_RELAENT,
-                                               sizeof (Elf64_External_Rela)))
+         if (!add_dynamic_entry (DT_RELA, 0)
+             || !add_dynamic_entry (DT_RELASZ, 0)
+             || !add_dynamic_entry (DT_RELAENT, sizeof (Elf64_External_Rela)))
            return false;
        }
 
-      if (reltext)
+      if ((info->flags & DF_TEXTREL) != 0)
        {
-         if (! bfd_elf64_add_dynamic_entry (info, DT_TEXTREL, 0))
+         if (!add_dynamic_entry (DT_TEXTREL, 0))
            return false;
-         info->flags |= DF_TEXTREL;
        }
     }
+#undef add_dynamic_entry
 
   return true;
 }
@@ -1079,7 +1150,7 @@ elf64_x86_64_discard_copies (h, inf)
 
 static boolean
 elf64_x86_64_relocate_section (output_bfd, info, input_bfd, input_section,
-                             contents, relocs, local_syms, local_sections)
+                              contents, relocs, local_syms, local_sections)
      bfd *output_bfd;
      struct bfd_link_info *info;
      bfd *input_bfd;
@@ -1126,6 +1197,9 @@ elf64_x86_64_relocate_section (output_bfd, info, input_bfd, input_section,
       unsigned int indx;
 
       r_type = ELF64_R_TYPE (rela->r_info);
+      if (r_type == (int) R_X86_64_GNU_VTINHERIT
+         || r_type == (int) R_X86_64_GNU_VTENTRY)
+       continue;
 
       if ((indx = (unsigned) r_type) >= R_X86_64_max)
        {
@@ -1155,7 +1229,7 @@ elf64_x86_64_relocate_section (output_bfd, info, input_bfd, input_section,
          continue;
        }
 
-      /* This is a final link.  */
+      /* This is a final link. */
       h = NULL;
       sym = NULL;
       sec = NULL;
@@ -1177,7 +1251,41 @@ elf64_x86_64_relocate_section (output_bfd, info, input_bfd, input_section,
              || h->root.type == bfd_link_hash_defweak)
            {
              sec = h->root.u.def.section;
-             if (sec->output_section == NULL)
+             if ((r_type == R_X86_64_PLT32
+                  && splt != NULL
+                  && h->plt.offset != (bfd_vma) -1)
+                 || ((r_type == R_X86_64_GOT32 || r_type == R_X86_64_GOTPCREL)
+                     && elf_hash_table (info)->dynamic_sections_created
+                     && (!info->shared
+                         || (! info->symbolic && h->dynindx != -1)
+                         || (h->elf_link_hash_flags
+                             & ELF_LINK_HASH_DEF_REGULAR) == 0))
+                 || (info->shared
+                     && ((! info->symbolic && h->dynindx != -1)
+                         || (h->elf_link_hash_flags
+                             & ELF_LINK_HASH_DEF_REGULAR) == 0)
+                     && (r_type == R_X86_64_8
+                         || r_type == R_X86_64_16
+                         || r_type == R_X86_64_32
+                         || r_type == R_X86_64_64
+                         || r_type == R_X86_64_PC8
+                         || r_type == R_X86_64_PC16
+                         || r_type == R_X86_64_PC32)
+                      && ((input_section->flags & SEC_ALLOC) != 0
+                          /* DWARF will emit R_X86_64_32 relocations in its
+                             sections against symbols defined externally
+                             in shared libraries.  We can't do anything
+                             with them here.  */
+                          || ((input_section->flags & SEC_DEBUGGING) != 0
+                             && (h->elf_link_hash_flags
+                                 & ELF_LINK_HASH_DEF_DYNAMIC) != 0))))
+               {
+                 /* In these cases, we don't need the relocation
+                     value.  We check specially because in some
+                     obscure cases sec->output_section will be NULL.  */
+                 relocation = 0;
+               }
+             else if (sec->output_section == NULL)
                {
                  (*_bfd_error_handler)
                    (_("%s: warning: unresolvable relocation against symbol `%s' from %s section"),
@@ -1214,92 +1322,10 @@ elf64_x86_64_relocate_section (output_bfd, info, input_bfd, input_section,
        case R_X86_64_GOT32:
          /* Relocation is to the entry for this symbol in the global
             offset table.  */
-         BFD_ASSERT (sgot != NULL);
-
-         if (h != NULL)
-           {
-             bfd_vma off = h->got.offset;
-             BFD_ASSERT (off != (bfd_vma) -1);
-
-             if (! elf_hash_table (info)->dynamic_sections_created
-                 || (info->shared
-                     && (info->symbolic || h->dynindx == -1)
-                     && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)))
-               {
-                 /* This is actually a static link, or it is a -Bsymbolic
-                    link and the symbol is defined locally, or the symbol
-                    was forced to be local because of a version file.  We
-                    must initialize this entry in the global offset table.
-                    Since the offset must always be a multiple of 8, we
-                    use the least significant bit to record whether we
-                    have initialized it already.
-
-                    When doing a dynamic link, we create a .rela.got
-                    relocation entry to initialize the value.  This is
-                    done in the finish_dynamic_symbol routine.  */
-                 if ((off & 1) != 0)
-                   off &= ~1;
-                 else
-                   {
-                     bfd_put_64 (output_bfd, relocation,
-                                 sgot->contents + off);
-                     h->got.offset |= 1;
-                   }
-               }
-             relocation = sgot->output_offset + off;
-           }
-         else
-           {
-             bfd_vma off;
-
-             BFD_ASSERT (local_got_offsets != NULL
-                         && local_got_offsets[r_symndx] != (bfd_vma) -1);
-
-             off = local_got_offsets[r_symndx];
-
-             /* The offset must always be a multiple of 8.  We use
-                 the least significant bit to record whether we have
-                 already generated the necessary reloc.  */
-             if ((off & 1) != 0)
-               off &= ~1;
-             else
-               {
-                 bfd_put_64 (output_bfd, relocation, sgot->contents + off);
-
-                 if (info->shared)
-                   {
-                     asection *srelgot;
-                     Elf_Internal_Rela outrel;
-
-                     /* We need to generate a R_X86_64_RELATIVE reloc
-                        for the dynamic linker.  */
-                     srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
-                     BFD_ASSERT (srelgot != NULL);
-
-                     outrel.r_offset = (sgot->output_section->vma
-                                        + sgot->output_offset
-                                        + off);
-                     outrel.r_info = ELF64_R_INFO (0, R_X86_64_RELATIVE);
-                     outrel.r_addend = relocation;
-                     bfd_elf64_swap_reloca_out (output_bfd, &outrel,
-                                                (((Elf64_External_Rela *)
-                                                  srelgot->contents)
-                                                 + srelgot->reloc_count));
-                     ++srelgot->reloc_count;
-                   }
-
-                 local_got_offsets[r_symndx] |= 1;
-               }
-
-             relocation = sgot->output_offset + off;
-           }
-
-         break;
-
        case R_X86_64_GOTPCREL:
          /* Use global offset table as symbol value.  */
-
          BFD_ASSERT (sgot != NULL);
+
          if (h != NULL)
            {
              bfd_vma off = h->got.offset;
@@ -1312,15 +1338,15 @@ elf64_x86_64_relocate_section (output_bfd, info, input_bfd, input_section,
                {
                  /* This is actually a static link, or it is a -Bsymbolic
                     link and the symbol is defined locally, or the symbol
-                    was forced to be local because of a version file.  We
+                    was forced to be local because of a version file.  We
                     must initialize this entry in the global offset table.
                     Since the offset must always be a multiple of 8, we
                     use the least significant bit to record whether we
                     have initialized it already.
 
                     When doing a dynamic link, we create a .rela.got
-                    relocation entry to initialize the value.  This is
-                    done in the finish_dynamic_symbol routine.  */
+                    relocation entry to initialize the value.  This is
+                    done in the finish_dynamic_symbol routine.  */
                  if ((off & 1) != 0)
                    off &= ~1;
                  else
@@ -1330,7 +1356,10 @@ elf64_x86_64_relocate_section (output_bfd, info, input_bfd, input_section,
                      h->got.offset |= 1;
                    }
                }
-             relocation = sgot->output_offset + off;
+             if (r_type == R_X86_64_GOTPCREL)
+               relocation = sgot->output_section->vma + sgot->output_offset + off;
+             else
+               relocation = sgot->output_offset + off;
            }
          else
            {
@@ -1342,8 +1371,8 @@ elf64_x86_64_relocate_section (output_bfd, info, input_bfd, input_section,
              off = local_got_offsets[r_symndx];
 
              /* The offset must always be a multiple of 8.  We use
-                 the least significant bit to record whether we have
-                 already generated the necessary reloc.  */
+                the least significant bit to record whether we have
+                already generated the necessary reloc.  */
              if ((off & 1) != 0)
                off &= ~1;
              else
@@ -1375,8 +1404,12 @@ elf64_x86_64_relocate_section (output_bfd, info, input_bfd, input_section,
                  local_got_offsets[r_symndx] |= 1;
                }
 
-             relocation = sgot->output_section->vma + off;
+             if (r_type == R_X86_64_GOTPCREL)
+               relocation = sgot->output_section->vma + sgot->output_offset + off;
+             else
+               relocation = sgot->output_offset + off;
            }
+
          break;
 
        case R_X86_64_PLT32:
@@ -1384,15 +1417,15 @@ elf64_x86_64_relocate_section (output_bfd, info, input_bfd, input_section,
             procedure linkage table.  */
 
          /* Resolve a PLT32 reloc against a local symbol directly,
-             without using the procedure linkage table.  */
+            without using the procedure linkage table.  */
          if (h == NULL)
            break;
 
          if (h->plt.offset == (bfd_vma) -1 || splt == NULL)
            {
              /* We didn't make a PLT entry for this symbol.  This
-                 happens when statically linking PIC code, or when
-                 using -Bsymbolic.  */
+                happens when statically linking PIC code, or when
+                using -Bsymbolic.  */
              break;
            }
 
@@ -1401,30 +1434,28 @@ elf64_x86_64_relocate_section (output_bfd, info, input_bfd, input_section,
                        + h->plt.offset);
          break;
 
-       case R_X86_64_8:
-       case R_X86_64_16:
-       case R_X86_64_32:
        case R_X86_64_PC8:
        case R_X86_64_PC16:
        case R_X86_64_PC32:
-         /* FIXME: The abi says the linker should make sure the value is
-            the same when it's zeroextended to 64 bit.  */
-         if (info->shared
-             && (input_section->flags & SEC_ALLOC) != 0
-             && ((r_type != R_X86_64_PC8 && r_type != R_X86_64_PC16
-                  && r_type != R_X86_64_PC32)
-                 || (h != NULL
-                     && h->dynindx != -1
-                     && (! info->symbolic
-                         || (h->elf_link_hash_flags
-                             & ELF_LINK_HASH_DEF_REGULAR) == 0))))
+         if (h == NULL || h->dynindx == -1
+             || (info->symbolic
+                 && h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))
+           break;
+         /* Fall through.  */
+       case R_X86_64_8:
+       case R_X86_64_16:
+       case R_X86_64_32:
+       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.  */
+         if (info->shared && (input_section->flags & SEC_ALLOC) != 0)
            {
              Elf_Internal_Rela outrel;
              boolean skip, relocate;
 
              /* When generating a shared object, these relocations
                 are copied into the output file to be resolved at run
-                time.  */
+                time.  */
 
              if (sreloc == NULL)
                {
@@ -1472,34 +1503,60 @@ elf64_x86_64_relocate_section (output_bfd, info, input_bfd, input_section,
                  memset (&outrel, 0, sizeof outrel);
                  relocate = false;
                }
-             else if ((r_type == R_X86_64_PC8) || (r_type == R_X86_64_PC16)
-                      || (r_type == R_X86_64_PC32))
+             /* h->dynindx may be -1 if this symbol was marked to
+                become local.  */
+             else if (h != NULL
+                      && ((! info->symbolic && h->dynindx != -1)
+                          || (h->elf_link_hash_flags
+                              & ELF_LINK_HASH_DEF_REGULAR) == 0))
                {
-                 BFD_ASSERT (h != NULL && h->dynindx != -1);
+                 BFD_ASSERT (h->dynindx != -1);
                  relocate = false;
                  outrel.r_info = ELF64_R_INFO (h->dynindx, r_type);
-                 outrel.r_addend = rela->r_addend;
+                 outrel.r_addend = relocation + rela->r_addend;
                }
              else
                {
-                 /* h->dynindx may be -1 if this symbol was marked to
-                     become local.  */
-                 if (h == NULL
-                     || ((info->symbolic || h->dynindx == -1)
-                         && (h->elf_link_hash_flags
-                             & ELF_LINK_HASH_DEF_REGULAR) != 0))
+                 if (r_type == R_X86_64_64)
                    {
                      relocate = true;
                      outrel.r_info = ELF64_R_INFO (0, R_X86_64_RELATIVE);
-                     outrel.r_addend = rela->r_addend;
+                     outrel.r_addend = relocation + rela->r_addend;
                    }
                  else
                    {
-                     BFD_ASSERT (h->dynindx != -1);
+                     long sindx;
+
+                     if (h == NULL)
+                       sec = local_sections[r_symndx];
+                     else
+                       {
+                         BFD_ASSERT (h->root.type == bfd_link_hash_defined
+                                     || (h->root.type
+                                         == bfd_link_hash_defweak));
+                         sec = h->root.u.def.section;
+                       }
+                     if (sec != NULL && bfd_is_abs_section (sec))
+                       sindx = 0;
+                     else if (sec == NULL || sec->owner == NULL)
+                       {
+                         bfd_set_error (bfd_error_bad_value);
+                         return false;
+                       }
+                     else
+                       {
+                         asection *osec;
+
+                         osec = sec->output_section;
+                         sindx = elf_section_data (osec)->dynindx;
+                         BFD_ASSERT (sindx > 0);
+                       }
+
                      relocate = false;
-                     outrel.r_info = ELF64_R_INFO (h->dynindx, R_X86_64_32);
-                     outrel.r_addend = rela->r_addend;
+                     outrel.r_info = ELF64_R_INFO (sindx, r_type);
+                     outrel.r_addend = relocation + rela->r_addend;
                    }
+
                }
 
              bfd_elf64_swap_reloca_out (output_bfd, &outrel,
@@ -1586,7 +1643,7 @@ elf64_x86_64_finish_dynamic_symbol (output_bfd, info, h, sym)
       Elf_Internal_Rela rela;
 
       /* This symbol has an entry in the procedure linkage table.  Set
-        it up.  */
+        it up.  */
 
       BFD_ASSERT (h->dynindx != -1);
 
@@ -1602,8 +1659,8 @@ elf64_x86_64_finish_dynamic_symbol (output_bfd, info, h, sym)
       plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1;
 
       /* Get the offset into the .got table of the entry that
-        corresponds to this function.  Each .got entry is GOT_ENTRY_SIZE
-        bytes. The first three are reserved.  */
+        corresponds to this function.  Each .got entry is GOT_ENTRY_SIZE
+        bytes. The first three are reserved for the dynamic linker.  */
       got_offset = (plt_index + 3) * GOT_ENTRY_SIZE;
 
       /* Fill in the entry in the procedure linkage table.  */
@@ -1613,13 +1670,26 @@ elf64_x86_64_finish_dynamic_symbol (output_bfd, info, h, sym)
       /* Insert the relocation positions of the plt section.  The magic
         numbers at the end of the statements are the positions of the
         relocations in the plt section.  */
-      bfd_put_64 (output_bfd, got_offset, splt->contents + h->plt.offset + 2);
-      bfd_put_64 (output_bfd, plt_index * sizeof (Elf64_External_Rela),
+      /* Put offset for jmp *name@GOTPCREL(%rip), since the
+        instruction uses 6 bytes, subtract this value.  */
+      bfd_put_32 (output_bfd,
+                     (sgot->output_section->vma
+                      + sgot->output_offset
+                      + got_offset
+                      - splt->output_section->vma
+                      - splt->output_offset
+                      - h->plt.offset
+                      - 6),
+                 splt->contents + h->plt.offset + 2);
+      /* Put relocation index.  */
+      bfd_put_32 (output_bfd, plt_index,
                  splt->contents + h->plt.offset + 7);
-      bfd_put_64 (output_bfd, - (h->plt.offset + PLT_ENTRY_SIZE),
+      /* Put offset for jmp .PLT0.  */
+      bfd_put_32 (output_bfd, - (h->plt.offset + PLT_ENTRY_SIZE),
                  splt->contents + h->plt.offset + 12);
 
-      /* Fill in the entry in the global offset table.  */
+      /* Fill in the entry in the global offset table, initially this
+        points to the pushq instruction in the PLT which is at offset 6.  */
       bfd_put_64 (output_bfd, (splt->output_section->vma + splt->output_offset
                               + h->plt.offset + 6),
                  sgot->contents + got_offset);
@@ -1637,11 +1707,65 @@ elf64_x86_64_finish_dynamic_symbol (output_bfd, info, h, sym)
       if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
        {
          /* Mark the symbol as undefined, rather than as defined in
-            the .plt section.  Leave the value alone.  */
+            the .plt section.  Leave the value alone.  */
          sym->st_shndx = SHN_UNDEF;
+         /* If the symbol is weak, we do need to clear the value.
+            Otherwise, the PLT entry would provide a definition for
+            the symbol even if the symbol wasn't defined anywhere,
+            and so the symbol would never be NULL.  */
+         if ((h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR_NONWEAK)
+             == 0)
+           sym->st_value = 0;
        }
     }
 
+  if (h->got.offset != (bfd_vma) -1)
+    {
+      asection *sgot;
+      asection *srela;
+      Elf_Internal_Rela rela;
+
+      /* This symbol has an entry in the global offset table.  Set it
+         up.  */
+
+      sgot = bfd_get_section_by_name (dynobj, ".got");
+      srela = bfd_get_section_by_name (dynobj, ".rela.got");
+      BFD_ASSERT (sgot != NULL && srela != NULL);
+
+      rela.r_offset = (sgot->output_section->vma
+                      + sgot->output_offset
+                      + (h->got.offset &~ (bfd_vma) 1));
+
+      /* If this is a static link, or it is a -Bsymbolic link and the
+        symbol is defined locally or was forced to be local because
+        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 (! elf_hash_table (info)->dynamic_sections_created
+         || (info->shared
+             && (info->symbolic || h->dynindx == -1)
+             && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)))
+       {
+         BFD_ASSERT((h->got.offset & 1) != 0);
+         rela.r_info = ELF64_R_INFO (0, R_X86_64_RELATIVE);
+         rela.r_addend = (h->root.u.def.value
+                          + h->root.u.def.section->output_section->vma
+                          + h->root.u.def.section->output_offset);
+       }
+      else
+       {
+         BFD_ASSERT((h->got.offset & 1) == 0);
+         bfd_put_64 (output_bfd, (bfd_vma) 0, sgot->contents + h->got.offset);
+         rela.r_info = ELF64_R_INFO (h->dynindx, R_X86_64_GLOB_DAT);
+         rela.r_addend = 0;
+       }
+
+      bfd_elf64_swap_reloca_out (output_bfd, &rela,
+                                ((Elf64_External_Rela *) srela->contents
+                                 + srela->reloc_count));
+      ++srela->reloc_count;
+    }
+
   if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_COPY) != 0)
     {
       asection *s;
@@ -1689,6 +1813,8 @@ elf64_x86_64_finish_dynamic_sections (output_bfd, info)
 
   dynobj = elf_hash_table (info)->dynobj;
 
+  sgot = bfd_get_section_by_name (dynobj, ".got.plt");
+  BFD_ASSERT (sgot != NULL);
   sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
 
   if (elf_hash_table (info)->dynamic_sections_created)
@@ -1696,8 +1822,7 @@ elf64_x86_64_finish_dynamic_sections (output_bfd, info)
       asection *splt;
       Elf64_External_Dyn *dyncon, *dynconend;
 
-      splt = bfd_get_section_by_name (dynobj, ".plt");
-      BFD_ASSERT (splt != NULL && sdyn != NULL);
+      BFD_ASSERT (sdyn != NULL);
 
       dyncon = (Elf64_External_Dyn *) sdyn->contents;
       dynconend = (Elf64_External_Dyn *) (sdyn->contents + sdyn->_raw_size);
@@ -1712,7 +1837,7 @@ elf64_x86_64_finish_dynamic_sections (output_bfd, info)
          switch (dyn.d_tag)
            {
            default:
-             break;
+             continue;
 
            case DT_PLTGOT:
              name = ".got";
@@ -1730,14 +1855,14 @@ elf64_x86_64_finish_dynamic_sections (output_bfd, info)
            case DT_RELASZ:
              /* FIXME: This comment and code is from elf64-alpha.c:  */
              /* My interpretation of the TIS v1.1 ELF document indicates
-                that RELASZ should not include JMPREL.  This is not what
+                that RELASZ should not include JMPREL.  This is not what
                 the rest of the BFD does.  It is, however, what the
                 glibc ld.so wants.  Do this fixup here until we found
                 out who is right.  */
              s = bfd_get_section_by_name (output_bfd, ".rela.plt");
              if (s)
                {
-                 /* Subtract JMPREL size from RELASZ.  */
+                 /* Subtract JMPREL size from RELASZ.  */
                  dyn.d_un.d_val -=
                    (s->_cooked_size ? s->_cooked_size : s->_raw_size);
                }
@@ -1750,14 +1875,37 @@ elf64_x86_64_finish_dynamic_sections (output_bfd, info)
                (s->_cooked_size != 0 ? s->_cooked_size : s->_raw_size);
              break;
            }
-
          bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon);
        }
 
       /* Initialize the contents of the .plt section.  */
+      splt = bfd_get_section_by_name (dynobj, ".plt");
+      BFD_ASSERT (splt != NULL);
       if (splt->_raw_size > 0)
        {
-           memcpy (splt->contents, elf64_x86_64_plt0_entry, PLT_ENTRY_SIZE);
+         /* Fill in the first entry in the procedure linkage table.  */
+         memcpy (splt->contents, elf64_x86_64_plt0_entry, PLT_ENTRY_SIZE);
+         /* Add offset for pushq GOT+8(%rip), since the instruction
+            uses 6 bytes subtract this value.  */
+         bfd_put_32 (output_bfd,
+                     (sgot->output_section->vma
+                      + sgot->output_offset
+                      + 8
+                      - splt->output_section->vma
+                      - splt->output_offset
+                      - 6),
+                     splt->contents + 2);
+         /* Add offset for jmp *GOT+16(%rip). The 12 is the offset to
+            the end of the instruction.  */
+         bfd_put_32 (output_bfd,
+                     (sgot->output_section->vma
+                      + sgot->output_offset
+                      + 16
+                      - splt->output_section->vma
+                      - splt->output_offset
+                      - 12),
+                     splt->contents + 8);
+
        }
 
       elf_section_data (splt->output_section)->this_hdr.sh_entsize =
@@ -1766,8 +1914,6 @@ elf64_x86_64_finish_dynamic_sections (output_bfd, info)
 
   /* Set the first entry in the global offset table to the address of
      the dynamic section.  */
-  sgot = bfd_get_section_by_name (dynobj, ".got");
-  BFD_ASSERT (sgot != NULL);
   if (sgot->_raw_size > 0)
     {
       if (sdyn == NULL)
@@ -1776,7 +1922,7 @@ elf64_x86_64_finish_dynamic_sections (output_bfd, info)
        bfd_put_64 (output_bfd,
                    sdyn->output_section->vma + sdyn->output_offset,
                    sgot->contents);
-      /* Write GOT[1] and GOT[2], needed for the linker.  */
+      /* Write GOT[1] and GOT[2], needed for the dynamic linker.  */
       bfd_put_64 (output_bfd, (bfd_vma) 0, sgot->contents + GOT_ENTRY_SIZE);
       bfd_put_64 (output_bfd, (bfd_vma) 0, sgot->contents + GOT_ENTRY_SIZE*2);
     }
@@ -1787,6 +1933,23 @@ elf64_x86_64_finish_dynamic_sections (output_bfd, info)
   return true;
 }
 
+static enum elf_reloc_type_class
+elf64_x86_64_reloc_type_class (type)
+     int type;
+{
+  switch (type)
+    {
+    case R_X86_64_RELATIVE:
+      return reloc_class_relative;
+    case R_X86_64_JUMP_SLOT:
+      return reloc_class_plt;
+    case R_X86_64_COPY:
+      return reloc_class_copy;
+    default:
+      return reloc_class_normal;
+    }
+}
+
 #define TARGET_LITTLE_SYM                  bfd_elf64_x86_64_vec
 #define TARGET_LITTLE_NAME                 "elf64-x86-64"
 #define ELF_ARCH                           bfd_arch_i386
@@ -1801,13 +1964,11 @@ elf64_x86_64_finish_dynamic_sections (output_bfd, info)
 #define elf_backend_plt_header_size        PLT_ENTRY_SIZE
 
 #define elf_info_to_howto                  elf64_x86_64_info_to_howto
-#define elf_backend_object_p               elf64_x86_64_elf_object_p
-#define elf_backend_relocate_section       elf64_x86_64_relocate_section
 
 #define bfd_elf64_bfd_final_link           _bfd_elf64_gc_common_final_link
 #define bfd_elf64_bfd_link_hash_table_create \
   elf64_x86_64_link_hash_table_create
-#define bfd_elf64_bfd_reloc_type_lookup     elf64_x86_64_reloc_type_lookup
+#define bfd_elf64_bfd_reloc_type_lookup            elf64_x86_64_reloc_type_lookup
 
 #define elf_backend_adjust_dynamic_symbol   elf64_x86_64_adjust_dynamic_symbol
 #define elf_backend_check_relocs           elf64_x86_64_check_relocs
@@ -1819,5 +1980,7 @@ elf64_x86_64_finish_dynamic_sections (output_bfd, info)
 #define elf_backend_gc_sweep_hook          elf64_x86_64_gc_sweep_hook
 #define elf_backend_relocate_section       elf64_x86_64_relocate_section
 #define elf_backend_size_dynamic_sections   elf64_x86_64_size_dynamic_sections
+#define elf_backend_object_p               elf64_x86_64_elf_object_p
+#define elf_backend_reloc_type_class       elf64_x86_64_reloc_type_class
 
 #include "elf64-target.h"
This page took 0.054625 seconds and 4 git commands to generate.