[WIP][PATCH] RISC-V: Implement relocations for GP-relative addressing

Maciej W. Rozycki macro@wdc.com
Mon Aug 31 14:08:37 GMT 2020


Implement R_RISCV_GPREL_HI20, R_RISCV_GPREL_LO12_I, and 
R_RISCV_GPREL_LO12_S relocations and the associated GAS relocations 
operators.

	bfd/
	* elfnn-riscv.c (perform_relocation): Handle R_RISCV_GPREL_HI20, 
	R_RISCV_GPREL_LO12_I, and R_RISCV_GPREL_LO12_S relocations.
	(riscv_elf_relocate_section): Likewise.
	* elfxx-riscv.c (howto_table, riscv_reloc_map): Likewise.
	* reloc.c (BFD_RELOC_RISCV_GPREL_HI20)
	(BFD_RELOC_RISCV_GPREL_LO12_I, BFD_RELOC_RISCV_GPREL_LO12_S): 
	New relocations.
	* bfd-in2.h: Regenerate.
	* libbfd.h: Regenerate.

	gas/
	* config/tc-riscv.c (append_insn): Handle 
	BFD_RELOC_RISCV_GPREL_HI20.
	(percent_op_utype): Add `%gprel_hi' operator.
	(percent_op_itype, percent_op_stype): Add `%gprel_lo' operator.
	(md_apply_fix): Handle BFD_RELOC_RISCV_GPREL_HI20, 
	BFD_RELOC_RISCV_GPREL_LO12_S, and BFD_RELOC_RISCV_GPREL_LO12_I 
	relocations.

	include/
	* elf/riscv.h (elf_riscv_reloc_type): Add R_RISCV_GPREL_HI20,
	R_RISCV_GPREL_LO12_I, and R_RISCV_GPREL_LO12_S relocations.
---
Hi,

 This is very early stage really, just implementing basic GP-relative 
relocation support, in preparation for FDPIC support discussed here:

<https://groups.google.com/a/groups.riscv.org/g/sw-dev/c/ZjYUJswknQ4>

I planned adding support to GAS macros such as LA next, but I won't be 
able to continue with this effort now as I am leaving Western Digital 
today, so I am posting this in case someone finds it useful or wishes to 
continue the effort.

 No regressions in `riscv64-linux-gnu' testing.

 A corresponding GCC change has also been posted.

  Maciej
---
 bfd/bfd-in2.h         |    3 ++
 bfd/elfnn-riscv.c     |    9 ++++++++
 bfd/elfxx-riscv.c     |   51 ++++++++++++++++++++++++++++++++++++++++++++++++++
 bfd/libbfd.h          |    3 ++
 bfd/reloc.c           |    6 +++++
 gas/config/tc-riscv.c |    9 +++++++-
 include/elf/riscv.h   |    3 ++
 7 files changed, 83 insertions(+), 1 deletion(-)

binutils-riscv-gprel.diff
Index: binutils-gdb/bfd/bfd-in2.h
===================================================================
--- binutils-gdb.orig/bfd/bfd-in2.h
+++ binutils-gdb/bfd/bfd-in2.h
@@ -4408,6 +4408,9 @@ number for the SBIC, SBIS, SBI and CBI i
   BFD_RELOC_RISCV_SET16,
   BFD_RELOC_RISCV_SET32,
   BFD_RELOC_RISCV_32_PCREL,
+  BFD_RELOC_RISCV_GPREL_HI20,
+  BFD_RELOC_RISCV_GPREL_LO12_I,
+  BFD_RELOC_RISCV_GPREL_LO12_S,
 
 /* Renesas RL78 Relocations.  */
   BFD_RELOC_RL78_NEG8,
Index: binutils-gdb/bfd/elfnn-riscv.c
===================================================================
--- binutils-gdb.orig/bfd/elfnn-riscv.c
+++ binutils-gdb/bfd/elfnn-riscv.c
@@ -1325,6 +1325,7 @@ perform_relocation (const reloc_howto_ty
     case R_RISCV_GOT_HI20:
     case R_RISCV_TLS_GOT_HI20:
     case R_RISCV_TLS_GD_HI20:
+    case R_RISCV_GPREL_HI20:
       if (ARCH_SIZE > 32 && !VALID_UTYPE_IMM (RISCV_CONST_HIGH_PART (value)))
 	return bfd_reloc_overflow;
       value = ENCODE_UTYPE_IMM (RISCV_CONST_HIGH_PART (value));
@@ -1335,6 +1336,7 @@ perform_relocation (const reloc_howto_ty
     case R_RISCV_TPREL_LO12_I:
     case R_RISCV_TPREL_I:
     case R_RISCV_PCREL_LO12_I:
+    case R_RISCV_GPREL_LO12_I:
       value = ENCODE_ITYPE_IMM (value);
       break;
 
@@ -1343,6 +1345,7 @@ perform_relocation (const reloc_howto_ty
     case R_RISCV_TPREL_LO12_S:
     case R_RISCV_TPREL_S:
     case R_RISCV_PCREL_LO12_S:
+    case R_RISCV_GPREL_LO12_S:
       value = ENCODE_STYPE_IMM (value);
       break;
 
@@ -1923,6 +1926,12 @@ riscv_elf_relocate_section (bfd *output_
 	    r = bfd_reloc_overflow;
 	  break;
 
+	case R_RISCV_GPREL_HI20:
+	case R_RISCV_GPREL_LO12_I:
+	case R_RISCV_GPREL_LO12_S:
+	  relocation -= riscv_global_pointer_value (info);
+	  break;
+
 	case R_RISCV_GPREL_I:
 	case R_RISCV_GPREL_S:
 	  {
Index: binutils-gdb/bfd/elfxx-riscv.c
===================================================================
--- binutils-gdb.orig/bfd/elfxx-riscv.c
+++ binutils-gdb/bfd/elfxx-riscv.c
@@ -854,6 +854,54 @@ static reloc_howto_type howto_table[] =
 	 0,				/* src_mask */
 	 MINUS_ONE,			/* dst_mask */
 	 FALSE),			/* pcrel_offset */
+
+  /* R_RISCV_IRELATIVE  */
+  EMPTY_HOWTO (58),
+
+  /* High 20 bits of a 32-bit GP-relative reference.  */
+  HOWTO (R_RISCV_GPREL_HI20,		/* type */
+	 0,				/* rightshift */
+	 2,				/* size */
+	 32,				/* bitsize */
+	 FALSE,				/* pc_relative */
+	 0,				/* bitpos */
+	 complain_overflow_signed,	/* complain_on_overflow */
+	 bfd_elf_generic_reloc,		/* special_function */
+	 "R_RISCV_GPREL_HI20",		/* name */
+	 FALSE,				/* partial_inplace */
+	 0,				/* src_mask */
+	 ENCODE_UTYPE_IMM (-1U),	/* dst_mask */
+	 FALSE),			/* pcrel_offset */
+
+  /* Low 12 bits of a 32-bit GP-relative load or add.  */
+  HOWTO (R_RISCV_GPREL_LO12_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_LO12_I",	/* name */
+	 FALSE,				/* partial_inplace */
+	 0,				/* src_mask */
+	 ENCODE_ITYPE_IMM (-1U),	/* dst_mask */
+	 FALSE),			/* pcrel_offset */
+
+  /* Low 12 bits of a 32-bit GP-relative store.  */
+  HOWTO (R_RISCV_GPREL_LO12_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_LO12_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.  */
@@ -916,6 +964,9 @@ static const struct elf_reloc_map riscv_
   { BFD_RELOC_RISCV_SET16, R_RISCV_SET16 },
   { BFD_RELOC_RISCV_SET32, R_RISCV_SET32 },
   { BFD_RELOC_RISCV_32_PCREL, R_RISCV_32_PCREL },
+  { BFD_RELOC_RISCV_GPREL_HI20, R_RISCV_GPREL_HI20 },
+  { BFD_RELOC_RISCV_GPREL_LO12_S, R_RISCV_GPREL_LO12_S },
+  { BFD_RELOC_RISCV_GPREL_LO12_I, R_RISCV_GPREL_LO12_I },
 };
 
 /* Given a BFD reloc type, return a howto structure.  */
Index: binutils-gdb/bfd/libbfd.h
===================================================================
--- binutils-gdb.orig/bfd/libbfd.h
+++ binutils-gdb/bfd/libbfd.h
@@ -2378,6 +2378,9 @@ static const char *const bfd_reloc_code_
   "BFD_RELOC_RISCV_SET16",
   "BFD_RELOC_RISCV_SET32",
   "BFD_RELOC_RISCV_32_PCREL",
+  "BFD_RELOC_RISCV_GPREL_HI20",
+  "BFD_RELOC_RISCV_GPREL_LO12_I",
+  "BFD_RELOC_RISCV_GPREL_LO12_S",
   "BFD_RELOC_RL78_NEG8",
   "BFD_RELOC_RL78_NEG16",
   "BFD_RELOC_RL78_NEG24",
Index: binutils-gdb/bfd/reloc.c
===================================================================
--- binutils-gdb.orig/bfd/reloc.c
+++ binutils-gdb/bfd/reloc.c
@@ -5215,6 +5215,12 @@ ENUMX
   BFD_RELOC_RISCV_SET32
 ENUMX
   BFD_RELOC_RISCV_32_PCREL
+ENUMX
+  BFD_RELOC_RISCV_GPREL_HI20
+ENUMX
+  BFD_RELOC_RISCV_GPREL_LO12_I
+ENUMX
+  BFD_RELOC_RISCV_GPREL_LO12_S
 ENUMDOC
   RISC-V relocations.
 
Index: binutils-gdb/gas/config/tc-riscv.c
===================================================================
--- binutils-gdb.orig/gas/config/tc-riscv.c
+++ binutils-gdb/gas/config/tc-riscv.c
@@ -1138,7 +1138,8 @@ append_insn (struct riscv_cl_insn *ip, e
       || reloc_type == BFD_RELOC_RISCV_HI20
       || reloc_type == BFD_RELOC_RISCV_PCREL_HI20
       || reloc_type == BFD_RELOC_RISCV_TPREL_HI20
-      || reloc_type == BFD_RELOC_RISCV_TPREL_ADD)
+      || reloc_type == BFD_RELOC_RISCV_TPREL_ADD
+      || reloc_type == BFD_RELOC_RISCV_GPREL_HI20)
     {
       frag_wane (frag_now);
       frag_new (0);
@@ -1501,6 +1502,7 @@ static const struct percent_op_match per
   {"%tls_ie_pcrel_hi", BFD_RELOC_RISCV_TLS_GOT_HI20},
   {"%tls_gd_pcrel_hi", BFD_RELOC_RISCV_TLS_GD_HI20},
   {"%hi", BFD_RELOC_RISCV_HI20},
+  {"%gprel_hi", BFD_RELOC_RISCV_GPREL_HI20},
   {0, 0}
 };
 
@@ -1509,6 +1511,7 @@ static const struct percent_op_match per
   {"%lo", BFD_RELOC_RISCV_LO12_I},
   {"%tprel_lo", BFD_RELOC_RISCV_TPREL_LO12_I},
   {"%pcrel_lo", BFD_RELOC_RISCV_PCREL_LO12_I},
+  {"%gprel_lo", BFD_RELOC_RISCV_GPREL_LO12_I},
   {0, 0}
 };
 
@@ -1517,6 +1520,7 @@ static const struct percent_op_match per
   {"%lo", BFD_RELOC_RISCV_LO12_S},
   {"%tprel_lo", BFD_RELOC_RISCV_TPREL_LO12_S},
   {"%pcrel_lo", BFD_RELOC_RISCV_PCREL_LO12_S},
+  {"%gprel_lo", BFD_RELOC_RISCV_GPREL_LO12_S},
   {0, 0}
 };
 
@@ -3009,6 +3013,9 @@ md_apply_fix (fixS *fixP, valueT *valP,
     case BFD_RELOC_RISCV_PCREL_HI20:
     case BFD_RELOC_RISCV_PCREL_LO12_S:
     case BFD_RELOC_RISCV_PCREL_LO12_I:
+    case BFD_RELOC_RISCV_GPREL_HI20:
+    case BFD_RELOC_RISCV_GPREL_LO12_S:
+    case BFD_RELOC_RISCV_GPREL_LO12_I:
       relaxable = riscv_opts.relax;
       break;
 
Index: binutils-gdb/include/elf/riscv.h
===================================================================
--- binutils-gdb.orig/include/elf/riscv.h
+++ binutils-gdb/include/elf/riscv.h
@@ -88,6 +88,9 @@ START_RELOC_NUMBERS (elf_riscv_reloc_typ
   RELOC_NUMBER (R_RISCV_SET16, 55)
   RELOC_NUMBER (R_RISCV_SET32, 56)
   RELOC_NUMBER (R_RISCV_32_PCREL, 57)
+  RELOC_NUMBER (R_RISCV_GPREL_HI20, 59)
+  RELOC_NUMBER (R_RISCV_GPREL_LO12_I, 60)
+  RELOC_NUMBER (R_RISCV_GPREL_LO12_S, 61)
 END_RELOC_NUMBERS (R_RISCV_max)
 
 /* Processor specific flags for the ELF header e_flags field.  */


More information about the Binutils mailing list