diff options
author | Alan Modra <amodra@gmail.com> | 2018-04-09 09:21:10 +0930 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2018-04-09 16:56:35 +0930 |
commit | 08be322439408ac02cff2ac9b5eca4f7243a0277 (patch) | |
tree | 24c19e9a35be1c92da4eb362bebaf88ad62374a7 /bfd | |
parent | 37da22e5c85375b30e1211ecff1b261f425375f0 (diff) | |
download | gdb-08be322439408ac02cff2ac9b5eca4f7243a0277.zip gdb-08be322439408ac02cff2ac9b5eca4f7243a0277.tar.gz gdb-08be322439408ac02cff2ac9b5eca4f7243a0277.tar.bz2 |
PowerPC PLT16 relocations
The PowerPC64 ELFv2 ABI and the PowerPC SysV ABI support a number of
relocations that can be used to create and access a PLT entry.
However, the relocs are not well defined. The PLT16 family of relocs
talk about "the section offset or address of the procedure linkage
table entry". It's plain that we do need a relative address when PIC
as otherwise we'd have dynamic text relocations, but "section offset"
doesn't specify which section. The most obvious one, ".plt", isn't
that useful because there is no readily available way of addressing
the start of the ".plt" section. Much more useful would be "the
GOT/TOC-pointer relative offset of the procedure linkage table entry",
and I suppose you could argue that is a "section offset" of sorts.
For PowerPC64 it is better to use the same TOC-pointer relative
addressing even when non-PIC, since ".plt" may be located outside the
range of a 32-bit address. However, for ppc32 we do want an absolute
address when non-PIC as a GOT pointer may not be set up. Also, for
ppc32 PIC we have a similar situation to R_PPC_PLTREL24 in that the
GOT pointer is set to a location in the .got2 section and we need to
specify the .got2 offset in the PLT16 reloc addend.
This patch supports PLT16 relocations using these semantics. This is
not an ABI change for ppc32 since the relocations were not previously
supported by GNU ld, but is for ppc64 where some of the PLT16 relocs
were supported. I'm not particularly concerned since the old ppc64
PLT16 reloc semantics made them almost completely useless.
bfd/
* elf32-ppc.c (ppc_elf_check_relocs): Handle PLT16 relocs.
(ppc_elf_relocate_section): Likewise.
* elf64-ppc.c (ppc64_elf_check_relocs): Handle PLT16_LO_DS.
(ppc64_elf_relocate_section): Likewise. Correct PLT16
resolution to plt entry relative to toc pointer.
gold/
* powerpc.cc (Target_powerpc::plt_off): New functions.
(is_plt16_reloc): New function.
(Stub_table::plt_off): Use Target_powerpc::plt_off.
(Stub_table::plt_call_size): Use plt_off.
(Stub_table::do_write): Likewise.
(Target_powerpc::Scan::get_reference_flags): Return RELATIVE_REF
for PLT16 relocations.
(Target_powerpc::Scan::reloc_needs_plt_for_ifunc): Return true
for PLT16 relocations.
(Target_powerpc::Scan::global): Make a PLT entry for PLT16 relocations.
(Target_powerpc::Relocate::relocate): Support PLT16 relocations.
(Powerpc_scan_relocatable_reloc::global_strategy): Return RELOC_SPECIAL
for ppc32 plt16 relocs.
Diffstat (limited to 'bfd')
-rw-r--r-- | bfd/ChangeLog | 8 | ||||
-rw-r--r-- | bfd/elf32-ppc.c | 110 | ||||
-rw-r--r-- | bfd/elf64-ppc.c | 12 |
3 files changed, 111 insertions, 19 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 99f5639..cb65c7d 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,5 +1,13 @@ 2018-04-09 Alan Modra <amodra@gmail.com> + * elf32-ppc.c (ppc_elf_check_relocs): Handle PLT16 relocs. + (ppc_elf_relocate_section): Likewise. + * elf64-ppc.c (ppc64_elf_check_relocs): Handle PLT16_LO_DS. + (ppc64_elf_relocate_section): Likewise. Correct PLT16 + resolution to plt entry relative to toc pointer. + +2018-04-09 Alan Modra <amodra@gmail.com> + * elf64-ppc.c (TLS_TLS, TLS_GD, TLS_LD, TLS_TPREL, TLS_DTPREL, TLS_TPRELGD, TLS_EXPLICIT): Renumber. Test TLS_TLS throughout file when other TLS flags are tested in a mask. diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index 5377461..9736301 100644 --- a/bfd/elf32-ppc.c +++ b/bfd/elf32-ppc.c @@ -4056,15 +4056,20 @@ ppc_elf_check_relocs (bfd *abfd, In a non-pie executable even when there are no plt calls. */ if (!bfd_link_pic (info) - || is_branch_reloc (r_type)) + || is_branch_reloc (r_type) + || r_type == R_PPC_PLT16_LO + || r_type == R_PPC_PLT16_HI + || r_type == R_PPC_PLT16_HA) { bfd_vma addend = 0; if (r_type == R_PPC_PLTREL24) - { - ppc_elf_tdata (abfd)->makes_plt_call = 1; - if (bfd_link_pic (info)) - addend = rel->r_addend; - } + ppc_elf_tdata (abfd)->makes_plt_call = 1; + 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, ifunc, got2, addend)) return FALSE; } @@ -4277,7 +4282,9 @@ ppc_elf_check_relocs (bfd *abfd, case R_PPC_PLTREL24: if (h == NULL) break; + ppc_elf_tdata (abfd)->makes_plt_call = 1; /* Fall through */ + case R_PPC_PLT32: case R_PPC_PLTREL32: case R_PPC_PLT16_LO: @@ -4306,12 +4313,12 @@ ppc_elf_check_relocs (bfd *abfd, { bfd_vma addend = 0; - if (r_type == R_PPC_PLTREL24) - { - ppc_elf_tdata (abfd)->makes_plt_call = 1; - if (bfd_link_pic (info)) - addend = rel->r_addend; - } + 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; h->needs_plt = 1; if (!update_plt_info (abfd, &h->plt.plist, got2, addend)) return FALSE; @@ -7747,7 +7754,7 @@ ppc_elf_relocate_section (bfd *output_bfd, bfd_boolean unresolved_reloc; bfd_boolean warned; unsigned int tls_type, tls_mask, tls_gd; - struct plt_entry **ifunc; + struct plt_entry **ifunc, **plt_list; struct reloc_howto_struct alt_howto; again: @@ -8099,8 +8106,33 @@ ppc_elf_relocate_section (bfd *output_bfd, insn ^= BRANCH_PREDICT_BIT; bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - break; } + break; + + case R_PPC_PLT16_HA: + { + unsigned int insn; + + insn = bfd_get_32 (input_bfd, + contents + rel->r_offset - d_offset); + if ((insn & (0x3f << 26)) == 15u << 26 + && (insn & (0x1f << 16)) != 0) + { + if (!bfd_link_pic (info)) + { + /* Convert addis to lis. */ + insn &= ~(0x1f << 16); + bfd_put_32 (input_bfd, insn, + contents + rel->r_offset - d_offset); + } + } + else if (bfd_link_pic (info)) + info->callbacks->einfo + (_("%P: %H: error: %s with unexpected instruction %x\n"), + input_bfd, input_section, rel->r_offset, + "R_PPC_PLT16_HA", insn); + } + break; } if (ELIMINATE_COPY_RELOCS @@ -8239,10 +8271,17 @@ ppc_elf_relocate_section (bfd *output_bfd, ent = NULL; if (ifunc != NULL && (!bfd_link_pic (info) - || is_branch_reloc (r_type))) + || is_branch_reloc (r_type) + || r_type == R_PPC_PLT16_LO + || r_type == R_PPC_PLT16_HI + || r_type == R_PPC_PLT16_HA)) { addend = 0; - if (r_type == R_PPC_PLTREL24 && bfd_link_pic (info)) + 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; ent = find_plt_ent (ifunc, got2, addend); } @@ -9092,6 +9131,42 @@ ppc_elf_relocate_section (bfd *output_bfd, addend = 0; break; + case R_PPC_PLT16_LO: + case R_PPC_PLT16_HI: + case R_PPC_PLT16_HA: + plt_list = ifunc; + if (h != NULL) + plt_list = &h->plt.plist; + unresolved_reloc = TRUE; + if (plt_list != NULL) + { + struct plt_entry *ent; + + ent = find_plt_ent (plt_list, got2, + bfd_link_pic (info) ? addend : 0); + if (ent != NULL) + { + unresolved_reloc = FALSE; + relocation = (htab->elf.splt->output_section->vma + + htab->elf.splt->output_offset + + ent->plt.offset); + if (bfd_link_pic (info)) + { + bfd_vma got = 0; + + if (ent->addend >= 32768) + got = (ent->addend + + ent->sec->output_section->vma + + ent->sec->output_offset); + else + got = SYM_VAL (htab->elf.hgot); + relocation -= got; + } + } + } + addend = 0; + break; + /* Relocate against _SDA_BASE_. */ case R_PPC_SDAREL16: { @@ -9420,9 +9495,6 @@ ppc_elf_relocate_section (bfd *output_bfd, case R_PPC_IRELATIVE: case R_PPC_PLT32: case R_PPC_PLTREL32: - case R_PPC_PLT16_LO: - case R_PPC_PLT16_HI: - case R_PPC_PLT16_HA: case R_PPC_ADDR30: case R_PPC_EMB_RELSEC16: case R_PPC_EMB_RELST_LO: diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index 4226120..835baec 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -5623,6 +5623,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_PPC64_PLT16_HA: case R_PPC64_PLT16_HI: case R_PPC64_PLT16_LO: + case R_PPC64_PLT16_LO_DS: case R_PPC64_PLT32: case R_PPC64_PLT64: /* This symbol requires a procedure linkage table entry. */ @@ -14664,6 +14665,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_PLT16_HA: case R_PPC64_PLT16_HI: case R_PPC64_PLT16_LO: + case R_PPC64_PLT16_LO_DS: case R_PPC64_PLT32: case R_PPC64_PLT64: /* Relocation is to the entry for this symbol in the @@ -14690,12 +14692,22 @@ ppc64_elf_relocate_section (bfd *output_bfd, && ent->addend == orig_rel.r_addend) { asection *plt; + bfd_vma got; plt = htab->elf.splt; if (!htab->elf.dynamic_sections_created || h == NULL || h->elf.dynindx == -1) plt = htab->elf.iplt; + if (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) + { + got = (elf_gp (output_bfd) + + htab->sec_info[input_section->id].toc_off); + relocation -= got; + } relocation = (plt->output_section->vma + plt->output_offset + ent->plt.offset); |