aboutsummaryrefslogtreecommitdiff
path: root/bfd
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 /bfd
parent9e390558cef76767a98123994c422d0642d86cf8 (diff)
downloadgdb-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 'bfd')
-rw-r--r--bfd/ChangeLog26
-rw-r--r--bfd/elf32-ppc.c41
-rw-r--r--bfd/elf32-ppc.h3
-rw-r--r--bfd/elf64-ppc.c58
-rw-r--r--bfd/elf64-ppc.h3
5 files changed, 113 insertions, 18 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index b922b73..cec6b16 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,5 +1,31 @@
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
__tls_get_addr_opt, and alignment sizing.
(TLS_GET_ADDR_GLINK_SIZE): Delete.
diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c
index efdaf04..73701d4 100644
--- a/bfd/elf32-ppc.c
+++ b/bfd/elf32-ppc.c
@@ -69,7 +69,7 @@ static bfd_reloc_status_type ppc_elf_unhandled_reloc
/* 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) \
@@ -155,6 +155,8 @@ static const bfd_vma ppc_elf_vxworks_pic_plt0_entry
#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
@@ -2878,15 +2880,14 @@ ppc_elf_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED)
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
@@ -3365,7 +3366,7 @@ ppc_elf_link_hash_table_create (bfd *abfd)
{
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)
@@ -7167,6 +7168,8 @@ ppc_elf_relax_section (bfd *abfd,
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)
@@ -7448,6 +7451,26 @@ elf_finish_pointer_linker_section (bfd *input_bfd,
#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,
@@ -7515,8 +7538,7 @@ write_glink_stub (struct elf_link_hash_entry *h, struct plt_entry *ent,
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);
@@ -8954,6 +8976,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
stub = stub_entry;
size = ARRAY_SIZE (stub_entry);
}
+ --size;
relocation += addend;
if (bfd_link_relocatable (info))
@@ -8978,6 +9001,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
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. */
@@ -10686,8 +10710,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
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,
diff --git a/bfd/elf32-ppc.h b/bfd/elf32-ppc.h
index f56d027..8977efa 100644
--- a/bfd/elf32-ppc.h
+++ b/bfd/elf32-ppc.h
@@ -35,6 +35,9 @@ struct ppc_elf_params
/* 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;
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index 10d3fe9..1b4404c 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -161,6 +161,10 @@ static bfd_vma opd_entry_value
#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 */
@@ -189,7 +193,8 @@ static bfd_vma opd_entry_value
/* __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: */
@@ -9881,6 +9886,8 @@ size_global_entry_stubs (struct elf_link_hash_entry *h, void *inf)
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;
@@ -10446,6 +10453,8 @@ plt_stub_size (struct ppc_link_hash_table *htab,
size += 4;
if (PPC_HA (off) != 0)
size += 4;
+ if (!htab->params->speculate_indirect_jumps)
+ size += 8;
if (htab->opd_abi)
{
size += 4;
@@ -10467,7 +10476,11 @@ plt_stub_size (struct ppc_link_hash_table *htab,
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;
}
@@ -10502,6 +10515,26 @@ plt_stub_pad (struct ppc_link_hash_table *htab,
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 *
@@ -10522,6 +10555,7 @@ build_plt_stub (struct ppc_link_hash_table *htab,
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))
@@ -10676,7 +10710,7 @@ build_plt_stub (struct ppc_link_hash_table *htab,
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;
}
@@ -10720,7 +10754,13 @@ build_tls_get_addr_stub (struct ppc_link_hash_table *htab,
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;
@@ -11073,8 +11113,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
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:
@@ -11407,6 +11446,8 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
if (PPC_LO (r2off) != 0)
size += 4;
}
+ if (!htab->params->speculate_indirect_jumps)
+ size += 8;
}
else if (info->emitrelocations)
{
@@ -13040,7 +13081,7 @@ build_global_entry_stubs (struct elf_link_hash_entry *h, void *inf)
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;
@@ -13169,8 +13210,7 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
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. */
diff --git a/bfd/elf64-ppc.h b/bfd/elf64-ppc.h
index 8fa0140..b3d4d59 100644
--- a/bfd/elf64-ppc.h
+++ b/bfd/elf64-ppc.h
@@ -51,6 +51,9 @@ struct ppc64_elf_params
/* 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;