/* IBM S/390-specific support for 64-bit ELF
- Copyright (C) 2000-2015 Free Software Foundation, Inc.
+ Copyright (C) 2000-2016 Free Software Foundation, Inc.
Contributed Martin Schwidefsky (schwidefsky@de.ibm.com).
This file is part of BFD, the Binary File Descriptor library.
&& strcasecmp (elf_howto_table[i].name, r_name) == 0)
return &elf_howto_table[i];
- if (strcasecmp (elf64_s390_vtinherit_howto.name, r_name) == 0)
- return &elf64_s390_vtinherit_howto;
- if (strcasecmp (elf64_s390_vtentry_howto.name, r_name) == 0)
- return &elf64_s390_vtentry_howto;
+ if (strcasecmp (elf64_s390_vtinherit_howto.name, r_name) == 0)
+ return &elf64_s390_vtinherit_howto;
+ if (strcasecmp (elf64_s390_vtentry_howto.name, r_name) == 0)
+ return &elf64_s390_vtentry_howto;
return NULL;
}
The GOT holds the address in the PLT to be executed.
The loader then gets:
- 24(15) = Pointer to the structure describing the object.
- 28(15) = Offset in symbol table
+ 48(15) = Pointer to the structure describing the object.
+ 56(15) = Offset in symbol table
The loader must then find the module where the function is
and insert the address in the GOT.
switch (r_type)
{
- case R_390_GOTOFF16:
- case R_390_GOTOFF32:
- case R_390_GOTOFF64:
case R_390_GOTPC:
case R_390_GOTPCDBL:
/* These relocs do not need a GOT slot. They just load the
the GOT. Since the GOT pointer has been set up above we
are done. */
break;
+ case R_390_GOTOFF16:
+ case R_390_GOTOFF32:
+ case R_390_GOTOFF64:
+ if (h == NULL || !s390_is_ifunc_symbol_p (h) || !h->def_regular)
+ break;
case R_390_PLT12DBL:
case R_390_PLT16DBL:
case R_390_PC32:
case R_390_PC32DBL:
case R_390_PC64:
- if (h != NULL)
+ if (h != NULL && bfd_link_executable (info))
{
/* If this reloc is in a read-only section, we might
need a copy reloc. We can't check reliably at this
case R_390_GOTOFF16:
case R_390_GOTOFF32:
case R_390_GOTOFF64:
+ if (h != NULL && s390_is_ifunc_symbol_p (h) && h->def_regular)
+ {
+ h->plt.refcount--;
+ break;
+ }
+
case R_390_GOTPC:
case R_390_GOTPCDBL:
break;
/* STT_GNU_IFUNC symbol must go through PLT. */
if (s390_is_ifunc_symbol_p (h))
- return TRUE;
+ {
+ /* All local STT_GNU_IFUNC references must be treated 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;
+ struct elf_s390_link_hash_entry *eh;
+ struct elf_dyn_relocs *p;
+
+ eh = (struct elf_s390_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;
+ h->needs_plt = 0;
+ }
+ return TRUE;
+ }
/* If this is a function, put it in the procedure linkage table. We
will fill in the contents of the procedure linkage table later
/* Since STT_GNU_IFUNC symbol must go through PLT, we handle it
here if it is defined and referenced in a non-shared object. */
if (s390_is_ifunc_symbol_p (h) && h->def_regular)
- return s390_elf_allocate_ifunc_dyn_relocs (info, h,
- &eh->dyn_relocs);
+ return s390_elf_allocate_ifunc_dyn_relocs (info, h);
else if (htab->elf.dynamic_sections_created
&& h->plt.refcount > 0)
{
PLT_ENTRY_SIZE;
/* Offset in GOT is PLT index plus GOT headers(3)
- times 4, addr & GOT addr. */
+ times 8, addr & GOT addr. */
relocation = (plt_index + 3) * GOT_ENTRY_SIZE;
if (r_type == R_390_GOTPLTENT)
relocation += htab->elf.sgot->output_section->vma;
/* Relocation is relative to the start of the global offset
table. */
+ if (h != NULL
+ && s390_is_ifunc_symbol_p (h)
+ && h->def_regular
+ && !bfd_link_executable (info))
+ {
+ relocation = (htab->elf.iplt->output_section->vma
+ + htab->elf.iplt->output_offset
+ + h->plt.offset
+ - htab->elf.sgot->output_section->vma);
+ goto do_relocation;
+ }
+
/* Note that sgot->output_offset is not involved in this
calculation. We always want the start of .got. If we
defined _GLOBAL_OFFSET_TABLE in a different way, as is
unresolved_reloc = FALSE;
break;
- case R_390_8:
- case R_390_16:
- case R_390_32:
- case R_390_64:
case R_390_PC16:
case R_390_PC12DBL:
case R_390_PC16DBL:
case R_390_PC32:
case R_390_PC32DBL:
case R_390_PC64:
+ /* The target of these relocs are instruction operands
+ residing in read-only sections. We cannot emit a runtime
+ reloc for it. */
+ if (h != NULL
+ && s390_is_ifunc_symbol_p (h)
+ && h->def_regular
+ && bfd_link_pic (info))
+ {
+ relocation = (htab->elf.iplt->output_section->vma
+ + htab->elf.iplt->output_offset
+ + h->plt.offset);
+ goto do_relocation;
+ }
+
+ case R_390_8:
+ case R_390_16:
+ case R_390_32:
+ case R_390_64:
if (h != NULL
&& s390_is_ifunc_symbol_p (h)
}
if (r == bfd_reloc_overflow)
- {
-
- if (! ((*info->callbacks->reloc_overflow)
- (info, (h ? &h->root : NULL), name, howto->name,
- (bfd_vma) 0, input_bfd, input_section,
- rel->r_offset)))
- return FALSE;
- }
+ (*info->callbacks->reloc_overflow)
+ (info, (h ? &h->root : NULL), name, howto->name,
+ (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
else
{
(*_bfd_error_handler)
/* This symbol has an entry in the procedure linkage table. Set
it up. */
- if (s390_is_ifunc_symbol_p (h))
+ if (s390_is_ifunc_symbol_p (h) && h->def_regular)
{
- /* If we can resolve the IFUNC symbol locally we generate an
- IRELATIVE reloc. */
- elf_s390_finish_ifunc_symbol (output_bfd, info, h, htab, h->plt.offset,
- eh->ifunc_resolver_address +
- eh->ifunc_resolver_section->output_offset +
- eh->ifunc_resolver_section->output_section->vma);
- ;
- /* Fallthrough. Handling of explicit GOT slots of IFUNC
- symbols is below. */
+ elf_s390_finish_ifunc_symbol (output_bfd, info, h,
+ htab, h->plt.offset,
+ eh->ifunc_resolver_address +
+ eh->ifunc_resolver_section->output_offset +
+ eh->ifunc_resolver_section->output_section->vma);
+
+ /* Do not return yet. Handling of explicit GOT slots of
+ IFUNC symbols is below. */
}
else
{
const asection *rel_sec ATTRIBUTE_UNUSED,
const Elf_Internal_Rela *rela)
{
+ bfd *abfd = info->output_bfd;
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ struct elf_s390_link_hash_table *htab = elf_s390_hash_table (info);
+ unsigned long r_symndx = ELF64_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;
+
switch ((int) ELF64_R_TYPE (rela->r_info))
{
case R_390_RELATIVE:
continue;
case DT_PLTGOT:
- dyn.d_un.d_ptr = htab->elf.sgot->output_section->vma;
+ s = htab->elf.sgotplt;
+ dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
break;
case DT_JMPREL:
- dyn.d_un.d_ptr = htab->elf.srelplt->output_section->vma;
+ s = htab->elf.srelplt;
+ dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
break;
case DT_PLTRELSZ:
- s = htab->elf.srelplt->output_section;
- dyn.d_un.d_val = s->size;
+ dyn.d_un.d_val = htab->elf.srelplt->size + htab->elf.irelplt->size;
break;
case DT_RELASZ:
linker script arranges for .rela.plt to follow all
other relocation sections, we don't have to worry
about changing the DT_RELA entry. */
- s = htab->elf.srelplt->output_section;
- dyn.d_un.d_val -= s->size;
+ dyn.d_un.d_val -= htab->elf.srelplt->size + htab->elf.irelplt->size;
break;
}
PLT_FIRST_ENTRY_SIZE);
/* Fixup relative address to start of GOT */
bfd_put_32 (output_bfd,
- (htab->elf.sgotplt->output_section->vma +
- htab->elf.sgotplt->output_offset
- - htab->elf.splt->output_section->vma - 6)/2,
+ (htab->elf.sgotplt->output_section->vma
+ + htab->elf.sgotplt->output_offset
+ - htab->elf.splt->output_section->vma
+ - htab->elf.splt->output_offset - 6)/2,
htab->elf.splt->contents + 8);
}
if (elf_section_data (htab->elf.splt->output_section) != NULL)
/* One entry for shared object struct ptr. */
bfd_put_64 (output_bfd, (bfd_vma) 0, htab->elf.sgotplt->contents + 8);
/* One entry for _dl_runtime_resolve. */
- bfd_put_64 (output_bfd, (bfd_vma) 0, htab->elf.sgotplt->contents + 12);
+ bfd_put_64 (output_bfd, (bfd_vma) 0, htab->elf.sgotplt->contents + 16);
}
elf_section_data (htab->elf.sgot->output_section)
#define bfd_elf64_mkobject elf_s390_mkobject
#define elf_backend_object_p elf_s390_object_p
-/* Enable ELF64 archive functions. */
-#define bfd_elf64_archive_functions
-extern bfd_boolean bfd_elf64_archive_slurp_armap (bfd *);
-extern bfd_boolean bfd_elf64_archive_write_armap (bfd *, unsigned int, struct orl *, unsigned int, int);
-
-#define bfd_elf64_archive_slurp_extended_name_table _bfd_archive_coff_slurp_extended_name_table
-#define bfd_elf64_archive_construct_extended_name_table _bfd_archive_coff_construct_extended_name_table
-#define bfd_elf64_archive_truncate_arname _bfd_archive_coff_truncate_arname
-#define bfd_elf64_archive_read_ar_hdr _bfd_archive_coff_read_ar_hdr
-#define bfd_elf64_archive_write_ar_hdr _bfd_archive_coff_write_ar_hdr
-#define bfd_elf64_archive_openr_next_archived_file _bfd_archive_coff_openr_next_archived_file
-#define bfd_elf64_archive_get_elt_at_index _bfd_archive_coff_get_elt_at_index
-#define bfd_elf64_archive_generic_stat_arch_elt _bfd_archive_coff_generic_stat_arch_elt
-#define bfd_elf64_archive_update_armap_timestamp _bfd_archive_coff_update_armap_timestamp
-
#include "elf64-target.h"