aboutsummaryrefslogtreecommitdiff
path: root/gold
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2018-01-17 14:19:08 +1030
committerAlan Modra <amodra@gmail.com>2018-01-17 18:52:57 +1030
commit1be5d8d3bbec4c9a112114993ac5c85b2b26c4c4 (patch)
treedf7f34ee05bf516ced0b7547c40ea3185087b662 /gold
parent9e390558cef76767a98123994c422d0642d86cf8 (diff)
downloadbinutils-1be5d8d3bbec4c9a112114993ac5c85b2b26c4c4.zip
binutils-1be5d8d3bbec4c9a112114993ac5c85b2b26c4c4.tar.gz
binutils-1be5d8d3bbec4c9a112114993ac5c85b2b26c4c4.tar.bz2
PowerPC PLT speculative execution barriers
Spectre variant 2 mitigation for PowerPC and PowerPC64. bfd/ * elf32-ppc.c (GLINK_ENTRY_SIZE): Handle speculation barrier. (CRSETEQ, BEQCTRM): Define. (is_nonpic_glink_stub): Don't check bctr. (ppc_elf_link_hash_table_create): Init new ppc_elf_params field. (ppc_elf_relax_section): Size speculation barrier. (output_bctr): New function. (write_glink_stub): Use output_bctr. (ppc_elf_relocate_section): Use output_bctr for long branch stub. (ppc_elf_finish_dynamic_symbol): Likewise. (ppc_elf_finish_dynamic_sections): Use output_bctr. * elf32-ppc.h (struct ppc_elf_params): Add speculate_indirect_jumps. * elf64-ppc.c (CRSETEQ, BEQCTRM, BEQCTRLM): Define. (GLINK_PLTRESOLVE_SIZE): Size speculation barrier. (size_global_entry_stubs): Handle speculation barrier sizing. (plt_stub_size): Likewise. (output_bctr): New function. (build_plt_stub, build_tls_get_addr_stub): Output speculation barrier. (ppc_build_one_stub): Likewise for ppc_stub_plt_branch. (ppc_size_one_stub): Size speculation barrier in ppc_stub_plt_branch. (build_global_entry_stubs): Output speculation barrier. (ppc64_elf_build_stubs): Likewise in __glink_PLTresolve stub. * elf64-ppc.h (struct ppc64_elf_params): Add speculate_indirect_jumps. gold/ * options.h (speculate_indirect_jumps): New option. * powerpc.cc (beqctrm, beqctrlm, crseteq): New insn constants. (output_bctr): New function. (Stub_table::plt_call_size): Add space for speculation barrier. (Stub_table::branch_stub_size): Likewise. (Output_data_glink::pltresolve_size): Likewise. (Stub_table::do_write): Output speculation barriers. ld/ * emultempl/ppc32elf.em (params): Init new field. (OPTION_SPECULATE_INDIRECT_JUMPS): Define. (OPTION_NO_SPECULATE_INDIRECT_JUMPS): Define. (PARSE_AND_LIST_LONGOPTS): Handle new options. (PARSE_AND_LIST_ARGS_CASES): Likewise. (PARSE_AND_LIST_OPTIONS): Likewise. * emultempl/ppc64elf.em (params): Init new field. (OPTION_SPECULATE_INDIRECT_JUMPS): Define. (OPTION_NO_SPECULATE_INDIRECT_JUMPS): Define. (PARSE_AND_LIST_LONGOPTS): Handle --speculate-indirect-jumps. (PARSE_AND_LIST_OPTIONS): Likewise. (PARSE_AND_LIST_ARGS_CASES): Likewise. * ld.texinfo (--no-plt-thread-safe): Correct itemx. (--speculate-indirect-jumps): Document. * testsuite/ld-powerpc/elfv2exe.d, * testsuite/ld-powerpc/elfv2so.d, * testsuite/ld-powerpc/relbrlt.d, * testsuite/ld-powerpc/powerpc.exp: Disable plt alignment and speculation barriers on various tests.
Diffstat (limited to 'gold')
-rw-r--r--gold/ChangeLog10
-rw-r--r--gold/options.h4
-rw-r--r--gold/powerpc.cc63
3 files changed, 64 insertions, 13 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog
index fff66e1..ec56a89 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -1,5 +1,15 @@
2018-01-17 Alan Modra <amodra@gmail.com>
+ * options.h (speculate_indirect_jumps): New option.
+ * powerpc.cc (beqctrm, beqctrlm, crseteq): New insn constants.
+ (output_bctr): New function.
+ (Stub_table::plt_call_size): Add space for speculation barrier.
+ (Stub_table::branch_stub_size): Likewise.
+ (Output_data_glink::pltresolve_size): Likewise.
+ (Stub_table::do_write): Output speculation barriers.
+
+2018-01-17 Alan Modra <amodra@gmail.com>
+
* options.h (plt_align): Support for PowerPC32 too.
* powerpc.cc (Stub_table::stub_align): Heed --plt-align for 32-bit.
(Stub_table::plt_call_size, branch_stub_size): Tidy.
diff --git a/gold/options.h b/gold/options.h
index b39d5ff..c80cd05 100644
--- a/gold/options.h
+++ b/gold/options.h
@@ -1108,6 +1108,10 @@ class General_options
N_("(PowerPC64 only) Optimize calls to ELFv2 localentry:0 functions"),
N_("(PowerPC64 only) Don't optimize ELFv2 calls"));
+ DEFINE_bool(speculate_indirect_jumps, options::TWO_DASHES, '\0', true,
+ N_("(PowerPC only) PLT call stubs without speculation barrier"),
+ N_("(PowerPC only) PLT call stubs with speculation barrier"));
+
DEFINE_bool(plt_static_chain, options::TWO_DASHES, '\0', false,
N_("(PowerPC64 only) PLT call stubs should load r11"),
N_("(PowerPC64 only) PLT call stubs should not load r11"));
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);