/* 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.
/* 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 ((h->root.type == bfd_link_hash_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))
{
+ /* 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;
continue;
}
+convert:
if (opcode == 0xff)
{
/* We have "call/jmp *foo@GOTPCREL(%rip)". */
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);
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;
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)
{
}
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))
{
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)
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)
"\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;
}
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;
bfd *abfd = info->output_bfd;
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
struct elf_x86_64_link_hash_table *htab = elf_x86_64_hash_table (info);
- unsigned long r_symndx = htab->r_sym (rela->r_info);
- Elf_Internal_Sym sym;
-
- if (htab->elf.dynsym == NULL
- || !bed->s->swap_symbol_in (abfd,
- (htab->elf.dynsym->contents
- + r_symndx * bed->s->sizeof_sym),
- 0, &sym))
- abort ();
- /* Check relocation against STT_GNU_IFUNC symbol. */
- if (ELF_ST_TYPE (sym.st_info) == STT_GNU_IFUNC)
- return reloc_class_ifunc;
+ if (htab->elf.dynsym != NULL
+ && htab->elf.dynsym->contents != NULL)
+ {
+ /* Check relocation against STT_GNU_IFUNC symbol if there are
+ dynamic symbols. */
+ unsigned long r_symndx = htab->r_sym (rela->r_info);
+ Elf_Internal_Sym sym;
+ if (!bed->s->swap_symbol_in (abfd,
+ (htab->elf.dynsym->contents
+ + r_symndx * bed->s->sizeof_sym),
+ 0, &sym))
+ abort ();
+
+ if (ELF_ST_TYPE (sym.st_info) == STT_GNU_IFUNC)
+ return reloc_class_ifunc;
+ }
switch ((int) ELF32_R_TYPE (rela->r_info))
{
reloc_index = H_GET_32 (abfd, (plt_contents + plt_offset
+ bed->plt_reloc_offset));
- if (reloc_index >= count)
- abort ();
- if (plt_bnd)
+ if (reloc_index < count)
{
- /* This is the index in .plt section. */
- long plt_index = plt_offset / bed->plt_entry_size;
- /* Store VMA + the offset in .plt.bnd section. */
- plt_sym_val[reloc_index] =
- (plt_bnd->vma
- + (plt_index - 1) * sizeof (elf_x86_64_legacy_plt2_entry));
+ if (plt_bnd)
+ {
+ /* This is the index in .plt section. */
+ long plt_index = plt_offset / bed->plt_entry_size;
+ /* Store VMA + the offset in .plt.bnd section. */
+ plt_sym_val[reloc_index] =
+ (plt_bnd->vma
+ + (plt_index - 1) * sizeof (elf_x86_64_legacy_plt2_entry));
+ }
+ else
+ plt_sym_val[reloc_index] = plt->vma + plt_offset;
}
- else
- plt_sym_val[reloc_index] = plt->vma + plt_offset;
plt_offset += bed->plt_entry_size;
/* PR binutils/18437: Skip extra relocations in the .rela.plt