aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/ChangeLog19
-rw-r--r--bfd/elfnn-riscv.c143
-rw-r--r--ld/ChangeLog7
-rw-r--r--ld/testsuite/ld-riscv-elf/weakref32.d25
-rw-r--r--ld/testsuite/ld-riscv-elf/weakref32.s3
-rw-r--r--ld/testsuite/ld-riscv-elf/weakref64.d25
-rw-r--r--ld/testsuite/ld-riscv-elf/weakref64.s3
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