From: Alan Modra Date: Sun, 8 Apr 2018 23:52:53 +0000 (+0930) Subject: Support PLT16 relocs against local symbols X-Git-Url: http://git.efficios.com/?a=commitdiff_plain;h=2d7ad24e8726ba4c45c9e67be08223a146a837ce;p=deliverable%2Fbinutils-gdb.git Support PLT16 relocs against local symbols Necessary if gcc is to use PLT16 relocs to implement -mlongcall, and there isn't a good technical reason why local symbols should be excluded from PLT16 support. Non-ifunc local symbol PLT entries go in a separate section to other PLT entries. In a fixed position executable they won't need to be relocated, and in a PIE or shared library I chose to not implement lazy relocation. bfd/ * elf64-ppc.c (LOCAL_PLT_ENTRY_SIZE): Define. (struct ppc_stub_hash_entry): Add symtype field. (PLT_KEEP): Define. (struct ppc_link_hash_table): Add pltlocal and relpltlocal. (create_linkage_sections): Create pltlocal and relpltlocal. (ppc64_elf_check_relocs): Allow PLT relocs on local symbols. Set PLT_KEEP. (ppc64_elf_adjust_dynamic_symbol): Keep PLT entries for inline calls. (allocate_dynrelocs): Allocate pltlocal and relpltlocal. (ppc64_elf_size_dynamic_sections): Size pltlocal and relpltlocal. Keep PLT entries for inline calls against locals. (ppc_build_one_stub): Use pltlocal as appropriate. (ppc_size_one_stub): Likewise. (ppc64_elf_size_stubs): Set symtype. (build_global_entry_stubs_and_plt): Init pltlocal and write relpltlocal for globals. (write_plt_relocs_for_local_syms): Likewise for local syms. (ppc64_elf_relocate_section): Support PLT for local syms. * elf32-ppc.c (PLT_KEEP): Define. (struct ppc_elf_link_hash_table): Add pltlocal and relpltlocal. (ppc_elf_create_glink): Create pltlocal and relpltlocal. (ppc_elf_check_relocs): Allow PLT relocs on local symbols. Set PLT_KEEP. Adjust update_local_sym_info call. (ppc_elf_adjust_dynamic_symbol): Keep PLT entries for inline calls. (allocate_dynrelocs): Allocate pltlocal and relpltlocal. (ppc_elf_size_dynamic_sections): Size pltlocal and relpltlocal. (ppc_elf_relocate_section): Support PLT16 relocs for local syms. (write_global_sym_plt): Init pltlocal and write relpltlocal. (ppc_finish_symbols): Likewise for locals. ld/ * emulparams/elf32ppc.sh (OTHER_RELRO_SECTIONS_2): Add .branch_lt. (OTHER_GOT_RELOC_SECTIONS): Add .rela.branch_lt. * testsuite/ld-powerpc/elfv2so.d: Update for symbol/stub reordering. * testsuite/ld-powerpc/relbrlt.d: Likewise. * testsuite/ld-powerpc/relbrlt.s: Likewise. * testsuite/ld-powerpc/tlsso.r: Likewise. * testsuite/ld-powerpc/tlstocso.r: Likewise. gold/ * powerpc.cc (Target_powerpc::lplt_): New variable. (Target_powerpc::lplt_section): Associated accessor. (Target_powerpc::plt_off): Handle local non-ifunc symbols. (Target_powerpc::make_lplt_section): New function. (Target_powerpc::make_local_plt_entry): New function. (Powerpc_relobj::do_relocate_sections): Write out lplt. (Output_data_plt_powerpc::first_plt_entry_offset): Zero for lplt. (Output_data_plt_powerpc::add_local_entry): New function. (Output_data_plt_powerpc::do_write): Ignore lplt. (Target_powerpc::make_iplt_section): Make lplt first. (Target_powerpc::make_brlt_section): Make .branch_lt relro. (Target_powerpc::Scan::local): Handle PLT16 relocs. --- diff --git a/bfd/ChangeLog b/bfd/ChangeLog index f6388c19dc..099d106e2f 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,35 @@ +2018-04-09 Alan Modra + + * elf64-ppc.c (LOCAL_PLT_ENTRY_SIZE): Define. + (struct ppc_stub_hash_entry): Add symtype field. + (PLT_KEEP): Define. + (struct ppc_link_hash_table): Add pltlocal and relpltlocal. + (create_linkage_sections): Create pltlocal and relpltlocal. + (ppc64_elf_check_relocs): Allow PLT relocs on local symbols. + Set PLT_KEEP. + (ppc64_elf_adjust_dynamic_symbol): Keep PLT entries for inline calls. + (allocate_dynrelocs): Allocate pltlocal and relpltlocal. + (ppc64_elf_size_dynamic_sections): Size pltlocal and relpltlocal. + Keep PLT entries for inline calls against locals. + (ppc_build_one_stub): Use pltlocal as appropriate. + (ppc_size_one_stub): Likewise. + (ppc64_elf_size_stubs): Set symtype. + (build_global_entry_stubs_and_plt): Init pltlocal and write + relpltlocal for globals. + (write_plt_relocs_for_local_syms): Likewise for local syms. + (ppc64_elf_relocate_section): Support PLT for local syms. + * elf32-ppc.c (PLT_KEEP): Define. + (struct ppc_elf_link_hash_table): Add pltlocal and relpltlocal. + (ppc_elf_create_glink): Create pltlocal and relpltlocal. + (ppc_elf_check_relocs): Allow PLT relocs on local symbols. + Set PLT_KEEP. Adjust update_local_sym_info call. + (ppc_elf_adjust_dynamic_symbol): Keep PLT entries for inline calls. + (allocate_dynrelocs): Allocate pltlocal and relpltlocal. + (ppc_elf_size_dynamic_sections): Size pltlocal and relpltlocal. + (ppc_elf_relocate_section): Support PLT16 relocs for local syms. + (write_global_sym_plt): Init pltlocal and write relpltlocal. + (ppc_finish_symbols): Likewise for locals. + 2018-04-09 Alan Modra * elf64-ppc.c (ppc_build_one_stub): Move output of PLT relocs diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index d24b095a54..5da7230da3 100644 --- a/bfd/elf32-ppc.c +++ b/bfd/elf32-ppc.c @@ -3248,6 +3248,7 @@ struct ppc_elf_link_hash_entry /* The above field is also used to mark function symbols. In which case TLS_TLS will be 0. */ #define PLT_IFUNC 2 /* STT_GNU_IFUNC. */ +#define PLT_KEEP 4 /* inline plt call requires plt entry. */ #define NON_GOT 256 /* local symbol plt, not stored. */ /* Nonzero if we have seen a small data relocation referring to this @@ -3277,6 +3278,8 @@ struct ppc_elf_link_hash_table elf_linker_section_t sdata[2]; asection *sbss; asection *glink_eh_frame; + asection *pltlocal; + asection *relpltlocal; /* The (unloaded but important) .rela.plt.unloaded on VxWorks. */ asection *srelplt2; @@ -3526,6 +3529,26 @@ ppc_elf_create_glink (bfd *abfd, struct bfd_link_info *info) || ! bfd_set_section_alignment (abfd, s, 2)) return FALSE; + /* Local plt entries. */ + flags = (SEC_ALLOC | SEC_LOAD + | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED); + htab->pltlocal = bfd_make_section_anyway_with_flags (abfd, ".branch_lt", + flags); + if (htab->pltlocal == NULL + || ! bfd_set_section_alignment (abfd, htab->pltlocal, 2)) + return FALSE; + + if (bfd_link_pic (info)) + { + flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY + | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED); + htab->relpltlocal + = bfd_make_section_anyway_with_flags (abfd, ".rela.branch_lt", flags); + if (htab->relpltlocal == NULL + || ! bfd_set_section_alignment (abfd, htab->relpltlocal, 2)) + return FALSE; + } + if (!ppc_elf_create_linker_section (abfd, info, 0, &htab->sdata[0])) return FALSE; @@ -4008,6 +4031,8 @@ ppc_elf_check_relocs (bfd *abfd, struct elf_link_hash_entry *h; int tls_type; struct plt_entry **ifunc; + struct plt_entry **pltent; + bfd_vma addend; r_symndx = ELF32_R_SYM (rel->r_info); if (r_symndx < symtab_hdr->sh_info) @@ -4061,7 +4086,7 @@ ppc_elf_check_relocs (bfd *abfd, || r_type == R_PPC_PLT16_HI || r_type == R_PPC_PLT16_HA) { - bfd_vma addend = 0; + addend = 0; if (r_type == R_PPC_PLTREL24) ppc_elf_tdata (abfd)->makes_plt_call = 1; if (bfd_link_pic (info) @@ -4296,33 +4321,27 @@ ppc_elf_check_relocs (bfd *abfd, /* This symbol requires a procedure linkage table entry. */ if (h == NULL) { - if (ifunc == NULL) - { - /* It does not make sense to have a procedure linkage - table entry for a non-ifunc local symbol. */ - info->callbacks->einfo - /* xgettext:c-format */ - (_("%H: %s reloc against local symbol\n"), - abfd, sec, rel->r_offset, - ppc_elf_howto_table[r_type]->name); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } + pltent = update_local_sym_info (abfd, symtab_hdr, r_symndx, + NON_GOT | PLT_KEEP); + if (pltent == NULL) + return FALSE; } else { - bfd_vma addend = 0; - - if (bfd_link_pic (info) - && (r_type == R_PPC_PLTREL24 - || r_type == R_PPC_PLT16_LO - || r_type == R_PPC_PLT16_HI - || r_type == R_PPC_PLT16_HA)) - addend = rel->r_addend; + if (r_type != R_PPC_PLTREL24) + ppc_elf_hash_entry (h)->tls_mask |= PLT_KEEP; h->needs_plt = 1; - if (!update_plt_info (abfd, &h->plt.plist, got2, addend)) - return FALSE; + pltent = &h->plt.plist; } + addend = 0; + if (bfd_link_pic (info) + && (r_type == R_PPC_PLTREL24 + || r_type == R_PPC_PLT16_LO + || r_type == R_PPC_PLT16_HI + || r_type == R_PPC_PLT16_HA)) + addend = rel->r_addend; + if (!update_plt_info (abfd, pltent, got2, addend)) + return FALSE; break; /* The following relocations don't need to propagate the @@ -5617,7 +5636,10 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info, if (ent->plt.refcount > 0) break; if (ent == NULL - || (h->type != STT_GNU_IFUNC && local)) + || (h->type != STT_GNU_IFUNC + && local + && ((ppc_elf_hash_entry (h)->tls_mask & (TLS_TLS | PLT_KEEP)) + != PLT_KEEP))) { /* A PLT entry is not required/allowed when: @@ -6103,13 +6125,25 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) sreloc->size += p->count * sizeof (Elf32_External_Rela); } - /* Handle PLT relocs. Done last, after dynindx has settled. */ + /* Handle PLT relocs. Done last, after dynindx has settled. + We might need a PLT entry when the symbol + a) is dynamic, or + b) is an ifunc, or + c) has plt16 relocs and has been processed by adjust_dynamic_symbol, or + d) has plt16 relocs and we are linking statically. */ dyn = htab->elf.dynamic_sections_created && h->dynindx != -1; - if (dyn || h->type == STT_GNU_IFUNC) + if (dyn + || h->type == STT_GNU_IFUNC + || (h->needs_plt && h->dynamic_adjusted) + || (h->needs_plt + && h->def_regular + && !htab->elf.dynamic_sections_created + && (ppc_elf_hash_entry (h)->tls_mask + & (TLS_TLS | PLT_KEEP)) == PLT_KEEP)) { struct plt_entry *ent; bfd_boolean doneone = FALSE; - bfd_vma plt_offset = 0, glink_offset = 0; + bfd_vma plt_offset = 0, glink_offset = (bfd_vma) -1; for (ent = h->plt.plist; ent != NULL; ent = ent->next) if (ent->plt.refcount > 0) @@ -6117,7 +6151,12 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) asection *s = htab->elf.splt; if (!dyn) - s = htab->elf.iplt; + { + if (h->type == STT_GNU_IFUNC) + s = htab->elf.iplt; + else + s = htab->pltlocal; + } if (htab->plt_type == PLT_NEW || !dyn) { @@ -6128,25 +6167,30 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) } ent->plt.offset = plt_offset; - s = htab->glink; - if (!doneone || bfd_link_pic (info)) - { - glink_offset = s->size; - s->size += GLINK_ENTRY_SIZE (htab, h); - } - if (!doneone - && !bfd_link_pic (info) - && h->def_dynamic - && !h->def_regular) + if (s == htab->pltlocal) + ent->glink_offset = glink_offset; + else { - h->root.u.def.section = s; - h->root.u.def.value = glink_offset; - } - ent->glink_offset = glink_offset; + s = htab->glink; + if (!doneone || bfd_link_pic (info)) + { + glink_offset = s->size; + s->size += GLINK_ENTRY_SIZE (htab, h); + } + if (!doneone + && !bfd_link_pic (info) + && h->def_dynamic + && !h->def_regular) + { + h->root.u.def.section = s; + h->root.u.def.value = glink_offset; + } + ent->glink_offset = glink_offset; - if (htab->params->emit_stub_syms - && !add_stub_sym (ent, h, info)) - return FALSE; + if (htab->params->emit_stub_syms + && !add_stub_sym (ent, h, info)) + return FALSE; + } } else { @@ -6199,7 +6243,18 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) if (!doneone) { if (!dyn) - htab->elf.irelplt->size += sizeof (Elf32_External_Rela); + { + if (h->type == STT_GNU_IFUNC) + { + s = htab->elf.irelplt; + s->size += sizeof (Elf32_External_Rela); + } + else if (bfd_link_pic (info)) + { + s = htab->relpltlocal; + s->size += sizeof (Elf32_External_Rela); + } + } else { htab->elf.srelplt->size += sizeof (Elf32_External_Rela); @@ -6425,16 +6480,25 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd, continue; /* Allocate space for calls to local STT_GNU_IFUNC syms in .iplt. */ - for (; local_plt < end_local_plt; ++local_plt) + lgot_masks = (char *) end_local_plt; + for (; local_plt < end_local_plt; ++local_plt, ++lgot_masks) { struct plt_entry *ent; bfd_boolean doneone = FALSE; - bfd_vma plt_offset = 0, glink_offset = 0; + bfd_vma plt_offset = 0, glink_offset = (bfd_vma) -1; for (ent = *local_plt; ent != NULL; ent = ent->next) if (ent->plt.refcount > 0) { - s = htab->elf.iplt; + if ((*lgot_masks & (TLS_TLS | PLT_IFUNC)) == PLT_IFUNC) + s = htab->elf.iplt; + else if ((*lgot_masks & (TLS_TLS | PLT_KEEP)) != PLT_KEEP) + { + ent->plt.offset = (bfd_vma) -1; + continue; + } + else + s = htab->pltlocal; if (!doneone) { @@ -6443,9 +6507,9 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd, } ent->plt.offset = plt_offset; - s = htab->glink; - if (!doneone || bfd_link_pic (info)) + if (s != htab->pltlocal && (!doneone || bfd_link_pic (info))) { + s = htab->glink; glink_offset = s->size; s->size += GLINK_ENTRY_SIZE (htab, NULL); } @@ -6453,7 +6517,16 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd, if (!doneone) { - htab->elf.irelplt->size += sizeof (Elf32_External_Rela); + if ((*lgot_masks & (TLS_TLS | PLT_IFUNC)) == PLT_IFUNC) + { + s = htab->elf.irelplt; + s->size += sizeof (Elf32_External_Rela); + } + else if (bfd_link_pic (info)) + { + s = htab->relpltlocal; + s->size += sizeof (Elf32_External_Rela); + } doneone = TRUE; } } @@ -6599,6 +6672,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd, comment below. */ } else if (s == htab->elf.iplt + || s == htab->pltlocal || s == htab->glink || s == htab->glink_eh_frame || s == htab->elf.sgotplt @@ -9173,9 +9247,18 @@ ppc_elf_relocate_section (bfd *output_bfd, case R_PPC_PLT16_LO: case R_PPC_PLT16_HI: case R_PPC_PLT16_HA: - plt_list = ifunc; + plt_list = NULL; if (h != NULL) plt_list = &h->plt.plist; + else if (ifunc != NULL) + plt_list = ifunc; + else if (local_got_offsets != NULL) + { + struct plt_entry **local_plt; + local_plt = (struct plt_entry **) (local_got_offsets + + symtab_hdr->sh_info); + plt_list = local_plt + r_symndx; + } unresolved_reloc = TRUE; if (plt_list != NULL) { @@ -9183,11 +9266,23 @@ ppc_elf_relocate_section (bfd *output_bfd, ent = find_plt_ent (plt_list, got2, bfd_link_pic (info) ? addend : 0); - if (ent != NULL) + if (ent != NULL && ent->plt.offset != (bfd_vma) -1) { + asection *plt; + unresolved_reloc = FALSE; - relocation = (htab->elf.splt->output_section->vma - + htab->elf.splt->output_offset + plt = htab->elf.splt; + if (!htab->elf.dynamic_sections_created + || h == NULL + || h->dynindx == -1) + { + if (ifunc != NULL) + plt = htab->elf.iplt; + else + plt = htab->pltlocal; + } + relocation = (plt->output_section->vma + + plt->output_offset + ent->plt.offset); if (bfd_link_pic (info)) { @@ -10085,6 +10180,8 @@ write_global_sym_plt (struct elf_link_hash_entry *h, void *inf) Elf_Internal_Rela rela; bfd_byte *loc; bfd_vma reloc_index; + asection *plt = htab->elf.splt; + asection *relplt = htab->elf.srelplt; if (htab->plt_type == PLT_NEW || !htab->elf.dynamic_sections_created @@ -10120,10 +10217,10 @@ write_global_sym_plt (struct elf_link_hash_entry *h, void *inf) { bfd_put_32 (info->output_bfd, plt_entry[0] | PPC_HA (got_offset), - htab->elf.splt->contents + ent->plt.offset + 0); + plt->contents + ent->plt.offset + 0); bfd_put_32 (info->output_bfd, plt_entry[1] | PPC_LO (got_offset), - htab->elf.splt->contents + ent->plt.offset + 4); + plt->contents + ent->plt.offset + 4); } else { @@ -10131,16 +10228,16 @@ write_global_sym_plt (struct elf_link_hash_entry *h, void *inf) bfd_put_32 (info->output_bfd, plt_entry[0] | PPC_HA (got_loc), - htab->elf.splt->contents + ent->plt.offset + 0); + plt->contents + ent->plt.offset + 0); bfd_put_32 (info->output_bfd, plt_entry[1] | PPC_LO (got_loc), - htab->elf.splt->contents + ent->plt.offset + 4); + plt->contents + ent->plt.offset + 4); } bfd_put_32 (info->output_bfd, plt_entry[2], - htab->elf.splt->contents + ent->plt.offset + 8); + plt->contents + ent->plt.offset + 8); bfd_put_32 (info->output_bfd, plt_entry[3], - htab->elf.splt->contents + ent->plt.offset + 12); + plt->contents + ent->plt.offset + 12); /* This instruction is an immediate load. The value loaded is the byte offset of the R_PPC_JMP_SLOT relocation from the @@ -10150,7 +10247,7 @@ write_global_sym_plt (struct elf_link_hash_entry *h, void *inf) prescaled offset. */ bfd_put_32 (info->output_bfd, plt_entry[4] | reloc_index, - htab->elf.splt->contents + ent->plt.offset + 16); + plt->contents + ent->plt.offset + 16); /* This instruction is a PC-relative branch whose target is the start of the PLT section. The address of this branch instruction is 20 bytes beyond the start of this PLT entry. @@ -10160,19 +10257,18 @@ write_global_sym_plt (struct elf_link_hash_entry *h, void *inf) bfd_put_32 (info->output_bfd, (plt_entry[5] | (-(ent->plt.offset + 20) & 0x03fffffc)), - htab->elf.splt->contents + ent->plt.offset + 20); + plt->contents + ent->plt.offset + 20); bfd_put_32 (info->output_bfd, plt_entry[6], - htab->elf.splt->contents + ent->plt.offset + 24); + plt->contents + ent->plt.offset + 24); bfd_put_32 (info->output_bfd, plt_entry[7], - htab->elf.splt->contents + ent->plt.offset + 28); + plt->contents + ent->plt.offset + 28); /* Fill in the GOT entry corresponding to this PLT slot with the address immediately after the "bctr" instruction in this PLT entry. */ - bfd_put_32 (info->output_bfd, - (htab->elf.splt->output_section->vma - + htab->elf.splt->output_offset - + ent->plt.offset + 16), + bfd_put_32 (info->output_bfd, (plt->output_section->vma + + plt->output_offset + + ent->plt.offset + 16), htab->elf.sgotplt->contents + got_offset); if (!bfd_link_pic (info)) @@ -10184,8 +10280,8 @@ write_global_sym_plt (struct elf_link_hash_entry *h, void *inf) * sizeof (Elf32_External_Rela)); /* Provide the @ha relocation for the first instruction. */ - rela.r_offset = (htab->elf.splt->output_section->vma - + htab->elf.splt->output_offset + rela.r_offset = (plt->output_section->vma + + plt->output_offset + ent->plt.offset + 2); rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_PPC_ADDR16_HA); @@ -10194,8 +10290,8 @@ write_global_sym_plt (struct elf_link_hash_entry *h, void *inf) loc += sizeof (Elf32_External_Rela); /* Provide the @l relocation for the second instruction. */ - rela.r_offset = (htab->elf.splt->output_section->vma - + htab->elf.splt->output_offset + rela.r_offset = (plt->output_section->vma + + plt->output_offset + ent->plt.offset + 6); rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_PPC_ADDR16_LO); @@ -10222,66 +10318,83 @@ write_global_sym_plt (struct elf_link_hash_entry *h, void *inf) rela.r_offset = (htab->elf.sgotplt->output_section->vma + htab->elf.sgotplt->output_offset + got_offset); - + rela.r_addend = 0; } else { - asection *splt = htab->elf.splt; + rela.r_addend = 0; if (!htab->elf.dynamic_sections_created || h->dynindx == -1) - splt = htab->elf.iplt; + { + if (h->type == STT_GNU_IFUNC) + { + plt = htab->elf.iplt; + relplt = htab->elf.irelplt; + } + else + { + plt = htab->pltlocal; + relplt = bfd_link_pic (info) ? htab->relpltlocal : NULL; + } + if (h->def_regular + && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak)) + rela.r_addend = SYM_VAL (h); + } - rela.r_offset = (splt->output_section->vma - + splt->output_offset - + ent->plt.offset); - if (htab->plt_type == PLT_OLD - || !htab->elf.dynamic_sections_created - || h->dynindx == -1) + if (relplt == NULL) { - /* We don't need to fill in the .plt. The ppc dynamic - linker will fill it in. */ + loc = plt->contents + ent->plt.offset; + bfd_put_32 (info->output_bfd, rela.r_addend, loc); } else { - bfd_vma val = (htab->glink_pltresolve + ent->plt.offset - + htab->glink->output_section->vma - + htab->glink->output_offset); - bfd_put_32 (info->output_bfd, val, - splt->contents + ent->plt.offset); + rela.r_offset = (plt->output_section->vma + + plt->output_offset + + ent->plt.offset); + + if (htab->plt_type == PLT_OLD + || !htab->elf.dynamic_sections_created + || h->dynindx == -1) + { + /* We don't need to fill in the .plt. The ppc dynamic + linker will fill it in. */ + } + else + { + bfd_vma val = (htab->glink_pltresolve + ent->plt.offset + + htab->glink->output_section->vma + + htab->glink->output_offset); + bfd_put_32 (info->output_bfd, val, + plt->contents + ent->plt.offset); + } } } - /* Fill in the entry in the .rela.plt section. */ - rela.r_addend = 0; - if (!htab->elf.dynamic_sections_created - || h->dynindx == -1) + if (relplt != NULL) { - BFD_ASSERT (h->type == STT_GNU_IFUNC - && h->def_regular - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak)); - rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE); - rela.r_addend = SYM_VAL (h); - } - else - rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_JMP_SLOT); - - if (!htab->elf.dynamic_sections_created - || h->dynindx == -1) - { - loc = (htab->elf.irelplt->contents - + (htab->elf.irelplt->reloc_count++ - * sizeof (Elf32_External_Rela))); - htab->local_ifunc_resolver = 1; - } - else - { - loc = (htab->elf.srelplt->contents - + reloc_index * sizeof (Elf32_External_Rela)); - if (h->type == STT_GNU_IFUNC && is_static_defined (h)) - htab->maybe_local_ifunc_resolver = 1; + /* Fill in the entry in the .rela.plt section. */ + if (!htab->elf.dynamic_sections_created + || h->dynindx == -1) + { + if (h->type == STT_GNU_IFUNC) + rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE); + else + rela.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE); + loc = relplt->contents + (relplt->reloc_count++ + * sizeof (Elf32_External_Rela)); + htab->local_ifunc_resolver = 1; + } + else + { + rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_JMP_SLOT); + loc = relplt->contents + (reloc_index + * sizeof (Elf32_External_Rela)); + if (h->type == STT_GNU_IFUNC && is_static_defined (h)) + htab->maybe_local_ifunc_resolver = 1; + } + bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc); } - bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc); doneone = TRUE; } @@ -10294,7 +10407,12 @@ write_global_sym_plt (struct elf_link_hash_entry *h, void *inf) if (!htab->elf.dynamic_sections_created || h->dynindx == -1) - plt = htab->elf.iplt; + { + if (h->type == STT_GNU_IFUNC) + plt = htab->elf.iplt; + else + break; + } p = (unsigned char *) htab->glink->contents + ent->glink_offset; write_glink_stub (h, ent, plt, p, info); @@ -10368,16 +10486,32 @@ ppc_finish_symbols (struct bfd_link_info *info) if (sym_sec != NULL && sym_sec->output_section != NULL) val += sym_sec->output_offset + sym_sec->output_section->vma; - BFD_ASSERT (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC); - - htab->local_ifunc_resolver = 1; - plt = htab->elf.iplt; - relplt = htab->elf.irelplt; + if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC) + { + htab->local_ifunc_resolver = 1; + plt = htab->elf.iplt; + relplt = htab->elf.irelplt; + rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE); + } + else + { + plt = htab->pltlocal; + if (bfd_link_pic (info)) + { + relplt = htab->relpltlocal; + rela.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE); + } + else + { + loc = plt->contents + ent->plt.offset; + bfd_put_32 (info->output_bfd, val, loc); + continue; + } + } rela.r_offset = (ent->plt.offset + plt->output_offset + plt->output_section->vma); - rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE); rela.r_addend = val; loc = relplt->contents + (relplt->reloc_count++ * sizeof (Elf32_External_Rela)); diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index 8291db8d25..4ea6a9ead5 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -129,6 +129,7 @@ static bfd_vma opd_entry_value /* The size in bytes of an entry in the procedure linkage table. */ #define PLT_ENTRY_SIZE(htab) (htab->opd_abi ? 24 : 8) +#define LOCAL_PLT_ENTRY_SIZE(htab) (htab->opd_abi ? 16 : 8) /* The initial size of the plt reserved for the dynamic linker. */ #define PLT_INITIAL_ENTRY_SIZE(htab) (htab->opd_abi ? 24 : 16) @@ -3977,6 +3978,9 @@ struct ppc_stub_hash_entry { struct ppc_link_hash_entry *h; struct plt_entry *plt_ent; + /* Symbol type. */ + unsigned char symtype; + /* Symbol st_other. */ unsigned char other; }; @@ -4068,6 +4072,7 @@ struct ppc_link_hash_entry /* The above field is also used to mark function symbols. In which case TLS_TLS will be 0. */ #define PLT_IFUNC 2 /* STT_GNU_IFUNC. */ +#define PLT_KEEP 4 /* inline plt call requires plt entry. */ #define NON_GOT 256 /* local symbol plt, not stored. */ }; @@ -4124,6 +4129,8 @@ struct ppc_link_hash_table asection *glink; asection *global_entry; asection *sfpr; + asection *pltlocal; + asection *relpltlocal; asection *brlt; asection *relbrlt; asection *glink_eh_frame; @@ -4505,18 +4512,31 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info) || ! bfd_set_section_alignment (dynobj, htab->brlt, 3)) return FALSE; + /* Local plt entries, put in .branch_lt but a separate section for + convenience. */ + htab->pltlocal = bfd_make_section_anyway_with_flags (dynobj, ".branch_lt", + flags); + if (htab->pltlocal == NULL + || ! bfd_set_section_alignment (dynobj, htab->pltlocal, 3)) + return FALSE; + if (!bfd_link_pic (info)) return TRUE; flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED); - htab->relbrlt = bfd_make_section_anyway_with_flags (dynobj, - ".rela.branch_lt", - flags); + htab->relbrlt + = bfd_make_section_anyway_with_flags (dynobj, ".rela.branch_lt", flags); if (htab->relbrlt == NULL || ! bfd_set_section_alignment (dynobj, htab->relbrlt, 3)) return FALSE; + htab->relpltlocal + = bfd_make_section_anyway_with_flags (dynobj, ".rela.branch_lt", flags); + if (htab->relpltlocal == NULL + || ! bfd_set_section_alignment (dynobj, htab->relpltlocal, 3)) + return FALSE; + return TRUE; } @@ -5634,20 +5654,13 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, if (h->root.root.string[0] == '.' && h->root.root.string[1] != '\0') ((struct ppc_link_hash_entry *) h)->is_func = 1; + ((struct ppc_link_hash_entry *) h)->tls_mask |= PLT_KEEP; plt_list = &h->plt.plist; } if (plt_list == NULL) - { - /* It does not make sense to have a procedure linkage - table entry for a non-ifunc local symbol. */ - info->callbacks->einfo - /* 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); - return FALSE; - } + plt_list = update_local_sym_info (abfd, symtab_hdr, r_symndx, + rel->r_addend, + NON_GOT | PLT_KEEP); if (!update_plt_info (abfd, plt_list, rel->r_addend)) return FALSE; break; @@ -7201,7 +7214,10 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info, if (ent->plt.refcount > 0) break; if (ent == NULL - || (h->type != STT_GNU_IFUNC && local)) + || (h->type != STT_GNU_IFUNC + && local + && (((struct ppc_link_hash_entry *) h)->tls_mask + & (TLS_TLS | PLT_KEEP)) != PLT_KEEP)) { h->plt.plist = NULL; h->needs_plt = 0; @@ -9822,9 +9838,19 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) } } - if ((htab->elf.dynamic_sections_created - && h->dynindx != -1) - || h->type == STT_GNU_IFUNC) + /* We might need a PLT entry when the symbol + a) is dynamic, or + b) is an ifunc, or + c) has plt16 relocs and has been processed by adjust_dynamic_symbol, or + d) has plt16 relocs and we are linking statically. */ + if ((htab->elf.dynamic_sections_created && h->dynindx != -1) + || h->type == STT_GNU_IFUNC + || (h->needs_plt && h->dynamic_adjusted) + || (h->needs_plt + && h->def_regular + && !htab->elf.dynamic_sections_created + && (((struct ppc_link_hash_entry *) h)->tls_mask + & (TLS_TLS | PLT_KEEP)) == PLT_KEEP)) { struct plt_entry *pent; bfd_boolean doneone = FALSE; @@ -9834,10 +9860,20 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) if (!htab->elf.dynamic_sections_created || h->dynindx == -1) { - s = htab->elf.iplt; - pent->plt.offset = s->size; - s->size += PLT_ENTRY_SIZE (htab); - s = htab->elf.irelplt; + if (h->type == STT_GNU_IFUNC) + { + s = htab->elf.iplt; + pent->plt.offset = s->size; + s->size += PLT_ENTRY_SIZE (htab); + s = htab->elf.irelplt; + } + else + { + s = htab->pltlocal; + pent->plt.offset = s->size; + s->size += LOCAL_PLT_ENTRY_SIZE (htab); + s = bfd_link_pic (info) ? htab->relpltlocal : NULL; + } } else { @@ -9869,7 +9905,8 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) /* We also need to make an entry in the .rela.plt section. */ s = htab->elf.srelplt; } - s->size += sizeof (Elf64_External_Rela); + if (s != NULL) + s->size += sizeof (Elf64_External_Rela); doneone = TRUE; } else @@ -10124,19 +10161,32 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd, *pent = ent->next; } - /* Allocate space for calls to local STT_GNU_IFUNC syms in .iplt. */ - for (; local_plt < end_local_plt; ++local_plt) + /* Allocate space for plt calls to local syms. */ + lgot_masks = (unsigned char *) end_local_plt; + for (; local_plt < end_local_plt; ++local_plt, ++lgot_masks) { struct plt_entry *ent; for (ent = *local_plt; ent != NULL; ent = ent->next) if (ent->plt.refcount > 0) { - s = htab->elf.iplt; - ent->plt.offset = s->size; - s->size += PLT_ENTRY_SIZE (htab); - - htab->elf.irelplt->size += sizeof (Elf64_External_Rela); + if ((*lgot_masks & (TLS_TLS | PLT_IFUNC)) == PLT_IFUNC) + { + s = htab->elf.iplt; + ent->plt.offset = s->size; + s->size += PLT_ENTRY_SIZE (htab); + htab->elf.irelplt->size += sizeof (Elf64_External_Rela); + } + else if ((*lgot_masks & (TLS_TLS | PLT_KEEP)) != PLT_KEEP) + ent->plt.offset = (bfd_vma) -1; + else + { + s = htab->pltlocal; + ent->plt.offset = s->size; + s->size += LOCAL_PLT_ENTRY_SIZE (htab); + if (bfd_link_pic (info)) + htab->relpltlocal->size += sizeof (Elf64_External_Rela); + } } else ent->plt.offset = (bfd_vma) -1; @@ -10199,6 +10249,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd, else if (s == htab->elf.sgot || s == htab->elf.splt || s == htab->elf.iplt + || s == htab->pltlocal || s == htab->glink || s == htab->global_entry || s == htab->elf.sdynbss @@ -11154,7 +11205,12 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) if (!htab->elf.dynamic_sections_created || stub_entry->h == NULL || stub_entry->h->elf.dynindx == -1) - plt = htab->elf.iplt; + { + if (stub_entry->symtype == STT_GNU_IFUNC) + plt = htab->elf.iplt; + else + plt = htab->pltlocal; + } dest += plt->output_offset + plt->output_section->vma; @@ -11303,7 +11359,12 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) if (!htab->elf.dynamic_sections_created || stub_entry->h == NULL || stub_entry->h->elf.dynindx == -1) - plt = htab->elf.iplt; + { + if (stub_entry->symtype == STT_GNU_IFUNC) + plt = htab->elf.iplt; + else + plt = htab->pltlocal; + } off += (plt->output_offset + plt->output_section->vma - elf_gp (info->output_bfd) @@ -12655,6 +12716,8 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) } stub_entry->h = hash; stub_entry->plt_ent = plt_ent; + stub_entry->symtype + = hash ? hash->elf.type : ELF_ST_TYPE (sym->st_info); stub_entry->other = hash ? hash->elf.other : sym->st_other; if (stub_entry->h != NULL) @@ -13017,6 +13080,7 @@ build_global_entry_stubs_and_plt (struct elf_link_hash_entry *h, void *inf) /* This symbol has an entry in the procedure linkage table. Set it up. */ Elf_Internal_Rela rela; + asection *plt, *relplt; bfd_byte *loc; if (!htab->elf.dynamic_sections_created @@ -13026,21 +13090,55 @@ build_global_entry_stubs_and_plt (struct elf_link_hash_entry *h, void *inf) && (h->root.type == bfd_link_hash_defined || h->root.type == bfd_link_hash_defweak))) continue; - rela.r_offset = (htab->elf.iplt->output_section->vma - + htab->elf.iplt->output_offset - + ent->plt.offset); - if (htab->opd_abi) - rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL); + if (h->type == STT_GNU_IFUNC) + { + plt = htab->elf.iplt; + relplt = htab->elf.irelplt; + htab->local_ifunc_resolver = 1; + if (htab->opd_abi) + rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL); + else + rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE); + } else - rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE); + { + plt = htab->pltlocal; + if (bfd_link_pic (info)) + { + relplt = htab->relpltlocal; + if (htab->opd_abi) + rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_SLOT); + else + rela.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE); + } + else + relplt = NULL; + } rela.r_addend = (h->root.u.def.value + h->root.u.def.section->output_offset + h->root.u.def.section->output_section->vma + ent->addend); - loc = (htab->elf.irelplt->contents - + (htab->elf.irelplt->reloc_count++ - * sizeof (Elf64_External_Rela))); - htab->local_ifunc_resolver = 1; + + if (relplt == NULL) + { + loc = plt->contents + ent->plt.offset; + bfd_put_64 (info->output_bfd, rela.r_addend, loc); + if (htab->opd_abi) + { + bfd_vma toc = elf_gp (info->output_bfd); + toc += htab->sec_info[h->root.u.def.section->id].toc_off; + bfd_put_64 (info->output_bfd, toc, loc + 8); + } + } + else + { + rela.r_offset = (plt->output_section->vma + + plt->output_offset + + ent->plt.offset); + loc = relplt->contents + (relplt->reloc_count++ + * sizeof (Elf64_External_Rela)); + bfd_elf64_swap_reloca_out (info->output_bfd, &rela, loc); + } } else { @@ -13054,8 +13152,8 @@ build_global_entry_stubs_and_plt (struct elf_link_hash_entry *h, void *inf) / 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 (info->output_bfd, &rela, loc); } - bfd_elf64_swap_reloca_out (info->output_bfd, &rela, loc); } if (!h->pointer_equality_needed) @@ -13080,7 +13178,12 @@ build_global_entry_stubs_and_plt (struct elf_link_hash_entry *h, void *inf) plt = htab->elf.splt; if (!htab->elf.dynamic_sections_created || h->dynindx == -1) - plt = htab->elf.iplt; + { + if (h->type == STT_GNU_IFUNC) + plt = htab->elf.iplt; + else + plt = htab->pltlocal; + } off = ent->plt.offset + plt->output_offset + plt->output_section->vma; off -= h->root.u.def.value + s->output_offset + s->output_section->vma; @@ -13173,7 +13276,6 @@ write_plt_relocs_for_local_syms (struct bfd_link_info *info) asection *plt, *relplt; bfd_byte *loc; bfd_vma val; - Elf_Internal_Rela rela; if (!get_sym_h (NULL, &sym, &sym_sec, NULL, &local_syms, lplt - local_plt, ibfd)) @@ -13189,23 +13291,53 @@ write_plt_relocs_for_local_syms (struct bfd_link_info *info) if (sym_sec != NULL && sym_sec->output_section != NULL) val += sym_sec->output_offset + sym_sec->output_section->vma; - BFD_ASSERT (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC); - - htab->local_ifunc_resolver = 1; - plt = htab->elf.iplt; - relplt = htab->elf.irelplt; + if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC) + { + htab->local_ifunc_resolver = 1; + plt = htab->elf.iplt; + relplt = htab->elf.irelplt; + } + else + { + plt = htab->pltlocal; + relplt = bfd_link_pic (info) ? htab->relpltlocal : NULL; + } - rela.r_offset = (ent->plt.offset - + plt->output_offset - + plt->output_section->vma); - if (htab->opd_abi) - rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL); + if (relplt == NULL) + { + loc = plt->contents + ent->plt.offset; + bfd_put_64 (info->output_bfd, val, loc); + if (htab->opd_abi) + { + bfd_vma toc = elf_gp (ibfd); + bfd_put_64 (info->output_bfd, toc, loc + 8); + } + } else - rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE); - rela.r_addend = val; - loc = relplt->contents + (relplt->reloc_count++ - * sizeof (Elf64_External_Rela)); - bfd_elf64_swap_reloca_out (info->output_bfd, &rela, loc); + { + Elf_Internal_Rela rela; + rela.r_offset = (ent->plt.offset + + plt->output_offset + + plt->output_section->vma); + if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC) + { + if (htab->opd_abi) + rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL); + else + rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE); + } + else + { + if (htab->opd_abi) + rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_SLOT); + else + rela.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE); + } + rela.r_addend = val; + loc = relplt->contents + (relplt->reloc_count++ + * sizeof (Elf64_External_Rela)); + bfd_elf64_swap_reloca_out (info->output_bfd, &rela, loc); + } } if (local_syms != NULL @@ -14792,10 +14924,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, { struct plt_entry **local_plt = (struct plt_entry **) (local_got_ents + symtab_hdr->sh_info); - unsigned char *local_got_tls_masks = (unsigned char *) - (local_plt + symtab_hdr->sh_info); - if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0) - plt_list = local_plt + r_symndx; + plt_list = local_plt + r_symndx; } if (plt_list) { @@ -14812,7 +14941,17 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (!htab->elf.dynamic_sections_created || h == NULL || h->elf.dynindx == -1) - plt = htab->elf.iplt; + { + if (h != NULL + ? h->elf.type == STT_GNU_IFUNC + : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC) + plt = htab->elf.iplt; + else + plt = htab->pltlocal; + } + relocation = (plt->output_section->vma + + plt->output_offset + + ent->plt.offset); if (r_type == R_PPC64_PLT16_HA || r_type ==R_PPC64_PLT16_HI || r_type ==R_PPC64_PLT16_LO @@ -14822,9 +14961,6 @@ ppc64_elf_relocate_section (bfd *output_bfd, + htab->sec_info[input_section->id].toc_off); relocation -= got; } - relocation = (plt->output_section->vma - + plt->output_offset - + ent->plt.offset); addend = 0; unresolved_reloc = FALSE; break; diff --git a/gold/ChangeLog b/gold/ChangeLog index 48c87e4bdd..bb30237739 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,18 @@ +2018-04-09 Alan Modra + + * powerpc.cc (Target_powerpc::lplt_): New variable. + (Target_powerpc::lplt_section): Associated accessor. + (Target_powerpc::plt_off): Handle local non-ifunc symbols. + (Target_powerpc::make_lplt_section): New function. + (Target_powerpc::make_local_plt_entry): New function. + (Powerpc_relobj::do_relocate_sections): Write out lplt. + (Output_data_plt_powerpc::first_plt_entry_offset): Zero for lplt. + (Output_data_plt_powerpc::add_local_entry): New function. + (Output_data_plt_powerpc::do_write): Ignore lplt. + (Target_powerpc::make_iplt_section): Make lplt first. + (Target_powerpc::make_brlt_section): Make .branch_lt relro. + (Target_powerpc::Scan::local): Handle PLT16 relocs. + 2018-04-09 Alan Modra * powerpc.cc (Target_powerpc::plt_off): New functions. diff --git a/gold/powerpc.cc b/gold/powerpc.cc index 0975fee35d..c3f1b232e0 100644 --- a/gold/powerpc.cc +++ b/gold/powerpc.cc @@ -607,7 +607,7 @@ class Target_powerpc : public Sized_target Target_powerpc() : Sized_target(&powerpc_info), - got_(NULL), plt_(NULL), iplt_(NULL), brlt_section_(NULL), + got_(NULL), plt_(NULL), iplt_(NULL), lplt_(NULL), brlt_section_(NULL), glink_(NULL), rela_dyn_(NULL), copy_relocs_(), tlsld_got_offset_(-1U), stub_tables_(), branch_lookup_table_(), branch_info_(), tocsave_loc_(), @@ -860,6 +860,13 @@ class Target_powerpc : public Sized_target return this->iplt_; } + // Get the LPLT section. + const Output_data_plt_powerpc* + lplt_section() const + { + return this->lplt_; + } + // Return the plt offset and section for the given global sym. Address plt_off(const Symbol* gsym, @@ -879,7 +886,11 @@ class Target_powerpc : public Sized_target unsigned int local_sym_index, const Output_data_plt_powerpc** sec) const { - *sec = this->iplt_section(); + const Symbol_value* lsym = relobj->local_symbol(local_sym_index); + if (lsym->is_ifunc_symbol()) + *sec = this->iplt_section(); + else + *sec = this->lplt_section(); return relobj->local_plt_offset(local_sym_index); } @@ -1440,6 +1451,9 @@ class Target_powerpc : public Sized_target void make_iplt_section(Symbol_table*, Layout*); + void + make_lplt_section(Layout*); + void make_brlt_section(Layout*); @@ -1453,6 +1467,12 @@ class Target_powerpc : public Sized_target Sized_relobj_file*, unsigned int); + // Create a PLT entry for a local non-IFUNC symbol. + void + make_local_plt_entry(Layout*, + Sized_relobj_file*, + unsigned int); + // Create a GOT entry for local dynamic __tls_get_addr. unsigned int @@ -1585,6 +1605,8 @@ class Target_powerpc : public Sized_target // section is emitted and marked with __rela_iplt_start and // __rela_iplt_end symbols. Output_data_plt_powerpc* iplt_; + // A PLT style section for local, non-ifunc symbols + Output_data_plt_powerpc* lplt_; // Section holding long branch destinations. Output_data_brlt_powerpc* brlt_section_; // The .glink section. @@ -2469,6 +2491,35 @@ Powerpc_relobj::do_relocate_sections( } this->relocate_section_range(symtab, layout, pshdrs, of, pviews, start, this->shnum() - 1); + + if (!parameters->options().output_is_position_independent()) + { + Target_powerpc* target + = static_cast*>( + parameters->sized_target()); + if (target->lplt_section() && target->lplt_section()->data_size() != 0) + { + const section_size_type offset = target->lplt_section()->offset(); + const section_size_type oview_size + = convert_to_section_size_type(target->lplt_section()->data_size()); + unsigned char* const oview = of->get_output_view(offset, oview_size); + + bool modified = false; + unsigned int nsyms = this->local_symbol_count(); + for (unsigned int i = 0; i < nsyms; i++) + if (this->local_has_plt_offset(i)) + { + Address value = this->local_symbol_value(i, 0); + if (size == 64) + value += ppc64_local_entry_offset(i); + size_t off = this->local_plt_offset(i); + elfcpp::Swap::writeval(oview + off, value); + modified = true; + } + if (modified) + of->write_output_view(offset, oview_size, oview); + } + } } // Set up some symbols. @@ -3667,6 +3718,9 @@ class Output_data_plt_powerpc : public Output_section_data_build void add_ifunc_entry(Symbol*); + void + add_local_entry(Sized_relobj_file*, unsigned int); + void add_local_ifunc_entry(Sized_relobj_file*, unsigned int); @@ -3704,8 +3758,8 @@ class Output_data_plt_powerpc : public Output_section_data_build unsigned int first_plt_entry_offset() const { - // IPLT has no reserved entry. - if (this->name_[3] == 'I') + // IPLT and LPLT have no reserved entry. + if (this->name_[3] == 'I' || this->name_[3] == 'L') return 0; return this->targ_->first_plt_entry_offset(); } @@ -3768,6 +3822,31 @@ Output_data_plt_powerpc::add_ifunc_entry(Symbol* gsym) } } +// Add an entry for a local symbol to the PLT. + +template +void +Output_data_plt_powerpc::add_local_entry( + Sized_relobj_file* relobj, + unsigned int local_sym_index) +{ + if (!relobj->local_has_plt_offset(local_sym_index)) + { + section_size_type off = this->current_data_size(); + relobj->set_local_plt_offset(local_sym_index, off); + if (this->rel_) + { + unsigned int dynrel = elfcpp::R_POWERPC_RELATIVE; + if (size == 64 && this->targ_->abiversion() < 2) + dynrel = elfcpp::R_POWERPC_JMP_SLOT; + this->rel_->add_symbolless_local_addend(relobj, local_sym_index, + dynrel, this, off, 0); + } + off += this->plt_entry_size(); + this->set_current_data_size(off); + } +} + // Add an entry for a local ifunc symbol to the IPLT. template @@ -3888,7 +3967,7 @@ template void Output_data_plt_powerpc::do_write(Output_file* of) { - if (size == 32 && this->name_[3] != 'I') + if (size == 32 && (this->name_[3] != 'I' && this->name_[3] != 'L')) { const section_size_type offset = this->offset(); const section_size_type oview_size @@ -3966,6 +4045,7 @@ Target_powerpc::make_iplt_section(Symbol_table* symtab, if (this->iplt_ == NULL) { this->make_plt_section(symtab, layout); + this->make_lplt_section(layout); Reloc_section* iplt_rel = new Reloc_section(false); if (this->rela_dyn_->output_section()) @@ -3978,6 +4058,40 @@ Target_powerpc::make_iplt_section(Symbol_table* symtab, } } +// Create the LPLT section. + +template +void +Target_powerpc::make_lplt_section(Layout* layout) +{ + if (this->lplt_ == NULL) + { + Reloc_section* lplt_rel = NULL; + if (parameters->options().output_is_position_independent()) + { + lplt_rel = new Reloc_section(false); + this->rela_dyn_section(layout); + if (this->rela_dyn_->output_section()) + this->rela_dyn_->output_section() + ->add_output_section_data(lplt_rel); + } + this->lplt_ + = new Output_data_plt_powerpc(this, lplt_rel, + "** LPLT"); + this->make_brlt_section(layout); + if (this->brlt_section_ && this->brlt_section_->output_section()) + this->brlt_section_->output_section() + ->add_output_section_data(this->lplt_); + else + layout->add_output_section_data(".branch_lt", + elfcpp::SHT_PROGBITS, + elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE, + this->lplt_, + ORDER_RELRO, + true); + } +} + // A section for huge long branch addresses, similar to plt section. template @@ -6132,6 +6246,20 @@ Target_powerpc::make_plt_entry(Symbol_table* symtab, } } +// Make a PLT entry for a local symbol. + +template +void +Target_powerpc::make_local_plt_entry( + Layout* layout, + Sized_relobj_file* relobj, + unsigned int r_sym) +{ + if (this->lplt_ == NULL) + this->make_lplt_section(layout); + this->lplt_->add_local_entry(relobj, r_sym); +} + // Make a PLT entry for a local STT_GNU_IFUNC symbol. template @@ -6669,6 +6797,17 @@ Target_powerpc::Scan::local( } break; + case elfcpp::R_POWERPC_PLT16_LO: + case elfcpp::R_POWERPC_PLT16_HI: + case elfcpp::R_POWERPC_PLT16_HA: + case elfcpp::R_PPC64_PLT16_LO_DS: + if (!is_ifunc) + { + unsigned int r_sym = elfcpp::elf_r_sym(reloc.get_r_info()); + target->make_local_plt_entry(layout, object, r_sym); + } + break; + case elfcpp::R_POWERPC_REL24: case elfcpp::R_PPC_PLTREL24: case elfcpp::R_PPC_LOCAL24PC: diff --git a/ld/ChangeLog b/ld/ChangeLog index 4e697a3b63..df36735103 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,13 @@ +2018-04-09 Alan Modra + + * emulparams/elf32ppc.sh (OTHER_RELRO_SECTIONS_2): Add .branch_lt. + (OTHER_GOT_RELOC_SECTIONS): Add .rela.branch_lt. + * testsuite/ld-powerpc/elfv2so.d: Update for symbol/stub reordering. + * testsuite/ld-powerpc/relbrlt.d: Likewise. + * testsuite/ld-powerpc/relbrlt.s: Likewise. + * testsuite/ld-powerpc/tlsso.r: Likewise. + * testsuite/ld-powerpc/tlstocso.r: Likewise. + 2018-04-09 Alan Modra * ppc32elf.em (ppc_finish): Call ppc_finish_symbols. diff --git a/ld/emulparams/elf32ppc.sh b/ld/emulparams/elf32ppc.sh index c3da11593a..477279c706 100644 --- a/ld/emulparams/elf32ppc.sh +++ b/ld/emulparams/elf32ppc.sh @@ -15,6 +15,10 @@ GOTPLT=".plt ${RELOCATING-0} : SPECIAL { *(.plt) }" PLT=".plt ${RELOCATING-0} : SPECIAL { *(.plt) } .iplt ${RELOCATING-0} : { *(.iplt) }" OTHER_TEXT_SECTIONS="*(.glink)" +OTHER_GOT_RELOC_SECTIONS=" + .rela.branch_lt ${RELOCATING-0} : { *(.rela.branch_lt) }" +OTHER_RELRO_SECTIONS_2=" + .branch_lt ${RELOCATING-0} :${RELOCATING+ ALIGN(4)} { *(.branch_lt) }" EXTRA_EM_FILE=ppc32elf if grep -q 'ld_elf32_spu_emulation' ldemul-list.h; then # crt1.o defines data_start and __data_start. Keep them first. diff --git a/ld/testsuite/ld-powerpc/elfv2so.d b/ld/testsuite/ld-powerpc/elfv2so.d index e7cd45c9c2..5f198a9691 100644 --- a/ld/testsuite/ld-powerpc/elfv2so.d +++ b/ld/testsuite/ld-powerpc/elfv2so.d @@ -14,16 +14,16 @@ Disassembly of section \.text: .*: (4e 80 04 20|20 04 80 4e) bctr \.\.\. -.* <.*\.plt_call\.f1>: +.* <.*\.plt_call\.f3>: .*: (f8 41 00 18|18 00 41 f8) std r2,24\(r1\) -.*: (e9 82 80 40|40 80 82 e9) ld r12,-32704\(r2\) +.*: (e9 82 80 28|28 80 82 e9) ld r12,-32728\(r2\) .*: (7d 89 03 a6|a6 03 89 7d) mtctr r12 .*: (4e 80 04 20|20 04 80 4e) bctr \.\.\. -.* <.*\.plt_call\.f3>: +.* <.*\.plt_call\.f1>: .*: (f8 41 00 18|18 00 41 f8) std r2,24\(r1\) -.*: (e9 82 80 28|28 80 82 e9) ld r12,-32728\(r2\) +.*: (e9 82 80 40|40 80 82 e9) ld r12,-32704\(r2\) .*: (7d 89 03 a6|a6 03 89 7d) mtctr r12 .*: (4e 80 04 20|20 04 80 4e) bctr \.\.\. @@ -41,12 +41,12 @@ Disassembly of section \.text: .*: (7c 08 02 a6|a6 02 08 7c) mflr r0 .*: (f8 21 ff e1|e1 ff 21 f8) stdu r1,-32\(r1\) .*: (f8 01 00 30|30 00 01 f8) std r0,48\(r1\) -.*: (4b ff ff 8d|8d ff ff 4b) bl .*\.plt_call\.f1> +.*: (4b ff ff ad|ad ff ff 4b) bl .*\.plt_call\.f1> .*: (e8 62 80 08|08 80 62 e8) ld r3,-32760\(r2\) .*: (4b ff ff c5|c5 ff ff 4b) bl .*\.plt_call\.f2> .*: (e8 41 00 18|18 00 41 e8) ld r2,24\(r1\) .*: (e8 62 80 10|10 80 62 e8) ld r3,-32752\(r2\) -.*: (4b ff ff 99|99 ff ff 4b) bl .*\.plt_call\.f3> +.*: (4b ff ff 79|79 ff ff 4b) bl .*\.plt_call\.f3> .*: (e8 41 00 18|18 00 41 e8) ld r2,24\(r1\) .*: (4b ff ff 51|51 ff ff 4b) bl .*\.plt_call\.f4> .*: (e8 41 00 18|18 00 41 e8) ld r2,24\(r1\) diff --git a/ld/testsuite/ld-powerpc/relbrlt.d b/ld/testsuite/ld-powerpc/relbrlt.d index 6f3db7d014..a00b1ffd0c 100644 --- a/ld/testsuite/ld-powerpc/relbrlt.d +++ b/ld/testsuite/ld-powerpc/relbrlt.d @@ -8,32 +8,32 @@ Disassembly of section \.text: 0*100000c0 <_start>: -[0-9a-f ]*: (49 bf 00 21|21 00 bf 49) bl .* +[0-9a-f ]*: (49 bf 00 2d|2d 00 bf 49) bl .* [0-9a-f ]*: R_PPC64_REL24 \.text\+0x37e003c [0-9a-f ]*: (60 00 00 00|00 00 00 60) nop -[0-9a-f ]*: (49 bf 00 1d|1d 00 bf 49) bl .* -[0-9a-f ]*: R_PPC64_REL24 \.text\+0x3bf002c +[0-9a-f ]*: (49 bf 00 19|19 00 bf 49) bl .* +[0-9a-f ]*: R_PPC64_REL24 \.text\+0x3bf0020 [0-9a-f ]*: (60 00 00 00|00 00 00 60) nop [0-9a-f ]*: (49 bf 00 21|21 00 bf 49) bl .* -[0-9a-f ]*: R_PPC64_REL24 \.text\+0x57e0030 +[0-9a-f ]*: R_PPC64_REL24 \.text\+0x57e0024 [0-9a-f ]*: (60 00 00 00|00 00 00 60) nop [0-9a-f ]*: 00 00 00 00 \.long 0x0 [0-9a-f ]*: (4b ff ff e4|e4 ff ff 4b) b .* <_start> \.\.\. -[0-9a-f ]*<.*long_branch.*>: -[0-9a-f ]*: (49 bf 00 1c|1c 00 bf 49) b .* -[0-9a-f ]*: R_PPC64_REL24 \*ABS\*\+0x137e00fc - [0-9a-f ]*<.*plt_branch.*>: -[0-9a-f ]*: (e9 82 80 f8|f8 80 82 e9) ld r12,-32520\(r2\) -[0-9a-f ]*: R_PPC64_TOC16_DS \*ABS\*\+0x157f00f8 +[0-9a-f ]*: (e9 82 80 e8|e8 80 82 e9) ld r12,-32536\(r2\) +[0-9a-f ]*: R_PPC64_TOC16_DS \*ABS\*\+0x157f00e8 [0-9a-f ]*: (7d 89 03 a6|a6 03 89 7d) mtctr r12 [0-9a-f ]*: (4e 80 04 20|20 04 80 4e) bctr +[0-9a-f ]*<.*long_branch.*>: +[0-9a-f ]*: (49 bf 00 10|10 00 bf 49) b .* +[0-9a-f ]*: R_PPC64_REL24 \*ABS\*\+0x137e00fc + [0-9a-f ]*<.*plt_branch.*>: -[0-9a-f ]*: (e9 82 81 00|00 81 82 e9) ld r12,-32512\(r2\) -[0-9a-f ]*: R_PPC64_TOC16_DS \*ABS\*\+0x157f0100 +[0-9a-f ]*: (e9 82 80 f0|f0 80 82 e9) ld r12,-32528\(r2\) +[0-9a-f ]*: R_PPC64_TOC16_DS \*ABS\*\+0x157f00f0 [0-9a-f ]*: (7d 89 03 a6|a6 03 89 7d) mtctr r12 [0-9a-f ]*: (4e 80 04 20|20 04 80 4e) bctr \.\.\. @@ -42,19 +42,19 @@ Disassembly of section \.text: [0-9a-f ]*: (4e 80 00 20|20 00 80 4e) blr \.\.\. -0*13bf00ec : +0*13bf00e0 : [0-9a-f ]*: (4e 80 00 20|20 00 80 4e) blr \.\.\. -0*157e00f0 : +0*157e00e4 : [0-9a-f ]*: (4e 80 00 20|20 00 80 4e) blr Disassembly of section \.branch_lt: -0*157f00f8 .*: -[0-9a-f ]*: (00 00 00 00|ec 00 bf 13) .* -[0-9a-f ]*: R_PPC64_RELATIVE \*ABS\*\+0x13bf00ec -[0-9a-f ]*: (13 bf 00 ec|00 00 00 00) .* -[0-9a-f ]*: (00 00 00 00|f0 00 7e 15) .* -[0-9a-f ]*: R_PPC64_RELATIVE \*ABS\*\+0x157e00f0 -[0-9a-f ]*: (15 7e 00 f0|00 00 00 00) .* +0*157f00e8 .*: +[0-9a-f ]*: (00 00 00 00|e0 00 bf 13) .* +[0-9a-f ]*: R_PPC64_RELATIVE \*ABS\*\+0x13bf00e0 +[0-9a-f ]*: (13 bf 00 e0|00 00 00 00) .* +[0-9a-f ]*: (00 00 00 00|e4 00 7e 15) .* +[0-9a-f ]*: R_PPC64_RELATIVE \*ABS\*\+0x157e00e4 +[0-9a-f ]*: (15 7e 00 e4|00 00 00 00) .* diff --git a/ld/testsuite/ld-powerpc/relbrlt.s b/ld/testsuite/ld-powerpc/relbrlt.s index fade6a281e..cee0cddfda 100644 --- a/ld/testsuite/ld-powerpc/relbrlt.s +++ b/ld/testsuite/ld-powerpc/relbrlt.s @@ -20,7 +20,7 @@ far: blr .section .text.pad2,"ax" - .space 0x40ffec + .space 0x40ffe0 .section .text.far2far,"ax" far2far: diff --git a/ld/testsuite/ld-powerpc/tlsso.r b/ld/testsuite/ld-powerpc/tlsso.r index 218a0ced25..5d349e58ab 100644 --- a/ld/testsuite/ld-powerpc/tlsso.r +++ b/ld/testsuite/ld-powerpc/tlsso.r @@ -114,8 +114,8 @@ Symbol table '\.symtab' contains [0-9]+ entries: .* TLS +LOCAL +DEFAULT +7 le5 .* FILE +LOCAL +DEFAULT +ABS .* OBJECT +LOCAL +DEFAULT +9 _DYNAMIC -.* NOTYPE +LOCAL +DEFAULT +6 .*\.plt_call\.__tls_get_addr .* NOTYPE +LOCAL +DEFAULT +6 __glink_PLTresolve +.* NOTYPE +LOCAL +DEFAULT +6 .*\.plt_call\.__tls_get_addr .* TLS +GLOBAL +DEFAULT +UND gd .* TLS +GLOBAL +DEFAULT +8 le0 .* NOTYPE +GLOBAL +DEFAULT +UND __tls_get_addr diff --git a/ld/testsuite/ld-powerpc/tlstocso.r b/ld/testsuite/ld-powerpc/tlstocso.r index 0296549f7b..f8922ee246 100644 --- a/ld/testsuite/ld-powerpc/tlstocso.r +++ b/ld/testsuite/ld-powerpc/tlstocso.r @@ -110,8 +110,8 @@ Symbol table '\.symtab' contains [0-9]+ entries: .* NOTYPE +LOCAL +DEFAULT +11 \.Lie0 .* FILE +LOCAL +DEFAULT +ABS .* OBJECT +LOCAL +DEFAULT +9 _DYNAMIC -.* NOTYPE +LOCAL +DEFAULT +6 .*\.plt_call\.__tls_get_addr .* NOTYPE +LOCAL +DEFAULT +6 __glink_PLTresolve +.* NOTYPE +LOCAL +DEFAULT +6 .*\.plt_call\.__tls_get_addr .* TLS +GLOBAL +DEFAULT +UND gd .* TLS +GLOBAL +DEFAULT +8 le0 .* NOTYPE +GLOBAL +DEFAULT +UND __tls_get_addr