diff options
author | Alan Modra <amodra@gmail.com> | 2018-01-17 14:19:08 +1030 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2018-01-17 18:52:57 +1030 |
commit | 1be5d8d3bbec4c9a112114993ac5c85b2b26c4c4 (patch) | |
tree | df7f34ee05bf516ced0b7547c40ea3185087b662 /gold/powerpc.cc | |
parent | 9e390558cef76767a98123994c422d0642d86cf8 (diff) | |
download | gdb-1be5d8d3bbec4c9a112114993ac5c85b2b26c4c4.zip gdb-1be5d8d3bbec4c9a112114993ac5c85b2b26c4c4.tar.gz gdb-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/powerpc.cc')
-rw-r--r-- | gold/powerpc.cc | 63 |
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); |