* coff-arm.c (coff_arm_link_hash_table_create): Use bfd_zmalloc.
[deliverable/binutils-gdb.git] / bfd / elf64-x86-64.c
index e98c32512ad019a30ee677b1b380b06747681ea9..f709c7a0985524189a31ae062a234dbe103f9f76 100644 (file)
@@ -148,8 +148,12 @@ static reloc_howto_type x86_64_elf_howto_table[] =
   HOWTO(R_X86_64_PLTOFF64, 0, 4, 64, FALSE, 0, complain_overflow_signed,
        bfd_elf_generic_reloc, "R_X86_64_PLTOFF64", FALSE, MINUS_ONE,
        MINUS_ONE, FALSE),
-  EMPTY_HOWTO (32),
-  EMPTY_HOWTO (33),
+  HOWTO(R_X86_64_SIZE32, 0, 2, 32, FALSE, 0, complain_overflow_unsigned,
+       bfd_elf_generic_reloc, "R_X86_64_SIZE32", FALSE, 0xffffffff, 0xffffffff,
+       FALSE),
+  HOWTO(R_X86_64_SIZE64, 0, 4, 64, FALSE, 0, complain_overflow_unsigned,
+       bfd_elf_generic_reloc, "R_X86_64_SIZE64", FALSE, MINUS_ONE, MINUS_ONE,
+       FALSE),
   HOWTO(R_X86_64_GOTPC32_TLSDESC, 0, 2, 32, TRUE, 0,
        complain_overflow_bitfield, bfd_elf_generic_reloc,
        "R_X86_64_GOTPC32_TLSDESC",
@@ -173,7 +177,7 @@ static reloc_howto_type x86_64_elf_howto_table[] =
      R_X86_64_standard counts the number up to this point, and
      R_X86_64_vt_offset is the value to subtract from a reloc type of
      R_X86_64_GNU_VT* to form an index into this table.  */
-#define R_X86_64_standard (R_X86_64_IRELATIVE + 1)
+#define R_X86_64_standard (R_X86_64_RELATIVE64 + 1)
 #define R_X86_64_vt_offset (R_X86_64_GNU_VTINHERIT - R_X86_64_standard)
 
 /* GNU extension to record C++ vtable hierarchy.  */
@@ -238,6 +242,8 @@ static const struct elf_reloc_map x86_64_reloc_map[] =
   { BFD_RELOC_X86_64_GOTPC64,  R_X86_64_GOTPC64, },
   { BFD_RELOC_X86_64_GOTPLT64, R_X86_64_GOTPLT64, },
   { BFD_RELOC_X86_64_PLTOFF64, R_X86_64_PLTOFF64, },
+  { BFD_RELOC_SIZE32,          R_X86_64_SIZE32, },
+  { BFD_RELOC_SIZE64,          R_X86_64_SIZE64, },
   { BFD_RELOC_X86_64_GOTPC32_TLSDESC, R_X86_64_GOTPC32_TLSDESC, },
   { BFD_RELOC_X86_64_TLSDESC_CALL, R_X86_64_TLSDESC_CALL, },
   { BFD_RELOC_X86_64_TLSDESC,  R_X86_64_TLSDESC, },
@@ -449,7 +455,7 @@ elf_x86_64_write_core_note (bfd *abfd, char *buf, int *bufsiz,
        }
       else
        {
-         prpsinfo_t data;
+         prpsinfo64_t data;
          memset (&data, 0, sizeof (data));
          strncpy (data.pr_fname, fname, sizeof (data.pr_fname));
          strncpy (data.pr_psargs, psargs, sizeof (data.pr_psargs));
@@ -490,7 +496,7 @@ elf_x86_64_write_core_note (bfd *abfd, char *buf, int *bufsiz,
        }
       else
        {
-         prstatus_t prstat;
+         prstatus64_t prstat;
          memset (&prstat, 0, sizeof (prstat));
          prstat.pr_pid = pid;
          prstat.pr_cursig = cursig;
@@ -882,7 +888,7 @@ elf_x86_64_link_hash_table_create (bfd *abfd)
   struct elf_x86_64_link_hash_table *ret;
   bfd_size_type amt = sizeof (struct elf_x86_64_link_hash_table);
 
-  ret = (struct elf_x86_64_link_hash_table *) bfd_malloc (amt);
+  ret = (struct elf_x86_64_link_hash_table *) bfd_zmalloc (amt);
   if (ret == NULL)
     return NULL;
 
@@ -895,18 +901,6 @@ elf_x86_64_link_hash_table_create (bfd *abfd)
       return NULL;
     }
 
-  ret->sdynbss = NULL;
-  ret->srelbss = NULL;
-  ret->plt_eh_frame = NULL;
-  ret->sym_cache.abfd = NULL;
-  ret->tlsdesc_plt = 0;
-  ret->tlsdesc_got = 0;
-  ret->tls_ld_got.refcount = 0;
-  ret->sgotplt_jump_table_size = 0;
-  ret->tls_module_base = NULL;
-  ret->next_jump_slot_index = 0;
-  ret->next_irelative_index = 0;
-
   if (ABI_64_P (abfd))
     {
       ret->r_info = elf64_r_info;
@@ -970,33 +964,26 @@ elf_x86_64_create_dynamic_sections (bfd *dynobj,
   if (htab == NULL)
     return FALSE;
 
-  htab->sdynbss = bfd_get_section_by_name (dynobj, ".dynbss");
+  htab->sdynbss = bfd_get_linker_section (dynobj, ".dynbss");
   if (!info->shared)
-    htab->srelbss = bfd_get_section_by_name (dynobj, ".rela.bss");
+    htab->srelbss = bfd_get_linker_section (dynobj, ".rela.bss");
 
   if (!htab->sdynbss
       || (!info->shared && !htab->srelbss))
     abort ();
 
   if (!info->no_ld_generated_unwind_info
-      && bfd_get_section_by_name (dynobj, ".eh_frame") == NULL
+      && htab->plt_eh_frame == NULL
       && htab->elf.splt != NULL)
     {
-      const struct elf_x86_64_backend_data *const abed
-       = get_elf_x86_64_backend_data (dynobj);
-      flagword flags = get_elf_backend_data (dynobj)->dynamic_sec_flags;
+      flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
+                       | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+                       | SEC_LINKER_CREATED);
       htab->plt_eh_frame
-       = bfd_make_section_with_flags (dynobj, ".eh_frame",
-                                      flags | SEC_READONLY);
+       = bfd_make_section_anyway_with_flags (dynobj, ".eh_frame", flags);
       if (htab->plt_eh_frame == NULL
          || !bfd_set_section_alignment (dynobj, htab->plt_eh_frame, 3))
        return FALSE;
-
-      htab->plt_eh_frame->size = abed->eh_frame_plt_size;
-      htab->plt_eh_frame->contents
-       = bfd_alloc (dynobj, htab->plt_eh_frame->size);
-      memcpy (htab->plt_eh_frame->contents,
-             abed->eh_frame_plt, abed->eh_frame_plt_size);
     }
   return TRUE;
 }
@@ -1425,6 +1412,7 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
       struct elf_link_hash_entry *h;
       Elf_Internal_Sym *isym;
       const char *name;
+      bfd_boolean size_reloc;
 
       r_symndx = htab->r_sym (rel->r_info);
       r_type = ELF32_R_TYPE (rel->r_info);
@@ -1529,82 +1517,8 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
              break;
            }
 
-         /* Since STT_GNU_IFUNC symbol must go through PLT, we handle
-            it here if it is defined in a non-shared object.  */
-         if (h->type == STT_GNU_IFUNC
-             && h->def_regular)
-           {
-             /* It is referenced by a non-shared object. */
-             h->ref_regular = 1;
-             h->needs_plt = 1;
-
-             /* STT_GNU_IFUNC symbol must go through PLT.  */
-             h->plt.refcount += 1;
-
-             /* STT_GNU_IFUNC needs dynamic sections.  */
-             if (htab->elf.dynobj == NULL)
-               htab->elf.dynobj = abfd;
-
-             switch (r_type)
-               {
-               default:
-                 if (h->root.root.string)
-                   name = h->root.root.string;
-                 else
-                   name = bfd_elf_sym_name (abfd, symtab_hdr, isym,
-                                            NULL);
-                 (*_bfd_error_handler)
-                   (_("%B: relocation %s against STT_GNU_IFUNC "
-                      "symbol `%s' isn't handled by %s"), abfd,
-                    x86_64_elf_howto_table[r_type].name,
-                    name, __FUNCTION__);
-                 bfd_set_error (bfd_error_bad_value);
-                 return FALSE;
-
-               case R_X86_64_32:
-                 if (ABI_64_P (abfd))
-                   goto not_pointer;
-               case R_X86_64_64:
-                 h->non_got_ref = 1;
-                 h->pointer_equality_needed = 1;
-                 if (info->shared)
-                   {
-                     /* 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_x86_64_link_hash_entry *) h)->dyn_relocs);
-                     if (sreloc == NULL)
-                       return FALSE;
-                   }
-                 break;
-
-               case R_X86_64_32S:
-               case R_X86_64_PC32:
-               case R_X86_64_PC64:
-not_pointer:
-                 h->non_got_ref = 1;
-                 if (r_type != R_X86_64_PC32
-                     && r_type != R_X86_64_PC64)
-                   h->pointer_equality_needed = 1;
-                 break;
-
-               case R_X86_64_PLT32:
-                 break;
-
-               case R_X86_64_GOTPCREL:
-               case R_X86_64_GOTPCREL64:
-                 h->got.refcount += 1;
-                 if (htab->elf.sgot == NULL
-                     && !_bfd_elf_create_got_section (htab->elf.dynobj,
-                                                      info))
-                   return FALSE;
-                 break;
-               }
-
-             continue;
-           }
+         /* It is referenced by a non-shared object. */
+         h->ref_regular = 1;
        }
 
       if (! elf_x86_64_tls_transition (info, abfd, sec, NULL,
@@ -1725,6 +1639,7 @@ not_pointer:
                    (*_bfd_error_handler)
                      (_("%B: '%s' accessed both as normal and thread local symbol"),
                       abfd, name);
+                   bfd_set_error (bfd_error_bad_value);
                    return FALSE;
                  }
              }
@@ -1780,6 +1695,11 @@ not_pointer:
            }
          goto create_got;
 
+       case R_X86_64_SIZE32:
+       case R_X86_64_SIZE64:
+         size_reloc = TRUE;
+         goto do_size;
+
        case R_X86_64_32:
          if (!ABI_64_P (abfd))
            goto pointer;
@@ -1829,6 +1749,8 @@ pointer:
                h->pointer_equality_needed = 1;
            }
 
+         size_reloc = FALSE;
+do_size:
          /* If we are creating a shared library, and this is a reloc
             against a global symbol, or a non PC relative reloc
             against a local symbol, then we need to copy the reloc
@@ -1929,7 +1851,8 @@ pointer:
                }
 
              p->count += 1;
-             if (IS_X86_64_PCREL_TYPE (r_type))
+             /* Count size relocation as PC-relative relocation.  */
+             if (IS_X86_64_PCREL_TYPE (r_type) || size_reloc)
                p->pc_count += 1;
            }
          break;
@@ -2107,6 +2030,8 @@ elf_x86_64_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
        case R_X86_64_PC16:
        case R_X86_64_PC32:
        case R_X86_64_PC64:
+       case R_X86_64_SIZE32:
+       case R_X86_64_SIZE64:
          if (info->shared
              && (h == NULL || h->type != STT_GNU_IFUNC))
            break;
@@ -2141,10 +2066,44 @@ elf_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info,
 {
   struct elf_x86_64_link_hash_table *htab;
   asection *s;
+  struct elf_x86_64_link_hash_entry *eh;
+  struct elf_dyn_relocs *p;
 
   /* STT_GNU_IFUNC symbol must go through PLT. */
   if (h->type == STT_GNU_IFUNC)
     {
+      /* All local STT_GNU_IFUNC references must be treate as local
+        calls via local PLT.  */
+      if (h->ref_regular
+         && SYMBOL_CALLS_LOCAL (info, h))
+       {
+         bfd_size_type pc_count = 0, count = 0;
+         struct elf_dyn_relocs **pp;
+
+         eh = (struct elf_x86_64_link_hash_entry *) h;
+         for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
+           {
+             pc_count += p->pc_count;
+             p->count -= p->pc_count;
+             p->pc_count = 0;
+             count += p->count;
+             if (p->count == 0)
+               *pp = p->next;
+             else
+               pp = &p->next;
+           }
+
+         if (pc_count || count)
+           {
+             h->needs_plt = 1;
+             h->non_got_ref = 1;
+             if (h->plt.refcount <= 0)
+               h->plt.refcount = 1;
+             else
+               h->plt.refcount += 1;
+           }
+       }
+
       if (h->plt.refcount <= 0)
        {
          h->plt.offset = (bfd_vma) -1;
@@ -2221,9 +2180,6 @@ elf_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info,
 
   if (ELIMINATE_COPY_RELOCS)
     {
-      struct elf_x86_64_link_hash_entry * eh;
-      struct elf_dyn_relocs *p;
-
       eh = (struct elf_x86_64_link_hash_entry *) h;
       for (p = eh->dyn_relocs; p != NULL; p = p->next)
        {
@@ -2579,6 +2535,154 @@ elf_x86_64_readonly_dynrelocs (struct elf_link_hash_entry *h,
   return TRUE;
 }
 
+/* Convert
+   mov foo@GOTPCREL(%rip), %reg
+   to
+   lea foo(%rip), %reg
+   with the local symbol, foo.  */
+
+static bfd_boolean
+elf_x86_64_convert_mov_to_lea (bfd *abfd, asection *sec,
+                              struct bfd_link_info *link_info)
+{
+  Elf_Internal_Shdr *symtab_hdr;
+  Elf_Internal_Rela *internal_relocs;
+  Elf_Internal_Rela *irel, *irelend;
+  bfd_byte *contents;
+  struct elf_x86_64_link_hash_table *htab;
+  bfd_boolean changed_contents;
+  bfd_boolean changed_relocs;
+  bfd_signed_vma *local_got_refcounts;
+
+  /* Don't even try to convert non-ELF outputs.  */
+  if (!is_elf_hash_table (link_info->hash))
+    return FALSE;
+
+  /* Nothing to do if there are no codes, no relocations or no output.  */
+  if ((sec->flags & (SEC_CODE | SEC_RELOC)) != (SEC_CODE | SEC_RELOC)
+      || sec->reloc_count == 0
+      || discarded_section (sec))
+    return TRUE;
+
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+
+  /* Load the relocations for this section.  */
+  internal_relocs = (_bfd_elf_link_read_relocs
+                    (abfd, sec, NULL, (Elf_Internal_Rela *) NULL,
+                     link_info->keep_memory));
+  if (internal_relocs == NULL)
+    return FALSE;
+
+  htab = elf_x86_64_hash_table (link_info);
+  changed_contents = FALSE;
+  changed_relocs = FALSE;
+  local_got_refcounts = elf_local_got_refcounts (abfd);
+
+  /* Get the section contents.  */
+  if (elf_section_data (sec)->this_hdr.contents != NULL)
+    contents = elf_section_data (sec)->this_hdr.contents;
+  else
+    {
+      if (!bfd_malloc_and_get_section (abfd, sec, &contents))
+       goto error_return;
+    }
+
+  irelend = internal_relocs + sec->reloc_count;
+  for (irel = internal_relocs; irel < irelend; irel++)
+    {
+      unsigned int r_type = ELF32_R_TYPE (irel->r_info);
+      unsigned int r_symndx = htab->r_sym (irel->r_info);
+      unsigned int indx;
+      struct elf_link_hash_entry *h;
+
+      if (r_type != R_X86_64_GOTPCREL)
+       continue;
+
+      /* Get the symbol referred to by the reloc.  */
+      if (r_symndx < symtab_hdr->sh_info)
+       {
+         Elf_Internal_Sym *isym;
+
+         isym = bfd_sym_from_r_symndx (&htab->sym_cache,
+                                       abfd, r_symndx);
+
+         /* STT_GNU_IFUNC must keep R_X86_64_GOTPCREL relocation.  */
+         if (ELF_ST_TYPE (isym->st_info) != STT_GNU_IFUNC
+             && bfd_get_8 (input_bfd,
+                           contents + irel->r_offset - 2) == 0x8b)
+           {
+             bfd_put_8 (output_bfd, 0x8d,
+                        contents + irel->r_offset - 2);
+             irel->r_info = htab->r_info (r_symndx, R_X86_64_PC32);
+             if (local_got_refcounts != NULL
+                 && local_got_refcounts[r_symndx] > 0)
+               local_got_refcounts[r_symndx] -= 1;
+             changed_contents = TRUE;
+             changed_relocs = TRUE;
+           }
+         continue;
+       }
+
+      indx = r_symndx - symtab_hdr->sh_info;
+      h = elf_sym_hashes (abfd)[indx];
+      BFD_ASSERT (h != NULL);
+
+      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;
+
+      /* STT_GNU_IFUNC must keep R_X86_64_GOTPCREL relocation.  We also
+        avoid optimizing _DYNAMIC since ld.so may use its link-time
+        address.  */
+      if (h->def_regular
+         && h->type != STT_GNU_IFUNC
+         && h != htab->elf.hdynamic
+         && SYMBOL_REFERENCES_LOCAL (link_info, h)
+         && bfd_get_8 (input_bfd,
+                       contents + irel->r_offset - 2) == 0x8b)
+       {
+         bfd_put_8 (output_bfd, 0x8d,
+                    contents + irel->r_offset - 2);
+         irel->r_info = htab->r_info (r_symndx, R_X86_64_PC32);
+         if (h->got.refcount > 0)
+           h->got.refcount -= 1;
+         changed_contents = TRUE;
+         changed_relocs = TRUE;
+       }
+    }
+
+  if (contents != NULL
+      && elf_section_data (sec)->this_hdr.contents != contents)
+    {
+      if (!changed_contents && !link_info->keep_memory)
+       free (contents);
+      else
+       {
+         /* Cache the section contents for elf_link_input_bfd.  */
+         elf_section_data (sec)->this_hdr.contents = contents;
+       }
+    }
+
+  if (elf_section_data (sec)->relocs != internal_relocs)
+    {
+      if (!changed_relocs)
+       free (internal_relocs);
+      else
+       elf_section_data (sec)->relocs = internal_relocs;
+    }
+
+  return TRUE;
+
+ error_return:
+  if (contents != NULL
+      && elf_section_data (sec)->this_hdr.contents != contents)
+    free (contents);
+  if (internal_relocs != NULL
+      && elf_section_data (sec)->relocs != internal_relocs)
+    free (internal_relocs);
+  return FALSE;
+}
+
 /* Set the sizes of the dynamic sections.  */
 
 static bfd_boolean
@@ -2606,7 +2710,7 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd,
       /* Set the contents of the .interp section to the interpreter.  */
       if (info->executable)
        {
-         s = bfd_get_section_by_name (dynobj, ".interp");
+         s = bfd_get_linker_section (dynobj, ".interp");
          if (s == NULL)
            abort ();
          s->size = htab->dynamic_interpreter_size;
@@ -2633,6 +2737,9 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd,
        {
          struct elf_dyn_relocs *p;
 
+         if (!elf_x86_64_convert_mov_to_lea (ibfd, s, info))
+           return FALSE;
+
          for (p = (struct elf_dyn_relocs *)
                    (elf_section_data (s)->local_dynrel);
               p != NULL;
@@ -2773,15 +2880,10 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd,
 
   if (htab->elf.sgotplt)
     {
-      struct elf_link_hash_entry *got;
-      got = elf_link_hash_lookup (elf_hash_table (info),
-                                 "_GLOBAL_OFFSET_TABLE_",
-                                 FALSE, FALSE, FALSE);
-
       /* Don't allocate .got.plt section if there are no GOT nor PLT
         entries and there is no refeence to _GLOBAL_OFFSET_TABLE_.  */
-      if ((got == NULL
-          || !got->ref_regular_nonweak)
+      if ((htab->elf.hgot == NULL
+          || !htab->elf.hgot->ref_regular_nonweak)
          && (htab->elf.sgotplt->size
              == get_elf_backend_data (output_bfd)->got_header_size)
          && (htab->elf.splt == NULL
@@ -2795,6 +2897,17 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd,
        htab->elf.sgotplt->size = 0;
     }
 
+  if (htab->plt_eh_frame != NULL
+      && htab->elf.splt != NULL
+      && htab->elf.splt->size != 0
+      && !bfd_is_abs_section (htab->elf.splt->output_section)
+      && _bfd_elf_eh_frame_present (info))
+    {
+      const struct elf_x86_64_backend_data *arch_data
+       = (const struct elf_x86_64_backend_data *) bed->arch_data;
+      htab->plt_eh_frame->size = arch_data->eh_frame_plt_size;
+    }
+
   /* We now have determined the sizes of the various dynamic sections.
      Allocate memory for them.  */
   relocs = FALSE;
@@ -2808,6 +2921,7 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd,
          || s == htab->elf.sgotplt
          || s == htab->elf.iplt
          || s == htab->elf.igotplt
+         || s == htab->plt_eh_frame
          || s == htab->sdynbss)
        {
          /* Strip this section if we don't need it; see the
@@ -2859,11 +2973,16 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd,
     }
 
   if (htab->plt_eh_frame != NULL
-      && htab->elf.splt != NULL
-      && htab->elf.splt->size != 0
-      && (htab->elf.splt->flags & SEC_EXCLUDE) == 0)
-    bfd_put_32 (dynobj, htab->elf.splt->size,
-               htab->plt_eh_frame->contents + PLT_FDE_LEN_OFFSET);
+      && htab->plt_eh_frame->contents != NULL)
+    {
+      const struct elf_x86_64_backend_data *arch_data
+       = (const struct elf_x86_64_backend_data *) bed->arch_data;
+
+      memcpy (htab->plt_eh_frame->contents,
+             arch_data->eh_frame_plt, htab->plt_eh_frame->size);
+      bfd_put_32 (dynobj, htab->elf.splt->size,
+                 htab->plt_eh_frame->contents + PLT_FDE_LEN_OFFSET);
+    }
 
   if (htab->elf.dynamic_sections_created)
     {
@@ -3088,14 +3207,18 @@ elf_x86_64_relocate_section (bfd *output_bfd,
       bfd_reloc_status_type r;
       int tls_type;
       asection *base_got;
+      bfd_vma st_size;
 
       r_type = ELF32_R_TYPE (rel->r_info);
       if (r_type == (int) R_X86_64_GNU_VTINHERIT
          || r_type == (int) R_X86_64_GNU_VTENTRY)
        continue;
 
-      if (r_type >= R_X86_64_max)
+      if (r_type >= (int) R_X86_64_standard)
        {
+         (*_bfd_error_handler)
+           (_("%B: unrecognized relocation (0x%x) in section `%A'"),
+            input_bfd, input_section, r_type);
          bfd_set_error (bfd_error_bad_value);
          return FALSE;
        }
@@ -3118,6 +3241,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
 
          relocation = _bfd_elf_rela_local_sym (output_bfd, sym,
                                                &sec, rel);
+         st_size = sym->st_size;
 
          /* Relocate against local STT_GNU_IFUNC symbol.  */
          if (!info->relocatable
@@ -3141,6 +3265,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
                                   r_symndx, symtab_hdr, sym_hashes,
                                   h, sec, relocation,
                                   unresolved_reloc, warned);
+         st_size = h->size;
        }
 
       if (sec != NULL && discarded_section (sec))
@@ -3150,14 +3275,22 @@ elf_x86_64_relocate_section (bfd *output_bfd,
       if (info->relocatable)
        continue;
 
-      if (rel->r_addend == 0
-         && r_type == R_X86_64_64
-         && !ABI_64_P (output_bfd))
+      if (rel->r_addend == 0 && !ABI_64_P (output_bfd))
        {
-         /* For x32, treat R_X86_64_64 like R_X86_64_32 and zero-extend
-            it to 64bit if addend is zero.  */
-         r_type = R_X86_64_32;
-         memset (contents + rel->r_offset + 4, 0, 4);
+         if (r_type == R_X86_64_64)
+           {
+             /* For x32, treat R_X86_64_64 like R_X86_64_32 and
+                zero-extend it to 64bit if addend is zero.  */
+             r_type = R_X86_64_32;
+             memset (contents + rel->r_offset + 4, 0, 4);
+           }
+         else if (r_type == R_X86_64_SIZE64)
+           {
+             /* For x32, treat R_X86_64_SIZE64 like R_X86_64_SIZE32 and
+                zero-extend it to 64bit if addend is zero.  */
+             r_type = R_X86_64_SIZE32;
+             memset (contents + rel->r_offset + 4, 0, 4);
+           }
        }
 
       /* Since STT_GNU_IFUNC symbol must go through PLT, we handle
@@ -3538,6 +3671,12 @@ elf_x86_64_relocate_section (bfd *output_bfd,
          unresolved_reloc = FALSE;
          break;
 
+       case R_X86_64_SIZE32:
+       case R_X86_64_SIZE64:
+         /* Set to symbol size.  */
+         relocation = st_size;
+         goto direct;
+
        case R_X86_64_PC8:
        case R_X86_64_PC16:
        case R_X86_64_PC32:
@@ -3610,6 +3749,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
          /* FIXME: The ABI says the linker should make sure the value is
             the same when it's zeroextended to 64 bit.  */
 
+direct:
          if ((input_section->flags & SEC_ALLOC) == 0)
            break;
 
@@ -3617,7 +3757,9 @@ elf_x86_64_relocate_section (bfd *output_bfd,
               && (h == NULL
                   || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
                   || h->root.type != bfd_link_hash_undefweak)
-              && (! IS_X86_64_PCREL_TYPE (r_type)
+              && ((! IS_X86_64_PCREL_TYPE (r_type)
+                     && r_type != R_X86_64_SIZE32
+                     && r_type != R_X86_64_SIZE64)
                   || ! SYMBOL_CALLS_LOCAL (info, h)))
              || (ELIMINATE_COPY_RELOCS
                  && !info->shared
@@ -3686,7 +3828,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
                          != (rel->r_addend & 0x80000000))
                        {
                          const char *name;
-                         long addend = rel->r_addend;
+                         int addend = rel->r_addend;
                          if (h && h->root.root.string)
                            name = h->root.root.string;
                          else
@@ -3694,7 +3836,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
                                                     sym, NULL);
                          if (addend < 0)
                            (*_bfd_error_handler)
-                             (_("%B: addend -0x%lx in relocation %s against "
+                             (_("%B: addend -0x%x in relocation %s against "
                                 "symbol `%s' at 0x%lx in section `%A' is "
                                 "out of range"),
                               input_bfd, input_section, addend,
@@ -3702,7 +3844,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
                               name, (unsigned long) rel->r_offset);
                          else
                            (*_bfd_error_handler)
-                             (_("%B: addend 0x%lx in relocation %s against "
+                             (_("%B: addend 0x%x in relocation %s against "
                                 "symbol `%s' at 0x%lx in section `%A' is "
                                 "out of range"),
                               input_bfd, input_section, addend,
@@ -4200,13 +4342,16 @@ elf_x86_64_relocate_section (bfd *output_bfd,
               && h->def_dynamic)
          && _bfd_elf_section_offset (output_bfd, info, input_section,
                                      rel->r_offset) != (bfd_vma) -1)
-       (*_bfd_error_handler)
-         (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"),
-          input_bfd,
-          input_section,
-          (long) rel->r_offset,
-          howto->name,
-          h->root.root.string);
+       {
+         (*_bfd_error_handler)
+           (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"),
+            input_bfd,
+            input_section,
+            (long) rel->r_offset,
+            howto->name,
+            h->root.root.string);
+         return FALSE;
+       }
 
 do_relocation:
       r = _bfd_final_link_relocate (howto, input_bfd, input_section,
@@ -4260,7 +4405,7 @@ static bfd_boolean
 elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
                                  struct bfd_link_info *info,
                                  struct elf_link_hash_entry *h,
-                                 Elf_Internal_Sym *sym)
+                                 Elf_Internal_Sym *sym ATTRIBUTE_UNUSED)
 {
   struct elf_x86_64_link_hash_table *htab;
   const struct elf_x86_64_backend_data *const abed
@@ -4303,7 +4448,7 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
          || plt == NULL
          || gotplt == NULL
          || relplt == NULL)
-       return FALSE;
+       abort ();
 
       /* Get the index in the procedure linkage table which
         corresponds to this symbol.  This is the index of this symbol
@@ -4499,13 +4644,6 @@ do_glob_dat:
       elf_append_rela (output_bfd, htab->srelbss, &rela);
     }
 
-  /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute.  SYM may
-     be NULL for local symbols.  */
-  if (sym != NULL
-      && (strcmp (h->root.root.string, "_DYNAMIC") == 0
-         || h == htab->elf.hgot))
-    sym->st_shndx = SHN_ABS;
-
   return TRUE;
 }
 
@@ -4561,7 +4699,7 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd,
     return FALSE;
 
   dynobj = htab->elf.dynobj;
-  sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
+  sdyn = bfd_get_linker_section (dynobj, ".dynamic");
 
   if (htab->elf.dynamic_sections_created)
     {
@@ -4730,7 +4868,8 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd,
     }
 
   /* Adjust .eh_frame for .plt section.  */
-  if (htab->plt_eh_frame != NULL)
+  if (htab->plt_eh_frame != NULL
+      && htab->plt_eh_frame->contents != NULL)
     {
       if (htab->elf.splt != NULL
          && htab->elf.splt->size != 0
This page took 0.032863 seconds and 4 git commands to generate.