mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-27 03:51:15 +08:00
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.
This commit is contained in:
parent
37da22e5c8
commit
08be322439
@ -1,3 +1,11 @@
|
||||
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,
|
||||
|
110
bfd/elf32-ppc.c
110
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:
|
||||
|
@ -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);
|
||||
|
@ -1,3 +1,19 @@
|
||||
2018-04-09 Alan Modra <amodra@gmail.com>
|
||||
|
||||
* 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.
|
||||
|
||||
2018-04-06 Cary Coutant <ccoutant@gmail.com>
|
||||
|
||||
* object.cc (Sized_relobj_file::include_section_group): Store
|
||||
|
191
gold/powerpc.cc
191
gold/powerpc.cc
@ -860,6 +860,29 @@ class Target_powerpc : public Sized_target<size, big_endian>
|
||||
return this->iplt_;
|
||||
}
|
||||
|
||||
// Return the plt offset and section for the given global sym.
|
||||
Address
|
||||
plt_off(const Symbol* gsym,
|
||||
const Output_data_plt_powerpc<size, big_endian>** sec) const
|
||||
{
|
||||
if (gsym->type() == elfcpp::STT_GNU_IFUNC
|
||||
&& gsym->can_use_relative_reloc(false))
|
||||
*sec = this->iplt_section();
|
||||
else
|
||||
*sec = this->plt_section();
|
||||
return gsym->plt_offset();
|
||||
}
|
||||
|
||||
// Return the plt offset and section for the given local sym.
|
||||
Address
|
||||
plt_off(const Sized_relobj_file<size, big_endian>* relobj,
|
||||
unsigned int local_sym_index,
|
||||
const Output_data_plt_powerpc<size, big_endian>** sec) const
|
||||
{
|
||||
*sec = this->iplt_section();
|
||||
return relobj->local_plt_offset(local_sym_index);
|
||||
}
|
||||
|
||||
// Get the .glink section.
|
||||
const Output_data_glink<size, big_endian>*
|
||||
glink_section() const
|
||||
@ -1730,6 +1753,17 @@ is_branch_reloc(unsigned int r_type)
|
||||
|| r_type == elfcpp::R_POWERPC_ADDR14_BRNTAKEN);
|
||||
}
|
||||
|
||||
// Reloc resolves to plt entry.
|
||||
template<int size>
|
||||
inline bool
|
||||
is_plt16_reloc(unsigned int r_type)
|
||||
{
|
||||
return (r_type == elfcpp::R_POWERPC_PLT16_LO
|
||||
|| r_type == elfcpp::R_POWERPC_PLT16_HI
|
||||
|| r_type == elfcpp::R_POWERPC_PLT16_HA
|
||||
|| (size == 64 && r_type == elfcpp::R_PPC64_PLT16_LO_DS));
|
||||
}
|
||||
|
||||
// If INSN is an opcode that may be used with an @tls operand, return
|
||||
// the transformed insn for TLS optimisation, otherwise return 0. If
|
||||
// REG is non-zero only match an insn with RB or RA equal to REG.
|
||||
@ -4408,21 +4442,17 @@ class Stub_table : public Output_relaxed_input_section
|
||||
|
||||
// Return the plt offset for the given call stub.
|
||||
Address
|
||||
plt_off(typename Plt_stub_entries::const_iterator p, bool* is_iplt) const
|
||||
plt_off(typename Plt_stub_entries::const_iterator p,
|
||||
const Output_data_plt_powerpc<size, big_endian>** sec) const
|
||||
{
|
||||
const Symbol* gsym = p->first.sym_;
|
||||
if (gsym != NULL)
|
||||
{
|
||||
*is_iplt = (gsym->type() == elfcpp::STT_GNU_IFUNC
|
||||
&& gsym->can_use_relative_reloc(false));
|
||||
return gsym->plt_offset();
|
||||
}
|
||||
return this->targ_->plt_off(gsym, sec);
|
||||
else
|
||||
{
|
||||
*is_iplt = true;
|
||||
const Sized_relobj_file<size, big_endian>* relobj = p->first.object_;
|
||||
unsigned int local_sym_index = p->first.locsym_;
|
||||
return relobj->local_plt_offset(local_sym_index);
|
||||
return this->targ_->plt_off(relobj, local_sym_index, sec);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4437,12 +4467,9 @@ class Stub_table : public Output_relaxed_input_section
|
||||
+ (this->targ_->is_tls_get_addr_opt(gsym) ? 8 * 4 : 0));
|
||||
}
|
||||
|
||||
bool is_iplt;
|
||||
Address plt_addr = this->plt_off(p, &is_iplt);
|
||||
if (is_iplt)
|
||||
plt_addr += this->targ_->iplt_section()->address();
|
||||
else
|
||||
plt_addr += this->targ_->plt_section()->address();
|
||||
const Output_data_plt_powerpc<size, big_endian>* plt;
|
||||
Address plt_addr = this->plt_off(p, &plt);
|
||||
plt_addr += plt->address();
|
||||
Address got_addr = this->targ_->got_section()->output_section()->address();
|
||||
const Powerpc_relobj<size, big_endian>* ppcobj = static_cast
|
||||
<const Powerpc_relobj<size, big_endian>*>(p->first.object_);
|
||||
@ -5158,27 +5185,15 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
|
||||
|
||||
if (!this->plt_call_stubs_.empty())
|
||||
{
|
||||
// The base address of the .plt section.
|
||||
Address plt_base = this->targ_->plt_section()->address();
|
||||
Address iplt_base = invalid_address;
|
||||
|
||||
// Write out plt call stubs.
|
||||
typename Plt_stub_entries::const_iterator cs;
|
||||
for (cs = this->plt_call_stubs_.begin();
|
||||
cs != this->plt_call_stubs_.end();
|
||||
++cs)
|
||||
{
|
||||
bool is_iplt;
|
||||
Address pltoff = this->plt_off(cs, &is_iplt);
|
||||
Address plt_addr = pltoff;
|
||||
if (is_iplt)
|
||||
{
|
||||
if (iplt_base == invalid_address)
|
||||
iplt_base = this->targ_->iplt_section()->address();
|
||||
plt_addr += iplt_base;
|
||||
}
|
||||
else
|
||||
plt_addr += plt_base;
|
||||
const Output_data_plt_powerpc<size, big_endian>* plt;
|
||||
Address pltoff = this->plt_off(cs, &plt);
|
||||
Address plt_addr = pltoff + plt->address();
|
||||
const Powerpc_relobj<size, big_endian>* ppcobj = static_cast
|
||||
<const Powerpc_relobj<size, big_endian>*>(cs->first.object_);
|
||||
Address got_addr = got_os_addr + ppcobj->toc_base_offset();
|
||||
@ -5397,9 +5412,6 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
|
||||
{
|
||||
if (!this->plt_call_stubs_.empty())
|
||||
{
|
||||
// The base address of the .plt section.
|
||||
Address plt_base = this->targ_->plt_section()->address();
|
||||
Address iplt_base = invalid_address;
|
||||
// The address of _GLOBAL_OFFSET_TABLE_.
|
||||
Address g_o_t = invalid_address;
|
||||
|
||||
@ -5409,16 +5421,9 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
|
||||
cs != this->plt_call_stubs_.end();
|
||||
++cs)
|
||||
{
|
||||
bool is_iplt;
|
||||
Address plt_addr = this->plt_off(cs, &is_iplt);
|
||||
if (is_iplt)
|
||||
{
|
||||
if (iplt_base == invalid_address)
|
||||
iplt_base = this->targ_->iplt_section()->address();
|
||||
plt_addr += iplt_base;
|
||||
}
|
||||
else
|
||||
plt_addr += plt_base;
|
||||
const Output_data_plt_powerpc<size, big_endian>* plt;
|
||||
Address plt_addr = this->plt_off(cs, &plt);
|
||||
plt_addr += plt->address();
|
||||
|
||||
p = oview + cs->second.off_;
|
||||
const Symbol* gsym = cs->first.sym_;
|
||||
@ -6244,6 +6249,10 @@ Target_powerpc<size, big_endian>::Scan::get_reference_flags(
|
||||
case elfcpp::R_PPC64_TOC16_HA:
|
||||
case elfcpp::R_PPC64_TOC16_DS:
|
||||
case elfcpp::R_PPC64_TOC16_LO_DS:
|
||||
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:
|
||||
ref = Symbol::RELATIVE_REF;
|
||||
break;
|
||||
|
||||
@ -6427,6 +6436,14 @@ Target_powerpc<size, big_endian>::Scan::reloc_needs_plt_for_ifunc(
|
||||
case elfcpp::R_PPC64_GOT16_LO_DS:
|
||||
return false;
|
||||
|
||||
// PLT relocs are OK and need a PLT entry.
|
||||
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:
|
||||
return true;
|
||||
break;
|
||||
|
||||
// Function calls are good, and these do need a PLT entry.
|
||||
case elfcpp::R_POWERPC_ADDR24:
|
||||
case elfcpp::R_POWERPC_ADDR14:
|
||||
@ -7245,6 +7262,14 @@ Target_powerpc<size, big_endian>::Scan::global(
|
||||
}
|
||||
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 (!pushed_ifunc)
|
||||
target->make_plt_entry(symtab, layout, gsym);
|
||||
break;
|
||||
|
||||
case elfcpp::R_PPC_PLTREL24:
|
||||
case elfcpp::R_POWERPC_REL24:
|
||||
if (!is_ifunc)
|
||||
@ -8366,9 +8391,12 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
|
||||
bool has_stub_value = false;
|
||||
bool localentry0 = false;
|
||||
unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
|
||||
if ((gsym != NULL
|
||||
bool has_plt_offset
|
||||
= (gsym != NULL
|
||||
? gsym->use_plt_offset(Scan::get_reference_flags(r_type, target))
|
||||
: object->local_has_plt_offset(r_sym))
|
||||
: object->local_has_plt_offset(r_sym));
|
||||
if (has_plt_offset
|
||||
&& !is_plt16_reloc<size>(r_type)
|
||||
&& (!psymval->is_ifunc_symbol()
|
||||
|| Scan::reloc_needs_plt_for_ifunc(target, object, r_type, false)))
|
||||
{
|
||||
@ -8440,12 +8468,38 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
|
||||
gold_assert(has_stub_value || !(os->flags() & elfcpp::SHF_ALLOC));
|
||||
}
|
||||
|
||||
if (r_type == elfcpp::R_POWERPC_GOT16
|
||||
|| r_type == elfcpp::R_POWERPC_GOT16_LO
|
||||
|| r_type == elfcpp::R_POWERPC_GOT16_HI
|
||||
|| r_type == elfcpp::R_POWERPC_GOT16_HA
|
||||
|| r_type == elfcpp::R_PPC64_GOT16_DS
|
||||
|| r_type == elfcpp::R_PPC64_GOT16_LO_DS)
|
||||
if (has_plt_offset && is_plt16_reloc<size>(r_type))
|
||||
{
|
||||
const Output_data_plt_powerpc<size, big_endian>* plt;
|
||||
if (gsym)
|
||||
value = target->plt_off(gsym, &plt);
|
||||
else
|
||||
value = target->plt_off(object, r_sym, &plt);
|
||||
value += plt->address();
|
||||
|
||||
if (size == 64)
|
||||
value -= (target->got_section()->output_section()->address()
|
||||
+ object->toc_base_offset());
|
||||
else if (parameters->options().output_is_position_independent())
|
||||
{
|
||||
if (rela.get_r_addend() >= 32768)
|
||||
{
|
||||
unsigned int got2 = object->got2_shndx();
|
||||
value -= (object->get_output_section_offset(got2)
|
||||
+ object->output_section(got2)->address()
|
||||
+ rela.get_r_addend());
|
||||
}
|
||||
else
|
||||
value -= (target->got_section()->address()
|
||||
+ target->got_section()->g_o_t());
|
||||
}
|
||||
}
|
||||
else if (r_type == elfcpp::R_POWERPC_GOT16
|
||||
|| r_type == elfcpp::R_POWERPC_GOT16_LO
|
||||
|| r_type == elfcpp::R_POWERPC_GOT16_HI
|
||||
|| r_type == elfcpp::R_POWERPC_GOT16_HA
|
||||
|| r_type == elfcpp::R_PPC64_GOT16_DS
|
||||
|| r_type == elfcpp::R_PPC64_GOT16_LO_DS)
|
||||
{
|
||||
if (gsym != NULL)
|
||||
{
|
||||
@ -8777,7 +8831,11 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
|
||||
else if (!has_stub_value)
|
||||
{
|
||||
Address addend = 0;
|
||||
if (!(size == 32 && r_type == elfcpp::R_PPC_PLTREL24))
|
||||
if (!(size == 32
|
||||
&& (r_type == elfcpp::R_PPC_PLTREL24
|
||||
|| r_type == elfcpp::R_POWERPC_PLT16_LO
|
||||
|| r_type == elfcpp::R_POWERPC_PLT16_HI
|
||||
|| r_type == elfcpp::R_POWERPC_PLT16_HA)))
|
||||
addend = rela.get_r_addend();
|
||||
value = psymval->value(object, addend);
|
||||
if (size == 64 && is_branch_reloc(r_type))
|
||||
@ -8944,6 +9002,23 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
|
||||
}
|
||||
break;
|
||||
|
||||
case elfcpp::R_POWERPC_PLT16_HA:
|
||||
if (size == 32
|
||||
&& !parameters->options().output_is_position_independent())
|
||||
{
|
||||
Insn* iview = reinterpret_cast<Insn*>(view - d_offset);
|
||||
Insn insn = elfcpp::Swap<32, big_endian>::readval(iview);
|
||||
|
||||
// Convert addis to lis.
|
||||
if ((insn & (0x3f << 26)) == 15u << 26
|
||||
&& (insn & (0x1f << 16)) != 0)
|
||||
{
|
||||
insn &= ~(0x1f << 16);
|
||||
elfcpp::Swap<32, big_endian>::writeval(iview, insn);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -9345,6 +9420,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
|
||||
case elfcpp::R_POWERPC_REL16_LO:
|
||||
case elfcpp::R_PPC64_TOC16_LO:
|
||||
case elfcpp::R_POWERPC_GOT16_LO:
|
||||
case elfcpp::R_POWERPC_PLT16_LO:
|
||||
case elfcpp::R_POWERPC_SECTOFF_LO:
|
||||
case elfcpp::R_POWERPC_TPREL16_LO:
|
||||
case elfcpp::R_POWERPC_DTPREL16_LO:
|
||||
@ -9371,6 +9447,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
|
||||
case elfcpp::R_POWERPC_REL16_HI:
|
||||
case elfcpp::R_PPC64_TOC16_HI:
|
||||
case elfcpp::R_POWERPC_GOT16_HI:
|
||||
case elfcpp::R_POWERPC_PLT16_HI:
|
||||
case elfcpp::R_POWERPC_SECTOFF_HI:
|
||||
case elfcpp::R_POWERPC_TPREL16_HI:
|
||||
case elfcpp::R_POWERPC_DTPREL16_HI:
|
||||
@ -9392,6 +9469,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
|
||||
case elfcpp::R_POWERPC_REL16_HA:
|
||||
case elfcpp::R_PPC64_TOC16_HA:
|
||||
case elfcpp::R_POWERPC_GOT16_HA:
|
||||
case elfcpp::R_POWERPC_PLT16_HA:
|
||||
case elfcpp::R_POWERPC_SECTOFF_HA:
|
||||
case elfcpp::R_POWERPC_TPREL16_HA:
|
||||
case elfcpp::R_POWERPC_DTPREL16_HA:
|
||||
@ -9464,6 +9542,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
|
||||
case elfcpp::R_PPC64_TOC16_LO_DS:
|
||||
case elfcpp::R_PPC64_GOT16_DS:
|
||||
case elfcpp::R_PPC64_GOT16_LO_DS:
|
||||
case elfcpp::R_PPC64_PLT16_LO_DS:
|
||||
case elfcpp::R_PPC64_SECTOFF_DS:
|
||||
case elfcpp::R_PPC64_SECTOFF_LO_DS:
|
||||
maybe_dq_reloc = true;
|
||||
@ -9522,9 +9601,6 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
|
||||
|
||||
case elfcpp::R_POWERPC_PLT32:
|
||||
case elfcpp::R_POWERPC_PLTREL32:
|
||||
case elfcpp::R_POWERPC_PLT16_LO:
|
||||
case elfcpp::R_POWERPC_PLT16_HI:
|
||||
case elfcpp::R_POWERPC_PLT16_HA:
|
||||
case elfcpp::R_PPC_SDAREL16:
|
||||
case elfcpp::R_POWERPC_ADDR30:
|
||||
case elfcpp::R_PPC64_PLT64:
|
||||
@ -9533,7 +9609,6 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
|
||||
case elfcpp::R_PPC64_PLTGOT16_LO:
|
||||
case elfcpp::R_PPC64_PLTGOT16_HI:
|
||||
case elfcpp::R_PPC64_PLTGOT16_HA:
|
||||
case elfcpp::R_PPC64_PLT16_LO_DS:
|
||||
case elfcpp::R_PPC64_PLTGOT16_DS:
|
||||
case elfcpp::R_PPC64_PLTGOT16_LO_DS:
|
||||
case elfcpp::R_PPC_EMB_RELSDA:
|
||||
@ -9660,7 +9735,11 @@ public:
|
||||
inline Relocatable_relocs::Reloc_strategy
|
||||
global_strategy(unsigned int r_type, Relobj*, unsigned int)
|
||||
{
|
||||
if (r_type == elfcpp::R_PPC_PLTREL24)
|
||||
if (size == 32
|
||||
&& (r_type == elfcpp::R_PPC_PLTREL24
|
||||
|| r_type == elfcpp::R_POWERPC_PLT16_LO
|
||||
|| r_type == elfcpp::R_POWERPC_PLT16_HI
|
||||
|| r_type == elfcpp::R_POWERPC_PLT16_HA))
|
||||
return Relocatable_relocs::RELOC_SPECIAL;
|
||||
return Relocatable_relocs::RELOC_COPY;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user