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 /bfd | |
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 'bfd')
-rw-r--r-- | bfd/ChangeLog | 26 | ||||
-rw-r--r-- | bfd/elf32-ppc.c | 41 | ||||
-rw-r--r-- | bfd/elf32-ppc.h | 3 | ||||
-rw-r--r-- | bfd/elf64-ppc.c | 58 | ||||
-rw-r--r-- | bfd/elf64-ppc.h | 3 |
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; |