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.
+2018-01-17 Alan Modra <amodra@gmail.com>
+
+ * 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.
+
2018-01-17 Alan Modra <amodra@gmail.com>
* elf32-ppc.c (GLINK_ENTRY_SIZE): Add parameters, handle
/* For new-style .glink and .plt. */
#define GLINK_PLTRESOLVE 16*4
#define GLINK_ENTRY_SIZE(htab, h) \
- ((4*4 \
+ (((!htab->params->speculate_indirect_jumps ? 6*4 : 4*4) \
+ (h != NULL \
&& h == htab->tls_get_addr \
&& !htab->params->no_tls_get_addr_opt ? 8*4 : 0) \
#define BA 0x48000002
#define BCL_20_31 0x429f0005
#define BCTR 0x4e800420
+#define CRSETEQ 0x4c421242
+#define BEQCTRM 0x4dc20420
#define BEQLR 0x4d820020
#define CMPWI_11_0 0x2c0b0000
#define LIS_11 0x3d600000
static bfd_boolean
is_nonpic_glink_stub (bfd *abfd, asection *glink, bfd_vma off)
{
- bfd_byte buf[4 * 4];
+ bfd_byte buf[3 * 4];
if (!bfd_get_section_contents (abfd, glink, buf, off, sizeof buf))
return FALSE;
return ((bfd_get_32 (abfd, buf + 0) & 0xffff0000) == LIS_11
&& (bfd_get_32 (abfd, buf + 4) & 0xffff0000) == LWZ_11_11
- && bfd_get_32 (abfd, buf + 8) == MTCTR_11
- && bfd_get_32 (abfd, buf + 12) == BCTR);
+ && bfd_get_32 (abfd, buf + 8) == MTCTR_11);
}
static bfd_boolean
{
struct ppc_elf_link_hash_table *ret;
static struct ppc_elf_params default_params
- = { PLT_OLD, 0, 0, 1, 0, 0, 12, 0, 0, 0 };
+ = { PLT_OLD, 0, 1, 0, 1, 0, 0, 12, 0, 0, 0 };
ret = bfd_zmalloc (sizeof (struct ppc_elf_link_hash_table));
if (ret == NULL)
size = 4 * ARRAY_SIZE (stub_entry);
insn_offset = 0;
}
+ if (!htab->params->speculate_indirect_jumps)
+ size += 8;
stub_rtype = R_PPC_RELAX;
if (tsec == htab->elf.splt
|| tsec == htab->glink)
#define PPC_HI(v) (((v) >> 16) & 0xffff)
#define PPC_HA(v) PPC_HI ((v) + 0x8000)
+static inline bfd_byte *
+output_bctr (struct ppc_elf_link_hash_table *htab, bfd *obfd, bfd_byte *p)
+{
+ if (!htab->params->speculate_indirect_jumps)
+ {
+ bfd_put_32 (obfd, CRSETEQ, p);
+ p += 4;
+ bfd_put_32 (obfd, BEQCTRM, p);
+ p += 4;
+ bfd_put_32 (obfd, B, p);
+ p += 4;
+ }
+ else
+ {
+ bfd_put_32 (obfd, BCTR, p);
+ p += 4;
+ }
+ return p;
+}
+
static void
write_glink_stub (struct elf_link_hash_entry *h, struct plt_entry *ent,
asection *plt_sec, unsigned char *p,
p += 4;
bfd_put_32 (output_bfd, MTCTR_11, p);
p += 4;
- bfd_put_32 (output_bfd, BCTR, p);
- p += 4;
+ p = output_bctr (htab, output_bfd, p);
while (p < end)
{
bfd_put_32 (output_bfd, htab->params->ppc476_workaround ? BA : NOP, p);
stub = stub_entry;
size = ARRAY_SIZE (stub_entry);
}
+ --size;
relocation += addend;
if (bfd_link_relocatable (info))
bfd_put_32 (input_bfd, insn, contents + insn_offset);
insn_offset += 4;
}
+ output_bctr (htab, input_bfd, contents + insn_offset);
/* Rewrite the reloc and convert one of the trailing nop
relocs to describe this relocation. */
p += 4;
bfd_put_32 (output_bfd, ADD_11_0_11, p);
p += 4;
- bfd_put_32 (output_bfd, BCTR, p);
- p += 4;
+ p = output_bctr (htab, output_bfd, p);
while (p < endp)
{
bfd_put_32 (output_bfd,
/* Set if individual PLT call stubs should be aligned. */
int plt_stub_align;
+ /* Clear if PLT call stubs should use a speculative execution barrier. */
+ int speculate_indirect_jumps;
+
/* Whether to emit symbols for stubs. */
int emit_stub_syms;
#define LD_R11_0R11 0xe96b0000 /* ld %r11,xxx+16@l(%r11) */
#define BCTR 0x4e800420 /* bctr */
+#define CRSETEQ 0x4c421242 /* crset 4*%cr0+%eq */
+#define BEQCTRM 0x4dc20420 /* beqctr- */
+#define BEQCTRLM 0x4dc20421 /* beqctrl- */
+
#define ADDI_R11_R11 0x396b0000 /* addi %r11,%r11,off@l */
#define ADDIS_R2_R2 0x3c420000 /* addis %r2,%r2,off@ha */
#define ADDI_R2_R2 0x38420000 /* addi %r2,%r2,off@l */
/* __glink_PLTresolve stub instructions. We enter with the index in R0. */
#define GLINK_PLTRESOLVE_SIZE(htab) \
- (8u + (htab->opd_abi ? 11 * 4 : 14 * 4))
+ (8u + (htab->opd_abi ? 11 * 4 : 14 * 4) \
+ + (!htab->params->speculate_indirect_jumps ? 2 * 4 : 0))
/* 0: */
/* .quad plt0-1f */
/* __glink: */
unsigned int align_power;
stub_size = 16;
+ if (!htab->params->speculate_indirect_jumps)
+ stub_size += 8;
stub_off = s->size;
if (htab->params->plt_stub_align >= 0)
align_power = htab->params->plt_stub_align;
size += 4;
if (PPC_HA (off) != 0)
size += 4;
+ if (!htab->params->speculate_indirect_jumps)
+ size += 8;
if (htab->opd_abi)
{
size += 4;
size += 7 * 4;
if (ALWAYS_EMIT_R2SAVE
|| stub_entry->stub_type == ppc_stub_plt_call_r2save)
- size += 6 * 4;
+ {
+ size += 6 * 4;
+ if (!htab->params->speculate_indirect_jumps)
+ size -= 4;
+ }
}
return size;
}
return 0;
}
+static inline bfd_byte *
+output_bctr (struct ppc_link_hash_table *htab, bfd *obfd, bfd_byte *p)
+{
+ if (!htab->params->speculate_indirect_jumps)
+ {
+ bfd_put_32 (obfd, CRSETEQ, p);
+ p += 4;
+ bfd_put_32 (obfd, BEQCTRM, p);
+ p += 4;
+ bfd_put_32 (obfd, B_DOT, p);
+ p += 4;
+ }
+ else
+ {
+ bfd_put_32 (obfd, BCTR, p);
+ p += 4;
+ }
+ return p;
+}
+
/* Build a .plt call stub. */
static inline bfd_byte *
if (!ALWAYS_USE_FAKE_DEP
&& plt_load_toc
&& plt_thread_safe
+ && htab->params->speculate_indirect_jumps
&& !((stub_entry->h == htab->tls_get_addr_fd
|| stub_entry->h == htab->tls_get_addr)
&& htab->params->tls_get_addr_opt))
bfd_put_32 (obfd, B_DOT | (cmp_branch_off & 0x3fffffc), p), p += 4;
}
else
- bfd_put_32 (obfd, BCTR, p), p += 4;
+ p = output_bctr (htab, obfd, p);
return p;
}
if (r != NULL)
r[0].r_offset += 2 * 4;
p = build_plt_stub (htab, stub_entry, p, offset, r);
- bfd_put_32 (obfd, BCTRL, p - 4);
+ if (!htab->params->speculate_indirect_jumps)
+ {
+ p -= 4;
+ bfd_put_32 (obfd, BEQCTRLM, p - 4);
+ }
+ else
+ bfd_put_32 (obfd, BCTRL, p - 4);
bfd_put_32 (obfd, LD_R2_0R1 + STK_TOC (htab), p), p += 4;
bfd_put_32 (obfd, LD_R11_0R1 + STK_LINKER (htab), p), p += 4;
p += 4;
bfd_put_32 (htab->params->stub_bfd, MTCTR_R12, p);
p += 4;
- bfd_put_32 (htab->params->stub_bfd, BCTR, p);
- p += 4;
+ p = output_bctr (htab, htab->params->stub_bfd, p);
break;
case ppc_stub_plt_call:
if (PPC_LO (r2off) != 0)
size += 4;
}
+ if (!htab->params->speculate_indirect_jumps)
+ size += 8;
}
else if (info->emitrelocations)
{
p += 4;
bfd_put_32 (s->owner, MTCTR_R12, p);
p += 4;
- bfd_put_32 (s->owner, BCTR, p);
+ output_bctr (htab, s->owner, p);
break;
}
return TRUE;
bfd_put_32 (htab->glink->owner, LD_R11_0R11 | 8, p);
p += 4;
}
- bfd_put_32 (htab->glink->owner, BCTR, p);
- p += 4;
+ p = output_bctr (htab, htab->glink->owner, p);
BFD_ASSERT (p - htab->glink->contents == GLINK_PLTRESOLVE_SIZE (htab));
/* Build the .glink lazy link call stubs. */
/* Set if PLT call stubs for localentry:0 functions should omit r2 save. */
int plt_localentry0;
+ /* Clear if PLT call stubs should use a speculative execution barrier. */
+ int speculate_indirect_jumps;
+
/* Whether to canonicalize .opd so that there are no overlapping
.opd entries. */
int non_overlapping_opd;
+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.
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"));
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;
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;
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
{
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));
}
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;
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;
{
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;
}
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>
= 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())
+ this->targ_->stk_linker()));
p += 4;
}
- use_fake_dep = thread_safe;
+ use_fake_dep |= thread_safe;
}
if (ha(off) != 0)
{
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;
write_insn<big_endian>(p, b | (cmp_branch_off & 0x3fffffc));
}
else
- write_insn<big_endian>(p, bctr);
+ output_bctr<big_endian>(p);
}
}
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);
}
}
}
p += 4;
write_insn<big_endian>(p, mtctr_11);
p += 4;
- write_insn<big_endian>(p, bctr);
+ output_bctr<big_endian>(p);
}
}
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_)
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.
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
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);
+2018-01-17 Alan Modra <amodra@gmail.com>
+
+ * 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.
+
2018-01-17 Alan Modra <amodra@gmail.com>
* emultempl/ppc32elf.em (params): Init new field.
/* Choose the correct place for .got. */
static int old_got = 0;
-static struct ppc_elf_params params = { PLT_UNSET, 0, -1,
+static struct ppc_elf_params params = { PLT_UNSET, 0, 1, -1,
0, 0, 0, 0, 0, 0, 0 };
static void
OPTION_NO_TLS_GET_ADDR_OPT,
OPTION_NEW_PLT,
OPTION_OLD_PLT,
+ OPTION_SPECULATE_INDIRECT_JUMPS,
+ OPTION_NO_SPECULATE_INDIRECT_JUMPS,
OPTION_PLT_ALIGN,
OPTION_NO_PLT_ALIGN,
OPTION_OLD_GOT,
PARSE_AND_LIST_LONGOPTS=${PARSE_AND_LIST_LONGOPTS}'
{ "secure-plt", no_argument, NULL, OPTION_NEW_PLT },
{ "bss-plt", no_argument, NULL, OPTION_OLD_PLT },
+ { "speculate-indirect-jumps", no_argument, NULL, OPTION_SPECULATE_INDIRECT_JUMPS },
+ { "no-speculate-indirect-jumps", no_argument, NULL, OPTION_NO_SPECULATE_INDIRECT_JUMPS },
{ "plt-align", no_argument, NULL, OPTION_PLT_ALIGN },
{ "no-plt-align", no_argument, NULL, OPTION_NO_PLT_ALIGN },
{ "sdata-got", no_argument, NULL, OPTION_OLD_GOT },'
--bss-plt Force old-style BSS PLT.\n"
));
fprintf (file, _("\
+ --speculate-indirect-jumps PLT call stubs without speculation barrier.\n"
+ ));
+ fprintf (file, _("\
+ --no-speculate-indirect-jumps PLT call stubs with speculation barrier.\n"
+ ));
+ fprintf (file, _("\
--plt-align Align PLT call stubs to fit cache lines.\n"
));
fprintf (file, _("\
params.plt_style = PLT_OLD;
break;
+ case OPTION_SPECULATE_INDIRECT_JUMPS:
+ params.speculate_indirect_jumps = 1;
+ break;
+
+ case OPTION_NO_SPECULATE_INDIRECT_JUMPS:
+ params.speculate_indirect_jumps = 0;
+ break;
+
case OPTION_PLT_ALIGN:
params.plt_stub_align = 5;
break;
&ppc_layout_sections_again,
1, -1, 0,
${DEFAULT_PLT_STATIC_CHAIN-0}, -1, 5,
- -1, 0, -1, -1, 0};
+ -1, 1, 0, -1, -1, 0};
/* Fake input file for stubs. */
static lang_input_statement_type *stub_file;
OPTION_NO_PLT_STATIC_CHAIN,
OPTION_PLT_THREAD_SAFE,
OPTION_NO_PLT_THREAD_SAFE,
+ OPTION_SPECULATE_INDIRECT_JUMPS,
+ OPTION_NO_SPECULATE_INDIRECT_JUMPS,
OPTION_PLT_ALIGN,
OPTION_NO_PLT_ALIGN,
OPTION_PLT_LOCALENTRY,
{ "no-plt-static-chain", no_argument, NULL, OPTION_NO_PLT_STATIC_CHAIN },
{ "plt-thread-safe", no_argument, NULL, OPTION_PLT_THREAD_SAFE },
{ "no-plt-thread-safe", no_argument, NULL, OPTION_NO_PLT_THREAD_SAFE },
+ { "speculate-indirect-jumps", no_argument, NULL, OPTION_SPECULATE_INDIRECT_JUMPS },
+ { "no-speculate-indirect-jumps", no_argument, NULL, OPTION_NO_SPECULATE_INDIRECT_JUMPS },
{ "plt-align", optional_argument, NULL, OPTION_PLT_ALIGN },
{ "no-plt-align", no_argument, NULL, OPTION_NO_PLT_ALIGN },
{ "plt-localentry", optional_argument, NULL, OPTION_PLT_LOCALENTRY },
--plt-thread-safe PLT call stubs with load-load barrier.\n"
));
fprintf (file, _("\
- --no-plt-thread-safe PLT call stubs without barrier.\n"
+ --no-plt-thread-safe PLT call stubs without load-load barrier.\n"
+ ));
+ fprintf (file, _("\
+ --speculate-indirect-jumps PLT call stubs without speculation barrier.\n"
+ ));
+ fprintf (file, _("\
+ --no-speculate-indirect-jumps PLT call stubs with speculation barrier.\n"
));
fprintf (file, _("\
--plt-align [=<align>] Align PLT call stubs to fit cache lines.\n"
params.plt_thread_safe = 0;
break;
+ case OPTION_SPECULATE_INDIRECT_JUMPS:
+ params.speculate_indirect_jumps = 1;
+ break;
+
+ case OPTION_NO_SPECULATE_INDIRECT_JUMPS:
+ params.speculate_indirect_jumps = 0;
+ break;
+
case OPTION_PLT_ALIGN:
if (optarg != NULL)
{
@kindex --plt-thread-safe
@kindex --no-plt-thread-safe
@item --plt-thread-safe
-@itemx --no-thread-safe
+@itemx --no-plt-thread-safe
With power7's weakly ordered memory model, it is possible when using
lazy binding for ld.so to update a plt entry in one thread and have
another thread see the individual plt entry words update in the wrong
seen, adds the necessary barriers. Use these options to change the
default behaviour.
+@cindex PowerPC64 PLT call stub speculative execution barrier
+@kindex --speculate-indirect-jumps
+@kindex --no-speculate-indirect-jumps
+@item --speculate-indirect-jumps
+@itemx --no-speculate-indirect-jumps
+Use these options to control whether all indirect branch instructions
+emitted by @code{ld}, such as those in the PLT, have a speculative
+execution barrier to mitigate Spectre variant 2 attacks.
+
@cindex PowerPC64 ELFv2 PLT localentry optimization
@kindex --plt-localentry
@kindex --no-plt-localentry
#source: elfv2.s
#as: -a64
-#ld: -melf64ppc --defsym f2=0x1234 --defsym f3=0x10008888 --defsym f4=0x1200000 --defsym _start=f1
+#ld: -melf64ppc --speculate-indirect-jumps --defsym f2=0x1234 --defsym f3=0x10008888 --defsym f4=0x1200000 --defsym _start=f1
#objdump: -dr
.*
#source: elfv2.s
#as: -a64
-#ld: -melf64ppc -shared
+#ld: -melf64ppc -shared --speculate-indirect-jumps
#objdump: -dr
.*
"tls32"}
{"TLS32 helper shared library" "-shared -melf32ppc tmpdir/tlslib32.o" "" "" {}
{} "libtlslib32.so"}
- {"TLS32 dynamic exec" "-melf32ppc --no-ld-generated-unwind-info --hash-style=sysv tmpdir/tls32.o tmpdir/libtlslib32.so" "" "" {}
+ {"TLS32 dynamic exec" "-melf32ppc --no-plt-align --speculate-indirect-jumps --no-ld-generated-unwind-info --hash-style=sysv tmpdir/tls32.o tmpdir/libtlslib32.so" "" "" {}
{{readelf -WSsrl tlsexe32.r} {objdump -dr tlsexe32.d}
{objdump -sj.got tlsexe32.g} {objdump -sj.tdata tlsexe32.t}}
"tlsexe32"}
- {"TLS32 shared" "-shared -melf32ppc --no-ld-generated-unwind-info --hash-style=sysv tmpdir/tls32.o" "" "" {}
+ {"TLS32 shared" "-shared -melf32ppc --no-plt-align --speculate-indirect-jumps --no-ld-generated-unwind-info --hash-style=sysv tmpdir/tls32.o" "" "" {}
{{readelf -WSsrl tlsso32.r} {objdump -dr tlsso32.d}
{objdump -sj.got tlsso32.g} {objdump -sj.tdata tlsso32.t}}
"tls32.so"}
{"TLS32 DLL" "-shared -melf32ppc --version-script tlsdll.ver" ""
"-a32" {tlsdll_32.s}
{} "tlsdll32.so"}
- {"TLS32 opt 5" "-melf32ppc -shared --gc-sections --secure-plt tmpdir/tlsdll32.so" "" "-a32" {tlsopt5_32.s}
+ {"TLS32 opt 5" "-melf32ppc -shared --gc-sections --secure-plt --no-plt-align --speculate-indirect-jumps tmpdir/tlsdll32.so" "" "-a32" {tlsopt5_32.s}
{{objdump -dr tlsopt5_32.d}}
"tlsopt5_32"}
{"Shared library with global symbol" "-shared -melf32ppc" "" "-a32" {sdalib.s}
{} "libtlslib.so"}
{"TLS helper old shared lib" "-shared -melf64ppc" "" "-a64" {oldtlslib.s}
{} "liboldlib.so"}
- {"TLS dynamic exec" "-melf64ppc --no-plt-align --no-ld-generated-unwind-info --hash-style=sysv tmpdir/tls.o tmpdir/libtlslib.so" "" "" {}
+ {"TLS dynamic exec" "-melf64ppc --no-plt-align --speculate-indirect-jumps --no-ld-generated-unwind-info --hash-style=sysv tmpdir/tls.o tmpdir/libtlslib.so" "" "" {}
{{readelf -WSsrl tlsexe.r} {objdump -dr tlsexe.d}
{objdump -sj.got tlsexe.g} {objdump -sj.tdata tlsexe.t}}
"tlsexe"}
- {"TLS dynamic old" "-melf64ppc --no-plt-align --no-ld-generated-unwind-info --hash-style=sysv tmpdir/tls.o tmpdir/liboldlib.so" "" "" {}
+ {"TLS dynamic old" "-melf64ppc --no-plt-align --speculate-indirect-jumps --no-ld-generated-unwind-info --hash-style=sysv tmpdir/tls.o tmpdir/liboldlib.so" "" "" {}
{{readelf -WSsrl tlsexe.r} {objdump -dr tlsexe.d}
{objdump -sj.got tlsexe.g} {objdump -sj.tdata tlsexe.t}}
"tlsexeold"}
- {"TLS shared" "-shared -melf64ppc --no-plt-align --no-ld-generated-unwind-info --hash-style=sysv tmpdir/tls.o" "" "" {}
+ {"TLS shared" "-shared -melf64ppc --no-plt-align --speculate-indirect-jumps --no-ld-generated-unwind-info --hash-style=sysv tmpdir/tls.o" "" "" {}
{{readelf -WSsrl tlsso.r} {objdump -dr tlsso.d}
{objdump -sj.got tlsso.g} {objdump -sj.tdata tlsso.t}}
"tls.so"}
{{objdump -dr tlstoc.d} {objdump -sj.got tlstoc.g}
{objdump -sj.tdata tlstoc.t}}
"tlstoc"}
- {"TLSTOC dynamic exec" "-melf64ppc --no-plt-align --no-ld-generated-unwind-info --hash-style=sysv tmpdir/tlstoc.o tmpdir/libtlslib.so" ""
+ {"TLSTOC dynamic exec" "-melf64ppc --no-plt-align --speculate-indirect-jumps --no-ld-generated-unwind-info --hash-style=sysv tmpdir/tlstoc.o tmpdir/libtlslib.so" ""
"" {}
{{readelf -WSsrl tlsexetoc.r} {objdump -dr tlsexetoc.d}
{objdump -sj.got tlsexetoc.g} {objdump -sj.tdata tlsexetoc.t}}
"tlsexetoc"}
- {"TLSTOC dynamic old" "-melf64ppc --no-plt-align --no-ld-generated-unwind-info --hash-style=sysv tmpdir/tlstoc.o tmpdir/liboldlib.so" ""
+ {"TLSTOC dynamic old" "-melf64ppc --no-plt-align --speculate-indirect-jumps --no-ld-generated-unwind-info --hash-style=sysv tmpdir/tlstoc.o tmpdir/liboldlib.so" ""
"" {}
{{readelf -WSsrl tlsexetoc.r} {objdump -dr tlsexetoc.d}
{objdump -sj.got tlsexetoc.g} {objdump -sj.tdata tlsexetoc.t}}
"tlsexetocold"}
- {"TLSTOC shared" "-shared -melf64ppc --no-plt-align --no-ld-generated-unwind-info --hash-style=sysv tmpdir/tlstoc.o" "" "" {}
+ {"TLSTOC shared" "-shared -melf64ppc --no-plt-align --speculate-indirect-jumps --no-ld-generated-unwind-info --hash-style=sysv tmpdir/tlstoc.o" "" "" {}
{{readelf -WSsrl tlstocso.r} {objdump -dr tlstocso.d}
{objdump -sj.got tlstocso.g} {objdump -sj.tdata tlstocso.t}}
"tlstoc.so"}
"tlsopt4"}
{"TLS DLL" "-shared -melf64ppc --version-script tlsdll.ver" "" "-a64" {tlsdll.s}
{} "tlsdll.so"}
- {"TLS opt 5" "-melf64ppc --no-plt-align -shared --gc-sections --no-plt-localentry tmpdir/tlsdll.so" "" "-a64" {tlsopt5.s}
+ {"TLS opt 5" "-melf64ppc --no-plt-align --speculate-indirect-jumps -shared --gc-sections --no-plt-localentry tmpdir/tlsdll.so" "" "-a64" {tlsopt5.s}
{{objdump -dr tlsopt5.d} {readelf -wf tlsopt5.wf}}
"tlsopt5"}
{"sym@tocbase" "-shared -melf64ppc" "" "-a64" {symtocbase-1.s symtocbase-2.s}
#source: relbrlt.s
#as: -a64
-#ld: -melf64ppc --no-plt-align --no-ld-generated-unwind-info --emit-relocs
+#ld: -melf64ppc --no-plt-align --speculate-indirect-jumps --no-ld-generated-unwind-info --emit-relocs
#objdump: -Dr
.*