Automatic date update in version.in
[deliverable/binutils-gdb.git] / bfd / elf64-x86-64.c
index 9778f2fa49604db6ece9a6482f41cb7c550db980..bbdb03a58cfaba82a57b196d253555a07abac508 100644 (file)
@@ -1,5 +1,5 @@
 /* X86-64 specific support for ELF
-   Copyright (C) 2000-2015 Free Software Foundation, Inc.
+   Copyright (C) 2000-2016 Free Software Foundation, Inc.
    Contributed by Jan Hubicka <jh@suse.cz>.
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -3116,8 +3116,6 @@ elf_x86_64_convert_load (bfd *abfd, asection *sec,
        }
       else
        {
-         bfd_boolean defined;
-
          indx = r_symndx - symtab_hdr->sh_info;
          h = elf_sym_hashes (abfd)[indx];
          BFD_ASSERT (h != NULL);
@@ -3126,17 +3124,29 @@ elf_x86_64_convert_load (bfd *abfd, asection *sec,
                 || h->root.type == bfd_link_hash_warning)
            h = (struct elf_link_hash_entry *) h->root.u.i.link;
 
-         defined = bfd_link_get_defined_symbol (link_info, &h->root,
-                                                &tsec, &toff);
-
          /* STT_GNU_IFUNC must keep GOTPCREL relocations.  We also
             avoid optimizing GOTPCREL relocations againt _DYNAMIC
             since ld.so may use its link-time address.  */
-         if (defined
+         if ((h->def_regular
+              || h->root.type == bfd_link_hash_defined
+              || h->root.type == bfd_link_hash_defweak)
              && h->type != STT_GNU_IFUNC
              && h != htab->elf.hdynamic
              && SYMBOL_REFERENCES_LOCAL (link_info, h))
-           symtype = h->type;
+           {
+             /* bfd_link_hash_new or bfd_link_hash_undefined is
+                set by an assignment in a linker script in
+                bfd_elf_record_link_assignment.  FIXME: If we
+                ever get a linker error due relocation overflow,
+                we will skip this optimization.  */
+             if (h->def_regular
+                 && (h->root.type == bfd_link_hash_new
+                     || h->root.type == bfd_link_hash_undefined))
+               goto convert;
+             tsec = h->root.u.def.section;
+             toff = h->root.u.def.value;
+             symtype = h->type;
+           }
          else
            continue;
        }
@@ -3213,6 +3223,7 @@ elf_x86_64_convert_load (bfd *abfd, asection *sec,
            continue;
        }
 
+convert:
       if (opcode == 0xff)
        {
          /* We have "call/jmp *foo@GOTPCREL(%rip)".  */
@@ -3858,6 +3869,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
   bfd_vma *local_got_offsets;
   bfd_vma *local_tlsdesc_gotents;
   Elf_Internal_Rela *rel;
+  Elf_Internal_Rela *wrel;
   Elf_Internal_Rela *relend;
   const unsigned int plt_entry_size = GET_PLT_ENTRY_SIZE (info->output_bfd);
 
@@ -3873,9 +3885,9 @@ elf_x86_64_relocate_section (bfd *output_bfd,
 
   elf_x86_64_set_tls_module_base (info);
 
-  rel = relocs;
+  rel = wrel = relocs;
   relend = relocs + input_section->reloc_count;
-  for (; rel < relend; rel++)
+  for (; rel < relend; wrel++, rel++)
     {
       unsigned int r_type;
       reloc_howto_type *howto;
@@ -3895,7 +3907,11 @@ elf_x86_64_relocate_section (bfd *output_bfd,
       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 (wrel != rel)
+           *wrel = *rel;
+         continue;
+       }
 
       if (r_type >= (int) R_X86_64_standard)
        {
@@ -3953,11 +3969,29 @@ elf_x86_64_relocate_section (bfd *output_bfd,
        }
 
       if (sec != NULL && discarded_section (sec))
-       RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
-                                        rel, 1, relend, howto, 0, contents);
+       {
+         _bfd_clear_contents (howto, input_bfd, input_section,
+                              contents + rel->r_offset);
+         wrel->r_offset = rel->r_offset;
+         wrel->r_info = 0;
+         wrel->r_addend = 0;
+
+         /* For ld -r, remove relocations in debug sections against
+            sections defined in discarded sections.  Not done for
+            eh_frame editing code expects to be present.  */
+          if (bfd_link_relocatable (info)
+              && (input_section->flags & SEC_DEBUGGING))
+            wrel--;
+
+         continue;
+       }
 
       if (bfd_link_relocatable (info))
-       continue;
+       {
+         if (wrel != rel)
+           *wrel = *rel;
+         continue;
+       }
 
       if (rel->r_addend == 0 && !ABI_64_P (output_bfd))
        {
@@ -4774,6 +4808,7 @@ direct:
                              contents + roff + 8 + largepic);
                  /* Skip R_X86_64_PC32/R_X86_64_PLT32/R_X86_64_PLTOFF64.  */
                  rel++;
+                 wrel++;
                  continue;
                }
              else if (ELF32_R_TYPE (rel->r_info) == R_X86_64_GOTPC32_TLSDESC)
@@ -5056,6 +5091,7 @@ direct:
                              contents + roff + 8 + largepic);
                  /* Skip R_X86_64_PLT32/R_X86_64_PLTOFF64.  */
                  rel++;
+                 wrel++;
                  continue;
                }
              else if (ELF32_R_TYPE (rel->r_info) == R_X86_64_GOTPC32_TLSDESC)
@@ -5140,6 +5176,7 @@ direct:
                        "\x0f\x1f\x40\x00\x64\x8b\x04\x25\0\0\0", 12);
              /* Skip R_X86_64_PC32/R_X86_64_PLT32/R_X86_64_PLTOFF64.  */
              rel++;
+             wrel++;
              continue;
            }
 
@@ -5256,6 +5293,29 @@ check_relocation_error:
              return FALSE;
            }
        }
+
+      if (wrel != rel)
+       *wrel = *rel;
+    }
+
+  if (wrel != rel)
+    {
+      Elf_Internal_Shdr *rel_hdr;
+      size_t deleted = rel - wrel;
+
+      rel_hdr = _bfd_elf_single_rel_hdr (input_section->output_section);
+      rel_hdr->sh_size -= rel_hdr->sh_entsize * deleted;
+      if (rel_hdr->sh_size == 0)
+       {
+         /* It is too late to remove an empty reloc section.  Leave
+            one NONE reloc.
+            ??? What is wrong with an empty section???  */
+         rel_hdr->sh_size = rel_hdr->sh_entsize;
+         deleted -= 1;
+       }
+      rel_hdr = _bfd_elf_single_rel_hdr (input_section);
+      rel_hdr->sh_size -= rel_hdr->sh_entsize * deleted;
+      input_section->reloc_count -= deleted;
     }
 
   return TRUE;
This page took 0.025019 seconds and 4 git commands to generate.