diff options
-rw-r--r-- | bfd/ChangeLog | 24 | ||||
-rw-r--r-- | bfd/elf32-ppc.c | 148 | ||||
-rw-r--r-- | bfd/elf64-ppc.c | 206 | ||||
-rw-r--r-- | elfcpp/ChangeLog | 4 | ||||
-rw-r--r-- | elfcpp/powerpc.h | 2 | ||||
-rw-r--r-- | gold/ChangeLog | 8 | ||||
-rw-r--r-- | gold/powerpc.cc | 65 | ||||
-rw-r--r-- | include/ChangeLog | 5 | ||||
-rw-r--r-- | include/elf/ppc.h | 4 | ||||
-rw-r--r-- | include/elf/ppc64.h | 4 |
10 files changed, 424 insertions, 46 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 099d106..445eff0 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,5 +1,29 @@ 2018-04-09 Alan Modra <amodra@gmail.com> + * elf32-ppc.c (ppc_elf_howto_raw): Add PLTSEQ and PLTCALL howtos. + (is_plt_seq_reloc): New function. + (ppc_elf_check_relocs): Handle PLTSEQ and PLTCALL relocs. + (ppc_elf_tls_optimize): Handle inline plt call sequence. + (ppc_elf_relax_section): Handle PLTCALL reloc. + (ppc_elf_relocate_section): Nop out inline plt call sequence when + resolving locally. + * elf64-ppc.c (ppc64_elf_howto_raw): Add R_PPC64_PLTSEQ and + R_PPC64_PLTCALL entries. Comment R_PPC64_TOCSAVE. + (has_tls_get_addr_call): Correct comment. + (is_branch_reloc): Add PLTCALL. + (is_plt_seq_reloc): New function. + (ppc64_elf_check_relocs): Handle PLT16_LO_DS reloc. Set + has_tls_reloc for R_PPC64_TLSGD and R_PPC64_TLSLD. Create plt + entry for R_PPC64_PLTCALL. + (ppc64_elf_tls_optimize): Handle inline plt call sequence. + (ppc_type_of_stub): Handle PLTCALL reloc. + (toc_adjusting_stub_needed): Likewise. + (ppc64_elf_relocate_section): Set "can_plt_call" for PLTCALL + reloc insn. Nop out inline plt call sequence when resolving + locally. Handle __tls_get_addr inline plt call optimization. + +2018-04-09 Alan Modra <amodra@gmail.com> + * elf64-ppc.c (LOCAL_PLT_ENTRY_SIZE): Define. (struct ppc_stub_hash_entry): Add symtype field. (PLT_KEEP): Define. diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index 5da7230..36a01ee 100644 --- a/bfd/elf32-ppc.c +++ b/bfd/elf32-ppc.c @@ -818,6 +818,35 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 0, /* dst_mask */ FALSE), /* pcrel_offset */ + /* Marker relocs on inline plt call instructions. */ + HOWTO (R_PPC_PLTSEQ, + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_PLTSEQ", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_PPC_PLTCALL, + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_PLTCALL", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + FALSE), /* pcrel_offset */ + /* Computes the load module index of the load module that contains the definition of its TLS sym. */ HOWTO (R_PPC_DTPMOD32, @@ -3956,6 +3985,17 @@ is_branch_reloc (enum elf_ppc_reloc_type r_type) || r_type == R_PPC_VLE_REL24); } +/* Relocs on inline plt call sequence insns prior to the call. */ + +static bfd_boolean +is_plt_seq_reloc (enum elf_ppc_reloc_type r_type) +{ + return (r_type == R_PPC_PLT16_HA + || r_type == R_PPC_PLT16_HI + || r_type == R_PPC_PLT16_LO + || r_type == R_PPC_PLTSEQ); +} + static void bad_shared_reloc (bfd *abfd, enum elf_ppc_reloc_type r_type) { @@ -4131,6 +4171,9 @@ ppc_elf_check_relocs (bfd *abfd, return FALSE; break; + case R_PPC_PLTSEQ: + break; + case R_PPC_GOT_TLSLD16: case R_PPC_GOT_TLSLD16_LO: case R_PPC_GOT_TLSLD16_HI: @@ -4310,6 +4353,7 @@ ppc_elf_check_relocs (bfd *abfd, ppc_elf_tdata (abfd)->makes_plt_call = 1; /* Fall through */ + case R_PPC_PLTCALL: case R_PPC_PLT32: case R_PPC_PLTREL32: case R_PPC_PLT16_LO: @@ -5437,6 +5481,40 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, case R_PPC_TLSGD: case R_PPC_TLSLD: + if (rel + 1 < relend + && is_plt_seq_reloc (ELF32_R_TYPE (rel[1].r_info))) + { + if (pass != 0 + && ELF32_R_TYPE (rel[1].r_info) != R_PPC_PLTSEQ) + { + r_type = ELF32_R_TYPE (rel[1].r_info); + r_symndx = ELF32_R_SYM (rel[1].r_info); + if (r_symndx >= symtab_hdr->sh_info) + { + struct elf_link_hash_entry **sym_hashes; + + sym_hashes = elf_sym_hashes (ibfd); + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + if (h != NULL) + { + struct plt_entry *ent = NULL; + bfd_vma addend = 0; + + if (bfd_link_pic (info)) + addend = rel->r_addend; + ent = find_plt_ent (&h->plt.plist, + got2, addend); + if (ent != NULL + && ent->plt.refcount > 0) + ent->plt.refcount -= 1; + } + } + } + continue; + } expecting_tls_get_addr = 2; tls_set = 0; tls_clear = 0; @@ -5449,8 +5527,7 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, if (pass == 0) { if (!expecting_tls_get_addr - || (expecting_tls_get_addr == 1 - && !sec->has_tls_get_addr_call)) + || !sec->has_tls_get_addr_call) continue; if (rel + 1 < relend @@ -5511,7 +5588,8 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, bfd_vma addend = 0; if (bfd_link_pic (info) - && ELF32_R_TYPE (rel[1].r_info) == R_PPC_PLTREL24) + && (ELF32_R_TYPE (rel[1].r_info) == R_PPC_PLTREL24 + || ELF32_R_TYPE (rel[1].r_info) == R_PPC_PLTCALL)) addend = rel[1].r_addend; ent = find_plt_ent (&htab->tls_get_addr->plt.plist, got2, addend); @@ -7062,6 +7140,7 @@ ppc_elf_relax_section (bfd *abfd, case R_PPC_REL24: case R_PPC_LOCAL24PC: case R_PPC_PLTREL24: + case R_PPC_PLTCALL: max_branch_offset = 1 << 25; break; @@ -7890,7 +7969,7 @@ ppc_elf_relocate_section (bfd *output_bfd, unsigned long r_symndx; bfd_vma relocation; bfd_vma branch_bit, from; - bfd_boolean unresolved_reloc; + bfd_boolean unresolved_reloc, save_unresolved_reloc; bfd_boolean warned; unsigned int tls_type, tls_mask, tls_gd; struct plt_entry **ifunc, **plt_list; @@ -8160,6 +8239,13 @@ ppc_elf_relocate_section (bfd *output_bfd, unsigned int insn2; bfd_vma offset = rel->r_offset; + if (is_plt_seq_reloc (ELF32_R_TYPE (rel[1].r_info))) + { + bfd_put_32 (input_bfd, NOP, contents + offset); + rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE); + break; + } + if ((tls_mask & TLS_TPRELGD) != 0) { /* IE */ @@ -8187,6 +8273,13 @@ ppc_elf_relocate_section (bfd *output_bfd, { unsigned int insn2; + if (is_plt_seq_reloc (ELF32_R_TYPE (rel[1].r_info))) + { + bfd_put_32 (input_bfd, NOP, contents + rel->r_offset); + rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE); + break; + } + for (r_symndx = 0; r_symndx < symtab_hdr->sh_info; r_symndx++) @@ -8230,7 +8323,7 @@ ppc_elf_relocate_section (bfd *output_bfd, case R_PPC_ADDR14_BRNTAKEN: case R_PPC_REL14_BRNTAKEN: { - bfd_vma insn; + unsigned int insn; insn = bfd_get_32 (input_bfd, contents + rel->r_offset); insn &= ~BRANCH_PREDICT_BIT; @@ -8464,6 +8557,7 @@ ppc_elf_relocate_section (bfd *output_bfd, } addend = rel->r_addend; + save_unresolved_reloc = unresolved_reloc; howto = NULL; if (r_type < R_PPC_max) howto = ppc_elf_howto_table[r_type]; @@ -9244,6 +9338,8 @@ ppc_elf_relocate_section (bfd *output_bfd, addend = 0; break; + case R_PPC_PLTSEQ: + case R_PPC_PLTCALL: case R_PPC_PLT16_LO: case R_PPC_PLT16_HI: case R_PPC_PLT16_HA: @@ -9644,6 +9740,48 @@ ppc_elf_relocate_section (bfd *output_bfd, goto copy_reloc; } + switch (r_type) + { + default: + break; + + case R_PPC_PLTCALL: + if (unresolved_reloc) + { + bfd_byte *p = contents + rel->r_offset; + unsigned int insn = bfd_get_32 (input_bfd, p); + insn &= 1; + bfd_put_32 (input_bfd, B | insn, p); + unresolved_reloc = save_unresolved_reloc; + r_type = R_PPC_REL24; + howto = ppc_elf_howto_table[r_type]; + } + else if (htab->plt_type != PLT_NEW) + info->callbacks->einfo + (_("%P: %H: %s relocation unsupported for bss-plt\n"), + input_bfd, input_section, rel->r_offset, + howto->name); + break; + + case R_PPC_PLTSEQ: + case R_PPC_PLT16_HA: + case R_PPC_PLT16_LO: + if (unresolved_reloc) + { + bfd_byte *p = contents + (rel->r_offset & ~3); + bfd_put_32 (input_bfd, NOP, p); + unresolved_reloc = FALSE; + r_type = R_PPC_NONE; + howto = ppc_elf_howto_table[r_type]; + } + else if (htab->plt_type != PLT_NEW) + info->callbacks->einfo + (_("%P: %H: %s relocation unsupported for bss-plt\n"), + input_bfd, input_section, rel->r_offset, + howto->name); + break; + } + /* Do any further special processing. */ switch (r_type) { diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index 4ea6a9e..9472f7b 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -1336,6 +1336,8 @@ static reloc_howto_type ppc64_elf_howto_raw[] = 0, /* dst_mask */ FALSE), /* pcrel_offset */ + /* Marker reloc for optimizing r2 save in prologue rather than on + each plt call stub. */ HOWTO (R_PPC64_TOCSAVE, 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ @@ -1350,6 +1352,35 @@ static reloc_howto_type ppc64_elf_howto_raw[] = 0, /* dst_mask */ FALSE), /* pcrel_offset */ + /* Marker relocs on inline plt call instructions. */ + HOWTO (R_PPC64_PLTSEQ, + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC64_PLTSEQ", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_PPC64_PLTCALL, + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC64_PLTCALL", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + FALSE), /* pcrel_offset */ + /* Computes the load module index of the load module that contains the definition of its TLS sym. */ HOWTO (R_PPC64_DTPMOD64, @@ -4187,7 +4218,7 @@ struct ppc_link_hash_table /* Nonzero if this section has TLS related relocations. */ #define has_tls_reloc sec_flg0 -/* Nonzero if this section has a call to __tls_get_addr. */ +/* Nonzero if this section has an old-style call to __tls_get_addr. */ #define has_tls_get_addr_call sec_flg1 /* Nonzero if this section has any toc or got relocs. */ @@ -5430,7 +5461,20 @@ is_branch_reloc (enum elf_ppc64_reloc_type r_type) || r_type == R_PPC64_ADDR24 || r_type == R_PPC64_ADDR14 || r_type == R_PPC64_ADDR14_BRTAKEN - || r_type == R_PPC64_ADDR14_BRNTAKEN); + || r_type == R_PPC64_ADDR14_BRNTAKEN + || r_type == R_PPC64_PLTCALL); +} + +/* Relocs on inline plt call sequence insns prior to the call. */ + +static bfd_boolean +is_plt_seq_reloc (enum elf_ppc64_reloc_type r_type) +{ + return (r_type == R_PPC64_PLT16_HA + || r_type == R_PPC64_PLT16_HI + || r_type == R_PPC64_PLT16_LO + || r_type == R_PPC64_PLT16_LO_DS + || r_type == R_PPC64_PLTSEQ); } /* Look through the relocs for a section during the first phase, and @@ -5777,6 +5821,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, /* Fall through. */ case R_PPC64_REL24: + case R_PPC64_PLTCALL: plt_list = ifunc; if (h != NULL) { @@ -8583,6 +8628,33 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) case R_PPC64_TLSGD: case R_PPC64_TLSLD: + if (rel + 1 < relend + && is_plt_seq_reloc (ELF64_R_TYPE (rel[1].r_info))) + { + if (pass != 0 + && ELF64_R_TYPE (rel[1].r_info) != R_PPC64_PLTSEQ) + { + r_symndx = ELF64_R_SYM (rel[1].r_info); + if (!get_sym_h (&h, NULL, NULL, NULL, &locsyms, + r_symndx, ibfd)) + goto err_free_rel; + if (h != NULL) + { + struct plt_entry *ent = NULL; + + for (ent = h->plt.plist; + ent != NULL; + ent = ent->next) + if (ent->addend == rel[1].r_addend) + break; + + if (ent != NULL + && ent->plt.refcount > 0) + ent->plt.refcount -= 1; + } + } + continue; + } found_tls_get_addr_arg = 1; /* Fall through. */ @@ -8736,35 +8808,27 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) != (TLS_TLS | TLS_MARK))) continue; - if (expecting_tls_get_addr && htab->tls_get_addr != NULL) + if (expecting_tls_get_addr) { - struct plt_entry *ent; - for (ent = htab->tls_get_addr->elf.plt.plist; - ent != NULL; - ent = ent->next) - if (ent->addend == 0) - { - if (ent->plt.refcount > 0) - { - ent->plt.refcount -= 1; - expecting_tls_get_addr = 0; - } + struct plt_entry *ent = NULL; + + if (htab->tls_get_addr != NULL) + for (ent = htab->tls_get_addr->elf.plt.plist; + ent != NULL; + ent = ent->next) + if (ent->addend == 0) break; - } - } - if (expecting_tls_get_addr && htab->tls_get_addr_fd != NULL) - { - struct plt_entry *ent; - for (ent = htab->tls_get_addr_fd->elf.plt.plist; - ent != NULL; - ent = ent->next) - if (ent->addend == 0) - { - if (ent->plt.refcount > 0) - ent->plt.refcount -= 1; + if (ent == NULL && htab->tls_get_addr_fd != NULL) + for (ent = htab->tls_get_addr_fd->elf.plt.plist; + ent != NULL; + ent = ent->next) + if (ent->addend == 0) break; - } + + if (ent != NULL + && ent->plt.refcount > 0) + ent->plt.refcount -= 1; } if (tls_clear == 0) @@ -10504,7 +10568,9 @@ ppc_type_of_stub (asection *input_sec, /* Determine if a long branch stub is needed. */ max_branch_offset = 1 << 25; - if (r_type != R_PPC64_REL24) + if (r_type == R_PPC64_REL14 + || r_type == R_PPC64_REL14_BRTAKEN + || r_type == R_PPC64_REL14_BRNTAKEN) max_branch_offset = 1 << 15; if (branch_offset + max_branch_offset >= 2 * max_branch_offset - local_off) @@ -11911,7 +11977,8 @@ toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec) if (r_type != R_PPC64_REL24 && r_type != R_PPC64_REL14 && r_type != R_PPC64_REL14_BRTAKEN - && r_type != R_PPC64_REL14_BRNTAKEN) + && r_type != R_PPC64_REL14_BRNTAKEN + && r_type != R_PPC64_PLTCALL) continue; r_symndx = ELF64_R_SYM (rel->r_info); @@ -13721,7 +13788,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, unsigned char tls_mask, tls_gd, tls_type; unsigned char sym_type; bfd_vma relocation; - bfd_boolean unresolved_reloc; + bfd_boolean unresolved_reloc, save_unresolved_reloc; bfd_boolean warned; enum { DEST_NORMAL, DEST_OPD, DEST_STUB } reloc_dest; unsigned int insn; @@ -14190,6 +14257,16 @@ ppc64_elf_relocate_section (bfd *output_bfd, unsigned int insn2; bfd_vma offset = rel->r_offset; + if (is_plt_seq_reloc (ELF64_R_TYPE (rel[1].r_info))) + { + bfd_put_32 (output_bfd, NOP, contents + offset); + rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE); + break; + } + + if (ELF64_R_TYPE (rel[1].r_info) == R_PPC64_PLTCALL) + bfd_put_32 (output_bfd, NOP, contents + offset + 4); + if ((tls_mask & TLS_TPRELGD) != 0) { /* IE */ @@ -14225,6 +14302,16 @@ ppc64_elf_relocate_section (bfd *output_bfd, unsigned int insn2; bfd_vma offset = rel->r_offset; + if (is_plt_seq_reloc (ELF64_R_TYPE (rel[1].r_info))) + { + bfd_put_32 (output_bfd, NOP, contents + offset); + rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE); + break; + } + + if (ELF64_R_TYPE (rel[1].r_info) == R_PPC64_PLTCALL) + bfd_put_32 (output_bfd, NOP, contents + offset + 4); + if (toc_symndx) sec = local_sections[toc_symndx]; for (r_symndx = 0; @@ -14416,6 +14503,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, /* Fall through. */ case R_PPC64_REL24: + case R_PPC64_PLTCALL: /* Calls to functions with a different TOC, such as calls to shared objects, need to alter the TOC pointer. This is done using a linkage stub. A REL24 branching to these @@ -14429,6 +14517,12 @@ ppc64_elf_relocate_section (bfd *output_bfd, fdh = ppc_follow_link (h->oh); stub_entry = ppc_get_stub_entry (input_section, sec, fdh, &orig_rel, htab); + if (r_type == R_PPC64_PLTCALL + && stub_entry != NULL + && (stub_entry->stub_type == ppc_stub_plt_call + || stub_entry->stub_type == ppc_stub_plt_call_r2save)) + stub_entry = NULL; + if (stub_entry != NULL && (stub_entry->stub_type == ppc_stub_plt_call || stub_entry->stub_type == ppc_stub_plt_call_r2save @@ -14461,8 +14555,11 @@ ppc64_elf_relocate_section (bfd *output_bfd, nop = bfd_get_32 (input_bfd, contents + rel->r_offset + 4); - if (nop == NOP - || nop == CROR_151515 || nop == CROR_313131) + if (nop == LD_R2_0R1 + STK_TOC (htab)) + can_plt_call = TRUE; + else if (nop == NOP + || nop == CROR_151515 + || nop == CROR_313131) { if (h != NULL && (h == htab->tls_get_addr_fd @@ -14656,6 +14753,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, /* Set `addend'. */ tls_type = 0; + save_unresolved_reloc = unresolved_reloc; switch (r_type) { default: @@ -14914,8 +15012,11 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_PLT16_LO_DS: case R_PPC64_PLT32: case R_PPC64_PLT64: + case R_PPC64_PLTSEQ: + case R_PPC64_PLTCALL: /* Relocation is to the entry for this symbol in the procedure linkage table. */ + unresolved_reloc = TRUE; { struct plt_entry **plt_list = NULL; if (h != NULL) @@ -15368,6 +15469,35 @@ ppc64_elf_relocate_section (bfd *output_bfd, insn. */ break; + case R_PPC64_PLTCALL: + if (unresolved_reloc) + { + /* No plt entry. Make this into a direct call. */ + bfd_byte *p = contents + rel->r_offset; + insn = bfd_get_32 (input_bfd, p); + insn &= 1; + bfd_put_32 (input_bfd, B_DOT | insn, p); + bfd_put_32 (input_bfd, NOP, p + 4); + unresolved_reloc = save_unresolved_reloc; + r_type = R_PPC64_REL24; + } + break; + + case R_PPC64_PLTSEQ: + if (unresolved_reloc) + { + unresolved_reloc = FALSE; + goto nop_it; + } + break; + + case R_PPC64_PLT16_HA: + if (unresolved_reloc) + { + unresolved_reloc = FALSE; + goto nop_it; + } + /* Fall through. */ case R_PPC64_GOT_TLSLD16_HA: case R_PPC64_GOT_TLSGD16_HA: case R_PPC64_GOT_TPREL16_HA: @@ -15377,12 +15507,22 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (htab->do_toc_opt && relocation + addend + 0x8000 < 0x10000 && !ppc64_elf_tdata (input_bfd)->unexpected_toc_insn) { - bfd_byte *p = contents + (rel->r_offset & ~3); + bfd_byte *p; + nop_it: + p = contents + (rel->r_offset & ~3); bfd_put_32 (input_bfd, NOP, p); goto copy_reloc; } break; + case R_PPC64_PLT16_LO: + case R_PPC64_PLT16_LO_DS: + if (unresolved_reloc) + { + unresolved_reloc = FALSE; + goto nop_it; + } + /* Fall through. */ case R_PPC64_GOT_TLSLD16_LO: case R_PPC64_GOT_TLSGD16_LO: case R_PPC64_GOT_TPREL16_LO_DS: diff --git a/elfcpp/ChangeLog b/elfcpp/ChangeLog index 776908f..7c4a514 100644 --- a/elfcpp/ChangeLog +++ b/elfcpp/ChangeLog @@ -1,3 +1,7 @@ +2018-04-09 Alan Modra <amodra@gmail.com> + + * powerpc.h (R_POWERPC_PLTSEQ, R_POWERPC_PLTCALL): Define. + 2018-03-28 Cary Coutant <ccoutant@gmail.com> PR gold/22969 diff --git a/elfcpp/powerpc.h b/elfcpp/powerpc.h index c4e993e..71de459 100644 --- a/elfcpp/powerpc.h +++ b/elfcpp/powerpc.h @@ -179,6 +179,8 @@ enum R_PPC64_REL24_NOTOC = 116, R_PPC64_ADDR64_LOCAL = 117, R_PPC64_ENTRY = 118, + R_POWERPC_PLTSEQ = 119, + R_POWERPC_PLTCALL = 120, R_PPC_VLE_REL8 = 216, R_PPC_VLE_REL15 = 217, diff --git a/gold/ChangeLog b/gold/ChangeLog index bb30237..4ae7f7c 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,5 +1,13 @@ 2018-04-09 Alan Modra <amodra@gmail.com> + * powerpc.cc (Target_powerpc::Track_tls::maybe_skip_tls_get_addr_call): + Handle inline plt sequence relocs. + (Stub_table::Plt_stub_key::Plt_stub_key): Likewise. + (Target_powerpc::Scan::reloc_needs_plt_for_ifunc): Likewise. + (Target_powerpc::Relocate::relocate): Likewise. + +2018-04-09 Alan Modra <amodra@gmail.com> + * powerpc.cc (Target_powerpc::lplt_): New variable. (Target_powerpc::lplt_section): Associated accessor. (Target_powerpc::plt_off): Handle local non-ifunc symbols. diff --git a/gold/powerpc.cc b/gold/powerpc.cc index c3f1b23..314eaa7 100644 --- a/gold/powerpc.cc +++ b/gold/powerpc.cc @@ -78,8 +78,10 @@ struct Stub_table_owner const Output_section::Input_section* owner; }; -inline bool -is_branch_reloc(unsigned int r_type); +inline bool is_branch_reloc(unsigned int); + +template<int size> +inline bool is_plt16_reloc(unsigned int); // Counter incremented on every Powerpc_relobj constructed. static uint32_t object_id = 0; @@ -1211,7 +1213,10 @@ class Target_powerpc : public Sized_target<size, big_endian> unsigned int r_type, const Symbol* gsym) { bool is_tls_call = ((r_type == elfcpp::R_POWERPC_REL24 - || r_type == elfcpp::R_PPC_PLTREL24) + || r_type == elfcpp::R_PPC_PLTREL24 + || is_plt16_reloc<size>(r_type) + || r_type == elfcpp::R_POWERPC_PLTSEQ + || r_type == elfcpp::R_POWERPC_PLTCALL) && gsym != NULL && (gsym == target->tls_get_addr() || gsym == target->tls_get_addr_opt())); @@ -4651,7 +4656,8 @@ class Stub_table : public Output_relaxed_input_section if (size != 32) this->addend_ = addend; else if (parameters->options().output_is_position_independent() - && r_type == elfcpp::R_PPC_PLTREL24) + && (r_type == elfcpp::R_PPC_PLTREL24 + || r_type == elfcpp::R_POWERPC_PLTCALL)) { this->addend_ = addend; if (this->addend_ >= 32768) @@ -4668,7 +4674,8 @@ class Stub_table : public Output_relaxed_input_section if (size != 32) this->addend_ = addend; else if (parameters->options().output_is_position_independent() - && r_type == elfcpp::R_PPC_PLTREL24) + && (r_type == elfcpp::R_PPC_PLTREL24 + || r_type == elfcpp::R_POWERPC_PLTCALL)) this->addend_ = addend; } @@ -6569,6 +6576,8 @@ Target_powerpc<size, big_endian>::Scan::reloc_needs_plt_for_ifunc( case elfcpp::R_POWERPC_PLT16_HI: case elfcpp::R_POWERPC_PLT16_HA: case elfcpp::R_PPC64_PLT16_LO_DS: + case elfcpp::R_POWERPC_PLTSEQ: + case elfcpp::R_POWERPC_PLTCALL: return true; break; @@ -6706,6 +6715,8 @@ Target_powerpc<size, big_endian>::Scan::local( case elfcpp::R_POWERPC_GNU_VTENTRY: case elfcpp::R_POWERPC_TLS: case elfcpp::R_PPC64_ENTRY: + case elfcpp::R_POWERPC_PLTSEQ: + case elfcpp::R_POWERPC_PLTCALL: break; case elfcpp::R_PPC64_TOC: @@ -7266,6 +7277,8 @@ Target_powerpc<size, big_endian>::Scan::global( case elfcpp::R_PPC_LOCAL24PC: case elfcpp::R_POWERPC_TLS: case elfcpp::R_PPC64_ENTRY: + case elfcpp::R_POWERPC_PLTSEQ: + case elfcpp::R_POWERPC_PLTCALL: break; case elfcpp::R_PPC64_TOC: @@ -8495,6 +8508,10 @@ Target_powerpc<size, big_endian>::Relocate::relocate( Address address, section_size_type view_size) { + typedef Powerpc_relocate_functions<size, big_endian> Reloc; + typedef typename elfcpp::Swap<32, big_endian>::Valtype Insn; + typedef typename elfcpp::Rela<size, big_endian> Reltype; + if (view == NULL) return true; @@ -8513,14 +8530,22 @@ Target_powerpc<size, big_endian>::Relocate::relocate( // We have already complained. break; case Track_tls::SKIP: + if (is_plt16_reloc<size>(r_type) + || r_type == elfcpp::R_POWERPC_PLTSEQ) + { + Insn* iview = reinterpret_cast<Insn*>(view); + elfcpp::Swap<32, big_endian>::writeval(iview, nop); + } + else if (size == 64 && r_type == elfcpp::R_POWERPC_PLTCALL) + { + Insn* iview = reinterpret_cast<Insn*>(view); + elfcpp::Swap<32, big_endian>::writeval(iview + 1, nop); + } return true; case Track_tls::NORMAL: break; } - typedef Powerpc_relocate_functions<size, big_endian> Reloc; - typedef typename elfcpp::Swap<32, big_endian>::Valtype Insn; - typedef typename elfcpp::Rela<size, big_endian> Reltype; // Offset from start of insn to d-field reloc. const int d_offset = big_endian ? 2 : 0; @@ -8536,6 +8561,8 @@ Target_powerpc<size, big_endian>::Relocate::relocate( : object->local_has_plt_offset(r_sym)); if (has_plt_offset && !is_plt16_reloc<size>(r_type) + && r_type != elfcpp::R_POWERPC_PLTSEQ + && r_type != elfcpp::R_POWERPC_PLTCALL && (!psymval->is_ifunc_symbol() || Scan::reloc_needs_plt_for_ifunc(target, object, r_type, false))) { @@ -8633,6 +8660,14 @@ Target_powerpc<size, big_endian>::Relocate::relocate( + target->got_section()->g_o_t()); } } + else if (!has_plt_offset + && (is_plt16_reloc<size>(r_type) + || r_type == elfcpp::R_POWERPC_PLTSEQ)) + { + Insn* iview = reinterpret_cast<Insn*>(view); + elfcpp::Swap<32, big_endian>::writeval(iview, nop); + r_type = elfcpp::R_POWERPC_NONE; + } else if (r_type == elfcpp::R_POWERPC_GOT16 || r_type == elfcpp::R_POWERPC_GOT16_LO || r_type == elfcpp::R_POWERPC_GOT16_HI @@ -8969,6 +9004,18 @@ Target_powerpc<size, big_endian>::Relocate::relocate( } else if (!has_stub_value) { + if (!has_plt_offset && r_type == elfcpp::R_POWERPC_PLTCALL) + { + // PLTCALL without plt entry => convert to direct call + Insn* iview = reinterpret_cast<Insn*>(view); + Insn insn = elfcpp::Swap<32, big_endian>::readval(iview); + insn = (insn & 1) | b; + elfcpp::Swap<32, big_endian>::writeval(iview, insn); + if (size == 32) + r_type = elfcpp::R_PPC_PLTREL24; + else + r_type = elfcpp::R_POWERPC_REL24; + } Address addend = 0; if (!(size == 32 && (r_type == elfcpp::R_PPC_PLTREL24 @@ -9498,6 +9545,8 @@ Target_powerpc<size, big_endian>::Relocate::relocate( case elfcpp::R_POWERPC_TLS: case elfcpp::R_POWERPC_GNU_VTINHERIT: case elfcpp::R_POWERPC_GNU_VTENTRY: + case elfcpp::R_POWERPC_PLTSEQ: + case elfcpp::R_POWERPC_PLTCALL: break; case elfcpp::R_PPC64_ADDR64: diff --git a/include/ChangeLog b/include/ChangeLog index 167ba03..74e6a53 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,8 @@ +2018-04-09 Alan Modra <amodra@gmail.com> + + * elf/ppc.h (R_PPC_PLTSEQ, R_PPC_PLTCALL): Define. + * elf/ppc64.h (R_PPC64_PLTSEQ, R_PPC64_PLTCALL): Define. + 2018-03-28 Renlin Li <renlin.li@arm.com> PR ld/22970 diff --git a/include/elf/ppc.h b/include/elf/ppc.h index 3de200c..c48733e 100644 --- a/include/elf/ppc.h +++ b/include/elf/ppc.h @@ -134,6 +134,10 @@ START_RELOC_NUMBERS (elf_ppc_reloc_type) RELOC_NUMBER (R_PPC_EMB_BIT_FLD, 115) RELOC_NUMBER (R_PPC_EMB_RELSDA, 116) +/* Marker reloc for inline plt call insns. */ + RELOC_NUMBER (R_PPC_PLTSEQ, 119) + RELOC_NUMBER (R_PPC_PLTCALL, 120) + /* PowerPC VLE relocations. */ RELOC_NUMBER (R_PPC_VLE_REL8, 216) RELOC_NUMBER (R_PPC_VLE_REL15, 217) diff --git a/include/elf/ppc64.h b/include/elf/ppc64.h index 04a7432..501aebc 100644 --- a/include/elf/ppc64.h +++ b/include/elf/ppc64.h @@ -154,6 +154,10 @@ START_RELOC_NUMBERS (elf_ppc64_reloc_type) RELOC_NUMBER (R_PPC64_ADDR64_LOCAL, 117) RELOC_NUMBER (R_PPC64_ENTRY, 118) +/* Marker reloc for inline plt call insns. */ + RELOC_NUMBER (R_PPC64_PLTSEQ, 119) + RELOC_NUMBER (R_PPC64_PLTCALL, 120) + #ifndef RELOC_MACROS_GEN_FUNC /* Relocation only used internally by ld. If you need to use these reloc numbers, you can change them to some other unused value |