power10_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),
void
set_power10_stubs()
{
- this->power10_stubs_ = true;
+ if (parameters->options().power10_stubs_enum()
+ != General_options::POWER10_STUBS_NO)
+ this->power10_stubs_ = true;
+ }
+
+ bool
+ power10_stubs_auto() const
+ {
+ return (parameters->options().power10_stubs_enum()
+ == General_options::POWER10_STUBS_AUTO);
}
bool
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_;
struct Plt_stub_ent
{
Plt_stub_ent(unsigned int off, unsigned int indx)
- : off_(off), indx_(indx), iter_(0), notoc_(0), r2save_(0), localentry0_(0)
+ : off_(off), indx_(indx), iter_(0), notoc_(0), toc_(0),
+ r2save_(0), localentry0_(0), tocoff_(0)
{ }
unsigned int off_;
- unsigned int indx_ : 28;
+ unsigned int indx_;
unsigned int iter_ : 1;
unsigned int notoc_ : 1;
+ unsigned int toc_ : 1;
unsigned int r2save_ : 1;
unsigned int localentry0_ : 1;
+ unsigned int tocoff_ : 8;
};
struct Branch_stub_ent
{
Branch_stub_ent(unsigned int off, bool notoc, bool save_res)
- : off_(off), iter_(false), notoc_(notoc), save_res_(save_res)
+ : off_(off), iter_(0), notoc_(notoc), toc_(0), save_res_(save_res),
+ tocoff_(0)
{ }
unsigned int off_;
- bool iter_;
- bool notoc_;
- bool save_res_;
+ unsigned int iter_ : 1;
+ unsigned int notoc_ : 1;
+ unsigned int toc_ : 1;
+ unsigned int save_res_ : 1;
+ unsigned int tocoff_ : 8;
};
typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
static const Address invalid_address = static_cast<Address>(0) - 1;
// Size of a given plt call stub.
unsigned int
- plt_call_size(typename Plt_stub_entries::const_iterator p) const;
+ plt_call_size(typename Plt_stub_entries::iterator p) const;
unsigned int
plt_call_align(unsigned int bytes) const
// Return long branch stub size.
unsigned int
- branch_stub_size(typename Branch_stub_entries::const_iterator p,
+ branch_stub_size(typename Branch_stub_entries::iterator p,
bool* need_lt);
- bool
- build_tls_opt_head(unsigned char** pp,
- typename Plt_stub_entries::const_iterator cs);
+ void
+ build_tls_opt_head(unsigned char** pp, bool save_lr);
- bool
- build_tls_opt_tail(unsigned char* p,
- typename Plt_stub_entries::const_iterator cs);
+ void
+ build_tls_opt_tail(unsigned char* p);
void
plt_error(const Plt_stub_key& p);
if (r_type == elfcpp::R_PPC64_REL24_NOTOC)
{
if (!p.second && !p.first->second.notoc_
- && !this->targ_->power10_stubs())
+ && (!this->targ_->power10_stubs()
+ || this->targ_->power10_stubs_auto()))
this->need_resize_ = true;
p.first->second.notoc_ = 1;
}
- else if (!tocsave && !p.first->second.localentry0_)
+ else
{
- if (!p.second && !p.first->second.r2save_)
+ if (!p.second && !p.first->second.toc_)
this->need_resize_ = true;
- p.first->second.r2save_ = 1;
+ p.first->second.toc_ = 1;
+ if (!tocsave && !p.first->second.localentry0_)
+ {
+ if (!p.second && !p.first->second.r2save_)
+ this->need_resize_ = true;
+ p.first->second.r2save_ = 1;
+ }
}
}
if (p.second || (this->resizing_ && !p.first->second.iter_))
if (r_type == elfcpp::R_PPC64_REL24_NOTOC)
{
if (!p.second && !p.first->second.notoc_
- && !this->targ_->power10_stubs())
+ && (!this->targ_->power10_stubs()
+ || this->targ_->power10_stubs_auto()))
this->need_resize_ = true;
p.first->second.notoc_ = 1;
}
- else if (!tocsave && !p.first->second.localentry0_)
+ else
{
- if (!p.second && !p.first->second.r2save_)
+ if (!p.second && !p.first->second.toc_)
this->need_resize_ = true;
- p.first->second.r2save_ = 1;
+ p.first->second.toc_ = 1;
+ if (!tocsave && !p.first->second.localentry0_)
+ {
+ if (!p.second && !p.first->second.r2save_)
+ this->need_resize_ = true;
+ p.first->second.r2save_ = 1;
+ }
}
}
if (p.second || (this->resizing_ && !p.first->second.iter_))
Branch_stub_ent ent(this->branch_size_, notoc, save_res);
std::pair<typename Branch_stub_entries::iterator, bool> p
= this->long_branch_stubs_.insert(std::make_pair(key, ent));
- if (notoc && !p.first->second.notoc_)
+ if (notoc)
{
- this->need_resize_ = true;
+ if (!p.second && !p.first->second.notoc_)
+ this->need_resize_ = true;
p.first->second.notoc_ = true;
}
+ else
+ {
+ if (!p.second && !p.first->second.toc_)
+ this->need_resize_ = true;
+ p.first->second.toc_ = true;
+ }
gold_assert(save_res == p.first->second.save_res_);
if (p.second || (this->resizing_ && !p.first->second.iter_))
{
if (!this->targ_->has_glink())
return;
- typedef typename Plt_stub_entries::const_iterator plt_iter;
+ typedef typename Plt_stub_entries::iterator plt_iter;
std::vector<plt_iter> calls;
if (!this->plt_call_stubs_.empty())
for (plt_iter cs = this->plt_call_stubs_.begin();
// output .symtab ordering depends on the order in which symbols
// are added to the linker symtab. We want reproducible output
// so must sort the call stub symbols.
- typedef typename Plt_stub_entries::const_iterator plt_iter;
+ typedef typename Plt_stub_entries::iterator plt_iter;
std::vector<plt_iter> sorted;
sorted.resize(this->plt_call_stubs_.size());
}
}
- typedef typename Branch_stub_entries::const_iterator branch_iter;
+ typedef typename Branch_stub_entries::iterator branch_iter;
for (branch_iter bs = this->long_branch_stubs_.begin();
bs != this->long_branch_stubs_.end();
++bs)
// Emit the start of a __tls_get_addr_opt plt call stub.
template<int size, bool big_endian>
-bool
-Stub_table<size, big_endian>::build_tls_opt_head(
- unsigned char** pp,
- typename Plt_stub_entries::const_iterator cs)
+void
+Stub_table<size, big_endian>::build_tls_opt_head(unsigned char** pp,
+ bool save_lr)
{
- if (this->targ_->is_tls_get_addr_opt(cs->first.sym_))
+ unsigned char* p = *pp;
+ if (size == 64)
{
- unsigned char* p = *pp;
- if (size == 64)
- {
- write_insn<big_endian>(p, ld_11_3 + 0);
- p += 4;
- write_insn<big_endian>(p, ld_12_3 + 8);
- p += 4;
- write_insn<big_endian>(p, mr_0_3);
- p += 4;
- write_insn<big_endian>(p, cmpdi_11_0);
- p += 4;
- write_insn<big_endian>(p, add_3_12_13);
- p += 4;
- write_insn<big_endian>(p, beqlr);
- p += 4;
- write_insn<big_endian>(p, mr_3_0);
- p += 4;
- if (cs->second.r2save_ && !cs->second.localentry0_)
- {
- write_insn<big_endian>(p, mflr_11);
- p += 4;
- write_insn<big_endian>(p, (std_11_1 + this->targ_->stk_linker()));
- p += 4;
- }
- }
- else
+ write_insn<big_endian>(p, ld_11_3 + 0);
+ p += 4;
+ write_insn<big_endian>(p, ld_12_3 + 8);
+ p += 4;
+ write_insn<big_endian>(p, mr_0_3);
+ p += 4;
+ write_insn<big_endian>(p, cmpdi_11_0);
+ p += 4;
+ write_insn<big_endian>(p, add_3_12_13);
+ p += 4;
+ write_insn<big_endian>(p, beqlr);
+ p += 4;
+ write_insn<big_endian>(p, mr_3_0);
+ p += 4;
+ if (save_lr)
{
- write_insn<big_endian>(p, lwz_11_3 + 0);
- p += 4;
- write_insn<big_endian>(p, lwz_12_3 + 4);
- p += 4;
- write_insn<big_endian>(p, mr_0_3);
- p += 4;
- write_insn<big_endian>(p, cmpwi_11_0);
- p += 4;
- write_insn<big_endian>(p, add_3_12_2);
- p += 4;
- write_insn<big_endian>(p, beqlr);
+ write_insn<big_endian>(p, mflr_11);
p += 4;
- write_insn<big_endian>(p, mr_3_0);
- p += 4;
- write_insn<big_endian>(p, nop);
+ write_insn<big_endian>(p, (std_11_1 + this->targ_->stk_linker()));
p += 4;
}
- *pp = p;
- return true;
}
- return false;
-}
-
-// Emit the tail of a __tls_get_addr_opt plt call stub.
-
-template<int size, bool big_endian>
-bool
-Stub_table<size, big_endian>::build_tls_opt_tail(
- unsigned char* p,
- typename Plt_stub_entries::const_iterator cs)
-{
- if (size == 64
- && cs->second.r2save_
- && !cs->second.localentry0_
- && this->targ_->is_tls_get_addr_opt(cs->first.sym_))
+ else
{
- write_insn<big_endian>(p, bctrl);
+ write_insn<big_endian>(p, lwz_11_3 + 0);
p += 4;
- write_insn<big_endian>(p, ld_2_1 + this->targ_->stk_toc());
+ write_insn<big_endian>(p, lwz_12_3 + 4);
p += 4;
- write_insn<big_endian>(p, ld_11_1 + this->targ_->stk_linker());
+ write_insn<big_endian>(p, mr_0_3);
p += 4;
- write_insn<big_endian>(p, mtlr_11);
+ write_insn<big_endian>(p, cmpwi_11_0);
+ p += 4;
+ write_insn<big_endian>(p, add_3_12_2);
+ p += 4;
+ write_insn<big_endian>(p, beqlr);
+ p += 4;
+ write_insn<big_endian>(p, mr_3_0);
+ p += 4;
+ write_insn<big_endian>(p, nop);
p += 4;
- write_insn<big_endian>(p, blr);
- return true;
}
- return false;
+ *pp = p;
+}
+
+// Emit the tail of a __tls_get_addr_opt plt call stub.
+
+template<int size, bool big_endian>
+void
+Stub_table<size, big_endian>::build_tls_opt_tail(unsigned char* p)
+{
+ write_insn<big_endian>(p, bctrl);
+ p += 4;
+ write_insn<big_endian>(p, ld_2_1 + this->targ_->stk_toc());
+ p += 4;
+ write_insn<big_endian>(p, ld_11_1 + this->targ_->stk_linker());
+ p += 4;
+ write_insn<big_endian>(p, mtlr_11);
+ p += 4;
+ write_insn<big_endian>(p, blr);
}
// Emit pc-relative plt call stub code.
template<int size, bool big_endian>
unsigned int
Stub_table<size, big_endian>::plt_call_size(
- typename Plt_stub_entries::const_iterator p) const
+ typename Plt_stub_entries::iterator p) const
{
if (size == 32)
{
const Output_data_plt_powerpc<size, big_endian>* plt;
uint64_t plt_addr = this->plt_off(p, &plt);
plt_addr += plt->address();
- unsigned int bytes = 0;
- const Symbol* gsym = p->first.sym_;
- if (this->targ_->is_tls_get_addr_opt(gsym))
+ if (this->targ_->power10_stubs()
+ && this->targ_->power10_stubs_auto())
{
- if (p->second.r2save_ && !p->second.localentry0_)
- bytes = 13 * 4;
- else
- bytes = 7 * 4;
+ unsigned int bytes = 0;
+ if (p->second.notoc_)
+ {
+ if (this->targ_->is_tls_get_addr_opt(p->first.sym_))
+ bytes = 7 * 4;
+ uint64_t from = this->stub_address() + p->second.off_ + bytes;
+ uint64_t odd = from & 4;
+ uint64_t off = plt_addr - from;
+ if (off - odd + (1ULL << 33) < 1ULL << 34)
+ bytes += odd + 4 * 4;
+ else if (off - (8 - odd) + (0x20002ULL << 32) < 0x40004ULL << 32)
+ bytes += 7 * 4;
+ else
+ bytes += 8 * 4;
+ bytes = this->plt_call_align(bytes);
+ }
+ unsigned int tail = 0;
+ if (p->second.toc_)
+ {
+ p->second.tocoff_ = bytes;
+ if (this->targ_->is_tls_get_addr_opt(p->first.sym_))
+ {
+ bytes += 7 * 4;
+ if (p->second.r2save_ && !p->second.localentry0_)
+ {
+ bytes += 2 * 4;
+ tail = 4 * 4;
+ }
+ }
+ if (p->second.r2save_)
+ bytes += 4;
+ uint64_t 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_);
+ got_addr += ppcobj->toc_base_offset();
+ uint64_t off = plt_addr - got_addr;
+ bytes += 3 * 4 + 4 * (ha(off) != 0);
+ }
+ return bytes + tail;
}
+ else
+ {
+ unsigned int bytes = 0;
+ unsigned int tail = 0;
+ if (this->targ_->is_tls_get_addr_opt(p->first.sym_))
+ {
+ bytes = 7 * 4;
+ if (p->second.r2save_ && !p->second.localentry0_)
+ {
+ bytes = 9 * 4;
+ tail = 4 * 4;
+ }
+ }
- if (p->second.r2save_)
- bytes += 4;
+ if (p->second.r2save_)
+ bytes += 4;
- if (this->targ_->power10_stubs())
- {
- uint64_t from = this->stub_address() + p->second.off_ + bytes;
- if (bytes > 8 * 4)
- from -= 4 * 4;
- uint64_t odd = from & 4;
- uint64_t off = plt_addr - from;
- if (off - odd + (1ULL << 33) < 1ULL << 34)
- bytes += odd + 4 * 4;
- else if (off - (8 - odd) + (0x20002ULL << 32) < 0x40004ULL << 32)
- bytes += 7 * 4;
- else
- bytes += 8 * 4;
- return bytes;
- }
+ if (this->targ_->power10_stubs())
+ {
+ uint64_t from = this->stub_address() + p->second.off_ + bytes;
+ uint64_t odd = from & 4;
+ uint64_t off = plt_addr - from;
+ if (off - odd + (1ULL << 33) < 1ULL << 34)
+ bytes += odd + 4 * 4;
+ else if (off - (8 - odd) + (0x20002ULL << 32) < 0x40004ULL << 32)
+ bytes += 7 * 4;
+ else
+ bytes += 8 * 4;
+ return bytes + tail;
+ }
- if (p->second.notoc_)
- {
- uint64_t from = this->stub_address() + p->second.off_ + bytes + 2 * 4;
- if (bytes > 32)
- from -= 4 * 4;
- uint64_t off = plt_addr - from;
- if (off + 0x8000 < 0x10000)
- bytes += 7 * 4;
- else if (off + 0x80008000ULL < 0x100000000ULL)
- bytes += 8 * 4;
- else
+ if (p->second.notoc_)
{
- bytes += 8 * 4;
- if (off + 0x800000000000ULL >= 0x1000000000000ULL
- && ((off >> 32) & 0xffff) != 0)
- bytes += 4;
- if (((off >> 32) & 0xffffffffULL) != 0)
- bytes += 4;
- if (hi(off) != 0)
- bytes += 4;
- if (l(off) != 0)
- bytes += 4;
+ uint64_t from = this->stub_address() + p->second.off_ + bytes + 2 * 4;
+ uint64_t off = plt_addr - from;
+ if (off + 0x8000 < 0x10000)
+ bytes += 7 * 4;
+ else if (off + 0x80008000ULL < 0x100000000ULL)
+ bytes += 8 * 4;
+ else
+ {
+ bytes += 8 * 4;
+ if (off + 0x800000000000ULL >= 0x1000000000000ULL
+ && ((off >> 32) & 0xffff) != 0)
+ bytes += 4;
+ if (((off >> 32) & 0xffffffffULL) != 0)
+ bytes += 4;
+ if (hi(off) != 0)
+ bytes += 4;
+ if (l(off) != 0)
+ bytes += 4;
+ }
+ return bytes + tail;
}
- return bytes;
- }
- uint64_t 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_);
- got_addr += ppcobj->toc_base_offset();
- uint64_t off = plt_addr - got_addr;
- bytes += 3 * 4 + 4 * (ha(off) != 0);
- if (this->targ_->abiversion() < 2)
- {
- bool static_chain = parameters->options().plt_static_chain();
- bool thread_safe = this->targ_->plt_thread_safe();
- bytes += (4
- + 4 * static_chain
- + 8 * thread_safe
- + 4 * (ha(off + 8 + 8 * static_chain) != ha(off)));
+ uint64_t 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_);
+ got_addr += ppcobj->toc_base_offset();
+ uint64_t off = plt_addr - got_addr;
+ bytes += 3 * 4 + 4 * (ha(off) != 0);
+ if (this->targ_->abiversion() < 2)
+ {
+ bool static_chain = parameters->options().plt_static_chain();
+ bool thread_safe = this->targ_->plt_thread_safe();
+ bytes += (4
+ + 4 * static_chain
+ + 8 * thread_safe
+ + 4 * (ha(off + 8 + 8 * static_chain) != ha(off)));
+ }
+ return bytes + tail;
}
- return bytes;
}
// Return long branch stub size.
template<int size, bool big_endian>
unsigned int
Stub_table<size, big_endian>::branch_stub_size(
- typename Branch_stub_entries::const_iterator p,
+ typename Branch_stub_entries::iterator p,
bool* need_lt)
{
Address loc = this->stub_address() + this->last_plt_size_ + p->second.off_;
}
uint64_t off = p->first.dest_ - loc;
+ unsigned int bytes = 0;
if (p->second.notoc_)
{
if (this->targ_->power10_stubs())
{
Address odd = loc & 4;
if (off + (1 << 25) < 2 << 25)
- return odd + 12;
- if (off - odd + (1ULL << 33) < 1ULL << 34)
- return odd + 16;
- if (off - (8 - odd) + (0x20002ULL << 32) < 0x40004ULL << 32)
- return 28;
- return 32;
- }
- off -= 8;
- if (off + 0x8000 < 0x10000)
- return 24;
- if (off + 0x80008000ULL < 0x100000000ULL)
- {
- if (off + 24 + (1 << 25) < 2 << 25)
- return 28;
- return 32;
- }
- unsigned int bytes = 32;
- if (off + 0x800000000000ULL >= 0x1000000000000ULL
- && ((off >> 32) & 0xffff) != 0)
- bytes += 4;
- if (((off >> 32) & 0xffffffffULL) != 0)
- bytes += 4;
- if (hi(off) != 0)
- bytes += 4;
- if (l(off) != 0)
- bytes += 4;
- return bytes;
+ bytes = odd + 12;
+ else if (off - odd + (1ULL << 33) < 1ULL << 34)
+ bytes = odd + 16;
+ else if (off - (8 - odd) + (0x20002ULL << 32) < 0x40004ULL << 32)
+ bytes = 28;
+ else
+ bytes = 32;
+ if (!(p->second.toc_ && this->targ_->power10_stubs_auto()))
+ return bytes;
+ p->second.tocoff_ = bytes;
+ }
+ else
+ {
+ off -= 8;
+ if (off + 0x8000 < 0x10000)
+ return 24;
+ if (off + 0x80008000ULL < 0x100000000ULL)
+ {
+ if (off + 24 + (1 << 25) < 2 << 25)
+ return 28;
+ return 32;
+ }
+
+ bytes = 32;
+ if (off + 0x800000000000ULL >= 0x1000000000000ULL
+ && ((off >> 32) & 0xffff) != 0)
+ bytes += 4;
+ if (((off >> 32) & 0xffffffffULL) != 0)
+ bytes += 4;
+ if (hi(off) != 0)
+ bytes += 4;
+ if (l(off) != 0)
+ bytes += 4;
+ return bytes;
+ }
}
if (off + (1 << 25) < 2 << 25)
- return 4;
- if (!this->targ_->power10_stubs())
+ return bytes + 4;
+ if (!this->targ_->power10_stubs()
+ || (p->second.toc_ && this->targ_->power10_stubs_auto()))
*need_lt = true;
- return 16;
+ return bytes + 16;
}
template<int size, bool big_endian>
if (size == 64
&& this->targ_->power10_stubs())
{
+ const Output_data_got_powerpc<size, big_endian>* got
+ = this->targ_->got_section();
+ Address got_os_addr = got->output_section()->address();
+
if (!this->plt_call_stubs_.empty())
{
// Write out plt call stubs.
++cs)
{
p = oview + cs->second.off_;
- this->build_tls_opt_head(&p, cs);
- if (cs->second.r2save_)
- {
- write_insn<big_endian>(p, std_2_1 + this->targ_->stk_toc());
- p += 4;
- }
const Output_data_plt_powerpc<size, big_endian>* plt;
Address pltoff = this->plt_off(cs, &plt);
Address plt_addr = pltoff + plt->address();
- Address from = this->stub_address() + (p - oview);
- Address delta = plt_addr - from;
- 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))
- write_insn<big_endian>(p, bctr);
+ if (this->targ_->power10_stubs_auto())
+ {
+ if (cs->second.notoc_)
+ {
+ if (this->targ_->is_tls_get_addr_opt(cs->first.sym_))
+ this->build_tls_opt_head(&p, false);
+ Address from = this->stub_address() + (p - oview);
+ Address delta = plt_addr - from;
+ p = build_power10_offset<big_endian>(p, delta, from & 4,
+ true);
+ write_insn<big_endian>(p, mtctr_12);
+ p += 4;
+ write_insn<big_endian>(p, bctr);
+ p += 4;
+ p = oview + this->plt_call_align(p - oview);
+ }
+ if (cs->second.toc_)
+ {
+ if (this->targ_->is_tls_get_addr_opt(cs->first.sym_))
+ {
+ bool save_lr
+ = cs->second.r2save_ && !cs->second.localentry0_;
+ this->build_tls_opt_head(&p, save_lr);
+ }
+ 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();
+ Address off = plt_addr - got_addr;
+
+ if (off + 0x80008000 > 0xffffffff || (off & 7) != 0)
+ this->plt_error(cs->first);
+
+ if (cs->second.r2save_)
+ {
+ write_insn<big_endian>(p, std_2_1 + this->targ_->stk_toc());
+ p += 4;
+ }
+ if (ha(off) != 0)
+ {
+ write_insn<big_endian>(p, addis_12_2 + ha(off));
+ p += 4;
+ write_insn<big_endian>(p, ld_12_12 + l(off));
+ p += 4;
+ }
+ else
+ {
+ write_insn<big_endian>(p, ld_12_2 + l(off));
+ p += 4;
+ }
+ write_insn<big_endian>(p, mtctr_12);
+ p += 4;
+ if (cs->second.r2save_
+ && !cs->second.localentry0_
+ && this->targ_->is_tls_get_addr_opt(cs->first.sym_))
+ this->build_tls_opt_tail(p);
+ else
+ write_insn<big_endian>(p, bctr);
+ }
+ }
+ else
+ {
+ if (this->targ_->is_tls_get_addr_opt(cs->first.sym_))
+ {
+ bool save_lr
+ = cs->second.r2save_ && !cs->second.localentry0_;
+ this->build_tls_opt_head(&p, save_lr);
+ }
+ if (cs->second.r2save_)
+ {
+ write_insn<big_endian>(p, std_2_1 + this->targ_->stk_toc());
+ p += 4;
+ }
+ Address from = this->stub_address() + (p - oview);
+ Address delta = plt_addr - from;
+ p = build_power10_offset<big_endian>(p, delta, from & 4, true);
+ write_insn<big_endian>(p, mtctr_12);
+ p += 4;
+ if (cs->second.r2save_
+ && !cs->second.localentry0_
+ && this->targ_->is_tls_get_addr_opt(cs->first.sym_))
+ this->build_tls_opt_tail(p);
+ else
+ write_insn<big_endian>(p, bctr);
+ }
}
}
p = oview + off;
Address loc = this->stub_address() + off;
Address delta = bs->first.dest_ - loc;
- if (bs->second.notoc_ || delta + (1 << 25) >= 2 << 25)
+ if (this->targ_->power10_stubs_auto())
{
- unsigned char* startp = p;
- p = build_power10_offset<big_endian>(p, delta, loc & 4, false);
- delta -= p - startp;
+ if (bs->second.notoc_)
+ {
+ unsigned char* startp = p;
+ p = build_power10_offset<big_endian>(p, delta,
+ loc & 4, false);
+ delta -= p - startp;
+ startp = p;
+ if (delta + (1 << 25) < 2 << 25)
+ write_insn<big_endian>(p, b | (delta & 0x3fffffc));
+ else
+ {
+ write_insn<big_endian>(p, mtctr_12);
+ p += 4;
+ write_insn<big_endian>(p, bctr);
+ }
+ p += 4;
+ delta -= p - startp;
+ }
+ if (bs->second.toc_)
+ {
+ if (delta + (1 << 25) >= 2 << 25)
+ {
+ Address brlt_addr
+ = this->targ_->find_branch_lookup_table(bs->first.dest_);
+ gold_assert(brlt_addr != invalid_address);
+ brlt_addr += this->targ_->brlt_section()->address();
+ Address got_addr = got_os_addr + bs->first.toc_base_off_;
+ Address brltoff = brlt_addr - got_addr;
+ if (ha(brltoff) == 0)
+ {
+ write_insn<big_endian>(p, ld_12_2 + l(brltoff));
+ p += 4;
+ }
+ else
+ {
+ write_insn<big_endian>(p, addis_12_2 + ha(brltoff));
+ p += 4;
+ write_insn<big_endian>(p, ld_12_12 + l(brltoff));
+ p += 4;
+ }
+ }
+ if (delta + (1 << 25) < 2 << 25)
+ write_insn<big_endian>(p, b | (delta & 0x3fffffc));
+ else
+ {
+ write_insn<big_endian>(p, mtctr_12);
+ p += 4;
+ write_insn<big_endian>(p, bctr);
+ }
+ }
}
- if (delta + (1 << 25) < 2 << 25)
- write_insn<big_endian>(p, b | (delta & 0x3fffffc));
else
{
- write_insn<big_endian>(p, mtctr_12);
- p += 4;
- write_insn<big_endian>(p, bctr);
+ if (bs->second.notoc_ || delta + (1 << 25) >= 2 << 25)
+ {
+ unsigned char* startp = p;
+ p = build_power10_offset<big_endian>(p, delta,
+ loc & 4, false);
+ delta -= p - startp;
+ }
+ if (delta + (1 << 25) < 2 << 25)
+ write_insn<big_endian>(p, b | (delta & 0x3fffffc));
+ else
+ {
+ write_insn<big_endian>(p, mtctr_12);
+ p += 4;
+ write_insn<big_endian>(p, bctr);
+ }
}
}
}
Address plt_addr = pltoff + plt->address();
p = oview + cs->second.off_;
- this->build_tls_opt_head(&p, cs);
+ if (this->targ_->is_tls_get_addr_opt(cs->first.sym_))
+ {
+ bool save_lr = cs->second.r2save_ && !cs->second.localentry0_;
+ this->build_tls_opt_head(&p, save_lr);
+ }
if (cs->second.r2save_)
{
write_insn<big_endian>(p, std_2_1 + this->targ_->stk_toc());
}
write_insn<big_endian>(p, mtctr_12);
p += 4;
- if (!this->build_tls_opt_tail(p, cs))
+ if (cs->second.r2save_
+ && !cs->second.localentry0_
+ && this->targ_->is_tls_get_addr_opt(cs->first.sym_))
+ this->build_tls_opt_tail(p);
+ else
write_insn<big_endian>(p, bctr);
}
}
}
p = oview + cs->second.off_;
- if (this->build_tls_opt_head(&p, cs))
- use_fake_dep = thread_safe;
+ if (this->targ_->is_tls_get_addr_opt(cs->first.sym_))
+ {
+ bool save_lr = cs->second.r2save_ && !cs->second.localentry0_;
+ this->build_tls_opt_head(&p, save_lr);
+ use_fake_dep = thread_safe;
+ }
if (cs->second.r2save_)
{
write_insn<big_endian>(p, std_2_1 + this->targ_->stk_toc());
write_insn<big_endian>(p, ld_2_2 + l(off + 8));
p += 4;
}
- if (this->build_tls_opt_tail(p, cs))
- ;
+ if (cs->second.r2save_
+ && !cs->second.localentry0_
+ && this->targ_->is_tls_get_addr_opt(cs->first.sym_))
+ this->build_tls_opt_tail(p);
else if (thread_safe && !use_fake_dep)
{
write_insn<big_endian>(p, cmpldi_2_0);
plt_addr += plt->address();
p = oview + cs->second.off_;
- this->build_tls_opt_head(&p, cs);
+ if (this->targ_->is_tls_get_addr_opt(cs->first.sym_))
+ this->build_tls_opt_head(&p, false);
if (parameters->options().output_is_position_independent())
{
Address got_addr;
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:
+ case elfcpp::R_PPC64_GOT_TLSGD_PCREL34:
+ case elfcpp::R_PPC64_GOT_TLSLD_PCREL34:
+ case elfcpp::R_PPC64_GOT_TPREL_PCREL34:
+ case elfcpp::R_PPC64_GOT_DTPREL_PCREL34:
ref = Symbol::TLS_REF;
break;
target->got_section(symtab, layout);
break;
- case elfcpp::R_PPC64_GOT_TLSGD34:
+ case elfcpp::R_PPC64_GOT_TLSGD_PCREL34:
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_PPC64_GOT_TLSLD_PCREL34:
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_PPC64_GOT_DTPREL_PCREL34:
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_PPC64_GOT_TPREL_PCREL34:
case elfcpp::R_POWERPC_GOT_TPREL16:
case elfcpp::R_POWERPC_GOT_TPREL16_LO:
case elfcpp::R_POWERPC_GOT_TPREL16_HI:
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:
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:
+ case elfcpp::R_PPC64_GOT_TLSGD_PCREL34:
+ case elfcpp::R_PPC64_GOT_TLSLD_PCREL34:
+ case elfcpp::R_PPC64_GOT_DTPREL_PCREL34:
+ case elfcpp::R_PPC64_GOT_TPREL_PCREL34:
target->set_power10_stubs();
break;
default:
target->got_section(symtab, layout);
break;
- case elfcpp::R_PPC64_GOT_TLSGD34:
+ case elfcpp::R_PPC64_GOT_TLSGD_PCREL34:
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_PPC64_GOT_TLSLD_PCREL34:
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_PPC64_GOT_DTPREL_PCREL34:
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_PPC64_GOT_TPREL_PCREL34:
case elfcpp::R_POWERPC_GOT_TPREL16:
case elfcpp::R_POWERPC_GOT_TPREL16_LO:
case elfcpp::R_POWERPC_GOT_TPREL16_HI:
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:
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:
+ case elfcpp::R_PPC64_GOT_TLSGD_PCREL34:
+ case elfcpp::R_PPC64_GOT_TLSLD_PCREL34:
+ case elfcpp::R_PPC64_GOT_DTPREL_PCREL34:
+ case elfcpp::R_PPC64_GOT_TPREL_PCREL34:
target->set_power10_stubs();
break;
default:
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 (size == 64
+ && r_type != elfcpp::R_PPC64_REL24_NOTOC)
+ value += ent->tocoff_;
if (size == 64
&& ent->r2save_
&& r_type == elfcpp::R_PPC64_REL24_NOTOC)
- value += 4;
+ {
+ if (!(target->power10_stubs()
+ && target->power10_stubs_auto()))
+ value += 4;
+ }
else if (size == 64
&& ent->r2save_
&& relnum < reloc_count - 1)
|| 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_PPC64_GOT_TLSGD34)
+ || r_type == elfcpp::R_PPC64_GOT_TLSGD_PCREL34)
{
// 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);
}
- if (r_type == elfcpp::R_PPC64_GOT_TLSGD34)
+ if (r_type == elfcpp::R_PPC64_GOT_TLSGD_PCREL34)
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_PPC64_GOT_TLSGD34)
+ if (r_type == elfcpp::R_PPC64_GOT_TLSGD_PCREL34)
{
Insn* iview = reinterpret_cast<Insn*>(view);
uint64_t pinsn = elfcpp::Swap<32, big_endian>::readval(iview);
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;
+ r_type = elfcpp::R_PPC64_GOT_TPREL_PCREL34;
}
else
{
}
else if (tls_type == tls::TLSOPT_TO_LE)
{
- if (r_type == elfcpp::R_PPC64_GOT_TLSGD34)
+ if (r_type == elfcpp::R_PPC64_GOT_TLSGD_PCREL34)
{
Insn* iview = reinterpret_cast<Insn*>(view);
uint64_t pinsn = elfcpp::Swap<32, big_endian>::readval(iview);
|| 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_PPC64_GOT_TLSLD34)
+ || r_type == elfcpp::R_PPC64_GOT_TLSLD_PCREL34)
{
// 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();
- if (r_type == elfcpp::R_PPC64_GOT_TLSLD34)
+ if (r_type == elfcpp::R_PPC64_GOT_TLSLD_PCREL34)
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_PPC64_GOT_TLSLD34)
+ if (r_type == elfcpp::R_PPC64_GOT_TLSLD_PCREL34)
{
Insn* iview = reinterpret_cast<Insn*>(view);
uint64_t pinsn = elfcpp::Swap<32, big_endian>::readval(iview);
|| 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_PPC64_GOT_DTPREL34)
+ || r_type == elfcpp::R_PPC64_GOT_DTPREL_PCREL34)
{
// 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);
}
- if (r_type == elfcpp::R_PPC64_GOT_DTPREL34)
+ if (r_type == elfcpp::R_PPC64_GOT_DTPREL_PCREL34)
value += target->got_section()->address();
else
value -= target->got_section()->got_base_offset(object);
|| 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_PPC64_GOT_TPREL34)
+ || r_type == elfcpp::R_PPC64_GOT_TPREL_PCREL34)
{
// 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);
}
- if (r_type == elfcpp::R_PPC64_GOT_TPREL34)
+ if (r_type == elfcpp::R_PPC64_GOT_TPREL_PCREL34)
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_PPC64_GOT_TPREL34)
+ if (r_type == elfcpp::R_PPC64_GOT_TPREL_PCREL34)
{
Insn* iview = reinterpret_cast<Insn*>(view);
uint64_t pinsn = elfcpp::Swap<32, big_endian>::readval(iview);
value = (value - target->savres_section()->address()
+ stub_table->branch_size());
else
- value = (stub_table->stub_address() + stub_table->plt_size()
- + ent->off_);
+ {
+ value = (stub_table->stub_address()
+ + stub_table->plt_size()
+ + ent->off_);
+ if (size == 64
+ && r_type != elfcpp::R_PPC64_REL24_NOTOC)
+ value += ent->tocoff_;
+ }
has_stub_value = true;
}
}
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_GOT_TLSGD_PCREL34:
+ case elfcpp::R_PPC64_GOT_TLSLD_PCREL34:
+ case elfcpp::R_PPC64_GOT_TPREL_PCREL34:
+ case elfcpp::R_PPC64_GOT_DTPREL_PCREL34:
case elfcpp::R_PPC64_REL16_HIGHER34:
case elfcpp::R_PPC64_REL16_HIGHERA34:
case elfcpp::R_PPC64_REL16_HIGHEST34:
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
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:
+ case elfcpp::R_PPC64_GOT_TLSGD_PCREL34:
+ case elfcpp::R_PPC64_GOT_TLSLD_PCREL34:
+ case elfcpp::R_PPC64_GOT_TPREL_PCREL34:
+ case elfcpp::R_PPC64_GOT_DTPREL_PCREL34:
overflow = Reloc::CHECK_SIGNED;
break;
}
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:
+ case elfcpp::R_PPC64_GOT_TLSGD_PCREL34:
+ case elfcpp::R_PPC64_GOT_TLSLD_PCREL34:
+ case elfcpp::R_PPC64_GOT_TPREL_PCREL34:
+ case elfcpp::R_PPC64_GOT_DTPREL_PCREL34:
if (size == 32)
goto unsupp;
status = Reloc::addr34(view, value, overflow);