// powerpc.cc -- powerpc target support for gold.
-// Copyright (C) 2008-2019 Free Software Foundation, Inc.
+// Copyright (C) 2008-2020 Free Software Foundation, Inc.
// Written by David S. Miller <davem@davemloft.net>
// and David Edelsohn <edelsohn@gnu.org>
glink_(NULL), rela_dyn_(NULL), copy_relocs_(),
tlsld_got_offset_(-1U),
stub_tables_(), branch_lookup_table_(), branch_info_(), tocsave_loc_(),
- powerxx_stubs_(false), plt_thread_safe_(false), plt_localentry0_(false),
+ power10_stubs_(false), plt_thread_safe_(false), plt_localentry0_(false),
plt_localentry0_init_(false), has_localentry0_(false),
has_tls_get_addr_opt_(false),
relax_failed_(false), relax_fail_count_(0),
}
bool
- powerxx_stubs() const
- { return this->powerxx_stubs_; }
+ power10_stubs() const
+ { return this->power10_stubs_; }
void
- set_powerxx_stubs()
+ set_power10_stubs()
{
- this->powerxx_stubs_ = true;
+ this->power10_stubs_ = true;
}
bool
// Merge object attributes from input object with those in the output.
void
- merge_object_attributes(const char*, const Attributes_section_data*);
+ merge_object_attributes(const Object*, const Attributes_section_data*);
private:
Branches branch_info_;
Tocsave_loc tocsave_loc_;
- bool powerxx_stubs_;
+ bool power10_stubs_;
bool plt_thread_safe_;
bool plt_localentry0_;
bool plt_localentry0_init_;
typedef typename elfcpp::Swap<fieldsize, big_endian>::Valtype Valtype;
Valtype* wv = reinterpret_cast<Valtype*>(view);
Valtype val = elfcpp::Swap<fieldsize, big_endian>::readval(wv);
- Valtype reloc = value >> right_shift;
+ if (overflow == CHECK_SIGNED)
+ value = static_cast<SignedAddress>(value) >> right_shift;
+ else
+ value = value >> right_shift;
+ Valtype reloc = value;
val &= ~dst_mask;
reloc &= dst_mask;
elfcpp::Swap<fieldsize, big_endian>::writeval(wv, val | reloc);
- return overflowed<valsize>(value >> right_shift, overflow);
+ return overflowed<valsize>(value, overflow);
}
// Do a simple RELA relocation, unaligned.
typedef typename elfcpp::Swap_unaligned<fieldsize, big_endian>::Valtype
Valtype;
Valtype val = elfcpp::Swap<fieldsize, big_endian>::readval(view);
- Valtype reloc = value >> right_shift;
+ if (overflow == CHECK_SIGNED)
+ value = static_cast<SignedAddress>(value) >> right_shift;
+ else
+ value = value >> right_shift;
+ Valtype reloc = value;
val &= ~dst_mask;
reloc &= dst_mask;
elfcpp::Swap_unaligned<fieldsize, big_endian>::writeval(view, val | reloc);
- return overflowed<valsize>(value >> right_shift, overflow);
+ return overflowed<valsize>(value, overflow);
}
public:
if (r_type == elfcpp::R_PPC64_REL24_NOTOC)
{
if (!p.second && !p.first->second.notoc_
- && !this->targ_->powerxx_stubs())
+ && !this->targ_->power10_stubs())
this->need_resize_ = true;
p.first->second.notoc_ = 1;
}
if (r_type == elfcpp::R_PPC64_REL24_NOTOC)
{
if (!p.second && !p.first->second.notoc_
- && !this->targ_->powerxx_stubs())
+ && !this->targ_->power10_stubs())
this->need_resize_ = true;
p.first->second.notoc_ = 1;
}
&& cs->second.r2save_
&& !cs->second.localentry0_)
|| (cs->second.notoc_
- && !this->targ_->powerxx_stubs()))
+ && !this->targ_->power10_stubs()))
calls.push_back(cs);
if (calls.size() > 1)
std::stable_sort(calls.begin(), calls.end(),
typedef typename Branch_stub_entries::const_iterator branch_iter;
std::vector<branch_iter> branches;
if (!this->long_branch_stubs_.empty()
- && !this->targ_->powerxx_stubs())
+ && !this->targ_->power10_stubs())
for (branch_iter bs = this->long_branch_stubs_.begin();
bs != this->long_branch_stubs_.end();
++bs)
template<bool big_endian>
static unsigned char*
-build_powerxx_offset(unsigned char* p, uint64_t off, uint64_t odd, bool load)
+build_power10_offset(unsigned char* p, uint64_t off, uint64_t odd, bool load)
{
uint64_t insn;
if (off - odd + (1ULL << 33) < 1ULL << 34)
if (p->second.r2save_)
bytes += 4;
- if (this->targ_->powerxx_stubs())
+ if (this->targ_->power10_stubs())
{
uint64_t from = this->stub_address() + p->second.off_ + bytes;
if (bytes > 8 * 4)
uint64_t off = p->first.dest_ - loc;
if (p->second.notoc_)
{
- if (this->targ_->powerxx_stubs())
+ if (this->targ_->power10_stubs())
{
Address odd = loc & 4;
if (off + (1 << 25) < 2 << 25)
if (off + (1 << 25) < 2 << 25)
return 4;
- if (!this->targ_->powerxx_stubs())
+ if (!this->targ_->power10_stubs())
*need_lt = true;
return 16;
}
unsigned char* p;
if (size == 64
- && this->targ_->powerxx_stubs())
+ && this->targ_->power10_stubs())
{
if (!this->plt_call_stubs_.empty())
{
Address plt_addr = pltoff + plt->address();
Address from = this->stub_address() + (p - oview);
Address delta = plt_addr - from;
- p = build_powerxx_offset<big_endian>(p, delta, from & 4, true);
+ p = build_power10_offset<big_endian>(p, delta, from & 4, true);
write_insn<big_endian>(p, mtctr_12);
p += 4;
if (!this->build_tls_opt_tail(p, cs))
if (bs->second.notoc_ || delta + (1 << 25) >= 2 << 25)
{
unsigned char* startp = p;
- p = build_powerxx_offset<big_endian>(p, delta, loc & 4, false);
+ p = build_power10_offset<big_endian>(p, delta, loc & 4, false);
delta -= p - startp;
}
if (delta + (1 << 25) < 2 << 25)
case elfcpp::R_POWERPC_ADDR16_LO:
case elfcpp::R_POWERPC_ADDR16_HI:
case elfcpp::R_POWERPC_ADDR16_HA:
+ case elfcpp::R_PPC64_ADDR16_HIGHER34:
+ case elfcpp::R_PPC64_ADDR16_HIGHERA34:
+ case elfcpp::R_PPC64_ADDR16_HIGHEST34:
+ case elfcpp::R_PPC64_ADDR16_HIGHESTA34:
+ case elfcpp::R_PPC64_D34:
+ case elfcpp::R_PPC64_D34_LO:
+ case elfcpp::R_PPC64_D34_HI30:
+ case elfcpp::R_PPC64_D34_HA30:
+ case elfcpp::R_PPC64_D28:
ref = Symbol::ABSOLUTE_REF;
break;
case elfcpp::R_POWERPC_GOT_TPREL16:
case elfcpp::R_POWERPC_TLS:
+ case elfcpp::R_PPC64_TLSGD:
+ case elfcpp::R_PPC64_TLSLD:
+ case elfcpp::R_PPC64_TPREL34:
+ case elfcpp::R_PPC64_DTPREL34:
+ case elfcpp::R_PPC64_GOT_TLSGD34:
+ case elfcpp::R_PPC64_GOT_TLSLD34:
+ case elfcpp::R_PPC64_GOT_TPREL34:
+ case elfcpp::R_PPC64_GOT_DTPREL34:
ref = Symbol::TLS_REF;
break;
case elfcpp::R_POWERPC_ADDR14_BRTAKEN:
case elfcpp::R_POWERPC_ADDR14_BRNTAKEN:
case elfcpp::R_POWERPC_REL32:
- case elfcpp::R_POWERPC_REL24:
case elfcpp::R_POWERPC_TPREL16:
case elfcpp::R_POWERPC_TPREL16_LO:
case elfcpp::R_POWERPC_TPREL16_HI:
{
// These are the relocation types supported only on 32-bit.
// ??? glibc ld.so doesn't need to support these.
+ case elfcpp::R_POWERPC_REL24:
case elfcpp::R_POWERPC_DTPREL16:
case elfcpp::R_POWERPC_DTPREL16_LO:
case elfcpp::R_POWERPC_DTPREL16_HI:
case elfcpp::R_PPC64_REL16_HIGHERA34:
case elfcpp::R_PPC64_REL16_HIGHEST34:
case elfcpp::R_PPC64_REL16_HIGHESTA34:
- break;
-
case elfcpp::R_PPC64_D34:
case elfcpp::R_PPC64_D34_LO:
case elfcpp::R_PPC64_D34_HI30:
case elfcpp::R_PPC64_D28:
case elfcpp::R_PPC64_PCREL34:
case elfcpp::R_PPC64_PCREL28:
- target->set_powerxx_stubs();
+ case elfcpp::R_PPC64_TPREL34:
+ case elfcpp::R_PPC64_DTPREL34:
break;
case elfcpp::R_PPC64_TOC:
case elfcpp::R_PPC64_PLT_PCREL34:
case elfcpp::R_PPC64_PLT_PCREL34_NOTOC:
- target->set_powerxx_stubs();
- // Fall through.
case elfcpp::R_POWERPC_PLT16_LO:
case elfcpp::R_POWERPC_PLT16_HI:
case elfcpp::R_POWERPC_PLT16_HA:
break;
case elfcpp::R_PPC64_GOT_PCREL34:
- target->set_powerxx_stubs();
- // Fall through.
case elfcpp::R_POWERPC_GOT16:
case elfcpp::R_POWERPC_GOT16_LO:
case elfcpp::R_POWERPC_GOT16_HI:
target->got_section(symtab, layout);
break;
+ case elfcpp::R_PPC64_GOT_TLSGD34:
case elfcpp::R_POWERPC_GOT_TLSGD16:
case elfcpp::R_POWERPC_GOT_TLSGD16_LO:
case elfcpp::R_POWERPC_GOT_TLSGD16_HI:
}
break;
+ case elfcpp::R_PPC64_GOT_TLSLD34:
case elfcpp::R_POWERPC_GOT_TLSLD16:
case elfcpp::R_POWERPC_GOT_TLSLD16_LO:
case elfcpp::R_POWERPC_GOT_TLSLD16_HI:
}
break;
+ case elfcpp::R_PPC64_GOT_DTPREL34:
case elfcpp::R_POWERPC_GOT_DTPREL16:
case elfcpp::R_POWERPC_GOT_DTPREL16_LO:
case elfcpp::R_POWERPC_GOT_DTPREL16_HI:
}
break;
+ case elfcpp::R_PPC64_GOT_TPREL34:
case elfcpp::R_POWERPC_GOT_TPREL16:
case elfcpp::R_POWERPC_GOT_TPREL16_LO:
case elfcpp::R_POWERPC_GOT_TPREL16_HI:
case elfcpp::R_PPC64_TOC16:
case elfcpp::R_PPC64_TOC16_DS:
ppc_object->set_has_small_toc_reloc();
+ break;
+ default:
+ break;
+ }
+
+ 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_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:
+ case elfcpp::R_PPC64_TPREL34:
+ layout->set_has_static_tls();
+ break;
+ default:
+ break;
+ }
+
+ switch (r_type)
+ {
+ case elfcpp::R_PPC64_D34:
+ case elfcpp::R_PPC64_D34_LO:
+ case elfcpp::R_PPC64_D34_HI30:
+ case elfcpp::R_PPC64_D34_HA30:
+ case elfcpp::R_PPC64_D28:
+ case elfcpp::R_PPC64_PCREL34:
+ case elfcpp::R_PPC64_PCREL28:
+ case elfcpp::R_PPC64_TPREL34:
+ case elfcpp::R_PPC64_DTPREL34:
+ case elfcpp::R_PPC64_PLT_PCREL34:
+ case elfcpp::R_PPC64_PLT_PCREL34_NOTOC:
+ case elfcpp::R_PPC64_GOT_PCREL34:
+ case elfcpp::R_PPC64_GOT_TLSGD34:
+ case elfcpp::R_PPC64_GOT_TLSLD34:
+ case elfcpp::R_PPC64_GOT_DTPREL34:
+ case elfcpp::R_PPC64_GOT_TPREL34:
+ target->set_power10_stubs();
+ break;
default:
break;
}
case elfcpp::R_PPC64_REL16_HIGHERA34:
case elfcpp::R_PPC64_REL16_HIGHEST34:
case elfcpp::R_PPC64_REL16_HIGHESTA34:
- break;
-
case elfcpp::R_PPC64_D34:
case elfcpp::R_PPC64_D34_LO:
case elfcpp::R_PPC64_D34_HI30:
case elfcpp::R_PPC64_D28:
case elfcpp::R_PPC64_PCREL34:
case elfcpp::R_PPC64_PCREL28:
- target->set_powerxx_stubs();
+ case elfcpp::R_PPC64_TPREL34:
+ case elfcpp::R_PPC64_DTPREL34:
break;
case elfcpp::R_PPC64_TOC:
case elfcpp::R_PPC64_PLT_PCREL34:
case elfcpp::R_PPC64_PLT_PCREL34_NOTOC:
- target->set_powerxx_stubs();
- // Fall through.
case elfcpp::R_POWERPC_PLT16_LO:
case elfcpp::R_POWERPC_PLT16_HI:
case elfcpp::R_POWERPC_PLT16_HA:
break;
case elfcpp::R_PPC64_GOT_PCREL34:
- target->set_powerxx_stubs();
- // Fall through.
case elfcpp::R_POWERPC_GOT16:
case elfcpp::R_POWERPC_GOT16_LO:
case elfcpp::R_POWERPC_GOT16_HI:
target->got_section(symtab, layout);
break;
+ case elfcpp::R_PPC64_GOT_TLSGD34:
case elfcpp::R_POWERPC_GOT_TLSGD16:
case elfcpp::R_POWERPC_GOT_TLSGD16_LO:
case elfcpp::R_POWERPC_GOT_TLSGD16_HI:
}
break;
+ case elfcpp::R_PPC64_GOT_TLSLD34:
case elfcpp::R_POWERPC_GOT_TLSLD16:
case elfcpp::R_POWERPC_GOT_TLSLD16_LO:
case elfcpp::R_POWERPC_GOT_TLSLD16_HI:
}
break;
+ case elfcpp::R_PPC64_GOT_DTPREL34:
case elfcpp::R_POWERPC_GOT_DTPREL16:
case elfcpp::R_POWERPC_GOT_DTPREL16_LO:
case elfcpp::R_POWERPC_GOT_DTPREL16_HI:
}
break;
+ case elfcpp::R_PPC64_GOT_TPREL34:
case elfcpp::R_POWERPC_GOT_TPREL16:
case elfcpp::R_POWERPC_GOT_TPREL16_LO:
case elfcpp::R_POWERPC_GOT_TPREL16_HI:
case elfcpp::R_PPC64_TOC16:
case elfcpp::R_PPC64_TOC16_DS:
ppc_object->set_has_small_toc_reloc();
+ break;
+ default:
+ break;
+ }
+
+ 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_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:
+ case elfcpp::R_PPC64_TPREL34:
+ layout->set_has_static_tls();
+ break;
+ default:
+ break;
+ }
+
+ switch (r_type)
+ {
+ case elfcpp::R_PPC64_D34:
+ case elfcpp::R_PPC64_D34_LO:
+ case elfcpp::R_PPC64_D34_HI30:
+ case elfcpp::R_PPC64_D34_HA30:
+ case elfcpp::R_PPC64_D28:
+ case elfcpp::R_PPC64_PCREL34:
+ case elfcpp::R_PPC64_PCREL28:
+ case elfcpp::R_PPC64_TPREL34:
+ case elfcpp::R_PPC64_DTPREL34:
+ case elfcpp::R_PPC64_PLT_PCREL34:
+ case elfcpp::R_PPC64_PLT_PCREL34_NOTOC:
+ case elfcpp::R_PPC64_GOT_PCREL34:
+ case elfcpp::R_PPC64_GOT_TLSGD34:
+ case elfcpp::R_PPC64_GOT_TLSLD34:
+ case elfcpp::R_PPC64_GOT_DTPREL34:
+ case elfcpp::R_PPC64_GOT_TPREL34:
+ target->set_power10_stubs();
+ break;
default:
break;
}
Symbol_table* symtab,
Symbol* sym) const
{
- if (size == 64)
+ if (size == 64 && sym->object()->pluginobj() == NULL)
{
Powerpc_relobj<size, big_endian>* ppc_object
= static_cast<Powerpc_relobj<size, big_endian>*>(sym->object());
Powerpc_relobj<size, big_endian>* ppc_relobj
= static_cast<Powerpc_relobj<size, big_endian>*>(*p);
if (ppc_relobj->attributes_section_data())
- this->merge_object_attributes(ppc_relobj->name().c_str(),
+ this->merge_object_attributes(ppc_relobj,
ppc_relobj->attributes_section_data());
}
for (Input_objects::Dynobj_iterator p = input_objects->dynobj_begin();
Powerpc_dynobj<size, big_endian>* ppc_dynobj
= static_cast<Powerpc_dynobj<size, big_endian>*>(*p);
if (ppc_dynobj->attributes_section_data())
- this->merge_object_attributes(ppc_dynobj->name().c_str(),
+ this->merge_object_attributes(ppc_dynobj,
ppc_dynobj->attributes_section_data());
}
template<int size, bool big_endian>
void
Target_powerpc<size, big_endian>::merge_object_attributes(
- const char* name,
+ const Object* obj,
const Attributes_section_data* pasd)
{
// Return if there is no attributes section data.
Object_attribute* out_attr
= this->attributes_section_data_->known_attributes(vendor);
+ const char* name = obj->name().c_str();
const char* err;
const char* first;
const char* second;
int tag = elfcpp::Tag_GNU_Power_ABI_FP;
int in_fp = in_attr[tag].int_value() & 0xf;
int out_fp = out_attr[tag].int_value() & 0xf;
+ bool warn_only = obj->is_dynamic();
if (in_fp != out_fp)
{
err = NULL;
;
else if ((out_fp & 3) == 0)
{
- out_fp |= in_fp & 3;
- out_attr[tag].set_int_value(out_fp);
- out_attr[tag].set_type(Object_attribute::ATTR_TYPE_FLAG_INT_VAL);
- this->last_fp_ = name;
+ if (!warn_only)
+ {
+ out_fp |= in_fp & 3;
+ out_attr[tag].set_int_value(out_fp);
+ out_attr[tag].set_type(Object_attribute::ATTR_TYPE_FLAG_INT_VAL);
+ this->last_fp_ = name;
+ }
}
else if ((out_fp & 3) != 2 && (in_fp & 3) == 2)
{
;
else if ((out_fp & 0xc) == 0)
{
- out_fp |= in_fp & 0xc;
- out_attr[tag].set_int_value(out_fp);
- out_attr[tag].set_type(Object_attribute::ATTR_TYPE_FLAG_INT_VAL);
- this->last_ld_ = name;
+ if (!warn_only)
+ {
+ out_fp |= in_fp & 0xc;
+ out_attr[tag].set_int_value(out_fp);
+ out_attr[tag].set_type(Object_attribute::ATTR_TYPE_FLAG_INT_VAL);
+ this->last_ld_ = name;
+ }
}
else if ((out_fp & 0xc) != 2 * 4 && (in_fp & 0xc) == 2 * 4)
{
if (err)
{
if (parameters->options().warn_mismatch())
- gold_error(_(err), first, second);
+ {
+ if (warn_only)
+ gold_warning(_(err), first, second);
+ else
+ gold_error(_(err), first, second);
+ }
// Arrange for this attribute to be deleted. It's better to
// say "don't know" about a file than to wrongly claim compliance.
- out_attr[tag].set_type(0);
+ if (!warn_only)
+ out_attr[tag].set_type(0);
}
}
else if (r_type == elfcpp::R_POWERPC_GOT_TLSGD16
|| r_type == elfcpp::R_POWERPC_GOT_TLSGD16_LO
|| r_type == elfcpp::R_POWERPC_GOT_TLSGD16_HI
- || r_type == elfcpp::R_POWERPC_GOT_TLSGD16_HA)
+ || r_type == elfcpp::R_POWERPC_GOT_TLSGD16_HA
+ || r_type == elfcpp::R_PPC64_GOT_TLSGD34)
{
// First instruction of a global dynamic sequence, arg setup insn.
const bool final = gsym == NULL || gsym->final_value_is_known();
gold_assert(object->local_has_got_offset(r_sym, got_type));
value = object->local_got_offset(r_sym, got_type);
}
- value -= target->got_section()->got_base_offset(object);
+ if (r_type == elfcpp::R_PPC64_GOT_TLSGD34)
+ value += target->got_section()->address();
+ else
+ value -= target->got_section()->got_base_offset(object);
}
if (tls_type == tls::TLSOPT_TO_IE)
{
- if (r_type == elfcpp::R_POWERPC_GOT_TLSGD16
- || r_type == elfcpp::R_POWERPC_GOT_TLSGD16_LO)
+ if (r_type == elfcpp::R_PPC64_GOT_TLSGD34)
{
- Insn* iview = reinterpret_cast<Insn*>(view - d_offset);
- Insn insn = elfcpp::Swap<32, big_endian>::readval(iview);
- insn &= (1 << 26) - (1 << 16); // extract rt,ra from addi
- if (size == 32)
- insn |= 32 << 26; // lwz
- else
- insn |= 58 << 26; // ld
- elfcpp::Swap<32, big_endian>::writeval(iview, insn);
+ Insn* iview = reinterpret_cast<Insn*>(view);
+ uint64_t pinsn = elfcpp::Swap<32, big_endian>::readval(iview);
+ pinsn <<= 32;
+ pinsn |= elfcpp::Swap<32, big_endian>::readval(iview + 1);
+ // pla -> pld
+ pinsn += (-2ULL << 56) + (57ULL << 26) - (14ULL << 26);
+ elfcpp::Swap<32, big_endian>::writeval(iview, pinsn >> 32);
+ elfcpp::Swap<32, big_endian>::writeval(iview + 1,
+ pinsn & 0xffffffff);
+ r_type = elfcpp::R_PPC64_GOT_TPREL34;
+ }
+ else
+ {
+ if (r_type == elfcpp::R_POWERPC_GOT_TLSGD16
+ || r_type == elfcpp::R_POWERPC_GOT_TLSGD16_LO)
+ {
+ Insn* iview = reinterpret_cast<Insn*>(view - d_offset);
+ Insn insn = elfcpp::Swap<32, big_endian>::readval(iview);
+ insn &= (1 << 26) - (1 << 16); // extract rt,ra from addi
+ if (size == 32)
+ insn |= 32 << 26; // lwz
+ else
+ insn |= 58 << 26; // ld
+ elfcpp::Swap<32, big_endian>::writeval(iview, insn);
+ }
+ r_type += (elfcpp::R_POWERPC_GOT_TPREL16
+ - elfcpp::R_POWERPC_GOT_TLSGD16);
}
- r_type += (elfcpp::R_POWERPC_GOT_TPREL16
- - elfcpp::R_POWERPC_GOT_TLSGD16);
}
else if (tls_type == tls::TLSOPT_TO_LE)
{
- if (r_type == elfcpp::R_POWERPC_GOT_TLSGD16
- || r_type == elfcpp::R_POWERPC_GOT_TLSGD16_LO)
+ if (r_type == elfcpp::R_PPC64_GOT_TLSGD34)
{
- Insn* iview = reinterpret_cast<Insn*>(view - d_offset);
- Insn insn = elfcpp::Swap<32, big_endian>::readval(iview);
- insn &= (1 << 26) - (1 << 21); // extract rt
- if (size == 32)
- insn |= addis_0_2;
- else
- insn |= addis_0_13;
- elfcpp::Swap<32, big_endian>::writeval(iview, insn);
- r_type = elfcpp::R_POWERPC_TPREL16_HA;
+ Insn* iview = reinterpret_cast<Insn*>(view);
+ uint64_t pinsn = elfcpp::Swap<32, big_endian>::readval(iview);
+ pinsn <<= 32;
+ pinsn |= elfcpp::Swap<32, big_endian>::readval(iview + 1);
+ // pla pcrel -> paddi r13
+ pinsn += (-1ULL << 52) + (13ULL << 16);
+ elfcpp::Swap<32, big_endian>::writeval(iview, pinsn >> 32);
+ elfcpp::Swap<32, big_endian>::writeval(iview + 1,
+ pinsn & 0xffffffff);
+ r_type = elfcpp::R_PPC64_TPREL34;
value = psymval->value(object, rela.get_r_addend());
}
else
{
- Insn* iview = reinterpret_cast<Insn*>(view - d_offset);
- Insn insn = nop;
- elfcpp::Swap<32, big_endian>::writeval(iview, insn);
- r_type = elfcpp::R_POWERPC_NONE;
+ if (r_type == elfcpp::R_POWERPC_GOT_TLSGD16
+ || r_type == elfcpp::R_POWERPC_GOT_TLSGD16_LO)
+ {
+ Insn* iview = reinterpret_cast<Insn*>(view - d_offset);
+ Insn insn = elfcpp::Swap<32, big_endian>::readval(iview);
+ insn &= (1 << 26) - (1 << 21); // extract rt
+ if (size == 32)
+ insn |= addis_0_2;
+ else
+ insn |= addis_0_13;
+ elfcpp::Swap<32, big_endian>::writeval(iview, insn);
+ r_type = elfcpp::R_POWERPC_TPREL16_HA;
+ value = psymval->value(object, rela.get_r_addend());
+ }
+ else
+ {
+ Insn* iview = reinterpret_cast<Insn*>(view - d_offset);
+ Insn insn = nop;
+ elfcpp::Swap<32, big_endian>::writeval(iview, insn);
+ r_type = elfcpp::R_POWERPC_NONE;
+ }
}
}
}
else if (r_type == elfcpp::R_POWERPC_GOT_TLSLD16
|| r_type == elfcpp::R_POWERPC_GOT_TLSLD16_LO
|| r_type == elfcpp::R_POWERPC_GOT_TLSLD16_HI
- || r_type == elfcpp::R_POWERPC_GOT_TLSLD16_HA)
+ || r_type == elfcpp::R_POWERPC_GOT_TLSLD16_HA
+ || r_type == elfcpp::R_PPC64_GOT_TLSLD34)
{
// First instruction of a local dynamic sequence, arg setup insn.
const tls::Tls_optimization tls_type = target->optimize_tls_ld();
if (tls_type == tls::TLSOPT_NONE)
{
value = target->tlsld_got_offset();
- value -= target->got_section()->got_base_offset(object);
+ if (r_type == elfcpp::R_PPC64_GOT_TLSLD34)
+ value += target->got_section()->address();
+ else
+ value -= target->got_section()->got_base_offset(object);
}
else
{
gold_assert(tls_type == tls::TLSOPT_TO_LE);
- if (r_type == elfcpp::R_POWERPC_GOT_TLSLD16
- || r_type == elfcpp::R_POWERPC_GOT_TLSLD16_LO)
+ if (r_type == elfcpp::R_PPC64_GOT_TLSLD34)
+ {
+ Insn* iview = reinterpret_cast<Insn*>(view);
+ uint64_t pinsn = elfcpp::Swap<32, big_endian>::readval(iview);
+ pinsn <<= 32;
+ pinsn |= elfcpp::Swap<32, big_endian>::readval(iview + 1);
+ // pla pcrel -> paddi r13
+ pinsn += (-1ULL << 52) + (13ULL << 16);
+ elfcpp::Swap<32, big_endian>::writeval(iview, pinsn >> 32);
+ elfcpp::Swap<32, big_endian>::writeval(iview + 1,
+ pinsn & 0xffffffff);
+ r_type = elfcpp::R_PPC64_TPREL34;
+ value = dtp_offset;
+ }
+ else if (r_type == elfcpp::R_POWERPC_GOT_TLSLD16
+ || r_type == elfcpp::R_POWERPC_GOT_TLSLD16_LO)
{
Insn* iview = reinterpret_cast<Insn*>(view - d_offset);
Insn insn = elfcpp::Swap<32, big_endian>::readval(iview);
else if (r_type == elfcpp::R_POWERPC_GOT_DTPREL16
|| r_type == elfcpp::R_POWERPC_GOT_DTPREL16_LO
|| r_type == elfcpp::R_POWERPC_GOT_DTPREL16_HI
- || r_type == elfcpp::R_POWERPC_GOT_DTPREL16_HA)
+ || r_type == elfcpp::R_POWERPC_GOT_DTPREL16_HA
+ || r_type == elfcpp::R_PPC64_GOT_DTPREL34)
{
// Accesses relative to a local dynamic sequence address,
// no optimisation here.
gold_assert(object->local_has_got_offset(r_sym, GOT_TYPE_DTPREL));
value = object->local_got_offset(r_sym, GOT_TYPE_DTPREL);
}
- value -= target->got_section()->got_base_offset(object);
+ if (r_type == elfcpp::R_PPC64_GOT_DTPREL34)
+ value += target->got_section()->address();
+ else
+ value -= target->got_section()->got_base_offset(object);
}
else if (r_type == elfcpp::R_POWERPC_GOT_TPREL16
|| r_type == elfcpp::R_POWERPC_GOT_TPREL16_LO
|| r_type == elfcpp::R_POWERPC_GOT_TPREL16_HI
- || r_type == elfcpp::R_POWERPC_GOT_TPREL16_HA)
+ || r_type == elfcpp::R_POWERPC_GOT_TPREL16_HA
+ || r_type == elfcpp::R_PPC64_GOT_TPREL34)
{
// First instruction of initial exec sequence.
const bool final = gsym == NULL || gsym->final_value_is_known();
gold_assert(object->local_has_got_offset(r_sym, GOT_TYPE_TPREL));
value = object->local_got_offset(r_sym, GOT_TYPE_TPREL);
}
- value -= target->got_section()->got_base_offset(object);
+ if (r_type == elfcpp::R_PPC64_GOT_TPREL34)
+ value += target->got_section()->address();
+ else
+ value -= target->got_section()->got_base_offset(object);
}
else
{
gold_assert(tls_type == tls::TLSOPT_TO_LE);
- if (r_type == elfcpp::R_POWERPC_GOT_TPREL16
- || r_type == elfcpp::R_POWERPC_GOT_TPREL16_LO)
+ if (r_type == elfcpp::R_PPC64_GOT_TPREL34)
+ {
+ Insn* iview = reinterpret_cast<Insn*>(view);
+ uint64_t pinsn = elfcpp::Swap<32, big_endian>::readval(iview);
+ pinsn <<= 32;
+ pinsn |= elfcpp::Swap<32, big_endian>::readval(iview + 1);
+ // pld ra,sym@got@tprel@pcrel -> paddi ra,r13,sym@tprel
+ pinsn += ((2ULL << 56) + (-1ULL << 52)
+ + (14ULL << 26) - (57ULL << 26) + (13ULL << 16));
+ elfcpp::Swap<32, big_endian>::writeval(iview, pinsn >> 32);
+ elfcpp::Swap<32, big_endian>::writeval(iview + 1,
+ pinsn & 0xffffffff);
+ r_type = elfcpp::R_PPC64_TPREL34;
+ value = psymval->value(object, rela.get_r_addend());
+ }
+ else if (r_type == elfcpp::R_POWERPC_GOT_TPREL16
+ || r_type == elfcpp::R_POWERPC_GOT_TPREL16_LO)
{
Insn* iview = reinterpret_cast<Insn*>(view - d_offset);
Insn insn = elfcpp::Swap<32, big_endian>::readval(iview);
}
else
{
+ bool is_pcrel = false;
+ 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)
+ {
+ Reltype next_rela(preloc + reloc_size);
+ unsigned int r_type2
+ = elfcpp::elf_r_type<size>(next_rela.get_r_info());
+ if ((r_type2 == elfcpp::R_PPC64_REL24_NOTOC
+ || r_type2 == elfcpp::R_PPC64_PLTCALL_NOTOC)
+ && next_rela.get_r_offset() == rela.get_r_offset())
+ is_pcrel = true;
+ }
Insn* iview = reinterpret_cast<Insn*>(view);
- Insn insn = addi_3_3;
- elfcpp::Swap<32, big_endian>::writeval(iview, insn);
- r_type = elfcpp::R_POWERPC_TPREL16_LO;
- view += d_offset;
- value = psymval->value(object, rela.get_r_addend());
+ if (is_pcrel)
+ {
+ elfcpp::Swap<32, big_endian>::writeval(iview, nop);
+ r_type = elfcpp::R_POWERPC_NONE;
+ }
+ else
+ {
+ elfcpp::Swap<32, big_endian>::writeval(iview, addi_3_3);
+ r_type = elfcpp::R_POWERPC_TPREL16_LO;
+ view += d_offset;
+ value = psymval->value(object, rela.get_r_addend());
+ }
}
this->skip_next_tls_get_addr_call();
}
const tls::Tls_optimization tls_type = target->optimize_tls_ld();
if (tls_type == tls::TLSOPT_TO_LE)
{
+ bool is_pcrel = false;
+ 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)
+ {
+ Reltype next_rela(preloc + reloc_size);
+ unsigned int r_type2
+ = elfcpp::elf_r_type<size>(next_rela.get_r_info());
+ if ((r_type2 == elfcpp::R_PPC64_REL24_NOTOC
+ || r_type2 == elfcpp::R_PPC64_PLTCALL_NOTOC)
+ && next_rela.get_r_offset() == rela.get_r_offset())
+ is_pcrel = true;
+ }
Insn* iview = reinterpret_cast<Insn*>(view);
- Insn insn = addi_3_3;
- elfcpp::Swap<32, big_endian>::writeval(iview, insn);
+ if (is_pcrel)
+ {
+ elfcpp::Swap<32, big_endian>::writeval(iview, nop);
+ r_type = elfcpp::R_POWERPC_NONE;
+ }
+ else
+ {
+ elfcpp::Swap<32, big_endian>::writeval(iview, addi_3_3);
+ r_type = elfcpp::R_POWERPC_TPREL16_LO;
+ view += d_offset;
+ value = dtp_offset;
+ }
this->skip_next_tls_get_addr_call();
- r_type = elfcpp::R_POWERPC_TPREL16_LO;
- view += d_offset;
- value = dtp_offset;
}
}
else if (r_type == elfcpp::R_POWERPC_TLS)
const tls::Tls_optimization tls_type = target->optimize_tls_ie(final);
if (tls_type == tls::TLSOPT_TO_LE)
{
- Insn* iview = reinterpret_cast<Insn*>(view);
+ Address roff = rela.get_r_offset() & 3;
+ Insn* iview = reinterpret_cast<Insn*>(view - roff);
Insn insn = elfcpp::Swap<32, big_endian>::readval(iview);
unsigned int reg = size == 32 ? 2 : 13;
insn = at_tls_transform(insn, reg);
gold_assert(insn != 0);
- elfcpp::Swap<32, big_endian>::writeval(iview, insn);
- r_type = elfcpp::R_POWERPC_TPREL16_LO;
- view += d_offset;
- value = psymval->value(object, rela.get_r_addend());
+ if (roff == 0)
+ {
+ elfcpp::Swap<32, big_endian>::writeval(iview, insn);
+ r_type = elfcpp::R_POWERPC_TPREL16_LO;
+ view += d_offset;
+ value = psymval->value(object, rela.get_r_addend());
+ }
+ else if (roff == 1)
+ {
+ // For pcrel IE to LE we already have the full offset
+ // and thus don't need an addi here. A nop or mr will do.
+ if ((insn & (0x3f << 26)) == 14 << 26)
+ {
+ // Extract regs from addi rt,ra,si.
+ unsigned int rt = (insn >> 21) & 0x1f;
+ unsigned int ra = (insn >> 16) & 0x1f;
+ if (rt == ra)
+ insn = nop;
+ else
+ {
+ // Build or ra,rs,rb with rb==rs, ie. mr ra,rs.
+ insn = (rt << 16) | (ra << 21) | (ra << 11);
+ insn |= (31u << 26) | (444u << 1);
+ }
+ }
+ elfcpp::Swap<32, big_endian>::writeval(iview, insn);
+ r_type = elfcpp::R_POWERPC_NONE;
+ }
}
}
else if (!has_stub_value)
case elfcpp::R_PPC64_PLT_PCREL34:
case elfcpp::R_PPC64_PLT_PCREL34_NOTOC:
case elfcpp::R_PPC64_PCREL28:
+ case elfcpp::R_PPC64_GOT_TLSGD34:
+ case elfcpp::R_PPC64_GOT_TLSLD34:
+ case elfcpp::R_PPC64_GOT_TPREL34:
+ case elfcpp::R_PPC64_GOT_DTPREL34:
case elfcpp::R_PPC64_REL16_HIGHER34:
case elfcpp::R_PPC64_REL16_HIGHERA34:
case elfcpp::R_PPC64_REL16_HIGHEST34:
case elfcpp::R_PPC64_TPREL16_HIGHERA:
case elfcpp::R_PPC64_TPREL16_HIGHEST:
case elfcpp::R_PPC64_TPREL16_HIGHESTA:
+ case elfcpp::R_PPC64_TPREL34:
// tls symbol values are relative to tls_segment()->vaddr()
value -= tp_offset;
break;
case elfcpp::R_POWERPC_DTPREL:
case elfcpp::R_PPC64_DTPREL16_HIGH:
case elfcpp::R_PPC64_DTPREL16_HIGHA:
+ case elfcpp::R_PPC64_DTPREL34:
// tls symbol values are relative to tls_segment()->vaddr()
value -= dtp_offset;
break;
case elfcpp::R_PPC64_PLT_PCREL34_NOTOC:
case elfcpp::R_PPC64_D28:
case elfcpp::R_PPC64_PCREL28:
+ case elfcpp::R_PPC64_TPREL34:
+ case elfcpp::R_PPC64_DTPREL34:
+ case elfcpp::R_PPC64_GOT_TLSGD34:
+ case elfcpp::R_PPC64_GOT_TLSLD34:
+ case elfcpp::R_PPC64_GOT_TPREL34:
+ case elfcpp::R_PPC64_GOT_DTPREL34:
overflow = Reloc::CHECK_SIGNED;
break;
}
case elfcpp::R_PPC64_GOT_PCREL34:
case elfcpp::R_PPC64_PLT_PCREL34:
case elfcpp::R_PPC64_PLT_PCREL34_NOTOC:
+ case elfcpp::R_PPC64_TPREL34:
+ case elfcpp::R_PPC64_DTPREL34:
+ case elfcpp::R_PPC64_GOT_TLSGD34:
+ case elfcpp::R_PPC64_GOT_TLSLD34:
+ case elfcpp::R_PPC64_GOT_TPREL34:
+ case elfcpp::R_PPC64_GOT_DTPREL34:
if (size == 32)
goto unsupp;
status = Reloc::addr34(view, value, overflow);