RISC-V: Don't emit internal relax relocations when --emit-relocs.

Message ID 20240507100749.44181-1-nelson@rivosinc.com
State New
Headers
Series RISC-V: Don't emit internal relax relocations when --emit-relocs. |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_binutils_build--master-arm success Testing passed
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 success Testing passed
linaro-tcwg-bot/tcwg_binutils_check--master-aarch64 success Testing passed
linaro-tcwg-bot/tcwg_binutils_check--master-arm success Testing passed

Commit Message

Nelson Chu May 7, 2024, 10:07 a.m. UTC
  Although PR27180 still has the bug, and there may be no conclusion yet about
PR30844, at least I think we cannot just emit the internal relocations when
--emit-relocs.  The internal relocation means it isn't defined in the riscv
psabi, it is just used in the GNU linker.  All of them are used for relaxation
so far.

For relax lui,
1. Emit R_RISCV_HI20 for R_RISCV_RVC_LUI.
2. R_RISCV_LUI_GPREL_I/S, which is same as R_RISCV_GPREL_I/S before, but it
   implies the relocation type before relaxing.  Emit R_RISCV_LO12_I/S for it,
   and may emit R_RISCV_GPREL_LO12_I/S for it in the future.

For relax auipc,
1. R_RISCV_AUIPC_GPREL_I/S is similar as R_RISCV_LUI_GPREL_I/S.  Emit
   R_RISCV_PCREL_LO12_I/S for it.  It is hard to find back the corresponding
   R_RISCV_PCREL_HI20 since deleted, so we still store the target symbol
   rather than it's pcrel instruction address.  I think it's fine since the
   symbol + addend field in the readelf/objdump is still shown as symbol - gp.
   Likewise, we may emit R_RISCV_GPREL_LO12_I/S for it in the future.

For relax tprel,
1. Emit R_RISCV_TPREL_LO12_I/S for R_RISCV_TPREL_I/S.

bfd/
	* elfnn-riscv.c (perform_relocation): Updated since R_RISCV_GPREL_I/S
	are seperated to R_RISCV_LUI_GPREL_I/S and R_RISCV_AUIPC_GPREL_I/S.
	(_bfd_riscv_relax_lui): Likewise.
	(_bfd_riscv_relax_pc): Likewise.
	(riscv_elf_relocate_section): Shouldn't emit internal relocation when
	--emit-relocs.
	* elfxx-riscv.c (howto_table_internal): Seperated R_RISCV_GPREL_I/S
	to R_RISCV_LUI_GPREL_I/S and R_RISCV_AUIPC_GPREL_I/S.
	(elf_internal_reloc_map, riscv_internal_reloc_map):
	Map the internal relax relocation to the one which we should emit when
	--emit-relocs.
	(riscv_emit_internal_reloc_type_lookup): New function.
	(elfxx-riscv.h): extern riscv_emit_internal_reloc_type_lookup.
include/
	* elf/riscv.h: Updated since R_RISCV_GPREL_I/S are seperated to
	R_RISCV_LUI_GPREL_I/S and R_RISCV_AUIPC_GPREL_I/S.
ld/
	* testsuite/ld-riscv-elf/c-lui-2-emitrelocs.d: New testcase.
	* testsuite/ld-riscv-elf/pcgp-relax-01-emitrelocs.d: Likewise.
	* testsuite/ld-riscv-elf/ld-riscv-elf.exp: Updated.
---
 bfd/elfnn-riscv.c                             | 28 +++++--
 bfd/elfxx-riscv.c                             | 84 +++++++++++++++++--
 bfd/elfxx-riscv.h                             |  3 +
 include/elf/riscv.h                           | 10 ++-
 .../ld-riscv-elf/c-lui-2-emitrelocs.d         | 23 +++++
 ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp    |  2 +
 .../ld-riscv-elf/pcgp-relax-01-emitrelocs.d   | 38 +++++++++
 7 files changed, 167 insertions(+), 21 deletions(-)
 create mode 100644 ld/testsuite/ld-riscv-elf/c-lui-2-emitrelocs.d
 create mode 100644 ld/testsuite/ld-riscv-elf/pcgp-relax-01-emitrelocs.d
  

Patch

diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index 604f6de4511..dbf7380986d 100644
--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -1804,7 +1804,8 @@  perform_relocation (const reloc_howto_type *howto,
       break;
 
     case R_RISCV_LO12_I:
-    case R_RISCV_GPREL_I:
+    case R_RISCV_LUI_GPREL_I:
+    case R_RISCV_AUIPC_GPREL_I:
     case R_RISCV_TPREL_LO12_I:
     case R_RISCV_TPREL_I:
     case R_RISCV_PCREL_LO12_I:
@@ -1814,7 +1815,8 @@  perform_relocation (const reloc_howto_type *howto,
       break;
 
     case R_RISCV_LO12_S:
-    case R_RISCV_GPREL_S:
+    case R_RISCV_LUI_GPREL_S:
+    case R_RISCV_AUIPC_GPREL_S:
     case R_RISCV_TPREL_LO12_S:
     case R_RISCV_TPREL_S:
     case R_RISCV_PCREL_LO12_S:
@@ -2816,8 +2818,10 @@  riscv_elf_relocate_section (bfd *output_bfd,
 	    r = bfd_reloc_overflow;
 	  break;
 
-	case R_RISCV_GPREL_I:
-	case R_RISCV_GPREL_S:
+	case R_RISCV_LUI_GPREL_I:
+	case R_RISCV_LUI_GPREL_S:
+	case R_RISCV_AUIPC_GPREL_I:
+	case R_RISCV_AUIPC_GPREL_S:
 	  {
 	    bfd_vma gp = riscv_global_pointer_value (info);
 	    bool x0_base = VALID_ITYPE_IMM (relocation + rel->r_addend);
@@ -3136,6 +3140,14 @@  riscv_elf_relocate_section (bfd *output_bfd,
       switch (r)
 	{
 	case bfd_reloc_ok:
+	  {
+	    /* Shouldn't emit internal relocs.  */
+	    reloc_howto_type *emit_howto =
+		riscv_emit_internal_reloc_type_lookup (input_bfd, r_type);
+	    if (emit_howto)
+	      rel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (rel->r_info),
+					  emit_howto->type);
+	  }
 	  continue;
 
 	case bfd_reloc_overflow:
@@ -4772,11 +4784,11 @@  _bfd_riscv_relax_lui (bfd *abfd,
       switch (ELFNN_R_TYPE (rel->r_info))
 	{
 	case R_RISCV_LO12_I:
-	  rel->r_info = ELFNN_R_INFO (sym, R_RISCV_GPREL_I);
+	  rel->r_info = ELFNN_R_INFO (sym, R_RISCV_LUI_GPREL_I);
 	  return true;
 
 	case R_RISCV_LO12_S:
-	  rel->r_info = ELFNN_R_INFO (sym, R_RISCV_GPREL_S);
+	  rel->r_info = ELFNN_R_INFO (sym, R_RISCV_LUI_GPREL_S);
 	  return true;
 
 	case R_RISCV_HI20:
@@ -5036,12 +5048,12 @@  _bfd_riscv_relax_pc (bfd *abfd ATTRIBUTE_UNUSED,
       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_info = ELFNN_R_INFO (sym, R_RISCV_AUIPC_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_info = ELFNN_R_INFO (sym, R_RISCV_AUIPC_GPREL_S);
 	  rel->r_addend += hi_reloc.hi_addend;
 	  return true;
 
diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c
index b08e44577b8..39a36a71958 100644
--- a/bfd/elfxx-riscv.c
+++ b/bfd/elfxx-riscv.c
@@ -884,7 +884,7 @@  static reloc_howto_type howto_table_internal[] =
   /* R_RISCV_DELETE.  */
   EMPTY_HOWTO (0),
 
-  /* High 6 bits of 18-bit absolute address.  */
+  /* For lui relaxation, high 6 bits of 18-bit absolute address.  */
   HOWTO (R_RISCV_RVC_LUI,		/* type */
 	 0,				/* rightshift */
 	 2,				/* size */
@@ -899,8 +899,8 @@  static reloc_howto_type howto_table_internal[] =
 	 ENCODE_CITYPE_IMM (-1U),	/* dst_mask */
 	 false),			/* pcrel_offset */
 
-  /* GP-relative load.  */
-  HOWTO (R_RISCV_GPREL_I,		/* type */
+  /* For lui relaxation, GP-relative load.  */
+  HOWTO (R_RISCV_LUI_GPREL_I,		/* type */
 	 0,				/* rightshift */
 	 4,				/* size */
 	 32,				/* bitsize */
@@ -908,14 +908,14 @@  static reloc_howto_type howto_table_internal[] =
 	 0,				/* bitpos */
 	 complain_overflow_dont,	/* complain_on_overflow */
 	 bfd_elf_generic_reloc,		/* special_function */
-	 "R_RISCV_GPREL_I",		/* name */
+	 "R_RISCV_LUI_GPREL_I",		/* name */
 	 false,				/* partial_inplace */
 	 0,				/* src_mask */
 	 ENCODE_ITYPE_IMM (-1U),	/* dst_mask */
 	 false),			/* pcrel_offset */
 
-  /* GP-relative store.  */
-  HOWTO (R_RISCV_GPREL_S,		/* type */
+  /* For lui relaxation, GP-relative store.  */
+  HOWTO (R_RISCV_LUI_GPREL_S,		/* type */
 	 0,				/* rightshift */
 	 4,				/* size */
 	 32,				/* bitsize */
@@ -923,13 +923,43 @@  static reloc_howto_type howto_table_internal[] =
 	 0,				/* bitpos */
 	 complain_overflow_dont,	/* complain_on_overflow */
 	 bfd_elf_generic_reloc,		/* special_function */
-	 "R_RISCV_GPREL_S",		/* name */
+	 "R_RISCV_LUI_GPREL_S",		/* name */
 	 false,				/* partial_inplace */
 	 0,				/* src_mask */
 	 ENCODE_STYPE_IMM (-1U),	/* dst_mask */
 	 false),			/* pcrel_offset */
 
-  /* TP-relative TLS LE load.  */
+  /* For auipc relaxation, GP-relative load.  */
+  HOWTO (R_RISCV_AUIPC_GPREL_I,		/* type */
+	 0,				/* rightshift */
+	 4,				/* size */
+	 32,				/* bitsize */
+	 false,				/* pc_relative */
+	 0,				/* bitpos */
+	 complain_overflow_dont,	/* complain_on_overflow */
+	 bfd_elf_generic_reloc,		/* special_function */
+	 "R_RISCV_AUIPC_GPREL_I",	/* name */
+	 false,				/* partial_inplace */
+	 0,				/* src_mask */
+	 ENCODE_ITYPE_IMM (-1U),	/* dst_mask */
+	 false),			/* pcrel_offset */
+
+  /* For auipc relaxation, GP-relative store.  */
+  HOWTO (R_RISCV_AUIPC_GPREL_S,		/* type */
+	 0,				/* rightshift */
+	 4,				/* size */
+	 32,				/* bitsize */
+	 false,				/* pc_relative */
+	 0,				/* bitpos */
+	 complain_overflow_dont,	/* complain_on_overflow */
+	 bfd_elf_generic_reloc,		/* special_function */
+	 "R_RISCV_AUIPC_GPREL_S",	/* name */
+	 false,				/* partial_inplace */
+	 0,				/* src_mask */
+	 ENCODE_STYPE_IMM (-1U),	/* dst_mask */
+	 false),			/* pcrel_offset */
+
+  /* For tprel relaxation, TP-relative TLS LE load.  */
   HOWTO (R_RISCV_TPREL_I,		/* type */
 	 0,				/* rightshift */
 	 4,				/* size */
@@ -944,7 +974,7 @@  static reloc_howto_type howto_table_internal[] =
 	 ENCODE_ITYPE_IMM (-1U),	/* dst_mask */
 	 false),			/* pcrel_offset */
 
-  /* TP-relative TLS LE store.  */
+  /* For tprel relaxation, TP-relative TLS LE store.  */
   HOWTO (R_RISCV_TPREL_S,		/* type */
 	 0,				/* rightshift */
 	 4,				/* size */
@@ -1038,6 +1068,42 @@  riscv_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
   return NULL;
 }
 
+/* A mapping from RISC-V internal reloc types to standard reloc types.  */
+struct elf_internal_reloc_map
+{ 
+  enum elf_riscv_reloc_type internal;
+  enum elf_riscv_reloc_type standard;
+};
+
+static const struct elf_internal_reloc_map riscv_internal_reloc_map[] =
+{
+  { R_RISCV_DELETE, R_RISCV_NONE },
+  { R_RISCV_RVC_LUI, R_RISCV_HI20 },
+  { R_RISCV_LUI_GPREL_I, R_RISCV_LO12_I},
+  { R_RISCV_LUI_GPREL_S, R_RISCV_LO12_S},
+  { R_RISCV_AUIPC_GPREL_I, R_RISCV_PCREL_LO12_I},
+  { R_RISCV_AUIPC_GPREL_S, R_RISCV_PCREL_LO12_S},
+  { R_RISCV_TPREL_I, R_RISCV_TPREL_LO12_I },
+  { R_RISCV_TPREL_S, R_RISCV_TPREL_LO12_S },
+};
+
+reloc_howto_type *
+riscv_emit_internal_reloc_type_lookup (bfd *abfd, unsigned int r_type)
+{
+  if (r_type < ARRAY_SIZE (howto_table))
+    return NULL;
+
+  unsigned int i;
+  for (i = 0; i < ARRAY_SIZE (riscv_internal_reloc_map); i++)
+    if (riscv_internal_reloc_map[i].internal == r_type)
+      return &howto_table[riscv_internal_reloc_map[i].standard];
+
+  (*_bfd_error_handler)
+	(_("%pB: warning: mismatched internal relocation type %#x"),
+	 abfd, r_type);
+  return NULL;
+}
+
 reloc_howto_type *
 riscv_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
 {
diff --git a/bfd/elfxx-riscv.h b/bfd/elfxx-riscv.h
index 49be71746b9..9c747fdd540 100644
--- a/bfd/elfxx-riscv.h
+++ b/bfd/elfxx-riscv.h
@@ -46,6 +46,9 @@  riscv_reloc_name_lookup (bfd *, const char *);
 extern reloc_howto_type *
 riscv_reloc_type_lookup (bfd *, bfd_reloc_code_real_type);
 
+extern reloc_howto_type *
+riscv_emit_internal_reloc_type_lookup (bfd *, unsigned int r_type);
+
 extern reloc_howto_type *
 riscv_elf_rtype_to_howto (bfd *, unsigned int r_type);
 
diff --git a/include/elf/riscv.h b/include/elf/riscv.h
index c1e73f7f5c0..3da04ef4806 100644
--- a/include/elf/riscv.h
+++ b/include/elf/riscv.h
@@ -100,10 +100,12 @@  END_RELOC_NUMBERS (R_RISCV_max)
 /* Internal relocations used exclusively by the relaxation pass.  */
 #define R_RISCV_DELETE  (R_RISCV_max)
 #define R_RISCV_RVC_LUI (R_RISCV_max + 1)
-#define R_RISCV_GPREL_I (R_RISCV_max + 2)
-#define R_RISCV_GPREL_S (R_RISCV_max + 3)
-#define R_RISCV_TPREL_I (R_RISCV_max + 4)
-#define R_RISCV_TPREL_S (R_RISCV_max + 5)
+#define R_RISCV_LUI_GPREL_I (R_RISCV_max + 2)
+#define R_RISCV_LUI_GPREL_S (R_RISCV_max + 3)
+#define R_RISCV_AUIPC_GPREL_I (R_RISCV_max + 4)
+#define R_RISCV_AUIPC_GPREL_S (R_RISCV_max + 5)
+#define R_RISCV_TPREL_I (R_RISCV_max + 6)
+#define R_RISCV_TPREL_S (R_RISCV_max + 7)
 
 /* Processor specific flags for the ELF header e_flags field.  */
 
diff --git a/ld/testsuite/ld-riscv-elf/c-lui-2-emitrelocs.d b/ld/testsuite/ld-riscv-elf/c-lui-2-emitrelocs.d
new file mode 100644
index 00000000000..f5658732239
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/c-lui-2-emitrelocs.d
@@ -0,0 +1,23 @@ 
+#name: c.lui to c.li relaxation
+#source: c-lui-2.s
+#as: -march=rv32ic
+#ld: -m[riscv_choose_ilp32_emul] -Tc-lui-2.ld --emit-relocs
+#objdump: -dr -M no-aliases,numeric
+
+.*:     file format .*
+
+
+Disassembly of section \.text:
+
+.* <_start>:
+.*:	4501                	c.li	x10,0
+.*:[ 	]+R_RISCV_HI20[ 	]+foo
+.*:	7fe00513          	addi	x10,x0,2046
+.*:[ 	]+R_RISCV_NONE[ 	]+\*ABS\*\+0x2
+.*:[ 	]+R_RISCV_LO12_I[ 	]+foo
+.*:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
+	...
+
+.* <foo>:
+.*:	8082                	c.jr	x1
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
index a1dd0e5e37e..de70dba628d 100644
--- a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
+++ b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
@@ -123,9 +123,11 @@  if [istarget "riscv*-*-*"] {
     run_dump_test "call-relax"
     run_dump_test "pcgp-relax-01"
     run_dump_test "pcgp-relax-01-norelaxgp"
+    run_dump_test "pcgp-relax-01-emitrelocs"
     run_dump_test "pcgp-relax-02"
     run_dump_test "c-lui"
     run_dump_test "c-lui-2"
+    run_dump_test "c-lui-2-emitrelocs"
     run_dump_test "disas-jalr"
     run_dump_test "pcrel-lo-addend"
     run_dump_test "pcrel-lo-addend-2a"
diff --git a/ld/testsuite/ld-riscv-elf/pcgp-relax-01-emitrelocs.d b/ld/testsuite/ld-riscv-elf/pcgp-relax-01-emitrelocs.d
new file mode 100644
index 00000000000..9aa05d5be6a
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/pcgp-relax-01-emitrelocs.d
@@ -0,0 +1,38 @@ 
+#source: pcgp-relax-01.s
+#ld: --relax --emit-relocs
+#objdump: -dr -Mno-aliases
+
+.*:[ 	]+file format .*
+
+
+Disassembly of section .text:
+
+0+[0-9a-f]+ <_start>:
+[ 	]+[0-9a-f]+:[ 	]+[0-9a-f]+[ 	]+addi[ 	]+a0,a0,[0-9]+
+[ 	]+[0-9a-f]+:[ 	]+R_RISCV_PCREL_LO12_I[ 	]+.L2
+[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
+[ 	]+[0-9a-f]+:[ 	]+[0-9a-f]+[ 	]+jal[ 	]+ra,[0-9a-f]+ <_start>
+[ 	]+[0-9a-f]+:[ 	]+R_RISCV_JAL[ 	]+_start
+[ 	]+[0-9a-f]+:[ 	]+[0-9a-f]+[ 	]+addi[ 	]+a1,gp,\-[0-9]+ # [0-9a-f]+ <data_g>
+[ 	]+[0-9a-f]+:[ 	]+R_RISCV_NONE[ 	]+\*ABS\*\+0x4
+[ 	]+[0-9a-f]+:[ 	]+R_RISCV_NONE[ 	]+\*ABS\*\+0x4
+[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
+[ 	]+[0-9a-f]+:[ 	]+R_RISCV_PCREL_LO12_I[ 	]+data_g\-0x[0-9a-f]+
+[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
+[ 	]+[0-9a-f]+:[ 	]+[0-9a-f]+[ 	]+addi[ 	]+a2,gp,\-[0-9]+ # [0-9a-f]+ <data_g>
+[ 	]+[0-9a-f]+:[ 	]+R_RISCV_NONE[ 	]+\*ABS\*\+0x4
+[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
+[ 	]+[0-9a-f]+:[ 	]+R_RISCV_LO12_I[ 	]+data_g\-0x[0-9a-f]+
+[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
+[ 	]+[0-9a-f]+:[ 	]+[0-9a-f]+[ 	]+addi[ 	]+a3,tp,0 # 0 <data_t>
+[ 	]+[0-9a-f]+:[ 	]+R_RISCV_NONE[ 	]+\*ABS\*\+0x4
+[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
+[ 	]+[0-9a-f]+:[ 	]+R_RISCV_NONE[ 	]+\*ABS\*\+0x4
+[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
+[ 	]+[0-9a-f]+:[ 	]+R_RISCV_TPREL_LO12_I[ 	]+data_t
+[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
+
+0+[0-9a-f]+ <.L2>:
+[ 	]+[0-9a-f]+:[ 	]+[0-9a-f]+[ 	]+auipc[ 	]+a0,0x[0-9a-f]+
+[ 	]+[0-9a-f]+:[ 	]+R_RISCV_PCREL_HI20[ 	]+data_g
+[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*