From 9d1da81b261a20050ef2ad01a5b4c8cf78404222 Mon Sep 17 00:00:00 2001 From: Jim Wilson Date: Fri, 20 Sep 2019 15:01:20 -0700 Subject: [PATCH] RISC-V: Optimize lui and auipc relaxations for undefweak symbol. For the lui and auipc relaxations, since the symbol value of an undefined weak symbol is always be zero, we can optimize the patterns into a single LI/MV/ADDI instruction. bfd/ * elfnn-riscv.c (riscv_pcgp_hi_reloc): Add new field undefined_weak. (riscv_record_pcgp_hi_reloc): New parameter undefined_weak. Set undefined_weak field from it. (relax_func_t): New parameter undefined_weak. (_bfd_riscv_relax_call): New ignored parameter undefined_weak. (_bfd_riscv_relax_tls_le): Likewise. (_bfd_riscv_relax_align): Likewise. (_bfd_riscv_relax_delete): Likewise. (_bfd_riscv_relax_lui): New parameter undefined_weak. If true, allow relaxing. For LO12* relocs, set rs1 to x0 when undefined_weak. (_bfd_riscv_relax_pc): New parameter undefined_weak. For LO12* relocs, set undefined_weak from hi_reloc. If true, allow relaxing. For LO12* relocs, set rs1 to x0 when undefined_weak and change to non-pcrel reloc. (_bfd_riscv_relax_section): New local undefined_weak. Set for undef weak relocs that can be relaxed. Pass to relax_func call. ld/ * testsuite/ld-riscv-elf/weakref32.s: Add relaxable undef weak code. * testsuite/ld-riscv-elf/weakref64.s: Likewise. * testsuite/ld-riscv-elf/weakref32.d: Updated. * testsuite/ld-riscv-elf/weakref64.d: Updated. --- bfd/ChangeLog | 19 ++++ bfd/elfnn-riscv.c | 143 +++++++++++++++++++++----- ld/ChangeLog | 7 ++ ld/testsuite/ld-riscv-elf/weakref32.d | 25 ++--- ld/testsuite/ld-riscv-elf/weakref32.s | 3 + ld/testsuite/ld-riscv-elf/weakref64.d | 25 ++--- ld/testsuite/ld-riscv-elf/weakref64.s | 3 + 7 files changed, 174 insertions(+), 51 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 080c628fee..b1a4aebd21 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,22 @@ +2019-09-20 Nelson Chu + + * elfnn-riscv.c (riscv_pcgp_hi_reloc): Add new field undefined_weak. + (riscv_record_pcgp_hi_reloc): New parameter undefined_weak. + Set undefined_weak field from it. + (relax_func_t): New parameter undefined_weak. + (_bfd_riscv_relax_call): New ignored parameter undefined_weak. + (_bfd_riscv_relax_tls_le): Likewise. + (_bfd_riscv_relax_align): Likewise. + (_bfd_riscv_relax_delete): Likewise. + (_bfd_riscv_relax_lui): New parameter undefined_weak. If true, + allow relaxing. For LO12* relocs, set rs1 to x0 when undefined_weak. + (_bfd_riscv_relax_pc): New parameter undefined_weak. For LO12* relocs, + set undefined_weak from hi_reloc. If true, allow relaxing. For LO12* + relocs, set rs1 to x0 when undefined_weak and change to non-pcrel + reloc. + (_bfd_riscv_relax_section): New local undefined_weak. Set for + undef weak relocs that can be relaxed. Pass to relax_func call. + 2019-09-20 Alan Modra * bfd-in.h (bfd_section_name, bfd_section_size, bfd_section_vma), diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c index ccf904af1b..4ffe6a36e6 100644 --- a/bfd/elfnn-riscv.c +++ b/bfd/elfnn-riscv.c @@ -3319,6 +3319,7 @@ struct riscv_pcgp_hi_reloc bfd_vma hi_addr; unsigned hi_sym; asection *sym_sec; + bfd_boolean undefined_weak; riscv_pcgp_hi_reloc *next; }; @@ -3377,7 +3378,8 @@ riscv_free_pcgp_relocs (riscv_pcgp_relocs *p, static bfd_boolean riscv_record_pcgp_hi_reloc (riscv_pcgp_relocs *p, bfd_vma hi_sec_off, bfd_vma hi_addend, bfd_vma hi_addr, - unsigned hi_sym, asection *sym_sec) + unsigned hi_sym, asection *sym_sec, + bfd_boolean undefined_weak) { riscv_pcgp_hi_reloc *new = bfd_malloc (sizeof(*new)); if (!new) @@ -3387,6 +3389,7 @@ riscv_record_pcgp_hi_reloc (riscv_pcgp_relocs *p, bfd_vma hi_sec_off, new->hi_addr = hi_addr; new->hi_sym = hi_sym; new->sym_sec = sym_sec; + new->undefined_weak = undefined_weak; new->next = p->hi; p->hi = new; return TRUE; @@ -3439,7 +3442,8 @@ typedef bfd_boolean (*relax_func_t) (bfd *, asection *, asection *, struct bfd_link_info *, Elf_Internal_Rela *, bfd_vma, bfd_vma, bfd_vma, bfd_boolean *, - riscv_pcgp_relocs *); + riscv_pcgp_relocs *, + bfd_boolean undefined_weak); /* Relax AUIPC + JALR into JAL. */ @@ -3451,7 +3455,8 @@ _bfd_riscv_relax_call (bfd *abfd, asection *sec, asection *sym_sec, bfd_vma max_alignment, bfd_vma reserve_size ATTRIBUTE_UNUSED, bfd_boolean *again, - riscv_pcgp_relocs *pcgp_relocs ATTRIBUTE_UNUSED) + riscv_pcgp_relocs *pcgp_relocs ATTRIBUTE_UNUSED, + bfd_boolean undefined_weak ATTRIBUTE_UNUSED) { bfd_byte *contents = elf_section_data (sec)->this_hdr.contents; bfd_signed_vma foff = symval - (sec_addr (sec) + rel->r_offset); @@ -3539,7 +3544,8 @@ _bfd_riscv_relax_lui (bfd *abfd, bfd_vma max_alignment, bfd_vma reserve_size, bfd_boolean *again, - riscv_pcgp_relocs *pcgp_relocs ATTRIBUTE_UNUSED) + riscv_pcgp_relocs *pcgp_relocs ATTRIBUTE_UNUSED, + bfd_boolean undefined_weak) { bfd_byte *contents = elf_section_data (sec)->this_hdr.contents; bfd_vma gp = riscv_global_pointer_value (link_info); @@ -3561,21 +3567,38 @@ _bfd_riscv_relax_lui (bfd *abfd, /* Is the reference in range of x0 or gp? Valid gp range conservatively because of alignment issue. */ - if (VALID_ITYPE_IMM (symval) - || (symval >= gp - && VALID_ITYPE_IMM (symval - gp + max_alignment + reserve_size)) - || (symval < gp - && VALID_ITYPE_IMM (symval - gp - max_alignment - reserve_size))) + if (undefined_weak + || (VALID_ITYPE_IMM (symval) + || (symval >= gp + && VALID_ITYPE_IMM (symval - gp + max_alignment + reserve_size)) + || (symval < gp + && VALID_ITYPE_IMM (symval - gp - max_alignment - reserve_size)))) { unsigned sym = ELFNN_R_SYM (rel->r_info); switch (ELFNN_R_TYPE (rel->r_info)) { case R_RISCV_LO12_I: - rel->r_info = ELFNN_R_INFO (sym, R_RISCV_GPREL_I); + if (undefined_weak) + { + /* Change the RS1 to zero. */ + bfd_vma insn = bfd_get_32 (abfd, contents + rel->r_offset); + insn &= ~(OP_MASK_RS1 << OP_SH_RS1); + bfd_put_32 (abfd, insn, contents + rel->r_offset); + } + else + rel->r_info = ELFNN_R_INFO (sym, R_RISCV_GPREL_I); return TRUE; case R_RISCV_LO12_S: - rel->r_info = ELFNN_R_INFO (sym, R_RISCV_GPREL_S); + if (undefined_weak) + { + /* Change the RS1 to zero. */ + bfd_vma insn = bfd_get_32 (abfd, contents + rel->r_offset); + insn &= ~(OP_MASK_RS1 << OP_SH_RS1); + bfd_put_32 (abfd, insn, contents + rel->r_offset); + } + else + rel->r_info = ELFNN_R_INFO (sym, R_RISCV_GPREL_S); return TRUE; case R_RISCV_HI20: @@ -3634,7 +3657,8 @@ _bfd_riscv_relax_tls_le (bfd *abfd, bfd_vma max_alignment ATTRIBUTE_UNUSED, bfd_vma reserve_size ATTRIBUTE_UNUSED, bfd_boolean *again, - riscv_pcgp_relocs *prcel_relocs ATTRIBUTE_UNUSED) + riscv_pcgp_relocs *prcel_relocs ATTRIBUTE_UNUSED, + bfd_boolean undefined_weak ATTRIBUTE_UNUSED) { /* See if this symbol is in range of tp. */ if (RISCV_CONST_HIGH_PART (tpoff (link_info, symval)) != 0) @@ -3674,7 +3698,8 @@ _bfd_riscv_relax_align (bfd *abfd, asection *sec, bfd_vma max_alignment ATTRIBUTE_UNUSED, bfd_vma reserve_size ATTRIBUTE_UNUSED, bfd_boolean *again ATTRIBUTE_UNUSED, - riscv_pcgp_relocs *pcrel_relocs ATTRIBUTE_UNUSED) + riscv_pcgp_relocs *pcrel_relocs ATTRIBUTE_UNUSED, + bfd_boolean undefined_weak ATTRIBUTE_UNUSED) { bfd_byte *contents = elf_section_data (sec)->this_hdr.contents; bfd_vma alignment = 1, pos; @@ -3732,8 +3757,10 @@ _bfd_riscv_relax_pc (bfd *abfd ATTRIBUTE_UNUSED, bfd_vma max_alignment, bfd_vma reserve_size, bfd_boolean *again ATTRIBUTE_UNUSED, - riscv_pcgp_relocs *pcgp_relocs) + riscv_pcgp_relocs *pcgp_relocs, + bfd_boolean undefined_weak) { + bfd_byte *contents = elf_section_data (sec)->this_hdr.contents; bfd_vma gp = riscv_global_pointer_value (link_info); BFD_ASSERT (rel->r_offset + 4 <= sec->size); @@ -3763,12 +3790,19 @@ _bfd_riscv_relax_pc (bfd *abfd ATTRIBUTE_UNUSED, hi_reloc = *hi; symval = hi_reloc.hi_addr; sym_sec = hi_reloc.sym_sec; + + /* We can not know whether the undefined weak symbol is referenced + according to the information of R_RISCV_PCREL_LO12_I/S. Therefore, + we have to record the 'undefined_weak' flag when handling the + corresponding R_RISCV_HI20 reloc in riscv_record_pcgp_hi_reloc. */ + undefined_weak = hi_reloc.undefined_weak; } break; case R_RISCV_PCREL_HI20: /* Mergeable symbols and code might later move out of range. */ - if (sym_sec->flags & (SEC_MERGE | SEC_CODE)) + if (! undefined_weak + && sym_sec->flags & (SEC_MERGE | SEC_CODE)) return TRUE; /* If the cooresponding lo relocation has already been seen then it's not @@ -3796,23 +3830,50 @@ _bfd_riscv_relax_pc (bfd *abfd ATTRIBUTE_UNUSED, /* Is the reference in range of x0 or gp? Valid gp range conservatively because of alignment issue. */ - if (VALID_ITYPE_IMM (symval) - || (symval >= gp - && VALID_ITYPE_IMM (symval - gp + max_alignment + reserve_size)) - || (symval < gp - && VALID_ITYPE_IMM (symval - gp - max_alignment - reserve_size))) + if (undefined_weak + || (VALID_ITYPE_IMM (symval) + || (symval >= gp + && VALID_ITYPE_IMM (symval - gp + max_alignment + reserve_size)) + || (symval < gp + && VALID_ITYPE_IMM (symval - gp - max_alignment - reserve_size)))) { unsigned sym = hi_reloc.hi_sym; switch (ELFNN_R_TYPE (rel->r_info)) { case R_RISCV_PCREL_LO12_I: - rel->r_info = ELFNN_R_INFO (sym, R_RISCV_GPREL_I); - rel->r_addend += hi_reloc.hi_addend; + if (undefined_weak) + { + /* Change the RS1 to zero, and then modify the relocation + type to R_RISCV_LO12_I. */ + bfd_vma insn = bfd_get_32 (abfd, contents + rel->r_offset); + insn &= ~(OP_MASK_RS1 << OP_SH_RS1); + bfd_put_32 (abfd, insn, contents + rel->r_offset); + rel->r_info = ELFNN_R_INFO (sym, R_RISCV_LO12_I); + rel->r_addend = hi_reloc.hi_addend; + } + else + { + rel->r_info = ELFNN_R_INFO (sym, R_RISCV_GPREL_I); + rel->r_addend += hi_reloc.hi_addend; + } return TRUE; case R_RISCV_PCREL_LO12_S: - rel->r_info = ELFNN_R_INFO (sym, R_RISCV_GPREL_S); - rel->r_addend += hi_reloc.hi_addend; + if (undefined_weak) + { + /* Change the RS1 to zero, and then modify the relocation + type to R_RISCV_LO12_S. */ + bfd_vma insn = bfd_get_32 (abfd, contents + rel->r_offset); + insn &= ~(OP_MASK_RS1 << OP_SH_RS1); + bfd_put_32 (abfd, insn, contents + rel->r_offset); + rel->r_info = ELFNN_R_INFO (sym, R_RISCV_LO12_S); + rel->r_addend = hi_reloc.hi_addend; + } + else + { + rel->r_info = ELFNN_R_INFO (sym, R_RISCV_GPREL_S); + rel->r_addend += hi_reloc.hi_addend; + } return TRUE; case R_RISCV_PCREL_HI20: @@ -3821,7 +3882,8 @@ _bfd_riscv_relax_pc (bfd *abfd ATTRIBUTE_UNUSED, rel->r_addend, symval, ELFNN_R_SYM(rel->r_info), - sym_sec); + sym_sec, + undefined_weak); /* We can delete the unnecessary AUIPC and reloc. */ rel->r_info = ELFNN_R_INFO (0, R_RISCV_DELETE); rel->r_addend = 4; @@ -3847,7 +3909,8 @@ _bfd_riscv_relax_delete (bfd *abfd, bfd_vma max_alignment ATTRIBUTE_UNUSED, bfd_vma reserve_size ATTRIBUTE_UNUSED, bfd_boolean *again ATTRIBUTE_UNUSED, - riscv_pcgp_relocs *pcgp_relocs ATTRIBUTE_UNUSED) + riscv_pcgp_relocs *pcgp_relocs ATTRIBUTE_UNUSED, + bfd_boolean undefined_weak ATTRIBUTE_UNUSED) { if (!riscv_relax_delete_bytes(abfd, sec, rel->r_offset, rel->r_addend, link_info)) @@ -3914,6 +3977,7 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec, int type = ELFNN_R_TYPE (rel->r_info); bfd_vma symval; char symtype; + bfd_boolean undefined_weak = FALSE; relax_func = NULL; if (info->relax_pass == 0) @@ -4008,11 +4072,36 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec, || h->root.type == bfd_link_hash_warning) h = (struct elf_link_hash_entry *) h->root.u.i.link; + if (h->root.type == bfd_link_hash_undefweak + && (relax_func == _bfd_riscv_relax_lui + || relax_func == _bfd_riscv_relax_pc)) + { + /* For the lui and auipc relaxations, since the symbol + value of an undefined weak symbol is always be zero, + we can optimize the patterns into a single LI/MV/ADDI + instruction. + + Note that, creating shared libraries and pie output may + break the rule above. Fortunately, since we do not relax + pc relocs when creating shared libraries and pie output, + and the absolute address access for R_RISCV_HI20 isn't + allowed when "-fPIC" is set, the problem of creating shared + libraries can not happen currently. Once we support the + auipc relaxations when creating shared libraries, then we will + need the more rigorous checking for this optimization. */ + undefined_weak = TRUE; + } + if (h->plt.offset != MINUS_ONE) { sym_sec = htab->elf.splt; symval = h->plt.offset; } + else if (undefined_weak) + { + symval = 0; + sym_sec = bfd_und_section_ptr; + } else if (h->root.u.def.section->output_section == NULL || (h->root.type != bfd_link_hash_defined && h->root.type != bfd_link_hash_defweak)) @@ -4065,7 +4154,7 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec, if (!relax_func (abfd, sec, sym_sec, info, rel, symval, max_alignment, reserve_size, again, - &pcgp_relocs)) + &pcgp_relocs, undefined_weak)) goto fail; } diff --git a/ld/ChangeLog b/ld/ChangeLog index 3f62dad9cc..57d4df713a 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,10 @@ +2019-09-20 Nelson Chu + + * testsuite/ld-riscv-elf/weakref32.s: Add relaxable undef weak code. + * testsuite/ld-riscv-elf/weakref64.s: Likewise. + * testsuite/ld-riscv-elf/weakref32.d: Updated. + * testsuite/ld-riscv-elf/weakref64.d: Updated. + 2019-09-20 Alan Modra * emultempl/xtensaelf.em (xtensa_get_section_deps): Comment. diff --git a/ld/testsuite/ld-riscv-elf/weakref32.d b/ld/testsuite/ld-riscv-elf/weakref32.d index 5ede7cb7f6..eaeb6dae7e 100644 --- a/ld/testsuite/ld-riscv-elf/weakref32.d +++ b/ld/testsuite/ld-riscv-elf/weakref32.d @@ -5,15 +5,16 @@ Disassembly of section \.text: 90000000 <_start>: -90000000: 70000797 auipc a5,0x70000 -90000004: 00078793 mv a5,a5 -90000008: 02078263 beqz a5,9000002c <_start\+0x2c> -9000000c: ff010113 addi sp,sp,-16 -90000010: 00112623 sw ra,12\(sp\) -90000014: 00000097 auipc ra,0x0 -90000018: 000000e7 jalr zero # 0 <_start\-0x90000000> -9000001c: 00c12083 lw ra,12\(sp\) -90000020: 01010113 addi sp,sp,16 -90000024: 00000317 auipc t1,0x0 -90000028: 00000067 jr zero # 0 <_start\-0x90000000> -9000002c: 00008067 ret +90000000: 00000793 li a5,0 +90000004: 02078663 beqz a5,90000030 <_start\+0x30> +90000008: 00000793 li a5,0 +9000000c: 02078263 beqz a5,90000030 <_start\+0x30> +90000010: ff010113 addi sp,sp,-16 +90000014: 00112623 sw ra,12\(sp\) +90000018: 00000097 auipc ra,0x0 +9000001c: 000000e7 jalr zero # 0 <_start\-0x90000000> +90000020: 00c12083 lw ra,12\(sp\) +90000024: 01010113 addi sp,sp,16 +90000028: 00000317 auipc t1,0x0 +9000002c: 00000067 jr zero # 0 <_start\-0x90000000> +90000030: 00008067 ret diff --git a/ld/testsuite/ld-riscv-elf/weakref32.s b/ld/testsuite/ld-riscv-elf/weakref32.s index 14df041218..6c3d84de5f 100644 --- a/ld/testsuite/ld-riscv-elf/weakref32.s +++ b/ld/testsuite/ld-riscv-elf/weakref32.s @@ -4,6 +4,9 @@ .globl _start .type _start, @function _start: + lui a5,%hi(f) + addi a5,a5,%lo(f) + beq a5,zero,.L1 lla a5,f beqz a5,.L1 addi sp,sp,-16 diff --git a/ld/testsuite/ld-riscv-elf/weakref64.d b/ld/testsuite/ld-riscv-elf/weakref64.d index 52db9c2d0c..cc718a91a3 100644 --- a/ld/testsuite/ld-riscv-elf/weakref64.d +++ b/ld/testsuite/ld-riscv-elf/weakref64.d @@ -5,15 +5,16 @@ Disassembly of section \.text: 0000000090000000 <_start>: - 90000000: 000007b7 lui a5,0x0 - 90000004: 00078793 mv a5,a5 - 90000008: 02078263 beqz a5,9000002c <_start\+0x2c> - 9000000c: ff010113 addi sp,sp,-16 - 90000010: 00113423 sd ra,8\(sp\) - 90000014: 00000097 auipc ra,0x0 - 90000018: 000000e7 jalr zero # 0 <_start\-0x90000000> - 9000001c: 00813083 ld ra,8\(sp\) - 90000020: 01010113 addi sp,sp,16 - 90000024: 00000317 auipc t1,0x0 - 90000028: 00000067 jr zero # 0 <_start\-0x90000000> - 9000002c: 00008067 ret + 90000000: 00000793 li a5,0 + 90000004: 02078663 beqz a5,90000030 <_start\+0x30> + 90000008: 00000793 li a5,0 + 9000000c: 02078263 beqz a5,90000030 <_start\+0x30> + 90000010: ff010113 addi sp,sp,-16 + 90000014: 00113423 sd ra,8\(sp\) + 90000018: 00000097 auipc ra,0x0 + 9000001c: 000000e7 jalr zero # 0 <_start\-0x90000000> + 90000020: 00813083 ld ra,8\(sp\) + 90000024: 01010113 addi sp,sp,16 + 90000028: 00000317 auipc t1,0x0 + 9000002c: 00000067 jr zero # 0 <_start\-0x90000000> + 90000030: 00008067 ret diff --git a/ld/testsuite/ld-riscv-elf/weakref64.s b/ld/testsuite/ld-riscv-elf/weakref64.s index 5872626665..83bcd28563 100644 --- a/ld/testsuite/ld-riscv-elf/weakref64.s +++ b/ld/testsuite/ld-riscv-elf/weakref64.s @@ -4,6 +4,9 @@ .globl _start .type _start, @function _start: + lui a5,%hi(f) + addi a5,a5,%lo(f) + beq a5,zero,.L1 lla a5,f beqz a5,.L1 addi sp,sp,-16 -- 2.34.1