From 77486630b13e9e586b0a1556cba9876a0ede99da Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Wed, 4 Sep 2019 15:30:37 +0930 Subject: [PATCH] R_PPC64_PCREL_OPT The loads and stores handled in the second instruction of a sequence marked by R_PPC64_PCREL_OPT may be a prefix instruction. For example: pld ra,symbol@got@pcrel 0: pld rt,off(ra) .reloc 0b-8,R_PPC64_PCREL_OPT,(.-8)-(0b-8) can be optimised to pld rt,symbol+off@pcrel pnop * elf64-ppc.c (xlate_pcrel_opt): Handle prefix loads and stores in second instruction. (ppc64_elf_relocate_section): Likewise. --- bfd/ChangeLog | 6 ++++ bfd/elf64-ppc.c | 51 +++++++++++++++++++++++------- ld/ChangeLog | 6 ++++ ld/testsuite/ld-powerpc/pcrelopt.d | 17 +++++++--- ld/testsuite/ld-powerpc/pcrelopt.s | 12 +++++++ 5 files changed, 75 insertions(+), 17 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 319ba5a5712..7f587df81af 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,9 @@ +2019-09-05 Alan Modra + + * elf64-ppc.c (xlate_pcrel_opt): Handle prefix loads and stores + in second instruction. + (ppc64_elf_relocate_section): Likewise. + 2019-09-05 Alan Modra PR 24955 diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index a5bd3426ee4..e39b6faf17b 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -8282,12 +8282,31 @@ ok_lo_toc_insn (unsigned int insn, enum elf_ppc64_reloc_type r_type) static bfd_boolean xlate_pcrel_opt (uint64_t *pinsn1, uint64_t *pinsn2, bfd_signed_vma *poff) { - uint32_t insn2 = *pinsn2 >> 32; - uint64_t i1new; + uint64_t insn1 = *pinsn1; + uint64_t insn2 = *pinsn2; bfd_signed_vma off; + if ((insn2 & (63ULL << 58)) == 1ULL << 58) + { + /* Check that regs match. */ + if (((insn2 >> 16) & 31) != ((insn1 >> 21) & 31)) + return FALSE; + + /* P8LS or PMLS form, non-pcrel. */ + if ((insn2 & (-1ULL << 50) & ~(1ULL << 56)) != (1ULL << 58)) + return FALSE; + + *pinsn1 = (insn2 & ~(31 << 16) & ~0x3ffff0000ffffULL) | (1ULL << 52); + *pinsn2 = PNOP; + off = ((insn2 >> 16) & 0x3ffff0000ULL) | (insn2 & 0xffff); + *poff = (off ^ 0x200000000ULL) - 0x200000000ULL; + return TRUE; + } + + insn2 >>= 32; + /* Check that regs match. */ - if (((insn2 >> 16) & 31) != ((*pinsn1 >> 21) & 31)) + if (((insn2 >> 16) & 31) != ((insn1 >> 21) & 31)) return FALSE; switch ((insn2 >> 26) & 63) @@ -8308,7 +8327,7 @@ xlate_pcrel_opt (uint64_t *pinsn1, uint64_t *pinsn2, bfd_signed_vma *poff) case 54: /* stfd */ /* These are the PMLS cases, where we just need to tack a prefix on the insn. */ - i1new = ((1ULL << 58) | (2ULL << 56) | (1ULL << 52) + insn1 = ((1ULL << 58) | (2ULL << 56) | (1ULL << 52) | (insn2 & ((63ULL << 26) | (31ULL << 21)))); off = insn2 & 0xffff; break; @@ -8316,7 +8335,7 @@ xlate_pcrel_opt (uint64_t *pinsn1, uint64_t *pinsn2, bfd_signed_vma *poff) case 58: /* lwa, ld */ if ((insn2 & 1) != 0) return FALSE; - i1new = ((1ULL << 58) | (1ULL << 52) + insn1 = ((1ULL << 58) | (1ULL << 52) | (insn2 & 2 ? 41ULL << 26 : 57ULL << 26) | (insn2 & (31ULL << 21))); off = insn2 & 0xfffc; @@ -8325,7 +8344,7 @@ xlate_pcrel_opt (uint64_t *pinsn1, uint64_t *pinsn2, bfd_signed_vma *poff) case 57: /* lxsd, lxssp */ if ((insn2 & 3) < 2) return FALSE; - i1new = ((1ULL << 58) | (1ULL << 52) + insn1 = ((1ULL << 58) | (1ULL << 52) | ((40ULL | (insn2 & 3)) << 26) | (insn2 & (31ULL << 21))); off = insn2 & 0xfffc; @@ -8336,14 +8355,14 @@ xlate_pcrel_opt (uint64_t *pinsn1, uint64_t *pinsn2, bfd_signed_vma *poff) return FALSE; else if ((insn2 & 3) >= 2) { - i1new = ((1ULL << 58) | (1ULL << 52) + insn1 = ((1ULL << 58) | (1ULL << 52) | ((44ULL | (insn2 & 3)) << 26) | (insn2 & (31ULL << 21))); off = insn2 & 0xfffc; } else { - i1new = ((1ULL << 58) | (1ULL << 52) + insn1 = ((1ULL << 58) | (1ULL << 52) | ((50ULL | (insn2 & 4) | ((insn2 & 8) >> 3)) << 26) | (insn2 & (31ULL << 21))); off = insn2 & 0xfff0; @@ -8351,7 +8370,7 @@ xlate_pcrel_opt (uint64_t *pinsn1, uint64_t *pinsn2, bfd_signed_vma *poff) break; case 56: /* lq */ - i1new = ((1ULL << 58) | (1ULL << 52) + insn1 = ((1ULL << 58) | (1ULL << 52) | (insn2 & ((63ULL << 26) | (31ULL << 21)))); off = insn2 & 0xffff; break; @@ -8359,14 +8378,14 @@ xlate_pcrel_opt (uint64_t *pinsn1, uint64_t *pinsn2, bfd_signed_vma *poff) case 62: /* std, stq */ if ((insn2 & 1) != 0) return FALSE; - i1new = ((1ULL << 58) | (1ULL << 52) + insn1 = ((1ULL << 58) | (1ULL << 52) | ((insn2 & 2) == 0 ? 61ULL << 26 : 60ULL << 26) | (insn2 & (31ULL << 21))); off = insn2 & 0xfffc; break; } - *pinsn1 = i1new; + *pinsn1 = insn1; *pinsn2 = (uint64_t) NOP << 32; *poff = (off ^ 0x8000) - 0x8000; return TRUE; @@ -15413,7 +15432,12 @@ ppc64_elf_relocate_section (bfd *output_bfd, pinsn2 = bfd_get_32 (input_bfd, contents + off2); pinsn2 <<= 32; if ((pinsn2 & (63ULL << 58)) == 1ULL << 58) - break; + { + if (off2 + 8 > input_section->size) + break; + pinsn2 |= bfd_get_32 (input_bfd, + contents + off2 + 4); + } if (xlate_pcrel_opt (&pinsn, &pinsn2, &addend_off)) { addend += addend_off; @@ -15424,6 +15448,9 @@ ppc64_elf_relocate_section (bfd *output_bfd, contents + offset + 4); bfd_put_32 (input_bfd, pinsn2 >> 32, contents + off2); + if ((pinsn2 & (63ULL << 58)) == 1ULL << 58) + bfd_put_32 (input_bfd, pinsn2, + contents + off2 + 4); } } } diff --git a/ld/ChangeLog b/ld/ChangeLog index b654eb9d363..0da9e2542da 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,9 @@ +2019-09-05 Alan Modra + + * testsuite/ld-powerpc/pcrelopt.s, + * testsuite/ld-powerpc/pcrelopt.d: Test offset and prefix in + second instruction. + 2019-08-29 Alan Modra PR ld/24406 diff --git a/ld/testsuite/ld-powerpc/pcrelopt.d b/ld/testsuite/ld-powerpc/pcrelopt.d index 18fdb95abff..aeaa0cdb5d9 100644 --- a/ld/testsuite/ld-powerpc/pcrelopt.d +++ b/ld/testsuite/ld-powerpc/pcrelopt.d @@ -80,10 +80,17 @@ Disassembly of section \.text: .*: (04 10 00 01|01 00 10 04) pstxv vs0,66028 .*: (d8 00 01 ec|ec 01 00 d8) .*: (60 00 00 00|00 00 00 60) nop -.*: (04 10 00 01|01 00 10 04) pld r9,66008 -.*: (e5 20 01 d8|d8 01 20 e5) -.*: (e8 09 00 00|00 00 09 e8) ld r0,0\(r9\) +.*: (06 10 00 01|01 00 10 06) plbz r3,70676 +.*: (88 60 14 14|14 14 60 88) +.*: (60 00 00 00|00 00 00 60) nop .*: (60 00 00 00|00 00 00 60) nop -.*: (06 10 00 01|01 00 10 06) pla r7,66000 -.*: (38 e0 01 d0|d0 01 e0 38) +.*: (04 10 12 35|35 12 10 04) plq r4,305485896 +.*: (e0 80 58 48|48 58 80 e0) +.*: (07 00 00 00|00 00 00 07) pnop +.*: (00 00 00 00|00 00 00 00) +.*: (04 10 00 01|01 00 10 04) pld r9,65976 +.*: (e5 20 01 b8|b8 01 20 e5) +.*: (e8 09 00 00|00 00 09 e8) ld r0,0\(r9\) +.*: (06 10 00 01|01 00 10 06) pla r7,65972 +.*: (38 e0 01 b4|b4 01 e0 38) .*: (88 c7 00 00|00 00 c7 88) lbz r6,0\(r7\) diff --git a/ld/testsuite/ld-powerpc/pcrelopt.s b/ld/testsuite/ld-powerpc/pcrelopt.s index 78b0f51f733..715a52b5f7b 100644 --- a/ld/testsuite/ld-powerpc/pcrelopt.s +++ b/ld/testsuite/ld-powerpc/pcrelopt.s @@ -103,6 +103,18 @@ _start: .reloc .-8,R_PPC64_PCREL_OPT,0f-(.-8) 0: stxv 0,0(9) +#offsets are allowed too + pld 9,sym@got@pcrel +0: + lbz 3,0x1234(9) + .reloc 0b-8,R_PPC64_PCREL_OPT,(.-4)-(0b-8) + +#and prefix insns as the second insn + pld 9,sym@got@pcrel +0: + plq 4,0x12345678(9) + .reloc 0b-8,R_PPC64_PCREL_OPT,(.-8)-(0b-8) + # This should not optimize .extern i .type i,@object -- 2.30.2