public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] [RISCV] Support subtraction of .uleb128.
@ 2019-11-27  8:12 Kuan-Lin Chen
  2019-11-27 10:36 ` Andreas Schwab
                   ` (2 more replies)
  0 siblings, 3 replies; 17+ messages in thread
From: Kuan-Lin Chen @ 2019-11-27  8:12 UTC (permalink / raw)
  To: binutils@sourceware.org Development

[-- Attachment #1: Type: text/plain, Size: 1226 bytes --]

The data length of uleb128 is variable.  So linker must recalculate the
value of the subtraction.  The patch leave relocations in object files
so that linker can relocate again after relaxation.

bfd/ChangeLog:
* bfd-in2.h: Regenerated.
* elfnn-riscv.c (write_uleb128): New function.
(perform_relocation): Perform R_RISCV_SUB_ULEB128 and
R_RISCV_SET_ULEB128 relocation.
(riscv_elf_relocate_section): Likewise.
* elfxx-riscv.c (howto_table): Add R_RISCV_SUB_ULEB128 and
R_RISCV_SET_ULEB128.
(riscv_elf_ignore_reloc): New function.
* libbfd.h: Regenerated.
* reloc.c (BFD_RELOC_RISCV_SET_ULEB128, BFD_RELOC_RISCV_SUB_ULEB128):
New relocations to support .uleb128.

gas/ChangeLog:
* config/tc-riscv.c (md_apply_fix): Add BFD_RELOC_RISCV_SET_ULEB128 and
BFD_RELOC_RISCV_SUB_ULEB128.
(riscv_insert_uleb128_fixes): New function.
(riscv_md_end): Scan rs_leb128 fragments.
(riscv_pseudo_table): Remove uleb128.

include/ChangeLog:
* elf/riscv.h ((R_RISCV_SET_ULEB128, (R_RISCV_SUB_ULEB128): Define.

ld/ChangeLog:
* testsuite/ld-riscv-elf/ld-riscv-elf.exp: Add uleb128.
* testsuite/ld-riscv-elf/uleb128.d: New test.
* testsuite/ld-riscv-elf/uleb128.s: New file.

OK to commit?
-- 
Best regards,
Kuan-Lin Chen.
kuanlinchentw@gmail.com

[-- Attachment #2: 0001-RISC-V-Support-subtraction-of-.uleb128.patch --]
[-- Type: application/octet-stream, Size: 15827 bytes --]

From 9f7f0aaa484dee2b32c550f8cca4de18959f01e1 Mon Sep 17 00:00:00 2001
From: Kuan-Lin Chen <rufus@andestech.com>
Date: Thu, 14 Nov 2019 14:24:22 +0800
Subject: [PATCH] RISC-V: Support subtraction of .uleb128.

The data length of uleb128 is variable.  So linker must recalculate the
value of the subtraction.  The patch leave relocations in object files
so that linker can relocate again after relaxation.

bfd/ChangeLog:
	* bfd-in2.h: Regenerated.
	* elfnn-riscv.c (write_uleb128): New function.
	(perform_relocation): Perform R_RISCV_SUB_ULEB128 and
	 R_RISCV_SET_ULEB128 relocation.
	(riscv_elf_relocate_section): Likewise.
	* elfxx-riscv.c (howto_table): Add R_RISCV_SUB_ULEB128 and
	R_RISCV_SET_ULEB128.
	(riscv_elf_ignore_reloc): New function.
	* libbfd.h: Regenerated.
	* reloc.c (BFD_RELOC_RISCV_SET_ULEB128, BFD_RELOC_RISCV_SUB_ULEB128):
	New relocations to support .uleb128.

gas/ChangeLog:
	* config/tc-riscv.c (md_apply_fix): Add BFD_RELOC_RISCV_SET_ULEB128 and
	BFD_RELOC_RISCV_SUB_ULEB128.
	(riscv_insert_uleb128_fixes): New function.
	(riscv_md_end): Scan rs_leb128 fragments.
	(riscv_pseudo_table): Remove uleb128.

include/ChangeLog:
	* elf/riscv.h ((R_RISCV_SET_ULEB128, (R_RISCV_SUB_ULEB128): Define.

ld/ChangeLog:
	* testsuite/ld-riscv-elf/ld-riscv-elf.exp: Add uleb128.
	* testsuite/ld-riscv-elf/uleb128.d: New test.
	* testsuite/ld-riscv-elf/uleb128.s: New file.
---
 bfd/ChangeLog                              | 14 ++++
 bfd/bfd-in2.h                              |  2 +
 bfd/elfnn-riscv.c                          | 82 ++++++++++++++++++++++
 bfd/elfxx-riscv.c                          | 51 ++++++++++++++
 bfd/libbfd.h                               |  2 +
 bfd/reloc.c                                |  4 ++
 gas/ChangeLog                              |  8 +++
 gas/config/tc-riscv.c                      | 47 ++++++++++++-
 include/ChangeLog                          |  4 ++
 include/elf/riscv.h                        |  2 +
 ld/ChangeLog                               |  6 ++
 ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp |  1 +
 ld/testsuite/ld-riscv-elf/uleb128.d        | 18 +++++
 ld/testsuite/ld-riscv-elf/uleb128.s        | 18 +++++
 14 files changed, 258 insertions(+), 1 deletion(-)
 create mode 100644 ld/testsuite/ld-riscv-elf/uleb128.d
 create mode 100644 ld/testsuite/ld-riscv-elf/uleb128.s

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 4a0852e577..d11ffde74c 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,17 @@
+2019-11-27  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
+
+	* bfd-in2.h: Regenerated.
+	* elfnn-riscv.c (write_uleb128): New function.
+	(perform_relocation): Perform R_RISCV_SUB_ULEB128 and
+	 R_RISCV_SET_ULEB128 relocation.
+	(riscv_elf_relocate_section): Likewise.
+	* elfxx-riscv.c (howto_table): Add R_RISCV_SUB_ULEB128 and
+	R_RISCV_SET_ULEB128.
+	(riscv_elf_ignore_reloc): New function.
+	* libbfd.h: Regenerated.
+	* reloc.c (BFD_RELOC_RISCV_SET_ULEB128, BFD_RELOC_RISCV_SUB_ULEB128):
+	New relocations to support .uleb128.
+
 2019-11-27  Alan Modra  <amodra@gmail.com>
 
 	PR 23652
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 44902fc8d0..a32708ebc2 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -4380,6 +4380,8 @@ number for the SBIC, SBIS, SBI and CBI instructions  */
   BFD_RELOC_RISCV_SET16,
   BFD_RELOC_RISCV_SET32,
   BFD_RELOC_RISCV_32_PCREL,
+  BFD_RELOC_RISCV_SET_ULEB128,
+  BFD_RELOC_RISCV_SUB_ULEB128,
 
 /* Renesas RL78 Relocations.  */
   BFD_RELOC_RL78_NEG8,
diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index 997f786602..075ef6b82d 100644
--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -1419,6 +1419,26 @@ riscv_global_pointer_value (struct bfd_link_info *info)
   return h->u.def.value + sec_addr (h->u.def.section);
 }
 
+/* Write VAL in uleb128 format to P, returning a pointer to the
+   following byte.
+   This code is copied from elf-attr.c.  */
+
+static bfd_byte *
+write_uleb128 (bfd_byte *p, unsigned int val)
+{
+  bfd_byte c;
+  do
+    {
+      c = val & 0x7f;
+      val >>= 7;
+      if (val)
+	c |= 0x80;
+      *(p++) = c;
+    }
+  while (val);
+  return p;
+}
+
 /* Emplace a static relocation.  */
 
 static bfd_reloc_status_type
@@ -1512,6 +1532,25 @@ perform_relocation (const reloc_howto_type *howto,
 	value = ENCODE_RVC_LUI_IMM (RISCV_CONST_HIGH_PART (value));
       break;
 
+    case R_RISCV_SET_ULEB128:
+    case R_RISCV_SUB_ULEB128:
+      {
+	unsigned int len = 0;
+	bfd_byte *endp, *p;
+
+	_bfd_read_unsigned_leb128 (input_bfd, contents + rel->r_offset, &len);
+
+	/* Clean the contents value to zero.  Do not reduce the length.  */
+	p = contents + rel->r_offset;
+	endp = p + len -1;
+	memset (p, 0x80, len);
+	*(endp) = 0;
+	p = write_uleb128 (p, value) - 1;
+	if (p < endp)
+	  *p |= 0x80;
+	return bfd_reloc_ok;
+      }
+
     case R_RISCV_32:
     case R_RISCV_64:
     case R_RISCV_ADD8:
@@ -1767,6 +1806,8 @@ riscv_elf_relocate_section (bfd *output_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;
+  bfd_vma uleb128_vma;
+  Elf_Internal_Rela *uleb128_rel = NULL;
 
   if (!riscv_init_pcrel_relocs (&pcrel_relocs))
     return FALSE;
@@ -1871,6 +1912,47 @@ riscv_elf_relocate_section (bfd *output_bfd,
 	case R_RISCV_DELETE:
 	  /* These require no special handling beyond perform_relocation.  */
 	  break;
+	case R_RISCV_SET_ULEB128:
+	  if (!uleb128_rel)
+	    {
+	      /* Save the minuend to use later.  */
+	      uleb128_vma = relocation;
+	      uleb128_rel = rel;
+	      continue;
+	    }
+	  else
+	    {
+	      if (uleb128_rel->r_offset != rel->r_offset)
+		{
+		  (*_bfd_error_handler) (_("%pB: relocation %s mismatched. "),
+					 input_bfd, howto->name);
+		  bfd_set_error (bfd_error_bad_value);
+		}
+	      relocation = relocation - uleb128_vma;
+	      uleb128_rel = NULL;
+	      break;
+	    }
+
+	case R_RISCV_SUB_ULEB128:
+	  if (uleb128_rel)
+	    {
+	      if (uleb128_rel->r_offset != rel->r_offset)
+		{
+		  (*_bfd_error_handler) (_("%pB: relocation %s mismatched. "),
+					 input_bfd, howto->name);
+		  bfd_set_error (bfd_error_bad_value);
+		}
+	      relocation = uleb128_vma - relocation;
+	      uleb128_rel = NULL;
+	      break;
+	    }
+	  else
+	    {
+	      /* Save the subtrahend to use later.  */
+	      uleb128_vma = relocation;
+	      uleb128_rel = rel;
+	      continue;
+	    }
 
 	case R_RISCV_GOT_HI20:
 	  if (h != NULL)
diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c
index 245717f70f..c136ba2207 100644
--- a/bfd/elfxx-riscv.c
+++ b/bfd/elfxx-riscv.c
@@ -38,6 +38,8 @@
    relocations for the debug info.  */
 static bfd_reloc_status_type riscv_elf_add_sub_reloc
   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
+static bfd_reloc_status_type riscv_elf_ignore_reloc
+  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
 
 /* The relocation table used for SHT_RELA sections.  */
 
@@ -855,8 +857,41 @@ static reloc_howto_type howto_table[] =
 	 0,				/* src_mask */
 	 MINUS_ONE,			/* dst_mask */
 	 FALSE),			/* pcrel_offset */
+
+  /* The length of unsigned-leb128 is variant, just assume the
+     size is one byte here.  */
+  HOWTO (R_RISCV_SET_ULEB128,		/* type */
+	 0,				/* rightshift */
+	 0,				/* size */
+	 0,				/* bitsize */
+	 FALSE,				/* pc_relative */
+	 0,				/* bitpos */
+	 complain_overflow_dont,	/* complain_on_overflow */
+	 riscv_elf_ignore_reloc,	/* special_function */
+	 "R_RISCV_SET_ULEB128",		/* name */
+	 FALSE,				/* partial_inplace */
+	 0,				/* src_mask */
+	 0,				/* dst_mask */
+	 FALSE),			/* pcrel_offset */
+
+  /* The length of unsigned-leb128 is variant, just assume the
+     size is one byte here.  */
+  HOWTO (R_RISCV_SUB_ULEB128,		/* type */
+	 0,				/* rightshift */
+	 0,				/* size */
+	 0,				/* bitsize */
+	 FALSE,				/* pc_relative */
+	 0,				/* bitpos */
+	 complain_overflow_dont,	/* complain_on_overflow */
+	 riscv_elf_ignore_reloc,	/* special_function */
+	 "R_RISCV_SUB_ULEB128",		/* name */
+	 FALSE,				/* partial_inplace */
+	 0,				/* src_mask */
+	 0,				/* dst_mask */
+	 FALSE),			/* pcrel_offset */
 };
 
+
 /* A mapping from BFD reloc types to RISC-V ELF reloc types.  */
 
 struct elf_reloc_map
@@ -917,6 +952,8 @@ static const struct elf_reloc_map riscv_reloc_map[] =
   { 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_SET_ULEB128, R_RISCV_SET_ULEB128 },
+  { BFD_RELOC_RISCV_SUB_ULEB128, R_RISCV_SUB_ULEB128 },
 };
 
 /* Given a BFD reloc type, return a howto structure.  */
@@ -1011,6 +1048,20 @@ riscv_elf_add_sub_reloc (bfd *abfd,
   return bfd_reloc_ok;
 }
 
+/* Special handler for relocations which don't have to be relocated.
+   This function just simply return bfd_reloc_ok.  */
+static bfd_reloc_status_type
+riscv_elf_ignore_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry,
+			asymbol *symbol ATTRIBUTE_UNUSED,
+			void *data ATTRIBUTE_UNUSED, asection *input_section,
+			bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED)
+{
+  if (output_bfd != NULL)
+    reloc_entry->address += input_section->output_offset;
+
+  return bfd_reloc_ok;
+}
+
 /* Parsing subset version.
 
    Return Value:
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index 77b732ee4b..7aa8f91504 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -2327,6 +2327,8 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_RISCV_SET16",
   "BFD_RELOC_RISCV_SET32",
   "BFD_RELOC_RISCV_32_PCREL",
+  "BFD_RELOC_RISCV_SET_ULEB128",
+  "BFD_RELOC_RISCV_SUB_ULEB128",
   "BFD_RELOC_RL78_NEG8",
   "BFD_RELOC_RL78_NEG16",
   "BFD_RELOC_RL78_NEG24",
diff --git a/bfd/reloc.c b/bfd/reloc.c
index b00b79f319..9b8b75ad21 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -5212,6 +5212,10 @@ ENUMX
   BFD_RELOC_RISCV_SET32
 ENUMX
   BFD_RELOC_RISCV_32_PCREL
+ENUMX
+  BFD_RELOC_RISCV_SET_ULEB128
+ENUMX
+  BFD_RELOC_RISCV_SUB_ULEB128
 ENUMDOC
   RISC-V relocations.
 
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 09991524da..e53ac0895b 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,11 @@
+2019-11-27  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
+
+	* config/tc-riscv.c (md_apply_fix): Add BFD_RELOC_RISCV_SET_ULEB128 and
+	BFD_RELOC_RISCV_SUB_ULEB128.
+	(riscv_insert_uleb128_fixes): New function.
+	(riscv_md_end): Scan rs_leb128 fragments.
+	(riscv_pseudo_table): Remove uleb128.
+
 2019-11-25  Andrew Pinski  <apinski@marvell.com>
 
 	* config/tc-aarch64.c (md_begin): Use correct
diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
index e50505138e..c35c591c0a 100644
--- a/gas/config/tc-riscv.c
+++ b/gas/config/tc-riscv.c
@@ -2392,6 +2392,9 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
     case BFD_RELOC_RISCV_SUB32:
     case BFD_RELOC_RISCV_SUB64:
     case BFD_RELOC_RISCV_RELAX:
+    /* cvt_frag_to_fill () has called output_leb128 ().  */
+    case BFD_RELOC_RISCV_SET_ULEB128:
+    case BFD_RELOC_RISCV_SUB_ULEB128:
       break;
 
     case BFD_RELOC_RISCV_TPREL_HI20:
@@ -3127,11 +3130,54 @@ riscv_set_public_attributes (void)
     riscv_write_out_arch_attr ();
 }
 
+/* Scan uleb128 subtraction expressions and insert fixups for them.
+   e.g., .uleb128 .L1 - .L0
+   Becuase relaxation may change the value of the subtraction, we
+   must resolve them in link-time.  */
+
+static void
+riscv_insert_uleb128_fixes (bfd *abfd ATTRIBUTE_UNUSED,
+			    asection *sec, void *xxx ATTRIBUTE_UNUSED)
+{
+  segment_info_type *seginfo = seg_info (sec);
+  struct frag *fragP;
+
+  subseg_set (sec, 0);
+
+  for (fragP = seginfo->frchainP->frch_root;
+       fragP; fragP = fragP->fr_next)
+    {
+      expressionS *exp, *exp_dup;
+
+      if (fragP->fr_type != rs_leb128  || fragP->fr_symbol == NULL)
+	continue;
+
+      exp = symbol_get_value_expression (fragP->fr_symbol);
+
+      if (exp->X_op != O_subtract)
+	continue;
+
+      /* Only unsigned leb128 can be handle.  */
+      gas_assert (fragP->fr_subtype == 0);
+      exp_dup = xmemdup (exp, sizeof (*exp), sizeof (*exp));
+      exp_dup->X_op = O_symbol;
+      exp_dup->X_op_symbol = NULL;
+
+      /* Insert relocations to resolve the subtraction in link-time.  */
+      fix_new_exp (fragP, fragP->fr_fix, 0,
+		   exp_dup, 0, BFD_RELOC_RISCV_SET_ULEB128);
+      exp_dup->X_add_symbol = exp->X_op_symbol;
+      fix_new_exp (fragP, fragP->fr_fix, 0,
+		   exp_dup, 0, BFD_RELOC_RISCV_SUB_ULEB128);
+    }
+}
+
 /* Called after all assembly has been done.  */
 
 void
 riscv_md_end (void)
 {
+  bfd_map_over_sections (stdoutput, riscv_insert_uleb128_fixes, NULL);
   riscv_set_public_attributes ();
 }
 
@@ -3215,7 +3261,6 @@ static const pseudo_typeS riscv_pseudo_table[] =
   {"dtprelword", s_dtprel, 4},
   {"dtpreldword", s_dtprel, 8},
   {"bss", s_bss, 0},
-  {"uleb128", s_riscv_leb128, 0},
   {"sleb128", s_riscv_leb128, 1},
   {"insn", s_riscv_insn, 0},
   {"attribute", s_riscv_attribute, 0},
diff --git a/include/ChangeLog b/include/ChangeLog
index 47bb86cf71..c290b245c6 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,3 +1,7 @@
+2019-11-27  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
+
+	* elf/riscv.h ((R_RISCV_SET_ULEB128, (R_RISCV_SUB_ULEB128): Define.
+
 2019-11-25  Alan Modra  <amodra@gmail.com>
 
 	* coff/ti.h (GET_SCNHDR_SIZE, PUT_SCNHDR_SIZE, GET_SCN_SCNLEN),
diff --git a/include/elf/riscv.h b/include/elf/riscv.h
index 2f98aa4a3e..030679b35f 100644
--- a/include/elf/riscv.h
+++ b/include/elf/riscv.h
@@ -88,6 +88,8 @@ START_RELOC_NUMBERS (elf_riscv_reloc_type)
   RELOC_NUMBER (R_RISCV_SET16, 55)
   RELOC_NUMBER (R_RISCV_SET32, 56)
   RELOC_NUMBER (R_RISCV_32_PCREL, 57)
+  RELOC_NUMBER (R_RISCV_SET_ULEB128, 58)
+  RELOC_NUMBER (R_RISCV_SUB_ULEB128, 59)
 END_RELOC_NUMBERS (R_RISCV_max)
 
 /* Processor specific flags for the ELF header e_flags field.  */
diff --git a/ld/ChangeLog b/ld/ChangeLog
index 969ab78035..5c2e406101 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,3 +1,9 @@
+2019-11-27  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
+
+	* testsuite/ld-riscv-elf/ld-riscv-elf.exp: Add uleb128.
+	* testsuite/ld-riscv-elf/uleb128.d: New test.
+	* testsuite/ld-riscv-elf/uleb128.s: New file.
+
 2019-11-26  Martin Liska  <mliska@suse.cz>
 
 	* scripttempl/arclinux.sc: Add .text.sorted.* which is sorted
diff --git a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
index 7aabbdd641..809e40f08d 100644
--- a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
+++ b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
@@ -38,6 +38,7 @@ if [istarget "riscv*-*-*"] {
     run_dump_test "attr-merge-priv-spec"
     run_dump_test "attr-merge-arch-failed-01"
     run_dump_test "attr-merge-stack-align-failed"
+    run_dump_test "uleb128"
     run_ld_link_tests {
 	{ "Weak reference 32" "-T weakref.ld -melf32lriscv" ""
 	    "-march=rv32i -mabi=ilp32" {weakref32.s}
diff --git a/ld/testsuite/ld-riscv-elf/uleb128.d b/ld/testsuite/ld-riscv-elf/uleb128.d
new file mode 100644
index 0000000000..a921478e98
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/uleb128.d
@@ -0,0 +1,18 @@
+#source: uleb128.s
+#as: -march=rv32ic
+#ld: -melf32lriscv
+#objdump: -d
+
+.*:[ 	]+file format .*
+
+Disassembly of section .text:
+
+.* <_start>:
+.*jal.*<bar>
+.*jal.*<bar>
+.*jal.*<bar>
+.*jal.*<bar>
+.*jal.*<bar>
+.*jal.*<bar>
+.*:[ 	]+0e0c.*
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/uleb128.s b/ld/testsuite/ld-riscv-elf/uleb128.s
new file mode 100644
index 0000000000..f7d23be163
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/uleb128.s
@@ -0,0 +1,18 @@
+.text
+.globl bar
+.globl _start
+.option rvc
+.align 2
+_start:
+.L0:
+        .rept 6
+        call bar
+        .endr
+.align 2
+.L1:
+        .uleb128 .L1 - .L0
+        .uleb128 .L2 - .L0
+.L2:
+.align 2
+bar:
+        nop
-- 
2.17.0


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] [RISCV] Support subtraction of .uleb128.
  2019-11-27  8:12 [PATCH] [RISCV] Support subtraction of .uleb128 Kuan-Lin Chen
@ 2019-11-27 10:36 ` Andreas Schwab
  2019-12-02  1:18   ` Kuan-Lin Chen
  2019-12-02 22:27 ` Jim Wilson
  2019-12-06 23:48 ` Palmer Dabbelt via binutils
  2 siblings, 1 reply; 17+ messages in thread
From: Andreas Schwab @ 2019-11-27 10:36 UTC (permalink / raw)
  To: Kuan-Lin Chen; +Cc: binutils@sourceware.org Development

On Nov 27 2019, Kuan-Lin Chen wrote:

> diff --git a/include/ChangeLog b/include/ChangeLog
> index 47bb86cf71..c290b245c6 100644
> --- a/include/ChangeLog
> +++ b/include/ChangeLog
> @@ -1,3 +1,7 @@
> +2019-11-27  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
> +
> +	* elf/riscv.h ((R_RISCV_SET_ULEB128, (R_RISCV_SUB_ULEB128): Define.

There are too many open parens here.

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510  2552 DF73 E780 A9DA AEC1
"And now for something completely different."

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] [RISCV] Support subtraction of .uleb128.
  2019-11-27 10:36 ` Andreas Schwab
@ 2019-12-02  1:18   ` Kuan-Lin Chen
  0 siblings, 0 replies; 17+ messages in thread
From: Kuan-Lin Chen @ 2019-12-02  1:18 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: binutils@sourceware.org Development

[-- Attachment #1: Type: text/plain, Size: 805 bytes --]

Fixed in the patch.
Thanks.

OK to commit?

Andreas Schwab <schwab@linux-m68k.org> 於 2019年11月27日 週三 下午6:36寫道:
>
> On Nov 27 2019, Kuan-Lin Chen wrote:
>
> > diff --git a/include/ChangeLog b/include/ChangeLog
> > index 47bb86cf71..c290b245c6 100644
> > --- a/include/ChangeLog
> > +++ b/include/ChangeLog
> > @@ -1,3 +1,7 @@
> > +2019-11-27  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
> > +
> > +     * elf/riscv.h ((R_RISCV_SET_ULEB128, (R_RISCV_SUB_ULEB128): Define.
>
> There are too many open parens here.
>
> Andreas.
>
> --
> Andreas Schwab, schwab@linux-m68k.org
> GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510  2552 DF73 E780 A9DA AEC1
> "And now for something completely different."



-- 
Best regards,
Kuan-Lin Chen.
kuanlinchentw@gmail.com

[-- Attachment #2: 0001-RISC-V-Support-subtraction-of-.uleb128.patch --]
[-- Type: application/octet-stream, Size: 15823 bytes --]

From 9f7f0aaa484dee2b32c550f8cca4de18959f01e1 Mon Sep 17 00:00:00 2001
From: Kuan-Lin Chen <rufus@andestech.com>
Date: Thu, 14 Nov 2019 14:24:22 +0800
Subject: [PATCH] RISC-V: Support subtraction of .uleb128.

The data length of uleb128 is variable.  So linker must recalculate the
value of the subtraction.  The patch leave relocations in object files
so that linker can relocate again after relaxation.

bfd/ChangeLog:
	* bfd-in2.h: Regenerated.
	* elfnn-riscv.c (write_uleb128): New function.
	(perform_relocation): Perform R_RISCV_SUB_ULEB128 and
	 R_RISCV_SET_ULEB128 relocation.
	(riscv_elf_relocate_section): Likewise.
	* elfxx-riscv.c (howto_table): Add R_RISCV_SUB_ULEB128 and
	R_RISCV_SET_ULEB128.
	(riscv_elf_ignore_reloc): New function.
	* libbfd.h: Regenerated.
	* reloc.c (BFD_RELOC_RISCV_SET_ULEB128, BFD_RELOC_RISCV_SUB_ULEB128):
	New relocations to support .uleb128.

gas/ChangeLog:
	* config/tc-riscv.c (md_apply_fix): Add BFD_RELOC_RISCV_SET_ULEB128 and
	BFD_RELOC_RISCV_SUB_ULEB128.
	(riscv_insert_uleb128_fixes): New function.
	(riscv_md_end): Scan rs_leb128 fragments.
	(riscv_pseudo_table): Remove uleb128.

include/ChangeLog:
	* elf/riscv.h (R_RISCV_SET_ULEB128, R_RISCV_SUB_ULEB128): Define.

ld/ChangeLog:
	* testsuite/ld-riscv-elf/ld-riscv-elf.exp: Add uleb128.
	* testsuite/ld-riscv-elf/uleb128.d: New test.
	* testsuite/ld-riscv-elf/uleb128.s: New file.
---
 bfd/ChangeLog                              | 14 ++++
 bfd/bfd-in2.h                              |  2 +
 bfd/elfnn-riscv.c                          | 82 ++++++++++++++++++++++
 bfd/elfxx-riscv.c                          | 51 ++++++++++++++
 bfd/libbfd.h                               |  2 +
 bfd/reloc.c                                |  4 ++
 gas/ChangeLog                              |  8 +++
 gas/config/tc-riscv.c                      | 47 ++++++++++++-
 include/ChangeLog                          |  4 ++
 include/elf/riscv.h                        |  2 +
 ld/ChangeLog                               |  6 ++
 ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp |  1 +
 ld/testsuite/ld-riscv-elf/uleb128.d        | 18 +++++
 ld/testsuite/ld-riscv-elf/uleb128.s        | 18 +++++
 14 files changed, 258 insertions(+), 1 deletion(-)
 create mode 100644 ld/testsuite/ld-riscv-elf/uleb128.d
 create mode 100644 ld/testsuite/ld-riscv-elf/uleb128.s

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 4a0852e577..d11ffde74c 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,17 @@
+2019-11-27  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
+
+	* bfd-in2.h: Regenerated.
+	* elfnn-riscv.c (write_uleb128): New function.
+	(perform_relocation): Perform R_RISCV_SUB_ULEB128 and
+	 R_RISCV_SET_ULEB128 relocation.
+	(riscv_elf_relocate_section): Likewise.
+	* elfxx-riscv.c (howto_table): Add R_RISCV_SUB_ULEB128 and
+	R_RISCV_SET_ULEB128.
+	(riscv_elf_ignore_reloc): New function.
+	* libbfd.h: Regenerated.
+	* reloc.c (BFD_RELOC_RISCV_SET_ULEB128, BFD_RELOC_RISCV_SUB_ULEB128):
+	New relocations to support .uleb128.
+
 2019-11-27  Alan Modra  <amodra@gmail.com>
 
 	PR 23652
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 44902fc8d0..a32708ebc2 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -4380,6 +4380,8 @@ number for the SBIC, SBIS, SBI and CBI instructions  */
   BFD_RELOC_RISCV_SET16,
   BFD_RELOC_RISCV_SET32,
   BFD_RELOC_RISCV_32_PCREL,
+  BFD_RELOC_RISCV_SET_ULEB128,
+  BFD_RELOC_RISCV_SUB_ULEB128,
 
 /* Renesas RL78 Relocations.  */
   BFD_RELOC_RL78_NEG8,
diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index 997f786602..075ef6b82d 100644
--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -1419,6 +1419,26 @@ riscv_global_pointer_value (struct bfd_link_info *info)
   return h->u.def.value + sec_addr (h->u.def.section);
 }
 
+/* Write VAL in uleb128 format to P, returning a pointer to the
+   following byte.
+   This code is copied from elf-attr.c.  */
+
+static bfd_byte *
+write_uleb128 (bfd_byte *p, unsigned int val)
+{
+  bfd_byte c;
+  do
+    {
+      c = val & 0x7f;
+      val >>= 7;
+      if (val)
+	c |= 0x80;
+      *(p++) = c;
+    }
+  while (val);
+  return p;
+}
+
 /* Emplace a static relocation.  */
 
 static bfd_reloc_status_type
@@ -1512,6 +1532,25 @@ perform_relocation (const reloc_howto_type *howto,
 	value = ENCODE_RVC_LUI_IMM (RISCV_CONST_HIGH_PART (value));
       break;
 
+    case R_RISCV_SET_ULEB128:
+    case R_RISCV_SUB_ULEB128:
+      {
+	unsigned int len = 0;
+	bfd_byte *endp, *p;
+
+	_bfd_read_unsigned_leb128 (input_bfd, contents + rel->r_offset, &len);
+
+	/* Clean the contents value to zero.  Do not reduce the length.  */
+	p = contents + rel->r_offset;
+	endp = p + len -1;
+	memset (p, 0x80, len);
+	*(endp) = 0;
+	p = write_uleb128 (p, value) - 1;
+	if (p < endp)
+	  *p |= 0x80;
+	return bfd_reloc_ok;
+      }
+
     case R_RISCV_32:
     case R_RISCV_64:
     case R_RISCV_ADD8:
@@ -1767,6 +1806,8 @@ riscv_elf_relocate_section (bfd *output_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;
+  bfd_vma uleb128_vma;
+  Elf_Internal_Rela *uleb128_rel = NULL;
 
   if (!riscv_init_pcrel_relocs (&pcrel_relocs))
     return FALSE;
@@ -1871,6 +1912,47 @@ riscv_elf_relocate_section (bfd *output_bfd,
 	case R_RISCV_DELETE:
 	  /* These require no special handling beyond perform_relocation.  */
 	  break;
+	case R_RISCV_SET_ULEB128:
+	  if (!uleb128_rel)
+	    {
+	      /* Save the minuend to use later.  */
+	      uleb128_vma = relocation;
+	      uleb128_rel = rel;
+	      continue;
+	    }
+	  else
+	    {
+	      if (uleb128_rel->r_offset != rel->r_offset)
+		{
+		  (*_bfd_error_handler) (_("%pB: relocation %s mismatched. "),
+					 input_bfd, howto->name);
+		  bfd_set_error (bfd_error_bad_value);
+		}
+	      relocation = relocation - uleb128_vma;
+	      uleb128_rel = NULL;
+	      break;
+	    }
+
+	case R_RISCV_SUB_ULEB128:
+	  if (uleb128_rel)
+	    {
+	      if (uleb128_rel->r_offset != rel->r_offset)
+		{
+		  (*_bfd_error_handler) (_("%pB: relocation %s mismatched. "),
+					 input_bfd, howto->name);
+		  bfd_set_error (bfd_error_bad_value);
+		}
+	      relocation = uleb128_vma - relocation;
+	      uleb128_rel = NULL;
+	      break;
+	    }
+	  else
+	    {
+	      /* Save the subtrahend to use later.  */
+	      uleb128_vma = relocation;
+	      uleb128_rel = rel;
+	      continue;
+	    }
 
 	case R_RISCV_GOT_HI20:
 	  if (h != NULL)
diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c
index 245717f70f..c136ba2207 100644
--- a/bfd/elfxx-riscv.c
+++ b/bfd/elfxx-riscv.c
@@ -38,6 +38,8 @@
    relocations for the debug info.  */
 static bfd_reloc_status_type riscv_elf_add_sub_reloc
   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
+static bfd_reloc_status_type riscv_elf_ignore_reloc
+  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
 
 /* The relocation table used for SHT_RELA sections.  */
 
@@ -855,8 +857,41 @@ static reloc_howto_type howto_table[] =
 	 0,				/* src_mask */
 	 MINUS_ONE,			/* dst_mask */
 	 FALSE),			/* pcrel_offset */
+
+  /* The length of unsigned-leb128 is variant, just assume the
+     size is one byte here.  */
+  HOWTO (R_RISCV_SET_ULEB128,		/* type */
+	 0,				/* rightshift */
+	 0,				/* size */
+	 0,				/* bitsize */
+	 FALSE,				/* pc_relative */
+	 0,				/* bitpos */
+	 complain_overflow_dont,	/* complain_on_overflow */
+	 riscv_elf_ignore_reloc,	/* special_function */
+	 "R_RISCV_SET_ULEB128",		/* name */
+	 FALSE,				/* partial_inplace */
+	 0,				/* src_mask */
+	 0,				/* dst_mask */
+	 FALSE),			/* pcrel_offset */
+
+  /* The length of unsigned-leb128 is variant, just assume the
+     size is one byte here.  */
+  HOWTO (R_RISCV_SUB_ULEB128,		/* type */
+	 0,				/* rightshift */
+	 0,				/* size */
+	 0,				/* bitsize */
+	 FALSE,				/* pc_relative */
+	 0,				/* bitpos */
+	 complain_overflow_dont,	/* complain_on_overflow */
+	 riscv_elf_ignore_reloc,	/* special_function */
+	 "R_RISCV_SUB_ULEB128",		/* name */
+	 FALSE,				/* partial_inplace */
+	 0,				/* src_mask */
+	 0,				/* dst_mask */
+	 FALSE),			/* pcrel_offset */
 };
 
+
 /* A mapping from BFD reloc types to RISC-V ELF reloc types.  */
 
 struct elf_reloc_map
@@ -917,6 +952,8 @@ static const struct elf_reloc_map riscv_reloc_map[] =
   { 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_SET_ULEB128, R_RISCV_SET_ULEB128 },
+  { BFD_RELOC_RISCV_SUB_ULEB128, R_RISCV_SUB_ULEB128 },
 };
 
 /* Given a BFD reloc type, return a howto structure.  */
@@ -1011,6 +1048,20 @@ riscv_elf_add_sub_reloc (bfd *abfd,
   return bfd_reloc_ok;
 }
 
+/* Special handler for relocations which don't have to be relocated.
+   This function just simply return bfd_reloc_ok.  */
+static bfd_reloc_status_type
+riscv_elf_ignore_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry,
+			asymbol *symbol ATTRIBUTE_UNUSED,
+			void *data ATTRIBUTE_UNUSED, asection *input_section,
+			bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED)
+{
+  if (output_bfd != NULL)
+    reloc_entry->address += input_section->output_offset;
+
+  return bfd_reloc_ok;
+}
+
 /* Parsing subset version.
 
    Return Value:
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index 77b732ee4b..7aa8f91504 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -2327,6 +2327,8 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_RISCV_SET16",
   "BFD_RELOC_RISCV_SET32",
   "BFD_RELOC_RISCV_32_PCREL",
+  "BFD_RELOC_RISCV_SET_ULEB128",
+  "BFD_RELOC_RISCV_SUB_ULEB128",
   "BFD_RELOC_RL78_NEG8",
   "BFD_RELOC_RL78_NEG16",
   "BFD_RELOC_RL78_NEG24",
diff --git a/bfd/reloc.c b/bfd/reloc.c
index b00b79f319..9b8b75ad21 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -5212,6 +5212,10 @@ ENUMX
   BFD_RELOC_RISCV_SET32
 ENUMX
   BFD_RELOC_RISCV_32_PCREL
+ENUMX
+  BFD_RELOC_RISCV_SET_ULEB128
+ENUMX
+  BFD_RELOC_RISCV_SUB_ULEB128
 ENUMDOC
   RISC-V relocations.
 
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 09991524da..e53ac0895b 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,11 @@
+2019-11-27  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
+
+	* config/tc-riscv.c (md_apply_fix): Add BFD_RELOC_RISCV_SET_ULEB128 and
+	BFD_RELOC_RISCV_SUB_ULEB128.
+	(riscv_insert_uleb128_fixes): New function.
+	(riscv_md_end): Scan rs_leb128 fragments.
+	(riscv_pseudo_table): Remove uleb128.
+
 2019-11-25  Andrew Pinski  <apinski@marvell.com>
 
 	* config/tc-aarch64.c (md_begin): Use correct
diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
index e50505138e..c35c591c0a 100644
--- a/gas/config/tc-riscv.c
+++ b/gas/config/tc-riscv.c
@@ -2392,6 +2392,9 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
     case BFD_RELOC_RISCV_SUB32:
     case BFD_RELOC_RISCV_SUB64:
     case BFD_RELOC_RISCV_RELAX:
+    /* cvt_frag_to_fill () has called output_leb128 ().  */
+    case BFD_RELOC_RISCV_SET_ULEB128:
+    case BFD_RELOC_RISCV_SUB_ULEB128:
       break;
 
     case BFD_RELOC_RISCV_TPREL_HI20:
@@ -3127,11 +3130,54 @@ riscv_set_public_attributes (void)
     riscv_write_out_arch_attr ();
 }
 
+/* Scan uleb128 subtraction expressions and insert fixups for them.
+   e.g., .uleb128 .L1 - .L0
+   Becuase relaxation may change the value of the subtraction, we
+   must resolve them in link-time.  */
+
+static void
+riscv_insert_uleb128_fixes (bfd *abfd ATTRIBUTE_UNUSED,
+			    asection *sec, void *xxx ATTRIBUTE_UNUSED)
+{
+  segment_info_type *seginfo = seg_info (sec);
+  struct frag *fragP;
+
+  subseg_set (sec, 0);
+
+  for (fragP = seginfo->frchainP->frch_root;
+       fragP; fragP = fragP->fr_next)
+    {
+      expressionS *exp, *exp_dup;
+
+      if (fragP->fr_type != rs_leb128  || fragP->fr_symbol == NULL)
+	continue;
+
+      exp = symbol_get_value_expression (fragP->fr_symbol);
+
+      if (exp->X_op != O_subtract)
+	continue;
+
+      /* Only unsigned leb128 can be handle.  */
+      gas_assert (fragP->fr_subtype == 0);
+      exp_dup = xmemdup (exp, sizeof (*exp), sizeof (*exp));
+      exp_dup->X_op = O_symbol;
+      exp_dup->X_op_symbol = NULL;
+
+      /* Insert relocations to resolve the subtraction in link-time.  */
+      fix_new_exp (fragP, fragP->fr_fix, 0,
+		   exp_dup, 0, BFD_RELOC_RISCV_SET_ULEB128);
+      exp_dup->X_add_symbol = exp->X_op_symbol;
+      fix_new_exp (fragP, fragP->fr_fix, 0,
+		   exp_dup, 0, BFD_RELOC_RISCV_SUB_ULEB128);
+    }
+}
+
 /* Called after all assembly has been done.  */
 
 void
 riscv_md_end (void)
 {
+  bfd_map_over_sections (stdoutput, riscv_insert_uleb128_fixes, NULL);
   riscv_set_public_attributes ();
 }
 
@@ -3215,7 +3261,6 @@ static const pseudo_typeS riscv_pseudo_table[] =
   {"dtprelword", s_dtprel, 4},
   {"dtpreldword", s_dtprel, 8},
   {"bss", s_bss, 0},
-  {"uleb128", s_riscv_leb128, 0},
   {"sleb128", s_riscv_leb128, 1},
   {"insn", s_riscv_insn, 0},
   {"attribute", s_riscv_attribute, 0},
diff --git a/include/ChangeLog b/include/ChangeLog
index 47bb86cf71..c290b245c6 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,3 +1,7 @@
+2019-11-27  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
+
+	* elf/riscv.h (R_RISCV_SET_ULEB128, R_RISCV_SUB_ULEB128): Define.
+
 2019-11-25  Alan Modra  <amodra@gmail.com>
 
 	* coff/ti.h (GET_SCNHDR_SIZE, PUT_SCNHDR_SIZE, GET_SCN_SCNLEN),
diff --git a/include/elf/riscv.h b/include/elf/riscv.h
index 2f98aa4a3e..030679b35f 100644
--- a/include/elf/riscv.h
+++ b/include/elf/riscv.h
@@ -88,6 +88,8 @@ START_RELOC_NUMBERS (elf_riscv_reloc_type)
   RELOC_NUMBER (R_RISCV_SET16, 55)
   RELOC_NUMBER (R_RISCV_SET32, 56)
   RELOC_NUMBER (R_RISCV_32_PCREL, 57)
+  RELOC_NUMBER (R_RISCV_SET_ULEB128, 58)
+  RELOC_NUMBER (R_RISCV_SUB_ULEB128, 59)
 END_RELOC_NUMBERS (R_RISCV_max)
 
 /* Processor specific flags for the ELF header e_flags field.  */
diff --git a/ld/ChangeLog b/ld/ChangeLog
index 969ab78035..5c2e406101 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,3 +1,9 @@
+2019-11-27  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
+
+	* testsuite/ld-riscv-elf/ld-riscv-elf.exp: Add uleb128.
+	* testsuite/ld-riscv-elf/uleb128.d: New test.
+	* testsuite/ld-riscv-elf/uleb128.s: New file.
+
 2019-11-26  Martin Liska  <mliska@suse.cz>
 
 	* scripttempl/arclinux.sc: Add .text.sorted.* which is sorted
diff --git a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
index 7aabbdd641..809e40f08d 100644
--- a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
+++ b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
@@ -38,6 +38,7 @@ if [istarget "riscv*-*-*"] {
     run_dump_test "attr-merge-priv-spec"
     run_dump_test "attr-merge-arch-failed-01"
     run_dump_test "attr-merge-stack-align-failed"
+    run_dump_test "uleb128"
     run_ld_link_tests {
 	{ "Weak reference 32" "-T weakref.ld -melf32lriscv" ""
 	    "-march=rv32i -mabi=ilp32" {weakref32.s}
diff --git a/ld/testsuite/ld-riscv-elf/uleb128.d b/ld/testsuite/ld-riscv-elf/uleb128.d
new file mode 100644
index 0000000000..a921478e98
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/uleb128.d
@@ -0,0 +1,18 @@
+#source: uleb128.s
+#as: -march=rv32ic
+#ld: -melf32lriscv
+#objdump: -d
+
+.*:[ 	]+file format .*
+
+Disassembly of section .text:
+
+.* <_start>:
+.*jal.*<bar>
+.*jal.*<bar>
+.*jal.*<bar>
+.*jal.*<bar>
+.*jal.*<bar>
+.*jal.*<bar>
+.*:[ 	]+0e0c.*
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/uleb128.s b/ld/testsuite/ld-riscv-elf/uleb128.s
new file mode 100644
index 0000000000..f7d23be163
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/uleb128.s
@@ -0,0 +1,18 @@
+.text
+.globl bar
+.globl _start
+.option rvc
+.align 2
+_start:
+.L0:
+        .rept 6
+        call bar
+        .endr
+.align 2
+.L1:
+        .uleb128 .L1 - .L0
+        .uleb128 .L2 - .L0
+.L2:
+.align 2
+bar:
+        nop
-- 
2.17.0


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] [RISCV] Support subtraction of .uleb128.
  2019-11-27  8:12 [PATCH] [RISCV] Support subtraction of .uleb128 Kuan-Lin Chen
  2019-11-27 10:36 ` Andreas Schwab
@ 2019-12-02 22:27 ` Jim Wilson
  2019-12-06 23:48 ` Palmer Dabbelt via binutils
  2 siblings, 0 replies; 17+ messages in thread
From: Jim Wilson @ 2019-12-02 22:27 UTC (permalink / raw)
  To: Kuan-Lin Chen, binutils@sourceware.org Development

On 11/27/19 12:11 AM, Kuan-Lin Chen wrote:
> The data length of uleb128 is variable.  So linker must recalculate the
> value of the subtraction.  The patch leave relocations in object files
> so that linker can relocate again after relaxation.

I think we should have some agreement on the psABI change before we 
accept binutils patches.  We should give the LLVM/lld folks a chance to 
comment.  I see you did file a psABI pull request, and that there is no 
discussion on that yet.
https://github.com/riscv/riscv-elf-psabi-doc/pull/124

I haven't reviewed the patch yet.  I took a week off, and am now trying 
to catch up on the backlog.

Jim

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] [RISCV] Support subtraction of .uleb128.
  2019-11-27  8:12 [PATCH] [RISCV] Support subtraction of .uleb128 Kuan-Lin Chen
  2019-11-27 10:36 ` Andreas Schwab
  2019-12-02 22:27 ` Jim Wilson
@ 2019-12-06 23:48 ` Palmer Dabbelt via binutils
  2019-12-10  5:43   ` Kuan-Lin Chen
  2020-01-09 23:20   ` Palmer Dabbelt via binutils
  2 siblings, 2 replies; 17+ messages in thread
From: Palmer Dabbelt via binutils @ 2019-12-06 23:48 UTC (permalink / raw)
  To: kuanlinchentw; +Cc: binutils

On Wed, 27 Nov 2019 00:11:50 PST (-0800), kuanlinchentw@gmail.com wrote:
> The data length of uleb128 is variable.  So linker must recalculate the
> value of the subtraction.  The patch leave relocations in object files
> so that linker can relocate again after relaxation.
>
> bfd/ChangeLog:
> * bfd-in2.h: Regenerated.
> * elfnn-riscv.c (write_uleb128): New function.
> (perform_relocation): Perform R_RISCV_SUB_ULEB128 and
> R_RISCV_SET_ULEB128 relocation.
> (riscv_elf_relocate_section): Likewise.
> * elfxx-riscv.c (howto_table): Add R_RISCV_SUB_ULEB128 and
> R_RISCV_SET_ULEB128.
> (riscv_elf_ignore_reloc): New function.
> * libbfd.h: Regenerated.
> * reloc.c (BFD_RELOC_RISCV_SET_ULEB128, BFD_RELOC_RISCV_SUB_ULEB128):
> New relocations to support .uleb128.
>
> gas/ChangeLog:
> * config/tc-riscv.c (md_apply_fix): Add BFD_RELOC_RISCV_SET_ULEB128 and
> BFD_RELOC_RISCV_SUB_ULEB128.
> (riscv_insert_uleb128_fixes): New function.
> (riscv_md_end): Scan rs_leb128 fragments.
> (riscv_pseudo_table): Remove uleb128.
>
> include/ChangeLog:
> * elf/riscv.h ((R_RISCV_SET_ULEB128, (R_RISCV_SUB_ULEB128): Define.
>
> ld/ChangeLog:
> * testsuite/ld-riscv-elf/ld-riscv-elf.exp: Add uleb128.
> * testsuite/ld-riscv-elf/uleb128.d: New test.
> * testsuite/ld-riscv-elf/uleb128.s: New file.
>
> OK to commit?

I'm having a lot of trouble trying to figure out how this works.  LMK if I'm
missing something, there's some comments in line:

> From 9f7f0aaa484dee2b32c550f8cca4de18959f01e1 Mon Sep 17 00:00:00 2001
> From: Kuan-Lin Chen <rufus@andestech.com>
> Date: Thu, 14 Nov 2019 14:24:22 +0800
> Subject: [PATCH] RISC-V: Support subtraction of .uleb128.
> 
> The data length of uleb128 is variable.  So linker must recalculate the
> value of the subtraction.  The patch leave relocations in object files
> so that linker can relocate again after relaxation.
> 
> bfd/ChangeLog:
>         * bfd-in2.h: Regenerated.
>         * elfnn-riscv.c (write_uleb128): New function.
>         (perform_relocation): Perform R_RISCV_SUB_ULEB128 and
>          R_RISCV_SET_ULEB128 relocation.
>         (riscv_elf_relocate_section): Likewise.
>         * elfxx-riscv.c (howto_table): Add R_RISCV_SUB_ULEB128 and
>         R_RISCV_SET_ULEB128.
>         (riscv_elf_ignore_reloc): New function.
>         * libbfd.h: Regenerated.
>         * reloc.c (BFD_RELOC_RISCV_SET_ULEB128, BFD_RELOC_RISCV_SUB_ULEB128):
>         New relocations to support .uleb128.
> 
> gas/ChangeLog:
>         * config/tc-riscv.c (md_apply_fix): Add BFD_RELOC_RISCV_SET_ULEB128 and
>         BFD_RELOC_RISCV_SUB_ULEB128.
>         (riscv_insert_uleb128_fixes): New function.
>         (riscv_md_end): Scan rs_leb128 fragments.
>         (riscv_pseudo_table): Remove uleb128.
> 
> include/ChangeLog:
>         * elf/riscv.h ((R_RISCV_SET_ULEB128, (R_RISCV_SUB_ULEB128): Define.
> 
> ld/ChangeLog:
>         * testsuite/ld-riscv-elf/ld-riscv-elf.exp: Add uleb128.
>         * testsuite/ld-riscv-elf/uleb128.d: New test.
>         * testsuite/ld-riscv-elf/uleb128.s: New file.
> ---
>  bfd/ChangeLog                              | 14 ++++
>  bfd/bfd-in2.h                              |  2 +
>  bfd/elfnn-riscv.c                          | 82 ++++++++++++++++++++++
>  bfd/elfxx-riscv.c                          | 51 ++++++++++++++
>  bfd/libbfd.h                               |  2 +
>  bfd/reloc.c                                |  4 ++
>  gas/ChangeLog                              |  8 +++
>  gas/config/tc-riscv.c                      | 47 ++++++++++++-
>  include/ChangeLog                          |  4 ++
>  include/elf/riscv.h                        |  2 +
>  ld/ChangeLog                               |  6 ++
>  ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp |  1 +
>  ld/testsuite/ld-riscv-elf/uleb128.d        | 18 +++++
>  ld/testsuite/ld-riscv-elf/uleb128.s        | 18 +++++
>  14 files changed, 258 insertions(+), 1 deletion(-)
>  create mode 100644 ld/testsuite/ld-riscv-elf/uleb128.d
>  create mode 100644 ld/testsuite/ld-riscv-elf/uleb128.s
> 
> diff --git a/bfd/ChangeLog b/bfd/ChangeLog
> index 4a0852e577..d11ffde74c 100644
> --- a/bfd/ChangeLog
> +++ b/bfd/ChangeLog
> @@ -1,3 +1,17 @@
> +2019-11-27  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
> +
> +        * bfd-in2.h: Regenerated.
> +        * elfnn-riscv.c (write_uleb128): New function.
> +        (perform_relocation): Perform R_RISCV_SUB_ULEB128 and
> +         R_RISCV_SET_ULEB128 relocation.
> +        (riscv_elf_relocate_section): Likewise.
> +        * elfxx-riscv.c (howto_table): Add R_RISCV_SUB_ULEB128 and
> +        R_RISCV_SET_ULEB128.
> +        (riscv_elf_ignore_reloc): New function.
> +        * libbfd.h: Regenerated.
> +        * reloc.c (BFD_RELOC_RISCV_SET_ULEB128, BFD_RELOC_RISCV_SUB_ULEB128):
> +        New relocations to support .uleb128.
> +
>  2019-11-27  Alan Modra  <amodra@gmail.com>
>  
>          PR 23652
> diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
> index 44902fc8d0..a32708ebc2 100644
> --- a/bfd/bfd-in2.h
> +++ b/bfd/bfd-in2.h
> @@ -4380,6 +4380,8 @@ number for the SBIC, SBIS, SBI and CBI instructions  */
>    BFD_RELOC_RISCV_SET16,
>    BFD_RELOC_RISCV_SET32,
>    BFD_RELOC_RISCV_32_PCREL,
> +  BFD_RELOC_RISCV_SET_ULEB128,
> +  BFD_RELOC_RISCV_SUB_ULEB128,
>  
>  /* Renesas RL78 Relocations.  */
>    BFD_RELOC_RL78_NEG8,
> diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
> index 997f786602..075ef6b82d 100644
> --- a/bfd/elfnn-riscv.c
> +++ b/bfd/elfnn-riscv.c
> @@ -1419,6 +1419,26 @@ riscv_global_pointer_value (struct bfd_link_info *info)
>    return h->u.def.value + sec_addr (h->u.def.section);
>  }
>  
> +/* Write VAL in uleb128 format to P, returning a pointer to the
> +   following byte.
> +   This code is copied from elf-attr.c.  */
> +
> +static bfd_byte *
> +write_uleb128 (bfd_byte *p, unsigned int val)
> +{
> +  bfd_byte c;
> +  do
> +    {
> +      c = val & 0x7f;
> +      val >>= 7;
> +      if (val)
> +        c |= 0x80;
> +      *(p++) = c;
> +    }
> +  while (val);
> +  return p;
> +}
> +
>  /* Emplace a static relocation.  */
>  
>  static bfd_reloc_status_type
> @@ -1512,6 +1532,25 @@ perform_relocation (const reloc_howto_type *howto,
>          value = ENCODE_RVC_LUI_IMM (RISCV_CONST_HIGH_PART (value));
>        break;
>  
> +    case R_RISCV_SET_ULEB128:
> +    case R_RISCV_SUB_ULEB128:
> +      {
> +        unsigned int len = 0;
> +        bfd_byte *endp, *p;
> +
> +        _bfd_read_unsigned_leb128 (input_bfd, contents + rel->r_offset, &len);
> +
> +        /* Clean the contents value to zero.  Do not reduce the length.  */
> +        p = contents + rel->r_offset;
> +        endp = p + len -1;
> +        memset (p, 0x80, len);
> +        *(endp) = 0;
> +        p = write_uleb128 (p, value) - 1;
> +        if (p < endp)
> +          *p |= 0x80;
> +        return bfd_reloc_ok;
> +      }
> +
>      case R_RISCV_32:
>      case R_RISCV_64:
>      case R_RISCV_ADD8:
> @@ -1767,6 +1806,8 @@ riscv_elf_relocate_section (bfd *output_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;
> +  bfd_vma uleb128_vma;
> +  Elf_Internal_Rela *uleb128_rel = NULL;
>  
>    if (!riscv_init_pcrel_relocs (&pcrel_relocs))
>      return FALSE;
> @@ -1871,6 +1912,47 @@ riscv_elf_relocate_section (bfd *output_bfd,
>          case R_RISCV_DELETE:
>            /* These require no special handling beyond perform_relocation.  */
>            break;
> +        case R_RISCV_SET_ULEB128:
> +          if (!uleb128_rel)
> +            {
> +              /* Save the minuend to use later.  */
> +              uleb128_vma = relocation;
> +              uleb128_rel = rel;
> +              continue;
> +            }
> +          else
> +            {
> +              if (uleb128_rel->r_offset != rel->r_offset)
> +                {
> +                  (*_bfd_error_handler) (_("%pB: relocation %s mismatched. "),
> +                                         input_bfd, howto->name);
> +                  bfd_set_error (bfd_error_bad_value);
> +                }
> +              relocation = relocation - uleb128_vma;
> +              uleb128_rel = NULL;
> +              break;
> +            }
> +
> +        case R_RISCV_SUB_ULEB128:
> +          if (uleb128_rel)
> +            {
> +              if (uleb128_rel->r_offset != rel->r_offset)
> +                {
> +                  (*_bfd_error_handler) (_("%pB: relocation %s mismatched. "),
> +                                         input_bfd, howto->name);
> +                  bfd_set_error (bfd_error_bad_value);
> +                }
> +              relocation = uleb128_vma - relocation;

GCC gives me -Wmaybe-uninitialized for both of these.

> +              uleb128_rel = NULL;
> +              break;
> +            }
> +          else
> +            {
> +              /* Save the subtrahend to use later.  */
> +              uleb128_vma = relocation;
> +              uleb128_rel = rel;
> +              continue;
> +            }
>  
>          case R_RISCV_GOT_HI20:
>            if (h != NULL)
> diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c
> index 245717f70f..c136ba2207 100644
> --- a/bfd/elfxx-riscv.c
> +++ b/bfd/elfxx-riscv.c
> @@ -38,6 +38,8 @@
>     relocations for the debug info.  */
>  static bfd_reloc_status_type riscv_elf_add_sub_reloc
>    (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
> +static bfd_reloc_status_type riscv_elf_ignore_reloc
> +  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
>  
>  /* The relocation table used for SHT_RELA sections.  */
>  
> @@ -855,8 +857,41 @@ static reloc_howto_type howto_table[] =
>           0,                                /* src_mask */
>           MINUS_ONE,                        /* dst_mask */
>           FALSE),                        /* pcrel_offset */
> +
> +  /* The length of unsigned-leb128 is variant, just assume the
> +     size is one byte here.  */
> +  HOWTO (R_RISCV_SET_ULEB128,                /* type */
> +         0,                                /* rightshift */
> +         0,                                /* size */
> +         0,                                /* bitsize */
> +         FALSE,                                /* pc_relative */
> +         0,                                /* bitpos */
> +         complain_overflow_dont,        /* complain_on_overflow */
> +         riscv_elf_ignore_reloc,        /* special_function */
> +         "R_RISCV_SET_ULEB128",                /* name */
> +         FALSE,                                /* partial_inplace */
> +         0,                                /* src_mask */
> +         0,                                /* dst_mask */
> +         FALSE),                        /* pcrel_offset */

I don't understand how this could possibly work: uleb128s can be long, so we
can't just treat them as a single byte.  I'm having trouble testing it, though,
as I can't figure out how to emit R_RISCV_SET_ULEB128 alone.  For example, when
I try to insert a uleb128 in the assembler I'm not even getting a relocation:

    .text
    .globl _start
    _start:
            nop
    .L0:
            nop
    .L1:
    uleb_l0:
            addi x0, x0, 1
            .uleb128 .L0
            # Manually fix up the alignment, as .align is broken.
            .rept 3
            .byte 0xAA
            .endr
            addi x0, x0, 2
    
    $ objdump -dr
    test.o:     file format elf64-littleriscv
    
    
    Disassembly of section .text:
    
    0000000000000000 <_start>:
       0:   00000013                nop
       4:   00000013                nop
    
    0000000000000008 <uleb_l0>:
       8:   00100013                li      zero,1
       c:   aa04                    fsd     fs1,16(a2)
       e:   aaaa                    fsd     fa0,336(sp)
      10:   00200013                li      zero,2

so then when I link I'm just getting the wrong value entirely.

    test:     file format elf64-littleriscv
    
    
    Disassembly of section .text:
    
    0000000000010078 <_start>:
       10078:       00000013                nop
       1007c:       00000013                nop
    
    0000000000010080 <uleb_l0>:
       10080:       00100013                li      zero,1
       10084:       aa04                    fsd     fs1,16(a2)
       10086:       aaaa                    fsd     fa0,336(sp)
       10088:       00200013                li      zero,2

> +  /* The length of unsigned-leb128 is variant, just assume the
> +     size is one byte here.  */
> +  HOWTO (R_RISCV_SUB_ULEB128,                /* type */
> +         0,                                /* rightshift */
> +         0,                                /* size */
> +         0,                                /* bitsize */
> +         FALSE,                                /* pc_relative */
> +         0,                                /* bitpos */
> +         complain_overflow_dont,        /* complain_on_overflow */
> +         riscv_elf_ignore_reloc,        /* special_function */
> +         "R_RISCV_SUB_ULEB128",                /* name */
> +         FALSE,                                /* partial_inplace */
> +         0,                                /* src_mask */
> +         0,                                /* dst_mask */
> +         FALSE),                        /* pcrel_offset */
>  };

I can get a R_RISCV_SUB_ULEB128, but it appears to be both producing the wrong
value and garbaging up bytes after the relocation.  For example:

    .text
    .globl _start
    _start:
            nop
    .L0:
            nop
    .L1:
    uleb_l1_l0:
            addi x0, x0, 1
            .uleb128 .L1 - .L0
            # Manually fix up the alignment, as .align is broken
            .rept 3
            .byte 0xAA
            .endr
            addi x0, x0, 2

produces the relocation

    test.o:     file format elf64-littleriscv
    
    
    Disassembly of section .text:
    
    0000000000000000 <_start>:
       0:   00000013                nop
    
    0000000000000004 <.L0>:
       4:   00000013                nop
    
    0000000000000008 <uleb_l1_l0>:
       8:   00100013                li      zero,1
       c:   aa04                    fsd     fs1,16(a2)
                            c: R_RISCV_SET_ULEB128  .L1
                            c: R_RISCV_SUB_ULEB128  .L0
       e:   aaaa                    fsd     fa0,336(sp)
      10:   00200013                li      zero,2

but then goes and corrupts the resulting executable


    test:     file format elf64-littleriscv
    Disassembly of section .text:
    
    0000000000010078 <_start>:
       10078:       00000013                nop
       1007c:       00000013                nop
    
    0000000000010080 <uleb_l1_l0>:
       10080:       00100013                li      zero,1
       10084:       ff84                    sd      s1,56(a5)
       10086:       000ffffb                0xffffb
       1008a:       0020                    addi    s0,sp,8

I can't think of a way to make this work aside from just emitting uleb128s at
their full length, which would make them work but would really defeat the
purpose of the format.  I guess we could then relax these, but that seems like
a lot of work.

> +
>  /* A mapping from BFD reloc types to RISC-V ELF reloc types.  */
>  
>  struct elf_reloc_map
> @@ -917,6 +952,8 @@ static const struct elf_reloc_map riscv_reloc_map[] =
>    { 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_SET_ULEB128, R_RISCV_SET_ULEB128 },
> +  { BFD_RELOC_RISCV_SUB_ULEB128, R_RISCV_SUB_ULEB128 },
>  };
>  
>  /* Given a BFD reloc type, return a howto structure.  */
> @@ -1011,6 +1048,20 @@ riscv_elf_add_sub_reloc (bfd *abfd,
>    return bfd_reloc_ok;
>  }
>  
> +/* Special handler for relocations which don't have to be relocated.
> +   This function just simply return bfd_reloc_ok.  */
> +static bfd_reloc_status_type
> +riscv_elf_ignore_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry,
> +                        asymbol *symbol ATTRIBUTE_UNUSED,
> +                        void *data ATTRIBUTE_UNUSED, asection *input_section,
> +                        bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED)
> +{
> +  if (output_bfd != NULL)
> +    reloc_entry->address += input_section->output_offset;
> +
> +  return bfd_reloc_ok;
> +}
> +
>  /* Parsing subset version.
>  
>     Return Value:
> diff --git a/bfd/libbfd.h b/bfd/libbfd.h
> index 77b732ee4b..7aa8f91504 100644
> --- a/bfd/libbfd.h
> +++ b/bfd/libbfd.h
> @@ -2327,6 +2327,8 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
>    "BFD_RELOC_RISCV_SET16",
>    "BFD_RELOC_RISCV_SET32",
>    "BFD_RELOC_RISCV_32_PCREL",
> +  "BFD_RELOC_RISCV_SET_ULEB128",
> +  "BFD_RELOC_RISCV_SUB_ULEB128",
>    "BFD_RELOC_RL78_NEG8",
>    "BFD_RELOC_RL78_NEG16",
>    "BFD_RELOC_RL78_NEG24",
> diff --git a/bfd/reloc.c b/bfd/reloc.c
> index b00b79f319..9b8b75ad21 100644
> --- a/bfd/reloc.c
> +++ b/bfd/reloc.c
> @@ -5212,6 +5212,10 @@ ENUMX
>    BFD_RELOC_RISCV_SET32
>  ENUMX
>    BFD_RELOC_RISCV_32_PCREL
> +ENUMX
> +  BFD_RELOC_RISCV_SET_ULEB128
> +ENUMX
> +  BFD_RELOC_RISCV_SUB_ULEB128
>  ENUMDOC
>    RISC-V relocations.
>  
> diff --git a/gas/ChangeLog b/gas/ChangeLog
> index 09991524da..e53ac0895b 100644
> --- a/gas/ChangeLog
> +++ b/gas/ChangeLog
> @@ -1,3 +1,11 @@
> +2019-11-27  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
> +
> +        * config/tc-riscv.c (md_apply_fix): Add BFD_RELOC_RISCV_SET_ULEB128 and
> +        BFD_RELOC_RISCV_SUB_ULEB128.
> +        (riscv_insert_uleb128_fixes): New function.
> +        (riscv_md_end): Scan rs_leb128 fragments.
> +        (riscv_pseudo_table): Remove uleb128.
> +
>  2019-11-25  Andrew Pinski  <apinski@marvell.com>
>  
>          * config/tc-aarch64.c (md_begin): Use correct
> diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
> index e50505138e..c35c591c0a 100644
> --- a/gas/config/tc-riscv.c
> +++ b/gas/config/tc-riscv.c
> @@ -2392,6 +2392,9 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
>      case BFD_RELOC_RISCV_SUB32:
>      case BFD_RELOC_RISCV_SUB64:
>      case BFD_RELOC_RISCV_RELAX:
> +    /* cvt_frag_to_fill () has called output_leb128 ().  */
> +    case BFD_RELOC_RISCV_SET_ULEB128:
> +    case BFD_RELOC_RISCV_SUB_ULEB128:
>        break;
>  
>      case BFD_RELOC_RISCV_TPREL_HI20:
> @@ -3127,11 +3130,54 @@ riscv_set_public_attributes (void)
>      riscv_write_out_arch_attr ();
>  }
>  
> +/* Scan uleb128 subtraction expressions and insert fixups for them.
> +   e.g., .uleb128 .L1 - .L0
> +   Becuase relaxation may change the value of the subtraction, we
> +   must resolve them in link-time.  */
> +
> +static void
> +riscv_insert_uleb128_fixes (bfd *abfd ATTRIBUTE_UNUSED,
> +                            asection *sec, void *xxx ATTRIBUTE_UNUSED)
> +{
> +  segment_info_type *seginfo = seg_info (sec);
> +  struct frag *fragP;
> +
> +  subseg_set (sec, 0);
> +
> +  for (fragP = seginfo->frchainP->frch_root;
> +       fragP; fragP = fragP->fr_next)
> +    {
> +      expressionS *exp, *exp_dup;
> +
> +      if (fragP->fr_type != rs_leb128  || fragP->fr_symbol == NULL)
> +        continue;
> +
> +      exp = symbol_get_value_expression (fragP->fr_symbol);
> +
> +      if (exp->X_op != O_subtract)
> +        continue;

Presumably that's why I can't get a _SET alone.

> +
> +      /* Only unsigned leb128 can be handle.  */
> +      gas_assert (fragP->fr_subtype == 0);
> +      exp_dup = xmemdup (exp, sizeof (*exp), sizeof (*exp));
> +      exp_dup->X_op = O_symbol;
> +      exp_dup->X_op_symbol = NULL;
> +
> +      /* Insert relocations to resolve the subtraction in link-time.  */
> +      fix_new_exp (fragP, fragP->fr_fix, 0,
> +                   exp_dup, 0, BFD_RELOC_RISCV_SET_ULEB128);
> +      exp_dup->X_add_symbol = exp->X_op_symbol;
> +      fix_new_exp (fragP, fragP->fr_fix, 0,
> +                   exp_dup, 0, BFD_RELOC_RISCV_SUB_ULEB128);
> +    }
> +}
> +
>  /* Called after all assembly has been done.  */
>  
>  void
>  riscv_md_end (void)
>  {
> +  bfd_map_over_sections (stdoutput, riscv_insert_uleb128_fixes, NULL);
>    riscv_set_public_attributes ();
>  }
>  
> @@ -3215,7 +3261,6 @@ static const pseudo_typeS riscv_pseudo_table[] =
>    {"dtprelword", s_dtprel, 4},
>    {"dtpreldword", s_dtprel, 8},
>    {"bss", s_bss, 0},
> -  {"uleb128", s_riscv_leb128, 0},
>    {"sleb128", s_riscv_leb128, 1},
>    {"insn", s_riscv_insn, 0},
>    {"attribute", s_riscv_attribute, 0},
> diff --git a/include/ChangeLog b/include/ChangeLog
> index 47bb86cf71..c290b245c6 100644
> --- a/include/ChangeLog
> +++ b/include/ChangeLog
> @@ -1,3 +1,7 @@
> +2019-11-27  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
> +
> +        * elf/riscv.h ((R_RISCV_SET_ULEB128, (R_RISCV_SUB_ULEB128): Define.
> +
>  2019-11-25  Alan Modra  <amodra@gmail.com>
>  
>          * coff/ti.h (GET_SCNHDR_SIZE, PUT_SCNHDR_SIZE, GET_SCN_SCNLEN),
> diff --git a/include/elf/riscv.h b/include/elf/riscv.h
> index 2f98aa4a3e..030679b35f 100644
> --- a/include/elf/riscv.h
> +++ b/include/elf/riscv.h
> @@ -88,6 +88,8 @@ START_RELOC_NUMBERS (elf_riscv_reloc_type)
>    RELOC_NUMBER (R_RISCV_SET16, 55)
>    RELOC_NUMBER (R_RISCV_SET32, 56)
>    RELOC_NUMBER (R_RISCV_32_PCREL, 57)
> +  RELOC_NUMBER (R_RISCV_SET_ULEB128, 58)
> +  RELOC_NUMBER (R_RISCV_SUB_ULEB128, 59)
>  END_RELOC_NUMBERS (R_RISCV_max)
>  
>  /* Processor specific flags for the ELF header e_flags field.  */
> diff --git a/ld/ChangeLog b/ld/ChangeLog
> index 969ab78035..5c2e406101 100644
> --- a/ld/ChangeLog
> +++ b/ld/ChangeLog
> @@ -1,3 +1,9 @@
> +2019-11-27  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
> +
> +        * testsuite/ld-riscv-elf/ld-riscv-elf.exp: Add uleb128.
> +        * testsuite/ld-riscv-elf/uleb128.d: New test.
> +        * testsuite/ld-riscv-elf/uleb128.s: New file.
> +
>  2019-11-26  Martin Liska  <mliska@suse.cz>
>  
>          * scripttempl/arclinux.sc: Add .text.sorted.* which is sorted
> diff --git a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
> index 7aabbdd641..809e40f08d 100644
> --- a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
> +++ b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
> @@ -38,6 +38,7 @@ if [istarget "riscv*-*-*"] {
>      run_dump_test "attr-merge-priv-spec"
>      run_dump_test "attr-merge-arch-failed-01"
>      run_dump_test "attr-merge-stack-align-failed"
> +    run_dump_test "uleb128"
>      run_ld_link_tests {
>          { "Weak reference 32" "-T weakref.ld -melf32lriscv" ""
>              "-march=rv32i -mabi=ilp32" {weakref32.s}
> diff --git a/ld/testsuite/ld-riscv-elf/uleb128.d b/ld/testsuite/ld-riscv-elf/uleb128.d
> new file mode 100644
> index 0000000000..a921478e98
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/uleb128.d
> @@ -0,0 +1,18 @@
> +#source: uleb128.s
> +#as: -march=rv32ic
> +#ld: -melf32lriscv
> +#objdump: -d
> +
> +.*:[         ]+file format .*
> +
> +Disassembly of section .text:
> +
> +.* <_start>:
> +.*jal.*<bar>
> +.*jal.*<bar>
> +.*jal.*<bar>
> +.*jal.*<bar>
> +.*jal.*<bar>
> +.*jal.*<bar>
> +.*:[         ]+0e0c.*
> +#pass
> diff --git a/ld/testsuite/ld-riscv-elf/uleb128.s b/ld/testsuite/ld-riscv-elf/uleb128.s
> new file mode 100644
> index 0000000000..f7d23be163
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/uleb128.s
> @@ -0,0 +1,18 @@
> +.text
> +.globl bar
> +.globl _start
> +.option rvc
> +.align 2
> +_start:
> +.L0:
> +        .rept 6
> +        call bar
> +        .endr
> +.align 2
> +.L1:
> +        .uleb128 .L1 - .L0
> +        .uleb128 .L2 - .L0
> +.L2:
> +.align 2
> +bar:
> +        nop

It looks like alignment is broken here after uleb128s, but it's not actually
triggering an error in all cases.  Having two of them in this test case doesn't
trigger the issue, but an odd number does.  For example, the following source

    .text
    .globl _start
    .align 2
    _start:
            .uleb128 _start
    .align 2
    _end:
            nop

links _end to a misaligned symbol

    Disassembly of section .text:
    
    0000000000010078 <_start>:
            ...
    
    0000000000010079 <_end>:
       10079:       00000013                nop
       1007d:       0000                    unimp
            ...

I'm assuming that's because norvc assumes 4-byte alignment in text sections, so
it's just eliding the alingment directives.  With RVC I do get an error message

    .text
    .globl _start
    .option rvc
    .align 2
    _start:
            .uleb128 _start
    .align 2
    _end:
            nop

    ./install/bin/riscv64-unknown-linux-gnu-ld: test.o(.text+0x1): 3 bytes required for alignment to 4-byte boundary, but only 2 present
    ./install/bin/riscv64-unknown-linux-gnu-ld: can't relax section: bad value


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] [RISCV] Support subtraction of .uleb128.
  2019-12-06 23:48 ` Palmer Dabbelt via binutils
@ 2019-12-10  5:43   ` Kuan-Lin Chen
  2019-12-17 23:59     ` Jim Wilson
  2020-01-09 23:20   ` Palmer Dabbelt via binutils
  1 sibling, 1 reply; 17+ messages in thread
From: Kuan-Lin Chen @ 2019-12-10  5:43 UTC (permalink / raw)
  To: Palmer Dabbelt; +Cc: binutils@sourceware.org Development

Hi Palmer,

> GCC gives me -Wmaybe-uninitialized for both of these.
May I know your gcc version?
I tried gcc-7.3.0 and gcc-8.2.0, and I didn't get the warning.

> I don't understand how this could possibly work: uleb128s can be long, so we
> can't just treat them as a single byte.
Yes, uleb128s can be long so I implement riscv_elf_ignore_reloc to
ignore the overflow checking.
And I relocate uleb128s by myself in perform_relocation.

> I'm having trouble testing it, though,
> as I can't figure out how to emit R_RISCV_SET_ULEB128 alone.  For example, when
> I try to insert a uleb128 in the assembler I'm not even getting a relocation:
.uleb128 only support subtract format. (.uleb128 .L1 - .L0)
It is impossible to get final the value and the length for ".uleb128
symbol" in assemble-time.
I think ".uleb128 symbol" is meaningless.
Therefore, all targets just fill the value as assemble-time value
without relocations.

>I can get a R_RISCV_SUB_ULEB128, but it appears to be both producing the wrong
>value and garbaging up bytes after the relocation.  For example:

I get the same result in the object file but the different result in executable.
pal.o:     file format elf64-littleriscv

Disassembly of section .text:

0000000000000000 <_start>:
   0:   00000013                nop

0000000000000004 <.L0>:
   4:   00000013                nop

0000000000000008 <uleb_l1_l0>:
   8:   00100013                li      zero,1
   c:   aa04                    fsd     fs1,16(a2)
                        c: R_RISCV_SET_ULEB128  .L1
                        c: R_RISCV_SUB_ULEB128  .L0
   e:   aaaa                    fsd     fa0,336(sp)
  10:   00200013                li      zero,2


a.out:     file format elf64-littleriscv


Disassembly of section .text:

0000000000010078 <_start>:
   10078:       00000013                nop
   1007c:       00000013                nop

0000000000010080 <uleb_l1_l0>:
   10080:       00100013                li      zero,1
   10084:       aa04                    fsd     fs1,16(a2)
   10086:       aaaa                    fsd     fa0,336(sp)
   10088:       00200013                li      zero,2

Maybe there is something mismatched. But I don't have any idea currently.
Could you please give me more information about your flow?
Thanks.

> Presumably that's why I can't get a _SET alone.
I think it's meaningless to use _SET alone in assembly.

> It looks like alignment is broken here after uleb128s, but it's not actually
> triggering an error in all cases.  Having two of them in this test case doesn't
> trigger the issue, but an odd number does.  For example, the following source
I think this alignment issue can be fixed by the following patch:
https://sourceware.org/ml/binutils/2019-12/msg00024.html

Thanks for your review.

Palmer Dabbelt <palmerdabbelt@google.com> 於 2019年12月7日 週六 上午7:47寫道:
>
> On Wed, 27 Nov 2019 00:11:50 PST (-0800), kuanlinchentw@gmail.com wrote:
> > The data length of uleb128 is variable.  So linker must recalculate the
> > value of the subtraction.  The patch leave relocations in object files
> > so that linker can relocate again after relaxation.
> >
> > bfd/ChangeLog:
> > * bfd-in2.h: Regenerated.
> > * elfnn-riscv.c (write_uleb128): New function.
> > (perform_relocation): Perform R_RISCV_SUB_ULEB128 and
> > R_RISCV_SET_ULEB128 relocation.
> > (riscv_elf_relocate_section): Likewise.
> > * elfxx-riscv.c (howto_table): Add R_RISCV_SUB_ULEB128 and
> > R_RISCV_SET_ULEB128.
> > (riscv_elf_ignore_reloc): New function.
> > * libbfd.h: Regenerated.
> > * reloc.c (BFD_RELOC_RISCV_SET_ULEB128, BFD_RELOC_RISCV_SUB_ULEB128):
> > New relocations to support .uleb128.
> >
> > gas/ChangeLog:
> > * config/tc-riscv.c (md_apply_fix): Add BFD_RELOC_RISCV_SET_ULEB128 and
> > BFD_RELOC_RISCV_SUB_ULEB128.
> > (riscv_insert_uleb128_fixes): New function.
> > (riscv_md_end): Scan rs_leb128 fragments.
> > (riscv_pseudo_table): Remove uleb128.
> >
> > include/ChangeLog:
> > * elf/riscv.h ((R_RISCV_SET_ULEB128, (R_RISCV_SUB_ULEB128): Define.
> >
> > ld/ChangeLog:
> > * testsuite/ld-riscv-elf/ld-riscv-elf.exp: Add uleb128.
> > * testsuite/ld-riscv-elf/uleb128.d: New test.
> > * testsuite/ld-riscv-elf/uleb128.s: New file.
> >
> > OK to commit?
>
> I'm having a lot of trouble trying to figure out how this works.  LMK if I'm
> missing something, there's some comments in line:
>
> > From 9f7f0aaa484dee2b32c550f8cca4de18959f01e1 Mon Sep 17 00:00:00 2001
> > From: Kuan-Lin Chen <rufus@andestech.com>
> > Date: Thu, 14 Nov 2019 14:24:22 +0800
> > Subject: [PATCH] RISC-V: Support subtraction of .uleb128.
> >
> > The data length of uleb128 is variable.  So linker must recalculate the
> > value of the subtraction.  The patch leave relocations in object files
> > so that linker can relocate again after relaxation.
> >
> > bfd/ChangeLog:
> >         * bfd-in2.h: Regenerated.
> >         * elfnn-riscv.c (write_uleb128): New function.
> >         (perform_relocation): Perform R_RISCV_SUB_ULEB128 and
> >          R_RISCV_SET_ULEB128 relocation.
> >         (riscv_elf_relocate_section): Likewise.
> >         * elfxx-riscv.c (howto_table): Add R_RISCV_SUB_ULEB128 and
> >         R_RISCV_SET_ULEB128.
> >         (riscv_elf_ignore_reloc): New function.
> >         * libbfd.h: Regenerated.
> >         * reloc.c (BFD_RELOC_RISCV_SET_ULEB128, BFD_RELOC_RISCV_SUB_ULEB128):
> >         New relocations to support .uleb128.
> >
> > gas/ChangeLog:
> >         * config/tc-riscv.c (md_apply_fix): Add BFD_RELOC_RISCV_SET_ULEB128 and
> >         BFD_RELOC_RISCV_SUB_ULEB128.
> >         (riscv_insert_uleb128_fixes): New function.
> >         (riscv_md_end): Scan rs_leb128 fragments.
> >         (riscv_pseudo_table): Remove uleb128.
> >
> > include/ChangeLog:
> >         * elf/riscv.h ((R_RISCV_SET_ULEB128, (R_RISCV_SUB_ULEB128): Define.
> >
> > ld/ChangeLog:
> >         * testsuite/ld-riscv-elf/ld-riscv-elf.exp: Add uleb128.
> >         * testsuite/ld-riscv-elf/uleb128.d: New test.
> >         * testsuite/ld-riscv-elf/uleb128.s: New file.
> > ---
> >  bfd/ChangeLog                              | 14 ++++
> >  bfd/bfd-in2.h                              |  2 +
> >  bfd/elfnn-riscv.c                          | 82 ++++++++++++++++++++++
> >  bfd/elfxx-riscv.c                          | 51 ++++++++++++++
> >  bfd/libbfd.h                               |  2 +
> >  bfd/reloc.c                                |  4 ++
> >  gas/ChangeLog                              |  8 +++
> >  gas/config/tc-riscv.c                      | 47 ++++++++++++-
> >  include/ChangeLog                          |  4 ++
> >  include/elf/riscv.h                        |  2 +
> >  ld/ChangeLog                               |  6 ++
> >  ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp |  1 +
> >  ld/testsuite/ld-riscv-elf/uleb128.d        | 18 +++++
> >  ld/testsuite/ld-riscv-elf/uleb128.s        | 18 +++++
> >  14 files changed, 258 insertions(+), 1 deletion(-)
> >  create mode 100644 ld/testsuite/ld-riscv-elf/uleb128.d
> >  create mode 100644 ld/testsuite/ld-riscv-elf/uleb128.s
> >
> > diff --git a/bfd/ChangeLog b/bfd/ChangeLog
> > index 4a0852e577..d11ffde74c 100644
> > --- a/bfd/ChangeLog
> > +++ b/bfd/ChangeLog
> > @@ -1,3 +1,17 @@
> > +2019-11-27  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
> > +
> > +        * bfd-in2.h: Regenerated.
> > +        * elfnn-riscv.c (write_uleb128): New function.
> > +        (perform_relocation): Perform R_RISCV_SUB_ULEB128 and
> > +         R_RISCV_SET_ULEB128 relocation.
> > +        (riscv_elf_relocate_section): Likewise.
> > +        * elfxx-riscv.c (howto_table): Add R_RISCV_SUB_ULEB128 and
> > +        R_RISCV_SET_ULEB128.
> > +        (riscv_elf_ignore_reloc): New function.
> > +        * libbfd.h: Regenerated.
> > +        * reloc.c (BFD_RELOC_RISCV_SET_ULEB128, BFD_RELOC_RISCV_SUB_ULEB128):
> > +        New relocations to support .uleb128.
> > +
> >  2019-11-27  Alan Modra  <amodra@gmail.com>
> >
> >          PR 23652
> > diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
> > index 44902fc8d0..a32708ebc2 100644
> > --- a/bfd/bfd-in2.h
> > +++ b/bfd/bfd-in2.h
> > @@ -4380,6 +4380,8 @@ number for the SBIC, SBIS, SBI and CBI instructions  */
> >    BFD_RELOC_RISCV_SET16,
> >    BFD_RELOC_RISCV_SET32,
> >    BFD_RELOC_RISCV_32_PCREL,
> > +  BFD_RELOC_RISCV_SET_ULEB128,
> > +  BFD_RELOC_RISCV_SUB_ULEB128,
> >
> >  /* Renesas RL78 Relocations.  */
> >    BFD_RELOC_RL78_NEG8,
> > diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
> > index 997f786602..075ef6b82d 100644
> > --- a/bfd/elfnn-riscv.c
> > +++ b/bfd/elfnn-riscv.c
> > @@ -1419,6 +1419,26 @@ riscv_global_pointer_value (struct bfd_link_info *info)
> >    return h->u.def.value + sec_addr (h->u.def.section);
> >  }
> >
> > +/* Write VAL in uleb128 format to P, returning a pointer to the
> > +   following byte.
> > +   This code is copied from elf-attr.c.  */
> > +
> > +static bfd_byte *
> > +write_uleb128 (bfd_byte *p, unsigned int val)
> > +{
> > +  bfd_byte c;
> > +  do
> > +    {
> > +      c = val & 0x7f;
> > +      val >>= 7;
> > +      if (val)
> > +        c |= 0x80;
> > +      *(p++) = c;
> > +    }
> > +  while (val);
> > +  return p;
> > +}
> > +
> >  /* Emplace a static relocation.  */
> >
> >  static bfd_reloc_status_type
> > @@ -1512,6 +1532,25 @@ perform_relocation (const reloc_howto_type *howto,
> >          value = ENCODE_RVC_LUI_IMM (RISCV_CONST_HIGH_PART (value));
> >        break;
> >
> > +    case R_RISCV_SET_ULEB128:
> > +    case R_RISCV_SUB_ULEB128:
> > +      {
> > +        unsigned int len = 0;
> > +        bfd_byte *endp, *p;
> > +
> > +        _bfd_read_unsigned_leb128 (input_bfd, contents + rel->r_offset, &len);
> > +
> > +        /* Clean the contents value to zero.  Do not reduce the length.  */
> > +        p = contents + rel->r_offset;
> > +        endp = p + len -1;
> > +        memset (p, 0x80, len);
> > +        *(endp) = 0;
> > +        p = write_uleb128 (p, value) - 1;
> > +        if (p < endp)
> > +          *p |= 0x80;
> > +        return bfd_reloc_ok;
> > +      }
> > +
> >      case R_RISCV_32:
> >      case R_RISCV_64:
> >      case R_RISCV_ADD8:
> > @@ -1767,6 +1806,8 @@ riscv_elf_relocate_section (bfd *output_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;
> > +  bfd_vma uleb128_vma;
> > +  Elf_Internal_Rela *uleb128_rel = NULL;
> >
> >    if (!riscv_init_pcrel_relocs (&pcrel_relocs))
> >      return FALSE;
> > @@ -1871,6 +1912,47 @@ riscv_elf_relocate_section (bfd *output_bfd,
> >          case R_RISCV_DELETE:
> >            /* These require no special handling beyond perform_relocation.  */
> >            break;
> > +        case R_RISCV_SET_ULEB128:
> > +          if (!uleb128_rel)
> > +            {
> > +              /* Save the minuend to use later.  */
> > +              uleb128_vma = relocation;
> > +              uleb128_rel = rel;
> > +              continue;
> > +            }
> > +          else
> > +            {
> > +              if (uleb128_rel->r_offset != rel->r_offset)
> > +                {
> > +                  (*_bfd_error_handler) (_("%pB: relocation %s mismatched. "),
> > +                                         input_bfd, howto->name);
> > +                  bfd_set_error (bfd_error_bad_value);
> > +                }
> > +              relocation = relocation - uleb128_vma;
> > +              uleb128_rel = NULL;
> > +              break;
> > +            }
> > +
> > +        case R_RISCV_SUB_ULEB128:
> > +          if (uleb128_rel)
> > +            {
> > +              if (uleb128_rel->r_offset != rel->r_offset)
> > +                {
> > +                  (*_bfd_error_handler) (_("%pB: relocation %s mismatched. "),
> > +                                         input_bfd, howto->name);
> > +                  bfd_set_error (bfd_error_bad_value);
> > +                }
> > +              relocation = uleb128_vma - relocation;
>
> GCC gives me -Wmaybe-uninitialized for both of these.
>
> > +              uleb128_rel = NULL;
> > +              break;
> > +            }
> > +          else
> > +            {
> > +              /* Save the subtrahend to use later.  */
> > +              uleb128_vma = relocation;
> > +              uleb128_rel = rel;
> > +              continue;
> > +            }
> >
> >          case R_RISCV_GOT_HI20:
> >            if (h != NULL)
> > diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c
> > index 245717f70f..c136ba2207 100644
> > --- a/bfd/elfxx-riscv.c
> > +++ b/bfd/elfxx-riscv.c
> > @@ -38,6 +38,8 @@
> >     relocations for the debug info.  */
> >  static bfd_reloc_status_type riscv_elf_add_sub_reloc
> >    (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
> > +static bfd_reloc_status_type riscv_elf_ignore_reloc
> > +  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
> >
> >  /* The relocation table used for SHT_RELA sections.  */
> >
> > @@ -855,8 +857,41 @@ static reloc_howto_type howto_table[] =
> >           0,                                /* src_mask */
> >           MINUS_ONE,                        /* dst_mask */
> >           FALSE),                        /* pcrel_offset */
> > +
> > +  /* The length of unsigned-leb128 is variant, just assume the
> > +     size is one byte here.  */
> > +  HOWTO (R_RISCV_SET_ULEB128,                /* type */
> > +         0,                                /* rightshift */
> > +         0,                                /* size */
> > +         0,                                /* bitsize */
> > +         FALSE,                                /* pc_relative */
> > +         0,                                /* bitpos */
> > +         complain_overflow_dont,        /* complain_on_overflow */
> > +         riscv_elf_ignore_reloc,        /* special_function */
> > +         "R_RISCV_SET_ULEB128",                /* name */
> > +         FALSE,                                /* partial_inplace */
> > +         0,                                /* src_mask */
> > +         0,                                /* dst_mask */
> > +         FALSE),                        /* pcrel_offset */
>
> I don't understand how this could possibly work: uleb128s can be long, so we
> can't just treat them as a single byte.  I'm having trouble testing it, though,
> as I can't figure out how to emit R_RISCV_SET_ULEB128 alone.  For example, when
> I try to insert a uleb128 in the assembler I'm not even getting a relocation:
>
>     .text
>     .globl _start
>     _start:
>             nop
>     .L0:
>             nop
>     .L1:
>     uleb_l0:
>             addi x0, x0, 1
>             .uleb128 .L0
>             # Manually fix up the alignment, as .align is broken.
>             .rept 3
>             .byte 0xAA
>             .endr
>             addi x0, x0, 2
>
>     $ objdump -dr
>     test.o:     file format elf64-littleriscv
>
>
>     Disassembly of section .text:
>
>     0000000000000000 <_start>:
>        0:   00000013                nop
>        4:   00000013                nop
>
>     0000000000000008 <uleb_l0>:
>        8:   00100013                li      zero,1
>        c:   aa04                    fsd     fs1,16(a2)
>        e:   aaaa                    fsd     fa0,336(sp)
>       10:   00200013                li      zero,2
>
> so then when I link I'm just getting the wrong value entirely.
>
>     test:     file format elf64-littleriscv
>
>
>     Disassembly of section .text:
>
>     0000000000010078 <_start>:
>        10078:       00000013                nop
>        1007c:       00000013                nop
>
>     0000000000010080 <uleb_l0>:
>        10080:       00100013                li      zero,1
>        10084:       aa04                    fsd     fs1,16(a2)
>        10086:       aaaa                    fsd     fa0,336(sp)
>        10088:       00200013                li      zero,2
>
> > +  /* The length of unsigned-leb128 is variant, just assume the
> > +     size is one byte here.  */
> > +  HOWTO (R_RISCV_SUB_ULEB128,                /* type */
> > +         0,                                /* rightshift */
> > +         0,                                /* size */
> > +         0,                                /* bitsize */
> > +         FALSE,                                /* pc_relative */
> > +         0,                                /* bitpos */
> > +         complain_overflow_dont,        /* complain_on_overflow */
> > +         riscv_elf_ignore_reloc,        /* special_function */
> > +         "R_RISCV_SUB_ULEB128",                /* name */
> > +         FALSE,                                /* partial_inplace */
> > +         0,                                /* src_mask */
> > +         0,                                /* dst_mask */
> > +         FALSE),                        /* pcrel_offset */
> >  };
>
> I can get a R_RISCV_SUB_ULEB128, but it appears to be both producing the wrong
> value and garbaging up bytes after the relocation.  For example:
>
>     .text
>     .globl _start
>     _start:
>             nop
>     .L0:
>             nop
>     .L1:
>     uleb_l1_l0:
>             addi x0, x0, 1
>             .uleb128 .L1 - .L0
>             # Manually fix up the alignment, as .align is broken
>             .rept 3
>             .byte 0xAA
>             .endr
>             addi x0, x0, 2
>
> produces the relocation
>
>     test.o:     file format elf64-littleriscv
>
>
>     Disassembly of section .text:
>
>     0000000000000000 <_start>:
>        0:   00000013                nop
>
>     0000000000000004 <.L0>:
>        4:   00000013                nop
>
>     0000000000000008 <uleb_l1_l0>:
>        8:   00100013                li      zero,1
>        c:   aa04                    fsd     fs1,16(a2)
>                             c: R_RISCV_SET_ULEB128  .L1
>                             c: R_RISCV_SUB_ULEB128  .L0
>        e:   aaaa                    fsd     fa0,336(sp)
>       10:   00200013                li      zero,2
>
> but then goes and corrupts the resulting executable
>
>
>     test:     file format elf64-littleriscv
>     Disassembly of section .text:
>
>     0000000000010078 <_start>:
>        10078:       00000013                nop
>        1007c:       00000013                nop
>
>     0000000000010080 <uleb_l1_l0>:
>        10080:       00100013                li      zero,1
>        10084:       ff84                    sd      s1,56(a5)
>        10086:       000ffffb                0xffffb
>        1008a:       0020                    addi    s0,sp,8
>
> I can't think of a way to make this work aside from just emitting uleb128s at
> their full length, which would make them work but would really defeat the
> purpose of the format.  I guess we could then relax these, but that seems like
> a lot of work.
>
> > +
> >  /* A mapping from BFD reloc types to RISC-V ELF reloc types.  */
> >
> >  struct elf_reloc_map
> > @@ -917,6 +952,8 @@ static const struct elf_reloc_map riscv_reloc_map[] =
> >    { 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_SET_ULEB128, R_RISCV_SET_ULEB128 },
> > +  { BFD_RELOC_RISCV_SUB_ULEB128, R_RISCV_SUB_ULEB128 },
> >  };
> >
> >  /* Given a BFD reloc type, return a howto structure.  */
> > @@ -1011,6 +1048,20 @@ riscv_elf_add_sub_reloc (bfd *abfd,
> >    return bfd_reloc_ok;
> >  }
> >
> > +/* Special handler for relocations which don't have to be relocated.
> > +   This function just simply return bfd_reloc_ok.  */
> > +static bfd_reloc_status_type
> > +riscv_elf_ignore_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry,
> > +                        asymbol *symbol ATTRIBUTE_UNUSED,
> > +                        void *data ATTRIBUTE_UNUSED, asection *input_section,
> > +                        bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED)
> > +{
> > +  if (output_bfd != NULL)
> > +    reloc_entry->address += input_section->output_offset;
> > +
> > +  return bfd_reloc_ok;
> > +}
> > +
> >  /* Parsing subset version.
> >
> >     Return Value:
> > diff --git a/bfd/libbfd.h b/bfd/libbfd.h
> > index 77b732ee4b..7aa8f91504 100644
> > --- a/bfd/libbfd.h
> > +++ b/bfd/libbfd.h
> > @@ -2327,6 +2327,8 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
> >    "BFD_RELOC_RISCV_SET16",
> >    "BFD_RELOC_RISCV_SET32",
> >    "BFD_RELOC_RISCV_32_PCREL",
> > +  "BFD_RELOC_RISCV_SET_ULEB128",
> > +  "BFD_RELOC_RISCV_SUB_ULEB128",
> >    "BFD_RELOC_RL78_NEG8",
> >    "BFD_RELOC_RL78_NEG16",
> >    "BFD_RELOC_RL78_NEG24",
> > diff --git a/bfd/reloc.c b/bfd/reloc.c
> > index b00b79f319..9b8b75ad21 100644
> > --- a/bfd/reloc.c
> > +++ b/bfd/reloc.c
> > @@ -5212,6 +5212,10 @@ ENUMX
> >    BFD_RELOC_RISCV_SET32
> >  ENUMX
> >    BFD_RELOC_RISCV_32_PCREL
> > +ENUMX
> > +  BFD_RELOC_RISCV_SET_ULEB128
> > +ENUMX
> > +  BFD_RELOC_RISCV_SUB_ULEB128
> >  ENUMDOC
> >    RISC-V relocations.
> >
> > diff --git a/gas/ChangeLog b/gas/ChangeLog
> > index 09991524da..e53ac0895b 100644
> > --- a/gas/ChangeLog
> > +++ b/gas/ChangeLog
> > @@ -1,3 +1,11 @@
> > +2019-11-27  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
> > +
> > +        * config/tc-riscv.c (md_apply_fix): Add BFD_RELOC_RISCV_SET_ULEB128 and
> > +        BFD_RELOC_RISCV_SUB_ULEB128.
> > +        (riscv_insert_uleb128_fixes): New function.
> > +        (riscv_md_end): Scan rs_leb128 fragments.
> > +        (riscv_pseudo_table): Remove uleb128.
> > +
> >  2019-11-25  Andrew Pinski  <apinski@marvell.com>
> >
> >          * config/tc-aarch64.c (md_begin): Use correct
> > diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
> > index e50505138e..c35c591c0a 100644
> > --- a/gas/config/tc-riscv.c
> > +++ b/gas/config/tc-riscv.c
> > @@ -2392,6 +2392,9 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
> >      case BFD_RELOC_RISCV_SUB32:
> >      case BFD_RELOC_RISCV_SUB64:
> >      case BFD_RELOC_RISCV_RELAX:
> > +    /* cvt_frag_to_fill () has called output_leb128 ().  */
> > +    case BFD_RELOC_RISCV_SET_ULEB128:
> > +    case BFD_RELOC_RISCV_SUB_ULEB128:
> >        break;
> >
> >      case BFD_RELOC_RISCV_TPREL_HI20:
> > @@ -3127,11 +3130,54 @@ riscv_set_public_attributes (void)
> >      riscv_write_out_arch_attr ();
> >  }
> >
> > +/* Scan uleb128 subtraction expressions and insert fixups for them.
> > +   e.g., .uleb128 .L1 - .L0
> > +   Becuase relaxation may change the value of the subtraction, we
> > +   must resolve them in link-time.  */
> > +
> > +static void
> > +riscv_insert_uleb128_fixes (bfd *abfd ATTRIBUTE_UNUSED,
> > +                            asection *sec, void *xxx ATTRIBUTE_UNUSED)
> > +{
> > +  segment_info_type *seginfo = seg_info (sec);
> > +  struct frag *fragP;
> > +
> > +  subseg_set (sec, 0);
> > +
> > +  for (fragP = seginfo->frchainP->frch_root;
> > +       fragP; fragP = fragP->fr_next)
> > +    {
> > +      expressionS *exp, *exp_dup;
> > +
> > +      if (fragP->fr_type != rs_leb128  || fragP->fr_symbol == NULL)
> > +        continue;
> > +
> > +      exp = symbol_get_value_expression (fragP->fr_symbol);
> > +
> > +      if (exp->X_op != O_subtract)
> > +        continue;
>
> Presumably that's why I can't get a _SET alone.
>
> > +
> > +      /* Only unsigned leb128 can be handle.  */
> > +      gas_assert (fragP->fr_subtype == 0);
> > +      exp_dup = xmemdup (exp, sizeof (*exp), sizeof (*exp));
> > +      exp_dup->X_op = O_symbol;
> > +      exp_dup->X_op_symbol = NULL;
> > +
> > +      /* Insert relocations to resolve the subtraction in link-time.  */
> > +      fix_new_exp (fragP, fragP->fr_fix, 0,
> > +                   exp_dup, 0, BFD_RELOC_RISCV_SET_ULEB128);
> > +      exp_dup->X_add_symbol = exp->X_op_symbol;
> > +      fix_new_exp (fragP, fragP->fr_fix, 0,
> > +                   exp_dup, 0, BFD_RELOC_RISCV_SUB_ULEB128);
> > +    }
> > +}
> > +
> >  /* Called after all assembly has been done.  */
> >
> >  void
> >  riscv_md_end (void)
> >  {
> > +  bfd_map_over_sections (stdoutput, riscv_insert_uleb128_fixes, NULL);
> >    riscv_set_public_attributes ();
> >  }
> >
> > @@ -3215,7 +3261,6 @@ static const pseudo_typeS riscv_pseudo_table[] =
> >    {"dtprelword", s_dtprel, 4},
> >    {"dtpreldword", s_dtprel, 8},
> >    {"bss", s_bss, 0},
> > -  {"uleb128", s_riscv_leb128, 0},
> >    {"sleb128", s_riscv_leb128, 1},
> >    {"insn", s_riscv_insn, 0},
> >    {"attribute", s_riscv_attribute, 0},
> > diff --git a/include/ChangeLog b/include/ChangeLog
> > index 47bb86cf71..c290b245c6 100644
> > --- a/include/ChangeLog
> > +++ b/include/ChangeLog
> > @@ -1,3 +1,7 @@
> > +2019-11-27  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
> > +
> > +        * elf/riscv.h ((R_RISCV_SET_ULEB128, (R_RISCV_SUB_ULEB128): Define.
> > +
> >  2019-11-25  Alan Modra  <amodra@gmail.com>
> >
> >          * coff/ti.h (GET_SCNHDR_SIZE, PUT_SCNHDR_SIZE, GET_SCN_SCNLEN),
> > diff --git a/include/elf/riscv.h b/include/elf/riscv.h
> > index 2f98aa4a3e..030679b35f 100644
> > --- a/include/elf/riscv.h
> > +++ b/include/elf/riscv.h
> > @@ -88,6 +88,8 @@ START_RELOC_NUMBERS (elf_riscv_reloc_type)
> >    RELOC_NUMBER (R_RISCV_SET16, 55)
> >    RELOC_NUMBER (R_RISCV_SET32, 56)
> >    RELOC_NUMBER (R_RISCV_32_PCREL, 57)
> > +  RELOC_NUMBER (R_RISCV_SET_ULEB128, 58)
> > +  RELOC_NUMBER (R_RISCV_SUB_ULEB128, 59)
> >  END_RELOC_NUMBERS (R_RISCV_max)
> >
> >  /* Processor specific flags for the ELF header e_flags field.  */
> > diff --git a/ld/ChangeLog b/ld/ChangeLog
> > index 969ab78035..5c2e406101 100644
> > --- a/ld/ChangeLog
> > +++ b/ld/ChangeLog
> > @@ -1,3 +1,9 @@
> > +2019-11-27  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
> > +
> > +        * testsuite/ld-riscv-elf/ld-riscv-elf.exp: Add uleb128.
> > +        * testsuite/ld-riscv-elf/uleb128.d: New test.
> > +        * testsuite/ld-riscv-elf/uleb128.s: New file.
> > +
> >  2019-11-26  Martin Liska  <mliska@suse.cz>
> >
> >          * scripttempl/arclinux.sc: Add .text.sorted.* which is sorted
> > diff --git a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
> > index 7aabbdd641..809e40f08d 100644
> > --- a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
> > +++ b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
> > @@ -38,6 +38,7 @@ if [istarget "riscv*-*-*"] {
> >      run_dump_test "attr-merge-priv-spec"
> >      run_dump_test "attr-merge-arch-failed-01"
> >      run_dump_test "attr-merge-stack-align-failed"
> > +    run_dump_test "uleb128"
> >      run_ld_link_tests {
> >          { "Weak reference 32" "-T weakref.ld -melf32lriscv" ""
> >              "-march=rv32i -mabi=ilp32" {weakref32.s}
> > diff --git a/ld/testsuite/ld-riscv-elf/uleb128.d b/ld/testsuite/ld-riscv-elf/uleb128.d
> > new file mode 100644
> > index 0000000000..a921478e98
> > --- /dev/null
> > +++ b/ld/testsuite/ld-riscv-elf/uleb128.d
> > @@ -0,0 +1,18 @@
> > +#source: uleb128.s
> > +#as: -march=rv32ic
> > +#ld: -melf32lriscv
> > +#objdump: -d
> > +
> > +.*:[         ]+file format .*
> > +
> > +Disassembly of section .text:
> > +
> > +.* <_start>:
> > +.*jal.*<bar>
> > +.*jal.*<bar>
> > +.*jal.*<bar>
> > +.*jal.*<bar>
> > +.*jal.*<bar>
> > +.*jal.*<bar>
> > +.*:[         ]+0e0c.*
> > +#pass
> > diff --git a/ld/testsuite/ld-riscv-elf/uleb128.s b/ld/testsuite/ld-riscv-elf/uleb128.s
> > new file mode 100644
> > index 0000000000..f7d23be163
> > --- /dev/null
> > +++ b/ld/testsuite/ld-riscv-elf/uleb128.s
> > @@ -0,0 +1,18 @@
> > +.text
> > +.globl bar
> > +.globl _start
> > +.option rvc
> > +.align 2
> > +_start:
> > +.L0:
> > +        .rept 6
> > +        call bar
> > +        .endr
> > +.align 2
> > +.L1:
> > +        .uleb128 .L1 - .L0
> > +        .uleb128 .L2 - .L0
> > +.L2:
> > +.align 2
> > +bar:
> > +        nop
>
> It looks like alignment is broken here after uleb128s, but it's not actually
> triggering an error in all cases.  Having two of them in this test case doesn't
> trigger the issue, but an odd number does.  For example, the following source
>
>     .text
>     .globl _start
>     .align 2
>     _start:
>             .uleb128 _start
>     .align 2
>     _end:
>             nop
>
> links _end to a misaligned symbol
>
>     Disassembly of section .text:
>
>     0000000000010078 <_start>:
>             ...
>
>     0000000000010079 <_end>:
>        10079:       00000013                nop
>        1007d:       0000                    unimp
>             ...
>
> I'm assuming that's because norvc assumes 4-byte alignment in text sections, so
> it's just eliding the alingment directives.  With RVC I do get an error message
>
>     .text
>     .globl _start
>     .option rvc
>     .align 2
>     _start:
>             .uleb128 _start
>     .align 2
>     _end:
>             nop
>
>     ./install/bin/riscv64-unknown-linux-gnu-ld: test.o(.text+0x1): 3 bytes required for alignment to 4-byte boundary, but only 2 present
>     ./install/bin/riscv64-unknown-linux-gnu-ld: can't relax section: bad value
>
>


-- 
Best regards,
Kuan-Lin Chen.
kuanlinchentw@gmail.com

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] [RISCV] Support subtraction of .uleb128.
  2019-12-10  5:43   ` Kuan-Lin Chen
@ 2019-12-17 23:59     ` Jim Wilson
  2019-12-18  1:50       ` Nelson Chu
  0 siblings, 1 reply; 17+ messages in thread
From: Jim Wilson @ 2019-12-17 23:59 UTC (permalink / raw)
  To: Kuan-Lin Chen; +Cc: Palmer Dabbelt, binutils@sourceware.org Development

I tried the patch, and it works for me.  It even fixes one gcc
testsuite failure oddly enough, gcc.dg/debug/dwarf2/inline5.c, I
didn't look at the details of why.

I see that there is no actual relaxation of the uleb128.  We just pick
the size at assembly time via a variant frag, and then assuming that
the value can never increase during relaxation, we just need to add
enough leading zeros at link time to ensure that the size of the
uleb128 doesn't change if the value gets smaller.  It is a little
worrying that we can only support uleb128 and not sleb128 here, since
this trick won't work for sleb128, but I don't think that is a
problem.  Just handling uleb128 is good enough to allow gcc to use
uleb128/sleb128, as we only use subtraction on addresses, and they are
always treated as unsigned.  I see that object files get a bit larger
due to the extra relocations, but executables end up smaller because
the gcc_except_table is now smaller.  A simple rv32 C++ hello world
program linked against a static libstdc++ reduces in size by about
2.4% with this patch.

The assumption that the uleb128 value always decreases could be wrong
if we are subtracting a text section address from a data section
address, because the size of alignment padding between the two can
increase if the text section size decreases.  This code could fail in
this case.  I don't believe that gcc ever does this, but an end user
could conceivably write assembly code that does this which could be a
problem.  We could handle this in the assembler by forcing the uleb128
size to the pointer size if we are subtracting two pointers that
aren't in the same section.  I think that being in the same section is
enough, and that we don't have to require them to be in the same frag
because of how we handle alignment when relaxing.  That would make the
patch safer, and shouldn't change the size reduction we get with it.
This may require some inconvenient code duplication though, since you
are currently using the generic s_leb128 support which doesn't do
this.  Unless maybe we can add a target dependent hook there to avoid
copying it.

There is the issue I mentioned before that I'd like to see the psABI
updated before we modify binutils to use the new relocs.  Letting gcc
emit code that llvm can't link will cause problems.  Once this patch
goes in, gcc will automatically start emitting the new relocs because
a configure test that currently fails will start working.  I added
some info to the psABI issue to help, but I think we really need some
feedback from the LLVM folks before we commit this.

Otherwise, I don't see anything wrong with the patch other than a few
style issues.  These are all minor problems.

+       endp = p + len -1;
+       memset (p, 0x80, len);
+       *(endp) = 0;

Seem like the memset should be len - 1 but it seems harmless because we
just set the *endp value twice.

+  /* The length of unsigned-leb128 is variant, just assume the
+     size is one byte here.  */

I'd use "variable" instead of "variant", but that is just a style
issue.  This happens in two places.

+   Becuase relaxation may change the value of the subtraction, we
+   must resolve them in link-time.  */

Becuase -> Because
in -> at

+      /* Only unsigned leb128 can be handle.  */

handle -> handled

+      /* Insert relocations to resolve the subtraction in link-time.  */

in -> at

Jim

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] [RISCV] Support subtraction of .uleb128.
  2019-12-17 23:59     ` Jim Wilson
@ 2019-12-18  1:50       ` Nelson Chu
  2020-01-06  8:18         ` Kuan-Lin Chen
  0 siblings, 1 reply; 17+ messages in thread
From: Nelson Chu @ 2019-12-18  1:50 UTC (permalink / raw)
  To: Jim Wilson
  Cc: Kuan-Lin Chen, Palmer Dabbelt, binutils@sourceware.org Development

There is one minor thing.  Maciej has pointed out before that it's
better done with one the percent-codes to `_bfd_error_handler' rather
than aborting the link right away, so that any further link errors are
also reported and you don't have to shake them out one by one.  So
report the relocation error via linker's callback function seems to be
better.  I think maybe we can report a dangerous relocation for the
mismatched R_RISCV_SET_ULEB128 and R_RISCV_SUB_ULEB128.  What I meant
is that,

+ case R_RISCV_SET_ULEB128:
...
+  else
+    {
+      if (uleb128_rel->r_offset != rel->r_offset)
+ {
-  (*_bfd_error_handler) (_("%pB: relocation %s mismatched. "),
- input_bfd, howto->name);
-  bfd_set_error (bfd_error_bad_value);
+ msg = ("R_RISCV_SET_ULEB128 and R_RISCV_SUB_ULEB128 are mismatched. ");
+ r = bfd_reloc_dangerous;
+ break;
+ }
+      relocation = relocation - uleb128_vma;
+      uleb128_rel = NULL;
+      break;
+    }
+
+ case R_RISCV_SUB_ULEB128:
+  if (uleb128_rel)
+    {
+      if (uleb128_rel->r_offset != rel->r_offset)
+ {
-  (*_bfd_error_handler) (_("%pB: relocation %s mismatched. "),
- input_bfd, howto->name);
-  bfd_set_error (bfd_error_bad_value);
+ msg = ("R_RISCV_SET_ULEB128 and R_RISCV_SUB_ULEB128 are mismatched. ");
+ r = bfd_reloc_dangerous;
+ break;
+ }
+      relocation = uleb128_vma - relocation;
+      uleb128_rel = NULL;
+      break;
+    }

Thanks and regards
Nelson

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] [RISCV] Support subtraction of .uleb128.
  2019-12-18  1:50       ` Nelson Chu
@ 2020-01-06  8:18         ` Kuan-Lin Chen
  2020-01-06  8:37           ` Kito Cheng
  2020-01-06  8:44           ` Kuan-Lin Chen
  0 siblings, 2 replies; 17+ messages in thread
From: Kuan-Lin Chen @ 2020-01-06  8:18 UTC (permalink / raw)
  To: Nelson Chu, Jim Wilson
  Cc: Palmer Dabbelt, binutils@sourceware.org Development

[-- Attachment #1: Type: text/plain, Size: 2081 bytes --]

Hi,

The patch is fixed some problems as your comments in previous mails.

>The assumption that the uleb128 address size can only decrease with relaxation is true only if both addresses are in the same section.
I found this kind of subtract is banned in cvt_frag_to_fill for
rs_leb128.  Therefore, it doesn't have to restrict by ourselves.

Thanks for your reviews.

Nelson Chu <nelson.chu@sifive.com> 於 2019年12月18日 週三 上午9:50寫道:
>
> There is one minor thing.  Maciej has pointed out before that it's
> better done with one the percent-codes to `_bfd_error_handler' rather
> than aborting the link right away, so that any further link errors are
> also reported and you don't have to shake them out one by one.  So
> report the relocation error via linker's callback function seems to be
> better.  I think maybe we can report a dangerous relocation for the
> mismatched R_RISCV_SET_ULEB128 and R_RISCV_SUB_ULEB128.  What I meant
> is that,
>
> + case R_RISCV_SET_ULEB128:
> ...
> +  else
> +    {
> +      if (uleb128_rel->r_offset != rel->r_offset)
> + {
> -  (*_bfd_error_handler) (_("%pB: relocation %s mismatched. "),
> - input_bfd, howto->name);
> -  bfd_set_error (bfd_error_bad_value);
> + msg = ("R_RISCV_SET_ULEB128 and R_RISCV_SUB_ULEB128 are mismatched. ");
> + r = bfd_reloc_dangerous;
> + break;
> + }
> +      relocation = relocation - uleb128_vma;
> +      uleb128_rel = NULL;
> +      break;
> +    }
> +
> + case R_RISCV_SUB_ULEB128:
> +  if (uleb128_rel)
> +    {
> +      if (uleb128_rel->r_offset != rel->r_offset)
> + {
> -  (*_bfd_error_handler) (_("%pB: relocation %s mismatched. "),
> - input_bfd, howto->name);
> -  bfd_set_error (bfd_error_bad_value);
> + msg = ("R_RISCV_SET_ULEB128 and R_RISCV_SUB_ULEB128 are mismatched. ");
> + r = bfd_reloc_dangerous;
> + break;
> + }
> +      relocation = uleb128_vma - relocation;
> +      uleb128_rel = NULL;
> +      break;
> +    }
>
> Thanks and regards
> Nelson



-- 
Best regards,
Kuan-Lin Chen.
kuanlinchentw@gmail.com

[-- Attachment #2: 0001-RISC-V-Support-subtraction-of-.uleb128.patch --]
[-- Type: application/octet-stream, Size: 14721 bytes --]

From 6a6367605ed66feb37a73c51c6cdbce9fe09ff42 Mon Sep 17 00:00:00 2001
From: Kuan-Lin Chen <rufus@andestech.com>
Date: Thu, 14 Nov 2019 14:24:22 +0800
Subject: [PATCH] RISC-V: Support subtraction of .uleb128.

The data length of uleb128 is variable.  So linker must recalculate the
value of the subtraction.  The patch leave relocations in object files
so that linker can relocate again after relaxation.

bfd/ChangeLog:
	* bfd-in2.h: Regenerated.
	* elfnn-riscv.c (write_uleb128): New function.
	(perform_relocation): Perform R_RISCV_SUB_ULEB128 and
	 R_RISCV_SET_ULEB128 relocation.
	(riscv_elf_relocate_section): Likewise.
	* elfxx-riscv.c (howto_table): Add R_RISCV_SUB_ULEB128 and
	R_RISCV_SET_ULEB128.
	(riscv_elf_ignore_reloc): New function.
	* libbfd.h: Regenerated.
	* reloc.c (BFD_RELOC_RISCV_SET_ULEB128, BFD_RELOC_RISCV_SUB_ULEB128):
	New relocations to support .uleb128.

gas/ChangeLog:
	* config/tc-riscv.c (md_apply_fix): Add BFD_RELOC_RISCV_SET_ULEB128 and
	BFD_RELOC_RISCV_SUB_ULEB128.
	(riscv_insert_uleb128_fixes): New function.
	(riscv_md_end): Scan rs_leb128 fragments.
	(riscv_pseudo_table): Remove uleb128.

include/ChangeLog:
	* elf/riscv.h ((R_RISCV_SET_ULEB128, (R_RISCV_SUB_ULEB128): Define.

ld/ChangeLog:
	* testsuite/ld-riscv-elf/ld-riscv-elf.exp: Add uleb128.
	* testsuite/ld-riscv-elf/uleb128.d: New test.
	* testsuite/ld-riscv-elf/uleb128.s: New file.
---
 bfd/ChangeLog                              | 14 ++++
 bfd/bfd-in2.h                              |  2 +
 bfd/elfnn-riscv.c                          | 82 ++++++++++++++++++++++
 bfd/elfxx-riscv.c                          | 51 ++++++++++++++
 bfd/libbfd.h                               |  2 +
 bfd/reloc.c                                |  4 ++
 gas/ChangeLog                              |  8 +++
 gas/config/tc-riscv.c                      | 49 ++++++++++++-
 include/ChangeLog                          |  4 ++
 include/elf/riscv.h                        |  2 +
 ld/ChangeLog                               |  6 ++
 ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp |  1 +
 12 files changed, 224 insertions(+), 1 deletion(-)

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 148de794bc..9e39b78554 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,17 @@
+2020-01-06  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
+
+	* bfd-in2.h: Regenerated.
+	* elfnn-riscv.c (write_uleb128): New function.
+	(perform_relocation): Perform R_RISCV_SUB_ULEB128 and
+	 R_RISCV_SET_ULEB128 relocation.
+	(riscv_elf_relocate_section): Likewise.
+	* elfxx-riscv.c (howto_table): Add R_RISCV_SUB_ULEB128 and
+	R_RISCV_SET_ULEB128.
+	(riscv_elf_ignore_reloc): New function.
+	* libbfd.h: Regenerated.
+	* reloc.c (BFD_RELOC_RISCV_SET_ULEB128, BFD_RELOC_RISCV_SUB_ULEB128):
+	New relocations to support .uleb128.
+
 2020-01-04  Alan Modra  <amodra@gmail.com>
 
 	* format.c (bfd_check_format_matches): Add preserve_match.
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 7c13bc8c91..e43c3a5557 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -4383,6 +4383,8 @@ number for the SBIC, SBIS, SBI and CBI instructions  */
   BFD_RELOC_RISCV_SET16,
   BFD_RELOC_RISCV_SET32,
   BFD_RELOC_RISCV_32_PCREL,
+  BFD_RELOC_RISCV_SET_ULEB128,
+  BFD_RELOC_RISCV_SUB_ULEB128,
 
 /* Renesas RL78 Relocations.  */
   BFD_RELOC_RL78_NEG8,
diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index d30fc8b66a..1ae8dd83d0 100644
--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -1419,6 +1419,26 @@ riscv_global_pointer_value (struct bfd_link_info *info)
   return h->u.def.value + sec_addr (h->u.def.section);
 }
 
+/* Write VAL in uleb128 format to P, returning a pointer to the
+   following byte.
+   This code is copied from elf-attr.c.  */
+
+static bfd_byte *
+write_uleb128 (bfd_byte *p, unsigned int val)
+{
+  bfd_byte c;
+  do
+    {
+      c = val & 0x7f;
+      val >>= 7;
+      if (val)
+	c |= 0x80;
+      *(p++) = c;
+    }
+  while (val);
+  return p;
+}
+
 /* Emplace a static relocation.  */
 
 static bfd_reloc_status_type
@@ -1512,6 +1532,25 @@ perform_relocation (const reloc_howto_type *howto,
 	value = ENCODE_RVC_LUI_IMM (RISCV_CONST_HIGH_PART (value));
       break;
 
+    case R_RISCV_SET_ULEB128:
+    case R_RISCV_SUB_ULEB128:
+      {
+	unsigned int len = 0;
+	bfd_byte *endp, *p;
+
+	_bfd_read_unsigned_leb128 (input_bfd, contents + rel->r_offset, &len);
+
+	/* Clean the contents value to zero.  Do not reduce the length.  */
+	p = contents + rel->r_offset;
+	endp = p + len -1;
+	memset (p, 0x80, len - 1);
+	*(endp) = 0;
+	p = write_uleb128 (p, value) - 1;
+	if (p < endp)
+	  *p |= 0x80;
+	return bfd_reloc_ok;
+      }
+
     case R_RISCV_32:
     case R_RISCV_64:
     case R_RISCV_ADD8:
@@ -1767,6 +1806,8 @@ riscv_elf_relocate_section (bfd *output_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;
+  bfd_vma uleb128_vma;
+  Elf_Internal_Rela *uleb128_rel = NULL;
 
   if (!riscv_init_pcrel_relocs (&pcrel_relocs))
     return FALSE;
@@ -1871,6 +1912,47 @@ riscv_elf_relocate_section (bfd *output_bfd,
 	case R_RISCV_DELETE:
 	  /* These require no special handling beyond perform_relocation.  */
 	  break;
+	case R_RISCV_SET_ULEB128:
+	  if (!uleb128_rel)
+	    {
+	      /* Save the minuend to use later.  */
+	      uleb128_vma = relocation;
+	      uleb128_rel = rel;
+	      continue;
+	    }
+	  else
+	    {
+	      if (uleb128_rel->r_offset != rel->r_offset)
+		{
+		  msg = ("R_RISCV_SET_ULEB128 and R_RISCV_SUB_ULEB128 are mismatched. ");
+		  r = bfd_reloc_dangerous;
+		  break;
+		}
+	      relocation = relocation - uleb128_vma;
+	      uleb128_rel = NULL;
+	      break;
+	    }
+
+	case R_RISCV_SUB_ULEB128:
+	  if (uleb128_rel)
+	    {
+	      if (uleb128_rel->r_offset != rel->r_offset)
+		{
+		  msg = ("R_RISCV_SET_ULEB128 and R_RISCV_SUB_ULEB128 are mismatched. ");
+		  r = bfd_reloc_dangerous;
+		  break;
+		}
+	      relocation = uleb128_vma - relocation;
+	      uleb128_rel = NULL;
+	      break;
+	    }
+	  else
+	    {
+	      /* Save the subtrahend to use later.  */
+	      uleb128_vma = relocation;
+	      uleb128_rel = rel;
+	      continue;
+	    }
 
 	case R_RISCV_GOT_HI20:
 	  if (h != NULL)
diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c
index 658629c0c8..c08b95ec24 100644
--- a/bfd/elfxx-riscv.c
+++ b/bfd/elfxx-riscv.c
@@ -38,6 +38,8 @@
    relocations for the debug info.  */
 static bfd_reloc_status_type riscv_elf_add_sub_reloc
   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
+static bfd_reloc_status_type riscv_elf_ignore_reloc
+  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
 
 /* The relocation table used for SHT_RELA sections.  */
 
@@ -855,8 +857,41 @@ static reloc_howto_type howto_table[] =
 	 0,				/* src_mask */
 	 MINUS_ONE,			/* dst_mask */
 	 FALSE),			/* pcrel_offset */
+
+  /* The length of unsigned-leb128 is variable, just assume the
+     size is one byte here.  */
+  HOWTO (R_RISCV_SET_ULEB128,		/* type */
+	 0,				/* rightshift */
+	 0,				/* size */
+	 0,				/* bitsize */
+	 FALSE,				/* pc_relative */
+	 0,				/* bitpos */
+	 complain_overflow_dont,	/* complain_on_overflow */
+	 riscv_elf_ignore_reloc,	/* special_function */
+	 "R_RISCV_SET_ULEB128",		/* name */
+	 FALSE,				/* partial_inplace */
+	 0,				/* src_mask */
+	 0,				/* dst_mask */
+	 FALSE),			/* pcrel_offset */
+
+  /* The length of unsigned-leb128 is variable, just assume the
+     size is one byte here.  */
+  HOWTO (R_RISCV_SUB_ULEB128,		/* type */
+	 0,				/* rightshift */
+	 0,				/* size */
+	 0,				/* bitsize */
+	 FALSE,				/* pc_relative */
+	 0,				/* bitpos */
+	 complain_overflow_dont,	/* complain_on_overflow */
+	 riscv_elf_ignore_reloc,	/* special_function */
+	 "R_RISCV_SUB_ULEB128",		/* name */
+	 FALSE,				/* partial_inplace */
+	 0,				/* src_mask */
+	 0,				/* dst_mask */
+	 FALSE),			/* pcrel_offset */
 };
 
+
 /* A mapping from BFD reloc types to RISC-V ELF reloc types.  */
 
 struct elf_reloc_map
@@ -917,6 +952,8 @@ static const struct elf_reloc_map riscv_reloc_map[] =
   { 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_SET_ULEB128, R_RISCV_SET_ULEB128 },
+  { BFD_RELOC_RISCV_SUB_ULEB128, R_RISCV_SUB_ULEB128 },
 };
 
 /* Given a BFD reloc type, return a howto structure.  */
@@ -1011,6 +1048,20 @@ riscv_elf_add_sub_reloc (bfd *abfd,
   return bfd_reloc_ok;
 }
 
+/* Special handler for relocations which don't have to be relocated.
+   This function just simply return bfd_reloc_ok.  */
+static bfd_reloc_status_type
+riscv_elf_ignore_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry,
+			asymbol *symbol ATTRIBUTE_UNUSED,
+			void *data ATTRIBUTE_UNUSED, asection *input_section,
+			bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED)
+{
+  if (output_bfd != NULL)
+    reloc_entry->address += input_section->output_offset;
+
+  return bfd_reloc_ok;
+}
+
 /* Parsing subset version.
 
    Return Value:
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index d97d4e57a7..74d12d8b99 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -2327,6 +2327,8 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_RISCV_SET16",
   "BFD_RELOC_RISCV_SET32",
   "BFD_RELOC_RISCV_32_PCREL",
+  "BFD_RELOC_RISCV_SET_ULEB128",
+  "BFD_RELOC_RISCV_SUB_ULEB128",
   "BFD_RELOC_RL78_NEG8",
   "BFD_RELOC_RL78_NEG16",
   "BFD_RELOC_RL78_NEG24",
diff --git a/bfd/reloc.c b/bfd/reloc.c
index 33cd67150c..9b797e7920 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -5212,6 +5212,10 @@ ENUMX
   BFD_RELOC_RISCV_SET32
 ENUMX
   BFD_RELOC_RISCV_32_PCREL
+ENUMX
+  BFD_RELOC_RISCV_SET_ULEB128
+ENUMX
+  BFD_RELOC_RISCV_SUB_ULEB128
 ENUMDOC
   RISC-V relocations.
 
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 5a16b9144a..69ec42335b 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,11 @@
+2020-01-06  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
+
+	* config/tc-riscv.c (md_apply_fix): Add BFD_RELOC_RISCV_SET_ULEB128 and
+	BFD_RELOC_RISCV_SUB_ULEB128.
+	(riscv_insert_uleb128_fixes): New function.
+	(riscv_md_end): Scan rs_leb128 fragments.
+	(riscv_pseudo_table): Remove uleb128.
+
 2020-01-03  Sergey Belyashov  <sergey.belyashov@gmail.com>
 
 	PR 25311
diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
index 21fff8ffab..e1e37c267a 100644
--- a/gas/config/tc-riscv.c
+++ b/gas/config/tc-riscv.c
@@ -2392,6 +2392,9 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
     case BFD_RELOC_RISCV_SUB32:
     case BFD_RELOC_RISCV_SUB64:
     case BFD_RELOC_RISCV_RELAX:
+    /* cvt_frag_to_fill () has called output_leb128 ().  */
+    case BFD_RELOC_RISCV_SET_ULEB128:
+    case BFD_RELOC_RISCV_SUB_ULEB128:
       break;
 
     case BFD_RELOC_RISCV_TPREL_HI20:
@@ -3131,11 +3134,56 @@ riscv_set_public_attributes (void)
     riscv_write_out_arch_attr ();
 }
 
+/* Scan uleb128 subtraction expressions and insert fixups for them.
+   e.g., .uleb128 .L1 - .L0
+   Because relaxation may change the value of the subtraction, we
+   must resolve them at link-time.  */
+
+static void
+riscv_insert_uleb128_fixes (bfd *abfd ATTRIBUTE_UNUSED,
+			    asection *sec, void *xxx ATTRIBUTE_UNUSED)
+{
+  segment_info_type *seginfo = seg_info (sec);
+  struct frag *fragP;
+
+  subseg_set (sec, 0);
+
+  for (fragP = seginfo->frchainP->frch_root;
+       fragP; fragP = fragP->fr_next)
+    {
+      expressionS *exp, *exp_dup;
+
+      if (fragP->fr_type != rs_leb128  || fragP->fr_symbol == NULL)
+	continue;
+
+      exp = symbol_get_value_expression (fragP->fr_symbol);
+
+      if (exp->X_op != O_subtract)
+	continue;
+
+      /* Only unsigned leb128 can be handled.  */
+      gas_assert (fragP->fr_subtype == 0);
+      exp_dup = xmemdup (exp, sizeof (*exp), sizeof (*exp));
+      exp_dup->X_op = O_symbol;
+      exp_dup->X_op_symbol = NULL;
+
+      /* Insert relocations to resolve the subtraction at link-time.  */
+      fix_new_exp (fragP, fragP->fr_fix, 0,
+		   exp_dup, 0, BFD_RELOC_RISCV_SET_ULEB128);
+      exp_dup->X_add_symbol = exp->X_op_symbol;
+      fix_new_exp (fragP, fragP->fr_fix, 0,
+		   exp_dup, 0, BFD_RELOC_RISCV_SUB_ULEB128);
+    }
+}
+
 /* Called after all assembly has been done.  */
 
 void
 riscv_md_end (void)
 {
+
+  if (riscv_opts.relax)
+    bfd_map_over_sections (stdoutput, riscv_insert_uleb128_fixes, NULL);
   riscv_set_public_attributes ();
 }
 
@@ -3219,7 +3267,6 @@ static const pseudo_typeS riscv_pseudo_table[] =
   {"dtprelword", s_dtprel, 4},
   {"dtpreldword", s_dtprel, 8},
   {"bss", s_bss, 0},
-  {"uleb128", s_riscv_leb128, 0},
   {"sleb128", s_riscv_leb128, 1},
   {"insn", s_riscv_insn, 0},
   {"attribute", s_riscv_attribute, 0},
diff --git a/include/ChangeLog b/include/ChangeLog
index e28c168f55..3166f708cf 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,3 +1,7 @@
+2020-01-06  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
+
+	* elf/riscv.h ((R_RISCV_SET_ULEB128, (R_RISCV_SUB_ULEB128): Define.
+
 2020-01-02  Sergey Belyashov  <sergey.belyashov@gmail.com>
 
 	* coff/internal.h: Add defintions of Z80 reloc names.
diff --git a/include/elf/riscv.h b/include/elf/riscv.h
index 5062a4998c..a839a0c843 100644
--- a/include/elf/riscv.h
+++ b/include/elf/riscv.h
@@ -88,6 +88,8 @@ START_RELOC_NUMBERS (elf_riscv_reloc_type)
   RELOC_NUMBER (R_RISCV_SET16, 55)
   RELOC_NUMBER (R_RISCV_SET32, 56)
   RELOC_NUMBER (R_RISCV_32_PCREL, 57)
+  RELOC_NUMBER (R_RISCV_SET_ULEB128, 58)
+  RELOC_NUMBER (R_RISCV_SUB_ULEB128, 59)
 END_RELOC_NUMBERS (R_RISCV_max)
 
 /* Processor specific flags for the ELF header e_flags field.  */
diff --git a/ld/ChangeLog b/ld/ChangeLog
index 476e6cb894..d1a9703526 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,3 +1,9 @@
+2020-01-06  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
+
+	* testsuite/ld-riscv-elf/ld-riscv-elf.exp: Add uleb128.
+	* testsuite/ld-riscv-elf/uleb128.d: New test.
+	* testsuite/ld-riscv-elf/uleb128.s: New file.
+
 2020-01-03  Hannes Domani  <ssbssa@yahoo.de>
 
 	* emultempl/pe.em: Add new option --enable-reloc-section.
diff --git a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
index 0e9750e496..412c00d1ec 100644
--- a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
+++ b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
@@ -38,6 +38,7 @@ if [istarget "riscv*-*-*"] {
     run_dump_test "attr-merge-priv-spec"
     run_dump_test "attr-merge-arch-failed-01"
     run_dump_test "attr-merge-stack-align-failed"
+    run_dump_test "uleb128"
     run_ld_link_tests {
 	{ "Weak reference 32" "-T weakref.ld -melf32lriscv" ""
 	    "-march=rv32i -mabi=ilp32" {weakref32.s}
-- 
2.17.0


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] [RISCV] Support subtraction of .uleb128.
  2020-01-06  8:18         ` Kuan-Lin Chen
@ 2020-01-06  8:37           ` Kito Cheng
  2020-01-06  8:44           ` Kuan-Lin Chen
  1 sibling, 0 replies; 17+ messages in thread
From: Kito Cheng @ 2020-01-06  8:37 UTC (permalink / raw)
  To: Kuan-Lin Chen
  Cc: Nelson Chu, Jim Wilson, Palmer Dabbelt,
	binutils@sourceware.org Development

Hi Kuan-Lin:

> * testsuite/ld-riscv-elf/uleb128.d: New test.
> * testsuite/ld-riscv-elf/uleb128.s: New file.
Those two files are not included in the patch, maybe you forgot add?

On Mon, Jan 6, 2020 at 4:18 PM Kuan-Lin Chen <kuanlinchentw@gmail.com>
wrote:

> Hi,
>
> The patch is fixed some problems as your comments in previous mails.
>
> >The assumption that the uleb128 address size can only decrease with
> relaxation is true only if both addresses are in the same section.
> I found this kind of subtract is banned in cvt_frag_to_fill for
> rs_leb128.  Therefore, it doesn't have to restrict by ourselves.
>
> Thanks for your reviews.
>
> Nelson Chu <nelson.chu@sifive.com> 於 2019年12月18日 週三 上午9:50寫道:
> >
> > There is one minor thing.  Maciej has pointed out before that it's
> > better done with one the percent-codes to `_bfd_error_handler' rather
> > than aborting the link right away, so that any further link errors are
> > also reported and you don't have to shake them out one by one.  So
> > report the relocation error via linker's callback function seems to be
> > better.  I think maybe we can report a dangerous relocation for the
> > mismatched R_RISCV_SET_ULEB128 and R_RISCV_SUB_ULEB128.  What I meant
> > is that,
> >
> > + case R_RISCV_SET_ULEB128:
> > ...
> > +  else
> > +    {
> > +      if (uleb128_rel->r_offset != rel->r_offset)
> > + {
> > -  (*_bfd_error_handler) (_("%pB: relocation %s mismatched. "),
> > - input_bfd, howto->name);
> > -  bfd_set_error (bfd_error_bad_value);
> > + msg = ("R_RISCV_SET_ULEB128 and R_RISCV_SUB_ULEB128 are mismatched. ");
> > + r = bfd_reloc_dangerous;
> > + break;
> > + }
> > +      relocation = relocation - uleb128_vma;
> > +      uleb128_rel = NULL;
> > +      break;
> > +    }
> > +
> > + case R_RISCV_SUB_ULEB128:
> > +  if (uleb128_rel)
> > +    {
> > +      if (uleb128_rel->r_offset != rel->r_offset)
> > + {
> > -  (*_bfd_error_handler) (_("%pB: relocation %s mismatched. "),
> > - input_bfd, howto->name);
> > -  bfd_set_error (bfd_error_bad_value);
> > + msg = ("R_RISCV_SET_ULEB128 and R_RISCV_SUB_ULEB128 are mismatched. ");
> > + r = bfd_reloc_dangerous;
> > + break;
> > + }
> > +      relocation = uleb128_vma - relocation;
> > +      uleb128_rel = NULL;
> > +      break;
> > +    }
> >
> > Thanks and regards
> > Nelson
>
>
>
> --
> Best regards,
> Kuan-Lin Chen.
> kuanlinchentw@gmail.com
>

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] [RISCV] Support subtraction of .uleb128.
  2020-01-06  8:18         ` Kuan-Lin Chen
  2020-01-06  8:37           ` Kito Cheng
@ 2020-01-06  8:44           ` Kuan-Lin Chen
  1 sibling, 0 replies; 17+ messages in thread
From: Kuan-Lin Chen @ 2020-01-06  8:44 UTC (permalink / raw)
  To: Nelson Chu, Jim Wilson
  Cc: Palmer Dabbelt, binutils@sourceware.org Development

[-- Attachment #1: Type: text/plain, Size: 2446 bytes --]

Hi,

Sorry, I miss the test case in the previous email.
So I resend this mail.

Kuan-Lin Chen <kuanlinchentw@gmail.com> 於 2020年1月6日 週一 下午4:18寫道:
>
> Hi,
>
> The patch is fixed some problems as your comments in previous mails.
>
> >The assumption that the uleb128 address size can only decrease with relaxation is true only if both addresses are in the same section.
> I found this kind of subtract is banned in cvt_frag_to_fill for
> rs_leb128.  Therefore, it doesn't have to restrict by ourselves.
>
> Thanks for your reviews.
>
> Nelson Chu <nelson.chu@sifive.com> 於 2019年12月18日 週三 上午9:50寫道:
> >
> > There is one minor thing.  Maciej has pointed out before that it's
> > better done with one the percent-codes to `_bfd_error_handler' rather
> > than aborting the link right away, so that any further link errors are
> > also reported and you don't have to shake them out one by one.  So
> > report the relocation error via linker's callback function seems to be
> > better.  I think maybe we can report a dangerous relocation for the
> > mismatched R_RISCV_SET_ULEB128 and R_RISCV_SUB_ULEB128.  What I meant
> > is that,
> >
> > + case R_RISCV_SET_ULEB128:
> > ...
> > +  else
> > +    {
> > +      if (uleb128_rel->r_offset != rel->r_offset)
> > + {
> > -  (*_bfd_error_handler) (_("%pB: relocation %s mismatched. "),
> > - input_bfd, howto->name);
> > -  bfd_set_error (bfd_error_bad_value);
> > + msg = ("R_RISCV_SET_ULEB128 and R_RISCV_SUB_ULEB128 are mismatched. ");
> > + r = bfd_reloc_dangerous;
> > + break;
> > + }
> > +      relocation = relocation - uleb128_vma;
> > +      uleb128_rel = NULL;
> > +      break;
> > +    }
> > +
> > + case R_RISCV_SUB_ULEB128:
> > +  if (uleb128_rel)
> > +    {
> > +      if (uleb128_rel->r_offset != rel->r_offset)
> > + {
> > -  (*_bfd_error_handler) (_("%pB: relocation %s mismatched. "),
> > - input_bfd, howto->name);
> > -  bfd_set_error (bfd_error_bad_value);
> > + msg = ("R_RISCV_SET_ULEB128 and R_RISCV_SUB_ULEB128 are mismatched. ");
> > + r = bfd_reloc_dangerous;
> > + break;
> > + }
> > +      relocation = uleb128_vma - relocation;
> > +      uleb128_rel = NULL;
> > +      break;
> > +    }
> >
> > Thanks and regards
> > Nelson
>
>
>
> --
> Best regards,
> Kuan-Lin Chen.
> kuanlinchentw@gmail.com



-- 
Best regards,
Kuan-Lin Chen.
kuanlinchentw@gmail.com

[-- Attachment #2: 0001-RISC-V-Support-subtraction-of-.uleb128.patch --]
[-- Type: application/octet-stream, Size: 15848 bytes --]

From a6e5a1bca889de33cf994543ced0706b8b982f72 Mon Sep 17 00:00:00 2001
From: Kuan-Lin Chen <rufus@andestech.com>
Date: Thu, 14 Nov 2019 14:24:22 +0800
Subject: [PATCH] RISC-V: Support subtraction of .uleb128.

The data length of uleb128 is variable.  So linker must recalculate the
value of the subtraction.  The patch leave relocations in object files
so that linker can relocate again after relaxation.

bfd/ChangeLog:
	* bfd-in2.h: Regenerated.
	* elfnn-riscv.c (write_uleb128): New function.
	(perform_relocation): Perform R_RISCV_SUB_ULEB128 and
	 R_RISCV_SET_ULEB128 relocation.
	(riscv_elf_relocate_section): Likewise.
	* elfxx-riscv.c (howto_table): Add R_RISCV_SUB_ULEB128 and
	R_RISCV_SET_ULEB128.
	(riscv_elf_ignore_reloc): New function.
	* libbfd.h: Regenerated.
	* reloc.c (BFD_RELOC_RISCV_SET_ULEB128, BFD_RELOC_RISCV_SUB_ULEB128):
	New relocations to support .uleb128.

gas/ChangeLog:
	* config/tc-riscv.c (md_apply_fix): Add BFD_RELOC_RISCV_SET_ULEB128 and
	BFD_RELOC_RISCV_SUB_ULEB128.
	(riscv_insert_uleb128_fixes): New function.
	(riscv_md_end): Scan rs_leb128 fragments.
	(riscv_pseudo_table): Remove uleb128.

include/ChangeLog:
	* elf/riscv.h ((R_RISCV_SET_ULEB128, (R_RISCV_SUB_ULEB128): Define.

ld/ChangeLog:
	* testsuite/ld-riscv-elf/ld-riscv-elf.exp: Add uleb128.
	* testsuite/ld-riscv-elf/uleb128.d: New test.
	* testsuite/ld-riscv-elf/uleb128.s: New file.
---
 bfd/ChangeLog                              | 14 ++++
 bfd/bfd-in2.h                              |  2 +
 bfd/elfnn-riscv.c                          | 82 ++++++++++++++++++++++
 bfd/elfxx-riscv.c                          | 51 ++++++++++++++
 bfd/libbfd.h                               |  2 +
 bfd/reloc.c                                |  4 ++
 gas/ChangeLog                              |  8 +++
 gas/config/tc-riscv.c                      | 49 ++++++++++++-
 include/ChangeLog                          |  4 ++
 include/elf/riscv.h                        |  2 +
 ld/ChangeLog                               |  6 ++
 ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp |  1 +
 ld/testsuite/ld-riscv-elf/uleb128.d        | 18 +++++
 ld/testsuite/ld-riscv-elf/uleb128.s        | 18 +++++
 14 files changed, 260 insertions(+), 1 deletion(-)
 create mode 100644 ld/testsuite/ld-riscv-elf/uleb128.d
 create mode 100644 ld/testsuite/ld-riscv-elf/uleb128.s

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 148de794bc..9e39b78554 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,17 @@
+2020-01-06  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
+
+	* bfd-in2.h: Regenerated.
+	* elfnn-riscv.c (write_uleb128): New function.
+	(perform_relocation): Perform R_RISCV_SUB_ULEB128 and
+	 R_RISCV_SET_ULEB128 relocation.
+	(riscv_elf_relocate_section): Likewise.
+	* elfxx-riscv.c (howto_table): Add R_RISCV_SUB_ULEB128 and
+	R_RISCV_SET_ULEB128.
+	(riscv_elf_ignore_reloc): New function.
+	* libbfd.h: Regenerated.
+	* reloc.c (BFD_RELOC_RISCV_SET_ULEB128, BFD_RELOC_RISCV_SUB_ULEB128):
+	New relocations to support .uleb128.
+
 2020-01-04  Alan Modra  <amodra@gmail.com>
 
 	* format.c (bfd_check_format_matches): Add preserve_match.
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 7c13bc8c91..e43c3a5557 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -4383,6 +4383,8 @@ number for the SBIC, SBIS, SBI and CBI instructions  */
   BFD_RELOC_RISCV_SET16,
   BFD_RELOC_RISCV_SET32,
   BFD_RELOC_RISCV_32_PCREL,
+  BFD_RELOC_RISCV_SET_ULEB128,
+  BFD_RELOC_RISCV_SUB_ULEB128,
 
 /* Renesas RL78 Relocations.  */
   BFD_RELOC_RL78_NEG8,
diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index d30fc8b66a..1ae8dd83d0 100644
--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -1419,6 +1419,26 @@ riscv_global_pointer_value (struct bfd_link_info *info)
   return h->u.def.value + sec_addr (h->u.def.section);
 }
 
+/* Write VAL in uleb128 format to P, returning a pointer to the
+   following byte.
+   This code is copied from elf-attr.c.  */
+
+static bfd_byte *
+write_uleb128 (bfd_byte *p, unsigned int val)
+{
+  bfd_byte c;
+  do
+    {
+      c = val & 0x7f;
+      val >>= 7;
+      if (val)
+	c |= 0x80;
+      *(p++) = c;
+    }
+  while (val);
+  return p;
+}
+
 /* Emplace a static relocation.  */
 
 static bfd_reloc_status_type
@@ -1512,6 +1532,25 @@ perform_relocation (const reloc_howto_type *howto,
 	value = ENCODE_RVC_LUI_IMM (RISCV_CONST_HIGH_PART (value));
       break;
 
+    case R_RISCV_SET_ULEB128:
+    case R_RISCV_SUB_ULEB128:
+      {
+	unsigned int len = 0;
+	bfd_byte *endp, *p;
+
+	_bfd_read_unsigned_leb128 (input_bfd, contents + rel->r_offset, &len);
+
+	/* Clean the contents value to zero.  Do not reduce the length.  */
+	p = contents + rel->r_offset;
+	endp = p + len -1;
+	memset (p, 0x80, len - 1);
+	*(endp) = 0;
+	p = write_uleb128 (p, value) - 1;
+	if (p < endp)
+	  *p |= 0x80;
+	return bfd_reloc_ok;
+      }
+
     case R_RISCV_32:
     case R_RISCV_64:
     case R_RISCV_ADD8:
@@ -1767,6 +1806,8 @@ riscv_elf_relocate_section (bfd *output_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;
+  bfd_vma uleb128_vma;
+  Elf_Internal_Rela *uleb128_rel = NULL;
 
   if (!riscv_init_pcrel_relocs (&pcrel_relocs))
     return FALSE;
@@ -1871,6 +1912,47 @@ riscv_elf_relocate_section (bfd *output_bfd,
 	case R_RISCV_DELETE:
 	  /* These require no special handling beyond perform_relocation.  */
 	  break;
+	case R_RISCV_SET_ULEB128:
+	  if (!uleb128_rel)
+	    {
+	      /* Save the minuend to use later.  */
+	      uleb128_vma = relocation;
+	      uleb128_rel = rel;
+	      continue;
+	    }
+	  else
+	    {
+	      if (uleb128_rel->r_offset != rel->r_offset)
+		{
+		  msg = ("R_RISCV_SET_ULEB128 and R_RISCV_SUB_ULEB128 are mismatched. ");
+		  r = bfd_reloc_dangerous;
+		  break;
+		}
+	      relocation = relocation - uleb128_vma;
+	      uleb128_rel = NULL;
+	      break;
+	    }
+
+	case R_RISCV_SUB_ULEB128:
+	  if (uleb128_rel)
+	    {
+	      if (uleb128_rel->r_offset != rel->r_offset)
+		{
+		  msg = ("R_RISCV_SET_ULEB128 and R_RISCV_SUB_ULEB128 are mismatched. ");
+		  r = bfd_reloc_dangerous;
+		  break;
+		}
+	      relocation = uleb128_vma - relocation;
+	      uleb128_rel = NULL;
+	      break;
+	    }
+	  else
+	    {
+	      /* Save the subtrahend to use later.  */
+	      uleb128_vma = relocation;
+	      uleb128_rel = rel;
+	      continue;
+	    }
 
 	case R_RISCV_GOT_HI20:
 	  if (h != NULL)
diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c
index 658629c0c8..c08b95ec24 100644
--- a/bfd/elfxx-riscv.c
+++ b/bfd/elfxx-riscv.c
@@ -38,6 +38,8 @@
    relocations for the debug info.  */
 static bfd_reloc_status_type riscv_elf_add_sub_reloc
   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
+static bfd_reloc_status_type riscv_elf_ignore_reloc
+  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
 
 /* The relocation table used for SHT_RELA sections.  */
 
@@ -855,8 +857,41 @@ static reloc_howto_type howto_table[] =
 	 0,				/* src_mask */
 	 MINUS_ONE,			/* dst_mask */
 	 FALSE),			/* pcrel_offset */
+
+  /* The length of unsigned-leb128 is variable, just assume the
+     size is one byte here.  */
+  HOWTO (R_RISCV_SET_ULEB128,		/* type */
+	 0,				/* rightshift */
+	 0,				/* size */
+	 0,				/* bitsize */
+	 FALSE,				/* pc_relative */
+	 0,				/* bitpos */
+	 complain_overflow_dont,	/* complain_on_overflow */
+	 riscv_elf_ignore_reloc,	/* special_function */
+	 "R_RISCV_SET_ULEB128",		/* name */
+	 FALSE,				/* partial_inplace */
+	 0,				/* src_mask */
+	 0,				/* dst_mask */
+	 FALSE),			/* pcrel_offset */
+
+  /* The length of unsigned-leb128 is variable, just assume the
+     size is one byte here.  */
+  HOWTO (R_RISCV_SUB_ULEB128,		/* type */
+	 0,				/* rightshift */
+	 0,				/* size */
+	 0,				/* bitsize */
+	 FALSE,				/* pc_relative */
+	 0,				/* bitpos */
+	 complain_overflow_dont,	/* complain_on_overflow */
+	 riscv_elf_ignore_reloc,	/* special_function */
+	 "R_RISCV_SUB_ULEB128",		/* name */
+	 FALSE,				/* partial_inplace */
+	 0,				/* src_mask */
+	 0,				/* dst_mask */
+	 FALSE),			/* pcrel_offset */
 };
 
+
 /* A mapping from BFD reloc types to RISC-V ELF reloc types.  */
 
 struct elf_reloc_map
@@ -917,6 +952,8 @@ static const struct elf_reloc_map riscv_reloc_map[] =
   { 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_SET_ULEB128, R_RISCV_SET_ULEB128 },
+  { BFD_RELOC_RISCV_SUB_ULEB128, R_RISCV_SUB_ULEB128 },
 };
 
 /* Given a BFD reloc type, return a howto structure.  */
@@ -1011,6 +1048,20 @@ riscv_elf_add_sub_reloc (bfd *abfd,
   return bfd_reloc_ok;
 }
 
+/* Special handler for relocations which don't have to be relocated.
+   This function just simply return bfd_reloc_ok.  */
+static bfd_reloc_status_type
+riscv_elf_ignore_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry,
+			asymbol *symbol ATTRIBUTE_UNUSED,
+			void *data ATTRIBUTE_UNUSED, asection *input_section,
+			bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED)
+{
+  if (output_bfd != NULL)
+    reloc_entry->address += input_section->output_offset;
+
+  return bfd_reloc_ok;
+}
+
 /* Parsing subset version.
 
    Return Value:
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index d97d4e57a7..74d12d8b99 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -2327,6 +2327,8 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_RISCV_SET16",
   "BFD_RELOC_RISCV_SET32",
   "BFD_RELOC_RISCV_32_PCREL",
+  "BFD_RELOC_RISCV_SET_ULEB128",
+  "BFD_RELOC_RISCV_SUB_ULEB128",
   "BFD_RELOC_RL78_NEG8",
   "BFD_RELOC_RL78_NEG16",
   "BFD_RELOC_RL78_NEG24",
diff --git a/bfd/reloc.c b/bfd/reloc.c
index 33cd67150c..9b797e7920 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -5212,6 +5212,10 @@ ENUMX
   BFD_RELOC_RISCV_SET32
 ENUMX
   BFD_RELOC_RISCV_32_PCREL
+ENUMX
+  BFD_RELOC_RISCV_SET_ULEB128
+ENUMX
+  BFD_RELOC_RISCV_SUB_ULEB128
 ENUMDOC
   RISC-V relocations.
 
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 5a16b9144a..69ec42335b 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,11 @@
+2020-01-06  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
+
+	* config/tc-riscv.c (md_apply_fix): Add BFD_RELOC_RISCV_SET_ULEB128 and
+	BFD_RELOC_RISCV_SUB_ULEB128.
+	(riscv_insert_uleb128_fixes): New function.
+	(riscv_md_end): Scan rs_leb128 fragments.
+	(riscv_pseudo_table): Remove uleb128.
+
 2020-01-03  Sergey Belyashov  <sergey.belyashov@gmail.com>
 
 	PR 25311
diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
index 21fff8ffab..e1e37c267a 100644
--- a/gas/config/tc-riscv.c
+++ b/gas/config/tc-riscv.c
@@ -2392,6 +2392,9 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
     case BFD_RELOC_RISCV_SUB32:
     case BFD_RELOC_RISCV_SUB64:
     case BFD_RELOC_RISCV_RELAX:
+    /* cvt_frag_to_fill () has called output_leb128 ().  */
+    case BFD_RELOC_RISCV_SET_ULEB128:
+    case BFD_RELOC_RISCV_SUB_ULEB128:
       break;
 
     case BFD_RELOC_RISCV_TPREL_HI20:
@@ -3131,11 +3134,56 @@ riscv_set_public_attributes (void)
     riscv_write_out_arch_attr ();
 }
 
+/* Scan uleb128 subtraction expressions and insert fixups for them.
+   e.g., .uleb128 .L1 - .L0
+   Because relaxation may change the value of the subtraction, we
+   must resolve them at link-time.  */
+
+static void
+riscv_insert_uleb128_fixes (bfd *abfd ATTRIBUTE_UNUSED,
+			    asection *sec, void *xxx ATTRIBUTE_UNUSED)
+{
+  segment_info_type *seginfo = seg_info (sec);
+  struct frag *fragP;
+
+  subseg_set (sec, 0);
+
+  for (fragP = seginfo->frchainP->frch_root;
+       fragP; fragP = fragP->fr_next)
+    {
+      expressionS *exp, *exp_dup;
+
+      if (fragP->fr_type != rs_leb128  || fragP->fr_symbol == NULL)
+	continue;
+
+      exp = symbol_get_value_expression (fragP->fr_symbol);
+
+      if (exp->X_op != O_subtract)
+	continue;
+
+      /* Only unsigned leb128 can be handled.  */
+      gas_assert (fragP->fr_subtype == 0);
+      exp_dup = xmemdup (exp, sizeof (*exp), sizeof (*exp));
+      exp_dup->X_op = O_symbol;
+      exp_dup->X_op_symbol = NULL;
+
+      /* Insert relocations to resolve the subtraction at link-time.  */
+      fix_new_exp (fragP, fragP->fr_fix, 0,
+		   exp_dup, 0, BFD_RELOC_RISCV_SET_ULEB128);
+      exp_dup->X_add_symbol = exp->X_op_symbol;
+      fix_new_exp (fragP, fragP->fr_fix, 0,
+		   exp_dup, 0, BFD_RELOC_RISCV_SUB_ULEB128);
+    }
+}
+
 /* Called after all assembly has been done.  */
 
 void
 riscv_md_end (void)
 {
+
+  if (riscv_opts.relax)
+    bfd_map_over_sections (stdoutput, riscv_insert_uleb128_fixes, NULL);
   riscv_set_public_attributes ();
 }
 
@@ -3219,7 +3267,6 @@ static const pseudo_typeS riscv_pseudo_table[] =
   {"dtprelword", s_dtprel, 4},
   {"dtpreldword", s_dtprel, 8},
   {"bss", s_bss, 0},
-  {"uleb128", s_riscv_leb128, 0},
   {"sleb128", s_riscv_leb128, 1},
   {"insn", s_riscv_insn, 0},
   {"attribute", s_riscv_attribute, 0},
diff --git a/include/ChangeLog b/include/ChangeLog
index e28c168f55..3166f708cf 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,3 +1,7 @@
+2020-01-06  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
+
+	* elf/riscv.h ((R_RISCV_SET_ULEB128, (R_RISCV_SUB_ULEB128): Define.
+
 2020-01-02  Sergey Belyashov  <sergey.belyashov@gmail.com>
 
 	* coff/internal.h: Add defintions of Z80 reloc names.
diff --git a/include/elf/riscv.h b/include/elf/riscv.h
index 5062a4998c..a839a0c843 100644
--- a/include/elf/riscv.h
+++ b/include/elf/riscv.h
@@ -88,6 +88,8 @@ START_RELOC_NUMBERS (elf_riscv_reloc_type)
   RELOC_NUMBER (R_RISCV_SET16, 55)
   RELOC_NUMBER (R_RISCV_SET32, 56)
   RELOC_NUMBER (R_RISCV_32_PCREL, 57)
+  RELOC_NUMBER (R_RISCV_SET_ULEB128, 58)
+  RELOC_NUMBER (R_RISCV_SUB_ULEB128, 59)
 END_RELOC_NUMBERS (R_RISCV_max)
 
 /* Processor specific flags for the ELF header e_flags field.  */
diff --git a/ld/ChangeLog b/ld/ChangeLog
index 476e6cb894..d1a9703526 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,3 +1,9 @@
+2020-01-06  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
+
+	* testsuite/ld-riscv-elf/ld-riscv-elf.exp: Add uleb128.
+	* testsuite/ld-riscv-elf/uleb128.d: New test.
+	* testsuite/ld-riscv-elf/uleb128.s: New file.
+
 2020-01-03  Hannes Domani  <ssbssa@yahoo.de>
 
 	* emultempl/pe.em: Add new option --enable-reloc-section.
diff --git a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
index 0e9750e496..412c00d1ec 100644
--- a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
+++ b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
@@ -38,6 +38,7 @@ if [istarget "riscv*-*-*"] {
     run_dump_test "attr-merge-priv-spec"
     run_dump_test "attr-merge-arch-failed-01"
     run_dump_test "attr-merge-stack-align-failed"
+    run_dump_test "uleb128"
     run_ld_link_tests {
 	{ "Weak reference 32" "-T weakref.ld -melf32lriscv" ""
 	    "-march=rv32i -mabi=ilp32" {weakref32.s}
diff --git a/ld/testsuite/ld-riscv-elf/uleb128.d b/ld/testsuite/ld-riscv-elf/uleb128.d
new file mode 100644
index 0000000000..a921478e98
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/uleb128.d
@@ -0,0 +1,18 @@
+#source: uleb128.s
+#as: -march=rv32ic
+#ld: -melf32lriscv
+#objdump: -d
+
+.*:[ 	]+file format .*
+
+Disassembly of section .text:
+
+.* <_start>:
+.*jal.*<bar>
+.*jal.*<bar>
+.*jal.*<bar>
+.*jal.*<bar>
+.*jal.*<bar>
+.*jal.*<bar>
+.*:[ 	]+0e0c.*
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/uleb128.s b/ld/testsuite/ld-riscv-elf/uleb128.s
new file mode 100644
index 0000000000..f7d23be163
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/uleb128.s
@@ -0,0 +1,18 @@
+.text
+.globl bar
+.globl _start
+.option rvc
+.align 2
+_start:
+.L0:
+        .rept 6
+        call bar
+        .endr
+.align 2
+.L1:
+        .uleb128 .L1 - .L0
+        .uleb128 .L2 - .L0
+.L2:
+.align 2
+bar:
+        nop
-- 
2.17.0


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] [RISCV] Support subtraction of .uleb128.
  2019-12-06 23:48 ` Palmer Dabbelt via binutils
  2019-12-10  5:43   ` Kuan-Lin Chen
@ 2020-01-09 23:20   ` Palmer Dabbelt via binutils
  2020-01-22  7:26     ` Kuan-Lin Chen
  1 sibling, 1 reply; 17+ messages in thread
From: Palmer Dabbelt via binutils @ 2020-01-09 23:20 UTC (permalink / raw)
  To: kuanlinchentw; +Cc: binutils

On Mon, 09 Dec 2019 21:42:58 PST (-0800), kuanlinchentw@gmail.com wrote:
> Hi Palmer,
>
>> GCC gives me -Wmaybe-uninitialized for both of these.
> May I know your gcc version?
> I tried gcc-7.3.0 and gcc-8.2.0, and I didn't get the warning.

$ gcc --version
gcc (Debian 8.3.0-6) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

>> I don't understand how this could possibly work: uleb128s can be long, so we
>> can't just treat them as a single byte.
> Yes, uleb128s can be long so I implement riscv_elf_ignore_reloc to
> ignore the overflow checking.
> And I relocate uleb128s by myself in perform_relocation.
>
>> I'm having trouble testing it, though,
>> as I can't figure out how to emit R_RISCV_SET_ULEB128 alone.  For example, when
>> I try to insert a uleb128 in the assembler I'm not even getting a relocation:
> .uleb128 only support subtract format. (.uleb128 .L1 - .L0)
> It is impossible to get final the value and the length for ".uleb128
> symbol" in assemble-time.

Well, you know symbols are at most 64-bit on rv64 and 32-bit on rv32, so you
can just emit enough space to encode any symbol.  That's better than emitting 7
bits, which is unlikely to encode any symbol.

> I think ".uleb128 symbol" is meaningless.
> Therefore, all targets just fill the value as assemble-time value
> without relocations.

If the assembler can't handle something then it needs to provide an error, it
can't just generate incorrect code.

>>I can get a R_RISCV_SUB_ULEB128, but it appears to be both producing the wrong
>>value and garbaging up bytes after the relocation.  For example:
>
> I get the same result in the object file but the different result in executable.
> pal.o:     file format elf64-littleriscv
>
> Disassembly of section .text:
>
> 0000000000000000 <_start>:
>    0:   00000013                nop
>
> 0000000000000004 <.L0>:
>    4:   00000013                nop
>
> 0000000000000008 <uleb_l1_l0>:
>    8:   00100013                li      zero,1
>    c:   aa04                    fsd     fs1,16(a2)
>                         c: R_RISCV_SET_ULEB128  .L1
>                         c: R_RISCV_SUB_ULEB128  .L0
>    e:   aaaa                    fsd     fa0,336(sp)
>   10:   00200013                li      zero,2
>
>
> a.out:     file format elf64-littleriscv
>
>
> Disassembly of section .text:
>
> 0000000000010078 <_start>:
>    10078:       00000013                nop
>    1007c:       00000013                nop
>
> 0000000000010080 <uleb_l1_l0>:
>    10080:       00100013                li      zero,1
>    10084:       aa04                    fsd     fs1,16(a2)
>    10086:       aaaa                    fsd     fa0,336(sp)
>    10088:       00200013                li      zero,2
>
> Maybe there is something mismatched. But I don't have any idea currently.
> Could you please give me more information about your flow?

IIRC I just applied the patch on top of whatever was HEAD of binutils-gdb at
the time, but I don't have the working directory around any more.

> Thanks.
>
>> Presumably that's why I can't get a _SET alone.
> I think it's meaningless to use _SET alone in assembly.
>
>> It looks like alignment is broken here after uleb128s, but it's not actually
>> triggering an error in all cases.  Having two of them in this test case doesn't
>> trigger the issue, but an odd number does.  For example, the following source
> I think this alignment issue can be fixed by the following patch:
> https://sourceware.org/ml/binutils/2019-12/msg00024.html

Ya, thanks -- I think there's some issues there as well, IIRC I commented on
it.

>
> Thanks for your review.
>
> Palmer Dabbelt <palmerdabbelt@google.com> 於 2019年12月7日 週六 上午7:47寫道:
>>
>> On Wed, 27 Nov 2019 00:11:50 PST (-0800), kuanlinchentw@gmail.com wrote:
>> > The data length of uleb128 is variable.  So linker must recalculate the
>> > value of the subtraction.  The patch leave relocations in object files
>> > so that linker can relocate again after relaxation.
>> >
>> > bfd/ChangeLog:
>> > * bfd-in2.h: Regenerated.
>> > * elfnn-riscv.c (write_uleb128): New function.
>> > (perform_relocation): Perform R_RISCV_SUB_ULEB128 and
>> > R_RISCV_SET_ULEB128 relocation.
>> > (riscv_elf_relocate_section): Likewise.
>> > * elfxx-riscv.c (howto_table): Add R_RISCV_SUB_ULEB128 and
>> > R_RISCV_SET_ULEB128.
>> > (riscv_elf_ignore_reloc): New function.
>> > * libbfd.h: Regenerated.
>> > * reloc.c (BFD_RELOC_RISCV_SET_ULEB128, BFD_RELOC_RISCV_SUB_ULEB128):
>> > New relocations to support .uleb128.
>> >
>> > gas/ChangeLog:
>> > * config/tc-riscv.c (md_apply_fix): Add BFD_RELOC_RISCV_SET_ULEB128 and
>> > BFD_RELOC_RISCV_SUB_ULEB128.
>> > (riscv_insert_uleb128_fixes): New function.
>> > (riscv_md_end): Scan rs_leb128 fragments.
>> > (riscv_pseudo_table): Remove uleb128.
>> >
>> > include/ChangeLog:
>> > * elf/riscv.h ((R_RISCV_SET_ULEB128, (R_RISCV_SUB_ULEB128): Define.
>> >
>> > ld/ChangeLog:
>> > * testsuite/ld-riscv-elf/ld-riscv-elf.exp: Add uleb128.
>> > * testsuite/ld-riscv-elf/uleb128.d: New test.
>> > * testsuite/ld-riscv-elf/uleb128.s: New file.
>> >
>> > OK to commit?
>>
>> I'm having a lot of trouble trying to figure out how this works.  LMK if I'm
>> missing something, there's some comments in line:
>>
>> > From 9f7f0aaa484dee2b32c550f8cca4de18959f01e1 Mon Sep 17 00:00:00 2001
>> > From: Kuan-Lin Chen <rufus@andestech.com>
>> > Date: Thu, 14 Nov 2019 14:24:22 +0800
>> > Subject: [PATCH] RISC-V: Support subtraction of .uleb128.
>> >
>> > The data length of uleb128 is variable.  So linker must recalculate the
>> > value of the subtraction.  The patch leave relocations in object files
>> > so that linker can relocate again after relaxation.
>> >
>> > bfd/ChangeLog:
>> >         * bfd-in2.h: Regenerated.
>> >         * elfnn-riscv.c (write_uleb128): New function.
>> >         (perform_relocation): Perform R_RISCV_SUB_ULEB128 and
>> >          R_RISCV_SET_ULEB128 relocation.
>> >         (riscv_elf_relocate_section): Likewise.
>> >         * elfxx-riscv.c (howto_table): Add R_RISCV_SUB_ULEB128 and
>> >         R_RISCV_SET_ULEB128.
>> >         (riscv_elf_ignore_reloc): New function.
>> >         * libbfd.h: Regenerated.
>> >         * reloc.c (BFD_RELOC_RISCV_SET_ULEB128, BFD_RELOC_RISCV_SUB_ULEB128):
>> >         New relocations to support .uleb128.
>> >
>> > gas/ChangeLog:
>> >         * config/tc-riscv.c (md_apply_fix): Add BFD_RELOC_RISCV_SET_ULEB128 and
>> >         BFD_RELOC_RISCV_SUB_ULEB128.
>> >         (riscv_insert_uleb128_fixes): New function.
>> >         (riscv_md_end): Scan rs_leb128 fragments.
>> >         (riscv_pseudo_table): Remove uleb128.
>> >
>> > include/ChangeLog:
>> >         * elf/riscv.h ((R_RISCV_SET_ULEB128, (R_RISCV_SUB_ULEB128): Define.
>> >
>> > ld/ChangeLog:
>> >         * testsuite/ld-riscv-elf/ld-riscv-elf.exp: Add uleb128.
>> >         * testsuite/ld-riscv-elf/uleb128.d: New test.
>> >         * testsuite/ld-riscv-elf/uleb128.s: New file.
>> > ---
>> >  bfd/ChangeLog                              | 14 ++++
>> >  bfd/bfd-in2.h                              |  2 +
>> >  bfd/elfnn-riscv.c                          | 82 ++++++++++++++++++++++
>> >  bfd/elfxx-riscv.c                          | 51 ++++++++++++++
>> >  bfd/libbfd.h                               |  2 +
>> >  bfd/reloc.c                                |  4 ++
>> >  gas/ChangeLog                              |  8 +++
>> >  gas/config/tc-riscv.c                      | 47 ++++++++++++-
>> >  include/ChangeLog                          |  4 ++
>> >  include/elf/riscv.h                        |  2 +
>> >  ld/ChangeLog                               |  6 ++
>> >  ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp |  1 +
>> >  ld/testsuite/ld-riscv-elf/uleb128.d        | 18 +++++
>> >  ld/testsuite/ld-riscv-elf/uleb128.s        | 18 +++++
>> >  14 files changed, 258 insertions(+), 1 deletion(-)
>> >  create mode 100644 ld/testsuite/ld-riscv-elf/uleb128.d
>> >  create mode 100644 ld/testsuite/ld-riscv-elf/uleb128.s
>> >
>> > diff --git a/bfd/ChangeLog b/bfd/ChangeLog
>> > index 4a0852e577..d11ffde74c 100644
>> > --- a/bfd/ChangeLog
>> > +++ b/bfd/ChangeLog
>> > @@ -1,3 +1,17 @@
>> > +2019-11-27  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
>> > +
>> > +        * bfd-in2.h: Regenerated.
>> > +        * elfnn-riscv.c (write_uleb128): New function.
>> > +        (perform_relocation): Perform R_RISCV_SUB_ULEB128 and
>> > +         R_RISCV_SET_ULEB128 relocation.
>> > +        (riscv_elf_relocate_section): Likewise.
>> > +        * elfxx-riscv.c (howto_table): Add R_RISCV_SUB_ULEB128 and
>> > +        R_RISCV_SET_ULEB128.
>> > +        (riscv_elf_ignore_reloc): New function.
>> > +        * libbfd.h: Regenerated.
>> > +        * reloc.c (BFD_RELOC_RISCV_SET_ULEB128, BFD_RELOC_RISCV_SUB_ULEB128):
>> > +        New relocations to support .uleb128.
>> > +
>> >  2019-11-27  Alan Modra  <amodra@gmail.com>
>> >
>> >          PR 23652
>> > diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
>> > index 44902fc8d0..a32708ebc2 100644
>> > --- a/bfd/bfd-in2.h
>> > +++ b/bfd/bfd-in2.h
>> > @@ -4380,6 +4380,8 @@ number for the SBIC, SBIS, SBI and CBI instructions  */
>> >    BFD_RELOC_RISCV_SET16,
>> >    BFD_RELOC_RISCV_SET32,
>> >    BFD_RELOC_RISCV_32_PCREL,
>> > +  BFD_RELOC_RISCV_SET_ULEB128,
>> > +  BFD_RELOC_RISCV_SUB_ULEB128,
>> >
>> >  /* Renesas RL78 Relocations.  */
>> >    BFD_RELOC_RL78_NEG8,
>> > diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
>> > index 997f786602..075ef6b82d 100644
>> > --- a/bfd/elfnn-riscv.c
>> > +++ b/bfd/elfnn-riscv.c
>> > @@ -1419,6 +1419,26 @@ riscv_global_pointer_value (struct bfd_link_info *info)
>> >    return h->u.def.value + sec_addr (h->u.def.section);
>> >  }
>> >
>> > +/* Write VAL in uleb128 format to P, returning a pointer to the
>> > +   following byte.
>> > +   This code is copied from elf-attr.c.  */
>> > +
>> > +static bfd_byte *
>> > +write_uleb128 (bfd_byte *p, unsigned int val)
>> > +{
>> > +  bfd_byte c;
>> > +  do
>> > +    {
>> > +      c = val & 0x7f;
>> > +      val >>= 7;
>> > +      if (val)
>> > +        c |= 0x80;
>> > +      *(p++) = c;
>> > +    }
>> > +  while (val);
>> > +  return p;
>> > +}
>> > +
>> >  /* Emplace a static relocation.  */
>> >
>> >  static bfd_reloc_status_type
>> > @@ -1512,6 +1532,25 @@ perform_relocation (const reloc_howto_type *howto,
>> >          value = ENCODE_RVC_LUI_IMM (RISCV_CONST_HIGH_PART (value));
>> >        break;
>> >
>> > +    case R_RISCV_SET_ULEB128:
>> > +    case R_RISCV_SUB_ULEB128:
>> > +      {
>> > +        unsigned int len = 0;
>> > +        bfd_byte *endp, *p;
>> > +
>> > +        _bfd_read_unsigned_leb128 (input_bfd, contents + rel->r_offset, &len);
>> > +
>> > +        /* Clean the contents value to zero.  Do not reduce the length.  */
>> > +        p = contents + rel->r_offset;
>> > +        endp = p + len -1;
>> > +        memset (p, 0x80, len);
>> > +        *(endp) = 0;
>> > +        p = write_uleb128 (p, value) - 1;
>> > +        if (p < endp)
>> > +          *p |= 0x80;
>> > +        return bfd_reloc_ok;
>> > +      }
>> > +
>> >      case R_RISCV_32:
>> >      case R_RISCV_64:
>> >      case R_RISCV_ADD8:
>> > @@ -1767,6 +1806,8 @@ riscv_elf_relocate_section (bfd *output_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;
>> > +  bfd_vma uleb128_vma;
>> > +  Elf_Internal_Rela *uleb128_rel = NULL;
>> >
>> >    if (!riscv_init_pcrel_relocs (&pcrel_relocs))
>> >      return FALSE;
>> > @@ -1871,6 +1912,47 @@ riscv_elf_relocate_section (bfd *output_bfd,
>> >          case R_RISCV_DELETE:
>> >            /* These require no special handling beyond perform_relocation.  */
>> >            break;
>> > +        case R_RISCV_SET_ULEB128:
>> > +          if (!uleb128_rel)
>> > +            {
>> > +              /* Save the minuend to use later.  */
>> > +              uleb128_vma = relocation;
>> > +              uleb128_rel = rel;
>> > +              continue;
>> > +            }
>> > +          else
>> > +            {
>> > +              if (uleb128_rel->r_offset != rel->r_offset)
>> > +                {
>> > +                  (*_bfd_error_handler) (_("%pB: relocation %s mismatched. "),
>> > +                                         input_bfd, howto->name);
>> > +                  bfd_set_error (bfd_error_bad_value);
>> > +                }
>> > +              relocation = relocation - uleb128_vma;
>> > +              uleb128_rel = NULL;
>> > +              break;
>> > +            }
>> > +
>> > +        case R_RISCV_SUB_ULEB128:
>> > +          if (uleb128_rel)
>> > +            {
>> > +              if (uleb128_rel->r_offset != rel->r_offset)
>> > +                {
>> > +                  (*_bfd_error_handler) (_("%pB: relocation %s mismatched. "),
>> > +                                         input_bfd, howto->name);
>> > +                  bfd_set_error (bfd_error_bad_value);
>> > +                }
>> > +              relocation = uleb128_vma - relocation;
>>
>> GCC gives me -Wmaybe-uninitialized for both of these.
>>
>> > +              uleb128_rel = NULL;
>> > +              break;
>> > +            }
>> > +          else
>> > +            {
>> > +              /* Save the subtrahend to use later.  */
>> > +              uleb128_vma = relocation;
>> > +              uleb128_rel = rel;
>> > +              continue;
>> > +            }
>> >
>> >          case R_RISCV_GOT_HI20:
>> >            if (h != NULL)
>> > diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c
>> > index 245717f70f..c136ba2207 100644
>> > --- a/bfd/elfxx-riscv.c
>> > +++ b/bfd/elfxx-riscv.c
>> > @@ -38,6 +38,8 @@
>> >     relocations for the debug info.  */
>> >  static bfd_reloc_status_type riscv_elf_add_sub_reloc
>> >    (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
>> > +static bfd_reloc_status_type riscv_elf_ignore_reloc
>> > +  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
>> >
>> >  /* The relocation table used for SHT_RELA sections.  */
>> >
>> > @@ -855,8 +857,41 @@ static reloc_howto_type howto_table[] =
>> >           0,                                /* src_mask */
>> >           MINUS_ONE,                        /* dst_mask */
>> >           FALSE),                        /* pcrel_offset */
>> > +
>> > +  /* The length of unsigned-leb128 is variant, just assume the
>> > +     size is one byte here.  */
>> > +  HOWTO (R_RISCV_SET_ULEB128,                /* type */
>> > +         0,                                /* rightshift */
>> > +         0,                                /* size */
>> > +         0,                                /* bitsize */
>> > +         FALSE,                                /* pc_relative */
>> > +         0,                                /* bitpos */
>> > +         complain_overflow_dont,        /* complain_on_overflow */
>> > +         riscv_elf_ignore_reloc,        /* special_function */
>> > +         "R_RISCV_SET_ULEB128",                /* name */
>> > +         FALSE,                                /* partial_inplace */
>> > +         0,                                /* src_mask */
>> > +         0,                                /* dst_mask */
>> > +         FALSE),                        /* pcrel_offset */
>>
>> I don't understand how this could possibly work: uleb128s can be long, so we
>> can't just treat them as a single byte.  I'm having trouble testing it, though,
>> as I can't figure out how to emit R_RISCV_SET_ULEB128 alone.  For example, when
>> I try to insert a uleb128 in the assembler I'm not even getting a relocation:
>>
>>     .text
>>     .globl _start
>>     _start:
>>             nop
>>     .L0:
>>             nop
>>     .L1:
>>     uleb_l0:
>>             addi x0, x0, 1
>>             .uleb128 .L0
>>             # Manually fix up the alignment, as .align is broken.
>>             .rept 3
>>             .byte 0xAA
>>             .endr
>>             addi x0, x0, 2
>>
>>     $ objdump -dr
>>     test.o:     file format elf64-littleriscv
>>
>>
>>     Disassembly of section .text:
>>
>>     0000000000000000 <_start>:
>>        0:   00000013                nop
>>        4:   00000013                nop
>>
>>     0000000000000008 <uleb_l0>:
>>        8:   00100013                li      zero,1
>>        c:   aa04                    fsd     fs1,16(a2)
>>        e:   aaaa                    fsd     fa0,336(sp)
>>       10:   00200013                li      zero,2
>>
>> so then when I link I'm just getting the wrong value entirely.
>>
>>     test:     file format elf64-littleriscv
>>
>>
>>     Disassembly of section .text:
>>
>>     0000000000010078 <_start>:
>>        10078:       00000013                nop
>>        1007c:       00000013                nop
>>
>>     0000000000010080 <uleb_l0>:
>>        10080:       00100013                li      zero,1
>>        10084:       aa04                    fsd     fs1,16(a2)
>>        10086:       aaaa                    fsd     fa0,336(sp)
>>        10088:       00200013                li      zero,2
>>
>> > +  /* The length of unsigned-leb128 is variant, just assume the
>> > +     size is one byte here.  */
>> > +  HOWTO (R_RISCV_SUB_ULEB128,                /* type */
>> > +         0,                                /* rightshift */
>> > +         0,                                /* size */
>> > +         0,                                /* bitsize */
>> > +         FALSE,                                /* pc_relative */
>> > +         0,                                /* bitpos */
>> > +         complain_overflow_dont,        /* complain_on_overflow */
>> > +         riscv_elf_ignore_reloc,        /* special_function */
>> > +         "R_RISCV_SUB_ULEB128",                /* name */
>> > +         FALSE,                                /* partial_inplace */
>> > +         0,                                /* src_mask */
>> > +         0,                                /* dst_mask */
>> > +         FALSE),                        /* pcrel_offset */
>> >  };
>>
>> I can get a R_RISCV_SUB_ULEB128, but it appears to be both producing the wrong
>> value and garbaging up bytes after the relocation.  For example:
>>
>>     .text
>>     .globl _start
>>     _start:
>>             nop
>>     .L0:
>>             nop
>>     .L1:
>>     uleb_l1_l0:
>>             addi x0, x0, 1
>>             .uleb128 .L1 - .L0
>>             # Manually fix up the alignment, as .align is broken
>>             .rept 3
>>             .byte 0xAA
>>             .endr
>>             addi x0, x0, 2
>>
>> produces the relocation
>>
>>     test.o:     file format elf64-littleriscv
>>
>>
>>     Disassembly of section .text:
>>
>>     0000000000000000 <_start>:
>>        0:   00000013                nop
>>
>>     0000000000000004 <.L0>:
>>        4:   00000013                nop
>>
>>     0000000000000008 <uleb_l1_l0>:
>>        8:   00100013                li      zero,1
>>        c:   aa04                    fsd     fs1,16(a2)
>>                             c: R_RISCV_SET_ULEB128  .L1
>>                             c: R_RISCV_SUB_ULEB128  .L0
>>        e:   aaaa                    fsd     fa0,336(sp)
>>       10:   00200013                li      zero,2
>>
>> but then goes and corrupts the resulting executable
>>
>>
>>     test:     file format elf64-littleriscv
>>     Disassembly of section .text:
>>
>>     0000000000010078 <_start>:
>>        10078:       00000013                nop
>>        1007c:       00000013                nop
>>
>>     0000000000010080 <uleb_l1_l0>:
>>        10080:       00100013                li      zero,1
>>        10084:       ff84                    sd      s1,56(a5)
>>        10086:       000ffffb                0xffffb
>>        1008a:       0020                    addi    s0,sp,8
>>
>> I can't think of a way to make this work aside from just emitting uleb128s at
>> their full length, which would make them work but would really defeat the
>> purpose of the format.  I guess we could then relax these, but that seems like
>> a lot of work.
>>
>> > +
>> >  /* A mapping from BFD reloc types to RISC-V ELF reloc types.  */
>> >
>> >  struct elf_reloc_map
>> > @@ -917,6 +952,8 @@ static const struct elf_reloc_map riscv_reloc_map[] =
>> >    { 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_SET_ULEB128, R_RISCV_SET_ULEB128 },
>> > +  { BFD_RELOC_RISCV_SUB_ULEB128, R_RISCV_SUB_ULEB128 },
>> >  };
>> >
>> >  /* Given a BFD reloc type, return a howto structure.  */
>> > @@ -1011,6 +1048,20 @@ riscv_elf_add_sub_reloc (bfd *abfd,
>> >    return bfd_reloc_ok;
>> >  }
>> >
>> > +/* Special handler for relocations which don't have to be relocated.
>> > +   This function just simply return bfd_reloc_ok.  */
>> > +static bfd_reloc_status_type
>> > +riscv_elf_ignore_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry,
>> > +                        asymbol *symbol ATTRIBUTE_UNUSED,
>> > +                        void *data ATTRIBUTE_UNUSED, asection *input_section,
>> > +                        bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED)
>> > +{
>> > +  if (output_bfd != NULL)
>> > +    reloc_entry->address += input_section->output_offset;
>> > +
>> > +  return bfd_reloc_ok;
>> > +}
>> > +
>> >  /* Parsing subset version.
>> >
>> >     Return Value:
>> > diff --git a/bfd/libbfd.h b/bfd/libbfd.h
>> > index 77b732ee4b..7aa8f91504 100644
>> > --- a/bfd/libbfd.h
>> > +++ b/bfd/libbfd.h
>> > @@ -2327,6 +2327,8 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
>> >    "BFD_RELOC_RISCV_SET16",
>> >    "BFD_RELOC_RISCV_SET32",
>> >    "BFD_RELOC_RISCV_32_PCREL",
>> > +  "BFD_RELOC_RISCV_SET_ULEB128",
>> > +  "BFD_RELOC_RISCV_SUB_ULEB128",
>> >    "BFD_RELOC_RL78_NEG8",
>> >    "BFD_RELOC_RL78_NEG16",
>> >    "BFD_RELOC_RL78_NEG24",
>> > diff --git a/bfd/reloc.c b/bfd/reloc.c
>> > index b00b79f319..9b8b75ad21 100644
>> > --- a/bfd/reloc.c
>> > +++ b/bfd/reloc.c
>> > @@ -5212,6 +5212,10 @@ ENUMX
>> >    BFD_RELOC_RISCV_SET32
>> >  ENUMX
>> >    BFD_RELOC_RISCV_32_PCREL
>> > +ENUMX
>> > +  BFD_RELOC_RISCV_SET_ULEB128
>> > +ENUMX
>> > +  BFD_RELOC_RISCV_SUB_ULEB128
>> >  ENUMDOC
>> >    RISC-V relocations.
>> >
>> > diff --git a/gas/ChangeLog b/gas/ChangeLog
>> > index 09991524da..e53ac0895b 100644
>> > --- a/gas/ChangeLog
>> > +++ b/gas/ChangeLog
>> > @@ -1,3 +1,11 @@
>> > +2019-11-27  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
>> > +
>> > +        * config/tc-riscv.c (md_apply_fix): Add BFD_RELOC_RISCV_SET_ULEB128 and
>> > +        BFD_RELOC_RISCV_SUB_ULEB128.
>> > +        (riscv_insert_uleb128_fixes): New function.
>> > +        (riscv_md_end): Scan rs_leb128 fragments.
>> > +        (riscv_pseudo_table): Remove uleb128.
>> > +
>> >  2019-11-25  Andrew Pinski  <apinski@marvell.com>
>> >
>> >          * config/tc-aarch64.c (md_begin): Use correct
>> > diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
>> > index e50505138e..c35c591c0a 100644
>> > --- a/gas/config/tc-riscv.c
>> > +++ b/gas/config/tc-riscv.c
>> > @@ -2392,6 +2392,9 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
>> >      case BFD_RELOC_RISCV_SUB32:
>> >      case BFD_RELOC_RISCV_SUB64:
>> >      case BFD_RELOC_RISCV_RELAX:
>> > +    /* cvt_frag_to_fill () has called output_leb128 ().  */
>> > +    case BFD_RELOC_RISCV_SET_ULEB128:
>> > +    case BFD_RELOC_RISCV_SUB_ULEB128:
>> >        break;
>> >
>> >      case BFD_RELOC_RISCV_TPREL_HI20:
>> > @@ -3127,11 +3130,54 @@ riscv_set_public_attributes (void)
>> >      riscv_write_out_arch_attr ();
>> >  }
>> >
>> > +/* Scan uleb128 subtraction expressions and insert fixups for them.
>> > +   e.g., .uleb128 .L1 - .L0
>> > +   Becuase relaxation may change the value of the subtraction, we
>> > +   must resolve them in link-time.  */
>> > +
>> > +static void
>> > +riscv_insert_uleb128_fixes (bfd *abfd ATTRIBUTE_UNUSED,
>> > +                            asection *sec, void *xxx ATTRIBUTE_UNUSED)
>> > +{
>> > +  segment_info_type *seginfo = seg_info (sec);
>> > +  struct frag *fragP;
>> > +
>> > +  subseg_set (sec, 0);
>> > +
>> > +  for (fragP = seginfo->frchainP->frch_root;
>> > +       fragP; fragP = fragP->fr_next)
>> > +    {
>> > +      expressionS *exp, *exp_dup;
>> > +
>> > +      if (fragP->fr_type != rs_leb128  || fragP->fr_symbol == NULL)
>> > +        continue;
>> > +
>> > +      exp = symbol_get_value_expression (fragP->fr_symbol);
>> > +
>> > +      if (exp->X_op != O_subtract)
>> > +        continue;
>>
>> Presumably that's why I can't get a _SET alone.
>>
>> > +
>> > +      /* Only unsigned leb128 can be handle.  */
>> > +      gas_assert (fragP->fr_subtype == 0);
>> > +      exp_dup = xmemdup (exp, sizeof (*exp), sizeof (*exp));
>> > +      exp_dup->X_op = O_symbol;
>> > +      exp_dup->X_op_symbol = NULL;
>> > +
>> > +      /* Insert relocations to resolve the subtraction in link-time.  */
>> > +      fix_new_exp (fragP, fragP->fr_fix, 0,
>> > +                   exp_dup, 0, BFD_RELOC_RISCV_SET_ULEB128);
>> > +      exp_dup->X_add_symbol = exp->X_op_symbol;
>> > +      fix_new_exp (fragP, fragP->fr_fix, 0,
>> > +                   exp_dup, 0, BFD_RELOC_RISCV_SUB_ULEB128);
>> > +    }
>> > +}
>> > +
>> >  /* Called after all assembly has been done.  */
>> >
>> >  void
>> >  riscv_md_end (void)
>> >  {
>> > +  bfd_map_over_sections (stdoutput, riscv_insert_uleb128_fixes, NULL);
>> >    riscv_set_public_attributes ();
>> >  }
>> >
>> > @@ -3215,7 +3261,6 @@ static const pseudo_typeS riscv_pseudo_table[] =
>> >    {"dtprelword", s_dtprel, 4},
>> >    {"dtpreldword", s_dtprel, 8},
>> >    {"bss", s_bss, 0},
>> > -  {"uleb128", s_riscv_leb128, 0},
>> >    {"sleb128", s_riscv_leb128, 1},
>> >    {"insn", s_riscv_insn, 0},
>> >    {"attribute", s_riscv_attribute, 0},
>> > diff --git a/include/ChangeLog b/include/ChangeLog
>> > index 47bb86cf71..c290b245c6 100644
>> > --- a/include/ChangeLog
>> > +++ b/include/ChangeLog
>> > @@ -1,3 +1,7 @@
>> > +2019-11-27  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
>> > +
>> > +        * elf/riscv.h ((R_RISCV_SET_ULEB128, (R_RISCV_SUB_ULEB128): Define.
>> > +
>> >  2019-11-25  Alan Modra  <amodra@gmail.com>
>> >
>> >          * coff/ti.h (GET_SCNHDR_SIZE, PUT_SCNHDR_SIZE, GET_SCN_SCNLEN),
>> > diff --git a/include/elf/riscv.h b/include/elf/riscv.h
>> > index 2f98aa4a3e..030679b35f 100644
>> > --- a/include/elf/riscv.h
>> > +++ b/include/elf/riscv.h
>> > @@ -88,6 +88,8 @@ START_RELOC_NUMBERS (elf_riscv_reloc_type)
>> >    RELOC_NUMBER (R_RISCV_SET16, 55)
>> >    RELOC_NUMBER (R_RISCV_SET32, 56)
>> >    RELOC_NUMBER (R_RISCV_32_PCREL, 57)
>> > +  RELOC_NUMBER (R_RISCV_SET_ULEB128, 58)
>> > +  RELOC_NUMBER (R_RISCV_SUB_ULEB128, 59)
>> >  END_RELOC_NUMBERS (R_RISCV_max)
>> >
>> >  /* Processor specific flags for the ELF header e_flags field.  */
>> > diff --git a/ld/ChangeLog b/ld/ChangeLog
>> > index 969ab78035..5c2e406101 100644
>> > --- a/ld/ChangeLog
>> > +++ b/ld/ChangeLog
>> > @@ -1,3 +1,9 @@
>> > +2019-11-27  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
>> > +
>> > +        * testsuite/ld-riscv-elf/ld-riscv-elf.exp: Add uleb128.
>> > +        * testsuite/ld-riscv-elf/uleb128.d: New test.
>> > +        * testsuite/ld-riscv-elf/uleb128.s: New file.
>> > +
>> >  2019-11-26  Martin Liska  <mliska@suse.cz>
>> >
>> >          * scripttempl/arclinux.sc: Add .text.sorted.* which is sorted
>> > diff --git a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
>> > index 7aabbdd641..809e40f08d 100644
>> > --- a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
>> > +++ b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
>> > @@ -38,6 +38,7 @@ if [istarget "riscv*-*-*"] {
>> >      run_dump_test "attr-merge-priv-spec"
>> >      run_dump_test "attr-merge-arch-failed-01"
>> >      run_dump_test "attr-merge-stack-align-failed"
>> > +    run_dump_test "uleb128"
>> >      run_ld_link_tests {
>> >          { "Weak reference 32" "-T weakref.ld -melf32lriscv" ""
>> >              "-march=rv32i -mabi=ilp32" {weakref32.s}
>> > diff --git a/ld/testsuite/ld-riscv-elf/uleb128.d b/ld/testsuite/ld-riscv-elf/uleb128.d
>> > new file mode 100644
>> > index 0000000000..a921478e98
>> > --- /dev/null
>> > +++ b/ld/testsuite/ld-riscv-elf/uleb128.d
>> > @@ -0,0 +1,18 @@
>> > +#source: uleb128.s
>> > +#as: -march=rv32ic
>> > +#ld: -melf32lriscv
>> > +#objdump: -d
>> > +
>> > +.*:[         ]+file format .*
>> > +
>> > +Disassembly of section .text:
>> > +
>> > +.* <_start>:
>> > +.*jal.*<bar>
>> > +.*jal.*<bar>
>> > +.*jal.*<bar>
>> > +.*jal.*<bar>
>> > +.*jal.*<bar>
>> > +.*jal.*<bar>
>> > +.*:[         ]+0e0c.*
>> > +#pass
>> > diff --git a/ld/testsuite/ld-riscv-elf/uleb128.s b/ld/testsuite/ld-riscv-elf/uleb128.s
>> > new file mode 100644
>> > index 0000000000..f7d23be163
>> > --- /dev/null
>> > +++ b/ld/testsuite/ld-riscv-elf/uleb128.s
>> > @@ -0,0 +1,18 @@
>> > +.text
>> > +.globl bar
>> > +.globl _start
>> > +.option rvc
>> > +.align 2
>> > +_start:
>> > +.L0:
>> > +        .rept 6
>> > +        call bar
>> > +        .endr
>> > +.align 2
>> > +.L1:
>> > +        .uleb128 .L1 - .L0
>> > +        .uleb128 .L2 - .L0
>> > +.L2:
>> > +.align 2
>> > +bar:
>> > +        nop
>>
>> It looks like alignment is broken here after uleb128s, but it's not actually
>> triggering an error in all cases.  Having two of them in this test case doesn't
>> trigger the issue, but an odd number does.  For example, the following source
>>
>>     .text
>>     .globl _start
>>     .align 2
>>     _start:
>>             .uleb128 _start
>>     .align 2
>>     _end:
>>             nop
>>
>> links _end to a misaligned symbol
>>
>>     Disassembly of section .text:
>>
>>     0000000000010078 <_start>:
>>             ...
>>
>>     0000000000010079 <_end>:
>>        10079:       00000013                nop
>>        1007d:       0000                    unimp
>>             ...
>>
>> I'm assuming that's because norvc assumes 4-byte alignment in text sections, so
>> it's just eliding the alingment directives.  With RVC I do get an error message
>>
>>     .text
>>     .globl _start
>>     .option rvc
>>     .align 2
>>     _start:
>>             .uleb128 _start
>>     .align 2
>>     _end:
>>             nop
>>
>>     ./install/bin/riscv64-unknown-linux-gnu-ld: test.o(.text+0x1): 3 bytes required for alignment to 4-byte boundary, but only 2 present
>>     ./install/bin/riscv64-unknown-linux-gnu-ld: can't relax section: bad value
>>
>>
>
>
> -- 
> Best regards,
> Kuan-Lin Chen.
> kuanlinchentw@gmail.com

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] [RISCV] Support subtraction of .uleb128.
  2020-01-09 23:20   ` Palmer Dabbelt via binutils
@ 2020-01-22  7:26     ` Kuan-Lin Chen
  2020-09-25  7:14       ` Kito Cheng
  0 siblings, 1 reply; 17+ messages in thread
From: Kuan-Lin Chen @ 2020-01-22  7:26 UTC (permalink / raw)
  To: Palmer Dabbelt; +Cc: binutils@sourceware.org Development

[-- Attachment #1: Type: text/plain, Size: 33531 bytes --]

Hi,

This version patch updates as follows:
Fix the warning about uninitialized variable.
Set a limit to .uleb128 expressions as Palmer's suggestion.
Thanks.

Palmer Dabbelt <palmerdabbelt@google.com> 於 2020年1月10日 週五 上午7:19寫道:
>
> On Mon, 09 Dec 2019 21:42:58 PST (-0800), kuanlinchentw@gmail.com wrote:
> > Hi Palmer,
> >
> >> GCC gives me -Wmaybe-uninitialized for both of these.
> > May I know your gcc version?
> > I tried gcc-7.3.0 and gcc-8.2.0, and I didn't get the warning.
>
> $ gcc --version
> gcc (Debian 8.3.0-6) 8.3.0
> Copyright (C) 2018 Free Software Foundation, Inc.
> This is free software; see the source for copying conditions.  There is NO
> warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
>
> >> I don't understand how this could possibly work: uleb128s can be long, so we
> >> can't just treat them as a single byte.
> > Yes, uleb128s can be long so I implement riscv_elf_ignore_reloc to
> > ignore the overflow checking.
> > And I relocate uleb128s by myself in perform_relocation.
> >
> >> I'm having trouble testing it, though,
> >> as I can't figure out how to emit R_RISCV_SET_ULEB128 alone.  For example, when
> >> I try to insert a uleb128 in the assembler I'm not even getting a relocation:
> > .uleb128 only support subtract format. (.uleb128 .L1 - .L0)
> > It is impossible to get final the value and the length for ".uleb128
> > symbol" in assemble-time.
>
> Well, you know symbols are at most 64-bit on rv64 and 32-bit on rv32, so you
> can just emit enough space to encode any symbol.  That's better than emitting 7
> bits, which is unlikely to encode any symbol.
>
> > I think ".uleb128 symbol" is meaningless.
> > Therefore, all targets just fill the value as assemble-time value
> > without relocations.
>
> If the assembler can't handle something then it needs to provide an error, it
> can't just generate incorrect code.
>
> >>I can get a R_RISCV_SUB_ULEB128, but it appears to be both producing the wrong
> >>value and garbaging up bytes after the relocation.  For example:
> >
> > I get the same result in the object file but the different result in executable.
> > pal.o:     file format elf64-littleriscv
> >
> > Disassembly of section .text:
> >
> > 0000000000000000 <_start>:
> >    0:   00000013                nop
> >
> > 0000000000000004 <.L0>:
> >    4:   00000013                nop
> >
> > 0000000000000008 <uleb_l1_l0>:
> >    8:   00100013                li      zero,1
> >    c:   aa04                    fsd     fs1,16(a2)
> >                         c: R_RISCV_SET_ULEB128  .L1
> >                         c: R_RISCV_SUB_ULEB128  .L0
> >    e:   aaaa                    fsd     fa0,336(sp)
> >   10:   00200013                li      zero,2
> >
> >
> > a.out:     file format elf64-littleriscv
> >
> >
> > Disassembly of section .text:
> >
> > 0000000000010078 <_start>:
> >    10078:       00000013                nop
> >    1007c:       00000013                nop
> >
> > 0000000000010080 <uleb_l1_l0>:
> >    10080:       00100013                li      zero,1
> >    10084:       aa04                    fsd     fs1,16(a2)
> >    10086:       aaaa                    fsd     fa0,336(sp)
> >    10088:       00200013                li      zero,2
> >
> > Maybe there is something mismatched. But I don't have any idea currently.
> > Could you please give me more information about your flow?
>
> IIRC I just applied the patch on top of whatever was HEAD of binutils-gdb at
> the time, but I don't have the working directory around any more.
>
> > Thanks.
> >
> >> Presumably that's why I can't get a _SET alone.
> > I think it's meaningless to use _SET alone in assembly.
> >
> >> It looks like alignment is broken here after uleb128s, but it's not actually
> >> triggering an error in all cases.  Having two of them in this test case doesn't
> >> trigger the issue, but an odd number does.  For example, the following source
> > I think this alignment issue can be fixed by the following patch:
> > https://sourceware.org/ml/binutils/2019-12/msg00024.html
>
> Ya, thanks -- I think there's some issues there as well, IIRC I commented on
> it.
>
> >
> > Thanks for your review.
> >
> > Palmer Dabbelt <palmerdabbelt@google.com> 於 2019年12月7日 週六 上午7:47寫道:
> >>
> >> On Wed, 27 Nov 2019 00:11:50 PST (-0800), kuanlinchentw@gmail.com wrote:
> >> > The data length of uleb128 is variable.  So linker must recalculate the
> >> > value of the subtraction.  The patch leave relocations in object files
> >> > so that linker can relocate again after relaxation.
> >> >
> >> > bfd/ChangeLog:
> >> > * bfd-in2.h: Regenerated.
> >> > * elfnn-riscv.c (write_uleb128): New function.
> >> > (perform_relocation): Perform R_RISCV_SUB_ULEB128 and
> >> > R_RISCV_SET_ULEB128 relocation.
> >> > (riscv_elf_relocate_section): Likewise.
> >> > * elfxx-riscv.c (howto_table): Add R_RISCV_SUB_ULEB128 and
> >> > R_RISCV_SET_ULEB128.
> >> > (riscv_elf_ignore_reloc): New function.
> >> > * libbfd.h: Regenerated.
> >> > * reloc.c (BFD_RELOC_RISCV_SET_ULEB128, BFD_RELOC_RISCV_SUB_ULEB128):
> >> > New relocations to support .uleb128.
> >> >
> >> > gas/ChangeLog:
> >> > * config/tc-riscv.c (md_apply_fix): Add BFD_RELOC_RISCV_SET_ULEB128 and
> >> > BFD_RELOC_RISCV_SUB_ULEB128.
> >> > (riscv_insert_uleb128_fixes): New function.
> >> > (riscv_md_end): Scan rs_leb128 fragments.
> >> > (riscv_pseudo_table): Remove uleb128.
> >> >
> >> > include/ChangeLog:
> >> > * elf/riscv.h ((R_RISCV_SET_ULEB128, (R_RISCV_SUB_ULEB128): Define.
> >> >
> >> > ld/ChangeLog:
> >> > * testsuite/ld-riscv-elf/ld-riscv-elf.exp: Add uleb128.
> >> > * testsuite/ld-riscv-elf/uleb128.d: New test.
> >> > * testsuite/ld-riscv-elf/uleb128.s: New file.
> >> >
> >> > OK to commit?
> >>
> >> I'm having a lot of trouble trying to figure out how this works.  LMK if I'm
> >> missing something, there's some comments in line:
> >>
> >> > From 9f7f0aaa484dee2b32c550f8cca4de18959f01e1 Mon Sep 17 00:00:00 2001
> >> > From: Kuan-Lin Chen <rufus@andestech.com>
> >> > Date: Thu, 14 Nov 2019 14:24:22 +0800
> >> > Subject: [PATCH] RISC-V: Support subtraction of .uleb128.
> >> >
> >> > The data length of uleb128 is variable.  So linker must recalculate the
> >> > value of the subtraction.  The patch leave relocations in object files
> >> > so that linker can relocate again after relaxation.
> >> >
> >> > bfd/ChangeLog:
> >> >         * bfd-in2.h: Regenerated.
> >> >         * elfnn-riscv.c (write_uleb128): New function.
> >> >         (perform_relocation): Perform R_RISCV_SUB_ULEB128 and
> >> >          R_RISCV_SET_ULEB128 relocation.
> >> >         (riscv_elf_relocate_section): Likewise.
> >> >         * elfxx-riscv.c (howto_table): Add R_RISCV_SUB_ULEB128 and
> >> >         R_RISCV_SET_ULEB128.
> >> >         (riscv_elf_ignore_reloc): New function.
> >> >         * libbfd.h: Regenerated.
> >> >         * reloc.c (BFD_RELOC_RISCV_SET_ULEB128, BFD_RELOC_RISCV_SUB_ULEB128):
> >> >         New relocations to support .uleb128.
> >> >
> >> > gas/ChangeLog:
> >> >         * config/tc-riscv.c (md_apply_fix): Add BFD_RELOC_RISCV_SET_ULEB128 and
> >> >         BFD_RELOC_RISCV_SUB_ULEB128.
> >> >         (riscv_insert_uleb128_fixes): New function.
> >> >         (riscv_md_end): Scan rs_leb128 fragments.
> >> >         (riscv_pseudo_table): Remove uleb128.
> >> >
> >> > include/ChangeLog:
> >> >         * elf/riscv.h ((R_RISCV_SET_ULEB128, (R_RISCV_SUB_ULEB128): Define.
> >> >
> >> > ld/ChangeLog:
> >> >         * testsuite/ld-riscv-elf/ld-riscv-elf.exp: Add uleb128.
> >> >         * testsuite/ld-riscv-elf/uleb128.d: New test.
> >> >         * testsuite/ld-riscv-elf/uleb128.s: New file.
> >> > ---
> >> >  bfd/ChangeLog                              | 14 ++++
> >> >  bfd/bfd-in2.h                              |  2 +
> >> >  bfd/elfnn-riscv.c                          | 82 ++++++++++++++++++++++
> >> >  bfd/elfxx-riscv.c                          | 51 ++++++++++++++
> >> >  bfd/libbfd.h                               |  2 +
> >> >  bfd/reloc.c                                |  4 ++
> >> >  gas/ChangeLog                              |  8 +++
> >> >  gas/config/tc-riscv.c                      | 47 ++++++++++++-
> >> >  include/ChangeLog                          |  4 ++
> >> >  include/elf/riscv.h                        |  2 +
> >> >  ld/ChangeLog                               |  6 ++
> >> >  ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp |  1 +
> >> >  ld/testsuite/ld-riscv-elf/uleb128.d        | 18 +++++
> >> >  ld/testsuite/ld-riscv-elf/uleb128.s        | 18 +++++
> >> >  14 files changed, 258 insertions(+), 1 deletion(-)
> >> >  create mode 100644 ld/testsuite/ld-riscv-elf/uleb128.d
> >> >  create mode 100644 ld/testsuite/ld-riscv-elf/uleb128.s
> >> >
> >> > diff --git a/bfd/ChangeLog b/bfd/ChangeLog
> >> > index 4a0852e577..d11ffde74c 100644
> >> > --- a/bfd/ChangeLog
> >> > +++ b/bfd/ChangeLog
> >> > @@ -1,3 +1,17 @@
> >> > +2019-11-27  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
> >> > +
> >> > +        * bfd-in2.h: Regenerated.
> >> > +        * elfnn-riscv.c (write_uleb128): New function.
> >> > +        (perform_relocation): Perform R_RISCV_SUB_ULEB128 and
> >> > +         R_RISCV_SET_ULEB128 relocation.
> >> > +        (riscv_elf_relocate_section): Likewise.
> >> > +        * elfxx-riscv.c (howto_table): Add R_RISCV_SUB_ULEB128 and
> >> > +        R_RISCV_SET_ULEB128.
> >> > +        (riscv_elf_ignore_reloc): New function.
> >> > +        * libbfd.h: Regenerated.
> >> > +        * reloc.c (BFD_RELOC_RISCV_SET_ULEB128, BFD_RELOC_RISCV_SUB_ULEB128):
> >> > +        New relocations to support .uleb128.
> >> > +
> >> >  2019-11-27  Alan Modra  <amodra@gmail.com>
> >> >
> >> >          PR 23652
> >> > diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
> >> > index 44902fc8d0..a32708ebc2 100644
> >> > --- a/bfd/bfd-in2.h
> >> > +++ b/bfd/bfd-in2.h
> >> > @@ -4380,6 +4380,8 @@ number for the SBIC, SBIS, SBI and CBI instructions  */
> >> >    BFD_RELOC_RISCV_SET16,
> >> >    BFD_RELOC_RISCV_SET32,
> >> >    BFD_RELOC_RISCV_32_PCREL,
> >> > +  BFD_RELOC_RISCV_SET_ULEB128,
> >> > +  BFD_RELOC_RISCV_SUB_ULEB128,
> >> >
> >> >  /* Renesas RL78 Relocations.  */
> >> >    BFD_RELOC_RL78_NEG8,
> >> > diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
> >> > index 997f786602..075ef6b82d 100644
> >> > --- a/bfd/elfnn-riscv.c
> >> > +++ b/bfd/elfnn-riscv.c
> >> > @@ -1419,6 +1419,26 @@ riscv_global_pointer_value (struct bfd_link_info *info)
> >> >    return h->u.def.value + sec_addr (h->u.def.section);
> >> >  }
> >> >
> >> > +/* Write VAL in uleb128 format to P, returning a pointer to the
> >> > +   following byte.
> >> > +   This code is copied from elf-attr.c.  */
> >> > +
> >> > +static bfd_byte *
> >> > +write_uleb128 (bfd_byte *p, unsigned int val)
> >> > +{
> >> > +  bfd_byte c;
> >> > +  do
> >> > +    {
> >> > +      c = val & 0x7f;
> >> > +      val >>= 7;
> >> > +      if (val)
> >> > +        c |= 0x80;
> >> > +      *(p++) = c;
> >> > +    }
> >> > +  while (val);
> >> > +  return p;
> >> > +}
> >> > +
> >> >  /* Emplace a static relocation.  */
> >> >
> >> >  static bfd_reloc_status_type
> >> > @@ -1512,6 +1532,25 @@ perform_relocation (const reloc_howto_type *howto,
> >> >          value = ENCODE_RVC_LUI_IMM (RISCV_CONST_HIGH_PART (value));
> >> >        break;
> >> >
> >> > +    case R_RISCV_SET_ULEB128:
> >> > +    case R_RISCV_SUB_ULEB128:
> >> > +      {
> >> > +        unsigned int len = 0;
> >> > +        bfd_byte *endp, *p;
> >> > +
> >> > +        _bfd_read_unsigned_leb128 (input_bfd, contents + rel->r_offset, &len);
> >> > +
> >> > +        /* Clean the contents value to zero.  Do not reduce the length.  */
> >> > +        p = contents + rel->r_offset;
> >> > +        endp = p + len -1;
> >> > +        memset (p, 0x80, len);
> >> > +        *(endp) = 0;
> >> > +        p = write_uleb128 (p, value) - 1;
> >> > +        if (p < endp)
> >> > +          *p |= 0x80;
> >> > +        return bfd_reloc_ok;
> >> > +      }
> >> > +
> >> >      case R_RISCV_32:
> >> >      case R_RISCV_64:
> >> >      case R_RISCV_ADD8:
> >> > @@ -1767,6 +1806,8 @@ riscv_elf_relocate_section (bfd *output_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;
> >> > +  bfd_vma uleb128_vma;
> >> > +  Elf_Internal_Rela *uleb128_rel = NULL;
> >> >
> >> >    if (!riscv_init_pcrel_relocs (&pcrel_relocs))
> >> >      return FALSE;
> >> > @@ -1871,6 +1912,47 @@ riscv_elf_relocate_section (bfd *output_bfd,
> >> >          case R_RISCV_DELETE:
> >> >            /* These require no special handling beyond perform_relocation.  */
> >> >            break;
> >> > +        case R_RISCV_SET_ULEB128:
> >> > +          if (!uleb128_rel)
> >> > +            {
> >> > +              /* Save the minuend to use later.  */
> >> > +              uleb128_vma = relocation;
> >> > +              uleb128_rel = rel;
> >> > +              continue;
> >> > +            }
> >> > +          else
> >> > +            {
> >> > +              if (uleb128_rel->r_offset != rel->r_offset)
> >> > +                {
> >> > +                  (*_bfd_error_handler) (_("%pB: relocation %s mismatched. "),
> >> > +                                         input_bfd, howto->name);
> >> > +                  bfd_set_error (bfd_error_bad_value);
> >> > +                }
> >> > +              relocation = relocation - uleb128_vma;
> >> > +              uleb128_rel = NULL;
> >> > +              break;
> >> > +            }
> >> > +
> >> > +        case R_RISCV_SUB_ULEB128:
> >> > +          if (uleb128_rel)
> >> > +            {
> >> > +              if (uleb128_rel->r_offset != rel->r_offset)
> >> > +                {
> >> > +                  (*_bfd_error_handler) (_("%pB: relocation %s mismatched. "),
> >> > +                                         input_bfd, howto->name);
> >> > +                  bfd_set_error (bfd_error_bad_value);
> >> > +                }
> >> > +              relocation = uleb128_vma - relocation;
> >>
> >> GCC gives me -Wmaybe-uninitialized for both of these.
> >>
> >> > +              uleb128_rel = NULL;
> >> > +              break;
> >> > +            }
> >> > +          else
> >> > +            {
> >> > +              /* Save the subtrahend to use later.  */
> >> > +              uleb128_vma = relocation;
> >> > +              uleb128_rel = rel;
> >> > +              continue;
> >> > +            }
> >> >
> >> >          case R_RISCV_GOT_HI20:
> >> >            if (h != NULL)
> >> > diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c
> >> > index 245717f70f..c136ba2207 100644
> >> > --- a/bfd/elfxx-riscv.c
> >> > +++ b/bfd/elfxx-riscv.c
> >> > @@ -38,6 +38,8 @@
> >> >     relocations for the debug info.  */
> >> >  static bfd_reloc_status_type riscv_elf_add_sub_reloc
> >> >    (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
> >> > +static bfd_reloc_status_type riscv_elf_ignore_reloc
> >> > +  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
> >> >
> >> >  /* The relocation table used for SHT_RELA sections.  */
> >> >
> >> > @@ -855,8 +857,41 @@ static reloc_howto_type howto_table[] =
> >> >           0,                                /* src_mask */
> >> >           MINUS_ONE,                        /* dst_mask */
> >> >           FALSE),                        /* pcrel_offset */
> >> > +
> >> > +  /* The length of unsigned-leb128 is variant, just assume the
> >> > +     size is one byte here.  */
> >> > +  HOWTO (R_RISCV_SET_ULEB128,                /* type */
> >> > +         0,                                /* rightshift */
> >> > +         0,                                /* size */
> >> > +         0,                                /* bitsize */
> >> > +         FALSE,                                /* pc_relative */
> >> > +         0,                                /* bitpos */
> >> > +         complain_overflow_dont,        /* complain_on_overflow */
> >> > +         riscv_elf_ignore_reloc,        /* special_function */
> >> > +         "R_RISCV_SET_ULEB128",                /* name */
> >> > +         FALSE,                                /* partial_inplace */
> >> > +         0,                                /* src_mask */
> >> > +         0,                                /* dst_mask */
> >> > +         FALSE),                        /* pcrel_offset */
> >>
> >> I don't understand how this could possibly work: uleb128s can be long, so we
> >> can't just treat them as a single byte.  I'm having trouble testing it, though,
> >> as I can't figure out how to emit R_RISCV_SET_ULEB128 alone.  For example, when
> >> I try to insert a uleb128 in the assembler I'm not even getting a relocation:
> >>
> >>     .text
> >>     .globl _start
> >>     _start:
> >>             nop
> >>     .L0:
> >>             nop
> >>     .L1:
> >>     uleb_l0:
> >>             addi x0, x0, 1
> >>             .uleb128 .L0
> >>             # Manually fix up the alignment, as .align is broken.
> >>             .rept 3
> >>             .byte 0xAA
> >>             .endr
> >>             addi x0, x0, 2
> >>
> >>     $ objdump -dr
> >>     test.o:     file format elf64-littleriscv
> >>
> >>
> >>     Disassembly of section .text:
> >>
> >>     0000000000000000 <_start>:
> >>        0:   00000013                nop
> >>        4:   00000013                nop
> >>
> >>     0000000000000008 <uleb_l0>:
> >>        8:   00100013                li      zero,1
> >>        c:   aa04                    fsd     fs1,16(a2)
> >>        e:   aaaa                    fsd     fa0,336(sp)
> >>       10:   00200013                li      zero,2
> >>
> >> so then when I link I'm just getting the wrong value entirely.
> >>
> >>     test:     file format elf64-littleriscv
> >>
> >>
> >>     Disassembly of section .text:
> >>
> >>     0000000000010078 <_start>:
> >>        10078:       00000013                nop
> >>        1007c:       00000013                nop
> >>
> >>     0000000000010080 <uleb_l0>:
> >>        10080:       00100013                li      zero,1
> >>        10084:       aa04                    fsd     fs1,16(a2)
> >>        10086:       aaaa                    fsd     fa0,336(sp)
> >>        10088:       00200013                li      zero,2
> >>
> >> > +  /* The length of unsigned-leb128 is variant, just assume the
> >> > +     size is one byte here.  */
> >> > +  HOWTO (R_RISCV_SUB_ULEB128,                /* type */
> >> > +         0,                                /* rightshift */
> >> > +         0,                                /* size */
> >> > +         0,                                /* bitsize */
> >> > +         FALSE,                                /* pc_relative */
> >> > +         0,                                /* bitpos */
> >> > +         complain_overflow_dont,        /* complain_on_overflow */
> >> > +         riscv_elf_ignore_reloc,        /* special_function */
> >> > +         "R_RISCV_SUB_ULEB128",                /* name */
> >> > +         FALSE,                                /* partial_inplace */
> >> > +         0,                                /* src_mask */
> >> > +         0,                                /* dst_mask */
> >> > +         FALSE),                        /* pcrel_offset */
> >> >  };
> >>
> >> I can get a R_RISCV_SUB_ULEB128, but it appears to be both producing the wrong
> >> value and garbaging up bytes after the relocation.  For example:
> >>
> >>     .text
> >>     .globl _start
> >>     _start:
> >>             nop
> >>     .L0:
> >>             nop
> >>     .L1:
> >>     uleb_l1_l0:
> >>             addi x0, x0, 1
> >>             .uleb128 .L1 - .L0
> >>             # Manually fix up the alignment, as .align is broken
> >>             .rept 3
> >>             .byte 0xAA
> >>             .endr
> >>             addi x0, x0, 2
> >>
> >> produces the relocation
> >>
> >>     test.o:     file format elf64-littleriscv
> >>
> >>
> >>     Disassembly of section .text:
> >>
> >>     0000000000000000 <_start>:
> >>        0:   00000013                nop
> >>
> >>     0000000000000004 <.L0>:
> >>        4:   00000013                nop
> >>
> >>     0000000000000008 <uleb_l1_l0>:
> >>        8:   00100013                li      zero,1
> >>        c:   aa04                    fsd     fs1,16(a2)
> >>                             c: R_RISCV_SET_ULEB128  .L1
> >>                             c: R_RISCV_SUB_ULEB128  .L0
> >>        e:   aaaa                    fsd     fa0,336(sp)
> >>       10:   00200013                li      zero,2
> >>
> >> but then goes and corrupts the resulting executable
> >>
> >>
> >>     test:     file format elf64-littleriscv
> >>     Disassembly of section .text:
> >>
> >>     0000000000010078 <_start>:
> >>        10078:       00000013                nop
> >>        1007c:       00000013                nop
> >>
> >>     0000000000010080 <uleb_l1_l0>:
> >>        10080:       00100013                li      zero,1
> >>        10084:       ff84                    sd      s1,56(a5)
> >>        10086:       000ffffb                0xffffb
> >>        1008a:       0020                    addi    s0,sp,8
> >>
> >> I can't think of a way to make this work aside from just emitting uleb128s at
> >> their full length, which would make them work but would really defeat the
> >> purpose of the format.  I guess we could then relax these, but that seems like
> >> a lot of work.
> >>
> >> > +
> >> >  /* A mapping from BFD reloc types to RISC-V ELF reloc types.  */
> >> >
> >> >  struct elf_reloc_map
> >> > @@ -917,6 +952,8 @@ static const struct elf_reloc_map riscv_reloc_map[] =
> >> >    { 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_SET_ULEB128, R_RISCV_SET_ULEB128 },
> >> > +  { BFD_RELOC_RISCV_SUB_ULEB128, R_RISCV_SUB_ULEB128 },
> >> >  };
> >> >
> >> >  /* Given a BFD reloc type, return a howto structure.  */
> >> > @@ -1011,6 +1048,20 @@ riscv_elf_add_sub_reloc (bfd *abfd,
> >> >    return bfd_reloc_ok;
> >> >  }
> >> >
> >> > +/* Special handler for relocations which don't have to be relocated.
> >> > +   This function just simply return bfd_reloc_ok.  */
> >> > +static bfd_reloc_status_type
> >> > +riscv_elf_ignore_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry,
> >> > +                        asymbol *symbol ATTRIBUTE_UNUSED,
> >> > +                        void *data ATTRIBUTE_UNUSED, asection *input_section,
> >> > +                        bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED)
> >> > +{
> >> > +  if (output_bfd != NULL)
> >> > +    reloc_entry->address += input_section->output_offset;
> >> > +
> >> > +  return bfd_reloc_ok;
> >> > +}
> >> > +
> >> >  /* Parsing subset version.
> >> >
> >> >     Return Value:
> >> > diff --git a/bfd/libbfd.h b/bfd/libbfd.h
> >> > index 77b732ee4b..7aa8f91504 100644
> >> > --- a/bfd/libbfd.h
> >> > +++ b/bfd/libbfd.h
> >> > @@ -2327,6 +2327,8 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
> >> >    "BFD_RELOC_RISCV_SET16",
> >> >    "BFD_RELOC_RISCV_SET32",
> >> >    "BFD_RELOC_RISCV_32_PCREL",
> >> > +  "BFD_RELOC_RISCV_SET_ULEB128",
> >> > +  "BFD_RELOC_RISCV_SUB_ULEB128",
> >> >    "BFD_RELOC_RL78_NEG8",
> >> >    "BFD_RELOC_RL78_NEG16",
> >> >    "BFD_RELOC_RL78_NEG24",
> >> > diff --git a/bfd/reloc.c b/bfd/reloc.c
> >> > index b00b79f319..9b8b75ad21 100644
> >> > --- a/bfd/reloc.c
> >> > +++ b/bfd/reloc.c
> >> > @@ -5212,6 +5212,10 @@ ENUMX
> >> >    BFD_RELOC_RISCV_SET32
> >> >  ENUMX
> >> >    BFD_RELOC_RISCV_32_PCREL
> >> > +ENUMX
> >> > +  BFD_RELOC_RISCV_SET_ULEB128
> >> > +ENUMX
> >> > +  BFD_RELOC_RISCV_SUB_ULEB128
> >> >  ENUMDOC
> >> >    RISC-V relocations.
> >> >
> >> > diff --git a/gas/ChangeLog b/gas/ChangeLog
> >> > index 09991524da..e53ac0895b 100644
> >> > --- a/gas/ChangeLog
> >> > +++ b/gas/ChangeLog
> >> > @@ -1,3 +1,11 @@
> >> > +2019-11-27  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
> >> > +
> >> > +        * config/tc-riscv.c (md_apply_fix): Add BFD_RELOC_RISCV_SET_ULEB128 and
> >> > +        BFD_RELOC_RISCV_SUB_ULEB128.
> >> > +        (riscv_insert_uleb128_fixes): New function.
> >> > +        (riscv_md_end): Scan rs_leb128 fragments.
> >> > +        (riscv_pseudo_table): Remove uleb128.
> >> > +
> >> >  2019-11-25  Andrew Pinski  <apinski@marvell.com>
> >> >
> >> >          * config/tc-aarch64.c (md_begin): Use correct
> >> > diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
> >> > index e50505138e..c35c591c0a 100644
> >> > --- a/gas/config/tc-riscv.c
> >> > +++ b/gas/config/tc-riscv.c
> >> > @@ -2392,6 +2392,9 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
> >> >      case BFD_RELOC_RISCV_SUB32:
> >> >      case BFD_RELOC_RISCV_SUB64:
> >> >      case BFD_RELOC_RISCV_RELAX:
> >> > +    /* cvt_frag_to_fill () has called output_leb128 ().  */
> >> > +    case BFD_RELOC_RISCV_SET_ULEB128:
> >> > +    case BFD_RELOC_RISCV_SUB_ULEB128:
> >> >        break;
> >> >
> >> >      case BFD_RELOC_RISCV_TPREL_HI20:
> >> > @@ -3127,11 +3130,54 @@ riscv_set_public_attributes (void)
> >> >      riscv_write_out_arch_attr ();
> >> >  }
> >> >
> >> > +/* Scan uleb128 subtraction expressions and insert fixups for them.
> >> > +   e.g., .uleb128 .L1 - .L0
> >> > +   Becuase relaxation may change the value of the subtraction, we
> >> > +   must resolve them in link-time.  */
> >> > +
> >> > +static void
> >> > +riscv_insert_uleb128_fixes (bfd *abfd ATTRIBUTE_UNUSED,
> >> > +                            asection *sec, void *xxx ATTRIBUTE_UNUSED)
> >> > +{
> >> > +  segment_info_type *seginfo = seg_info (sec);
> >> > +  struct frag *fragP;
> >> > +
> >> > +  subseg_set (sec, 0);
> >> > +
> >> > +  for (fragP = seginfo->frchainP->frch_root;
> >> > +       fragP; fragP = fragP->fr_next)
> >> > +    {
> >> > +      expressionS *exp, *exp_dup;
> >> > +
> >> > +      if (fragP->fr_type != rs_leb128  || fragP->fr_symbol == NULL)
> >> > +        continue;
> >> > +
> >> > +      exp = symbol_get_value_expression (fragP->fr_symbol);
> >> > +
> >> > +      if (exp->X_op != O_subtract)
> >> > +        continue;
> >>
> >> Presumably that's why I can't get a _SET alone.
> >>
> >> > +
> >> > +      /* Only unsigned leb128 can be handle.  */
> >> > +      gas_assert (fragP->fr_subtype == 0);
> >> > +      exp_dup = xmemdup (exp, sizeof (*exp), sizeof (*exp));
> >> > +      exp_dup->X_op = O_symbol;
> >> > +      exp_dup->X_op_symbol = NULL;
> >> > +
> >> > +      /* Insert relocations to resolve the subtraction in link-time.  */
> >> > +      fix_new_exp (fragP, fragP->fr_fix, 0,
> >> > +                   exp_dup, 0, BFD_RELOC_RISCV_SET_ULEB128);
> >> > +      exp_dup->X_add_symbol = exp->X_op_symbol;
> >> > +      fix_new_exp (fragP, fragP->fr_fix, 0,
> >> > +                   exp_dup, 0, BFD_RELOC_RISCV_SUB_ULEB128);
> >> > +    }
> >> > +}
> >> > +
> >> >  /* Called after all assembly has been done.  */
> >> >
> >> >  void
> >> >  riscv_md_end (void)
> >> >  {
> >> > +  bfd_map_over_sections (stdoutput, riscv_insert_uleb128_fixes, NULL);
> >> >    riscv_set_public_attributes ();
> >> >  }
> >> >
> >> > @@ -3215,7 +3261,6 @@ static const pseudo_typeS riscv_pseudo_table[] =
> >> >    {"dtprelword", s_dtprel, 4},
> >> >    {"dtpreldword", s_dtprel, 8},
> >> >    {"bss", s_bss, 0},
> >> > -  {"uleb128", s_riscv_leb128, 0},
> >> >    {"sleb128", s_riscv_leb128, 1},
> >> >    {"insn", s_riscv_insn, 0},
> >> >    {"attribute", s_riscv_attribute, 0},
> >> > diff --git a/include/ChangeLog b/include/ChangeLog
> >> > index 47bb86cf71..c290b245c6 100644
> >> > --- a/include/ChangeLog
> >> > +++ b/include/ChangeLog
> >> > @@ -1,3 +1,7 @@
> >> > +2019-11-27  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
> >> > +
> >> > +        * elf/riscv.h ((R_RISCV_SET_ULEB128, (R_RISCV_SUB_ULEB128): Define.
> >> > +
> >> >  2019-11-25  Alan Modra  <amodra@gmail.com>
> >> >
> >> >          * coff/ti.h (GET_SCNHDR_SIZE, PUT_SCNHDR_SIZE, GET_SCN_SCNLEN),
> >> > diff --git a/include/elf/riscv.h b/include/elf/riscv.h
> >> > index 2f98aa4a3e..030679b35f 100644
> >> > --- a/include/elf/riscv.h
> >> > +++ b/include/elf/riscv.h
> >> > @@ -88,6 +88,8 @@ START_RELOC_NUMBERS (elf_riscv_reloc_type)
> >> >    RELOC_NUMBER (R_RISCV_SET16, 55)
> >> >    RELOC_NUMBER (R_RISCV_SET32, 56)
> >> >    RELOC_NUMBER (R_RISCV_32_PCREL, 57)
> >> > +  RELOC_NUMBER (R_RISCV_SET_ULEB128, 58)
> >> > +  RELOC_NUMBER (R_RISCV_SUB_ULEB128, 59)
> >> >  END_RELOC_NUMBERS (R_RISCV_max)
> >> >
> >> >  /* Processor specific flags for the ELF header e_flags field.  */
> >> > diff --git a/ld/ChangeLog b/ld/ChangeLog
> >> > index 969ab78035..5c2e406101 100644
> >> > --- a/ld/ChangeLog
> >> > +++ b/ld/ChangeLog
> >> > @@ -1,3 +1,9 @@
> >> > +2019-11-27  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
> >> > +
> >> > +        * testsuite/ld-riscv-elf/ld-riscv-elf.exp: Add uleb128.
> >> > +        * testsuite/ld-riscv-elf/uleb128.d: New test.
> >> > +        * testsuite/ld-riscv-elf/uleb128.s: New file.
> >> > +
> >> >  2019-11-26  Martin Liska  <mliska@suse.cz>
> >> >
> >> >          * scripttempl/arclinux.sc: Add .text.sorted.* which is sorted
> >> > diff --git a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
> >> > index 7aabbdd641..809e40f08d 100644
> >> > --- a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
> >> > +++ b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
> >> > @@ -38,6 +38,7 @@ if [istarget "riscv*-*-*"] {
> >> >      run_dump_test "attr-merge-priv-spec"
> >> >      run_dump_test "attr-merge-arch-failed-01"
> >> >      run_dump_test "attr-merge-stack-align-failed"
> >> > +    run_dump_test "uleb128"
> >> >      run_ld_link_tests {
> >> >          { "Weak reference 32" "-T weakref.ld -melf32lriscv" ""
> >> >              "-march=rv32i -mabi=ilp32" {weakref32.s}
> >> > diff --git a/ld/testsuite/ld-riscv-elf/uleb128.d b/ld/testsuite/ld-riscv-elf/uleb128.d
> >> > new file mode 100644
> >> > index 0000000000..a921478e98
> >> > --- /dev/null
> >> > +++ b/ld/testsuite/ld-riscv-elf/uleb128.d
> >> > @@ -0,0 +1,18 @@
> >> > +#source: uleb128.s
> >> > +#as: -march=rv32ic
> >> > +#ld: -melf32lriscv
> >> > +#objdump: -d
> >> > +
> >> > +.*:[         ]+file format .*
> >> > +
> >> > +Disassembly of section .text:
> >> > +
> >> > +.* <_start>:
> >> > +.*jal.*<bar>
> >> > +.*jal.*<bar>
> >> > +.*jal.*<bar>
> >> > +.*jal.*<bar>
> >> > +.*jal.*<bar>
> >> > +.*jal.*<bar>
> >> > +.*:[         ]+0e0c.*
> >> > +#pass
> >> > diff --git a/ld/testsuite/ld-riscv-elf/uleb128.s b/ld/testsuite/ld-riscv-elf/uleb128.s
> >> > new file mode 100644
> >> > index 0000000000..f7d23be163
> >> > --- /dev/null
> >> > +++ b/ld/testsuite/ld-riscv-elf/uleb128.s
> >> > @@ -0,0 +1,18 @@
> >> > +.text
> >> > +.globl bar
> >> > +.globl _start
> >> > +.option rvc
> >> > +.align 2
> >> > +_start:
> >> > +.L0:
> >> > +        .rept 6
> >> > +        call bar
> >> > +        .endr
> >> > +.align 2
> >> > +.L1:
> >> > +        .uleb128 .L1 - .L0
> >> > +        .uleb128 .L2 - .L0
> >> > +.L2:
> >> > +.align 2
> >> > +bar:
> >> > +        nop
> >>
> >> It looks like alignment is broken here after uleb128s, but it's not actually
> >> triggering an error in all cases.  Having two of them in this test case doesn't
> >> trigger the issue, but an odd number does.  For example, the following source
> >>
> >>     .text
> >>     .globl _start
> >>     .align 2
> >>     _start:
> >>             .uleb128 _start
> >>     .align 2
> >>     _end:
> >>             nop
> >>
> >> links _end to a misaligned symbol
> >>
> >>     Disassembly of section .text:
> >>
> >>     0000000000010078 <_start>:
> >>             ...
> >>
> >>     0000000000010079 <_end>:
> >>        10079:       00000013                nop
> >>        1007d:       0000                    unimp
> >>             ...
> >>
> >> I'm assuming that's because norvc assumes 4-byte alignment in text sections, so
> >> it's just eliding the alingment directives.  With RVC I do get an error message
> >>
> >>     .text
> >>     .globl _start
> >>     .option rvc
> >>     .align 2
> >>     _start:
> >>             .uleb128 _start
> >>     .align 2
> >>     _end:
> >>             nop
> >>
> >>     ./install/bin/riscv64-unknown-linux-gnu-ld: test.o(.text+0x1): 3 bytes required for alignment to 4-byte boundary, but only 2 present
> >>     ./install/bin/riscv64-unknown-linux-gnu-ld: can't relax section: bad value
> >>
> >>
> >
> >
> > --
> > Best regards,
> > Kuan-Lin Chen.
> > kuanlinchentw@gmail.com



-- 
Best regards,
Kuan-Lin Chen.
kuanlinchentw@gmail.com

[-- Attachment #2: 0001-RISC-V-Support-subtraction-of-.uleb128.patch --]
[-- Type: application/octet-stream, Size: 16325 bytes --]

From d733abde65adca030288819c2221953ed40d7a64 Mon Sep 17 00:00:00 2001
From: Kuan-Lin Chen <rufus@andestech.com>
Date: Thu, 14 Nov 2019 14:24:22 +0800
Subject: [PATCH] RISC-V: Support subtraction of .uleb128.

The data length of uleb128 is variable.  So linker must recalculate the
value of the subtraction.  The patch leave relocations in object files
so that linker can relocate again after relaxation.

bfd/ChangeLog:
	* bfd-in2.h: Regenerated.
	* elfnn-riscv.c (write_uleb128): New function.
	(perform_relocation): Perform R_RISCV_SUB_ULEB128 and
	 R_RISCV_SET_ULEB128 relocation.
	(riscv_elf_relocate_section): Likewise.
	* elfxx-riscv.c (howto_table): Add R_RISCV_SUB_ULEB128 and
	R_RISCV_SET_ULEB128.
	(riscv_elf_ignore_reloc): New function.
	* libbfd.h: Regenerated.
	* reloc.c (BFD_RELOC_RISCV_SET_ULEB128, BFD_RELOC_RISCV_SUB_ULEB128):
	New relocations to support .uleb128.

gas/ChangeLog:
	* config/tc-riscv.c (md_apply_fix): Add BFD_RELOC_RISCV_SET_ULEB128 and
	BFD_RELOC_RISCV_SUB_ULEB128.
	(riscv_insert_uleb128_fixes): New function.
	(riscv_md_end): Scan rs_leb128 fragments.
	(riscv_pseudo_table): Remove uleb128.

include/ChangeLog:
	* elf/riscv.h ((R_RISCV_SET_ULEB128, (R_RISCV_SUB_ULEB128): Define.

ld/ChangeLog:
	* testsuite/ld-riscv-elf/ld-riscv-elf.exp: Add uleb128.
	* testsuite/ld-riscv-elf/uleb128.d: New test.
	* testsuite/ld-riscv-elf/uleb128.s: New file.
---
 bfd/ChangeLog                              | 14 ++++
 bfd/bfd-in2.h                              |  2 +
 bfd/elfnn-riscv.c                          | 84 +++++++++++++++++++++-
 bfd/elfxx-riscv.c                          | 51 +++++++++++++
 bfd/libbfd.h                               |  2 +
 bfd/reloc.c                                |  4 ++
 gas/ChangeLog                              |  8 +++
 gas/config/tc-riscv.c                      | 55 +++++++++++++-
 include/ChangeLog                          |  4 ++
 include/elf/riscv.h                        |  2 +
 ld/ChangeLog                               |  6 ++
 ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp |  1 +
 ld/testsuite/ld-riscv-elf/uleb128.d        | 18 +++++
 ld/testsuite/ld-riscv-elf/uleb128.s        | 18 +++++
 14 files changed, 266 insertions(+), 3 deletions(-)
 create mode 100644 ld/testsuite/ld-riscv-elf/uleb128.d
 create mode 100644 ld/testsuite/ld-riscv-elf/uleb128.s

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 45f2499735..94082f6213 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,17 @@
+2020-01-22  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
+
+	* bfd-in2.h: Regenerated.
+	* elfnn-riscv.c (write_uleb128): New function.
+	(perform_relocation): Perform R_RISCV_SUB_ULEB128 and
+	 R_RISCV_SET_ULEB128 relocation.
+	(riscv_elf_relocate_section): Likewise.
+	* elfxx-riscv.c (howto_table): Add R_RISCV_SUB_ULEB128 and
+	R_RISCV_SET_ULEB128.
+	(riscv_elf_ignore_reloc): New function.
+	* libbfd.h: Regenerated.
+	* reloc.c (BFD_RELOC_RISCV_SET_ULEB128, BFD_RELOC_RISCV_SUB_ULEB128):
+	New relocations to support .uleb128.
+
 2020-01-20  Nick Clifton  <nickc@redhat.com>
 
 	* po/pt.po: Updates Portuguese translation.
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 7c13bc8c91..e43c3a5557 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -4383,6 +4383,8 @@ number for the SBIC, SBIS, SBI and CBI instructions  */
   BFD_RELOC_RISCV_SET16,
   BFD_RELOC_RISCV_SET32,
   BFD_RELOC_RISCV_32_PCREL,
+  BFD_RELOC_RISCV_SET_ULEB128,
+  BFD_RELOC_RISCV_SUB_ULEB128,
 
 /* Renesas RL78 Relocations.  */
   BFD_RELOC_RL78_NEG8,
diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index 46f0100ace..74c19bf0fc 100644
--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -1419,6 +1419,26 @@ riscv_global_pointer_value (struct bfd_link_info *info)
   return h->u.def.value + sec_addr (h->u.def.section);
 }
 
+/* Write VAL in uleb128 format to P, returning a pointer to the
+   following byte.
+   This code is copied from elf-attr.c.  */
+
+static bfd_byte *
+write_uleb128 (bfd_byte *p, unsigned int val)
+{
+  bfd_byte c;
+  do
+    {
+      c = val & 0x7f;
+      val >>= 7;
+      if (val)
+	c |= 0x80;
+      *(p++) = c;
+    }
+  while (val);
+  return p;
+}
+
 /* Emplace a static relocation.  */
 
 static bfd_reloc_status_type
@@ -1512,6 +1532,25 @@ perform_relocation (const reloc_howto_type *howto,
 	value = ENCODE_RVC_LUI_IMM (RISCV_CONST_HIGH_PART (value));
       break;
 
+    case R_RISCV_SET_ULEB128:
+    case R_RISCV_SUB_ULEB128:
+      {
+	unsigned int len = 0;
+	bfd_byte *endp, *p;
+
+	_bfd_read_unsigned_leb128 (input_bfd, contents + rel->r_offset, &len);
+
+	/* Clean the contents value to zero.  Do not reduce the length.  */
+	p = contents + rel->r_offset;
+	endp = p + len -1;
+	memset (p, 0x80, len - 1);
+	*(endp) = 0;
+	p = write_uleb128 (p, value) - 1;
+	if (p < endp)
+	  *p |= 0x80;
+	return bfd_reloc_ok;
+      }
+
     case R_RISCV_32:
     case R_RISCV_64:
     case R_RISCV_ADD8:
@@ -1767,6 +1806,8 @@ riscv_elf_relocate_section (bfd *output_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;
+  bfd_vma uleb128_vma = 0;
+  Elf_Internal_Rela *uleb128_rel = NULL;
 
   if (!riscv_init_pcrel_relocs (&pcrel_relocs))
     return FALSE;
@@ -1778,7 +1819,7 @@ riscv_elf_relocate_section (bfd *output_bfd,
       struct elf_link_hash_entry *h;
       Elf_Internal_Sym *sym;
       asection *sec;
-      bfd_vma relocation;
+      bfd_vma relocation = 0;
       bfd_reloc_status_type r = bfd_reloc_ok;
       const char *name;
       bfd_vma off, ie_off;
@@ -1871,6 +1912,47 @@ riscv_elf_relocate_section (bfd *output_bfd,
 	case R_RISCV_DELETE:
 	  /* These require no special handling beyond perform_relocation.  */
 	  break;
+	case R_RISCV_SET_ULEB128:
+	  if (!uleb128_rel)
+	    {
+	      /* Save the minuend to use later.  */
+	      uleb128_vma = relocation;
+	      uleb128_rel = rel;
+	      continue;
+	    }
+	  else
+	    {
+	      if (uleb128_rel->r_offset != rel->r_offset)
+		{
+		  msg = ("R_RISCV_SET_ULEB128 and R_RISCV_SUB_ULEB128 are mismatched. ");
+		  r = bfd_reloc_dangerous;
+		  break;
+		}
+	      relocation = relocation - uleb128_vma;
+	      uleb128_rel = NULL;
+	      break;
+	    }
+
+	case R_RISCV_SUB_ULEB128:
+	  if (uleb128_rel)
+	    {
+	      if (uleb128_rel->r_offset != rel->r_offset)
+		{
+		  msg = ("R_RISCV_SET_ULEB128 and R_RISCV_SUB_ULEB128 are mismatched. ");
+		  r = bfd_reloc_dangerous;
+		  break;
+		}
+	      relocation = uleb128_vma - relocation;
+	      uleb128_rel = NULL;
+	      break;
+	    }
+	  else
+	    {
+	      /* Save the subtrahend to use later.  */
+	      uleb128_vma = relocation;
+	      uleb128_rel = rel;
+	      continue;
+	    }
 
 	case R_RISCV_GOT_HI20:
 	  if (h != NULL)
diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c
index 66e343f4a5..244353573b 100644
--- a/bfd/elfxx-riscv.c
+++ b/bfd/elfxx-riscv.c
@@ -38,6 +38,8 @@
    relocations for the debug info.  */
 static bfd_reloc_status_type riscv_elf_add_sub_reloc
   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
+static bfd_reloc_status_type riscv_elf_ignore_reloc
+  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
 
 /* The relocation table used for SHT_RELA sections.  */
 
@@ -855,8 +857,41 @@ static reloc_howto_type howto_table[] =
 	 0,				/* src_mask */
 	 MINUS_ONE,			/* dst_mask */
 	 FALSE),			/* pcrel_offset */
+
+  /* The length of unsigned-leb128 is variable, just assume the
+     size is one byte here.  */
+  HOWTO (R_RISCV_SET_ULEB128,		/* type */
+	 0,				/* rightshift */
+	 0,				/* size */
+	 0,				/* bitsize */
+	 FALSE,				/* pc_relative */
+	 0,				/* bitpos */
+	 complain_overflow_dont,	/* complain_on_overflow */
+	 riscv_elf_ignore_reloc,	/* special_function */
+	 "R_RISCV_SET_ULEB128",		/* name */
+	 FALSE,				/* partial_inplace */
+	 0,				/* src_mask */
+	 0,				/* dst_mask */
+	 FALSE),			/* pcrel_offset */
+
+  /* The length of unsigned-leb128 is variable, just assume the
+     size is one byte here.  */
+  HOWTO (R_RISCV_SUB_ULEB128,		/* type */
+	 0,				/* rightshift */
+	 0,				/* size */
+	 0,				/* bitsize */
+	 FALSE,				/* pc_relative */
+	 0,				/* bitpos */
+	 complain_overflow_dont,	/* complain_on_overflow */
+	 riscv_elf_ignore_reloc,	/* special_function */
+	 "R_RISCV_SUB_ULEB128",		/* name */
+	 FALSE,				/* partial_inplace */
+	 0,				/* src_mask */
+	 0,				/* dst_mask */
+	 FALSE),			/* pcrel_offset */
 };
 
+
 /* A mapping from BFD reloc types to RISC-V ELF reloc types.  */
 
 struct elf_reloc_map
@@ -917,6 +952,8 @@ static const struct elf_reloc_map riscv_reloc_map[] =
   { 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_SET_ULEB128, R_RISCV_SET_ULEB128 },
+  { BFD_RELOC_RISCV_SUB_ULEB128, R_RISCV_SUB_ULEB128 },
 };
 
 /* Given a BFD reloc type, return a howto structure.  */
@@ -1011,6 +1048,20 @@ riscv_elf_add_sub_reloc (bfd *abfd,
   return bfd_reloc_ok;
 }
 
+/* Special handler for relocations which don't have to be relocated.
+   This function just simply return bfd_reloc_ok.  */
+static bfd_reloc_status_type
+riscv_elf_ignore_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry,
+			asymbol *symbol ATTRIBUTE_UNUSED,
+			void *data ATTRIBUTE_UNUSED, asection *input_section,
+			bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED)
+{
+  if (output_bfd != NULL)
+    reloc_entry->address += input_section->output_offset;
+
+  return bfd_reloc_ok;
+}
+
 /* Parsing subset version.
 
    Return Value:
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index d97d4e57a7..74d12d8b99 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -2327,6 +2327,8 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_RISCV_SET16",
   "BFD_RELOC_RISCV_SET32",
   "BFD_RELOC_RISCV_32_PCREL",
+  "BFD_RELOC_RISCV_SET_ULEB128",
+  "BFD_RELOC_RISCV_SUB_ULEB128",
   "BFD_RELOC_RL78_NEG8",
   "BFD_RELOC_RL78_NEG16",
   "BFD_RELOC_RL78_NEG24",
diff --git a/bfd/reloc.c b/bfd/reloc.c
index 33cd67150c..9b797e7920 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -5212,6 +5212,10 @@ ENUMX
   BFD_RELOC_RISCV_SET32
 ENUMX
   BFD_RELOC_RISCV_32_PCREL
+ENUMX
+  BFD_RELOC_RISCV_SET_ULEB128
+ENUMX
+  BFD_RELOC_RISCV_SUB_ULEB128
 ENUMDOC
   RISC-V relocations.
 
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 8f414396f5..3beb4060c2 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,11 @@
+2020-01-22  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
+
+	* config/tc-riscv.c (md_apply_fix): Add BFD_RELOC_RISCV_SET_ULEB128 and
+	BFD_RELOC_RISCV_SUB_ULEB128.
+	(riscv_insert_uleb128_fixes): New function.
+	(riscv_md_end): Scan rs_leb128 fragments.
+	(riscv_pseudo_table): Remove uleb128.
+
 2020-01-21  Jan Beulich  <jbeulich@suse.com>
 
 	* testsuite/gas/i386/inval-crc32.s,
diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
index 21fff8ffab..61094fab3a 100644
--- a/gas/config/tc-riscv.c
+++ b/gas/config/tc-riscv.c
@@ -2392,6 +2392,9 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
     case BFD_RELOC_RISCV_SUB32:
     case BFD_RELOC_RISCV_SUB64:
     case BFD_RELOC_RISCV_RELAX:
+    /* cvt_frag_to_fill () has called output_leb128 ().  */
+    case BFD_RELOC_RISCV_SET_ULEB128:
+    case BFD_RELOC_RISCV_SUB_ULEB128:
       break;
 
     case BFD_RELOC_RISCV_TPREL_HI20:
@@ -3067,8 +3070,11 @@ s_riscv_leb128 (int sign)
   char *save_in = input_line_pointer;
 
   expression (&exp);
-  if (exp.X_op != O_constant)
-    as_bad (_("non-constant .%cleb128 is not supported"), sign ? 's' : 'u');
+  if (sign && exp.X_op != O_constant)
+    as_bad (_("non-constant .sleb128 is not supported"));
+  else if (!sign && exp.X_op != O_constant && exp.X_op != O_subtract)
+    as_bad (_(".uleb128 only supports constant or subtract expressions."));
+
   demand_empty_rest_of_line ();
 
   input_line_pointer = save_in;
@@ -3131,11 +3137,56 @@ riscv_set_public_attributes (void)
     riscv_write_out_arch_attr ();
 }
 
+/* Scan uleb128 subtraction expressions and insert fixups for them.
+   e.g., .uleb128 .L1 - .L0
+   Because relaxation may change the value of the subtraction, we
+   must resolve them at link-time.  */
+
+static void
+riscv_insert_uleb128_fixes (bfd *abfd ATTRIBUTE_UNUSED,
+			    asection *sec, void *xxx ATTRIBUTE_UNUSED)
+{
+  segment_info_type *seginfo = seg_info (sec);
+  struct frag *fragP;
+
+  subseg_set (sec, 0);
+
+  for (fragP = seginfo->frchainP->frch_root;
+       fragP; fragP = fragP->fr_next)
+    {
+      expressionS *exp, *exp_dup;
+
+      if (fragP->fr_type != rs_leb128  || fragP->fr_symbol == NULL)
+	continue;
+
+      exp = symbol_get_value_expression (fragP->fr_symbol);
+
+      if (exp->X_op != O_subtract)
+	continue;
+
+      /* Only unsigned leb128 can be handled.  */
+      gas_assert (fragP->fr_subtype == 0);
+      exp_dup = xmemdup (exp, sizeof (*exp), sizeof (*exp));
+      exp_dup->X_op = O_symbol;
+      exp_dup->X_op_symbol = NULL;
+
+      /* Insert relocations to resolve the subtraction at link-time.  */
+      fix_new_exp (fragP, fragP->fr_fix, 0,
+		   exp_dup, 0, BFD_RELOC_RISCV_SET_ULEB128);
+      exp_dup->X_add_symbol = exp->X_op_symbol;
+      fix_new_exp (fragP, fragP->fr_fix, 0,
+		   exp_dup, 0, BFD_RELOC_RISCV_SUB_ULEB128);
+    }
+}
+
 /* Called after all assembly has been done.  */
 
 void
 riscv_md_end (void)
 {
+
+  if (riscv_opts.relax)
+    bfd_map_over_sections (stdoutput, riscv_insert_uleb128_fixes, NULL);
   riscv_set_public_attributes ();
 }
 
diff --git a/include/ChangeLog b/include/ChangeLog
index c7fd4ab141..67ac887fe8 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,3 +1,7 @@
+2020-01-06  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
+
+	* elf/riscv.h ((R_RISCV_SET_ULEB128, (R_RISCV_SUB_ULEB128): Define.
+
 2020-01-18  Nick Clifton  <nickc@redhat.com>
 
 	Binutils 2.34 branch created.
diff --git a/include/elf/riscv.h b/include/elf/riscv.h
index 5062a4998c..a839a0c843 100644
--- a/include/elf/riscv.h
+++ b/include/elf/riscv.h
@@ -88,6 +88,8 @@ START_RELOC_NUMBERS (elf_riscv_reloc_type)
   RELOC_NUMBER (R_RISCV_SET16, 55)
   RELOC_NUMBER (R_RISCV_SET32, 56)
   RELOC_NUMBER (R_RISCV_32_PCREL, 57)
+  RELOC_NUMBER (R_RISCV_SET_ULEB128, 58)
+  RELOC_NUMBER (R_RISCV_SUB_ULEB128, 59)
 END_RELOC_NUMBERS (R_RISCV_max)
 
 /* Processor specific flags for the ELF header e_flags field.  */
diff --git a/ld/ChangeLog b/ld/ChangeLog
index d8949bbc38..c9b5d194a5 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,3 +1,9 @@
+2020-01-06  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
+
+	* testsuite/ld-riscv-elf/ld-riscv-elf.exp: Add uleb128.
+	* testsuite/ld-riscv-elf/uleb128.d: New test.
+	* testsuite/ld-riscv-elf/uleb128.s: New file.
+
 2020-01-22  Yuri Chornoivan  <yurchor@mageia.org>
 
 	PR 25417
diff --git a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
index 0e9750e496..412c00d1ec 100644
--- a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
+++ b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
@@ -38,6 +38,7 @@ if [istarget "riscv*-*-*"] {
     run_dump_test "attr-merge-priv-spec"
     run_dump_test "attr-merge-arch-failed-01"
     run_dump_test "attr-merge-stack-align-failed"
+    run_dump_test "uleb128"
     run_ld_link_tests {
 	{ "Weak reference 32" "-T weakref.ld -melf32lriscv" ""
 	    "-march=rv32i -mabi=ilp32" {weakref32.s}
diff --git a/ld/testsuite/ld-riscv-elf/uleb128.d b/ld/testsuite/ld-riscv-elf/uleb128.d
new file mode 100644
index 0000000000..a921478e98
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/uleb128.d
@@ -0,0 +1,18 @@
+#source: uleb128.s
+#as: -march=rv32ic
+#ld: -melf32lriscv
+#objdump: -d
+
+.*:[ 	]+file format .*
+
+Disassembly of section .text:
+
+.* <_start>:
+.*jal.*<bar>
+.*jal.*<bar>
+.*jal.*<bar>
+.*jal.*<bar>
+.*jal.*<bar>
+.*jal.*<bar>
+.*:[ 	]+0e0c.*
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/uleb128.s b/ld/testsuite/ld-riscv-elf/uleb128.s
new file mode 100644
index 0000000000..f7d23be163
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/uleb128.s
@@ -0,0 +1,18 @@
+.text
+.globl bar
+.globl _start
+.option rvc
+.align 2
+_start:
+.L0:
+        .rept 6
+        call bar
+        .endr
+.align 2
+.L1:
+        .uleb128 .L1 - .L0
+        .uleb128 .L2 - .L0
+.L2:
+.align 2
+bar:
+        nop
-- 
2.17.0


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] [RISCV] Support subtraction of .uleb128.
  2020-01-22  7:26     ` Kuan-Lin Chen
@ 2020-09-25  7:14       ` Kito Cheng
  2020-09-25 15:55         ` Jozef Lawrynowicz
  0 siblings, 1 reply; 17+ messages in thread
From: Kito Cheng @ 2020-09-25  7:14 UTC (permalink / raw)
  To: Kuan-Lin Chen
  Cc: Palmer Dabbelt, binutils@sourceware.org Development, Jim Wilson

Hi Jim, Palmer:

ping, I think this patch should be ready to land after rebase and
adjust reloc number?

On Wed, Jan 22, 2020 at 3:26 PM Kuan-Lin Chen <kuanlinchentw@gmail.com> wrote:
>
> Hi,
>
> This version patch updates as follows:
> Fix the warning about uninitialized variable.
> Set a limit to .uleb128 expressions as Palmer's suggestion.
> Thanks.
>
> Palmer Dabbelt <palmerdabbelt@google.com> 於 2020年1月10日 週五 上午7:19寫道:
> >
> > On Mon, 09 Dec 2019 21:42:58 PST (-0800), kuanlinchentw@gmail.com wrote:
> > > Hi Palmer,
> > >
> > >> GCC gives me -Wmaybe-uninitialized for both of these.
> > > May I know your gcc version?
> > > I tried gcc-7.3.0 and gcc-8.2.0, and I didn't get the warning.
> >
> > $ gcc --version
> > gcc (Debian 8.3.0-6) 8.3.0
> > Copyright (C) 2018 Free Software Foundation, Inc.
> > This is free software; see the source for copying conditions.  There is NO
> > warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
> >
> > >> I don't understand how this could possibly work: uleb128s can be long, so we
> > >> can't just treat them as a single byte.
> > > Yes, uleb128s can be long so I implement riscv_elf_ignore_reloc to
> > > ignore the overflow checking.
> > > And I relocate uleb128s by myself in perform_relocation.
> > >
> > >> I'm having trouble testing it, though,
> > >> as I can't figure out how to emit R_RISCV_SET_ULEB128 alone.  For example, when
> > >> I try to insert a uleb128 in the assembler I'm not even getting a relocation:
> > > .uleb128 only support subtract format. (.uleb128 .L1 - .L0)
> > > It is impossible to get final the value and the length for ".uleb128
> > > symbol" in assemble-time.
> >
> > Well, you know symbols are at most 64-bit on rv64 and 32-bit on rv32, so you
> > can just emit enough space to encode any symbol.  That's better than emitting 7
> > bits, which is unlikely to encode any symbol.
> >
> > > I think ".uleb128 symbol" is meaningless.
> > > Therefore, all targets just fill the value as assemble-time value
> > > without relocations.
> >
> > If the assembler can't handle something then it needs to provide an error, it
> > can't just generate incorrect code.
> >
> > >>I can get a R_RISCV_SUB_ULEB128, but it appears to be both producing the wrong
> > >>value and garbaging up bytes after the relocation.  For example:
> > >
> > > I get the same result in the object file but the different result in executable.
> > > pal.o:     file format elf64-littleriscv
> > >
> > > Disassembly of section .text:
> > >
> > > 0000000000000000 <_start>:
> > >    0:   00000013                nop
> > >
> > > 0000000000000004 <.L0>:
> > >    4:   00000013                nop
> > >
> > > 0000000000000008 <uleb_l1_l0>:
> > >    8:   00100013                li      zero,1
> > >    c:   aa04                    fsd     fs1,16(a2)
> > >                         c: R_RISCV_SET_ULEB128  .L1
> > >                         c: R_RISCV_SUB_ULEB128  .L0
> > >    e:   aaaa                    fsd     fa0,336(sp)
> > >   10:   00200013                li      zero,2
> > >
> > >
> > > a.out:     file format elf64-littleriscv
> > >
> > >
> > > Disassembly of section .text:
> > >
> > > 0000000000010078 <_start>:
> > >    10078:       00000013                nop
> > >    1007c:       00000013                nop
> > >
> > > 0000000000010080 <uleb_l1_l0>:
> > >    10080:       00100013                li      zero,1
> > >    10084:       aa04                    fsd     fs1,16(a2)
> > >    10086:       aaaa                    fsd     fa0,336(sp)
> > >    10088:       00200013                li      zero,2
> > >
> > > Maybe there is something mismatched. But I don't have any idea currently.
> > > Could you please give me more information about your flow?
> >
> > IIRC I just applied the patch on top of whatever was HEAD of binutils-gdb at
> > the time, but I don't have the working directory around any more.
> >
> > > Thanks.
> > >
> > >> Presumably that's why I can't get a _SET alone.
> > > I think it's meaningless to use _SET alone in assembly.
> > >
> > >> It looks like alignment is broken here after uleb128s, but it's not actually
> > >> triggering an error in all cases.  Having two of them in this test case doesn't
> > >> trigger the issue, but an odd number does.  For example, the following source
> > > I think this alignment issue can be fixed by the following patch:
> > > https://sourceware.org/ml/binutils/2019-12/msg00024.html
> >
> > Ya, thanks -- I think there's some issues there as well, IIRC I commented on
> > it.
> >
> > >
> > > Thanks for your review.
> > >
> > > Palmer Dabbelt <palmerdabbelt@google.com> 於 2019年12月7日 週六 上午7:47寫道:
> > >>
> > >> On Wed, 27 Nov 2019 00:11:50 PST (-0800), kuanlinchentw@gmail.com wrote:
> > >> > The data length of uleb128 is variable.  So linker must recalculate the
> > >> > value of the subtraction.  The patch leave relocations in object files
> > >> > so that linker can relocate again after relaxation.
> > >> >
> > >> > bfd/ChangeLog:
> > >> > * bfd-in2.h: Regenerated.
> > >> > * elfnn-riscv.c (write_uleb128): New function.
> > >> > (perform_relocation): Perform R_RISCV_SUB_ULEB128 and
> > >> > R_RISCV_SET_ULEB128 relocation.
> > >> > (riscv_elf_relocate_section): Likewise.
> > >> > * elfxx-riscv.c (howto_table): Add R_RISCV_SUB_ULEB128 and
> > >> > R_RISCV_SET_ULEB128.
> > >> > (riscv_elf_ignore_reloc): New function.
> > >> > * libbfd.h: Regenerated.
> > >> > * reloc.c (BFD_RELOC_RISCV_SET_ULEB128, BFD_RELOC_RISCV_SUB_ULEB128):
> > >> > New relocations to support .uleb128.
> > >> >
> > >> > gas/ChangeLog:
> > >> > * config/tc-riscv.c (md_apply_fix): Add BFD_RELOC_RISCV_SET_ULEB128 and
> > >> > BFD_RELOC_RISCV_SUB_ULEB128.
> > >> > (riscv_insert_uleb128_fixes): New function.
> > >> > (riscv_md_end): Scan rs_leb128 fragments.
> > >> > (riscv_pseudo_table): Remove uleb128.
> > >> >
> > >> > include/ChangeLog:
> > >> > * elf/riscv.h ((R_RISCV_SET_ULEB128, (R_RISCV_SUB_ULEB128): Define.
> > >> >
> > >> > ld/ChangeLog:
> > >> > * testsuite/ld-riscv-elf/ld-riscv-elf.exp: Add uleb128.
> > >> > * testsuite/ld-riscv-elf/uleb128.d: New test.
> > >> > * testsuite/ld-riscv-elf/uleb128.s: New file.
> > >> >
> > >> > OK to commit?
> > >>
> > >> I'm having a lot of trouble trying to figure out how this works.  LMK if I'm
> > >> missing something, there's some comments in line:
> > >>
> > >> > From 9f7f0aaa484dee2b32c550f8cca4de18959f01e1 Mon Sep 17 00:00:00 2001
> > >> > From: Kuan-Lin Chen <rufus@andestech.com>
> > >> > Date: Thu, 14 Nov 2019 14:24:22 +0800
> > >> > Subject: [PATCH] RISC-V: Support subtraction of .uleb128.
> > >> >
> > >> > The data length of uleb128 is variable.  So linker must recalculate the
> > >> > value of the subtraction.  The patch leave relocations in object files
> > >> > so that linker can relocate again after relaxation.
> > >> >
> > >> > bfd/ChangeLog:
> > >> >         * bfd-in2.h: Regenerated.
> > >> >         * elfnn-riscv.c (write_uleb128): New function.
> > >> >         (perform_relocation): Perform R_RISCV_SUB_ULEB128 and
> > >> >          R_RISCV_SET_ULEB128 relocation.
> > >> >         (riscv_elf_relocate_section): Likewise.
> > >> >         * elfxx-riscv.c (howto_table): Add R_RISCV_SUB_ULEB128 and
> > >> >         R_RISCV_SET_ULEB128.
> > >> >         (riscv_elf_ignore_reloc): New function.
> > >> >         * libbfd.h: Regenerated.
> > >> >         * reloc.c (BFD_RELOC_RISCV_SET_ULEB128, BFD_RELOC_RISCV_SUB_ULEB128):
> > >> >         New relocations to support .uleb128.
> > >> >
> > >> > gas/ChangeLog:
> > >> >         * config/tc-riscv.c (md_apply_fix): Add BFD_RELOC_RISCV_SET_ULEB128 and
> > >> >         BFD_RELOC_RISCV_SUB_ULEB128.
> > >> >         (riscv_insert_uleb128_fixes): New function.
> > >> >         (riscv_md_end): Scan rs_leb128 fragments.
> > >> >         (riscv_pseudo_table): Remove uleb128.
> > >> >
> > >> > include/ChangeLog:
> > >> >         * elf/riscv.h ((R_RISCV_SET_ULEB128, (R_RISCV_SUB_ULEB128): Define.
> > >> >
> > >> > ld/ChangeLog:
> > >> >         * testsuite/ld-riscv-elf/ld-riscv-elf.exp: Add uleb128.
> > >> >         * testsuite/ld-riscv-elf/uleb128.d: New test.
> > >> >         * testsuite/ld-riscv-elf/uleb128.s: New file.
> > >> > ---
> > >> >  bfd/ChangeLog                              | 14 ++++
> > >> >  bfd/bfd-in2.h                              |  2 +
> > >> >  bfd/elfnn-riscv.c                          | 82 ++++++++++++++++++++++
> > >> >  bfd/elfxx-riscv.c                          | 51 ++++++++++++++
> > >> >  bfd/libbfd.h                               |  2 +
> > >> >  bfd/reloc.c                                |  4 ++
> > >> >  gas/ChangeLog                              |  8 +++
> > >> >  gas/config/tc-riscv.c                      | 47 ++++++++++++-
> > >> >  include/ChangeLog                          |  4 ++
> > >> >  include/elf/riscv.h                        |  2 +
> > >> >  ld/ChangeLog                               |  6 ++
> > >> >  ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp |  1 +
> > >> >  ld/testsuite/ld-riscv-elf/uleb128.d        | 18 +++++
> > >> >  ld/testsuite/ld-riscv-elf/uleb128.s        | 18 +++++
> > >> >  14 files changed, 258 insertions(+), 1 deletion(-)
> > >> >  create mode 100644 ld/testsuite/ld-riscv-elf/uleb128.d
> > >> >  create mode 100644 ld/testsuite/ld-riscv-elf/uleb128.s
> > >> >
> > >> > diff --git a/bfd/ChangeLog b/bfd/ChangeLog
> > >> > index 4a0852e577..d11ffde74c 100644
> > >> > --- a/bfd/ChangeLog
> > >> > +++ b/bfd/ChangeLog
> > >> > @@ -1,3 +1,17 @@
> > >> > +2019-11-27  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
> > >> > +
> > >> > +        * bfd-in2.h: Regenerated.
> > >> > +        * elfnn-riscv.c (write_uleb128): New function.
> > >> > +        (perform_relocation): Perform R_RISCV_SUB_ULEB128 and
> > >> > +         R_RISCV_SET_ULEB128 relocation.
> > >> > +        (riscv_elf_relocate_section): Likewise.
> > >> > +        * elfxx-riscv.c (howto_table): Add R_RISCV_SUB_ULEB128 and
> > >> > +        R_RISCV_SET_ULEB128.
> > >> > +        (riscv_elf_ignore_reloc): New function.
> > >> > +        * libbfd.h: Regenerated.
> > >> > +        * reloc.c (BFD_RELOC_RISCV_SET_ULEB128, BFD_RELOC_RISCV_SUB_ULEB128):
> > >> > +        New relocations to support .uleb128.
> > >> > +
> > >> >  2019-11-27  Alan Modra  <amodra@gmail.com>
> > >> >
> > >> >          PR 23652
> > >> > diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
> > >> > index 44902fc8d0..a32708ebc2 100644
> > >> > --- a/bfd/bfd-in2.h
> > >> > +++ b/bfd/bfd-in2.h
> > >> > @@ -4380,6 +4380,8 @@ number for the SBIC, SBIS, SBI and CBI instructions  */
> > >> >    BFD_RELOC_RISCV_SET16,
> > >> >    BFD_RELOC_RISCV_SET32,
> > >> >    BFD_RELOC_RISCV_32_PCREL,
> > >> > +  BFD_RELOC_RISCV_SET_ULEB128,
> > >> > +  BFD_RELOC_RISCV_SUB_ULEB128,
> > >> >
> > >> >  /* Renesas RL78 Relocations.  */
> > >> >    BFD_RELOC_RL78_NEG8,
> > >> > diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
> > >> > index 997f786602..075ef6b82d 100644
> > >> > --- a/bfd/elfnn-riscv.c
> > >> > +++ b/bfd/elfnn-riscv.c
> > >> > @@ -1419,6 +1419,26 @@ riscv_global_pointer_value (struct bfd_link_info *info)
> > >> >    return h->u.def.value + sec_addr (h->u.def.section);
> > >> >  }
> > >> >
> > >> > +/* Write VAL in uleb128 format to P, returning a pointer to the
> > >> > +   following byte.
> > >> > +   This code is copied from elf-attr.c.  */
> > >> > +
> > >> > +static bfd_byte *
> > >> > +write_uleb128 (bfd_byte *p, unsigned int val)
> > >> > +{
> > >> > +  bfd_byte c;
> > >> > +  do
> > >> > +    {
> > >> > +      c = val & 0x7f;
> > >> > +      val >>= 7;
> > >> > +      if (val)
> > >> > +        c |= 0x80;
> > >> > +      *(p++) = c;
> > >> > +    }
> > >> > +  while (val);
> > >> > +  return p;
> > >> > +}
> > >> > +
> > >> >  /* Emplace a static relocation.  */
> > >> >
> > >> >  static bfd_reloc_status_type
> > >> > @@ -1512,6 +1532,25 @@ perform_relocation (const reloc_howto_type *howto,
> > >> >          value = ENCODE_RVC_LUI_IMM (RISCV_CONST_HIGH_PART (value));
> > >> >        break;
> > >> >
> > >> > +    case R_RISCV_SET_ULEB128:
> > >> > +    case R_RISCV_SUB_ULEB128:
> > >> > +      {
> > >> > +        unsigned int len = 0;
> > >> > +        bfd_byte *endp, *p;
> > >> > +
> > >> > +        _bfd_read_unsigned_leb128 (input_bfd, contents + rel->r_offset, &len);
> > >> > +
> > >> > +        /* Clean the contents value to zero.  Do not reduce the length.  */
> > >> > +        p = contents + rel->r_offset;
> > >> > +        endp = p + len -1;
> > >> > +        memset (p, 0x80, len);
> > >> > +        *(endp) = 0;
> > >> > +        p = write_uleb128 (p, value) - 1;
> > >> > +        if (p < endp)
> > >> > +          *p |= 0x80;
> > >> > +        return bfd_reloc_ok;
> > >> > +      }
> > >> > +
> > >> >      case R_RISCV_32:
> > >> >      case R_RISCV_64:
> > >> >      case R_RISCV_ADD8:
> > >> > @@ -1767,6 +1806,8 @@ riscv_elf_relocate_section (bfd *output_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;
> > >> > +  bfd_vma uleb128_vma;
> > >> > +  Elf_Internal_Rela *uleb128_rel = NULL;
> > >> >
> > >> >    if (!riscv_init_pcrel_relocs (&pcrel_relocs))
> > >> >      return FALSE;
> > >> > @@ -1871,6 +1912,47 @@ riscv_elf_relocate_section (bfd *output_bfd,
> > >> >          case R_RISCV_DELETE:
> > >> >            /* These require no special handling beyond perform_relocation.  */
> > >> >            break;
> > >> > +        case R_RISCV_SET_ULEB128:
> > >> > +          if (!uleb128_rel)
> > >> > +            {
> > >> > +              /* Save the minuend to use later.  */
> > >> > +              uleb128_vma = relocation;
> > >> > +              uleb128_rel = rel;
> > >> > +              continue;
> > >> > +            }
> > >> > +          else
> > >> > +            {
> > >> > +              if (uleb128_rel->r_offset != rel->r_offset)
> > >> > +                {
> > >> > +                  (*_bfd_error_handler) (_("%pB: relocation %s mismatched. "),
> > >> > +                                         input_bfd, howto->name);
> > >> > +                  bfd_set_error (bfd_error_bad_value);
> > >> > +                }
> > >> > +              relocation = relocation - uleb128_vma;
> > >> > +              uleb128_rel = NULL;
> > >> > +              break;
> > >> > +            }
> > >> > +
> > >> > +        case R_RISCV_SUB_ULEB128:
> > >> > +          if (uleb128_rel)
> > >> > +            {
> > >> > +              if (uleb128_rel->r_offset != rel->r_offset)
> > >> > +                {
> > >> > +                  (*_bfd_error_handler) (_("%pB: relocation %s mismatched. "),
> > >> > +                                         input_bfd, howto->name);
> > >> > +                  bfd_set_error (bfd_error_bad_value);
> > >> > +                }
> > >> > +              relocation = uleb128_vma - relocation;
> > >>
> > >> GCC gives me -Wmaybe-uninitialized for both of these.
> > >>
> > >> > +              uleb128_rel = NULL;
> > >> > +              break;
> > >> > +            }
> > >> > +          else
> > >> > +            {
> > >> > +              /* Save the subtrahend to use later.  */
> > >> > +              uleb128_vma = relocation;
> > >> > +              uleb128_rel = rel;
> > >> > +              continue;
> > >> > +            }
> > >> >
> > >> >          case R_RISCV_GOT_HI20:
> > >> >            if (h != NULL)
> > >> > diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c
> > >> > index 245717f70f..c136ba2207 100644
> > >> > --- a/bfd/elfxx-riscv.c
> > >> > +++ b/bfd/elfxx-riscv.c
> > >> > @@ -38,6 +38,8 @@
> > >> >     relocations for the debug info.  */
> > >> >  static bfd_reloc_status_type riscv_elf_add_sub_reloc
> > >> >    (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
> > >> > +static bfd_reloc_status_type riscv_elf_ignore_reloc
> > >> > +  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
> > >> >
> > >> >  /* The relocation table used for SHT_RELA sections.  */
> > >> >
> > >> > @@ -855,8 +857,41 @@ static reloc_howto_type howto_table[] =
> > >> >           0,                                /* src_mask */
> > >> >           MINUS_ONE,                        /* dst_mask */
> > >> >           FALSE),                        /* pcrel_offset */
> > >> > +
> > >> > +  /* The length of unsigned-leb128 is variant, just assume the
> > >> > +     size is one byte here.  */
> > >> > +  HOWTO (R_RISCV_SET_ULEB128,                /* type */
> > >> > +         0,                                /* rightshift */
> > >> > +         0,                                /* size */
> > >> > +         0,                                /* bitsize */
> > >> > +         FALSE,                                /* pc_relative */
> > >> > +         0,                                /* bitpos */
> > >> > +         complain_overflow_dont,        /* complain_on_overflow */
> > >> > +         riscv_elf_ignore_reloc,        /* special_function */
> > >> > +         "R_RISCV_SET_ULEB128",                /* name */
> > >> > +         FALSE,                                /* partial_inplace */
> > >> > +         0,                                /* src_mask */
> > >> > +         0,                                /* dst_mask */
> > >> > +         FALSE),                        /* pcrel_offset */
> > >>
> > >> I don't understand how this could possibly work: uleb128s can be long, so we
> > >> can't just treat them as a single byte.  I'm having trouble testing it, though,
> > >> as I can't figure out how to emit R_RISCV_SET_ULEB128 alone.  For example, when
> > >> I try to insert a uleb128 in the assembler I'm not even getting a relocation:
> > >>
> > >>     .text
> > >>     .globl _start
> > >>     _start:
> > >>             nop
> > >>     .L0:
> > >>             nop
> > >>     .L1:
> > >>     uleb_l0:
> > >>             addi x0, x0, 1
> > >>             .uleb128 .L0
> > >>             # Manually fix up the alignment, as .align is broken.
> > >>             .rept 3
> > >>             .byte 0xAA
> > >>             .endr
> > >>             addi x0, x0, 2
> > >>
> > >>     $ objdump -dr
> > >>     test.o:     file format elf64-littleriscv
> > >>
> > >>
> > >>     Disassembly of section .text:
> > >>
> > >>     0000000000000000 <_start>:
> > >>        0:   00000013                nop
> > >>        4:   00000013                nop
> > >>
> > >>     0000000000000008 <uleb_l0>:
> > >>        8:   00100013                li      zero,1
> > >>        c:   aa04                    fsd     fs1,16(a2)
> > >>        e:   aaaa                    fsd     fa0,336(sp)
> > >>       10:   00200013                li      zero,2
> > >>
> > >> so then when I link I'm just getting the wrong value entirely.
> > >>
> > >>     test:     file format elf64-littleriscv
> > >>
> > >>
> > >>     Disassembly of section .text:
> > >>
> > >>     0000000000010078 <_start>:
> > >>        10078:       00000013                nop
> > >>        1007c:       00000013                nop
> > >>
> > >>     0000000000010080 <uleb_l0>:
> > >>        10080:       00100013                li      zero,1
> > >>        10084:       aa04                    fsd     fs1,16(a2)
> > >>        10086:       aaaa                    fsd     fa0,336(sp)
> > >>        10088:       00200013                li      zero,2
> > >>
> > >> > +  /* The length of unsigned-leb128 is variant, just assume the
> > >> > +     size is one byte here.  */
> > >> > +  HOWTO (R_RISCV_SUB_ULEB128,                /* type */
> > >> > +         0,                                /* rightshift */
> > >> > +         0,                                /* size */
> > >> > +         0,                                /* bitsize */
> > >> > +         FALSE,                                /* pc_relative */
> > >> > +         0,                                /* bitpos */
> > >> > +         complain_overflow_dont,        /* complain_on_overflow */
> > >> > +         riscv_elf_ignore_reloc,        /* special_function */
> > >> > +         "R_RISCV_SUB_ULEB128",                /* name */
> > >> > +         FALSE,                                /* partial_inplace */
> > >> > +         0,                                /* src_mask */
> > >> > +         0,                                /* dst_mask */
> > >> > +         FALSE),                        /* pcrel_offset */
> > >> >  };
> > >>
> > >> I can get a R_RISCV_SUB_ULEB128, but it appears to be both producing the wrong
> > >> value and garbaging up bytes after the relocation.  For example:
> > >>
> > >>     .text
> > >>     .globl _start
> > >>     _start:
> > >>             nop
> > >>     .L0:
> > >>             nop
> > >>     .L1:
> > >>     uleb_l1_l0:
> > >>             addi x0, x0, 1
> > >>             .uleb128 .L1 - .L0
> > >>             # Manually fix up the alignment, as .align is broken
> > >>             .rept 3
> > >>             .byte 0xAA
> > >>             .endr
> > >>             addi x0, x0, 2
> > >>
> > >> produces the relocation
> > >>
> > >>     test.o:     file format elf64-littleriscv
> > >>
> > >>
> > >>     Disassembly of section .text:
> > >>
> > >>     0000000000000000 <_start>:
> > >>        0:   00000013                nop
> > >>
> > >>     0000000000000004 <.L0>:
> > >>        4:   00000013                nop
> > >>
> > >>     0000000000000008 <uleb_l1_l0>:
> > >>        8:   00100013                li      zero,1
> > >>        c:   aa04                    fsd     fs1,16(a2)
> > >>                             c: R_RISCV_SET_ULEB128  .L1
> > >>                             c: R_RISCV_SUB_ULEB128  .L0
> > >>        e:   aaaa                    fsd     fa0,336(sp)
> > >>       10:   00200013                li      zero,2
> > >>
> > >> but then goes and corrupts the resulting executable
> > >>
> > >>
> > >>     test:     file format elf64-littleriscv
> > >>     Disassembly of section .text:
> > >>
> > >>     0000000000010078 <_start>:
> > >>        10078:       00000013                nop
> > >>        1007c:       00000013                nop
> > >>
> > >>     0000000000010080 <uleb_l1_l0>:
> > >>        10080:       00100013                li      zero,1
> > >>        10084:       ff84                    sd      s1,56(a5)
> > >>        10086:       000ffffb                0xffffb
> > >>        1008a:       0020                    addi    s0,sp,8
> > >>
> > >> I can't think of a way to make this work aside from just emitting uleb128s at
> > >> their full length, which would make them work but would really defeat the
> > >> purpose of the format.  I guess we could then relax these, but that seems like
> > >> a lot of work.
> > >>
> > >> > +
> > >> >  /* A mapping from BFD reloc types to RISC-V ELF reloc types.  */
> > >> >
> > >> >  struct elf_reloc_map
> > >> > @@ -917,6 +952,8 @@ static const struct elf_reloc_map riscv_reloc_map[] =
> > >> >    { 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_SET_ULEB128, R_RISCV_SET_ULEB128 },
> > >> > +  { BFD_RELOC_RISCV_SUB_ULEB128, R_RISCV_SUB_ULEB128 },
> > >> >  };
> > >> >
> > >> >  /* Given a BFD reloc type, return a howto structure.  */
> > >> > @@ -1011,6 +1048,20 @@ riscv_elf_add_sub_reloc (bfd *abfd,
> > >> >    return bfd_reloc_ok;
> > >> >  }
> > >> >
> > >> > +/* Special handler for relocations which don't have to be relocated.
> > >> > +   This function just simply return bfd_reloc_ok.  */
> > >> > +static bfd_reloc_status_type
> > >> > +riscv_elf_ignore_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry,
> > >> > +                        asymbol *symbol ATTRIBUTE_UNUSED,
> > >> > +                        void *data ATTRIBUTE_UNUSED, asection *input_section,
> > >> > +                        bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED)
> > >> > +{
> > >> > +  if (output_bfd != NULL)
> > >> > +    reloc_entry->address += input_section->output_offset;
> > >> > +
> > >> > +  return bfd_reloc_ok;
> > >> > +}
> > >> > +
> > >> >  /* Parsing subset version.
> > >> >
> > >> >     Return Value:
> > >> > diff --git a/bfd/libbfd.h b/bfd/libbfd.h
> > >> > index 77b732ee4b..7aa8f91504 100644
> > >> > --- a/bfd/libbfd.h
> > >> > +++ b/bfd/libbfd.h
> > >> > @@ -2327,6 +2327,8 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
> > >> >    "BFD_RELOC_RISCV_SET16",
> > >> >    "BFD_RELOC_RISCV_SET32",
> > >> >    "BFD_RELOC_RISCV_32_PCREL",
> > >> > +  "BFD_RELOC_RISCV_SET_ULEB128",
> > >> > +  "BFD_RELOC_RISCV_SUB_ULEB128",
> > >> >    "BFD_RELOC_RL78_NEG8",
> > >> >    "BFD_RELOC_RL78_NEG16",
> > >> >    "BFD_RELOC_RL78_NEG24",
> > >> > diff --git a/bfd/reloc.c b/bfd/reloc.c
> > >> > index b00b79f319..9b8b75ad21 100644
> > >> > --- a/bfd/reloc.c
> > >> > +++ b/bfd/reloc.c
> > >> > @@ -5212,6 +5212,10 @@ ENUMX
> > >> >    BFD_RELOC_RISCV_SET32
> > >> >  ENUMX
> > >> >    BFD_RELOC_RISCV_32_PCREL
> > >> > +ENUMX
> > >> > +  BFD_RELOC_RISCV_SET_ULEB128
> > >> > +ENUMX
> > >> > +  BFD_RELOC_RISCV_SUB_ULEB128
> > >> >  ENUMDOC
> > >> >    RISC-V relocations.
> > >> >
> > >> > diff --git a/gas/ChangeLog b/gas/ChangeLog
> > >> > index 09991524da..e53ac0895b 100644
> > >> > --- a/gas/ChangeLog
> > >> > +++ b/gas/ChangeLog
> > >> > @@ -1,3 +1,11 @@
> > >> > +2019-11-27  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
> > >> > +
> > >> > +        * config/tc-riscv.c (md_apply_fix): Add BFD_RELOC_RISCV_SET_ULEB128 and
> > >> > +        BFD_RELOC_RISCV_SUB_ULEB128.
> > >> > +        (riscv_insert_uleb128_fixes): New function.
> > >> > +        (riscv_md_end): Scan rs_leb128 fragments.
> > >> > +        (riscv_pseudo_table): Remove uleb128.
> > >> > +
> > >> >  2019-11-25  Andrew Pinski  <apinski@marvell.com>
> > >> >
> > >> >          * config/tc-aarch64.c (md_begin): Use correct
> > >> > diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
> > >> > index e50505138e..c35c591c0a 100644
> > >> > --- a/gas/config/tc-riscv.c
> > >> > +++ b/gas/config/tc-riscv.c
> > >> > @@ -2392,6 +2392,9 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
> > >> >      case BFD_RELOC_RISCV_SUB32:
> > >> >      case BFD_RELOC_RISCV_SUB64:
> > >> >      case BFD_RELOC_RISCV_RELAX:
> > >> > +    /* cvt_frag_to_fill () has called output_leb128 ().  */
> > >> > +    case BFD_RELOC_RISCV_SET_ULEB128:
> > >> > +    case BFD_RELOC_RISCV_SUB_ULEB128:
> > >> >        break;
> > >> >
> > >> >      case BFD_RELOC_RISCV_TPREL_HI20:
> > >> > @@ -3127,11 +3130,54 @@ riscv_set_public_attributes (void)
> > >> >      riscv_write_out_arch_attr ();
> > >> >  }
> > >> >
> > >> > +/* Scan uleb128 subtraction expressions and insert fixups for them.
> > >> > +   e.g., .uleb128 .L1 - .L0
> > >> > +   Becuase relaxation may change the value of the subtraction, we
> > >> > +   must resolve them in link-time.  */
> > >> > +
> > >> > +static void
> > >> > +riscv_insert_uleb128_fixes (bfd *abfd ATTRIBUTE_UNUSED,
> > >> > +                            asection *sec, void *xxx ATTRIBUTE_UNUSED)
> > >> > +{
> > >> > +  segment_info_type *seginfo = seg_info (sec);
> > >> > +  struct frag *fragP;
> > >> > +
> > >> > +  subseg_set (sec, 0);
> > >> > +
> > >> > +  for (fragP = seginfo->frchainP->frch_root;
> > >> > +       fragP; fragP = fragP->fr_next)
> > >> > +    {
> > >> > +      expressionS *exp, *exp_dup;
> > >> > +
> > >> > +      if (fragP->fr_type != rs_leb128  || fragP->fr_symbol == NULL)
> > >> > +        continue;
> > >> > +
> > >> > +      exp = symbol_get_value_expression (fragP->fr_symbol);
> > >> > +
> > >> > +      if (exp->X_op != O_subtract)
> > >> > +        continue;
> > >>
> > >> Presumably that's why I can't get a _SET alone.
> > >>
> > >> > +
> > >> > +      /* Only unsigned leb128 can be handle.  */
> > >> > +      gas_assert (fragP->fr_subtype == 0);
> > >> > +      exp_dup = xmemdup (exp, sizeof (*exp), sizeof (*exp));
> > >> > +      exp_dup->X_op = O_symbol;
> > >> > +      exp_dup->X_op_symbol = NULL;
> > >> > +
> > >> > +      /* Insert relocations to resolve the subtraction in link-time.  */
> > >> > +      fix_new_exp (fragP, fragP->fr_fix, 0,
> > >> > +                   exp_dup, 0, BFD_RELOC_RISCV_SET_ULEB128);
> > >> > +      exp_dup->X_add_symbol = exp->X_op_symbol;
> > >> > +      fix_new_exp (fragP, fragP->fr_fix, 0,
> > >> > +                   exp_dup, 0, BFD_RELOC_RISCV_SUB_ULEB128);
> > >> > +    }
> > >> > +}
> > >> > +
> > >> >  /* Called after all assembly has been done.  */
> > >> >
> > >> >  void
> > >> >  riscv_md_end (void)
> > >> >  {
> > >> > +  bfd_map_over_sections (stdoutput, riscv_insert_uleb128_fixes, NULL);
> > >> >    riscv_set_public_attributes ();
> > >> >  }
> > >> >
> > >> > @@ -3215,7 +3261,6 @@ static const pseudo_typeS riscv_pseudo_table[] =
> > >> >    {"dtprelword", s_dtprel, 4},
> > >> >    {"dtpreldword", s_dtprel, 8},
> > >> >    {"bss", s_bss, 0},
> > >> > -  {"uleb128", s_riscv_leb128, 0},
> > >> >    {"sleb128", s_riscv_leb128, 1},
> > >> >    {"insn", s_riscv_insn, 0},
> > >> >    {"attribute", s_riscv_attribute, 0},
> > >> > diff --git a/include/ChangeLog b/include/ChangeLog
> > >> > index 47bb86cf71..c290b245c6 100644
> > >> > --- a/include/ChangeLog
> > >> > +++ b/include/ChangeLog
> > >> > @@ -1,3 +1,7 @@
> > >> > +2019-11-27  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
> > >> > +
> > >> > +        * elf/riscv.h ((R_RISCV_SET_ULEB128, (R_RISCV_SUB_ULEB128): Define.
> > >> > +
> > >> >  2019-11-25  Alan Modra  <amodra@gmail.com>
> > >> >
> > >> >          * coff/ti.h (GET_SCNHDR_SIZE, PUT_SCNHDR_SIZE, GET_SCN_SCNLEN),
> > >> > diff --git a/include/elf/riscv.h b/include/elf/riscv.h
> > >> > index 2f98aa4a3e..030679b35f 100644
> > >> > --- a/include/elf/riscv.h
> > >> > +++ b/include/elf/riscv.h
> > >> > @@ -88,6 +88,8 @@ START_RELOC_NUMBERS (elf_riscv_reloc_type)
> > >> >    RELOC_NUMBER (R_RISCV_SET16, 55)
> > >> >    RELOC_NUMBER (R_RISCV_SET32, 56)
> > >> >    RELOC_NUMBER (R_RISCV_32_PCREL, 57)
> > >> > +  RELOC_NUMBER (R_RISCV_SET_ULEB128, 58)
> > >> > +  RELOC_NUMBER (R_RISCV_SUB_ULEB128, 59)
> > >> >  END_RELOC_NUMBERS (R_RISCV_max)
> > >> >
> > >> >  /* Processor specific flags for the ELF header e_flags field.  */
> > >> > diff --git a/ld/ChangeLog b/ld/ChangeLog
> > >> > index 969ab78035..5c2e406101 100644
> > >> > --- a/ld/ChangeLog
> > >> > +++ b/ld/ChangeLog
> > >> > @@ -1,3 +1,9 @@
> > >> > +2019-11-27  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
> > >> > +
> > >> > +        * testsuite/ld-riscv-elf/ld-riscv-elf.exp: Add uleb128.
> > >> > +        * testsuite/ld-riscv-elf/uleb128.d: New test.
> > >> > +        * testsuite/ld-riscv-elf/uleb128.s: New file.
> > >> > +
> > >> >  2019-11-26  Martin Liska  <mliska@suse.cz>
> > >> >
> > >> >          * scripttempl/arclinux.sc: Add .text.sorted.* which is sorted
> > >> > diff --git a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
> > >> > index 7aabbdd641..809e40f08d 100644
> > >> > --- a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
> > >> > +++ b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
> > >> > @@ -38,6 +38,7 @@ if [istarget "riscv*-*-*"] {
> > >> >      run_dump_test "attr-merge-priv-spec"
> > >> >      run_dump_test "attr-merge-arch-failed-01"
> > >> >      run_dump_test "attr-merge-stack-align-failed"
> > >> > +    run_dump_test "uleb128"
> > >> >      run_ld_link_tests {
> > >> >          { "Weak reference 32" "-T weakref.ld -melf32lriscv" ""
> > >> >              "-march=rv32i -mabi=ilp32" {weakref32.s}
> > >> > diff --git a/ld/testsuite/ld-riscv-elf/uleb128.d b/ld/testsuite/ld-riscv-elf/uleb128.d
> > >> > new file mode 100644
> > >> > index 0000000000..a921478e98
> > >> > --- /dev/null
> > >> > +++ b/ld/testsuite/ld-riscv-elf/uleb128.d
> > >> > @@ -0,0 +1,18 @@
> > >> > +#source: uleb128.s
> > >> > +#as: -march=rv32ic
> > >> > +#ld: -melf32lriscv
> > >> > +#objdump: -d
> > >> > +
> > >> > +.*:[         ]+file format .*
> > >> > +
> > >> > +Disassembly of section .text:
> > >> > +
> > >> > +.* <_start>:
> > >> > +.*jal.*<bar>
> > >> > +.*jal.*<bar>
> > >> > +.*jal.*<bar>
> > >> > +.*jal.*<bar>
> > >> > +.*jal.*<bar>
> > >> > +.*jal.*<bar>
> > >> > +.*:[         ]+0e0c.*
> > >> > +#pass
> > >> > diff --git a/ld/testsuite/ld-riscv-elf/uleb128.s b/ld/testsuite/ld-riscv-elf/uleb128.s
> > >> > new file mode 100644
> > >> > index 0000000000..f7d23be163
> > >> > --- /dev/null
> > >> > +++ b/ld/testsuite/ld-riscv-elf/uleb128.s
> > >> > @@ -0,0 +1,18 @@
> > >> > +.text
> > >> > +.globl bar
> > >> > +.globl _start
> > >> > +.option rvc
> > >> > +.align 2
> > >> > +_start:
> > >> > +.L0:
> > >> > +        .rept 6
> > >> > +        call bar
> > >> > +        .endr
> > >> > +.align 2
> > >> > +.L1:
> > >> > +        .uleb128 .L1 - .L0
> > >> > +        .uleb128 .L2 - .L0
> > >> > +.L2:
> > >> > +.align 2
> > >> > +bar:
> > >> > +        nop
> > >>
> > >> It looks like alignment is broken here after uleb128s, but it's not actually
> > >> triggering an error in all cases.  Having two of them in this test case doesn't
> > >> trigger the issue, but an odd number does.  For example, the following source
> > >>
> > >>     .text
> > >>     .globl _start
> > >>     .align 2
> > >>     _start:
> > >>             .uleb128 _start
> > >>     .align 2
> > >>     _end:
> > >>             nop
> > >>
> > >> links _end to a misaligned symbol
> > >>
> > >>     Disassembly of section .text:
> > >>
> > >>     0000000000010078 <_start>:
> > >>             ...
> > >>
> > >>     0000000000010079 <_end>:
> > >>        10079:       00000013                nop
> > >>        1007d:       0000                    unimp
> > >>             ...
> > >>
> > >> I'm assuming that's because norvc assumes 4-byte alignment in text sections, so
> > >> it's just eliding the alingment directives.  With RVC I do get an error message
> > >>
> > >>     .text
> > >>     .globl _start
> > >>     .option rvc
> > >>     .align 2
> > >>     _start:
> > >>             .uleb128 _start
> > >>     .align 2
> > >>     _end:
> > >>             nop
> > >>
> > >>     ./install/bin/riscv64-unknown-linux-gnu-ld: test.o(.text+0x1): 3 bytes required for alignment to 4-byte boundary, but only 2 present
> > >>     ./install/bin/riscv64-unknown-linux-gnu-ld: can't relax section: bad value
> > >>
> > >>
> > >
> > >
> > > --
> > > Best regards,
> > > Kuan-Lin Chen.
> > > kuanlinchentw@gmail.com
>
>
>
> --
> Best regards,
> Kuan-Lin Chen.
> kuanlinchentw@gmail.com

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] [RISCV] Support subtraction of .uleb128.
  2020-09-25  7:14       ` Kito Cheng
@ 2020-09-25 15:55         ` Jozef Lawrynowicz
  0 siblings, 0 replies; 17+ messages in thread
From: Jozef Lawrynowicz @ 2020-09-25 15:55 UTC (permalink / raw)
  To: Kito Cheng
  Cc: Kuan-Lin Chen, Palmer Dabbelt, binutils@sourceware.org Development

On Fri, Sep 25, 2020 at 03:14:01PM +0800, Kito Cheng via Binutils wrote:
> Hi Jim, Palmer:
> 
> ping, I think this patch should be ready to land after rebase and
> adjust reloc number?

Hi,

You may want to look at some of the improvements I made to the original
patch in my commit of this functionality for msp430-elf, in 7d81bc937c.

Particularly, the "right-aligning" of the finalized uleb128 value within
the available space, preventing the clobbering of bytes following the
uleb128 value if the available space is not enough, and leveraging BFD
library functions for writing out the uleb128 value.

I also had to make adjustments to msp430_insert_uleb128_fixes, but they
may have been target-specific requirements.

Regards,
Jozef

> 
> On Wed, Jan 22, 2020 at 3:26 PM Kuan-Lin Chen <kuanlinchentw@gmail.com> wrote:
> >
> > Hi,
> >
> > This version patch updates as follows:
> > Fix the warning about uninitialized variable.
> > Set a limit to .uleb128 expressions as Palmer's suggestion.
> > Thanks.
> >
> > Palmer Dabbelt <palmerdabbelt@google.com> 於 2020年1月10日 週五 上午7:19寫道:
> > >
> > > On Mon, 09 Dec 2019 21:42:58 PST (-0800), kuanlinchentw@gmail.com wrote:
> > > > Hi Palmer,
> > > >
> > > >> GCC gives me -Wmaybe-uninitialized for both of these.
> > > > May I know your gcc version?
> > > > I tried gcc-7.3.0 and gcc-8.2.0, and I didn't get the warning.
> > >
> > > $ gcc --version
> > > gcc (Debian 8.3.0-6) 8.3.0
> > > Copyright (C) 2018 Free Software Foundation, Inc.
> > > This is free software; see the source for copying conditions.  There is NO
> > > warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
> > >
> > > >> I don't understand how this could possibly work: uleb128s can be long, so we
> > > >> can't just treat them as a single byte.
> > > > Yes, uleb128s can be long so I implement riscv_elf_ignore_reloc to
> > > > ignore the overflow checking.
> > > > And I relocate uleb128s by myself in perform_relocation.
> > > >
> > > >> I'm having trouble testing it, though,
> > > >> as I can't figure out how to emit R_RISCV_SET_ULEB128 alone.  For example, when
> > > >> I try to insert a uleb128 in the assembler I'm not even getting a relocation:
> > > > .uleb128 only support subtract format. (.uleb128 .L1 - .L0)
> > > > It is impossible to get final the value and the length for ".uleb128
> > > > symbol" in assemble-time.
> > >
> > > Well, you know symbols are at most 64-bit on rv64 and 32-bit on rv32, so you
> > > can just emit enough space to encode any symbol.  That's better than emitting 7
> > > bits, which is unlikely to encode any symbol.
> > >
> > > > I think ".uleb128 symbol" is meaningless.
> > > > Therefore, all targets just fill the value as assemble-time value
> > > > without relocations.
> > >
> > > If the assembler can't handle something then it needs to provide an error, it
> > > can't just generate incorrect code.
> > >
> > > >>I can get a R_RISCV_SUB_ULEB128, but it appears to be both producing the wrong
> > > >>value and garbaging up bytes after the relocation.  For example:
> > > >
> > > > I get the same result in the object file but the different result in executable.
> > > > pal.o:     file format elf64-littleriscv
> > > >
> > > > Disassembly of section .text:
> > > >
> > > > 0000000000000000 <_start>:
> > > >    0:   00000013                nop
> > > >
> > > > 0000000000000004 <.L0>:
> > > >    4:   00000013                nop
> > > >
> > > > 0000000000000008 <uleb_l1_l0>:
> > > >    8:   00100013                li      zero,1
> > > >    c:   aa04                    fsd     fs1,16(a2)
> > > >                         c: R_RISCV_SET_ULEB128  .L1
> > > >                         c: R_RISCV_SUB_ULEB128  .L0
> > > >    e:   aaaa                    fsd     fa0,336(sp)
> > > >   10:   00200013                li      zero,2
> > > >
> > > >
> > > > a.out:     file format elf64-littleriscv
> > > >
> > > >
> > > > Disassembly of section .text:
> > > >
> > > > 0000000000010078 <_start>:
> > > >    10078:       00000013                nop
> > > >    1007c:       00000013                nop
> > > >
> > > > 0000000000010080 <uleb_l1_l0>:
> > > >    10080:       00100013                li      zero,1
> > > >    10084:       aa04                    fsd     fs1,16(a2)
> > > >    10086:       aaaa                    fsd     fa0,336(sp)
> > > >    10088:       00200013                li      zero,2
> > > >
> > > > Maybe there is something mismatched. But I don't have any idea currently.
> > > > Could you please give me more information about your flow?
> > >
> > > IIRC I just applied the patch on top of whatever was HEAD of binutils-gdb at
> > > the time, but I don't have the working directory around any more.
> > >
> > > > Thanks.
> > > >
> > > >> Presumably that's why I can't get a _SET alone.
> > > > I think it's meaningless to use _SET alone in assembly.
> > > >
> > > >> It looks like alignment is broken here after uleb128s, but it's not actually
> > > >> triggering an error in all cases.  Having two of them in this test case doesn't
> > > >> trigger the issue, but an odd number does.  For example, the following source
> > > > I think this alignment issue can be fixed by the following patch:
> > > > https://sourceware.org/ml/binutils/2019-12/msg00024.html
> > >
> > > Ya, thanks -- I think there's some issues there as well, IIRC I commented on
> > > it.
> > >
> > > >
> > > > Thanks for your review.
> > > >
> > > > Palmer Dabbelt <palmerdabbelt@google.com> 於 2019年12月7日 週六 上午7:47寫道:
> > > >>
> > > >> On Wed, 27 Nov 2019 00:11:50 PST (-0800), kuanlinchentw@gmail.com wrote:
> > > >> > The data length of uleb128 is variable.  So linker must recalculate the
> > > >> > value of the subtraction.  The patch leave relocations in object files
> > > >> > so that linker can relocate again after relaxation.
> > > >> >
> > > >> > bfd/ChangeLog:
> > > >> > * bfd-in2.h: Regenerated.
> > > >> > * elfnn-riscv.c (write_uleb128): New function.
> > > >> > (perform_relocation): Perform R_RISCV_SUB_ULEB128 and
> > > >> > R_RISCV_SET_ULEB128 relocation.
> > > >> > (riscv_elf_relocate_section): Likewise.
> > > >> > * elfxx-riscv.c (howto_table): Add R_RISCV_SUB_ULEB128 and
> > > >> > R_RISCV_SET_ULEB128.
> > > >> > (riscv_elf_ignore_reloc): New function.
> > > >> > * libbfd.h: Regenerated.
> > > >> > * reloc.c (BFD_RELOC_RISCV_SET_ULEB128, BFD_RELOC_RISCV_SUB_ULEB128):
> > > >> > New relocations to support .uleb128.
> > > >> >
> > > >> > gas/ChangeLog:
> > > >> > * config/tc-riscv.c (md_apply_fix): Add BFD_RELOC_RISCV_SET_ULEB128 and
> > > >> > BFD_RELOC_RISCV_SUB_ULEB128.
> > > >> > (riscv_insert_uleb128_fixes): New function.
> > > >> > (riscv_md_end): Scan rs_leb128 fragments.
> > > >> > (riscv_pseudo_table): Remove uleb128.
> > > >> >
> > > >> > include/ChangeLog:
> > > >> > * elf/riscv.h ((R_RISCV_SET_ULEB128, (R_RISCV_SUB_ULEB128): Define.
> > > >> >
> > > >> > ld/ChangeLog:
> > > >> > * testsuite/ld-riscv-elf/ld-riscv-elf.exp: Add uleb128.
> > > >> > * testsuite/ld-riscv-elf/uleb128.d: New test.
> > > >> > * testsuite/ld-riscv-elf/uleb128.s: New file.
> > > >> >
> > > >> > OK to commit?
> > > >>
> > > >> I'm having a lot of trouble trying to figure out how this works.  LMK if I'm
> > > >> missing something, there's some comments in line:
> > > >>
> > > >> > From 9f7f0aaa484dee2b32c550f8cca4de18959f01e1 Mon Sep 17 00:00:00 2001
> > > >> > From: Kuan-Lin Chen <rufus@andestech.com>
> > > >> > Date: Thu, 14 Nov 2019 14:24:22 +0800
> > > >> > Subject: [PATCH] RISC-V: Support subtraction of .uleb128.
> > > >> >
> > > >> > The data length of uleb128 is variable.  So linker must recalculate the
> > > >> > value of the subtraction.  The patch leave relocations in object files
> > > >> > so that linker can relocate again after relaxation.
> > > >> >
> > > >> > bfd/ChangeLog:
> > > >> >         * bfd-in2.h: Regenerated.
> > > >> >         * elfnn-riscv.c (write_uleb128): New function.
> > > >> >         (perform_relocation): Perform R_RISCV_SUB_ULEB128 and
> > > >> >          R_RISCV_SET_ULEB128 relocation.
> > > >> >         (riscv_elf_relocate_section): Likewise.
> > > >> >         * elfxx-riscv.c (howto_table): Add R_RISCV_SUB_ULEB128 and
> > > >> >         R_RISCV_SET_ULEB128.
> > > >> >         (riscv_elf_ignore_reloc): New function.
> > > >> >         * libbfd.h: Regenerated.
> > > >> >         * reloc.c (BFD_RELOC_RISCV_SET_ULEB128, BFD_RELOC_RISCV_SUB_ULEB128):
> > > >> >         New relocations to support .uleb128.
> > > >> >
> > > >> > gas/ChangeLog:
> > > >> >         * config/tc-riscv.c (md_apply_fix): Add BFD_RELOC_RISCV_SET_ULEB128 and
> > > >> >         BFD_RELOC_RISCV_SUB_ULEB128.
> > > >> >         (riscv_insert_uleb128_fixes): New function.
> > > >> >         (riscv_md_end): Scan rs_leb128 fragments.
> > > >> >         (riscv_pseudo_table): Remove uleb128.
> > > >> >
> > > >> > include/ChangeLog:
> > > >> >         * elf/riscv.h ((R_RISCV_SET_ULEB128, (R_RISCV_SUB_ULEB128): Define.
> > > >> >
> > > >> > ld/ChangeLog:
> > > >> >         * testsuite/ld-riscv-elf/ld-riscv-elf.exp: Add uleb128.
> > > >> >         * testsuite/ld-riscv-elf/uleb128.d: New test.
> > > >> >         * testsuite/ld-riscv-elf/uleb128.s: New file.
> > > >> > ---
> > > >> >  bfd/ChangeLog                              | 14 ++++
> > > >> >  bfd/bfd-in2.h                              |  2 +
> > > >> >  bfd/elfnn-riscv.c                          | 82 ++++++++++++++++++++++
> > > >> >  bfd/elfxx-riscv.c                          | 51 ++++++++++++++
> > > >> >  bfd/libbfd.h                               |  2 +
> > > >> >  bfd/reloc.c                                |  4 ++
> > > >> >  gas/ChangeLog                              |  8 +++
> > > >> >  gas/config/tc-riscv.c                      | 47 ++++++++++++-
> > > >> >  include/ChangeLog                          |  4 ++
> > > >> >  include/elf/riscv.h                        |  2 +
> > > >> >  ld/ChangeLog                               |  6 ++
> > > >> >  ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp |  1 +
> > > >> >  ld/testsuite/ld-riscv-elf/uleb128.d        | 18 +++++
> > > >> >  ld/testsuite/ld-riscv-elf/uleb128.s        | 18 +++++
> > > >> >  14 files changed, 258 insertions(+), 1 deletion(-)
> > > >> >  create mode 100644 ld/testsuite/ld-riscv-elf/uleb128.d
> > > >> >  create mode 100644 ld/testsuite/ld-riscv-elf/uleb128.s
> > > >> >
> > > >> > diff --git a/bfd/ChangeLog b/bfd/ChangeLog
> > > >> > index 4a0852e577..d11ffde74c 100644
> > > >> > --- a/bfd/ChangeLog
> > > >> > +++ b/bfd/ChangeLog
> > > >> > @@ -1,3 +1,17 @@
> > > >> > +2019-11-27  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
> > > >> > +
> > > >> > +        * bfd-in2.h: Regenerated.
> > > >> > +        * elfnn-riscv.c (write_uleb128): New function.
> > > >> > +        (perform_relocation): Perform R_RISCV_SUB_ULEB128 and
> > > >> > +         R_RISCV_SET_ULEB128 relocation.
> > > >> > +        (riscv_elf_relocate_section): Likewise.
> > > >> > +        * elfxx-riscv.c (howto_table): Add R_RISCV_SUB_ULEB128 and
> > > >> > +        R_RISCV_SET_ULEB128.
> > > >> > +        (riscv_elf_ignore_reloc): New function.
> > > >> > +        * libbfd.h: Regenerated.
> > > >> > +        * reloc.c (BFD_RELOC_RISCV_SET_ULEB128, BFD_RELOC_RISCV_SUB_ULEB128):
> > > >> > +        New relocations to support .uleb128.
> > > >> > +
> > > >> >  2019-11-27  Alan Modra  <amodra@gmail.com>
> > > >> >
> > > >> >          PR 23652
> > > >> > diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
> > > >> > index 44902fc8d0..a32708ebc2 100644
> > > >> > --- a/bfd/bfd-in2.h
> > > >> > +++ b/bfd/bfd-in2.h
> > > >> > @@ -4380,6 +4380,8 @@ number for the SBIC, SBIS, SBI and CBI instructions  */
> > > >> >    BFD_RELOC_RISCV_SET16,
> > > >> >    BFD_RELOC_RISCV_SET32,
> > > >> >    BFD_RELOC_RISCV_32_PCREL,
> > > >> > +  BFD_RELOC_RISCV_SET_ULEB128,
> > > >> > +  BFD_RELOC_RISCV_SUB_ULEB128,
> > > >> >
> > > >> >  /* Renesas RL78 Relocations.  */
> > > >> >    BFD_RELOC_RL78_NEG8,
> > > >> > diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
> > > >> > index 997f786602..075ef6b82d 100644
> > > >> > --- a/bfd/elfnn-riscv.c
> > > >> > +++ b/bfd/elfnn-riscv.c
> > > >> > @@ -1419,6 +1419,26 @@ riscv_global_pointer_value (struct bfd_link_info *info)
> > > >> >    return h->u.def.value + sec_addr (h->u.def.section);
> > > >> >  }
> > > >> >
> > > >> > +/* Write VAL in uleb128 format to P, returning a pointer to the
> > > >> > +   following byte.
> > > >> > +   This code is copied from elf-attr.c.  */
> > > >> > +
> > > >> > +static bfd_byte *
> > > >> > +write_uleb128 (bfd_byte *p, unsigned int val)
> > > >> > +{
> > > >> > +  bfd_byte c;
> > > >> > +  do
> > > >> > +    {
> > > >> > +      c = val & 0x7f;
> > > >> > +      val >>= 7;
> > > >> > +      if (val)
> > > >> > +        c |= 0x80;
> > > >> > +      *(p++) = c;
> > > >> > +    }
> > > >> > +  while (val);
> > > >> > +  return p;
> > > >> > +}
> > > >> > +
> > > >> >  /* Emplace a static relocation.  */
> > > >> >
> > > >> >  static bfd_reloc_status_type
> > > >> > @@ -1512,6 +1532,25 @@ perform_relocation (const reloc_howto_type *howto,
> > > >> >          value = ENCODE_RVC_LUI_IMM (RISCV_CONST_HIGH_PART (value));
> > > >> >        break;
> > > >> >
> > > >> > +    case R_RISCV_SET_ULEB128:
> > > >> > +    case R_RISCV_SUB_ULEB128:
> > > >> > +      {
> > > >> > +        unsigned int len = 0;
> > > >> > +        bfd_byte *endp, *p;
> > > >> > +
> > > >> > +        _bfd_read_unsigned_leb128 (input_bfd, contents + rel->r_offset, &len);
> > > >> > +
> > > >> > +        /* Clean the contents value to zero.  Do not reduce the length.  */
> > > >> > +        p = contents + rel->r_offset;
> > > >> > +        endp = p + len -1;
> > > >> > +        memset (p, 0x80, len);
> > > >> > +        *(endp) = 0;
> > > >> > +        p = write_uleb128 (p, value) - 1;
> > > >> > +        if (p < endp)
> > > >> > +          *p |= 0x80;
> > > >> > +        return bfd_reloc_ok;
> > > >> > +      }
> > > >> > +
> > > >> >      case R_RISCV_32:
> > > >> >      case R_RISCV_64:
> > > >> >      case R_RISCV_ADD8:
> > > >> > @@ -1767,6 +1806,8 @@ riscv_elf_relocate_section (bfd *output_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;
> > > >> > +  bfd_vma uleb128_vma;
> > > >> > +  Elf_Internal_Rela *uleb128_rel = NULL;
> > > >> >
> > > >> >    if (!riscv_init_pcrel_relocs (&pcrel_relocs))
> > > >> >      return FALSE;
> > > >> > @@ -1871,6 +1912,47 @@ riscv_elf_relocate_section (bfd *output_bfd,
> > > >> >          case R_RISCV_DELETE:
> > > >> >            /* These require no special handling beyond perform_relocation.  */
> > > >> >            break;
> > > >> > +        case R_RISCV_SET_ULEB128:
> > > >> > +          if (!uleb128_rel)
> > > >> > +            {
> > > >> > +              /* Save the minuend to use later.  */
> > > >> > +              uleb128_vma = relocation;
> > > >> > +              uleb128_rel = rel;
> > > >> > +              continue;
> > > >> > +            }
> > > >> > +          else
> > > >> > +            {
> > > >> > +              if (uleb128_rel->r_offset != rel->r_offset)
> > > >> > +                {
> > > >> > +                  (*_bfd_error_handler) (_("%pB: relocation %s mismatched. "),
> > > >> > +                                         input_bfd, howto->name);
> > > >> > +                  bfd_set_error (bfd_error_bad_value);
> > > >> > +                }
> > > >> > +              relocation = relocation - uleb128_vma;
> > > >> > +              uleb128_rel = NULL;
> > > >> > +              break;
> > > >> > +            }
> > > >> > +
> > > >> > +        case R_RISCV_SUB_ULEB128:
> > > >> > +          if (uleb128_rel)
> > > >> > +            {
> > > >> > +              if (uleb128_rel->r_offset != rel->r_offset)
> > > >> > +                {
> > > >> > +                  (*_bfd_error_handler) (_("%pB: relocation %s mismatched. "),
> > > >> > +                                         input_bfd, howto->name);
> > > >> > +                  bfd_set_error (bfd_error_bad_value);
> > > >> > +                }
> > > >> > +              relocation = uleb128_vma - relocation;
> > > >>
> > > >> GCC gives me -Wmaybe-uninitialized for both of these.
> > > >>
> > > >> > +              uleb128_rel = NULL;
> > > >> > +              break;
> > > >> > +            }
> > > >> > +          else
> > > >> > +            {
> > > >> > +              /* Save the subtrahend to use later.  */
> > > >> > +              uleb128_vma = relocation;
> > > >> > +              uleb128_rel = rel;
> > > >> > +              continue;
> > > >> > +            }
> > > >> >
> > > >> >          case R_RISCV_GOT_HI20:
> > > >> >            if (h != NULL)
> > > >> > diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c
> > > >> > index 245717f70f..c136ba2207 100644
> > > >> > --- a/bfd/elfxx-riscv.c
> > > >> > +++ b/bfd/elfxx-riscv.c
> > > >> > @@ -38,6 +38,8 @@
> > > >> >     relocations for the debug info.  */
> > > >> >  static bfd_reloc_status_type riscv_elf_add_sub_reloc
> > > >> >    (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
> > > >> > +static bfd_reloc_status_type riscv_elf_ignore_reloc
> > > >> > +  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
> > > >> >
> > > >> >  /* The relocation table used for SHT_RELA sections.  */
> > > >> >
> > > >> > @@ -855,8 +857,41 @@ static reloc_howto_type howto_table[] =
> > > >> >           0,                                /* src_mask */
> > > >> >           MINUS_ONE,                        /* dst_mask */
> > > >> >           FALSE),                        /* pcrel_offset */
> > > >> > +
> > > >> > +  /* The length of unsigned-leb128 is variant, just assume the
> > > >> > +     size is one byte here.  */
> > > >> > +  HOWTO (R_RISCV_SET_ULEB128,                /* type */
> > > >> > +         0,                                /* rightshift */
> > > >> > +         0,                                /* size */
> > > >> > +         0,                                /* bitsize */
> > > >> > +         FALSE,                                /* pc_relative */
> > > >> > +         0,                                /* bitpos */
> > > >> > +         complain_overflow_dont,        /* complain_on_overflow */
> > > >> > +         riscv_elf_ignore_reloc,        /* special_function */
> > > >> > +         "R_RISCV_SET_ULEB128",                /* name */
> > > >> > +         FALSE,                                /* partial_inplace */
> > > >> > +         0,                                /* src_mask */
> > > >> > +         0,                                /* dst_mask */
> > > >> > +         FALSE),                        /* pcrel_offset */
> > > >>
> > > >> I don't understand how this could possibly work: uleb128s can be long, so we
> > > >> can't just treat them as a single byte.  I'm having trouble testing it, though,
> > > >> as I can't figure out how to emit R_RISCV_SET_ULEB128 alone.  For example, when
> > > >> I try to insert a uleb128 in the assembler I'm not even getting a relocation:
> > > >>
> > > >>     .text
> > > >>     .globl _start
> > > >>     _start:
> > > >>             nop
> > > >>     .L0:
> > > >>             nop
> > > >>     .L1:
> > > >>     uleb_l0:
> > > >>             addi x0, x0, 1
> > > >>             .uleb128 .L0
> > > >>             # Manually fix up the alignment, as .align is broken.
> > > >>             .rept 3
> > > >>             .byte 0xAA
> > > >>             .endr
> > > >>             addi x0, x0, 2
> > > >>
> > > >>     $ objdump -dr
> > > >>     test.o:     file format elf64-littleriscv
> > > >>
> > > >>
> > > >>     Disassembly of section .text:
> > > >>
> > > >>     0000000000000000 <_start>:
> > > >>        0:   00000013                nop
> > > >>        4:   00000013                nop
> > > >>
> > > >>     0000000000000008 <uleb_l0>:
> > > >>        8:   00100013                li      zero,1
> > > >>        c:   aa04                    fsd     fs1,16(a2)
> > > >>        e:   aaaa                    fsd     fa0,336(sp)
> > > >>       10:   00200013                li      zero,2
> > > >>
> > > >> so then when I link I'm just getting the wrong value entirely.
> > > >>
> > > >>     test:     file format elf64-littleriscv
> > > >>
> > > >>
> > > >>     Disassembly of section .text:
> > > >>
> > > >>     0000000000010078 <_start>:
> > > >>        10078:       00000013                nop
> > > >>        1007c:       00000013                nop
> > > >>
> > > >>     0000000000010080 <uleb_l0>:
> > > >>        10080:       00100013                li      zero,1
> > > >>        10084:       aa04                    fsd     fs1,16(a2)
> > > >>        10086:       aaaa                    fsd     fa0,336(sp)
> > > >>        10088:       00200013                li      zero,2
> > > >>
> > > >> > +  /* The length of unsigned-leb128 is variant, just assume the
> > > >> > +     size is one byte here.  */
> > > >> > +  HOWTO (R_RISCV_SUB_ULEB128,                /* type */
> > > >> > +         0,                                /* rightshift */
> > > >> > +         0,                                /* size */
> > > >> > +         0,                                /* bitsize */
> > > >> > +         FALSE,                                /* pc_relative */
> > > >> > +         0,                                /* bitpos */
> > > >> > +         complain_overflow_dont,        /* complain_on_overflow */
> > > >> > +         riscv_elf_ignore_reloc,        /* special_function */
> > > >> > +         "R_RISCV_SUB_ULEB128",                /* name */
> > > >> > +         FALSE,                                /* partial_inplace */
> > > >> > +         0,                                /* src_mask */
> > > >> > +         0,                                /* dst_mask */
> > > >> > +         FALSE),                        /* pcrel_offset */
> > > >> >  };
> > > >>
> > > >> I can get a R_RISCV_SUB_ULEB128, but it appears to be both producing the wrong
> > > >> value and garbaging up bytes after the relocation.  For example:
> > > >>
> > > >>     .text
> > > >>     .globl _start
> > > >>     _start:
> > > >>             nop
> > > >>     .L0:
> > > >>             nop
> > > >>     .L1:
> > > >>     uleb_l1_l0:
> > > >>             addi x0, x0, 1
> > > >>             .uleb128 .L1 - .L0
> > > >>             # Manually fix up the alignment, as .align is broken
> > > >>             .rept 3
> > > >>             .byte 0xAA
> > > >>             .endr
> > > >>             addi x0, x0, 2
> > > >>
> > > >> produces the relocation
> > > >>
> > > >>     test.o:     file format elf64-littleriscv
> > > >>
> > > >>
> > > >>     Disassembly of section .text:
> > > >>
> > > >>     0000000000000000 <_start>:
> > > >>        0:   00000013                nop
> > > >>
> > > >>     0000000000000004 <.L0>:
> > > >>        4:   00000013                nop
> > > >>
> > > >>     0000000000000008 <uleb_l1_l0>:
> > > >>        8:   00100013                li      zero,1
> > > >>        c:   aa04                    fsd     fs1,16(a2)
> > > >>                             c: R_RISCV_SET_ULEB128  .L1
> > > >>                             c: R_RISCV_SUB_ULEB128  .L0
> > > >>        e:   aaaa                    fsd     fa0,336(sp)
> > > >>       10:   00200013                li      zero,2
> > > >>
> > > >> but then goes and corrupts the resulting executable
> > > >>
> > > >>
> > > >>     test:     file format elf64-littleriscv
> > > >>     Disassembly of section .text:
> > > >>
> > > >>     0000000000010078 <_start>:
> > > >>        10078:       00000013                nop
> > > >>        1007c:       00000013                nop
> > > >>
> > > >>     0000000000010080 <uleb_l1_l0>:
> > > >>        10080:       00100013                li      zero,1
> > > >>        10084:       ff84                    sd      s1,56(a5)
> > > >>        10086:       000ffffb                0xffffb
> > > >>        1008a:       0020                    addi    s0,sp,8
> > > >>
> > > >> I can't think of a way to make this work aside from just emitting uleb128s at
> > > >> their full length, which would make them work but would really defeat the
> > > >> purpose of the format.  I guess we could then relax these, but that seems like
> > > >> a lot of work.
> > > >>
> > > >> > +
> > > >> >  /* A mapping from BFD reloc types to RISC-V ELF reloc types.  */
> > > >> >
> > > >> >  struct elf_reloc_map
> > > >> > @@ -917,6 +952,8 @@ static const struct elf_reloc_map riscv_reloc_map[] =
> > > >> >    { 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_SET_ULEB128, R_RISCV_SET_ULEB128 },
> > > >> > +  { BFD_RELOC_RISCV_SUB_ULEB128, R_RISCV_SUB_ULEB128 },
> > > >> >  };
> > > >> >
> > > >> >  /* Given a BFD reloc type, return a howto structure.  */
> > > >> > @@ -1011,6 +1048,20 @@ riscv_elf_add_sub_reloc (bfd *abfd,
> > > >> >    return bfd_reloc_ok;
> > > >> >  }
> > > >> >
> > > >> > +/* Special handler for relocations which don't have to be relocated.
> > > >> > +   This function just simply return bfd_reloc_ok.  */
> > > >> > +static bfd_reloc_status_type
> > > >> > +riscv_elf_ignore_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry,
> > > >> > +                        asymbol *symbol ATTRIBUTE_UNUSED,
> > > >> > +                        void *data ATTRIBUTE_UNUSED, asection *input_section,
> > > >> > +                        bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED)
> > > >> > +{
> > > >> > +  if (output_bfd != NULL)
> > > >> > +    reloc_entry->address += input_section->output_offset;
> > > >> > +
> > > >> > +  return bfd_reloc_ok;
> > > >> > +}
> > > >> > +
> > > >> >  /* Parsing subset version.
> > > >> >
> > > >> >     Return Value:
> > > >> > diff --git a/bfd/libbfd.h b/bfd/libbfd.h
> > > >> > index 77b732ee4b..7aa8f91504 100644
> > > >> > --- a/bfd/libbfd.h
> > > >> > +++ b/bfd/libbfd.h
> > > >> > @@ -2327,6 +2327,8 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
> > > >> >    "BFD_RELOC_RISCV_SET16",
> > > >> >    "BFD_RELOC_RISCV_SET32",
> > > >> >    "BFD_RELOC_RISCV_32_PCREL",
> > > >> > +  "BFD_RELOC_RISCV_SET_ULEB128",
> > > >> > +  "BFD_RELOC_RISCV_SUB_ULEB128",
> > > >> >    "BFD_RELOC_RL78_NEG8",
> > > >> >    "BFD_RELOC_RL78_NEG16",
> > > >> >    "BFD_RELOC_RL78_NEG24",
> > > >> > diff --git a/bfd/reloc.c b/bfd/reloc.c
> > > >> > index b00b79f319..9b8b75ad21 100644
> > > >> > --- a/bfd/reloc.c
> > > >> > +++ b/bfd/reloc.c
> > > >> > @@ -5212,6 +5212,10 @@ ENUMX
> > > >> >    BFD_RELOC_RISCV_SET32
> > > >> >  ENUMX
> > > >> >    BFD_RELOC_RISCV_32_PCREL
> > > >> > +ENUMX
> > > >> > +  BFD_RELOC_RISCV_SET_ULEB128
> > > >> > +ENUMX
> > > >> > +  BFD_RELOC_RISCV_SUB_ULEB128
> > > >> >  ENUMDOC
> > > >> >    RISC-V relocations.
> > > >> >
> > > >> > diff --git a/gas/ChangeLog b/gas/ChangeLog
> > > >> > index 09991524da..e53ac0895b 100644
> > > >> > --- a/gas/ChangeLog
> > > >> > +++ b/gas/ChangeLog
> > > >> > @@ -1,3 +1,11 @@
> > > >> > +2019-11-27  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
> > > >> > +
> > > >> > +        * config/tc-riscv.c (md_apply_fix): Add BFD_RELOC_RISCV_SET_ULEB128 and
> > > >> > +        BFD_RELOC_RISCV_SUB_ULEB128.
> > > >> > +        (riscv_insert_uleb128_fixes): New function.
> > > >> > +        (riscv_md_end): Scan rs_leb128 fragments.
> > > >> > +        (riscv_pseudo_table): Remove uleb128.
> > > >> > +
> > > >> >  2019-11-25  Andrew Pinski  <apinski@marvell.com>
> > > >> >
> > > >> >          * config/tc-aarch64.c (md_begin): Use correct
> > > >> > diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
> > > >> > index e50505138e..c35c591c0a 100644
> > > >> > --- a/gas/config/tc-riscv.c
> > > >> > +++ b/gas/config/tc-riscv.c
> > > >> > @@ -2392,6 +2392,9 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
> > > >> >      case BFD_RELOC_RISCV_SUB32:
> > > >> >      case BFD_RELOC_RISCV_SUB64:
> > > >> >      case BFD_RELOC_RISCV_RELAX:
> > > >> > +    /* cvt_frag_to_fill () has called output_leb128 ().  */
> > > >> > +    case BFD_RELOC_RISCV_SET_ULEB128:
> > > >> > +    case BFD_RELOC_RISCV_SUB_ULEB128:
> > > >> >        break;
> > > >> >
> > > >> >      case BFD_RELOC_RISCV_TPREL_HI20:
> > > >> > @@ -3127,11 +3130,54 @@ riscv_set_public_attributes (void)
> > > >> >      riscv_write_out_arch_attr ();
> > > >> >  }
> > > >> >
> > > >> > +/* Scan uleb128 subtraction expressions and insert fixups for them.
> > > >> > +   e.g., .uleb128 .L1 - .L0
> > > >> > +   Becuase relaxation may change the value of the subtraction, we
> > > >> > +   must resolve them in link-time.  */
> > > >> > +
> > > >> > +static void
> > > >> > +riscv_insert_uleb128_fixes (bfd *abfd ATTRIBUTE_UNUSED,
> > > >> > +                            asection *sec, void *xxx ATTRIBUTE_UNUSED)
> > > >> > +{
> > > >> > +  segment_info_type *seginfo = seg_info (sec);
> > > >> > +  struct frag *fragP;
> > > >> > +
> > > >> > +  subseg_set (sec, 0);
> > > >> > +
> > > >> > +  for (fragP = seginfo->frchainP->frch_root;
> > > >> > +       fragP; fragP = fragP->fr_next)
> > > >> > +    {
> > > >> > +      expressionS *exp, *exp_dup;
> > > >> > +
> > > >> > +      if (fragP->fr_type != rs_leb128  || fragP->fr_symbol == NULL)
> > > >> > +        continue;
> > > >> > +
> > > >> > +      exp = symbol_get_value_expression (fragP->fr_symbol);
> > > >> > +
> > > >> > +      if (exp->X_op != O_subtract)
> > > >> > +        continue;
> > > >>
> > > >> Presumably that's why I can't get a _SET alone.
> > > >>
> > > >> > +
> > > >> > +      /* Only unsigned leb128 can be handle.  */
> > > >> > +      gas_assert (fragP->fr_subtype == 0);
> > > >> > +      exp_dup = xmemdup (exp, sizeof (*exp), sizeof (*exp));
> > > >> > +      exp_dup->X_op = O_symbol;
> > > >> > +      exp_dup->X_op_symbol = NULL;
> > > >> > +
> > > >> > +      /* Insert relocations to resolve the subtraction in link-time.  */
> > > >> > +      fix_new_exp (fragP, fragP->fr_fix, 0,
> > > >> > +                   exp_dup, 0, BFD_RELOC_RISCV_SET_ULEB128);
> > > >> > +      exp_dup->X_add_symbol = exp->X_op_symbol;
> > > >> > +      fix_new_exp (fragP, fragP->fr_fix, 0,
> > > >> > +                   exp_dup, 0, BFD_RELOC_RISCV_SUB_ULEB128);
> > > >> > +    }
> > > >> > +}
> > > >> > +
> > > >> >  /* Called after all assembly has been done.  */
> > > >> >
> > > >> >  void
> > > >> >  riscv_md_end (void)
> > > >> >  {
> > > >> > +  bfd_map_over_sections (stdoutput, riscv_insert_uleb128_fixes, NULL);
> > > >> >    riscv_set_public_attributes ();
> > > >> >  }
> > > >> >
> > > >> > @@ -3215,7 +3261,6 @@ static const pseudo_typeS riscv_pseudo_table[] =
> > > >> >    {"dtprelword", s_dtprel, 4},
> > > >> >    {"dtpreldword", s_dtprel, 8},
> > > >> >    {"bss", s_bss, 0},
> > > >> > -  {"uleb128", s_riscv_leb128, 0},
> > > >> >    {"sleb128", s_riscv_leb128, 1},
> > > >> >    {"insn", s_riscv_insn, 0},
> > > >> >    {"attribute", s_riscv_attribute, 0},
> > > >> > diff --git a/include/ChangeLog b/include/ChangeLog
> > > >> > index 47bb86cf71..c290b245c6 100644
> > > >> > --- a/include/ChangeLog
> > > >> > +++ b/include/ChangeLog
> > > >> > @@ -1,3 +1,7 @@
> > > >> > +2019-11-27  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
> > > >> > +
> > > >> > +        * elf/riscv.h ((R_RISCV_SET_ULEB128, (R_RISCV_SUB_ULEB128): Define.
> > > >> > +
> > > >> >  2019-11-25  Alan Modra  <amodra@gmail.com>
> > > >> >
> > > >> >          * coff/ti.h (GET_SCNHDR_SIZE, PUT_SCNHDR_SIZE, GET_SCN_SCNLEN),
> > > >> > diff --git a/include/elf/riscv.h b/include/elf/riscv.h
> > > >> > index 2f98aa4a3e..030679b35f 100644
> > > >> > --- a/include/elf/riscv.h
> > > >> > +++ b/include/elf/riscv.h
> > > >> > @@ -88,6 +88,8 @@ START_RELOC_NUMBERS (elf_riscv_reloc_type)
> > > >> >    RELOC_NUMBER (R_RISCV_SET16, 55)
> > > >> >    RELOC_NUMBER (R_RISCV_SET32, 56)
> > > >> >    RELOC_NUMBER (R_RISCV_32_PCREL, 57)
> > > >> > +  RELOC_NUMBER (R_RISCV_SET_ULEB128, 58)
> > > >> > +  RELOC_NUMBER (R_RISCV_SUB_ULEB128, 59)
> > > >> >  END_RELOC_NUMBERS (R_RISCV_max)
> > > >> >
> > > >> >  /* Processor specific flags for the ELF header e_flags field.  */
> > > >> > diff --git a/ld/ChangeLog b/ld/ChangeLog
> > > >> > index 969ab78035..5c2e406101 100644
> > > >> > --- a/ld/ChangeLog
> > > >> > +++ b/ld/ChangeLog
> > > >> > @@ -1,3 +1,9 @@
> > > >> > +2019-11-27  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
> > > >> > +
> > > >> > +        * testsuite/ld-riscv-elf/ld-riscv-elf.exp: Add uleb128.
> > > >> > +        * testsuite/ld-riscv-elf/uleb128.d: New test.
> > > >> > +        * testsuite/ld-riscv-elf/uleb128.s: New file.
> > > >> > +
> > > >> >  2019-11-26  Martin Liska  <mliska@suse.cz>
> > > >> >
> > > >> >          * scripttempl/arclinux.sc: Add .text.sorted.* which is sorted
> > > >> > diff --git a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
> > > >> > index 7aabbdd641..809e40f08d 100644
> > > >> > --- a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
> > > >> > +++ b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
> > > >> > @@ -38,6 +38,7 @@ if [istarget "riscv*-*-*"] {
> > > >> >      run_dump_test "attr-merge-priv-spec"
> > > >> >      run_dump_test "attr-merge-arch-failed-01"
> > > >> >      run_dump_test "attr-merge-stack-align-failed"
> > > >> > +    run_dump_test "uleb128"
> > > >> >      run_ld_link_tests {
> > > >> >          { "Weak reference 32" "-T weakref.ld -melf32lriscv" ""
> > > >> >              "-march=rv32i -mabi=ilp32" {weakref32.s}
> > > >> > diff --git a/ld/testsuite/ld-riscv-elf/uleb128.d b/ld/testsuite/ld-riscv-elf/uleb128.d
> > > >> > new file mode 100644
> > > >> > index 0000000000..a921478e98
> > > >> > --- /dev/null
> > > >> > +++ b/ld/testsuite/ld-riscv-elf/uleb128.d
> > > >> > @@ -0,0 +1,18 @@
> > > >> > +#source: uleb128.s
> > > >> > +#as: -march=rv32ic
> > > >> > +#ld: -melf32lriscv
> > > >> > +#objdump: -d
> > > >> > +
> > > >> > +.*:[         ]+file format .*
> > > >> > +
> > > >> > +Disassembly of section .text:
> > > >> > +
> > > >> > +.* <_start>:
> > > >> > +.*jal.*<bar>
> > > >> > +.*jal.*<bar>
> > > >> > +.*jal.*<bar>
> > > >> > +.*jal.*<bar>
> > > >> > +.*jal.*<bar>
> > > >> > +.*jal.*<bar>
> > > >> > +.*:[         ]+0e0c.*
> > > >> > +#pass
> > > >> > diff --git a/ld/testsuite/ld-riscv-elf/uleb128.s b/ld/testsuite/ld-riscv-elf/uleb128.s
> > > >> > new file mode 100644
> > > >> > index 0000000000..f7d23be163
> > > >> > --- /dev/null
> > > >> > +++ b/ld/testsuite/ld-riscv-elf/uleb128.s
> > > >> > @@ -0,0 +1,18 @@
> > > >> > +.text
> > > >> > +.globl bar
> > > >> > +.globl _start
> > > >> > +.option rvc
> > > >> > +.align 2
> > > >> > +_start:
> > > >> > +.L0:
> > > >> > +        .rept 6
> > > >> > +        call bar
> > > >> > +        .endr
> > > >> > +.align 2
> > > >> > +.L1:
> > > >> > +        .uleb128 .L1 - .L0
> > > >> > +        .uleb128 .L2 - .L0
> > > >> > +.L2:
> > > >> > +.align 2
> > > >> > +bar:
> > > >> > +        nop
> > > >>
> > > >> It looks like alignment is broken here after uleb128s, but it's not actually
> > > >> triggering an error in all cases.  Having two of them in this test case doesn't
> > > >> trigger the issue, but an odd number does.  For example, the following source
> > > >>
> > > >>     .text
> > > >>     .globl _start
> > > >>     .align 2
> > > >>     _start:
> > > >>             .uleb128 _start
> > > >>     .align 2
> > > >>     _end:
> > > >>             nop
> > > >>
> > > >> links _end to a misaligned symbol
> > > >>
> > > >>     Disassembly of section .text:
> > > >>
> > > >>     0000000000010078 <_start>:
> > > >>             ...
> > > >>
> > > >>     0000000000010079 <_end>:
> > > >>        10079:       00000013                nop
> > > >>        1007d:       0000                    unimp
> > > >>             ...
> > > >>
> > > >> I'm assuming that's because norvc assumes 4-byte alignment in text sections, so
> > > >> it's just eliding the alingment directives.  With RVC I do get an error message
> > > >>
> > > >>     .text
> > > >>     .globl _start
> > > >>     .option rvc
> > > >>     .align 2
> > > >>     _start:
> > > >>             .uleb128 _start
> > > >>     .align 2
> > > >>     _end:
> > > >>             nop
> > > >>
> > > >>     ./install/bin/riscv64-unknown-linux-gnu-ld: test.o(.text+0x1): 3 bytes required for alignment to 4-byte boundary, but only 2 present
> > > >>     ./install/bin/riscv64-unknown-linux-gnu-ld: can't relax section: bad value
> > > >>
> > > >>
> > > >
> > > >
> > > > --
> > > > Best regards,
> > > > Kuan-Lin Chen.
> > > > kuanlinchentw@gmail.com
> >
> >
> >
> > --
> > Best regards,
> > Kuan-Lin Chen.
> > kuanlinchentw@gmail.com

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] [RISCV] Support subtraction of .uleb128.
  2020-09-01 12:56 Jozef Lawrynowicz
@ 2020-09-02  1:29 ` Kuan-Lin Chen
  0 siblings, 0 replies; 17+ messages in thread
From: Kuan-Lin Chen @ 2020-09-02  1:29 UTC (permalink / raw)
  To: jozef.l; +Cc: binutils@sourceware.org Development

Hi,

Yes, it's fine with me.

Best regards,
Kuan-Lin Chen

Jozef Lawrynowicz <jozef.l@mittosystems.com> 於 2020年9月1日 週二 下午8:56寫道:
>
> Hi,
>
> I adapted and extended your patch for the MSP430 target. MSP430 also has issues
> when linker relaxation changes the distance between symbols, which has been
> calculated in .uleb128 directives.
>
> I see your original patch still hasn't been applied to upstream Binutils, would
> you be ok with me applying the attached patch with the following ChangeLog
> entry, to credit your original work?
>
> 2020-09-01 Jozef Lawrynowicz  <jozef.l@mittosystems.com>
>            Kuan-Lin Chen  <kuanlinchentw@gmail.com>
>
> Thanks,
> Jozef



-- 
Best regards,
Kuan-Lin Chen.
kuanlinchentw@gmail.com

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] [RISCV] Support subtraction of .uleb128.
@ 2020-09-01 12:56 Jozef Lawrynowicz
  2020-09-02  1:29 ` Kuan-Lin Chen
  0 siblings, 1 reply; 17+ messages in thread
From: Jozef Lawrynowicz @ 2020-09-01 12:56 UTC (permalink / raw)
  To: kuanlinchentw; +Cc: binutils

[-- Attachment #1: Type: text/plain, Size: 507 bytes --]

Hi,

I adapted and extended your patch for the MSP430 target. MSP430 also has issues
when linker relaxation changes the distance between symbols, which has been
calculated in .uleb128 directives.

I see your original patch still hasn't been applied to upstream Binutils, would
you be ok with me applying the attached patch with the following ChangeLog
entry, to credit your original work?

2020-09-01 Jozef Lawrynowicz  <jozef.l@mittosystems.com>
	   Kuan-Lin Chen  <kuanlinchentw@gmail.com>

Thanks,
Jozef

[-- Attachment #2: 0001-MSP430-Support-relocations-for-subtract-expressions-.patch --]
[-- Type: text/plain, Size: 18488 bytes --]

From 2aa6c6ec5a603d1b65b3775a6c48720650ddc83f Mon Sep 17 00:00:00 2001
From: Jozef Lawrynowicz <jozef.l@mittosystems.com>
Date: Mon, 31 Aug 2020 10:28:06 +0100
Subject: [PATCH] MSP430: Support relocations for subtract expressions in
 .uleb128 directives

Link-time relaxations of branches are common for MSP430, given that GCC
often generates pessimal branch instructions, and the
-mcode-region=either/-mdata-region=either options to shuffle sections
can further cause a change the type of branch instruction required.

These relaxations can result in invalid code when .uleb128
directives, used in the .gcc_except_table section, are used to calculate
the distance between two labels. A value for the .uleb128 directive is
calculated at assembly-time, and can't be updated at link-time, even if
relaxation causes the distance between the labels to change.

This patch adds relocations for subtract expressions in .uleb128
directives, to allow the linker to re-calculate the value of these
expressions after relaxation has been performed.
---
 bfd/bfd-in2.h                             |   2 +
 bfd/elf32-msp430.c                        | 152 +++++++++++++++++++++-
 bfd/libbfd.h                              |   2 +
 bfd/reloc.c                               |   5 +
 binutils/readelf.c                        |  27 +++-
 gas/config/tc-msp430.c                    |  54 +++++++-
 include/elf/msp430.h                      |   4 +
 ld/testsuite/ld-msp430-elf/msp430-elf.exp |   3 +
 ld/testsuite/ld-msp430-elf/uleb128.s      |  35 +++++
 ld/testsuite/ld-msp430-elf/uleb128_430.d  |  10 ++
 ld/testsuite/ld-msp430-elf/uleb128_430x.d |  10 ++
 11 files changed, 294 insertions(+), 10 deletions(-)
 create mode 100644 ld/testsuite/ld-msp430-elf/uleb128.s
 create mode 100644 ld/testsuite/ld-msp430-elf/uleb128_430.d
 create mode 100644 ld/testsuite/ld-msp430-elf/uleb128_430x.d

diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 3c85b073013..74d3a8ab53e 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -5113,6 +5113,8 @@ then it may be truncated to 8 bits.  */
   BFD_RELOC_MSP430_ABS_HI16,
   BFD_RELOC_MSP430_PREL31,
   BFD_RELOC_MSP430_SYM_DIFF,
+  BFD_RELOC_MSP430_SET_ULEB128,
+  BFD_RELOC_MSP430_SUB_ULEB128,
 
 /* Relocations used by the Altera Nios II core.  */
   BFD_RELOC_NIOS2_S16,
diff --git a/bfd/elf32-msp430.c b/bfd/elf32-msp430.c
index 59e54ecbc9a..afbd61a215e 100644
--- a/bfd/elf32-msp430.c
+++ b/bfd/elf32-msp430.c
@@ -56,6 +56,20 @@ rl78_sym_diff_handler (bfd * abfd,
   return bfd_reloc_continue;
 }
 
+/* Special handler for relocations which don't have to be relocated.
+   This function just simply returns bfd_reloc_ok.  */
+static bfd_reloc_status_type
+msp430_elf_ignore_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry,
+			asymbol *symbol ATTRIBUTE_UNUSED,
+			void *data ATTRIBUTE_UNUSED, asection *input_section,
+			bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED)
+{
+  if (output_bfd != NULL)
+    reloc_entry->address += input_section->output_offset;
+
+  return bfd_reloc_ok;
+}
+
 static reloc_howto_type elf_msp430_howto_table[] =
 {
   HOWTO (R_MSP430_NONE,		/* type */
@@ -220,7 +234,40 @@ static reloc_howto_type elf_msp430_howto_table[] =
 	 FALSE,			/* partial_inplace */
 	 0xffffffff,		/* src_mask */
 	 0xffffffff,		/* dst_mask */
-	 FALSE)			/* pcrel_offset */
+	 FALSE),		/* pcrel_offset */
+
+  /* The length of unsigned-leb128 is variable, just assume the
+     size is one byte here.  */
+  HOWTO (R_MSP430_SET_ULEB128,		/* type */
+	 0,				/* rightshift */
+	 0,				/* size */
+	 0,				/* bitsize */
+	 FALSE,				/* pc_relative */
+	 0,				/* bitpos */
+	 complain_overflow_dont,	/* complain_on_overflow */
+	 msp430_elf_ignore_reloc,	/* special handler.  */
+	 "R_MSP430_SET_ULEB128",	/* name */
+	 FALSE,				/* partial_inplace */
+	 0,				/* src_mask */
+	 0,				/* dst_mask */
+	 FALSE),			/* pcrel_offset */
+
+  /* The length of unsigned-leb128 is variable, just assume the
+     size is one byte here.  */
+  HOWTO (R_MSP430_SUB_ULEB128,		/* type */
+	 0,				/* rightshift */
+	 0,				/* size */
+	 0,				/* bitsize */
+	 FALSE,				/* pc_relative */
+	 0,				/* bitpos */
+	 complain_overflow_dont,	/* complain_on_overflow */
+	 msp430_elf_ignore_reloc,	/* special handler.  */
+	 "R_MSP430_SUB_ULEB128",	/* name */
+	 FALSE,				/* partial_inplace */
+	 0,				/* src_mask */
+	 0,				/* dst_mask */
+	 FALSE),			/* pcrel_offset */
+
 };
 
 static reloc_howto_type elf_msp430x_howto_table[] =
@@ -523,7 +570,40 @@ static reloc_howto_type elf_msp430x_howto_table[] =
 	 FALSE,			/* partial_inplace */
 	 0xffffffff,		/* src_mask */
 	 0xffffffff,		/* dst_mask */
-	 FALSE)			/* pcrel_offset */
+	 FALSE),		/* pcrel_offset */
+
+  /* The length of unsigned-leb128 is variable, just assume the
+     size is one byte here.  */
+  HOWTO (R_MSP430X_SET_ULEB128,		/* type */
+	 0,				/* rightshift */
+	 0,				/* size */
+	 0,				/* bitsize */
+	 FALSE,				/* pc_relative */
+	 0,				/* bitpos */
+	 complain_overflow_dont,	/* complain_on_overflow */
+	 msp430_elf_ignore_reloc,	/* special handler.  */
+	 "R_MSP430X_SET_ULEB128",	/* name */
+	 FALSE,				/* partial_inplace */
+	 0,				/* src_mask */
+	 0,				/* dst_mask */
+	 FALSE),			/* pcrel_offset */
+
+  /* The length of unsigned-leb128 is variable, just assume the
+     size is one byte here.  */
+  HOWTO (R_MSP430X_SUB_ULEB128,		/* type */
+	 0,				/* rightshift */
+	 0,				/* size */
+	 0,				/* bitsize */
+	 FALSE,				/* pc_relative */
+	 0,				/* bitpos */
+	 complain_overflow_dont,	/* complain_on_overflow */
+	 msp430_elf_ignore_reloc,	/* special handler.  */
+	 "R_MSP430X_SUB_ULEB128",	/* name */
+	 FALSE,				/* partial_inplace */
+	 0,				/* src_mask */
+	 0,				/* dst_mask */
+	 FALSE),			/* pcrel_offset */
+
 };
 
 /* Map BFD reloc types to MSP430 ELF reloc types.  */
@@ -547,7 +627,9 @@ static const struct msp430_reloc_map msp430_reloc_map[] =
   {BFD_RELOC_MSP430_2X_PCREL,	   R_MSP430_2X_PCREL},
   {BFD_RELOC_MSP430_RL_PCREL,	   R_MSP430_RL_PCREL},
   {BFD_RELOC_8,			   R_MSP430_8},
-  {BFD_RELOC_MSP430_SYM_DIFF,	   R_MSP430_SYM_DIFF}
+  {BFD_RELOC_MSP430_SYM_DIFF,	   R_MSP430_SYM_DIFF},
+  {BFD_RELOC_MSP430_SET_ULEB128,   R_MSP430_SET_ULEB128 },
+  {BFD_RELOC_MSP430_SUB_ULEB128,   R_MSP430_SUB_ULEB128 }
 };
 
 static const struct msp430_reloc_map msp430x_reloc_map[] =
@@ -573,7 +655,9 @@ static const struct msp430_reloc_map msp430x_reloc_map[] =
   {BFD_RELOC_MSP430_10_PCREL,	      R_MSP430X_10_PCREL},
   {BFD_RELOC_MSP430_2X_PCREL,	      R_MSP430X_2X_PCREL},
   {BFD_RELOC_MSP430_RL_PCREL,	      R_MSP430X_PCR16},
-  {BFD_RELOC_MSP430_SYM_DIFF,	      R_MSP430X_SYM_DIFF}
+  {BFD_RELOC_MSP430_SYM_DIFF,	      R_MSP430X_SYM_DIFF},
+  {BFD_RELOC_MSP430_SET_ULEB128,      R_MSP430X_SET_ULEB128 },
+  {BFD_RELOC_MSP430_SUB_ULEB128,      R_MSP430X_SUB_ULEB128 }
 };
 
 static inline bfd_boolean
@@ -711,6 +795,26 @@ elf32_msp430_check_relocs (bfd * abfd, struct bfd_link_info * info,
   return TRUE;
 }
 
+/* Write VAL in uleb128 format to P, returning a pointer to the
+   following byte.
+   This code is copied from elf-attr.c.  */
+
+static bfd_byte *
+write_uleb128 (bfd_byte *p, unsigned int val)
+{
+  bfd_byte c;
+  do
+    {
+      c = val & 0x7f;
+      val >>= 7;
+      if (val)
+	c |= 0x80;
+      *(p++) = c;
+    }
+  while (val);
+  return p;
+}
+
 /* Perform a single relocation.  By default we use the standard BFD
    routines, but a few relocs, we have to do them ourselves.  */
 
@@ -755,6 +859,9 @@ msp430_final_link_relocate (reloc_howto_type *	   howto,
      if (uses_msp430x_relocs (input_bfd))
        switch (howto->type)
 	 {
+	 case R_MSP430X_SET_ULEB128:
+	   relocation += (!is_rel_reloc ? rel->r_addend : 0);
+	   /* Fall through.  */
 	 case R_MSP430_ABS32:
 	  /* If we are computing a 32-bit value for the location lists
 	     and the result is 0 then we add one to the value.  A zero
@@ -780,6 +887,9 @@ msp430_final_link_relocate (reloc_howto_type *	   howto,
      else
        switch (howto->type)
 	 {
+	 case R_MSP430_SET_ULEB128:
+	   relocation += (!is_rel_reloc ? rel->r_addend : 0);
+	   /* Fall through.  */
 	 case R_MSP430_32:
 	 case R_MSP430_16:
 	 case R_MSP430_16_BYTE:
@@ -794,16 +904,42 @@ msp430_final_link_relocate (reloc_howto_type *	   howto,
       sym_diff_section = NULL;
     }
 
-  if (uses_msp430x_relocs (input_bfd))
+  if ((uses_msp430x_relocs (input_bfd) && howto->type == R_MSP430X_SET_ULEB128)
+      || (!uses_msp430x_relocs (input_bfd)
+	  && howto->type == R_MSP430_SET_ULEB128))
+    {
+      unsigned int len = 0;
+      bfd_byte *endp, *p;
+
+      _bfd_read_unsigned_leb128 (input_bfd, contents + rel->r_offset, &len);
+
+      /* Clean the contents value to zero.  Do not reduce the length.  */
+      p = contents + rel->r_offset;
+      endp = p + len -1;
+      memset (p, 0x80, len - 1);
+      *(endp) = 0;
+      p = write_uleb128 (p, relocation) - 1;
+      if (p < endp)
+	*p |= 0x80;
+      else if (p > endp)
+	_bfd_error_handler
+	  (_("error: final size of uleb128 value in %pA from %pB exceeds "
+	     "available space"), input_section, input_bfd);
+
+      return bfd_reloc_ok;
+    }
+  else if (uses_msp430x_relocs (input_bfd))
     switch (howto->type)
       {
       case R_MSP430X_SYM_DIFF:
+      case R_MSP430X_SUB_ULEB128:
 	/* Cache the input section and value.
 	   The offset is unreliable, since relaxation may
 	   have reduced the following reloc's offset.  */
 	BFD_ASSERT (! is_rel_reloc);
 	sym_diff_section = input_section;
-	sym_diff_value = relocation;
+	sym_diff_value = relocation + (howto->type == R_MSP430X_SUB_ULEB128
+				       ? rel->r_addend : 0);
 	return bfd_reloc_ok;
 
       case R_MSP430_ABS16:
@@ -1254,11 +1390,13 @@ msp430_final_link_relocate (reloc_howto_type *	   howto,
       break;
 
     case R_MSP430_SYM_DIFF:
+    case R_MSP430_SUB_ULEB128:
       /* Cache the input section and value.
 	 The offset is unreliable, since relaxation may
 	 have reduced the following reloc's offset.  */
       sym_diff_section = input_section;
-      sym_diff_value = relocation;
+      sym_diff_value = relocation + (howto->type == R_MSP430_SUB_ULEB128
+				     ? rel->r_addend : 0);
       return bfd_reloc_ok;
 
       default:
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index b97534fc9fe..d4df99d151b 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -2802,6 +2802,8 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_MSP430_ABS_HI16",
   "BFD_RELOC_MSP430_PREL31",
   "BFD_RELOC_MSP430_SYM_DIFF",
+  "BFD_RELOC_MSP430_SET_ULEB128",
+  "BFD_RELOC_MSP430_SUB_ULEB128",
   "BFD_RELOC_NIOS2_S16",
   "BFD_RELOC_NIOS2_U16",
   "BFD_RELOC_NIOS2_CALL26",
diff --git a/bfd/reloc.c b/bfd/reloc.c
index 7d3479acef4..7f402257188 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -6366,6 +6366,11 @@ ENUMX
   BFD_RELOC_MSP430_PREL31
 ENUMX
   BFD_RELOC_MSP430_SYM_DIFF
+ENUMX
+  BFD_RELOC_MSP430_SET_ULEB128
+ENUMX
+  BFD_RELOC_MSP430_SUB_ULEB128
+
 ENUMDOC
   msp430 specific relocation codes
 
diff --git a/binutils/readelf.c b/binutils/readelf.c
index f02848e4681..7ac1461f194 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -12586,10 +12586,12 @@ target_specific_reloc_handling (Filedata *           filedata,
 	switch (reloc_type)
 	  {
 	  case 10: /* R_MSP430_SYM_DIFF */
+	  case 12: /* R_MSP430_SUB_ULEB128 */
 	    if (uses_msp430x_relocs (filedata))
 	      break;
 	    /* Fall through.  */
 	  case 21: /* R_MSP430X_SYM_DIFF */
+	  case 23: /* R_MSP430X_SUB_ULEB128 */
 	    /* PR 21139.  */
 	    if (sym_index >= num_syms)
 	      error (_("MSP430 SYM_DIFF reloc contains invalid symbol index %lu\n"),
@@ -12604,12 +12606,14 @@ target_specific_reloc_handling (Filedata *           filedata,
 
 	  case 5: /* R_MSP430_16_BYTE */
 	  case 9: /* R_MSP430_8 */
+	  case 11: /* R_MSP430_SET_ULEB128 */
 	    if (uses_msp430x_relocs (filedata))
 	      break;
 	    goto handle_sym_diff;
 
 	  case 2: /* R_MSP430_ABS16 */
 	  case 15: /* R_MSP430X_ABS16 */
+	  case 22: /* R_MSP430X_SET_ULEB128 */
 	    if (! uses_msp430x_relocs (filedata))
 	      break;
 	    goto handle_sym_diff;
@@ -12617,10 +12621,29 @@ target_specific_reloc_handling (Filedata *           filedata,
 	  handle_sym_diff:
 	    if (saved_sym != NULL)
 	      {
-		int reloc_size = reloc_type == 1 ? 4 : 2;
 		bfd_vma value;
+		unsigned int reloc_size;
+		int leb_ret = 0;
+		switch (reloc_type)
+		  {
+		  case 1: /* R_MSP430_32 or R_MSP430_ABS32 */
+		    reloc_size = 4;
+		    break;
+		  case 11: /* R_MSP430_SET_ULEB128 */
+		  case 22: /* R_MSP430X_SET_ULEB128 */
+		    read_leb128 (start + reloc->r_offset, end, FALSE,
+				 &reloc_size, &leb_ret);
+		    break;
+		  default:
+		    reloc_size = 2;
+		    break;
+		  }
 
-		if (sym_index >= num_syms)
+		if (leb_ret != 0)
+		  error (_("MSP430 ULEB128 field at 0x%lx contains invalid "
+			   "ULEB128 value\n"),
+			 (long) reloc->r_offset);
+		else if (sym_index >= num_syms)
 		  error (_("MSP430 reloc contains invalid symbol index %lu\n"),
 			 sym_index);
 		else
diff --git a/gas/config/tc-msp430.c b/gas/config/tc-msp430.c
index 2738937b112..6d1803202ce 100644
--- a/gas/config/tc-msp430.c
+++ b/gas/config/tc-msp430.c
@@ -5048,8 +5048,56 @@ msp430_fix_adjustable (struct fix *fixp ATTRIBUTE_UNUSED)
   return FALSE;
 }
 
-/* Set the contents of the .MSP430.attributes and .GNU.attributes sections.  */
+/* Scan uleb128 subtraction expressions and insert fixups for them.
+   e.g., .uleb128 .L1 - .L0
+   Because relaxation may change the value of the subtraction, we
+   must resolve them at link-time.  */
 
+static void
+msp430_insert_uleb128_fixes (bfd *abfd ATTRIBUTE_UNUSED,
+			    asection *sec, void *xxx ATTRIBUTE_UNUSED)
+{
+  segment_info_type *seginfo = seg_info (sec);
+  struct frag *fragP;
+
+  subseg_set (sec, 0);
+
+  for (fragP = seginfo->frchainP->frch_root;
+       fragP; fragP = fragP->fr_next)
+    {
+      expressionS *exp, *exp_dup;
+
+      if (fragP->fr_type != rs_leb128  || fragP->fr_symbol == NULL)
+	continue;
+
+      exp = symbol_get_value_expression (fragP->fr_symbol);
+
+      if (exp->X_op != O_subtract)
+	continue;
+
+      /* FIXME: Skip for .sleb128.  */
+      if (fragP->fr_subtype != 0)
+	continue;
+
+      exp_dup = xmemdup (exp, sizeof (*exp), sizeof (*exp));
+      exp_dup->X_op = O_symbol;
+      exp_dup->X_op_symbol = NULL;
+
+      /* Emit the SUB relocation first, since the SET relocation will write out
+	 the final value.  */
+      exp_dup->X_add_symbol = exp->X_op_symbol;
+      fix_new_exp (fragP, fragP->fr_fix, 0,
+		   exp_dup, 0, BFD_RELOC_MSP430_SUB_ULEB128);
+
+      exp_dup->X_add_symbol = exp->X_add_symbol;
+      /* Insert relocations to resolve the subtraction at link-time.  */
+      fix_new_exp (fragP, fragP->fr_fix, 0,
+		   exp_dup, 0, BFD_RELOC_MSP430_SET_ULEB128);
+
+    }
+}
+
+/* Called after all assembly has been done.  */
 void
 msp430_md_end (void)
 {
@@ -5065,6 +5113,10 @@ msp430_md_end (void)
 	as_warn (_(WARN_NOP_AT_EOF));
     }
 
+  /* Insert relocations for uleb128 directives, so the values can be recomputed
+     at link time.  */
+  bfd_map_over_sections (stdoutput, msp430_insert_uleb128_fixes, NULL);
+
   /* We have already emitted an error if any of the following attributes
      disagree with the attributes in the input assembly file.  See
      msp430_object_attribute.  */
diff --git a/include/elf/msp430.h b/include/elf/msp430.h
index 536f71452f6..6169801f3fa 100644
--- a/include/elf/msp430.h
+++ b/include/elf/msp430.h
@@ -113,6 +113,8 @@ START_RELOC_NUMBERS (elf_msp430_reloc_type)
      RELOC_NUMBER (R_MSP430_RL_PCREL,		8)
      RELOC_NUMBER (R_MSP430_8,			9)
      RELOC_NUMBER (R_MSP430_SYM_DIFF,		10)
+     RELOC_NUMBER (R_MSP430_SET_ULEB128, 11) /* GNU only.  */
+     RELOC_NUMBER (R_MSP430_SUB_ULEB128, 12) /* GNU only.  */
 END_RELOC_NUMBERS (R_MSP430_max)
 
 START_RELOC_NUMBERS (elf_msp430x_reloc_type)
@@ -137,6 +139,8 @@ START_RELOC_NUMBERS (elf_msp430x_reloc_type)
      RELOC_NUMBER (R_MSP430X_10_PCREL, 19)	/* Red Hat invention.  Used for Jump instructions.  */
      RELOC_NUMBER (R_MSP430X_2X_PCREL, 20)	/* Red Hat invention.  Used for relaxing jumps.  */
      RELOC_NUMBER (R_MSP430X_SYM_DIFF, 21)	/* Red Hat invention.  Used for relaxing debug info.  */
+     RELOC_NUMBER (R_MSP430X_SET_ULEB128, 22) /* GNU only.  */
+     RELOC_NUMBER (R_MSP430X_SUB_ULEB128, 23) /* GNU only.  */
 END_RELOC_NUMBERS (R_MSP430x_max)
 
 #endif /* _ELF_MSP430_H */
diff --git a/ld/testsuite/ld-msp430-elf/msp430-elf.exp b/ld/testsuite/ld-msp430-elf/msp430-elf.exp
index a2fa4db48d4..875b413c149 100644
--- a/ld/testsuite/ld-msp430-elf/msp430-elf.exp
+++ b/ld/testsuite/ld-msp430-elf/msp430-elf.exp
@@ -176,6 +176,9 @@ set msp430arraytests {
 
 run_ld_link_tests $msp430arraytests
 
+run_dump_test uleb128_430
+run_dump_test uleb128_430x
+
 # Don't run further tests when msp430 ISA is selected
 if {[string match "*-mcpu=msp430 *" [board_info [target_info name] multilib_flags]]
   || [string match "*-mcpu=msp430" [board_info [target_info name] multilib_flags]]} {
diff --git a/ld/testsuite/ld-msp430-elf/uleb128.s b/ld/testsuite/ld-msp430-elf/uleb128.s
new file mode 100644
index 00000000000..93d745ed426
--- /dev/null
+++ b/ld/testsuite/ld-msp430-elf/uleb128.s
@@ -0,0 +1,35 @@
+.data
+	.global	bar
+	.balign 2
+bar:
+	.short	42
+	.short	43
+
+	.global foo
+foo:
+.skip 0xff
+
+	.global	foo2
+	.balign 2
+foo2:
+	.short	4
+
+.text
+
+  .balign 2
+  .global byte
+byte:
+  .word foo-bar
+  .word foo2-bar
+
+  .global uleb
+  .balign 2
+uleb:
+	.uleb128 foo-bar  ; this value can be stored in one byte
+	.uleb128 foo2-bar ; this value requires 2 bytes
+
+  .balign 2
+  .global _start
+  _start:
+  nop
+
diff --git a/ld/testsuite/ld-msp430-elf/uleb128_430.d b/ld/testsuite/ld-msp430-elf/uleb128_430.d
new file mode 100644
index 00000000000..5104552e7a9
--- /dev/null
+++ b/ld/testsuite/ld-msp430-elf/uleb128_430.d
@@ -0,0 +1,10 @@
+#source: uleb128.s
+#as: -mcpu=msp430
+#ld:
+#objdump: -sj.text
+
+.*:[ 	]+file format .*
+
+Contents of section .text:
+ [0-9a-f]+ 04000401 04840200.*
+#pass
diff --git a/ld/testsuite/ld-msp430-elf/uleb128_430x.d b/ld/testsuite/ld-msp430-elf/uleb128_430x.d
new file mode 100644
index 00000000000..e808a53bedf
--- /dev/null
+++ b/ld/testsuite/ld-msp430-elf/uleb128_430x.d
@@ -0,0 +1,10 @@
+#source: uleb128.s
+#as: -mcpu=msp430x
+#ld:
+#objdump: -sj.text
+
+.*:[ 	]+file format .*
+
+Contents of section .text:
+ [0-9a-f]+ 04000401 04840200.*
+#pass
-- 
2.28.0


^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2020-09-25 15:55 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-27  8:12 [PATCH] [RISCV] Support subtraction of .uleb128 Kuan-Lin Chen
2019-11-27 10:36 ` Andreas Schwab
2019-12-02  1:18   ` Kuan-Lin Chen
2019-12-02 22:27 ` Jim Wilson
2019-12-06 23:48 ` Palmer Dabbelt via binutils
2019-12-10  5:43   ` Kuan-Lin Chen
2019-12-17 23:59     ` Jim Wilson
2019-12-18  1:50       ` Nelson Chu
2020-01-06  8:18         ` Kuan-Lin Chen
2020-01-06  8:37           ` Kito Cheng
2020-01-06  8:44           ` Kuan-Lin Chen
2020-01-09 23:20   ` Palmer Dabbelt via binutils
2020-01-22  7:26     ` Kuan-Lin Chen
2020-09-25  7:14       ` Kito Cheng
2020-09-25 15:55         ` Jozef Lawrynowicz
2020-09-01 12:56 Jozef Lawrynowicz
2020-09-02  1:29 ` Kuan-Lin Chen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).