aboutsummaryrefslogtreecommitdiff
path: root/binutils
diff options
context:
space:
mode:
authorAndrew Waterman <waterman@cs.berkeley.edu>2015-10-10 15:40:59 -0700
committerAndrew Waterman <waterman@cs.berkeley.edu>2015-10-10 15:43:58 -0700
commit50af352e5e0f5744f48e864661f880f401967eb2 (patch)
tree8ef89bd960c6ba80a5e32c9b0b19533fac17947e /binutils
parent6154561c2af6d26752beffb80c5284880b03b860 (diff)
downloadriscv-gnu-toolchain-50af352e5e0f5744f48e864661f880f401967eb2.zip
riscv-gnu-toolchain-50af352e5e0f5744f48e864661f880f401967eb2.tar.gz
riscv-gnu-toolchain-50af352e5e0f5744f48e864661f880f401967eb2.tar.bz2
binutils: fix LUI relaxation bug
Section merging could make a gp-relative reference go out of range after relaxation. Stop relaxing LUIs against mergeable symbols, and add error checking to catch things like this in the future.
Diffstat (limited to 'binutils')
-rw-r--r--binutils/bfd/elfnn-riscv.c50
-rw-r--r--binutils/bfd/elfxx-riscv.c32
-rw-r--r--binutils/include/elf/riscv.h2
3 files changed, 71 insertions, 13 deletions
diff --git a/binutils/bfd/elfnn-riscv.c b/binutils/bfd/elfnn-riscv.c
index bd086d6..46c24ba 100644
--- a/binutils/bfd/elfnn-riscv.c
+++ b/binutils/bfd/elfnn-riscv.c
@@ -1488,12 +1488,14 @@ perform_relocation (const reloc_howto_type *howto,
break;
case R_RISCV_LO12_I:
+ case R_RISCV_GPREL_I:
case R_RISCV_TPREL_LO12_I:
case R_RISCV_PCREL_LO12_I:
value = ENCODE_ITYPE_IMM (value);
break;
case R_RISCV_LO12_S:
+ case R_RISCV_GPREL_S:
case R_RISCV_TPREL_LO12_S:
case R_RISCV_PCREL_LO12_S:
value = ENCODE_STYPE_IMM (value);
@@ -1810,6 +1812,8 @@ riscv_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
case R_RISCV_BRANCH:
case R_RISCV_RVC_BRANCH:
case R_RISCV_RVC_LUI:
+ case R_RISCV_LO12_I:
+ case R_RISCV_LO12_S:
/* These require no special handling beyond perform_relocation. */
break;
@@ -1943,8 +1947,8 @@ riscv_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
}
break;
- case R_RISCV_LO12_I:
- case R_RISCV_LO12_S:
+ case R_RISCV_GPREL_I:
+ case R_RISCV_GPREL_S:
{
bfd_vma gp = riscv_global_pointer_value (info);
bfd_boolean x0_base = VALID_ITYPE_IMM (relocation + rel->r_addend);
@@ -1960,6 +1964,8 @@ riscv_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
}
bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
}
+ else
+ r = bfd_reloc_overflow;
break;
}
@@ -2712,8 +2718,7 @@ _bfd_riscv_relax_call (bfd *abfd, asection *sec, asection *sym_sec,
/* Relax non-PIC global variable references. */
static bfd_boolean
-_bfd_riscv_relax_lui (bfd *abfd, asection *sec,
- asection *sym_sec ATTRIBUTE_UNUSED,
+_bfd_riscv_relax_lui (bfd *abfd, asection *sec, asection *sym_sec,
struct bfd_link_info *link_info,
Elf_Internal_Rela *rel,
bfd_vma symval,
@@ -2723,22 +2728,41 @@ _bfd_riscv_relax_lui (bfd *abfd, asection *sec,
bfd_vma gp = riscv_global_pointer_value (link_info);
int use_rvc = elf_elfheader (abfd)->e_flags & EF_RISCV_RVC;
+ /* Mergeable symbols might later move out of range. */
+ if (sym_sec->flags & SEC_MERGE)
+ return TRUE;
+
BFD_ASSERT (rel->r_offset + 4 <= sec->size);
/* Is the reference in range of x0 or gp? */
- if (VALID_ITYPE_IMM (symval - gp) || (symval < RISCV_IMM_REACH/2))
+ if (VALID_ITYPE_IMM (symval) || VALID_ITYPE_IMM (symval - gp))
{
- /* We can delete the unnecessary AUIPC. The corresponding LO12 reloc
- will be converted to gp- or x0-relative during relocation. */
- rel->r_info = ELFNN_R_INFO (0, R_RISCV_NONE);
+ 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);
+ return TRUE;
- *again = TRUE;
- return riscv_relax_delete_bytes (abfd, sec, rel->r_offset, 4);
+ case R_RISCV_LO12_S:
+ rel->r_info = ELFNN_R_INFO (sym, R_RISCV_GPREL_S);
+ return TRUE;
+
+ case R_RISCV_HI20:
+ /* We can delete the unnecessary LUI and reloc. */
+ rel->r_info = ELFNN_R_INFO (0, R_RISCV_NONE);
+ *again = TRUE;
+ return riscv_relax_delete_bytes (abfd, sec, rel->r_offset, 4);
+
+ default:
+ abort ();
+ }
}
/* Can we relax LUI to C.LUI? Alignment might move the section forward;
account for this assuming page alignment at worst. */
if (use_rvc
+ && ELFNN_R_TYPE (rel->r_info) == R_RISCV_HI20
&& VALID_RVC_LUI_IMM (RISCV_CONST_HIGH_PART (symval))
&& VALID_RVC_LUI_IMM (RISCV_CONST_HIGH_PART (symval + ELF_MAXPAGESIZE)))
{
@@ -2870,7 +2894,9 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
{
if (type == R_RISCV_CALL || type == R_RISCV_CALL_PLT)
relax_func = _bfd_riscv_relax_call;
- else if (type == R_RISCV_HI20)
+ else if (type == R_RISCV_HI20
+ || type == R_RISCV_LO12_I
+ || type == R_RISCV_LO12_S)
relax_func = _bfd_riscv_relax_lui;
else if (type == R_RISCV_TPREL_HI20 || type == R_RISCV_TPREL_ADD)
relax_func = _bfd_riscv_relax_tls_le;
@@ -2929,8 +2955,6 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
if (h->plt.offset != MINUS_ONE)
symval = sec_addr (htab->elf.splt) + h->plt.offset;
- else if (h->root.type == bfd_link_hash_undefweak)
- symval = 0;
else if (h->root.u.def.section->output_section == NULL
|| (h->root.type != bfd_link_hash_defined
&& h->root.type != bfd_link_hash_defweak))
diff --git a/binutils/bfd/elfxx-riscv.c b/binutils/bfd/elfxx-riscv.c
index 447b791..e51514c 100644
--- a/binutils/bfd/elfxx-riscv.c
+++ b/binutils/bfd/elfxx-riscv.c
@@ -689,6 +689,36 @@ static reloc_howto_type howto_table[] =
0, /* src_mask */
ENCODE_RVC_IMM (-1U), /* dst_mask */
FALSE), /* pcrel_offset */
+
+ /* High 12 bits of 32-bit load or add. */
+ HOWTO (R_RISCV_GPREL_I, /* type */
+ 0, /* rightshift */
+ 2, /* size */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_RISCV_GPREL_I", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ ENCODE_ITYPE_IMM (-1U), /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* High 12 bits of 32-bit store. */
+ HOWTO (R_RISCV_GPREL_S, /* type */
+ 0, /* rightshift */
+ 2, /* size */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_RISCV_GPREL_S", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ ENCODE_STYPE_IMM (-1U), /* dst_mask */
+ FALSE), /* pcrel_offset */
};
/* A mapping from BFD reloc types to RISC-V ELF reloc types. */
@@ -739,6 +769,8 @@ static const struct elf_reloc_map riscv_reloc_map[] =
{ BFD_RELOC_RISCV_RVC_BRANCH, R_RISCV_RVC_BRANCH },
{ BFD_RELOC_RISCV_RVC_JUMP, R_RISCV_RVC_JUMP },
{ BFD_RELOC_RISCV_RVC_LUI, R_RISCV_RVC_LUI },
+ { BFD_RELOC_RISCV_GPREL_I, R_RISCV_GPREL_I },
+ { BFD_RELOC_RISCV_GPREL_S, R_RISCV_GPREL_S },
};
/* Given a BFD reloc type, return a howto structure. */
diff --git a/binutils/include/elf/riscv.h b/binutils/include/elf/riscv.h
index c250b65..bb63287 100644
--- a/binutils/include/elf/riscv.h
+++ b/binutils/include/elf/riscv.h
@@ -77,6 +77,8 @@ START_RELOC_NUMBERS (elf_riscv_reloc_type)
RELOC_NUMBER (R_RISCV_RVC_BRANCH, 44)
RELOC_NUMBER (R_RISCV_RVC_JUMP, 45)
RELOC_NUMBER (R_RISCV_RVC_LUI, 46)
+ RELOC_NUMBER (R_RISCV_GPREL_I, 47)
+ RELOC_NUMBER (R_RISCV_GPREL_S, 48)
END_RELOC_NUMBERS (R_RISCV_max)
/* Processor specific flags for the ELF header e_flags field. */