aboutsummaryrefslogtreecommitdiff
path: root/gold/powerpc.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gold/powerpc.cc')
-rw-r--r--gold/powerpc.cc63
1 files changed, 50 insertions, 13 deletions
diff --git a/gold/powerpc.cc b/gold/powerpc.cc
index 9ed5b21..6b65792 100644
--- a/gold/powerpc.cc
+++ b/gold/powerpc.cc
@@ -3781,6 +3781,8 @@ static const uint32_t b = 0x48000000;
static const uint32_t bcl_20_31 = 0x429f0005;
static const uint32_t bctr = 0x4e800420;
static const uint32_t bctrl = 0x4e800421;
+static const uint32_t beqctrm = 0x4dc20420;
+static const uint32_t beqctrlm = 0x4dc20421;
static const uint32_t beqlr = 0x4d820020;
static const uint32_t blr = 0x4e800020;
static const uint32_t bnectr_p4 = 0x4ce20420;
@@ -3790,6 +3792,7 @@ static const uint32_t cmpdi_11_0 = 0x2c2b0000;
static const uint32_t cmpwi_11_0 = 0x2c0b0000;
static const uint32_t cror_15_15_15 = 0x4def7b82;
static const uint32_t cror_31_31_31 = 0x4ffffb82;
+static const uint32_t crseteq = 0x4c421242;
static const uint32_t ld_0_1 = 0xe8010000;
static const uint32_t ld_0_12 = 0xe80c0000;
static const uint32_t ld_2_1 = 0xe8410000;
@@ -4165,6 +4168,24 @@ write_insn(unsigned char* p, uint32_t v)
elfcpp::Swap<32, big_endian>::writeval(p, v);
}
+template<bool big_endian>
+static unsigned char*
+output_bctr(unsigned char* p)
+{
+ if (!parameters->options().speculate_indirect_jumps())
+ {
+ write_insn<big_endian>(p, crseteq);
+ p += 4;
+ write_insn<big_endian>(p, beqctrm);
+ p += 4;
+ write_insn<big_endian>(p, b);
+ }
+ else
+ write_insn<big_endian>(p, bctr);
+ p += 4;
+ return p;
+}
+
// Stub_table holds information about plt and long branch stubs.
// Stubs are built in an area following some input section determined
// by group_sections(). This input section is converted to a relaxed
@@ -4426,6 +4447,7 @@ class Stub_table : public Output_relaxed_input_section
{
const Symbol* gsym = p->first.sym_;
return (4 * 4
+ + (!parameters->options().speculate_indirect_jumps() ? 2 * 4 : 0)
+ (this->targ_->is_tls_get_addr_opt(gsym) ? 8 * 4 : 0));
}
@@ -4441,6 +4463,8 @@ class Stub_table : public Output_relaxed_input_section
got_addr += ppcobj->toc_base_offset();
Address off = plt_addr - got_addr;
unsigned int bytes = 4 * 4 + 4 * (ha(off) != 0);
+ if (!parameters->options().speculate_indirect_jumps())
+ bytes += 2 * 4;
const Symbol* gsym = p->first.sym_;
if (this->targ_->is_tls_get_addr_opt(gsym))
bytes += 13 * 4;
@@ -4471,6 +4495,8 @@ class Stub_table : public Output_relaxed_input_section
if (p->first.dest_ - loc + (1 << 25) < 2 << 25)
return 4;
unsigned int bytes = 16;
+ if (!parameters->options().speculate_indirect_jumps())
+ bytes += 8;
if (size == 32 && parameters->options().output_is_position_independent())
bytes += 16;
return bytes;
@@ -4924,7 +4950,8 @@ class Output_data_glink : public Output_section_data
{
if (size == 64)
return (8
- + (this->targ_->abiversion() < 2 ? 11 * 4 : 14 * 4));
+ + (this->targ_->abiversion() < 2 ? 11 * 4 : 14 * 4)
+ + (!parameters->options().speculate_indirect_jumps() ? 2 * 4 : 0));
return 16 * 4;
}
@@ -5001,7 +5028,8 @@ Output_data_glink<size, big_endian>::add_global_entry(const Symbol* gsym)
std::pair<typename Global_entry_stub_entries::iterator, bool> p
= this->global_entry_stubs_.insert(std::make_pair(gsym, off));
if (p.second)
- this->ge_size_ = off + 16;
+ this->ge_size_
+ = off + 16 + (!parameters->options().speculate_indirect_jumps() ? 8 : 0);
}
template<int size, bool big_endian>
@@ -5190,7 +5218,10 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
= plt_load_toc && this->targ_->plt_thread_safe();
bool use_fake_dep = false;
Address cmp_branch_off = 0;
- if (thread_safe)
+ if (thread_safe
+ && !parameters->options().speculate_indirect_jumps())
+ use_fake_dep = true;
+ else if (thread_safe)
{
unsigned int pltindex
= ((pltoff - this->targ_->first_plt_entry_offset())
@@ -5238,7 +5269,7 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
+ this->targ_->stk_linker()));
p += 4;
}
- use_fake_dep = thread_safe;
+ use_fake_dep |= thread_safe;
}
if (ha(off) != 0)
{
@@ -5329,7 +5360,14 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
if (!cs->second.localentry0_
&& this->targ_->is_tls_get_addr_opt(gsym))
{
- write_insn<big_endian>(p, bctrl);
+ if (!parameters->options().speculate_indirect_jumps())
+ {
+ write_insn<big_endian>(p, crseteq);
+ p += 4;
+ write_insn<big_endian>(p, beqctrlm);
+ }
+ else
+ write_insn<big_endian>(p, bctrl);
p += 4;
write_insn<big_endian>(p, ld_2_1 + this->targ_->stk_toc());
p += 4;
@@ -5348,7 +5386,7 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
write_insn<big_endian>(p, b | (cmp_branch_off & 0x3fffffc));
}
else
- write_insn<big_endian>(p, bctr);
+ output_bctr<big_endian>(p);
}
}
@@ -5383,7 +5421,7 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
write_insn<big_endian>(p, ld_12_12 + l(brltoff)), p += 4;
}
write_insn<big_endian>(p, mtctr_12), p += 4;
- write_insn<big_endian>(p, bctr);
+ output_bctr<big_endian>(p);
}
}
}
@@ -5479,7 +5517,7 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
p += 4;
write_insn<big_endian>(p, mtctr_11);
p += 4;
- write_insn<big_endian>(p, bctr);
+ output_bctr<big_endian>(p);
}
}
@@ -5520,7 +5558,7 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
p += 4;
write_insn<big_endian>(p, mtctr_12);
p += 4;
- write_insn<big_endian>(p, bctr);
+ output_bctr<big_endian>(p);
}
}
if (this->need_save_res_)
@@ -5587,7 +5625,7 @@ Output_data_glink<size, big_endian>::do_write(Output_file* of)
write_insn<big_endian>(p, mtctr_12), p += 4;
write_insn<big_endian>(p, ld_11_11 + 8), p += 4;
}
- write_insn<big_endian>(p, bctr), p += 4;
+ p = output_bctr<big_endian>(p);
gold_assert(p == oview + this->pltresolve_size());
// Write lazy link call stubs.
@@ -5643,7 +5681,7 @@ Output_data_glink<size, big_endian>::do_write(Output_file* of)
write_insn<big_endian>(p, addis_12_12 + ha(off)), p += 4;
write_insn<big_endian>(p, ld_12_12 + l(off)), p += 4;
write_insn<big_endian>(p, mtctr_12), p += 4;
- write_insn<big_endian>(p, bctr);
+ output_bctr<big_endian>(p);
}
}
else
@@ -5735,8 +5773,7 @@ Output_data_glink<size, big_endian>::do_write(Output_file* of)
write_insn<big_endian>(p, add_11_0_11);
}
p += 4;
- write_insn<big_endian>(p, bctr);
- p += 4;
+ p = output_bctr<big_endian>(p);
while (p < end_p)
{
write_insn<big_endian>(p, nop);