MSP430: Support relocations for subtract expressions in .uleb128 directives
authorJozef Lawrynowicz <jozef.l@mittosystems.com>
Tue, 8 Sep 2020 15:13:48 +0000 (16:13 +0100)
committerJozef Lawrynowicz <jozef.l@mittosystems.com>
Tue, 8 Sep 2020 15:18:38 +0000 (16:18 +0100)
Link-time relaxations of branches are common for MSP430, given that GCC
can generate pessimal branch instructions, and the
-mcode-region=either/-mdata-region=either options to shuffle sections
can further 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/ChangeLog:
* bfd-in2.h (bfd_reloc_code_real): Add
BFD_RELOC_MSP430_{SET,SUB}_ULEB128.
* elf32-msp430.c (msp430_elf_ignore_reloc): New.
(elf_msp430_howto_table): Add R_MSP430{,X}_GNU_{SET,SUB}_ULEB128.
(msp430_reloc_map): Add R_MSP430_GNU_{SET,SUB}_ULEB128.
(msp430x_reloc_map): Add R_MSP430X_GNU_{SET,SUB}_ULEB128.
(write_uleb128): New.
(msp430_final_link_relocate): Handle R_MSP430{,X}_GNU_{SET,SUB}_ULEB128.
* libbfd.c (_bfd_write_unsigned_leb128): New.
* libbfd.h (_bfd_write_unsigned_leb128): New prototype.
Add BFD_RELOC_MSP430_{SET,SUB}_ULEB128.
* reloc.c: Document BFD_RELOC_MSP430_{SET,SUB}_ULEB128.

binutils/ChangeLog:
* readelf.c (target_specific_reloc_handling): Handle
R_MSP430{,X}_GNU_{SET,SUB}_ULEB128.

gas/ChangeLog:
* config/tc-msp430.c (msp430_insert_uleb128_fixes): New.
(msp430_md_end): Call msp430_insert_uleb128_fixes.

include/ChangeLog:
* elf/msp430.h (elf_msp430_reloc_type): Add
R_MSP430_GNU_{SET,SUB}_ULEB128.
(elf_msp430x_reloc_type): Add R_MSP430X_GNU_{SET,SUB}_ULEB128.

ld/ChangeLog:
* testsuite/ld-msp430-elf/msp430-elf.exp: Run new tests.
* testsuite/ld-msp430-elf/uleb128.s: New test.
* testsuite/ld-msp430-elf/uleb128_430.d: New test.
* testsuite/ld-msp430-elf/uleb128_430x.d: New test.

17 files changed:
bfd/ChangeLog
bfd/bfd-in2.h
bfd/elf32-msp430.c
bfd/libbfd.c
bfd/libbfd.h
bfd/reloc.c
binutils/ChangeLog
binutils/readelf.c
gas/ChangeLog
gas/config/tc-msp430.c
include/ChangeLog
include/elf/msp430.h
ld/ChangeLog
ld/testsuite/ld-msp430-elf/msp430-elf.exp
ld/testsuite/ld-msp430-elf/uleb128.s [new file with mode: 0644]
ld/testsuite/ld-msp430-elf/uleb128_430.d [new file with mode: 0644]
ld/testsuite/ld-msp430-elf/uleb128_430x.d [new file with mode: 0644]

index 0ae5d3047c2a6d9a2eabfda5d16707cdd900d649..39dab961da651fd0252274fa8172d06cfd381554 100644 (file)
@@ -1,3 +1,19 @@
+2020-09-08  Jozef Lawrynowicz  <jozef.l@mittosystems.com>
+       Kuan-Lin Chen  <kuanlinchentw@gmail.com>
+
+       * bfd-in2.h (bfd_reloc_code_real): Add
+       BFD_RELOC_MSP430_{SET,SUB}_ULEB128.
+       * elf32-msp430.c (msp430_elf_ignore_reloc): New.
+       (elf_msp430_howto_table): Add R_MSP430{,X}_GNU_{SET,SUB}_ULEB128.
+       (msp430_reloc_map): Add R_MSP430_GNU_{SET,SUB}_ULEB128.
+       (msp430x_reloc_map): Add R_MSP430X_GNU_{SET,SUB}_ULEB128.
+       (write_uleb128): New.
+       (msp430_final_link_relocate): Handle R_MSP430{,X}_GNU_{SET,SUB}_ULEB128.
+       * libbfd.c (_bfd_write_unsigned_leb128): New.
+       * libbfd.h (_bfd_write_unsigned_leb128): New prototype.
+       Add BFD_RELOC_MSP430_{SET,SUB}_ULEB128.
+       * reloc.c: Document BFD_RELOC_MSP430_{SET,SUB}_ULEB128.
+
 2020-09-08  Alex Coplan  <alex.coplan@arm.com>
 
        * archures.c (bfd_mach_aarch64_8R): New.
index 2202cab43938e352a3b6ab85dddab1ca4be67776..935ba535b540d94b80496beb1e9e53faf833df53 100644 (file)
@@ -5114,6 +5114,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,
index 59e54ecbc9ae8445063290afdbc649fddab40460..fd1922b3ddaef295546e5abd0dc10de071d61f28 100644 (file)
@@ -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_GNU_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_GNU_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_GNU_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_GNU_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_GNU_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_GNU_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_GNU_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_GNU_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_GNU_SET_ULEB128 },
+  {BFD_RELOC_MSP430_SUB_ULEB128,   R_MSP430_GNU_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_GNU_SET_ULEB128 },
+  {BFD_RELOC_MSP430_SUB_ULEB128,      R_MSP430X_GNU_SUB_ULEB128 }
 };
 
 static inline bfd_boolean
@@ -755,6 +839,9 @@ msp430_final_link_relocate (reloc_howto_type *         howto,
      if (uses_msp430x_relocs (input_bfd))
        switch (howto->type)
         {
+        case R_MSP430X_GNU_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 +867,9 @@ msp430_final_link_relocate (reloc_howto_type *         howto,
      else
        switch (howto->type)
         {
+        case R_MSP430_GNU_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 +884,63 @@ 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_GNU_SET_ULEB128)
+      || (!uses_msp430x_relocs (input_bfd)
+         && howto->type == R_MSP430_GNU_SET_ULEB128))
+    {
+      unsigned int len, new_len = 0;
+      bfd_byte *endp, *p;
+      unsigned int val = relocation;
+
+      _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;
+
+      /* Get the length of the new uleb128 value.  */
+      do
+       {
+         new_len++;
+         val >>= 7;
+       } while (val);
+
+      if (new_len > len)
+       {
+         _bfd_error_handler
+           (_("error: final size of uleb128 value at offset 0x%lx in %pA "
+              "from %pB exceeds available space"),
+            (long) rel->r_offset, input_section, input_bfd);
+       }
+      else
+       {
+         /* If the number of bytes required to store the new value has
+            decreased, "right align" the new value within the available space,
+            so the MSB side is padded with uleb128 zeros (0x80).  */
+         p = _bfd_write_unsigned_leb128 (p + (len - new_len), endp,
+                                         relocation);
+         /* We checked there is enough space for the new value above, so this
+            should never be NULL.  */
+         BFD_ASSERT (p);
+       }
+
+      return bfd_reloc_ok;
+    }
+  else if (uses_msp430x_relocs (input_bfd))
     switch (howto->type)
       {
       case R_MSP430X_SYM_DIFF:
+      case R_MSP430X_GNU_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_GNU_SUB_ULEB128
+                                      ? rel->r_addend : 0);
        return bfd_reloc_ok;
 
       case R_MSP430_ABS16:
@@ -1254,11 +1391,13 @@ msp430_final_link_relocate (reloc_howto_type *     howto,
       break;
 
     case R_MSP430_SYM_DIFF:
+    case R_MSP430_GNU_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_GNU_SUB_ULEB128
+                                    ? rel->r_addend : 0);
       return bfd_reloc_ok;
 
       default:
index efe10d22e8903ff257eb02b081bb2f4c927bc7ad..8046e4873bbcd287c7cd5e4893588176ff6c68d0 100644 (file)
@@ -1151,6 +1151,30 @@ _bfd_read_signed_leb128 (bfd *abfd ATTRIBUTE_UNUSED,
   return result;
 }
 
+/* Write VAL in uleb128 format to P.
+   END indicates the last byte of allocated space for the uleb128 value to fit
+   in.
+   Return a pointer to the byte following the last byte that was written, or
+   NULL if the uleb128 value does not fit in the allocated space between P and
+   END.  */
+bfd_byte *
+_bfd_write_unsigned_leb128 (bfd_byte *p, bfd_byte *end, bfd_vma val)
+{
+  bfd_byte c;
+  do
+    {
+      if (p > end)
+       return NULL;
+      c = val & 0x7f;
+      val >>= 7;
+      if (val)
+       c |= 0x80;
+      *(p++) = c;
+    }
+  while (val);
+  return p;
+}
+
 bfd_boolean
 _bfd_generic_init_private_section_data (bfd *ibfd ATTRIBUTE_UNUSED,
                                        asection *isec ATTRIBUTE_UNUSED,
index b97534fc9fed2c850f400dead5d085dd19f70bf1..7587e8f3c73a445d9e6f27e447969f1f555d6eeb 100644 (file)
@@ -901,6 +901,8 @@ extern bfd_signed_vma _bfd_read_signed_leb128
 extern bfd_vma _bfd_safe_read_leb128
   (bfd *, bfd_byte *, unsigned int *, bfd_boolean, const bfd_byte * const)
   ATTRIBUTE_HIDDEN;
+extern bfd_byte * _bfd_write_unsigned_leb128
+  (bfd_byte *p, bfd_byte *end, bfd_vma val) ATTRIBUTE_HIDDEN;
 
 #if GCC_VERSION >= 7000
 #define _bfd_mul_overflow(a, b, res) __builtin_mul_overflow (a, b, res)
@@ -2802,6 +2804,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",
index b17c5e64ec9f829e272e21912874ef549621c1ba..dc923fe39c25ee09c0cafcc3698247b411eb167c 100644 (file)
@@ -6367,6 +6367,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
 
index 96701b3a9a39f8e33acdb4b2bbd7d0a3f715407a..0c06bcedae092d54a350a61c1162c215bbebf7cd 100644 (file)
@@ -1,3 +1,9 @@
+2020-09-08  Jozef Lawrynowicz  <jozef.l@mittosystems.com>
+       Kuan-Lin Chen  <kuanlinchentw@gmail.com>
+
+       * readelf.c (target_specific_reloc_handling): Handle
+       R_MSP430{,X}_GNU_{SET,SUB}_ULEB128.
+
 2020-09-02  Alan Modra  <amodra@gmail.com>
 
        * objdump.c (disassemble_bytes): Use an unsigned type for "addend".
index 94aa876b5aeb269d495255f6fa43549a5e35e29e..cb4208f7b96aa7291245ea508d162cceb5c8f381 100644 (file)
@@ -12586,10 +12586,12 @@ target_specific_reloc_handling (Filedata *           filedata,
        switch (reloc_type)
          {
          case 10: /* R_MSP430_SYM_DIFF */
+         case 12: /* R_MSP430_GNU_SUB_ULEB128 */
            if (uses_msp430x_relocs (filedata))
              break;
            /* Fall through.  */
          case 21: /* R_MSP430X_SYM_DIFF */
+         case 23: /* R_MSP430X_GNU_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_GNU_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_GNU_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_GNU_SET_ULEB128 */
+                 case 22: /* R_MSP430X_GNU_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
index e89d7e0400750996d73371def0a55e131eaa94b2..7335e83941afaa357486fd639590c88a21a34796 100644 (file)
@@ -1,3 +1,9 @@
+2020-09-08  Jozef Lawrynowicz  <jozef.l@mittosystems.com>
+       Kuan-Lin Chen  <kuanlinchentw@gmail.com>
+
+       * config/tc-msp430.c (msp430_insert_uleb128_fixes): New.
+       (msp430_md_end): Call msp430_insert_uleb128_fixes.
+
 2020-09-08  Alex Coplan  <alex.coplan@arm.com>
 
        * config/tc-aarch64.c (aarch64_cpus): Add Cortex-R82.
index 2738937b11237e78e57b4290f4260f7c6f740dc8..6d1803202ce7cfea1b280d38873f25efea0b717c 100644 (file)
@@ -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.  */
index eff811641f11306f2c8185b131dbd372f19b6735..6017c8b794c83e4b955536e9a24dc572dccf086c 100644 (file)
@@ -1,3 +1,10 @@
+2020-09-08  Jozef Lawrynowicz  <jozef.l@mittosystems.com>
+       Kuan-Lin Chen  <kuanlinchentw@gmail.com>
+
+       * elf/msp430.h (elf_msp430_reloc_type): Add
+       R_MSP430_GNU_{SET,SUB}_ULEB128.
+       (elf_msp430x_reloc_type): Add R_MSP430X_GNU_{SET,SUB}_ULEB128.
+
 2020-09-08  Alex Coplan  <alex.coplan@arm.com>
 
        * opcode/aarch64.h (aarch64_sys_ins_reg_supported_p): Also take
index 536f71452f6f03587251a2e7798c96a1fc32cfaa..8d047cd18bbe50db6342bfa0b1f3581ce9ae11f1 100644 (file)
@@ -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_GNU_SET_ULEB128, 11) /* GNU only.  */
+     RELOC_NUMBER (R_MSP430_GNU_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_GNU_SET_ULEB128, 22) /* GNU only.  */
+     RELOC_NUMBER (R_MSP430X_GNU_SUB_ULEB128, 23) /* GNU only.  */
 END_RELOC_NUMBERS (R_MSP430x_max)
 
 #endif /* _ELF_MSP430_H */
index 4b42f05171c2eb892dedf7f972b29248450eed62..1f804793107269da2db658aab7ec26056b401c4a 100644 (file)
@@ -1,3 +1,10 @@
+2020-09-08  Jozef Lawrynowicz  <jozef.l@mittosystems.com>
+
+       * testsuite/ld-msp430-elf/msp430-elf.exp: Run new tests.
+       * testsuite/ld-msp430-elf/uleb128.s: New test.
+       * testsuite/ld-msp430-elf/uleb128_430.d: New test.
+       * testsuite/ld-msp430-elf/uleb128_430x.d: New test.
+
 2020-09-08  Alan Modra  <amodra@gmail.com>
 
        * testsuite/ld-elf/pr26580-a.s,
index a2fa4db48d45bec9a39b9aca54e47e42f29f67d6..875b413c149cff3458565d8c00e697df3870e7e0 100644 (file)
@@ -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 (file)
index 0000000..598ee0c
--- /dev/null
@@ -0,0 +1,34 @@
+.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 (file)
index 0000000..5104552
--- /dev/null
@@ -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 (file)
index 0000000..e808a53
--- /dev/null
@@ -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