diff options
author | Alan Modra <amodra@gmail.com> | 2019-08-29 11:30:11 +0930 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2019-08-29 12:57:33 +0930 |
commit | dd9b12c2451f0e46e73ec54d8762727d428b4c14 (patch) | |
tree | 16eaf6d814475f3b04a3edd5319852d19aacbfa1 /bfd/elf64-ppc.c | |
parent | 507685a390b47d853f22176273cb949e2ee8da81 (diff) | |
download | gdb-dd9b12c2451f0e46e73ec54d8762727d428b4c14.zip gdb-dd9b12c2451f0e46e73ec54d8762727d428b4c14.tar.gz gdb-dd9b12c2451f0e46e73ec54d8762727d428b4c14.tar.bz2 |
PowerPC64 xlate_pcrel_opt
We can easily support an offset on the second instruction of a
sequence marked with R_PPC64_PCREL_OPT. For example,
pla ra,symbol@pcrel
ld rt,off(ra)
can be optimised to
pld rt,symbol+off@pcrel
nop
* elf64-ppc.c (xlate_pcrel_opt): Add poff parameter. Allow offset
on second insn, return it in poff.
(ppc64_elf_relocate_section): Add offset to paddi addend for
PCREL_OPT.
Diffstat (limited to 'bfd/elf64-ppc.c')
-rw-r--r-- | bfd/elf64-ppc.c | 41 |
1 files changed, 22 insertions, 19 deletions
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index 4eba829..a5bd342 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -8265,25 +8265,26 @@ ok_lo_toc_insn (unsigned int insn, enum elf_ppc64_reloc_type r_type) /* PCREL_OPT in one instance flags to the linker that a pair of insns: pld ra,symbol@got@pcrel - load/store rt,0(ra) + load/store rt,off(ra) or pla ra,symbol@pcrel - load/store rt,0(ra) + load/store rt,off(ra) may be translated to - pload/pstore rt,symbol@pcrel + pload/pstore rt,symbol+off@pcrel nop. This function returns true if the optimization is possible, placing - the prefix insn in *PINSN1 and a NOP in *PINSN2. + the prefix insn in *PINSN1, a NOP in *PINSN2 and the offset in *POFF. On entry to this function, the linker has already determined that the pld can be replaced with pla: *PINSN1 is that pla insn, while *PINSN2 is the second instruction. */ static bfd_boolean -xlate_pcrel_opt (uint64_t *pinsn1, uint64_t *pinsn2) +xlate_pcrel_opt (uint64_t *pinsn1, uint64_t *pinsn2, bfd_signed_vma *poff) { uint32_t insn2 = *pinsn2 >> 32; uint64_t i1new; + bfd_signed_vma off; /* Check that regs match. */ if (((insn2 >> 16) & 31) != ((*pinsn1 >> 21) & 31)) @@ -8306,27 +8307,28 @@ xlate_pcrel_opt (uint64_t *pinsn1, uint64_t *pinsn2) case 52: /* stfs */ case 54: /* stfd */ /* These are the PMLS cases, where we just need to tack a prefix - on the insn. Check that the D field is zero. */ - if ((insn2 & 0xffff) != 0) - return FALSE; + on the insn. */ i1new = ((1ULL << 58) | (2ULL << 56) | (1ULL << 52) | (insn2 & ((63ULL << 26) | (31ULL << 21)))); + off = insn2 & 0xffff; break; case 58: /* lwa, ld */ - if ((insn2 & 0xfffd) != 0) + if ((insn2 & 1) != 0) return FALSE; i1new = ((1ULL << 58) | (1ULL << 52) | (insn2 & 2 ? 41ULL << 26 : 57ULL << 26) | (insn2 & (31ULL << 21))); + off = insn2 & 0xfffc; break; case 57: /* lxsd, lxssp */ - if ((insn2 & 0xfffc) != 0 || (insn2 & 3) < 2) + if ((insn2 & 3) < 2) return FALSE; i1new = ((1ULL << 58) | (1ULL << 52) | ((40ULL | (insn2 & 3)) << 26) | (insn2 & (31ULL << 21))); + off = insn2 & 0xfffc; break; case 61: /* stxsd, stxssp, lxv, stxv */ @@ -8334,40 +8336,39 @@ xlate_pcrel_opt (uint64_t *pinsn1, uint64_t *pinsn2) return FALSE; else if ((insn2 & 3) >= 2) { - if ((insn2 & 0xfffc) != 0) - return FALSE; i1new = ((1ULL << 58) | (1ULL << 52) | ((44ULL | (insn2 & 3)) << 26) | (insn2 & (31ULL << 21))); + off = insn2 & 0xfffc; } else { - if ((insn2 & 0xfff0) != 0) - return FALSE; i1new = ((1ULL << 58) | (1ULL << 52) | ((50ULL | (insn2 & 4) | ((insn2 & 8) >> 3)) << 26) | (insn2 & (31ULL << 21))); + off = insn2 & 0xfff0; } break; case 56: /* lq */ - if ((insn2 & 0xffff) != 0) - return FALSE; i1new = ((1ULL << 58) | (1ULL << 52) | (insn2 & ((63ULL << 26) | (31ULL << 21)))); + off = insn2 & 0xffff; break; case 62: /* std, stq */ - if ((insn2 & 0xfffd) != 0) + if ((insn2 & 1) != 0) return FALSE; i1new = ((1ULL << 58) | (1ULL << 52) | ((insn2 & 2) == 0 ? 61ULL << 26 : 60ULL << 26) | (insn2 & (31ULL << 21))); + off = insn2 & 0xfffc; break; } *pinsn1 = i1new; *pinsn2 = (uint64_t) NOP << 32; + *poff = (off ^ 0x8000) - 0x8000; return TRUE; } @@ -15408,12 +15409,15 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (off2 + 4 <= input_section->size) { uint64_t pinsn2; + bfd_signed_vma addend_off; pinsn2 = bfd_get_32 (input_bfd, contents + off2); pinsn2 <<= 32; if ((pinsn2 & (63ULL << 58)) == 1ULL << 58) break; - if (xlate_pcrel_opt (&pinsn, &pinsn2)) + if (xlate_pcrel_opt (&pinsn, &pinsn2, &addend_off)) { + addend += addend_off; + rel->r_addend = addend; bfd_put_32 (input_bfd, pinsn >> 32, contents + offset); bfd_put_32 (input_bfd, pinsn, @@ -15428,7 +15432,6 @@ ppc64_elf_relocate_section (bfd *output_bfd, break; } - /* Set `addend'. */ tls_type = 0; save_unresolved_reloc = unresolved_reloc; switch (r_type) |