powerxx_stubs_(false), plt_thread_safe_(false), plt_localentry0_(false),
plt_localentry0_init_(false), has_localentry0_(false),
has_tls_get_addr_opt_(false),
+ tprel_opt_(parameters->options().tls_optimize()),
relax_failed_(false), relax_fail_count_(0),
stub_group_size_(0), savres_section_(0),
tls_get_addr_(NULL), tls_get_addr_opt_(NULL),
return false;
}
+ bool
+ tprel_opt() const
+ { return this->tprel_opt_; }
+
+ void
+ set_tprel_opt(bool val)
+ { this->tprel_opt_ = val; }
+
// Remember any symbols seen with non-zero localentry, even those
// not providing a definition
bool
bool plt_localentry0_init_;
bool has_localentry0_;
bool has_tls_get_addr_opt_;
+ bool tprel_opt_;
bool relax_failed_;
int relax_fail_count_;
switch (r_type)
{
- case elfcpp::R_POWERPC_TPREL16:
- case elfcpp::R_POWERPC_TPREL16_LO:
- case elfcpp::R_POWERPC_TPREL16_HI:
- case elfcpp::R_POWERPC_TPREL16_HA:
case elfcpp::R_PPC64_TPREL16_DS:
case elfcpp::R_PPC64_TPREL16_LO_DS:
case elfcpp::R_PPC64_TPREL16_HIGH:
case elfcpp::R_PPC64_TPREL16_HIGHEST:
case elfcpp::R_PPC64_TPREL16_HIGHESTA:
case elfcpp::R_PPC64_TPREL34:
+ if (size != 64)
+ break;
+ // Fall through.
+ case elfcpp::R_POWERPC_TPREL16:
+ case elfcpp::R_POWERPC_TPREL16_LO:
+ case elfcpp::R_POWERPC_TPREL16_HI:
+ case elfcpp::R_POWERPC_TPREL16_HA:
layout->set_has_static_tls();
break;
default:
break;
}
+ switch (r_type)
+ {
+ case elfcpp::R_POWERPC_TPREL16_HA:
+ if (target->tprel_opt())
+ {
+ section_size_type slen;
+ const unsigned char* view = NULL;
+ view = ppc_object->section_contents(data_shndx, &slen, false);
+ section_size_type off
+ = convert_to_section_size_type(reloc.get_r_offset()) & -4;
+ if (off < slen)
+ {
+ uint32_t insn = elfcpp::Swap<32, big_endian>::readval(view + off);
+ if ((insn & ((0x3fu << 26) | 0x1f << 16))
+ != ((15u << 26) | ((size == 32 ? 2 : 13) << 16)))
+ target->set_tprel_opt(false);
+ }
+ }
+ break;
+
+ case elfcpp::R_PPC64_TPREL16_HIGH:
+ case elfcpp::R_PPC64_TPREL16_HIGHA:
+ case elfcpp::R_PPC64_TPREL16_HIGHER:
+ case elfcpp::R_PPC64_TPREL16_HIGHERA:
+ case elfcpp::R_PPC64_TPREL16_HIGHEST:
+ case elfcpp::R_PPC64_TPREL16_HIGHESTA:
+ if (size != 64)
+ break;
+ // Fall through.
+ case elfcpp::R_POWERPC_TPREL16_HI:
+ target->set_tprel_opt(false);
+ break;
+ default:
+ break;
+ }
+
switch (r_type)
{
case elfcpp::R_PPC64_D34:
switch (r_type)
{
- case elfcpp::R_POWERPC_TPREL16:
- case elfcpp::R_POWERPC_TPREL16_LO:
- case elfcpp::R_POWERPC_TPREL16_HI:
- case elfcpp::R_POWERPC_TPREL16_HA:
case elfcpp::R_PPC64_TPREL16_DS:
case elfcpp::R_PPC64_TPREL16_LO_DS:
case elfcpp::R_PPC64_TPREL16_HIGH:
case elfcpp::R_PPC64_TPREL16_HIGHEST:
case elfcpp::R_PPC64_TPREL16_HIGHESTA:
case elfcpp::R_PPC64_TPREL34:
+ if (size != 64)
+ break;
+ // Fall through.
+ case elfcpp::R_POWERPC_TPREL16:
+ case elfcpp::R_POWERPC_TPREL16_LO:
+ case elfcpp::R_POWERPC_TPREL16_HI:
+ case elfcpp::R_POWERPC_TPREL16_HA:
layout->set_has_static_tls();
break;
default:
break;
}
+ switch (r_type)
+ {
+ case elfcpp::R_POWERPC_TPREL16_HA:
+ if (target->tprel_opt())
+ {
+ section_size_type slen;
+ const unsigned char* view = NULL;
+ view = ppc_object->section_contents(data_shndx, &slen, false);
+ section_size_type off
+ = convert_to_section_size_type(reloc.get_r_offset()) & -4;
+ if (off < slen)
+ {
+ uint32_t insn = elfcpp::Swap<32, big_endian>::readval(view + off);
+ if ((insn & ((0x3fu << 26) | 0x1f << 16))
+ != ((15u << 26) | ((size == 32 ? 2 : 13) << 16)))
+ target->set_tprel_opt(false);
+ }
+ }
+ break;
+
+ case elfcpp::R_PPC64_TPREL16_HIGH:
+ case elfcpp::R_PPC64_TPREL16_HIGHA:
+ case elfcpp::R_PPC64_TPREL16_HIGHER:
+ case elfcpp::R_PPC64_TPREL16_HIGHERA:
+ case elfcpp::R_PPC64_TPREL16_HIGHEST:
+ case elfcpp::R_PPC64_TPREL16_HIGHESTA:
+ if (size != 64)
+ break;
+ // Fall through.
+ case elfcpp::R_POWERPC_TPREL16_HI:
+ target->set_tprel_opt(false);
+ break;
+ default:
+ break;
+ }
+
switch (r_type)
{
case elfcpp::R_PPC64_D34:
break;
}
- if (size == 64
- && (gsym
- ? relative_value_is_known(gsym)
- : relative_value_is_known(psymval)))
+ if (gsym
+ ? relative_value_is_known(gsym)
+ : relative_value_is_known(psymval))
{
Insn* iview;
Insn* iview2;
case elfcpp::R_POWERPC_GOT_DTPREL16_HA:
case elfcpp::R_POWERPC_GOT16_HA:
case elfcpp::R_PPC64_TOC16_HA:
- if (parameters->options().toc_optimize())
+ if (size == 64 && parameters->options().toc_optimize())
{
iview = reinterpret_cast<Insn*>(view - d_offset);
insn = elfcpp::Swap<32, big_endian>::readval(iview);
case elfcpp::R_PPC64_GOT16_LO_DS:
case elfcpp::R_PPC64_TOC16_LO:
case elfcpp::R_PPC64_TOC16_LO_DS:
- if (parameters->options().toc_optimize())
+ if (size == 64 && parameters->options().toc_optimize())
{
iview = reinterpret_cast<Insn*>(view - d_offset);
insn = elfcpp::Swap<32, big_endian>::readval(iview);
break;
case elfcpp::R_PPC64_GOT_PCREL34:
- if (parameters->options().toc_optimize())
+ if (size == 64 && parameters->options().toc_optimize())
{
iview = reinterpret_cast<Insn*>(view);
pinsn = elfcpp::Swap<32, big_endian>::readval(iview);
break;
case elfcpp::R_PPC64_PCREL34:
- {
- iview = reinterpret_cast<Insn*>(view);
- pinsn = elfcpp::Swap<32, big_endian>::readval(iview);
- pinsn <<= 32;
- pinsn |= elfcpp::Swap<32, big_endian>::readval(iview + 1);
- if ((pinsn & ((-1ULL << 50) | (63ULL << 26)))
- != ((1ULL << 58) | (2ULL << 56) | (1ULL << 52)
- | (14ULL << 26) /* paddi */))
- break;
+ if (size == 64)
+ {
+ iview = reinterpret_cast<Insn*>(view);
+ pinsn = elfcpp::Swap<32, big_endian>::readval(iview);
+ pinsn <<= 32;
+ pinsn |= elfcpp::Swap<32, big_endian>::readval(iview + 1);
+ if ((pinsn & ((-1ULL << 50) | (63ULL << 26)))
+ != ((1ULL << 58) | (2ULL << 56) | (1ULL << 52)
+ | (14ULL << 26) /* paddi */))
+ break;
- pcrelopt:
- const int reloc_size = elfcpp::Elf_sizes<size>::rela_size;
- elfcpp::Shdr<size, big_endian> shdr(relinfo->reloc_shdr);
- size_t reloc_count = shdr.get_sh_size() / reloc_size;
- if (relnum >= reloc_count - 1)
- break;
+ pcrelopt:
+ const int reloc_size = elfcpp::Elf_sizes<size>::rela_size;
+ elfcpp::Shdr<size, big_endian> shdr(relinfo->reloc_shdr);
+ size_t reloc_count = shdr.get_sh_size() / reloc_size;
+ if (relnum >= reloc_count - 1)
+ break;
- Reltype next_rela(preloc + reloc_size);
- if ((elfcpp::elf_r_type<size>(next_rela.get_r_info())
- != elfcpp::R_PPC64_PCREL_OPT)
- || next_rela.get_r_offset() != rela.get_r_offset())
- break;
+ Reltype next_rela(preloc + reloc_size);
+ if ((elfcpp::elf_r_type<size>(next_rela.get_r_info())
+ != elfcpp::R_PPC64_PCREL_OPT)
+ || next_rela.get_r_offset() != rela.get_r_offset())
+ break;
- Address off = next_rela.get_r_addend();
- if (off == 0)
- off = 8; // zero means next insn.
- if (off + rela.get_r_offset() + 4 > view_size)
- break;
+ Address off = next_rela.get_r_addend();
+ if (off == 0)
+ off = 8; // zero means next insn.
+ if (off + rela.get_r_offset() + 4 > view_size)
+ break;
- iview2 = reinterpret_cast<Insn*>(view + off);
- pinsn2 = elfcpp::Swap<32, big_endian>::readval(iview2);
- pinsn2 <<= 32;
- if ((pinsn2 & (63ULL << 58)) == 1ULL << 58)
- break;
- if (xlate_pcrel_opt(&pinsn, &pinsn2))
- {
- elfcpp::Swap<32, big_endian>::writeval(iview, pinsn >> 32);
- elfcpp::Swap<32, big_endian>::writeval(iview + 1,
- pinsn & 0xffffffff);
- elfcpp::Swap<32, big_endian>::writeval(iview2, pinsn2 >> 32);
- }
- }
+ iview2 = reinterpret_cast<Insn*>(view + off);
+ pinsn2 = elfcpp::Swap<32, big_endian>::readval(iview2);
+ pinsn2 <<= 32;
+ if ((pinsn2 & (63ULL << 58)) == 1ULL << 58)
+ break;
+ if (xlate_pcrel_opt(&pinsn, &pinsn2))
+ {
+ elfcpp::Swap<32, big_endian>::writeval(iview, pinsn >> 32);
+ elfcpp::Swap<32, big_endian>::writeval(iview + 1,
+ pinsn & 0xffffffff);
+ elfcpp::Swap<32, big_endian>::writeval(iview2, pinsn2 >> 32);
+ }
+ }
break;
case elfcpp::R_POWERPC_TPREL16_HA:
- if (parameters->options().tls_optimize() && value + 0x8000 < 0x10000)
+ if (target->tprel_opt() && value + 0x8000 < 0x10000)
{
Insn* iview = reinterpret_cast<Insn*>(view - d_offset);
- Insn insn = elfcpp::Swap<32, big_endian>::readval(iview);
- if ((insn & ((0x3f << 26) | 0x1f << 16))
- != ((15u << 26) | ((size == 32 ? 2 : 13) << 16)))
- ;
- else
- {
- elfcpp::Swap<32, big_endian>::writeval(iview, nop);
- return true;
- }
+ elfcpp::Swap<32, big_endian>::writeval(iview, nop);
+ return true;
}
break;
break;
// Fall through.
case elfcpp::R_POWERPC_TPREL16_LO:
- if (parameters->options().tls_optimize() && value + 0x8000 < 0x10000)
+ if (target->tprel_opt() && value + 0x8000 < 0x10000)
{
Insn* iview = reinterpret_cast<Insn*>(view - d_offset);
Insn insn = elfcpp::Swap<32, big_endian>::readval(iview);
break;
case elfcpp::R_PPC64_ENTRY:
- value = (target->got_section()->output_section()->address()
- + object->toc_base_offset());
- if (value + 0x80008000 <= 0xffffffff
- && !parameters->options().output_is_position_independent())
- {
- Insn* iview = reinterpret_cast<Insn*>(view);
- Insn insn1 = elfcpp::Swap<32, big_endian>::readval(iview);
- Insn insn2 = elfcpp::Swap<32, big_endian>::readval(iview + 1);
-
- if ((insn1 & ~0xfffc) == ld_2_12
- && insn2 == add_2_2_12)
- {
- insn1 = lis_2 + ha(value);
- elfcpp::Swap<32, big_endian>::writeval(iview, insn1);
- insn2 = addi_2_2 + l(value);
- elfcpp::Swap<32, big_endian>::writeval(iview + 1, insn2);
- return true;
- }
- }
- else
+ if (size == 64)
{
- value -= address;
- if (value + 0x80008000 <= 0xffffffff)
+ value = (target->got_section()->output_section()->address()
+ + object->toc_base_offset());
+ if (value + 0x80008000 <= 0xffffffff
+ && !parameters->options().output_is_position_independent())
{
Insn* iview = reinterpret_cast<Insn*>(view);
Insn insn1 = elfcpp::Swap<32, big_endian>::readval(iview);
if ((insn1 & ~0xfffc) == ld_2_12
&& insn2 == add_2_2_12)
{
- insn1 = addis_2_12 + ha(value);
+ insn1 = lis_2 + ha(value);
elfcpp::Swap<32, big_endian>::writeval(iview, insn1);
insn2 = addi_2_2 + l(value);
elfcpp::Swap<32, big_endian>::writeval(iview + 1, insn2);
return true;
}
}
+ else
+ {
+ value -= address;
+ if (value + 0x80008000 <= 0xffffffff)
+ {
+ Insn* iview = reinterpret_cast<Insn*>(view);
+ Insn insn1 = elfcpp::Swap<32, big_endian>::readval(iview);
+ Insn insn2 = elfcpp::Swap<32, big_endian>::readval(iview + 1);
+
+ if ((insn1 & ~0xfffc) == ld_2_12
+ && insn2 == add_2_2_12)
+ {
+ insn1 = addis_2_12 + ha(value);
+ elfcpp::Swap<32, big_endian>::writeval(iview, insn1);
+ insn2 = addi_2_2 + l(value);
+ elfcpp::Swap<32, big_endian>::writeval(iview + 1, insn2);
+ return true;
+ }
+ }
+ }
}
break;
// lis 2,.TOC.@ha
// addi 2,2,.TOC.@l
// if .TOC. is in range. */
- if (value + address - 4 + 0x80008000 <= 0xffffffff
+ if (size == 64
+ && value + address - 4 + 0x80008000 <= 0xffffffff
&& relnum + 1 > 1
&& preloc != NULL
&& target->abiversion() >= 2