diff options
Diffstat (limited to 'bfd/elf64-ppc.c')
-rw-r--r-- | bfd/elf64-ppc.c | 58 |
1 files changed, 49 insertions, 9 deletions
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. */ |