bfd_vma hi_addr;
unsigned hi_sym;
asection *sym_sec;
+ bfd_boolean undefined_weak;
riscv_pcgp_hi_reloc *next;
};
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)
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;
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. */
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);
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);
/* 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:
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)
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;
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);
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
/* 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:
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;
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))
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)
|| 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))
if (!relax_func (abfd, sec, sym_sec, info, rel, symval,
max_alignment, reserve_size, again,
- &pcgp_relocs))
+ &pcgp_relocs, undefined_weak))
goto fail;
}