/* RISC-V-specific support for NN-bit ELF.
- Copyright (C) 2011-2019 Free Software Foundation, Inc.
+ Copyright (C) 2011-2020 Free Software Foundation, Inc.
Contributed by Andrew Waterman (andrew@sifive.com).
Based on TILE-Gx and MIPS targets.
break;
case R_RISCV_CALL:
+ case R_RISCV_CALL_PLT:
/* Handle a call to an undefined weak function. This won't be
relaxed, so we have to handle it here. */
if (h != NULL && h->root.type == bfd_link_hash_undefweak
- && h->plt.offset == MINUS_ONE)
+ && (!bfd_link_pic (info) || h->plt.offset == MINUS_ONE))
{
/* We can use x0 as the base register. */
bfd_vma insn = bfd_get_32 (input_bfd,
}
/* Fall through. */
- case R_RISCV_CALL_PLT:
case R_RISCV_JAL:
case R_RISCV_RVC_JUMP:
+ /* This line has to match the check in _bfd_riscv_relax_section. */
if (bfd_link_pic (info) && h != NULL && h->plt.offset != MINUS_ONE)
{
/* Refer to the PLT entry. */
int rd, r_type, len = 4, rvc = elf_elfheader (abfd)->e_flags & EF_RISCV_RVC;
/* If the call crosses section boundaries, an alignment directive could
- cause the PC-relative offset to later increase. */
- if (VALID_UJTYPE_IMM (foff) && sym_sec->output_section != sec->output_section)
- foff += (foff < 0 ? -max_alignment : max_alignment);
+ cause the PC-relative offset to later increase, so we need to add in the
+ max alignment of any section inclusive from the call to the target.
+ Otherwise, we only need to use the alignment of the current section. */
+ if (VALID_UJTYPE_IMM (foff))
+ {
+ if (sym_sec->output_section == sec->output_section
+ && sym_sec->output_section != bfd_abs_section_ptr)
+ max_alignment = (bfd_vma) 1 << sym_sec->output_section->alignment_power;
+ foff += (foff < 0 ? -max_alignment : max_alignment);
+ }
/* See if this function call can be shortened. */
if (!VALID_UJTYPE_IMM (foff) && !(!bfd_link_pic (link_info) && near_zero))
undefined_weak = TRUE;
}
- if (h->plt.offset != MINUS_ONE)
+ /* This line has to match the check in riscv_elf_relocate_section
+ in the R_RISCV_CALL[_PLT] case. */
+ if (bfd_link_pic (info) && h->plt.offset != MINUS_ONE)
{
sym_sec = htab->elf.splt;
symval = h->plt.offset;