X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felf64-ppc.c;h=f399e351e0b954772902e247bd9ebea2670e40bb;hb=8a2df5e2df374289e00ecd8f099eb46d76ef982e;hp=2a9ea1e2d261beea6a44fae81c4e284b7493a4d0;hpb=4eca02287cf48e60ee89338ddd35f8d0d8257a51;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index 2a9ea1e2d2..f399e351e0 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -1,5 +1,5 @@ /* PowerPC64-specific support for 64-bit ELF. - Copyright (C) 1999-2016 Free Software Foundation, Inc. + Copyright (C) 1999-2017 Free Software Foundation, Inc. Written by Linus Nordberg, Swox AB , based on elf32-ppc.c by Ian Lance Taylor. Largely rewritten by Alan Modra. @@ -72,9 +72,11 @@ static bfd_vma opd_entry_value #define elf_backend_plt_alignment 3 #define elf_backend_plt_not_loaded 1 #define elf_backend_got_header_size 8 +#define elf_backend_want_dynrelro 1 #define elf_backend_can_gc_sections 1 #define elf_backend_can_refcount 1 #define elf_backend_rela_normal 1 +#define elf_backend_dtrel_excludes_plt 1 #define elf_backend_default_execstack 0 #define bfd_elf64_mkobject ppc64_elf_mkobject @@ -86,12 +88,13 @@ static bfd_vma opd_entry_value #define bfd_elf64_bfd_link_hash_table_create ppc64_elf_link_hash_table_create #define bfd_elf64_get_synthetic_symtab ppc64_elf_get_synthetic_symtab #define bfd_elf64_bfd_link_just_syms ppc64_elf_link_just_syms +#define bfd_elf64_bfd_gc_sections ppc64_elf_gc_sections #define elf_backend_object_p ppc64_elf_object_p #define elf_backend_grok_prstatus ppc64_elf_grok_prstatus #define elf_backend_grok_psinfo ppc64_elf_grok_psinfo #define elf_backend_write_core_note ppc64_elf_write_core_note -#define elf_backend_create_dynamic_sections ppc64_elf_create_dynamic_sections +#define elf_backend_create_dynamic_sections _bfd_elf_create_dynamic_sections #define elf_backend_copy_indirect_symbol ppc64_elf_copy_indirect_symbol #define elf_backend_add_symbol_hook ppc64_elf_add_symbol_hook #define elf_backend_check_directives ppc64_elf_before_check_relocs @@ -117,6 +120,8 @@ static bfd_vma opd_entry_value #define elf_backend_link_output_symbol_hook ppc64_elf_output_symbol_hook #define elf_backend_special_sections ppc64_elf_special_sections #define elf_backend_merge_symbol_attribute ppc64_elf_merge_symbol_attribute +#define elf_backend_merge_symbol ppc64_elf_merge_symbol +#define elf_backend_get_reloc_section bfd_get_section_by_name /* The name of the dynamic interpreter. This is put in the .interp section. */ @@ -2041,6 +2046,21 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 0x1fffc1, /* dst_mask */ TRUE), /* pcrel_offset */ + /* A split-field reloc for addpcis, non-relative (gas internal use only). */ + HOWTO (R_PPC64_16DX_HA, /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + ppc64_elf_ha_reloc, /* special_function */ + "R_PPC64_16DX_HA", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0x1fffc1, /* dst_mask */ + FALSE), /* pcrel_offset */ + /* Like R_PPC64_ADDR16_HI, but no overflow. */ HOWTO (R_PPC64_ADDR16_HIGH, /* type */ 16, /* rightshift */ @@ -2446,6 +2466,8 @@ ppc64_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, break; case BFD_RELOC_HI16_S_PCREL: r = R_PPC64_REL16_HA; break; + case BFD_RELOC_PPC_16DX_HA: r = R_PPC64_16DX_HA; + break; case BFD_RELOC_PPC_REL16DX_HA: r = R_PPC64_REL16DX_HA; break; case BFD_RELOC_PPC64_ENTRY: r = R_PPC64_ENTRY; @@ -2478,7 +2500,7 @@ ppc64_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, /* Set the howto pointer for a PowerPC ELF reloc. */ static void -ppc64_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr, +ppc64_elf_info_to_howto (bfd *abfd, arelent *cache_ptr, Elf_Internal_Rela *dst) { unsigned int type; @@ -2490,6 +2512,7 @@ ppc64_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr, type = ELF64_R_TYPE (dst->r_info); if (type >= ARRAY_SIZE (ppc64_elf_howto_table)) { + /* xgettext:c-format */ _bfd_error_handler (_("%B: invalid relocation type %d"), abfd, (int) type); type = R_PPC64_NONE; @@ -3166,7 +3189,7 @@ compare_symbols (const void *ap, const void *bp) if ((a->flags & BSF_DYNAMIC) == 0 && (b->flags & BSF_DYNAMIC) != 0) return 1; - return 0; + return a > b; } /* Search SYMS for a symbol of the given VALUE. */ @@ -3797,6 +3820,13 @@ must_be_dyn_reloc (struct bfd_link_info *info, } } +/* Whether an undefined weak symbol should resolve to its link-time + value, even in PIC or PIE objects. */ +#define UNDEFWEAK_NO_DYNAMIC_RELOC(INFO, H) \ + ((H)->root.type == bfd_link_hash_undefweak \ + && (ELF_ST_VISIBILITY ((H)->other) != STV_DEFAULT \ + || (INFO)->dynamic_undefined_weak == 0)) + /* If ELIMINATE_COPY_RELOCS is non-zero, the linker will try to avoid copying dynamic variables from a shared lib into an app's dynbss section, and instead use a dynamic relocation to point into the @@ -3976,9 +4006,6 @@ struct ppc_link_hash_entry should be set for all globals defined in any opd/toc section. */ unsigned int adjust_done:1; - /* Set if we twiddled this symbol to weak at some stage. */ - unsigned int was_undefined:1; - /* Set if this is an out-of-line register save/restore function, with non-standard calling convention. */ unsigned int save_res:1; @@ -4052,8 +4079,6 @@ struct ppc_link_hash_table struct ppc_link_hash_entry *dot_syms; /* Shortcuts to get to dynamic linker sections. */ - asection *dynbss; - asection *relbss; asection *glink; asection *sfpr; asection *brlt; @@ -4085,8 +4110,16 @@ struct ppc_link_hash_table /* Set on error. */ unsigned int stub_error:1; - /* Temp used by ppc64_elf_before_check_relocs. */ - unsigned int twiddled_syms:1; + /* Whether func_desc_adjust needs to be run over symbols. */ + unsigned int need_func_desc_adj:1; + + /* Whether there exist local gnu indirect function resolvers, + referenced by dynamic relocations. */ + unsigned int local_ifunc_resolver:1; + unsigned int maybe_local_ifunc_resolver:1; + + /* Whether plt calls for ELFv2 localentry:0 funcs have been optimized. */ + unsigned int has_plt_localentry0:1; /* Incremented every time we size stubs. */ unsigned int stub_iteration; @@ -4261,7 +4294,7 @@ static hashval_t tocsave_htab_hash (const void *p) { const struct tocsave_entry *e = (const struct tocsave_entry *) p; - return ((bfd_vma)(intptr_t) e->sec ^ e->offset) >> 3; + return ((bfd_vma) (intptr_t) e->sec ^ e->offset) >> 3; } static int @@ -4588,6 +4621,7 @@ ppc_add_stub (const char *stub_name, TRUE, FALSE); if (stub_entry == NULL) { + /* xgettext:c-format */ info->callbacks->einfo (_("%P: %B: cannot create stub entry %s\n"), section->owner, stub_name); return NULL; @@ -4636,31 +4670,6 @@ create_got_section (bfd *abfd, struct bfd_link_info *info) return TRUE; } -/* Create the dynamic sections, and set up shortcuts. */ - -static bfd_boolean -ppc64_elf_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info) -{ - struct ppc_link_hash_table *htab; - - if (!_bfd_elf_create_dynamic_sections (dynobj, info)) - return FALSE; - - htab = ppc_hash_table (info); - if (htab == NULL) - return FALSE; - - htab->dynbss = bfd_get_linker_section (dynobj, ".dynbss"); - if (!bfd_link_pic (info)) - htab->relbss = bfd_get_linker_section (dynobj, ".rela.bss"); - - if (!htab->elf.sgot || !htab->elf.splt || !htab->elf.srelplt || !htab->dynbss - || (!bfd_link_pic (info) && !htab->relbss)) - abort (); - - return TRUE; -} - /* Follow indirect and warning symbol links. */ static inline struct bfd_link_hash_entry * @@ -4745,7 +4754,8 @@ ppc64_elf_copy_indirect_symbol (struct bfd_link_info *info, && edir->elf.dynamic_adjusted)) edir->elf.non_got_ref |= eind->elf.non_got_ref; - edir->elf.ref_dynamic |= eind->elf.ref_dynamic; + if (edir->elf.versioned != versioned_hidden) + edir->elf.ref_dynamic |= eind->elf.ref_dynamic; edir->elf.ref_regular |= eind->elf.ref_regular; edir->elf.ref_regular_nonweak |= eind->elf.ref_regular_nonweak; edir->elf.needs_plt |= eind->elf.needs_plt; @@ -4892,32 +4902,29 @@ lookup_fdh (struct ppc_link_hash_entry *fh, struct ppc_link_hash_table *htab) fh->oh = fdh; } - return ppc_follow_link (fdh); + fdh = ppc_follow_link (fdh); + fdh->is_func_descriptor = 1; + fdh->oh = fh; + return fdh; } -/* Make a fake function descriptor sym for the code sym FH. */ +/* Make a fake function descriptor sym for the undefined code sym FH. */ static struct ppc_link_hash_entry * make_fdh (struct bfd_link_info *info, struct ppc_link_hash_entry *fh) { - bfd *abfd; - asymbol *newsym; - struct bfd_link_hash_entry *bh; + bfd *abfd = fh->elf.root.u.undef.abfd; + struct bfd_link_hash_entry *bh = NULL; struct ppc_link_hash_entry *fdh; - - abfd = fh->elf.root.u.undef.abfd; - newsym = bfd_make_empty_symbol (abfd); - newsym->name = fh->elf.root.root.string + 1; - newsym->section = bfd_und_section_ptr; - newsym->value = 0; - newsym->flags = BSF_WEAK; - - bh = NULL; - if (!_bfd_generic_link_add_one_symbol (info, abfd, newsym->name, - newsym->flags, newsym->section, - newsym->value, NULL, FALSE, FALSE, - &bh)) + flagword flags = (fh->elf.root.type == bfd_link_hash_undefweak + ? BSF_WEAK + : BSF_GLOBAL); + + if (!_bfd_generic_link_add_one_symbol (info, abfd, + fh->elf.root.root.string + 1, + flags, bfd_und_section_ptr, 0, + NULL, FALSE, FALSE, &bh)) return NULL; fdh = (struct ppc_link_hash_entry *) bh; @@ -5001,11 +5008,27 @@ ppc64_elf_merge_symbol_attribute (struct elf_link_hash_entry *h, bfd_boolean definition, bfd_boolean dynamic) { - if (definition && !dynamic) + if (definition && (!dynamic || !h->def_regular)) h->other = ((isym->st_other & ~ELF_ST_VISIBILITY (-1)) | ELF_ST_VISIBILITY (h->other)); } +/* Hook called on merging a symbol. We use this to clear "fake" since + we now have a real symbol. */ + +static bfd_boolean +ppc64_elf_merge_symbol (struct elf_link_hash_entry *h, + const Elf_Internal_Sym *isym ATTRIBUTE_UNUSED, + asection **psec ATTRIBUTE_UNUSED, + bfd_boolean newdef ATTRIBUTE_UNUSED, + bfd_boolean olddef ATTRIBUTE_UNUSED, + bfd *oldbfd ATTRIBUTE_UNUSED, + const asection *oldsec ATTRIBUTE_UNUSED) +{ + ((struct ppc_link_hash_entry *) h)->fake = 0; + return TRUE; +} + /* This function makes an old ABI object reference to ".bar" cause the inclusion of a new ABI object archive that defines "bar". NAME is a symbol defined in an archive. Return a symbol in the hash @@ -5024,8 +5047,7 @@ ppc64_elf_archive_symbol_lookup (bfd *abfd, if (h != NULL /* Don't return this sym if it is a fake function descriptor created by add_symbol_adjust. */ - && !(h->root.type == bfd_link_hash_undefweak - && ((struct ppc_link_hash_entry *) h)->fake)) + && !((struct ppc_link_hash_entry *) h)->fake) return h; if (name[0] == '.') @@ -5057,12 +5079,12 @@ add_symbol_adjust (struct ppc_link_hash_entry *eh, struct bfd_link_info *info) struct ppc_link_hash_table *htab; struct ppc_link_hash_entry *fdh; - if (eh->elf.root.type == bfd_link_hash_indirect) - return TRUE; - if (eh->elf.root.type == bfd_link_hash_warning) eh = (struct ppc_link_hash_entry *) eh->elf.root.u.i.link; + if (eh->elf.root.type == bfd_link_hash_indirect) + return TRUE; + if (eh->elf.root.root.string[0] != '.') abort (); @@ -5071,38 +5093,50 @@ add_symbol_adjust (struct ppc_link_hash_entry *eh, struct bfd_link_info *info) return FALSE; fdh = lookup_fdh (eh, htab); - if (fdh == NULL) - { - if (!bfd_link_relocatable (info) - && (eh->elf.root.type == bfd_link_hash_undefined - || eh->elf.root.type == bfd_link_hash_undefweak) - && eh->elf.ref_regular) - { - /* Make an undefweak function descriptor sym, which is enough to - pull in an --as-needed shared lib, but won't cause link - errors. Archives are handled elsewhere. */ - fdh = make_fdh (info, eh); - if (fdh == NULL) - return FALSE; - fdh->elf.ref_regular = 1; - } + if (fdh == NULL + && !bfd_link_relocatable (info) + && (eh->elf.root.type == bfd_link_hash_undefined + || eh->elf.root.type == bfd_link_hash_undefweak) + && eh->elf.ref_regular) + { + /* Make an undefined function descriptor sym, in order to + pull in an --as-needed shared lib. Archives are handled + elsewhere. */ + fdh = make_fdh (info, eh); + if (fdh == NULL) + return FALSE; } - else + + if (fdh != NULL) { unsigned entry_vis = ELF_ST_VISIBILITY (eh->elf.other) - 1; unsigned descr_vis = ELF_ST_VISIBILITY (fdh->elf.other) - 1; + + /* Make both descriptor and entry symbol have the most + constraining visibility of either symbol. */ if (entry_vis < descr_vis) fdh->elf.other += entry_vis - descr_vis; else if (entry_vis > descr_vis) eh->elf.other += descr_vis - entry_vis; - if ((fdh->elf.root.type == bfd_link_hash_defined - || fdh->elf.root.type == bfd_link_hash_defweak) - && eh->elf.root.type == bfd_link_hash_undefined) - { - eh->elf.root.type = bfd_link_hash_undefweak; - eh->was_undefined = 1; - htab->twiddled_syms = 1; + /* Propagate reference flags from entry symbol to function + descriptor symbol. */ + fdh->elf.root.non_ir_ref_regular |= eh->elf.root.non_ir_ref_regular; + fdh->elf.root.non_ir_ref_dynamic |= eh->elf.root.non_ir_ref_dynamic; + fdh->elf.ref_regular |= eh->elf.ref_regular; + fdh->elf.ref_regular_nonweak |= eh->elf.ref_regular_nonweak; + + if (!fdh->elf.forced_local + && fdh->elf.dynindx == -1 + && fdh->elf.versioned != versioned_hidden + && (bfd_link_dll (info) + || fdh->elf.def_dynamic + || fdh->elf.ref_dynamic) + && (eh->elf.ref_regular + || eh->elf.def_regular)) + { + if (! bfd_elf_link_record_dynamic_symbol (info, &fdh->elf)) + return FALSE; } } @@ -5125,6 +5159,7 @@ ppc64_elf_before_check_relocs (bfd *ibfd, struct bfd_link_info *info) set_abiversion (ibfd, 1); else if (abiversion (ibfd) >= 2) { + /* xgettext:c-format */ info->callbacks->einfo (_("%P: %B .opd not allowed in ABI" " version %d\n"), ibfd, abiversion (ibfd)); @@ -5183,26 +5218,14 @@ ppc64_elf_before_check_relocs (bfd *ibfd, struct bfd_link_info *info) else if (htab->elf.hgot == NULL && strcmp (eh->elf.root.root.string, ".TOC.") == 0) htab->elf.hgot = &eh->elf; - else if (!add_symbol_adjust (eh, info)) - return FALSE; - p = &eh->u.next_dot_sym; - } - - /* Clear the list for non-ppc64 input files. */ - p = &htab->dot_syms; - while ((eh = *p) != NULL) - { - *p = NULL; + else if (abiversion (ibfd) <= 1) + { + htab->need_func_desc_adj = 1; + if (!add_symbol_adjust (eh, info)) + return FALSE; + } p = &eh->u.next_dot_sym; } - - /* We need to fix the undefs list for any syms we have twiddled to - undefweak. */ - if (htab->twiddled_syms) - { - bfd_link_repair_undef_list (&htab->elf.root); - htab->twiddled_syms = 0; - } return TRUE; } @@ -5395,12 +5418,17 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, h = NULL; else { + struct ppc_link_hash_entry *eh; + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; h = elf_follow_link (h); + eh = (struct ppc_link_hash_entry *) h; /* PR15323, ref flags aren't set for references in the same object. */ - h->root.non_ir_ref = 1; + h->root.non_ir_ref_regular = 1; + if (eh->is_func && eh->oh != NULL) + eh->oh->elf.root.non_ir_ref_regular = 1; if (h == htab->elf.hgot) sec->has_toc_reloc = 1; @@ -5471,7 +5499,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, tls_type = TLS_TLS | TLS_DTPREL; dogottls: sec->has_tls_reloc = 1; - /* Fall thru */ + /* Fall through */ case R_PPC64_GOT16: case R_PPC64_GOT16_DS: @@ -5559,7 +5587,8 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, /* It does not make sense to have a procedure linkage table entry for a non-ifunc local symbol. */ info->callbacks->einfo - (_("%P: %H: %s reloc against local symbol\n"), + /* xgettext:c-format */ + (_("%H: %s reloc against local symbol\n"), abfd, sec, rel->r_offset, ppc64_elf_howto_table[r_type]->name); bfd_set_error (bfd_error_bad_value); @@ -5606,7 +5635,8 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, { if (!ppc64_elf_howto_table[R_PPC64_ADDR32]) ppc_howto_init (); - info->callbacks->einfo (_("%P: %H: %s reloc unsupported " + /* xgettext:c-format */ + info->callbacks->einfo (_("%H: %s reloc unsupported " "in shared libraries and PIEs.\n"), abfd, sec, rel->r_offset, ppc64_elf_howto_table[r_type]->name); @@ -5619,6 +5649,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_PPC64_TOC16_DS: htab->do_multi_toc = 1; ppc64_elf_tdata (abfd)->has_small_toc_reloc = 1; + /* Fall through. */ case R_PPC64_TOC16_LO: case R_PPC64_TOC16_HI: case R_PPC64_TOC16_HA: @@ -5807,14 +5838,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, && ELF64_R_TYPE ((rel + 1)->r_info) == R_PPC64_TOC) { if (h != NULL) - { - if (h->root.root.string[0] == '.' - && h->root.root.string[1] != 0 - && lookup_fdh ((struct ppc_link_hash_entry *) h, htab)) - ; - else - ((struct ppc_link_hash_entry *) h)->is_func = 1; - } + ((struct ppc_link_hash_entry *) h)->is_func = 1; else { asection *s; @@ -5998,8 +6022,9 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, object file when linking. */ static bfd_boolean -ppc64_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) +ppc64_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) { + bfd *obfd = info->output_bfd; unsigned long iflags, oflags; if ((ibfd->flags & BFD_LINKER_CREATED) != 0) @@ -6008,7 +6033,7 @@ ppc64_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) if (!is_ppc64_elf (ibfd) || !is_ppc64_elf (obfd)) return TRUE; - if (!_bfd_generic_verify_endian_match (ibfd, obfd)) + if (!_bfd_generic_verify_endian_match (ibfd, info)) return FALSE; iflags = elf_elfheader (ibfd)->e_flags; @@ -6017,6 +6042,7 @@ ppc64_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) if (iflags & ~EF_PPC64_ABI) { _bfd_error_handler + /* xgettext:c-format */ (_("%B uses unknown e_flags 0x%lx"), ibfd, iflags); bfd_set_error (bfd_error_bad_value); return FALSE; @@ -6024,16 +6050,17 @@ ppc64_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) else if (iflags != oflags && iflags != 0) { _bfd_error_handler + /* xgettext:c-format */ (_("%B: ABI version %ld is not compatible with ABI version %ld output"), ibfd, iflags, oflags); bfd_set_error (bfd_error_bad_value); return FALSE; } - _bfd_elf_ppc_merge_fp_attributes (ibfd, obfd); + _bfd_elf_ppc_merge_fp_attributes (ibfd, info); /* Merge Tag_compatibility attributes and any common GNU ones. */ - _bfd_elf_merge_object_attributes (ibfd, obfd); + _bfd_elf_merge_object_attributes (ibfd, info); return TRUE; } @@ -6048,7 +6075,6 @@ ppc64_elf_print_private_bfd_data (bfd *abfd, void *ptr) { FILE *file = ptr; - /* xgettext:c-format */ fprintf (file, _("private flags = 0x%lx:"), elf_elfheader (abfd)->e_flags); @@ -6295,6 +6321,21 @@ ppc64_elf_maybe_function_sym (const asymbol *sym, asection *sec, return size; } +/* Return true if symbol is a strong function defined in an ELFv2 + object with st_other localentry bits of zero, ie. its local entry + point coincides with its global entry point. */ + +static bfd_boolean +is_elfv2_localentry0 (struct elf_link_hash_entry *h) +{ + return (h != NULL + && h->type == STT_FUNC + && h->root.type == bfd_link_hash_defined + && (STO_PPC64_LOCAL_MASK & h->other) == 0 + && is_ppc64_elf (h->root.u.def.section->owner) + && abiversion (h->root.u.def.section->owner) >= 2); +} + /* Return true if symbol is defined in a regular object file. */ static bfd_boolean @@ -6339,6 +6380,23 @@ defined_func_desc (struct ppc_link_hash_entry *fh) return NULL; } +static bfd_boolean func_desc_adjust (struct elf_link_hash_entry *, void *); + +/* Garbage collect sections, after first dealing with dot-symbols. */ + +static bfd_boolean +ppc64_elf_gc_sections (bfd *abfd, struct bfd_link_info *info) +{ + struct ppc_link_hash_table *htab = ppc_hash_table (info); + + if (htab != NULL && htab->need_func_desc_adj) + { + elf_link_hash_traverse (&htab->elf, func_desc_adjust, info); + htab->need_func_desc_adj = 0; + } + return bfd_elf_gc_sections (abfd, info); +} + /* Mark all our entry sym sections, both opd and code section. */ static void @@ -6404,11 +6462,12 @@ ppc64_elf_gc_mark_dynamic_ref (struct elf_link_hash_entry *h, void *inf) && ELF_ST_VISIBILITY (eh->elf.other) != STV_INTERNAL && ELF_ST_VISIBILITY (eh->elf.other) != STV_HIDDEN && (!bfd_link_executable (info) + || info->gc_keep_exported || info->export_dynamic || (eh->elf.dynamic && d != NULL && (*d->match) (&d->head, NULL, eh->elf.root.root.string))) - && (strchr (eh->elf.root.root.string, ELF_VER_CHR) != NULL + && (eh->elf.versioned >= versioned || !bfd_hide_sym_by_version (info->version_info, eh->elf.root.root.string))))) { @@ -6473,7 +6532,15 @@ ppc64_elf_gc_mark_hook (asection *sec, eh = (struct ppc_link_hash_entry *) h; fdh = defined_func_desc (eh); if (fdh != NULL) - eh = fdh; + { + /* -mcall-aixdesc code references the dot-symbol on + a call reloc. Mark the function descriptor too + against garbage collection. */ + fdh->elf.mark = 1; + if (fdh->elf.u.weakdef != NULL) + fdh->elf.u.weakdef->mark = 1; + eh = fdh; + } /* Function descriptor syms cause the associated function code sym section to be marked. */ @@ -6555,7 +6622,7 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, unsigned long r_symndx; enum elf_ppc64_reloc_type r_type; struct elf_link_hash_entry *h = NULL; - struct plt_entry **plt_list; + struct plt_entry **plt_list = NULL; unsigned char tls_type = 0; r_symndx = ELF64_R_SYM (rel->r_info); @@ -6634,6 +6701,8 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, if (ent->got.refcount > 0) ent->got.refcount -= 1; } + if (h != NULL && !bfd_link_pic (info) && abiversion (abfd) != 1) + plt_list = &h->plt.plist; break; case R_PPC64_PLT16_HA: @@ -6645,7 +6714,6 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, case R_PPC64_REL14_BRNTAKEN: case R_PPC64_REL14_BRTAKEN: case R_PPC64_REL24: - plt_list = NULL; if (h != NULL) plt_list = &h->plt.plist; else if (local_got_ents != NULL) @@ -6657,21 +6725,39 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0) plt_list = local_plt + r_symndx; } - if (plt_list) - { - struct plt_entry *ent; + break; - for (ent = *plt_list; ent != NULL; ent = ent->next) - if (ent->addend == rel->r_addend) - break; - if (ent != NULL && ent->plt.refcount > 0) - ent->plt.refcount -= 1; - } + case R_PPC64_ADDR64: + case R_PPC64_ADDR16: + case R_PPC64_ADDR16_DS: + case R_PPC64_ADDR16_HA: + case R_PPC64_ADDR16_HI: + case R_PPC64_ADDR16_HIGH: + case R_PPC64_ADDR16_HIGHA: + case R_PPC64_ADDR16_HIGHER: + case R_PPC64_ADDR16_HIGHERA: + case R_PPC64_ADDR16_HIGHEST: + case R_PPC64_ADDR16_HIGHESTA: + case R_PPC64_ADDR16_LO: + case R_PPC64_ADDR16_LO_DS: + if (h != NULL && !bfd_link_pic (info) && abiversion (abfd) != 1 + && rel->r_addend == 0) + plt_list = &h->plt.plist; break; default: break; } + if (plt_list != NULL) + { + struct plt_entry *ent; + + for (ent = *plt_list; ent != NULL; ent = ent->next) + if (ent->addend == rel->r_addend) + break; + if (ent != NULL && ent->plt.refcount > 0) + ent->plt.refcount -= 1; + } } return TRUE; } @@ -6952,7 +7038,6 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf) { struct bfd_link_info *info; struct ppc_link_hash_table *htab; - struct plt_entry *ent; struct ppc_link_hash_entry *fh; struct ppc_link_hash_entry *fdh; bfd_boolean force_local; @@ -6961,18 +7046,29 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf) if (fh->elf.root.type == bfd_link_hash_indirect) return TRUE; + if (!fh->is_func) + return TRUE; + + if (fh->elf.root.root.string[0] != '.' + || fh->elf.root.root.string[1] == '\0') + return TRUE; + info = inf; htab = ppc_hash_table (info); if (htab == NULL) return FALSE; + /* Find the corresponding function descriptor symbol. */ + fdh = lookup_fdh (fh, htab); + /* Resolve undefined references to dot-symbols as the value in the function descriptor, if we have one in a regular object. This is to satisfy cases like ".quad .foo". Calls to functions in dynamic objects are handled elsewhere. */ - if (fh->elf.root.type == bfd_link_hash_undefweak - && fh->was_undefined - && (fdh = defined_func_desc (fh)) != NULL + if ((fh->elf.root.type == bfd_link_hash_undefined + || fh->elf.root.type == bfd_link_hash_undefweak) + && (fdh->elf.root.type == bfd_link_hash_defined + || fdh->elf.root.type == bfd_link_hash_defweak) && get_opd_info (fdh->elf.root.u.def.section) != NULL && opd_entry_value (fdh->elf.root.u.def.section, fdh->elf.root.u.def.value, @@ -6985,23 +7081,18 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf) fh->elf.def_dynamic = fdh->elf.def_dynamic; } - /* If this is a function code symbol, transfer dynamic linking - information to the function descriptor symbol. */ - if (!fh->is_func) - return TRUE; - - for (ent = fh->elf.plt.plist; ent != NULL; ent = ent->next) - if (ent->plt.refcount > 0) - break; - if (ent == NULL - || fh->elf.root.root.string[0] != '.' - || fh->elf.root.root.string[1] == '\0') - return TRUE; + if (!fh->elf.dynamic) + { + struct plt_entry *ent; - /* Find the corresponding function descriptor symbol. Create it - as undefined if necessary. */ + for (ent = fh->elf.plt.plist; ent != NULL; ent = ent->next) + if (ent->plt.refcount > 0) + break; + if (ent == NULL) + return TRUE; + } - fdh = lookup_fdh (fh, htab); + /* Create a descriptor as undefined if necessary. */ if (fdh == NULL && !bfd_link_executable (info) && (fh->elf.root.type == bfd_link_hash_undefined @@ -7012,51 +7103,30 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf) return FALSE; } - /* Fake function descriptors are made undefweak. If the function - code symbol is strong undefined, make the fake sym the same. - If the function code symbol is defined, then force the fake - descriptor local; We can't support overriding of symbols in a - shared library on a fake descriptor. */ - + /* We can't support overriding of symbols on a fake descriptor. */ if (fdh != NULL && fdh->fake - && fdh->elf.root.type == bfd_link_hash_undefweak) - { - if (fh->elf.root.type == bfd_link_hash_undefined) - { - fdh->elf.root.type = bfd_link_hash_undefined; - bfd_link_add_undef (&htab->elf.root, &fdh->elf.root); - } - else if (fh->elf.root.type == bfd_link_hash_defined - || fh->elf.root.type == bfd_link_hash_defweak) - { - _bfd_elf_link_hash_hide_symbol (info, &fdh->elf, TRUE); - } - } + && (fh->elf.root.type == bfd_link_hash_defined + || fh->elf.root.type == bfd_link_hash_defweak)) + _bfd_elf_link_hash_hide_symbol (info, &fdh->elf, TRUE); - if (fdh != NULL - && !fdh->elf.forced_local - && (!bfd_link_executable (info) - || fdh->elf.def_dynamic - || fdh->elf.ref_dynamic - || (fdh->elf.root.type == bfd_link_hash_undefweak - && ELF_ST_VISIBILITY (fdh->elf.other) == STV_DEFAULT))) - { - if (fdh->elf.dynindx == -1) - if (! bfd_elf_link_record_dynamic_symbol (info, &fdh->elf)) - return FALSE; + /* Transfer dynamic linking information to the function descriptor. */ + if (fdh != NULL) + { fdh->elf.ref_regular |= fh->elf.ref_regular; fdh->elf.ref_dynamic |= fh->elf.ref_dynamic; fdh->elf.ref_regular_nonweak |= fh->elf.ref_regular_nonweak; fdh->elf.non_got_ref |= fh->elf.non_got_ref; - if (ELF_ST_VISIBILITY (fh->elf.other) == STV_DEFAULT) - { - move_plt_plist (fh, fdh); - fdh->elf.needs_plt = 1; - } - fdh->is_func_descriptor = 1; - fdh->oh = fh; - fh->oh = fdh; + fdh->elf.dynamic |= fh->elf.dynamic; + fdh->elf.needs_plt |= (fh->elf.needs_plt + || fh->elf.type == STT_FUNC + || fh->elf.type == STT_GNU_IFUNC); + move_plt_plist (fh, fdh); + + if (!fdh->elf.forced_local + && fh->elf.dynindx != -1) + if (!bfd_elf_link_record_dynamic_symbol (info, &fdh->elf)) + return FALSE; } /* Now that the info is on the function descriptor, clear the @@ -7141,7 +7211,11 @@ ppc64_elf_func_desc_adjust (bfd *obfd ATTRIBUTE_UNUSED, | STV_HIDDEN); } - elf_link_hash_traverse (&htab->elf, func_desc_adjust, info); + if (htab->need_func_desc_adj) + { + elf_link_hash_traverse (&htab->elf, func_desc_adjust, info); + htab->need_func_desc_adj = 0; + } return TRUE; } @@ -7229,7 +7303,7 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info, struct elf_link_hash_entry *h) { struct ppc_link_hash_table *htab; - asection *s; + asection *s, *srel; htab = ppc_hash_table (info); if (htab == NULL) @@ -7249,8 +7323,7 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info, if (ent == NULL || (h->type != STT_GNU_IFUNC && (SYMBOL_CALLS_LOCAL (info, h) - || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT - && h->root.type == bfd_link_hash_undefweak))) + || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))) || ((struct ppc_link_hash_entry *) h)->save_res) { h->plt.plist = NULL; @@ -7359,14 +7432,22 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info, to copy the initial value out of the dynamic object and into the runtime process image. We need to remember the offset into the .rela.bss section we are going to use. */ + if ((h->root.u.def.section->flags & SEC_READONLY) != 0) + { + s = htab->elf.sdynrelro; + srel = htab->elf.sreldynrelro; + } + else + { + s = htab->elf.sdynbss; + srel = htab->elf.srelbss; + } if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0) { - htab->relbss->size += sizeof (Elf64_External_Rela); + srel->size += sizeof (Elf64_External_Rela); h->needs_copy = 1; } - s = htab->dynbss; - return _bfd_elf_adjust_dynamic_copy (info, h, s); } @@ -7388,7 +7469,7 @@ ppc64_elf_hide_symbol (struct bfd_link_info *info, if (fh == NULL) { const char *p, *q; - struct ppc_link_hash_table *htab; + struct elf_link_hash_table *htab = elf_hash_table (info); char save; /* We aren't supposed to use alloca in BFD because on @@ -7403,12 +7484,8 @@ ppc64_elf_hide_symbol (struct bfd_link_info *info, p = eh->elf.root.root.string - 1; save = *p; *(char *) p = '.'; - htab = ppc_hash_table (info); - if (htab == NULL) - return; - fh = (struct ppc_link_hash_entry *) - elf_link_hash_lookup (&htab->elf, p, FALSE, FALSE, FALSE); + elf_link_hash_lookup (htab, p, FALSE, FALSE, FALSE); *(char *) p = save; /* Unfortunately, if it so happens that the string we were @@ -7422,7 +7499,7 @@ ppc64_elf_hide_symbol (struct bfd_link_info *info, --q, --p; if (q < eh->elf.root.root.string && *p == '.') fh = (struct ppc_link_hash_entry *) - elf_link_hash_lookup (&htab->elf, p, FALSE, FALSE, FALSE); + elf_link_hash_lookup (htab, p, FALSE, FALSE, FALSE); } if (fh != NULL) { @@ -7600,7 +7677,7 @@ tocsave_find (struct ppc_link_hash_table *htab, if (ent.sec == NULL || ent.sec->output_section == NULL) { _bfd_error_handler - (_("%B: undefined symbol on R_PPC64_TOCSAVE relocation")); + (_("%B: undefined symbol on R_PPC64_TOCSAVE relocation"), ibfd); return NULL; } @@ -7829,6 +7906,7 @@ dec_dynrel_count (bfd_vma r_info, } } + /* xgettext:c-format */ info->callbacks->einfo (_("%P: dynreloc miscount for %B, section %A\n"), sec->owner, sec); bfd_set_error (bfd_error_bad_value); @@ -7927,6 +8005,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info) || (r_type = ELF64_R_TYPE ((rel + 1)->r_info)) != R_PPC64_TOC) { _bfd_error_handler + /* xgettext:c-format */ (_("%B: unexpected reloc type %u in .opd section"), ibfd, r_type); broken = TRUE; @@ -7948,6 +8027,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info) sym_sec); _bfd_error_handler + /* xgettext:c-format */ (_("%B: undefined sym `%s' in .opd section"), ibfd, sym_name); broken = TRUE; @@ -8089,11 +8169,14 @@ ppc64_elf_edit_opd (struct bfd_link_info *info) if (h != NULL && h->root.root.string[0] == '.') { - fdh = lookup_fdh ((struct ppc_link_hash_entry *) h, htab); - if (fdh != NULL - && fdh->elf.root.type != bfd_link_hash_defined - && fdh->elf.root.type != bfd_link_hash_defweak) - fdh = NULL; + fdh = ((struct ppc_link_hash_entry *) h)->oh; + if (fdh != NULL) + { + fdh = ppc_follow_link (fdh); + if (fdh->elf.root.type != bfd_link_hash_defined + && fdh->elf.root.type != bfd_link_hash_defweak) + fdh = NULL; + } } skip = (sym_sec->owner != ibfd @@ -8263,6 +8346,11 @@ ppc64_elf_tls_setup (struct bfd_link_info *info) else if (!htab->do_multi_toc) htab->params->no_multi_toc = 1; + if (htab->params->plt_localentry0 < 0) + htab->params->plt_localentry0 + = elf_link_hash_lookup (&htab->elf, "GLIBC_2.26", + FALSE, FALSE, FALSE) != NULL; + htab->tls_get_addr = ((struct ppc_link_hash_entry *) elf_link_hash_lookup (&htab->elf, ".__tls_get_addr", FALSE, FALSE, TRUE)); @@ -8296,8 +8384,7 @@ ppc64_elf_tls_setup (struct bfd_link_info *info) && (tga_fd->type == STT_FUNC || tga_fd->needs_plt) && !(SYMBOL_CALLS_LOCAL (info, tga_fd) - || (ELF_ST_VISIBILITY (tga_fd->other) != STV_DEFAULT - && tga_fd->root.type == bfd_link_hash_undefweak))) + || UNDEFWEAK_NO_DYNAMIC_RELOC (info, tga_fd))) { struct plt_entry *ent; @@ -8309,7 +8396,7 @@ ppc64_elf_tls_setup (struct bfd_link_info *info) tga_fd->root.type = bfd_link_hash_indirect; tga_fd->root.u.i.link = &opt_fd->root; ppc64_elf_copy_indirect_symbol (info, opt_fd, tga_fd); - opt_fd->forced_local = 0; + opt_fd->mark = 1; if (opt_fd->dynindx != -1) { /* Use __tls_get_addr_opt in dynamic relocations. */ @@ -8326,7 +8413,7 @@ ppc64_elf_tls_setup (struct bfd_link_info *info) tga->root.type = bfd_link_hash_indirect; tga->root.u.i.link = &opt->root; ppc64_elf_copy_indirect_symbol (info, opt, tga); - opt->forced_local = 0; + opt->mark = 1; _bfd_elf_link_hash_hide_symbol (info, opt, tga->forced_local); htab->tls_get_addr = (struct ppc_link_hash_entry *) opt; @@ -8524,7 +8611,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) case R_PPC64_GOT_TLSLD16_LO: expecting_tls_get_addr = 1; found_tls_get_addr_arg = 1; - /* Fall thru */ + /* Fall through. */ case R_PPC64_GOT_TLSLD16_HI: case R_PPC64_GOT_TLSLD16_HA: @@ -8544,7 +8631,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) case R_PPC64_GOT_TLSGD16_LO: expecting_tls_get_addr = 1; found_tls_get_addr_arg = 1; - /* Fall thru */ + /* Fall through. */ case R_PPC64_GOT_TLSGD16_HI: case R_PPC64_GOT_TLSGD16_HA: @@ -8575,7 +8662,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) case R_PPC64_TLSGD: case R_PPC64_TLSLD: found_tls_get_addr_arg = 1; - /* Fall thru */ + /* Fall through. */ case R_PPC64_TLS: case R_PPC64_TOC16: @@ -8707,6 +8794,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) could just mark this symbol to exclude it from tls optimization but it's safer to skip the entire optimization. */ + /* xgettext:c-format */ info->callbacks->minfo (_("%H arg lost __tls_get_addr, " "TLS optimization disabled\n"), ibfd, sec, rel->r_offset); @@ -8816,7 +8904,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) the values of any global symbols in a toc section that has been edited. Globals in toc sections should be a rarity, so this function sets a flag if any are found in toc sections other than the one just - edited, so that futher hash table traversals can be avoided. */ + edited, so that further hash table traversals can be avoided. */ struct adjust_toc_info { @@ -8868,12 +8956,14 @@ adjust_toc_syms (struct elf_link_hash_entry *h, void *inf) return TRUE; } -/* Return TRUE iff INSN is one we expect on a _LO variety toc/got reloc. */ +/* Return TRUE iff INSN with a relocation of R_TYPE is one we expect + on a _LO variety toc/got reloc. */ static bfd_boolean -ok_lo_toc_insn (unsigned int insn) +ok_lo_toc_insn (unsigned int insn, enum elf_ppc64_reloc_type r_type) { - return ((insn & (0x3f << 26)) == 14u << 26 /* addi */ + return ((insn & (0x3f << 26)) == 12u << 26 /* addic */ + || (insn & (0x3f << 26)) == 14u << 26 /* addi */ || (insn & (0x3f << 26)) == 32u << 26 /* lwz */ || (insn & (0x3f << 26)) == 34u << 26 /* lbz */ || (insn & (0x3f << 26)) == 36u << 26 /* stw */ @@ -8887,11 +8977,20 @@ ok_lo_toc_insn (unsigned int insn) || (insn & (0x3f << 26)) == 50u << 26 /* lfd */ || (insn & (0x3f << 26)) == 52u << 26 /* stfs */ || (insn & (0x3f << 26)) == 54u << 26 /* stfd */ - || ((insn & (0x3f << 26)) == 58u << 26 /* lwa,ld,lmd */ - && (insn & 3) != 1) - || ((insn & (0x3f << 26)) == 62u << 26 /* std, stmd */ - && ((insn & 3) == 0 || (insn & 3) == 3)) - || (insn & (0x3f << 26)) == 12u << 26 /* addic */); + || (insn & (0x3f << 26)) == 56u << 26 /* lq,lfq */ + || ((insn & (0x3f << 26)) == 57u << 26 /* lxsd,lxssp,lfdp */ + /* Exclude lfqu by testing reloc. If relocs are ever + defined for the reduced D field in psq_lu then those + will need testing too. */ + && r_type != R_PPC64_TOC16_LO && r_type != R_PPC64_GOT16_LO) + || ((insn & (0x3f << 26)) == 58u << 26 /* ld,lwa */ + && (insn & 1) == 0) + || (insn & (0x3f << 26)) == 60u << 26 /* stfq */ + || ((insn & (0x3f << 26)) == 61u << 26 /* lxv,stx{v,sd,ssp},stfdp */ + /* Exclude stfqu. psq_stu as above for psq_lu. */ + && r_type != R_PPC64_TOC16_LO && r_type != R_PPC64_GOT16_LO) + || ((insn & (0x3f << 26)) == 62u << 26 /* std,stq */ + && (insn & 1) == 0)); } /* Examine all relocs referencing .toc sections in order to remove @@ -9196,7 +9295,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) } insn = bfd_get_32 (ibfd, buf); if (insn_check == check_lo - ? !ok_lo_toc_insn (insn) + ? !ok_lo_toc_insn (insn, r_type) : ((insn & ((0x3f << 26) | 0x1f << 16)) != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */)) { @@ -9205,7 +9304,8 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) ppc64_elf_tdata (ibfd)->unexpected_toc_insn = 1; sprintf (str, "%#08x", insn); info->callbacks->einfo - (_("%P: %H: toc optimization is not supported for" + /* xgettext:c-format */ + (_("%H: toc optimization is not supported for" " %s instruction.\n"), ibfd, sec, rel->r_offset & ~3, str); } @@ -9268,7 +9368,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) } if ((opc & (0x3f << 2)) == (58u << 2)) break; - /* Fall thru */ + /* Fall through. */ default: /* Wrong sort of reloc, or not a ld. We may @@ -9300,7 +9400,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) /* Merge the used and skip arrays. Assume that TOC doublewords not appearing as either used or unused belong - to to an entry more than one doubleword in size. */ + to an entry more than one doubleword in size. */ for (drop = skip, keep = used, last = 0, some_unused = 0; drop < skip + (toc->size + 7) / 8; ++drop, ++keep) @@ -9433,7 +9533,8 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) if (!ppc64_elf_howto_table[R_PPC64_ADDR32]) ppc_howto_init (); info->callbacks->einfo - (_("%P: %H: %s references " + /* xgettext:c-format */ + (_("%H: %s references " "optimized away TOC entry\n"), ibfd, sec, rel->r_offset, ppc64_elf_howto_table[r_type]->name); @@ -9568,7 +9669,6 @@ allocate_got (struct elf_link_hash_entry *h, struct got_entry *gent) { struct ppc_link_hash_table *htab = ppc_hash_table (info); - bfd_boolean dyn; struct ppc_link_hash_entry *eh = (struct ppc_link_hash_entry *) h; int entsize = (gent->tls_type & eh->tls_mask & (TLS_GD | TLS_LD) ? 16 : 8); @@ -9579,16 +9679,16 @@ allocate_got (struct elf_link_hash_entry *h, gent->got.offset = got->size; got->size += entsize; - dyn = htab->elf.dynamic_sections_created; if (h->type == STT_GNU_IFUNC) { htab->elf.irelplt->size += rentsize; htab->got_reli_size += rentsize; } else if ((bfd_link_pic (info) - || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)) - && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - || h->root.type != bfd_link_hash_undefweak)) + || (htab->elf.dynamic_sections_created + && h->dynindx != -1 + && !SYMBOL_REFERENCES_LOCAL (info, h))) + && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)) { asection *relgot = ppc64_elf_tdata (gent->owner)->relgot; relgot->size += rentsize; @@ -9615,6 +9715,24 @@ merge_got_entries (struct got_entry **pent) } } +/* If H is undefined weak, make it dynamic if that makes sense. */ + +static bfd_boolean +ensure_undefweak_dynamic (struct bfd_link_info *info, + struct elf_link_hash_entry *h) +{ + struct elf_link_hash_table *htab = elf_hash_table (info); + + if (htab->dynamic_sections_created + && info->dynamic_undefined_weak != 0 + && h->root.type == bfd_link_hash_undefweak + && h->dynindx == -1 + && !h->forced_local + && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT) + return bfd_elf_link_record_dynamic_symbol (info, h); + return TRUE; +} + /* Allocate space in .plt, .got and associated reloc sections for dynamic relocs. */ @@ -9687,16 +9805,9 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) if (!gent->is_indirect) { /* Make sure this symbol is output as a dynamic symbol. - Undefined weak syms won't yet be marked as dynamic, - nor will all TLS symbols. */ - if (h->dynindx == -1 - && !h->forced_local - && h->type != STT_GNU_IFUNC - && htab->elf.dynamic_sections_created) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } + Undefined weak syms won't yet be marked as dynamic. */ + if (!ensure_undefweak_dynamic (info, h)) + return FALSE; if (!is_ppc64_elf (gent->owner)) abort (); @@ -9704,10 +9815,17 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) allocate_got (h, info, gent); } + /* If no dynamic sections we can't have dynamic relocs, except for + IFUNCs which are handled even in static executables. */ if (!htab->elf.dynamic_sections_created && h->type != STT_GNU_IFUNC) eh->dyn_relocs = NULL; + /* Also discard relocs on undefined weak syms with non-default + visibility, or when dynamic_undefined_weak says so. */ + else if (UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)) + eh->dyn_relocs = NULL; + if (eh->dyn_relocs != NULL) { struct elf_dyn_relocs *p, **pp; @@ -9740,22 +9858,12 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) } } - /* Also discard relocs on undefined weak syms with - non-default visibility. */ - if (eh->dyn_relocs != NULL - && h->root.type == bfd_link_hash_undefweak) + if (eh->dyn_relocs != NULL) { - if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) - eh->dyn_relocs = NULL; - /* Make sure this symbol is output as a dynamic symbol. Undefined weak syms won't yet be marked as dynamic. */ - else if (h->dynindx == -1 - && !h->forced_local) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } + if (!ensure_undefweak_dynamic (info, h)) + return FALSE; } } else if (h->type == STT_GNU_IFUNC) @@ -9786,20 +9894,18 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) /* For the non-pic case, discard space for relocs against symbols which turn out to need copy relocs or are not dynamic. */ + if (!h->non_got_ref + && !h->def_regular) + { + /* Make sure this symbol is output as a dynamic symbol. + Undefined weak syms won't yet be marked as dynamic. */ + if (!ensure_undefweak_dynamic (info, h)) + return FALSE; - /* First make sure this symbol is output as a dynamic symbol. - Undefined weak syms won't yet be marked as dynamic. */ - if (h->root.type == bfd_link_hash_undefweak - && !h->non_got_ref - && !h->def_regular - && h->dynindx == -1 - && !h->forced_local - && !bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - - if (h->non_got_ref - || h->def_regular - || h->dynindx == -1) + if (h->dynindx == -1) + eh->dyn_relocs = NULL; + } + else eh->dyn_relocs = NULL; } @@ -9814,8 +9920,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) } if ((htab->elf.dynamic_sections_created - && h->dynindx != -1 - && WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), h)) + && h->dynindx != -1) || h->type == STT_GNU_IFUNC) { struct plt_entry *pent; @@ -10152,7 +10257,8 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd, || s == htab->elf.splt || s == htab->elf.iplt || s == htab->glink - || s == htab->dynbss) + || s == htab->elf.sdynbss + || s == htab->elf.sdynrelro) { /* Strip this section if we don't need it; see the comment below. */ @@ -10205,7 +10311,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd, but this way if it does we get a R_PPC64_NONE reloc in .rela sections instead of garbage. We also rely on the section contents being zero when writing - the GOT. */ + the GOT and .dynrelro. */ s->contents = bfd_zalloc (dynobj, s->size); if (s->contents == NULL) return FALSE; @@ -10465,7 +10571,12 @@ plt_stub_size (struct ppc_link_hash_table *htab, && (stub_entry->h == htab->tls_get_addr_fd || stub_entry->h == htab->tls_get_addr) && htab->params->tls_get_addr_opt) - size += 13 * 4; + { + size += 7 * 4; + if (ALWAYS_EMIT_R2SAVE + || stub_entry->stub_type == ppc_stub_plt_call_r2save) + size += 6 * 4; + } return size; } @@ -10692,11 +10803,17 @@ build_tls_get_addr_stub (struct ppc_link_hash_table *htab, bfd_put_32 (obfd, ADD_R3_R12_R13, p), p += 4; bfd_put_32 (obfd, BEQLR, p), p += 4; bfd_put_32 (obfd, MR_R3_R0, p), p += 4; + if (r != NULL) + r[0].r_offset += 7 * 4; + if (!ALWAYS_EMIT_R2SAVE + && stub_entry->stub_type != ppc_stub_plt_call_r2save) + return build_plt_stub (htab, stub_entry, p, offset, r); + bfd_put_32 (obfd, MFLR_R11, p), p += 4; bfd_put_32 (obfd, STD_R11_0R1 + STK_LINKER (htab), p), p += 4; if (r != NULL) - r[0].r_offset += 9 * 4; + r[0].r_offset += 2 * 4; p = build_plt_stub (htab, stub_entry, p, offset, r); bfd_put_32 (obfd, BCTRL, p - 4); @@ -11074,10 +11191,10 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) /* If the old-ABI "dot-symbol" is undefined make it weak so we don't get a link error from RELOC_FOR_GLOBAL_SYMBOL. */ - if (fh->elf.root.type == bfd_link_hash_undefined) + if (fh->elf.root.type == bfd_link_hash_undefined + && (stub_entry->h->elf.root.type == bfd_link_hash_defined + || stub_entry->h->elf.root.type == bfd_link_hash_defweak)) fh->elf.root.type = bfd_link_hash_undefweak; - /* Stop undo_symbol_twiddle changing it back to undefined. */ - fh->was_undefined = 0; } /* Now build the stub. */ @@ -11113,6 +11230,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) * sizeof (Elf64_External_Rela))); bfd_elf64_swap_reloca_out (info->output_bfd, &rela, rl); stub_entry->plt_ent->plt.offset |= 1; + htab->local_ifunc_resolver = 1; } off = (dest @@ -11122,6 +11240,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) if (off + 0x80008000 > 0xffffffff || (off & 7) != 0) { info->callbacks->einfo + /* xgettext:c-format */ (_("%P: linkage table error against `%T'\n"), stub_entry->h != NULL ? stub_entry->h->elf.root.root.string @@ -12104,6 +12223,7 @@ group_sections (struct bfd_link_info *info, big_sec = total > group_size; if (big_sec && !suppress_size_errors) + /* xgettext:c-format */ _bfd_error_handler (_("%B section %A exceeds stub group size"), tail->owner, tail); curr_toc = htab->sec_info[tail->id].toc_off; @@ -12179,8 +12299,7 @@ static const unsigned char glink_eh_frame_cie[] = 65, /* RA reg. */ 1, /* Augmentation size. */ DW_EH_PE_pcrel | DW_EH_PE_sdata4, /* FDE encoding. */ - DW_CFA_def_cfa, 1, 0, /* def_cfa: r1 offset 0. */ - 0, 0, 0, 0 + DW_CFA_def_cfa, 1, 0 /* def_cfa: r1 offset 0. */ }; /* Stripping output sections is normally done before dynamic section @@ -12404,8 +12523,9 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) use the func descriptor sym instead if it is defined. */ if (hash->elf.root.root.string[0] == '.' - && (fdh = lookup_fdh (hash, htab)) != NULL) + && hash->oh != NULL) { + fdh = ppc_follow_link (hash->oh); if (fdh->elf.root.type == bfd_link_hash_defined || fdh->elf.root.type == bfd_link_hash_defweak) { @@ -12512,17 +12632,24 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) continue; } - if (stub_type == ppc_stub_plt_call - && irela + 1 < irelaend - && irela[1].r_offset == irela->r_offset + 4 - && ELF64_R_TYPE (irela[1].r_info) == R_PPC64_TOCSAVE) + if (stub_type == ppc_stub_plt_call) { - if (!tocsave_find (htab, INSERT, - &local_syms, irela + 1, input_bfd)) - goto error_ret_free_internal; + if (!htab->opd_abi + && htab->params->plt_localentry0 != 0 + && is_elfv2_localentry0 (&hash->elf)) + htab->has_plt_localentry0 = 1; + else if (irela + 1 < irelaend + && irela[1].r_offset == irela->r_offset + 4 + && (ELF64_R_TYPE (irela[1].r_info) + == R_PPC64_TOCSAVE)) + { + if (!tocsave_find (htab, INSERT, + &local_syms, irela + 1, input_bfd)) + goto error_ret_free_internal; + } + else + stub_type = ppc_stub_plt_call_r2save; } - else if (stub_type == ppc_stub_plt_call) - stub_type = ppc_stub_plt_call_r2save; /* Support for grouping stub sections. */ id_sec = htab->sec_info[section->id].u.group->link_sec; @@ -12600,7 +12727,10 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) stub_sec = stub_sec->next) if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) { - stub_sec->rawsize = stub_sec->size; + if (htab->stub_iteration <= STUB_SHRINK_ITER + || stub_sec->rawsize < stub_sec->size) + /* Past STUB_SHRINK_ITER, rawsize is the max size seen. */ + stub_sec->rawsize = stub_sec->size; stub_sec->size = 0; stub_sec->reloc_count = 0; stub_sec->flags &= ~SEC_RELOC; @@ -12629,21 +12759,19 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) && !bfd_is_abs_section (htab->glink_eh_frame->output_section) && htab->glink_eh_frame->output_section->size != 0) { - size_t size = 0, align; + size_t size = 0, align = 4; for (stub_sec = htab->params->stub_bfd->sections; stub_sec != NULL; stub_sec = stub_sec->next) if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) - size += 24; + size += (17 + align - 1) & -align; if (htab->glink != NULL && htab->glink->size != 0) - size += 24; + size += (24 + align - 1) & -align; if (size != 0) - size += sizeof (glink_eh_frame_cie); - align = 1; - align <<= htab->glink_eh_frame->output_section->alignment_power; - align -= 1; - size = (size + align) & ~align; + size += (sizeof (glink_eh_frame_cie) + align - 1) & -align; + align = 1ul << htab->glink_eh_frame->output_section->alignment_power; + size = (size + align - 1) & -align; htab->glink_eh_frame->rawsize = htab->glink_eh_frame->size; htab->glink_eh_frame->size = size; } @@ -12688,12 +12816,13 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) return FALSE; htab->glink_eh_frame->contents = p; last_fde = p; + align = 4; memcpy (p, glink_eh_frame_cie, sizeof (glink_eh_frame_cie)); /* CIE length (rewrite in case little-endian). */ - last_fde_len = sizeof (glink_eh_frame_cie) - 4; + last_fde_len = ((sizeof (glink_eh_frame_cie) + align - 1) & -align) - 4; bfd_put_32 (htab->elf.dynobj, last_fde_len, p); - p += sizeof (glink_eh_frame_cie); + p += last_fde_len + 4; for (stub_sec = htab->params->stub_bfd->sections; stub_sec != NULL; @@ -12701,9 +12830,9 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) { last_fde = p; - last_fde_len = 20; + last_fde_len = ((17 + align - 1) & -align) - 4; /* FDE length. */ - bfd_put_32 (htab->elf.dynobj, 20, p); + bfd_put_32 (htab->elf.dynobj, last_fde_len, p); p += 4; /* CIE pointer. */ val = p - htab->glink_eh_frame->contents; @@ -12717,14 +12846,14 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) /* Augmentation. */ p += 1; /* Pad. */ - p += 7; + p += ((17 + align - 1) & -align) - 17; } if (htab->glink != NULL && htab->glink->size != 0) { last_fde = p; - last_fde_len = 20; + last_fde_len = ((24 + align - 1) & -align) - 4; /* FDE length. */ - bfd_put_32 (htab->elf.dynobj, 20, p); + bfd_put_32 (htab->elf.dynobj, last_fde_len, p); p += 4; /* CIE pointer. */ val = p - htab->glink_eh_frame->contents; @@ -12742,18 +12871,17 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) *p++ = DW_CFA_register; *p++ = 65; *p++ = htab->opd_abi ? 12 : 0; - *p++ = DW_CFA_advance_loc + 4; + *p++ = DW_CFA_advance_loc + (htab->opd_abi ? 5 : 7); *p++ = DW_CFA_restore_extended; *p++ = 65; + p += ((24 + align - 1) & -align) - 24; } /* Subsume any padding into the last FDE if user .eh_frame sections are aligned more than glink_eh_frame. Otherwise any zero padding will be seen as a terminator. */ + align = 1ul << htab->glink_eh_frame->output_section->alignment_power; size = p - htab->glink_eh_frame->contents; - align = 1; - align <<= htab->glink_eh_frame->output_section->alignment_power; - align -= 1; - pad = ((size + align) & ~align) - size; + pad = ((size + align - 1) & -align) - size; htab->glink_eh_frame->size = size + pad; bfd_put_32 (htab->elf.dynobj, last_fde_len + pad, last_fde); } @@ -13073,6 +13201,8 @@ ppc64_elf_build_stubs (struct bfd_link_info *info, p += 4; bfd_put_32 (htab->glink->owner, MFLR_R11, p); p += 4; + bfd_put_32 (htab->glink->owner, STD_R2_0R1 + 24, p); + p += 4; bfd_put_32 (htab->glink->owner, LD_R2_0R11 | (-16 & 0xfffc), p); p += 4; bfd_put_32 (htab->glink->owner, MTLR_R0, p); @@ -13231,33 +13361,6 @@ ppc64_elf_build_stubs (struct bfd_link_info *info, return TRUE; } -/* This function undoes the changes made by add_symbol_adjust. */ - -static bfd_boolean -undo_symbol_twiddle (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED) -{ - struct ppc_link_hash_entry *eh; - - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - eh = (struct ppc_link_hash_entry *) h; - if (eh->elf.root.type != bfd_link_hash_undefweak || !eh->was_undefined) - return TRUE; - - eh->elf.root.type = bfd_link_hash_undefined; - return TRUE; -} - -void -ppc64_elf_restore_symbols (struct bfd_link_info *info) -{ - struct ppc_link_hash_table *htab = ppc_hash_table (info); - - if (htab != NULL) - elf_link_hash_traverse (&htab->elf, undo_symbol_twiddle, info); -} - /* What to do when ld finds relocations against symbols defined in discarded sections. */ @@ -13329,7 +13432,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, bfd_boolean is_opd; /* Assume 'at' branch hints. */ bfd_boolean is_isa_v2 = TRUE; - bfd_vma d_offset = (bfd_big_endian (output_bfd) ? 2 : 0); + bfd_vma d_offset = (bfd_big_endian (input_bfd) ? 2 : 0); /* Initialize howto table if needed. */ if (!ppc64_elf_howto_table[R_PPC64_ADDR32]) @@ -13558,8 +13661,10 @@ ppc64_elf_relocate_section (bfd *output_bfd, else info->callbacks->einfo (!IS_PPC64_TLS_RELOC (r_type) - ? _("%P: %H: %s used with TLS symbol `%T'\n") - : _("%P: %H: %s used with non-TLS symbol `%T'\n"), + /* xgettext:c-format */ + ? _("%H: %s used with TLS symbol `%T'\n") + /* xgettext:c-format */ + : _("%H: %s used with non-TLS symbol `%T'\n"), input_bfd, input_section, rel->r_offset, ppc64_elf_howto_table[r_type]->name, sym_name); @@ -13584,11 +13689,11 @@ ppc64_elf_relocate_section (bfd *output_bfd, break; case R_PPC64_LO_DS_OPT: - insn = bfd_get_32 (output_bfd, contents + rel->r_offset - d_offset); + insn = bfd_get_32 (input_bfd, contents + rel->r_offset - d_offset); if ((insn & (0x3f << 26)) != 58u << 26) abort (); insn += (14u << 26) - (58u << 26); - bfd_put_32 (output_bfd, insn, contents + rel->r_offset - d_offset); + bfd_put_32 (input_bfd, insn, contents + rel->r_offset - d_offset); r_type = R_PPC64_TOC16_LO; rel->r_info = ELF64_R_INFO (r_symndx, r_type); break; @@ -13643,7 +13748,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, && (tls_mask & TLS_TPREL) == 0) { rel->r_offset -= d_offset; - bfd_put_32 (output_bfd, NOP, contents + rel->r_offset); + bfd_put_32 (input_bfd, NOP, contents + rel->r_offset); r_type = R_PPC64_NONE; rel->r_info = ELF64_R_INFO (r_symndx, r_type); } @@ -13655,11 +13760,11 @@ ppc64_elf_relocate_section (bfd *output_bfd, && (tls_mask & TLS_TPREL) == 0) { toctprel: - insn = bfd_get_32 (output_bfd, + insn = bfd_get_32 (input_bfd, contents + rel->r_offset - d_offset); insn &= 31 << 21; insn |= 0x3c0d0000; /* addis 0,13,0 */ - bfd_put_32 (output_bfd, insn, + bfd_put_32 (input_bfd, insn, contents + rel->r_offset - d_offset); r_type = R_PPC64_TPREL16_HA; if (toc_symndx != 0) @@ -13679,11 +13784,11 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (tls_mask != 0 && (tls_mask & TLS_TPREL) == 0) { - insn = bfd_get_32 (output_bfd, contents + rel->r_offset); + insn = bfd_get_32 (input_bfd, contents + rel->r_offset); insn = _bfd_elf_ppc_at_tls_transform (insn, 13); if (insn == 0) abort (); - bfd_put_32 (output_bfd, insn, contents + rel->r_offset); + bfd_put_32 (input_bfd, insn, contents + rel->r_offset); /* Was PPC64_TLS which sits on insn boundary, now PPC64_TPREL16_LO which is at low-order half-word. */ rel->r_offset += d_offset; @@ -13719,7 +13824,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, else { rel->r_offset -= d_offset; - bfd_put_32 (output_bfd, NOP, contents + rel->r_offset); + bfd_put_32 (input_bfd, NOP, contents + rel->r_offset); r_type = R_PPC64_NONE; } rel->r_info = ELF64_R_INFO (r_symndx, r_type); @@ -13757,7 +13862,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, need to keep the destination reg. It may be something other than the usual r3, and moved to r3 before the call by intervening code. */ - insn1 = bfd_get_32 (output_bfd, + insn1 = bfd_get_32 (input_bfd, contents + rel->r_offset - d_offset); if ((tls_mask & tls_gd) != 0) { @@ -13813,20 +13918,20 @@ ppc64_elf_relocate_section (bfd *output_bfd, rel[1].r_addend = rel->r_addend; } } - bfd_put_32 (output_bfd, insn1, + bfd_put_32 (input_bfd, insn1, contents + rel->r_offset - d_offset); if (offset != (bfd_vma) -1) { - insn3 = bfd_get_32 (output_bfd, + insn3 = bfd_get_32 (input_bfd, contents + offset + 4); if (insn3 == NOP || insn3 == CROR_151515 || insn3 == CROR_313131) { rel[1].r_offset += 4; - bfd_put_32 (output_bfd, insn2, contents + offset + 4); + bfd_put_32 (input_bfd, insn2, contents + offset + 4); insn2 = NOP; } - bfd_put_32 (output_bfd, insn2, contents + offset); + bfd_put_32 (input_bfd, insn2, contents + offset); } if ((tls_mask & tls_gd) == 0 && (tls_gd == 0 || toc_symndx != 0)) @@ -13866,16 +13971,16 @@ ppc64_elf_relocate_section (bfd *output_bfd, /* Zap the reloc on the _tls_get_addr call too. */ BFD_ASSERT (offset == rel[1].r_offset); rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE); - insn3 = bfd_get_32 (output_bfd, + insn3 = bfd_get_32 (input_bfd, contents + offset + 4); if (insn3 == NOP || insn3 == CROR_151515 || insn3 == CROR_313131) { rel->r_offset += 4; - bfd_put_32 (output_bfd, insn2, contents + offset + 4); + bfd_put_32 (input_bfd, insn2, contents + offset + 4); insn2 = NOP; } - bfd_put_32 (output_bfd, insn2, contents + offset); + bfd_put_32 (input_bfd, insn2, contents + offset); if ((tls_mask & TLS_TPRELGD) == 0 && toc_symndx != 0) goto again; } @@ -13909,16 +14014,16 @@ ppc64_elf_relocate_section (bfd *output_bfd, BFD_ASSERT (offset == rel[1].r_offset); rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE); insn2 = 0x38630000; /* addi 3,3,0 */ - insn3 = bfd_get_32 (output_bfd, + insn3 = bfd_get_32 (input_bfd, contents + offset + 4); if (insn3 == NOP || insn3 == CROR_151515 || insn3 == CROR_313131) { rel->r_offset += 4; - bfd_put_32 (output_bfd, insn2, contents + offset + 4); + bfd_put_32 (input_bfd, insn2, contents + offset + 4); insn2 = NOP; } - bfd_put_32 (output_bfd, insn2, contents + offset); + bfd_put_32 (input_bfd, insn2, contents + offset); goto again; } break; @@ -13973,10 +14078,10 @@ ppc64_elf_relocate_section (bfd *output_bfd, if ((insn1 & ~0xfffc) == LD_R2_0R12 && insn2 == ADD_R2_R2_R12) { - bfd_put_32 (output_bfd, + bfd_put_32 (input_bfd, LIS_R2 + PPC_HA (relocation), contents + rel->r_offset); - bfd_put_32 (output_bfd, + bfd_put_32 (input_bfd, ADDI_R2_R2 + PPC_LO (relocation), contents + rel->r_offset + 4); } @@ -13995,10 +14100,10 @@ ppc64_elf_relocate_section (bfd *output_bfd, if ((insn1 & ~0xfffc) == LD_R2_0R12 && insn2 == ADD_R2_R2_R12) { - bfd_put_32 (output_bfd, + bfd_put_32 (input_bfd, ADDIS_R2_R12 + PPC_HA (relocation), contents + rel->r_offset); - bfd_put_32 (output_bfd, + bfd_put_32 (input_bfd, ADDI_R2_R2 + PPC_LO (relocation), contents + rel->r_offset + 4); } @@ -14027,8 +14132,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, { unsigned int insn1, insn2; bfd_vma offset = rel->r_offset - d_offset; - insn1 = bfd_get_32 (output_bfd, contents + offset); - insn2 = bfd_get_32 (output_bfd, contents + offset + 4); + insn1 = bfd_get_32 (input_bfd, contents + offset); + insn2 = bfd_get_32 (input_bfd, contents + offset + 4); if ((insn1 & 0xffff0000) == ADDIS_R2_R12 && (insn2 & 0xffff0000) == ADDI_R2_R2) { @@ -14037,7 +14142,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, rel->r_addend -= d_offset; rel[1].r_info = ELF64_R_INFO (r_symndx, R_PPC64_ADDR16_LO); rel[1].r_addend -= d_offset + 4; - bfd_put_32 (output_bfd, LIS_R2, contents + offset); + bfd_put_32 (input_bfd, LIS_R2, contents + offset); } } break; @@ -14073,18 +14178,18 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_ADDR14_BRTAKEN: case R_PPC64_REL14_BRTAKEN: insn = 0x01 << 21; /* 'y' or 't' bit, lowest bit of BO field. */ - /* Fall thru. */ + /* Fall through. */ /* Branch not taken prediction relocations. */ case R_PPC64_ADDR14_BRNTAKEN: case R_PPC64_REL14_BRNTAKEN: - insn |= bfd_get_32 (output_bfd, + insn |= bfd_get_32 (input_bfd, contents + rel->r_offset) & ~(0x01 << 21); - /* Fall thru. */ + /* Fall through. */ case R_PPC64_REL14: max_br_offset = 1 << 15; - /* Fall thru. */ + /* Fall through. */ case R_PPC64_REL24: /* Calls to functions with a different TOC, such as calls to @@ -14108,10 +14213,19 @@ ppc64_elf_relocate_section (bfd *output_bfd, { bfd_boolean can_plt_call = FALSE; - /* All of these stubs will modify r2, so there must be a + if (stub_entry->stub_type == ppc_stub_plt_call + && !htab->opd_abi + && htab->params->plt_localentry0 != 0 + && is_elfv2_localentry0 (&h->elf)) + { + /* The function doesn't use or change r2. */ + can_plt_call = TRUE; + } + + /* All of these stubs may modify r2, so there must be a branch and link followed by a nop. The nop is replaced by an insn to restore r2. */ - if (rel->r_offset + 8 <= input_section->size) + else if (rel->r_offset + 8 <= input_section->size) { unsigned long br; @@ -14188,12 +14302,14 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (stub_entry->stub_type == ppc_stub_plt_call || stub_entry->stub_type == ppc_stub_plt_call_r2save) info->callbacks->einfo - (_("%P: %H: call to `%T' lacks nop, can't restore toc; " + /* xgettext:c-format */ + (_("%H: call to `%T' lacks nop, can't restore toc; " "recompile with -fPIC\n"), input_bfd, input_section, rel->r_offset, sym_name); else info->callbacks->einfo - (_("%P: %H: call to `%T' lacks nop, can't restore toc; " + /* xgettext:c-format */ + (_("%H: call to `%T' lacks nop, can't restore toc; " "(-mcmodel=small toc adjust stub)\n"), input_bfd, input_section, rel->r_offset, sym_name); @@ -14264,7 +14380,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, addend = 0; reloc_dest = DEST_STUB; - if ((stub_entry->stub_type == ppc_stub_plt_call + if ((stub_entry->stub_type == ppc_stub_plt_call || stub_entry->stub_type == ppc_stub_plt_call_r2save) && (ALWAYS_EMIT_R2SAVE || stub_entry->stub_type == ppc_stub_plt_call_r2save) @@ -14295,7 +14411,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, insn ^= 0x01 << 21; } - bfd_put_32 (output_bfd, insn, contents + rel->r_offset); + bfd_put_32 (input_bfd, insn, contents + rel->r_offset); } /* NOP out calls to undefined weak functions. @@ -14308,7 +14424,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, && relocation == 0 && addend == 0) { - bfd_put_32 (output_bfd, NOP, contents + rel->r_offset); + bfd_put_32 (input_bfd, NOP, contents + rel->r_offset); goto copy_reloc; } break; @@ -14320,6 +14436,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, { default: info->callbacks->einfo + /* xgettext:c-format */ (_("%P: %B: unknown relocation type %d for `%T'\n"), input_bfd, (int) r_type, sym_name); @@ -14391,14 +14508,12 @@ ppc64_elf_relocate_section (bfd *output_bfd, ent = ppc64_tlsld_got (input_bfd); else { - if (h != NULL) { - bfd_boolean dyn = htab->elf.dynamic_sections_created; - if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), - &h->elf) - || (bfd_link_pic (info) - && SYMBOL_REFERENCES_LOCAL (info, &h->elf))) + if (!htab->elf.dynamic_sections_created + || h->elf.dynindx == -1 + || SYMBOL_REFERENCES_LOCAL (info, &h->elf) + || UNDEFWEAK_NO_DYNAMIC_RELOC (info, &h->elf)) /* This is actually a static link, or it is a -Bsymbolic link and the symbol is defined locally, or the symbol was forced to be local @@ -14406,7 +14521,6 @@ ppc64_elf_relocate_section (bfd *output_bfd, ; else { - BFD_ASSERT (h->elf.dynindx != -1); indx = h->elf.dynindx; unresolved_reloc = FALSE; } @@ -14455,13 +14569,19 @@ ppc64_elf_relocate_section (bfd *output_bfd, ? h->elf.type == STT_GNU_IFUNC : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC); if (ifunc) - relgot = htab->elf.irelplt; - else if ((bfd_link_pic (info) || indx != 0) - && (h == NULL - || (tls_type == (TLS_TLS | TLS_LD) - && !h->elf.def_dynamic) - || ELF_ST_VISIBILITY (h->elf.other) == STV_DEFAULT - || h->elf.root.type != bfd_link_hash_undefweak)) + { + relgot = htab->elf.irelplt; + if (indx == 0) + htab->local_ifunc_resolver = 1; + else if (is_static_defined (&h->elf)) + htab->maybe_local_ifunc_resolver = 1; + } + else if (indx != 0 + || (bfd_link_pic (info) + && (h == NULL + || !UNDEFWEAK_NO_DYNAMIC_RELOC (info, &h->elf) + || (tls_type == (TLS_TLS | TLS_LD) + && !h->elf.def_dynamic)))) relgot = ppc64_elf_tdata (ent->owner)->relgot; if (relgot != NULL) { @@ -14528,27 +14648,27 @@ ppc64_elf_relocate_section (bfd *output_bfd, else { relocation += addend; - if (tls_type == (TLS_TLS | TLS_LD)) - relocation = 1; - else if (tls_type != 0) + if (tls_type != 0) { if (htab->elf.tls_sec == NULL) relocation = 0; else { - relocation -= htab->elf.tls_sec->vma + DTP_OFFSET; - if (tls_type == (TLS_TLS | TLS_TPREL)) + if (tls_type & TLS_LD) + relocation = 0; + else + relocation -= htab->elf.tls_sec->vma + DTP_OFFSET; + if (tls_type & TLS_TPREL) relocation += DTP_OFFSET - TP_OFFSET; } - if (tls_type == (TLS_TLS | TLS_GD)) + if (tls_type & (TLS_GD | TLS_LD)) { bfd_put_64 (output_bfd, relocation, got->contents + off + 8); relocation = 1; } } - bfd_put_64 (output_bfd, relocation, got->contents + off); } @@ -14680,10 +14800,10 @@ ppc64_elf_relocate_section (bfd *output_bfd, defined before using them. */ bfd_byte *p = contents + rel->r_offset - d_offset; - insn = bfd_get_32 (output_bfd, p); + insn = bfd_get_32 (input_bfd, p); insn = _bfd_elf_ppc_at_tprel_transform (insn, 13); if (insn != 0) - bfd_put_32 (output_bfd, insn, p); + bfd_put_32 (input_bfd, insn, p); break; } if (htab->elf.tls_sec != NULL) @@ -14730,7 +14850,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_DTPREL64: if (htab->elf.tls_sec != NULL) addend -= htab->elf.tls_sec->vma + DTP_OFFSET; - /* Fall thru */ + /* Fall through. */ /* Relocations that may need to be propagated if this is a dynamic object. */ @@ -14766,8 +14886,10 @@ ppc64_elf_relocate_section (bfd *output_bfd, break; if (bfd_link_pic (info) - ? ((h != NULL && pc_dynrelocs (h)) - || must_be_dyn_reloc (info, r_type)) + ? ((h == NULL + || h->dyn_relocs != NULL) + && ((h != NULL && pc_dynrelocs (h)) + || must_be_dyn_reloc (info, r_type))) : (h != NULL ? h->dyn_relocs != NULL : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)) @@ -14775,6 +14897,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, bfd_boolean skip, relocate; asection *sreloc; bfd_vma out_off; + long indx = 0; /* When generating a dynamic object, these relocations are copied into the output file to be resolved at run @@ -14811,8 +14934,9 @@ ppc64_elf_relocate_section (bfd *output_bfd, && !is_opd && r_type != R_PPC64_TOC) { - BFD_ASSERT (h->elf.dynindx != -1); - outrel.r_info = ELF64_R_INFO (h->elf.dynindx, r_type); + indx = h->elf.dynindx; + BFD_ASSERT (indx != -1); + outrel.r_info = ELF64_R_INFO (indx, r_type); } else { @@ -14855,14 +14979,13 @@ ppc64_elf_relocate_section (bfd *output_bfd, } else { - long indx = 0; - if (h != NULL ? h->elf.type == STT_GNU_IFUNC : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC) { info->callbacks->einfo - (_("%P: %H: %s for indirect " + /* xgettext:c-format */ + (_("%H: %s for indirect " "function `%T' unsupported\n"), input_bfd, input_section, rel->r_offset, ppc64_elf_howto_table[r_type]->name, @@ -14910,7 +15033,13 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (h != NULL ? h->elf.type == STT_GNU_IFUNC : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC) - sreloc = htab->elf.irelplt; + { + sreloc = htab->elf.irelplt; + if (indx == 0) + htab->local_ifunc_resolver = 1; + else if (is_static_defined (&h->elf)) + htab->maybe_local_ifunc_resolver = 1; + } if (sreloc == NULL) abort (); @@ -14942,9 +15071,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, addend = outrel.r_addend; /* Adjust pc_relative relocs to have zero in *r_offset. */ else if (ppc64_elf_howto_table[r_type]->pc_relative) - addend = (input_section->output_section->vma - + input_section->output_offset - + rel->r_offset); + addend = outrel.r_offset; } } break; @@ -14969,6 +15096,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, /* These ones haven't been implemented yet. */ info->callbacks->einfo + /* xgettext:c-format */ (_("%P: %B: %s is not supported for `%T'\n"), input_bfd, ppc64_elf_howto_table[r_type]->name, sym_name); @@ -15073,7 +15201,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, alone (it will be set to zero elsewhere in the link). */ if (sec == NULL) break; - /* Fall thru */ + /* Fall through. */ case R_PPC64_GOT16_HA: case R_PPC64_PLTGOT16_HA: @@ -15123,7 +15251,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, { relocation ^= relocation & mask; info->callbacks->einfo - (_("%P: %H: error: %s not a multiple of %u\n"), + /* xgettext:c-format */ + (_("%H: error: %s not a multiple of %u\n"), input_bfd, input_section, rel->r_offset, howto->name, mask + 1); @@ -15144,7 +15273,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, rel->r_offset) != (bfd_vma) -1) { info->callbacks->einfo - (_("%P: %H: unresolvable %s against `%T'\n"), + /* xgettext:c-format */ + (_("%H: unresolvable %s against `%T'\n"), input_bfd, input_section, rel->r_offset, howto->name, h->elf.root.root.string); @@ -15240,7 +15370,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, else { info->callbacks->einfo - (_("%P: %H: %s against `%T': error %d\n"), + /* xgettext:c-format */ + (_("%H: %s against `%T': error %d\n"), input_bfd, input_section, rel->r_offset, reloc_name, sym_name, (int) r); ret = FALSE; @@ -15331,7 +15462,7 @@ static bfd_boolean ppc64_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info, struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym ATTRIBUTE_UNUSED) + Elf_Internal_Sym *sym) { struct ppc_link_hash_table *htab; struct plt_entry *ent; @@ -15368,6 +15499,7 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd, loc = (htab->elf.irelplt->contents + (htab->elf.irelplt->reloc_count++ * sizeof (Elf64_External_Rela))); + htab->local_ifunc_resolver = 1; } else { @@ -15379,6 +15511,8 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd, loc = (htab->elf.srelplt->contents + ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE (htab)) / PLT_ENTRY_SIZE (htab) * sizeof (Elf64_External_Rela))); + if (h->type == STT_GNU_IFUNC && is_static_defined (h)) + htab->maybe_local_ifunc_resolver = 1; } bfd_elf64_swap_reloca_out (output_bfd, &rela, loc); @@ -15410,11 +15544,13 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd, if (h->needs_copy) { /* This symbol needs a copy reloc. Set it up. */ + asection *srel; if (h->dynindx == -1 || (h->root.type != bfd_link_hash_defined && h->root.type != bfd_link_hash_defweak) - || htab->relbss == NULL) + || htab->elf.srelbss == NULL + || htab->elf.sreldynrelro == NULL) abort (); rela.r_offset = (h->root.u.def.value @@ -15422,8 +15558,12 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd, + h->root.u.def.section->output_offset); rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_COPY); rela.r_addend = 0; - loc = htab->relbss->contents; - loc += htab->relbss->reloc_count++ * sizeof (Elf64_External_Rela); + if (h->root.u.def.section == htab->elf.sdynrelro) + srel = htab->elf.sreldynrelro; + else + srel = htab->elf.srelbss; + loc = srel->contents; + loc += srel->reloc_count++ * sizeof (Elf64_External_Rela); bfd_elf64_swap_reloca_out (output_bfd, &rela, loc); } @@ -15516,6 +15656,8 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd, case DT_PPC64_OPT: if (htab->do_multi_toc && htab->multi_toc_needed) dyn.d_un.d_val |= PPC64_OPT_MULTI_TOC; + if (htab->has_plt_localentry0) + dyn.d_un.d_val |= PPC64_OPT_LOCALENTRY; break; case DT_PPC64_OPDSZ: @@ -15539,33 +15681,24 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd, dyn.d_un.d_val = htab->elf.srelplt->size; break; - case DT_RELASZ: - /* Don't count procedure linkage table relocs in the - overall reloc count. */ - s = htab->elf.srelplt; - if (s == NULL) - continue; - dyn.d_un.d_val -= s->size; - break; - - case DT_RELA: - /* We may not be using the standard ELF linker script. - If .rela.plt is the first .rela section, we adjust - DT_RELA to not include it. */ - s = htab->elf.srelplt; - if (s == NULL) - continue; - if (dyn.d_un.d_ptr != s->output_section->vma + s->output_offset) - continue; - dyn.d_un.d_ptr += s->size; - break; + case DT_TEXTREL: + if (htab->local_ifunc_resolver) + info->callbacks->einfo + (_("%X%P: text relocations and GNU indirect " + "functions will result in a segfault at runtime\n")); + else if (htab->maybe_local_ifunc_resolver) + info->callbacks->einfo + (_("%P: warning: text relocations and GNU indirect " + "functions may result in a segfault at runtime\n")); + continue; } bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon); } } - if (htab->elf.sgot != NULL && htab->elf.sgot->size != 0) + if (htab->elf.sgot != NULL && htab->elf.sgot->size != 0 + && htab->elf.sgot->output_section != bfd_abs_section_ptr) { /* Fill in the first entry in the global offset table. We use it to hold the link-time TOCbase. */ @@ -15577,7 +15710,8 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd, elf_section_data (htab->elf.sgot->output_section)->this_hdr.sh_entsize = 8; } - if (htab->elf.splt != NULL && htab->elf.splt->size != 0) + if (htab->elf.splt != NULL && htab->elf.splt->size != 0 + && htab->elf.splt->output_section != bfd_abs_section_ptr) { /* Set .plt entry size. */ elf_section_data (htab->elf.splt->output_section)->this_hdr.sh_entsize @@ -15610,8 +15744,10 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd, bfd_vma val; bfd_byte *p; asection *stub_sec; + size_t align = 4; - p = htab->glink_eh_frame->contents + sizeof (glink_eh_frame_cie); + p = htab->glink_eh_frame->contents; + p += (sizeof (glink_eh_frame_cie) + align - 1) & -align; for (stub_sec = htab->params->stub_bfd->sections; stub_sec != NULL; stub_sec = stub_sec->next) @@ -15641,7 +15777,7 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd, /* Augmentation. */ p += 1; /* Pad. */ - p += 7; + p += ((17 + align - 1) & -align) - 17; } if (htab->glink != NULL && htab->glink->size != 0) { @@ -15671,6 +15807,7 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd, p += 1; /* Ops. */ p += 7; + p += ((24 + align - 1) & -align) - 24; } if (htab->glink_eh_frame->sec_info_type == SEC_INFO_TYPE_EH_FRAME @@ -15730,4 +15867,3 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd, #define elf64_bed elf64_powerpc_fbsd_bed #include "elf64-target.h" -