for (rel = relocs; rel < relocs + sec->reloc_count; rel++)
{
unsigned int r_type;
- unsigned long r_symndx;
+ unsigned int r_symndx;
struct elf_link_hash_entry *h;
r_symndx = ELFNN_R_SYM (rel->r_info);
/* PR15323, ref flags aren't set for references in the same
object. */
- h->root.non_ir_ref = 1;
+ h->root.non_ir_ref_regular = 1;
}
switch (r_type)
to copy the initial value out of the dynamic object and into the
runtime process image. We need to remember the offset into the
.rel.bss section we are going to use. */
- if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
+ if (eh->tls_type & ~GOT_NORMAL)
+ {
+ s = htab->sdyntdata;
+ srel = htab->elf.srelbss;
+ }
+ else if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
{
s = htab->elf.sdynrelro;
srel = htab->elf.sreldynrelro;
h->needs_copy = 1;
}
- if (eh->tls_type & ~GOT_NORMAL)
- return _bfd_elf_adjust_dynamic_copy (info, h, htab->sdyntdata);
-
return _bfd_elf_adjust_dynamic_copy (info, h, s);
}
{
struct bfd_link_hash_entry *h;
- h = bfd_link_hash_lookup (info->hash, "__global_pointer$", FALSE, FALSE, TRUE);
+ h = bfd_link_hash_lookup (info->hash, RISCV_GP_SYMBOL, FALSE, FALSE, TRUE);
if (h == NULL || h->type != bfd_link_hash_defined)
return 0;
case R_RISCV_SET8:
case R_RISCV_SET16:
case R_RISCV_SET32:
+ case R_RISCV_32_PCREL:
case R_RISCV_TLS_DTPREL32:
case R_RISCV_TLS_DTPREL64:
break;
}
static bfd_boolean
-riscv_record_pcrel_hi_reloc (riscv_pcrel_relocs *p, bfd_vma addr, bfd_vma value)
+riscv_zero_pcrel_hi_reloc (Elf_Internal_Rela *rel,
+ struct bfd_link_info *info,
+ bfd_vma pc,
+ bfd_vma addr,
+ bfd_byte *contents,
+ const reloc_howto_type *howto,
+ bfd *input_bfd)
+{
+ /* We may need to reference low addreses in PC-relative modes even when the
+ * PC is far away from these addresses. For example, undefweak references
+ * need to produce the address 0 when linked. As 0 is far from the arbitrary
+ * addresses that we can link PC-relative programs at, the linker can't
+ * actually relocate references to those symbols. In order to allow these
+ * programs to work we simply convert the PC-relative auipc sequences to
+ * 0-relative lui sequences. */
+ if (bfd_link_pic (info))
+ return FALSE;
+
+ /* If it's possible to reference the symbol using auipc we do so, as that's
+ * more in the spirit of the PC-relative relocations we're processing. */
+ bfd_vma offset = addr - pc;
+ if (ARCH_SIZE == 32 || VALID_UTYPE_IMM (RISCV_CONST_HIGH_PART (offset)))
+ return FALSE;
+
+ /* If it's impossible to reference this with a LUI-based offset then don't
+ * bother to convert it at all so users still see the PC-relative relocation
+ * in the truncation message. */
+ if (ARCH_SIZE > 32 && !VALID_UTYPE_IMM (RISCV_CONST_HIGH_PART (addr)))
+ return FALSE;
+
+ rel->r_info = ELFNN_R_INFO(addr, R_RISCV_HI20);
+
+ bfd_vma insn = bfd_get(howto->bitsize, input_bfd, contents + rel->r_offset);
+ insn = (insn & ~MASK_AUIPC) | MATCH_LUI;
+ bfd_put(howto->bitsize, input_bfd, insn, contents + rel->r_offset);
+ return TRUE;
+}
+
+static bfd_boolean
+riscv_record_pcrel_hi_reloc (riscv_pcrel_relocs *p, bfd_vma addr,
+ bfd_vma value, bfd_boolean absolute)
{
- riscv_pcrel_hi_reloc entry = {addr, value - addr};
+ bfd_vma offset = absolute ? value : value - addr;
+ riscv_pcrel_hi_reloc entry = {addr, offset};
riscv_pcrel_hi_reloc **slot =
(riscv_pcrel_hi_reloc **) htab_find_slot (p->hi_relocs, &entry, INSERT);
Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (input_bfd);
struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd);
bfd_vma *local_got_offsets = elf_local_got_offsets (input_bfd);
+ bfd_boolean absolute;
if (!riscv_init_pcrel_relocs (&pcrel_relocs))
return FALSE;
case R_RISCV_SET8:
case R_RISCV_SET16:
case R_RISCV_SET32:
+ case R_RISCV_32_PCREL:
/* These require no special handling beyond perform_relocation. */
break;
}
}
relocation = sec_addr (htab->elf.sgot) + off;
- if (!riscv_record_pcrel_hi_reloc (&pcrel_relocs, pc, relocation))
+ absolute = riscv_zero_pcrel_hi_reloc (rel,
+ info,
+ pc,
+ relocation,
+ contents,
+ howto,
+ input_bfd);
+ r_type = ELFNN_R_TYPE (rel->r_info);
+ howto = riscv_elf_rtype_to_howto (r_type);
+ if (!riscv_record_pcrel_hi_reloc (&pcrel_relocs, pc,
+ relocation, absolute))
r = bfd_reloc_overflow;
break;
}
case R_RISCV_PCREL_HI20:
+ absolute = riscv_zero_pcrel_hi_reloc (rel,
+ info,
+ pc,
+ relocation,
+ contents,
+ howto,
+ input_bfd);
+ r_type = ELFNN_R_TYPE (rel->r_info);
+ howto = riscv_elf_rtype_to_howto (r_type);
if (!riscv_record_pcrel_hi_reloc (&pcrel_relocs, pc,
- relocation + rel->r_addend))
+ relocation + rel->r_addend,
+ absolute))
r = bfd_reloc_overflow;
break;
BFD_ASSERT (off < (bfd_vma) -2);
relocation = sec_addr (htab->elf.sgot) + off + (is_ie ? ie_off : 0);
- if (!riscv_record_pcrel_hi_reloc (&pcrel_relocs, pc, relocation))
+ if (!riscv_record_pcrel_hi_reloc (&pcrel_relocs, pc,
+ relocation, FALSE))
r = bfd_reloc_overflow;
unresolved_reloc = FALSE;
break;
rel->r_offset) != (bfd_vma) -1)
{
(*_bfd_error_handler)
- (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"),
+ (_("%B(%A+%#Lx): unresolvable %s relocation against symbol `%s'"),
input_bfd,
input_section,
- (long) rel->r_offset,
+ rel->r_offset,
howto->name,
h->root.root.string);
continue;
rela.r_offset = sec_addr (h->root.u.def.section) + h->root.u.def.value;
rela.r_info = ELFNN_R_INFO (h->dynindx, R_RISCV_COPY);
rela.r_addend = 0;
- if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
+ if (h->root.u.def.section == htab->elf.sdynrelro)
s = htab->elf.sreldynrelro;
else
s = htab->elf.srelbss;
ret = riscv_finish_dyn (output_bfd, info, dynobj, sdyn);
- if (ret != TRUE)
+ if (!ret)
return ret;
/* Fill in the head and tail entries in the procedure linkage table. */
BFD_ASSERT (rel->r_offset + 4 <= sec->size);
+ if (gp)
+ {
+ /* If gp and the symbol are in the same output section, then
+ consider only that section's alignment. */
+ struct bfd_link_hash_entry *h =
+ bfd_link_hash_lookup (link_info->hash, RISCV_GP_SYMBOL, FALSE, FALSE,
+ TRUE);
+ if (h->u.def.section->output_section == sym_sec->output_section)
+ max_alignment = (bfd_vma) 1 << sym_sec->output_section->alignment_power;
+ }
+
/* Is the reference in range of x0 or gp?
Valid gp range conservatively because of alignment issue. */
if (VALID_ITYPE_IMM (symval)
static bfd_boolean
_bfd_riscv_relax_align (bfd *abfd, asection *sec,
- asection *sym_sec ATTRIBUTE_UNUSED,
+ asection *sym_sec,
struct bfd_link_info *link_info ATTRIBUTE_UNUSED,
Elf_Internal_Rela *rel,
bfd_vma symval,
/* Make sure there are enough NOPs to actually achieve the alignment. */
if (rel->r_addend < nop_bytes)
- return FALSE;
+ {
+ (*_bfd_error_handler)
+ (_("%B(%A+0x%lx): %d bytes required for alignment"
+ "to %d-byte boundary, but only %d present"),
+ abfd, sym_sec, rel->r_offset, nop_bytes, alignment, rel->r_addend);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
/* Delete the reloc. */
rel->r_info = ELFNN_R_INFO (0, R_RISCV_NONE);