diff options
-rw-r--r-- | bfd/ChangeLog | 19 | ||||
-rw-r--r-- | bfd/elfnn-riscv.c | 143 | ||||
-rw-r--r-- | ld/ChangeLog | 7 | ||||
-rw-r--r-- | ld/testsuite/ld-riscv-elf/weakref32.d | 25 | ||||
-rw-r--r-- | ld/testsuite/ld-riscv-elf/weakref32.s | 3 | ||||
-rw-r--r-- | ld/testsuite/ld-riscv-elf/weakref64.d | 25 | ||||
-rw-r--r-- | ld/testsuite/ld-riscv-elf/weakref64.s | 3 |
7 files changed, 174 insertions, 51 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 080c628..b1a4aeb 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,22 @@ +2019-09-20 Nelson Chu <nelson.chu@sifive.com> + + * 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 <amodra@gmail.com> * 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 ccf904a..4ffe6a3 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 3f62dad..57d4df7 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,10 @@ +2019-09-20 Nelson Chu <nelson.chu@sifive.com> + + * 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 <amodra@gmail.com> * 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 5ede7cb..eaeb6da 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 14df041..6c3d84d 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 52db9c2..cc718a9 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 5872626..83bcd28 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 |