]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
LoongArch: Fix immediate overflow check bug
authormengqinggang <mengqinggang@loongson.cn>
Mon, 24 Jul 2023 09:08:26 +0000 (10:08 +0100)
committerNick Clifton <nickc@redhat.com>
Mon, 24 Jul 2023 09:08:26 +0000 (10:08 +0100)
  * elfnn-loongarch.c (RELOCATE_CALC_PC32_HI20): Redefined.
  (RELOCATE_CALC_PC64_HI32): Redefined.
  * elfxx-loongarch.c (reloc_bits_pcrel20_s2): Delete.
  (reloc_bits_b16): Delete.
  (reloc_bits_b21): Delete.
  (reloc_bits_b26): Delete.
  (reloc_sign_bits): New.

bfd/ChangeLog
bfd/elfnn-loongarch.c
bfd/elfxx-loongarch.c

index 2352f4f69ee0d8e1e68dca702e2b946855bce323..723c8c273f55b452aa654b82dcf5b74737186618 100644 (file)
@@ -1,3 +1,15 @@
+2023-07-24  Nick Clifton  <nickc@redhat.com>
+
+       Import from mainline:
+       * elfnn-loongarch.c (RELOCATE_CALC_PC32_HI20): Redefined.
+       (RELOCATE_CALC_PC64_HI32): Redefined.
+
+       * elfxx-loongarch.c (reloc_bits_pcrel20_s2): Delete.
+       (reloc_bits_b16): Delete.
+       (reloc_bits_b21): Delete.
+       (reloc_bits_b26): Delete.
+       (reloc_sign_bits): New.
+
 2023-07-03  Nick Clifton  <nickc@redhat.com>
 
        * version.m4: Update version number to 2.40.90.
index d3d8419d80b40b88c7f283795d2125a410c8ee56..e9c408b2dff36ee910637bf62d37dd8884c0212f 100644 (file)
@@ -2284,26 +2284,65 @@ loongarch_reloc_is_fatal (struct bfd_link_info *info,
   return fatal;
 }
 
+/* If lo12 immediate > 0x7ff, because sign-extend caused by addi.d/ld.d,
+   hi20 immediate need to add 0x1.
+   For example: pc 0x120000000, symbol 0x120000812
+   lo12 immediate is 0x812, 0x120000812 & 0xfff = 0x812
+   hi20 immediate is 1, because lo12 imm > 0x7ff, symbol need to add 0x1000
+   (((0x120000812 + 0x1000) & ~0xfff) - (0x120000000 & ~0xfff)) >> 12 = 0x1
+
+   At run:
+   pcalau12i $t0, hi20 (0x1)
+      $t0 = 0x120000000 + (0x1 << 12) = 0x120001000
+   addi.d $t0, $t0, lo12 (0x812)
+      $t0 = 0x120001000 + 0xfffffffffffff812 (-(0x1000 - 0x812) = -0x7ee)
+         = 0x120001000 - 0x7ee (0x1000 - 0x7ee = 0x812)
+         = 0x120000812
+    Without hi20 add 0x1000, the result 0x120000000 - 0x7ee = 0x11ffff812 is
+    error.
+    0x1000 + sign-extend-to64(0x8xx) = 0x8xx.  */
 #define RELOCATE_CALC_PC32_HI20(relocation, pc)        \
   ({                                                   \
     bfd_vma __lo = (relocation) & ((bfd_vma)0xfff);    \
-    pc = pc & (~(bfd_vma)0xfff);                       \
+    relocation = (relocation & ~(bfd_vma)0xfff)                \
+                 - (pc & ~(bfd_vma)0xfff);             \
     if (__lo > 0x7ff)                                  \
-      {                                                        \
        relocation += 0x1000;                           \
-      }                                                \
-    relocation &= ~(bfd_vma)0xfff;                     \
-    relocation -= pc;                                  \
   })
 
+/* For example: pc is 0x11000010000100, symbol is 0x1812348ffff812
+   offset = (0x1812348ffff812 & ~0xfff) - (0x11000010000100 & ~0xfff)
+         = 0x712347ffff000
+   lo12: 0x1812348ffff812 & 0xfff = 0x812
+   hi20: 0x7ffff + 0x1(lo12 > 0x7ff) = 0x80000
+   lo20: 0x71234 - 0x1(lo12 > 0x7ff) + 0x1(hi20 > 0x7ffff)
+   hi12: 0x0
+
+   pcalau12i $t1, hi20 (0x80000)
+      $t1 = 0x11000010000100 + sign-extend(0x80000 << 12)
+         = 0x11000010000100 + 0xffffffff80000000
+         = 0x10ffff90000000
+   addi.d $t0, $zero, lo12 (0x812)
+      $t0 = 0xfffffffffffff812 (if lo12 > 0x7ff, because sign-extend,
+      lo20 need to sub 0x1)
+   lu32i.d $t0, lo12 (0x71234)
+      $t0 = {0x71234, 0xfffff812}
+         = 0x71234fffff812
+   lu52i.d $t0, hi12 (0x0)
+      $t0 = {0x0, 0x71234fffff812}
+         = 0x71234fffff812
+   add.d $t1, $t1, $t0
+      $t1 = 0x10ffff90000000 + 0x71234fffff812
+         = 0x1812348ffff812.  */
 #define RELOCATE_CALC_PC64_HI32(relocation, pc)        \
   ({                                                   \
-    bfd_vma __lo = (relocation) & ((bfd_vma)0xfff);    \
+    bfd_vma __lo = (relocation & (bfd_vma)0xfff);      \
+    relocation = (relocation & ~(bfd_vma)0xfff)                \
+                 - (pc & ~(bfd_vma)0xfff);             \
     if (__lo > 0x7ff)                                  \
-      {                                                \
-       relocation -= 0x100000000;                      \
-      }                                                \
-    relocation -= (pc & ~(bfd_vma)0xffffffff);         \
+       relocation += (0x1000 - 0x100000000);           \
+    if (relocation & 0x80000000)                       \
+      relocation += 0x100000000;                       \
   })
 
 static int
index da440d55c3c58fe18d328b99a7e66e1e79de2db7..2d299050c12249e5598f286f3ea724d838370062 100644 (file)
@@ -54,13 +54,7 @@ typedef struct loongarch_reloc_howto_type_struct
 static bool
 reloc_bits (bfd *abfd, reloc_howto_type *howto, bfd_vma *val);
 static bool
-reloc_bits_pcrel20_s2 (bfd *abfd, reloc_howto_type *howto, bfd_vma *fix_val);
-static bool
-reloc_bits_b16 (bfd *abfd, reloc_howto_type *howto, bfd_vma *fix_val);
-static bool
-reloc_bits_b21 (bfd *abfd, reloc_howto_type *howto, bfd_vma *fix_val);
-static bool
-reloc_bits_b26 (bfd *abfd, reloc_howto_type *howto, bfd_vma *val);
+reloc_sign_bits (bfd *abfd, reloc_howto_type *howto, bfd_vma *fix_val);
 
 static bfd_reloc_status_type
 loongarch_elf_add_sub_reloc (bfd *, arelent *, asymbol *, void *,
@@ -457,7 +451,7 @@ static loongarch_reloc_howto_type loongarch_howto_table[] =
         0x3fffc00,                               /* dst_mask */
         false,                                   /* pcrel_offset */
         BFD_RELOC_LARCH_SOP_POP_32_S_10_16_S2,   /* bfd_reloc_code_real_type */
-        reloc_bits_b16,                          /* adjust_reloc_bits */
+        reloc_sign_bits,                         /* adjust_reloc_bits */
         NULL),                                   /* larch_reloc_type_name */
 
   LOONGARCH_HOWTO (R_LARCH_SOP_POP_32_S_5_20,    /* type (43).  */
@@ -493,7 +487,7 @@ static loongarch_reloc_howto_type loongarch_howto_table[] =
         false,                                   /* pcrel_offset */
         BFD_RELOC_LARCH_SOP_POP_32_S_0_5_10_16_S2,
                                                  /* bfd_reloc_code_real_type */
-        reloc_bits_b21,                          /* adjust_reloc_bits */
+        reloc_sign_bits,                         /* adjust_reloc_bits */
         NULL),                                   /* larch_reloc_type_name */
 
   LOONGARCH_HOWTO (R_LARCH_SOP_POP_32_S_0_10_10_16_S2, /* type (45).  */
@@ -511,7 +505,7 @@ static loongarch_reloc_howto_type loongarch_howto_table[] =
         false,                                 /* pcrel_offset */
         BFD_RELOC_LARCH_SOP_POP_32_S_0_10_10_16_S2,
                                                /* bfd_reloc_code_real_type */
-        reloc_bits_b26,                        /* adjust_reloc_bits */
+        reloc_sign_bits,                       /* adjust_reloc_bits */
         NULL),                                 /* larch_reloc_type_name */
 
   LOONGARCH_HOWTO (R_LARCH_SOP_POP_32_U,       /* type (46).  */
@@ -766,7 +760,7 @@ static loongarch_reloc_howto_type loongarch_howto_table[] =
         0x3fffc00,                             /* dst_mask.  */
         false,                                 /* pcrel_offset.  */
         BFD_RELOC_LARCH_B16,                   /* bfd_reloc_code_real_type.  */
-        reloc_bits_b16,                        /* adjust_reloc_bits.  */
+        reloc_sign_bits,                       /* adjust_reloc_bits.  */
         "b16"),                                /* larch_reloc_type_name.  */
 
   LOONGARCH_HOWTO (R_LARCH_B21,                        /* type (65).  */
@@ -783,7 +777,7 @@ static loongarch_reloc_howto_type loongarch_howto_table[] =
         0x3fffc1f,                             /* dst_mask.  */
         false,                                 /* pcrel_offset.  */
         BFD_RELOC_LARCH_B21,                   /* bfd_reloc_code_real_type.  */
-        reloc_bits_b21,                        /* adjust_reloc_bits.  */
+        reloc_sign_bits,                       /* adjust_reloc_bits.  */
         "b21"),                                /* larch_reloc_type_name.  */
 
   LOONGARCH_HOWTO (R_LARCH_B26,                        /* type (66).  */
@@ -800,7 +794,7 @@ static loongarch_reloc_howto_type loongarch_howto_table[] =
         0x03ffffff,                            /* dst_mask.  */
         false,                                 /* pcrel_offset.  */
         BFD_RELOC_LARCH_B26,                   /* bfd_reloc_code_real_type.  */
-        reloc_bits_b26,                        /* adjust_reloc_bits.  */
+        reloc_sign_bits,                       /* adjust_reloc_bits.  */
         "b26"),                                /* larch_reloc_type_name.  */
 
   LOONGARCH_HOWTO (R_LARCH_ABS_HI20,           /* type (67).  */
@@ -1436,7 +1430,7 @@ static loongarch_reloc_howto_type loongarch_howto_table[] =
         0x1ffffe0,                             /* dst_mask.  */
         false,                                 /* pcrel_offset.  */
         BFD_RELOC_LARCH_PCREL20_S2,            /* bfd_reloc_code_real_type.  */
-        reloc_bits_pcrel20_s2,                 /* adjust_reloc_bits.  */
+        reloc_sign_bits,                       /* adjust_reloc_bits.  */
         NULL),                                 /* larch_reloc_type_name.  */
 
   /* Canonical Frame Address.  */
@@ -1677,12 +1671,14 @@ reloc_bits (bfd *abfd ATTRIBUTE_UNUSED,
 }
 
 static bool
-reloc_bits_pcrel20_s2 (bfd *abfd, reloc_howto_type *howto, bfd_vma *fix_val)
+reloc_sign_bits (bfd *abfd, reloc_howto_type *howto, bfd_vma *fix_val)
 {
+  if (howto->complain_on_overflow != complain_overflow_signed)
+    return false;
+
   bfd_signed_vma val = (bfd_signed_vma)(*fix_val);
-  bfd_signed_vma mask = ((bfd_signed_vma)0x1 << howto->bitsize) - 1;
 
-  /* Check rightshift.  */
+  /* Check alignment. FIXME: if rightshift is not alingment.  */
   if (howto->rightshift
       && (val & ((((bfd_signed_vma) 1) << howto->rightshift) - 1)))
     {
@@ -1692,8 +1688,12 @@ reloc_bits_pcrel20_s2 (bfd *abfd, reloc_howto_type *howto, bfd_vma *fix_val)
       return false;
     }
 
-  val = val >> howto->rightshift;
+  bfd_signed_vma mask = ((bfd_signed_vma)0x1 << (howto->bitsize
+                         + howto->rightshift - 1)) - 1;
 
+  /* Positive number: high part is all 0;
+     Negative number: if high part is not all 0, high part must be all 1.
+     high part: from sign bit to highest bit.  */
   if ((val & ~mask) && ((val & ~mask) != ~mask))
     {
       (*_bfd_error_handler) (_("%pB: relocation %s overflow 0x%lx"),
@@ -1702,123 +1702,27 @@ reloc_bits_pcrel20_s2 (bfd *abfd, reloc_howto_type *howto, bfd_vma *fix_val)
       return false;
     }
 
-  /* Perform insn bits field.  */
-  val = val & mask;
-  val <<= howto->bitpos;
-
-  *fix_val = (bfd_vma)val;
-
-  return true;
-}
-
-
-/* Adjust val to perform insn
-   R_LARCH_SOP_POP_32_S_10_16_S2
-   R_LARCH_B16.  */
-static bool
-reloc_bits_b16 (bfd *abfd, reloc_howto_type *howto, bfd_vma *fix_val)
-{
-  bfd_signed_vma val = *fix_val;
-  bfd_signed_vma mask = ((bfd_signed_vma)0x1 << howto->bitsize) - 1;
-
-  if (howto->complain_on_overflow != complain_overflow_signed)
-    return false;
-
-  /* Judge whether 4 bytes align.  */
-  if (val & ((0x1UL << howto->rightshift) - 1))
-    return false;
-
-  val = val >> howto->rightshift;
-
-  if ((val & ~mask) && ((val & ~mask) != ~mask))
-    {
-      (*_bfd_error_handler) (_("%pB: relocation %s overflow 0x%lx"),
-                            abfd, howto->name, (long) val);
-      bfd_set_error (bfd_error_bad_value);
-      return false;
-    }
-
-  /* Perform insn bits field.  */
-  val = val & mask;
-  val <<= howto->bitpos;
-
-  *fix_val = val;
-
-  return true;
-}
-
-/* Reloc type :
-   R_LARCH_SOP_POP_32_S_0_5_10_16_S2
-   R_LARCH_B21.  */
-static bool
-reloc_bits_b21 (bfd *abfd, reloc_howto_type *howto, bfd_vma *fix_val)
-{
-  bfd_signed_vma val = *fix_val;
-  bfd_signed_vma mask = ((bfd_signed_vma)0x1 << howto->bitsize) - 1;
-
-  if (howto->complain_on_overflow != complain_overflow_signed)
-    return false;
-
-  /* Judge whether 4 bytes align.  */
-  if (val & ((0x1UL << howto->rightshift) - 1))
-    return false;
-
   val = val >> howto->rightshift;
-
-  if ((val & ~mask) && ((val & ~mask) != ~mask))
-    {
-      (*_bfd_error_handler) (_("%pB: relocation %s overflow 0x%lx"),
-                            abfd, howto->name, (long) val);
-      bfd_set_error (bfd_error_bad_value);
-      return false;
-    }
-
-  /* Perform insn bits field.  */
+  /* can delete? */
+  mask = ((bfd_signed_vma)0x1 << howto->bitsize) - 1;
   val = val & mask;
 
-  /* Perform insn bits field.  15:0<<10, 20:16>>16.  */
-  val = ((val & 0xffff) << 10) | ((val >> 16) & 0x1f);
-
-  *fix_val = val;
-
-  return true;
-}
-
-/* Reloc type:
-   R_LARCH_SOP_POP_32_S_0_10_10_16_S2
-   R_LARCH_B26.  */
-static bool
-reloc_bits_b26 (bfd *abfd, reloc_howto_type *howto, bfd_vma *fix_val)
-{
-  bfd_signed_vma val = *fix_val;
-  bfd_signed_vma mask = ((bfd_signed_vma)0x1 << howto->bitsize) - 1;
-
-  if (howto->complain_on_overflow != complain_overflow_signed)
-    return false;
-
-  /* Judge whether 4 bytes align.  */
-  if (val & ((0x1UL << howto->rightshift) - 1))
-    return false;
-
-  val = val >> howto->rightshift;
-
-  if ((val & ~mask) && ((val & ~mask) != ~mask))
+  switch (howto->type)
     {
-      (*_bfd_error_handler) (_("%pB: relocation %s overflow 0x%lx"),
-                            abfd, howto->name, (long) val);
-      bfd_set_error (bfd_error_bad_value);
-      return false;
+    case R_LARCH_SOP_POP_32_S_0_10_10_16_S2:
+    case R_LARCH_B26:
+      /* Perform insn bits field.  25:16>>16, 15:0<<10.  */
+      val = ((val & 0xffff) << 10) | ((val >> 16) & 0x3ff);
+      break;
+    case R_LARCH_B21:
+      val = ((val & 0xffff) << 10) | ((val >> 16) & 0x1f);
+      break;
+    default:
+      val <<= howto->bitpos;
+      break;
     }
 
-
-  /* Perform insn bits field.  */
-  val = val & mask;
-
-  /* Perform insn bits field.  25:16>>16, 15:0<<10.  */
-  val = ((val & 0xffff) << 10) | ((val >> 16) & 0x3ff);
-
   *fix_val = val;
-
   return true;
 }