X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felf64-s390.c;h=6c53ed395eda736f7774cfb5c12b527313943bcd;hb=63c1f59d665542359de4737e3e48033c588f44dc;hp=64a74c5dfcdd87bed5636d29d379d5b92425ff45;hpb=5474d94f03aedba2f832006dc7d680cc15792a7b;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf64-s390.c b/bfd/elf64-s390.c index 64a74c5dfc..6c53ed395e 100644 --- a/bfd/elf64-s390.c +++ b/bfd/elf64-s390.c @@ -1,5 +1,5 @@ /* IBM S/390-specific support for 64-bit ELF - Copyright (C) 2000-2016 Free Software Foundation, Inc. + Copyright (C) 2000-2017 Free Software Foundation, Inc. Contributed Martin Schwidefsky (schwidefsky@de.ibm.com). This file is part of BFD, the Binary File Descriptor library. @@ -25,6 +25,7 @@ #include "libbfd.h" #include "elf-bfd.h" #include "elf/s390.h" +#include "elf-s390.h" #include /* In case we're on a 32-bit machine, construct a 64-bit "-1" value @@ -660,6 +661,9 @@ struct elf_s390_link_hash_table /* Small local sym cache. */ struct sym_cache sym_cache; + + /* Options passed from the linker. */ + struct s390_elf_params *params; }; /* Get the s390 ELF linker hash table from a link_info structure. */ @@ -785,7 +789,8 @@ elf_s390_copy_indirect_symbol (struct bfd_link_info *info, /* If called to transfer flags for a weakdef during processing of elf_adjust_dynamic_symbol, don't copy non_got_ref. We clear it ourselves for ELIMINATE_COPY_RELOCS. */ - dir->ref_dynamic |= ind->ref_dynamic; + if (dir->versioned != versioned_hidden) + dir->ref_dynamic |= ind->ref_dynamic; dir->ref_regular |= ind->ref_regular; dir->ref_regular_nonweak |= ind->ref_regular_nonweak; dir->needs_plt |= ind->needs_plt; @@ -858,7 +863,7 @@ elf_s390_check_relocs (bfd *abfd, for (rel = relocs; rel < rel_end; rel++) { unsigned int r_type; - unsigned long r_symndx; + unsigned int r_symndx; struct elf_link_hash_entry *h; Elf_Internal_Sym *isym; @@ -907,10 +912,6 @@ elf_s390_check_relocs (bfd *abfd, 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; - - /* PR15323, ref flags aren't set for references in the same - object. */ - h->root.non_ir_ref = 1; } /* Create got section and local_got_refcounts array if they @@ -1328,186 +1329,6 @@ elf_s390_gc_mark_hook (asection *sec, return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); } -/* Update the got entry reference counts for the section being removed. */ - -static bfd_boolean -elf_s390_gc_sweep_hook (bfd *abfd, - struct bfd_link_info *info, - asection *sec, - const Elf_Internal_Rela *relocs) -{ - struct elf_s390_link_hash_table *htab; - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - bfd_signed_vma *local_got_refcounts; - const Elf_Internal_Rela *rel, *relend; - - if (bfd_link_relocatable (info)) - return TRUE; - - htab = elf_s390_hash_table (info); - if (htab == NULL) - return FALSE; - - elf_section_data (sec)->local_dynrel = NULL; - - symtab_hdr = &elf_symtab_hdr (abfd); - sym_hashes = elf_sym_hashes (abfd); - local_got_refcounts = elf_local_got_refcounts (abfd); - - relend = relocs + sec->reloc_count; - for (rel = relocs; rel < relend; rel++) - { - unsigned long r_symndx; - unsigned int r_type; - struct elf_link_hash_entry *h = NULL; - - r_symndx = ELF64_R_SYM (rel->r_info); - if (r_symndx >= symtab_hdr->sh_info) - { - struct elf_s390_link_hash_entry *eh; - struct elf_dyn_relocs **pp; - struct elf_dyn_relocs *p; - - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - 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; - eh = (struct elf_s390_link_hash_entry *) h; - - for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next) - if (p->sec == sec) - { - /* Everything must go for SEC. */ - *pp = p->next; - break; - } - } - else - { - Elf_Internal_Sym *isym; - - /* A local symbol. */ - isym = bfd_sym_from_r_symndx (&htab->sym_cache, - abfd, r_symndx); - if (isym == NULL) - return FALSE; - - if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC) - { - struct plt_entry *plt = elf_s390_local_plt (abfd); - if (plt[r_symndx].plt.refcount > 0) - plt[r_symndx].plt.refcount--; - } - } - - r_type = ELF64_R_TYPE (rel->r_info); - r_type = elf_s390_tls_transition (info, r_type, h != NULL); - switch (r_type) - { - case R_390_TLS_LDM64: - if (htab->tls_ldm_got.refcount > 0) - htab->tls_ldm_got.refcount -= 1; - 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) - { - h->plt.refcount--; - break; - } - - case R_390_GOTPC: - case R_390_GOTPCDBL: - break; - - case R_390_TLS_GD64: - case R_390_TLS_IE64: - case R_390_TLS_GOTIE12: - case R_390_TLS_GOTIE20: - case R_390_TLS_GOTIE64: - case R_390_TLS_IEENT: - case R_390_GOT12: - case R_390_GOT16: - case R_390_GOT20: - case R_390_GOT32: - case R_390_GOT64: - case R_390_GOTENT: - if (h != NULL) - { - if (h->got.refcount > 0) - h->got.refcount -= 1; - } - else if (local_got_refcounts != NULL) - { - if (local_got_refcounts[r_symndx] > 0) - local_got_refcounts[r_symndx] -= 1; - } - break; - - case R_390_8: - case R_390_12: - case R_390_16: - case R_390_20: - case R_390_32: - case R_390_64: - case R_390_PC16: - case R_390_PC12DBL: - case R_390_PC16DBL: - case R_390_PC24DBL: - case R_390_PC32: - case R_390_PC32DBL: - case R_390_PC64: - if (bfd_link_pic (info)) - break; - /* Fall through */ - - case R_390_PLT12DBL: - case R_390_PLT16DBL: - case R_390_PLT24DBL: - case R_390_PLT32: - case R_390_PLT32DBL: - case R_390_PLT64: - case R_390_PLTOFF16: - case R_390_PLTOFF32: - case R_390_PLTOFF64: - if (h != NULL) - { - if (h->plt.refcount > 0) - h->plt.refcount -= 1; - } - break; - - case R_390_GOTPLT12: - case R_390_GOTPLT16: - case R_390_GOTPLT20: - case R_390_GOTPLT32: - case R_390_GOTPLT64: - case R_390_GOTPLTENT: - if (h != NULL) - { - if (h->plt.refcount > 0) - { - ((struct elf_s390_link_hash_entry *) h)->gotplt_refcount--; - h->plt.refcount -= 1; - } - } - else if (local_got_refcounts != NULL) - { - if (local_got_refcounts[r_symndx] > 0) - local_got_refcounts[r_symndx] -= 1; - } - break; - - default: - break; - } - } - - return TRUE; -} - /* Make sure we emit a GOT entry if the symbol was supposed to have a PLT entry but we found we will not create any. Called when we find we will not have any PLT for this symbol, by for example @@ -1530,6 +1351,23 @@ elf_s390_adjust_gotplt (struct elf_s390_link_hash_entry *h) h->gotplt_refcount = -1; } +/* Find dynamic relocs for H that apply to read-only sections. */ + +static asection * +readonly_dynrelocs (struct elf_link_hash_entry *h) +{ + struct elf_dyn_relocs *p; + + for (p = elf_s390_hash_entry (h)->dyn_relocs; p != NULL; p = p->next) + { + asection *s = p->sec->output_section; + + if (s != NULL && (s->flags & SEC_READONLY) != 0) + return p->sec; + } + return NULL; +} + /* Adjust a symbol defined by a dynamic object and referenced by a regular object. The current definition is in some section of the dynamic object, but we're not including those sections. We have to @@ -1621,14 +1459,14 @@ elf_s390_adjust_dynamic_symbol (struct bfd_link_info *info, /* 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. */ - if (h->u.weakdef != NULL) + if (h->is_weakalias) { - BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined - || h->u.weakdef->root.type == bfd_link_hash_defweak); - h->root.u.def.section = h->u.weakdef->root.u.def.section; - h->root.u.def.value = h->u.weakdef->root.u.def.value; + struct elf_link_hash_entry *def = weakdef (h); + BFD_ASSERT (def->root.type == bfd_link_hash_defined); + h->root.u.def.section = def->root.u.def.section; + h->root.u.def.value = def->root.u.def.value; if (ELIMINATE_COPY_RELOCS || info->nocopyreloc) - h->non_got_ref = h->u.weakdef->non_got_ref; + h->non_got_ref = def->non_got_ref; return TRUE; } @@ -1885,7 +1723,8 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, if (eh->dyn_relocs != NULL && h->root.type == bfd_link_hash_undefweak) { - if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) + if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT + || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)) eh->dyn_relocs = NULL; /* Make sure undefined weak symbols are output as a dynamic @@ -1941,28 +1780,29 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, return TRUE; } -/* Find any dynamic relocs that apply to read-only sections. */ +/* Set DF_TEXTREL if we find any dynamic relocs that apply to + read-only sections. */ static bfd_boolean -readonly_dynrelocs (struct elf_link_hash_entry *h, void * inf) +maybe_set_textrel (struct elf_link_hash_entry *h, void *info_p) { - struct elf_s390_link_hash_entry *eh; - struct elf_dyn_relocs *p; + asection *sec; - eh = (struct elf_s390_link_hash_entry *) h; - for (p = eh->dyn_relocs; p != NULL; p = p->next) - { - asection *s = p->sec->output_section; + if (h->root.type == bfd_link_hash_indirect) + return TRUE; - if (s != NULL && (s->flags & SEC_READONLY) != 0) - { - struct bfd_link_info *info = (struct bfd_link_info *) inf; + sec = readonly_dynrelocs (h); + if (sec != NULL) + { + struct bfd_link_info *info = (struct bfd_link_info *) info_p; - info->flags |= DF_TEXTREL; + info->flags |= DF_TEXTREL; + info->callbacks->minfo + (_("%B: dynamic relocation against `%T' in read-only section `%A'\n"), + sec->owner, h->root.root.string, sec); - /* Not an error, just cut short the traversal. */ - return FALSE; - } + /* Not an error, just cut short the traversal. */ + return FALSE; } return TRUE; } @@ -2194,8 +2034,7 @@ elf_s390_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, /* If any dynamic relocs apply to a read-only section, then we need a DT_TEXTREL entry. */ if ((info->flags & DF_TEXTREL) == 0) - elf_link_hash_traverse (&htab->elf, readonly_dynrelocs, - info); + elf_link_hash_traverse (&htab->elf, maybe_set_textrel, info); if ((info->flags & DF_TEXTREL) != 0) { @@ -2249,10 +2088,10 @@ invalid_tls_insn (bfd *input_bfd, howto = elf_howto_table + ELF64_R_TYPE (rel->r_info); _bfd_error_handler /* xgettext:c-format */ - (_("%B(%A+0x%lx): invalid instruction for TLS relocation %s"), + (_("%B(%A+%#Lx): invalid instruction for TLS relocation %s"), input_bfd, input_section, - (long) rel->r_offset, + rel->r_offset, howto->name); bfd_set_error (bfd_error_bad_value); } @@ -2302,6 +2141,7 @@ elf_s390_relocate_section (bfd *output_bfd, bfd_reloc_status_type r; int tls_type; asection *base_got = htab->elf.sgot; + bfd_boolean resolved_to_zero; r_type = ELF64_R_TYPE (rel->r_info); if (r_type == (int) R_390_GNU_VTINHERIT @@ -2397,6 +2237,9 @@ elf_s390_relocate_section (bfd *output_bfd, if (bfd_link_relocatable (info)) continue; + resolved_to_zero = (h != NULL + && UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)); + switch (r_type) { case R_390_GOTPLT12: @@ -2700,6 +2543,18 @@ elf_s390_relocate_section (bfd *output_bfd, case R_390_PC32: case R_390_PC32DBL: case R_390_PC64: + if (h != NULL + && bfd_link_pie (info) + && !h->def_regular) + { + _bfd_error_handler (_("%B: `%s' non-PLT reloc for symbol defined " + "in shared library and accessed " + "from executable " + "(rebuild file with -fPIC ?)"), + input_bfd, h->root.root.string); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } /* The target of these relocs are instruction operands residing in read-only sections. We cannot emit a runtime reloc for it. */ @@ -2724,10 +2579,11 @@ elf_s390_relocate_section (bfd *output_bfd, && s390_is_ifunc_symbol_p (h) && h->def_regular) { - if (!bfd_link_pic (info) || !h->non_got_ref) + if (!bfd_link_pic (info)) { - /* For a non-shared object STT_GNU_IFUNC symbol must - go through PLT. */ + /* For a non-shared object the symbol will not + change. Hence we can write the address of the + target IPLT slot now. */ relocation = (htab->elf.iplt->output_section->vma + htab->elf.iplt->output_offset + h ->plt.offset); @@ -2786,7 +2642,8 @@ elf_s390_relocate_section (bfd *output_bfd, if ((bfd_link_pic (info) && (h == NULL - || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT + || (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT + && !resolved_to_zero) || h->root.type != bfd_link_hash_undefweak) && ((r_type != R_390_PC16 && r_type != R_390_PC12DBL @@ -3183,8 +3040,10 @@ elf_s390_relocate_section (bfd *output_bfd, insn0 = bfd_get_32 (input_bfd, contents + rel->r_offset); insn1 = bfd_get_16 (input_bfd, contents + rel->r_offset + 4); if (insn1 != 0x0004) - invalid_tls_insn (input_bfd, input_section, rel); - ry = 0; + { + invalid_tls_insn (input_bfd, input_section, rel); + return FALSE; + } if ((insn0 & 0xff00f000) == 0xe3000000) /* lg %rx,0(%ry,0) -> sllg %rx,%ry,0 */ ry = (insn0 & 0x000f0000); @@ -3198,7 +3057,10 @@ elf_s390_relocate_section (bfd *output_bfd, /* lg %rx,0(%r12,%ry) -> sllg %rx,%ry,0 */ ry = (insn0 & 0x0000f000) << 4; else - invalid_tls_insn (input_bfd, input_section, rel); + { + invalid_tls_insn (input_bfd, input_section, rel); + return FALSE; + } insn0 = 0xeb000000 | (insn0 & 0x00f00000) | ry; insn1 = 0x000d; bfd_put_32 (output_bfd, insn0, contents + rel->r_offset); @@ -3212,7 +3074,10 @@ elf_s390_relocate_section (bfd *output_bfd, insn0 = bfd_get_32 (input_bfd, contents + rel->r_offset); insn1 = bfd_get_16 (input_bfd, contents + rel->r_offset + 4); if ((insn0 & 0xffff0000) != 0xc0e50000) - invalid_tls_insn (input_bfd, input_section, rel); + { + invalid_tls_insn (input_bfd, input_section, rel); + return FALSE; + } if (!bfd_link_pic (info) && (h == NULL || h->dynindx == -1)) { /* GD->LE transition. @@ -3239,7 +3104,10 @@ elf_s390_relocate_section (bfd *output_bfd, insn0 = bfd_get_32 (input_bfd, contents + rel->r_offset); insn1 = bfd_get_16 (input_bfd, contents + rel->r_offset + 4); if ((insn0 & 0xffff0000) != 0xc0e50000) - invalid_tls_insn (input_bfd, input_section, rel); + { + invalid_tls_insn (input_bfd, input_section, rel); + return FALSE; + } /* LD->LE transition. brasl %r14,__tls_get_addr@plt -> brcl 0,. */ insn0 = 0xc0040000; @@ -3264,10 +3132,10 @@ elf_s390_relocate_section (bfd *output_bfd, rel->r_offset) != (bfd_vma) -1) _bfd_error_handler /* xgettext:c-format */ - (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"), + (_("%B(%A+%#Lx): unresolvable %s relocation against symbol `%s'"), input_bfd, input_section, - (long) rel->r_offset, + rel->r_offset, howto->name, h->root.root.string); @@ -3321,9 +3189,9 @@ elf_s390_relocate_section (bfd *output_bfd, { _bfd_error_handler /* xgettext:c-format */ - (_("%B(%A+0x%lx): reloc against `%s': error %d"), + (_("%B(%A+%#Lx): reloc against `%s': error %d"), input_bfd, input_section, - (long) rel->r_offset, name, (int) r); + rel->r_offset, name, (int) r); return FALSE; } } @@ -3569,7 +3437,7 @@ elf_s390_finish_dynamic_symbol (bfd *output_bfd, RELATIVE reloc. The entry in the global offset table will already have been initialized in the relocate_section function. */ - if (!h->def_regular) + if (!(h->def_regular || ELF_COMMON_DEF_P (h))) return FALSE; BFD_ASSERT((h->got.offset & 1) != 0); rela.r_info = ELF64_R_INFO (0, R_390_RELATIVE); @@ -3610,7 +3478,7 @@ elf_s390_finish_dynamic_symbol (bfd *output_bfd, + h->root.u.def.section->output_offset); rela.r_info = ELF64_R_INFO (h->dynindx, R_390_COPY); rela.r_addend = 0; - if ((h->root.u.def.section->flags & SEC_READONLY) != 0) + if (h->root.u.def.section == htab->elf.sdynrelro) s = htab->elf.sreldynrelro; else s = htab->elf.srelbss; @@ -3716,7 +3584,9 @@ elf_s390_finish_dynamic_sections (bfd *output_bfd, break; case DT_PLTRELSZ: - dyn.d_un.d_val = htab->elf.srelplt->size + htab->elf.irelplt->size; + dyn.d_un.d_val = htab->elf.srelplt->size; + if (htab->elf.irelplt) + dyn.d_un.d_val += htab->elf.irelplt->size; break; case DT_RELASZ: @@ -3727,7 +3597,9 @@ elf_s390_finish_dynamic_sections (bfd *output_bfd, linker script arranges for .rela.plt to follow all other relocation sections, we don't have to worry about changing the DT_RELA entry. */ - dyn.d_un.d_val -= htab->elf.srelplt->size + htab->elf.irelplt->size; + dyn.d_un.d_val -= htab->elf.srelplt->size; + if (htab->elf.irelplt) + dyn.d_un.d_val -= htab->elf.irelplt->size; break; } @@ -3781,6 +3653,9 @@ elf_s390_finish_dynamic_sections (bfd *output_bfd, symtab_hdr = &elf_symtab_hdr (ibfd); + if (!is_s390_elf (ibfd)) + continue; + local_plt = elf_s390_local_plt (ibfd); if (local_plt != NULL) for (i = 0; i < symtab_hdr->sh_info; i++) @@ -3941,6 +3816,81 @@ elf64_s390_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) return elf_s390_merge_obj_attributes (ibfd, info); } +/* We may add a PT_S390_PGSTE program header. */ + +static int +elf_s390_additional_program_headers (bfd *abfd ATTRIBUTE_UNUSED, + struct bfd_link_info *info) +{ + struct elf_s390_link_hash_table *htab; + + if (info) + { + htab = elf_s390_hash_table (info); + if (htab) + return htab->params->pgste; + } + return 0; +} + + +/* Add the PT_S390_PGSTE program header. */ + +static bfd_boolean +elf_s390_modify_segment_map (bfd *abfd, struct bfd_link_info *info) +{ + struct elf_s390_link_hash_table *htab; + struct elf_segment_map *m, *pm = NULL; + + if (!abfd || !info) + return TRUE; + + htab = elf_s390_hash_table (info); + if (!htab || !htab->params->pgste) + return TRUE; + + /* If there is already a PT_S390_PGSTE header, avoid adding + another. */ + m = elf_seg_map (abfd); + while (m && m->p_type != PT_S390_PGSTE) + { + pm = m; + m = m->next; + } + + if (m) + return TRUE; + + m = (struct elf_segment_map *) + bfd_zalloc (abfd, sizeof (struct elf_segment_map)); + if (m == NULL) + return FALSE; + m->p_type = PT_S390_PGSTE; + m->count = 0; + m->next = NULL; + if (pm) + pm->next = m; + + return TRUE; +} + +bfd_boolean +bfd_elf_s390_set_options (struct bfd_link_info *info, + struct s390_elf_params *params) +{ + struct elf_s390_link_hash_table *htab; + + if (info) + { + htab = elf_s390_hash_table (info); + if (htab) + htab->params = params; + } + + return TRUE; +} + + /* Why was the hash table entry size definition changed from ARCH_SIZE/8 to 4? This breaks the 64 bit dynamic linker and this is the only reason for the s390_elf64_size_info structure. */ @@ -4010,7 +3960,6 @@ const struct elf_size_info s390_elf64_size_info = #define elf_backend_finish_dynamic_sections elf_s390_finish_dynamic_sections #define elf_backend_finish_dynamic_symbol elf_s390_finish_dynamic_symbol #define elf_backend_gc_mark_hook elf_s390_gc_mark_hook -#define elf_backend_gc_sweep_hook elf_s390_gc_sweep_hook #define elf_backend_reloc_type_class elf_s390_reloc_type_class #define elf_backend_relocate_section elf_s390_relocate_section #define elf_backend_size_dynamic_sections elf_s390_size_dynamic_sections @@ -4021,6 +3970,8 @@ const struct elf_size_info s390_elf64_size_info = #define elf_backend_plt_sym_val elf_s390_plt_sym_val #define elf_backend_add_symbol_hook elf_s390_add_symbol_hook #define elf_backend_sort_relocs_p elf_s390_elf_sort_relocs_p +#define elf_backend_additional_program_headers elf_s390_additional_program_headers +#define elf_backend_modify_segment_map elf_s390_modify_segment_map #define bfd_elf64_mkobject elf_s390_mkobject #define elf_backend_object_p elf_s390_object_p