xtensa: fix XTENSA_NDIFF handling for PR ld/25861
authorMax Filippov <jcmvbkbc@gmail.com>
Sat, 25 Apr 2020 07:40:25 +0000 (00:40 -0700)
committerMax Filippov <jcmvbkbc@gmail.com>
Thu, 30 Apr 2020 01:34:23 +0000 (18:34 -0700)
Fields marked with XTENSA_NDIFF relocations are not negated, they only
have sign bits removed. Don't negate their values when relaxation is
performed. Don't add sign bits when the value is zero. Report overflow
when the result has negative sign but all significant bits are zero.

2020-04-29  Max Filippov  <jcmvbkbc@gmail.com>
bfd/
* elf32-xtensa.c (relax_section): Don't negate diff_value for
XTENSA_NDIFF relocations. Don't add sign bits whe diff_value
equals 0. Report overflow when the result has negative sign but
all significant bits are zero.

ld/
* testsuite/ld-xtensa/relax-diff1.d: New test definition.
* testsuite/ld-xtensa/relax-diff1.s: New test source.
* testsuite/ld-xtensa/relax-ndiff.d: New test definition.
* testsuite/ld-xtensa/relax-ndiff.s: New test source.
* testsuite/ld-xtensa/xtensa.exp: (relax-diff1)
(relax-ndiff): New tests.

bfd/ChangeLog
bfd/elf32-xtensa.c
ld/ChangeLog
ld/testsuite/ld-xtensa/relax-diff1.d [new file with mode: 0644]
ld/testsuite/ld-xtensa/relax-diff1.s [new file with mode: 0644]
ld/testsuite/ld-xtensa/relax-ndiff.d [new file with mode: 0644]
ld/testsuite/ld-xtensa/relax-ndiff.s [new file with mode: 0644]
ld/testsuite/ld-xtensa/xtensa.exp

index 31e8526da9fddc101c590e3dcba903673cfe93bd..25453b384bfe6f5470831c66de2c23afd67f06aa 100644 (file)
@@ -1,3 +1,10 @@
+2020-04-29  Max Filippov  <jcmvbkbc@gmail.com>
+
+       * elf32-xtensa.c (relax_section): Don't negate diff_value for
+       XTENSA_NDIFF relocations. Don't add sign bits whe diff_value
+       equals 0. Report overflow when the result has negative sign but
+       all significant bits are zero.
+
 2020-04-29  Gunther Nikl  <gnikl@justmail.de>
 
        * aoutx.h (swap_std_reloc_out): Special case 64 bit relocations.
index fded42d52a9a4bd04b56e98a23454b37e17a92d8..4327b027911ff251c422db28aeef05d527416426 100644 (file)
@@ -9670,37 +9670,44 @@ relax_section (bfd *abfd, asection *sec, struct bfd_link_info *link_info)
                  switch (r_type)
                    {
                    case R_XTENSA_DIFF8:
+                     diff_mask = 0x7f;
                      diff_value =
                        bfd_get_signed_8 (abfd, &contents[old_source_offset]);
                      break;
                    case R_XTENSA_DIFF16:
+                     diff_mask = 0x7fff;
                      diff_value =
                        bfd_get_signed_16 (abfd, &contents[old_source_offset]);
                      break;
                    case R_XTENSA_DIFF32:
+                     diff_mask = 0x7fffffff;
                      diff_value =
                        bfd_get_signed_32 (abfd, &contents[old_source_offset]);
                      break;
                    case R_XTENSA_PDIFF8:
                    case R_XTENSA_NDIFF8:
+                     diff_mask = 0xff;
                      diff_value =
                        bfd_get_8 (abfd, &contents[old_source_offset]);
                      break;
                    case R_XTENSA_PDIFF16:
                    case R_XTENSA_NDIFF16:
+                     diff_mask = 0xffff;
                      diff_value =
                        bfd_get_16 (abfd, &contents[old_source_offset]);
                      break;
                    case R_XTENSA_PDIFF32:
                    case R_XTENSA_NDIFF32:
+                     diff_mask = 0xffffffff;
                      diff_value =
                        bfd_get_32 (abfd, &contents[old_source_offset]);
                      break;
                    }
 
                  if (r_type >= R_XTENSA_NDIFF8
-                     && r_type <= R_XTENSA_NDIFF32)
-                   diff_value = -diff_value;
+                     && r_type <= R_XTENSA_NDIFF32
+                     && diff_value)
+                   diff_value |= ~diff_mask;
 
                  new_end_offset = offset_with_removed_text_map
                    (&target_relax_info->action_list,
@@ -9710,43 +9717,40 @@ relax_section (bfd *abfd, asection *sec, struct bfd_link_info *link_info)
                  switch (r_type)
                    {
                    case R_XTENSA_DIFF8:
-                     diff_mask = 0x7f;
                      bfd_put_signed_8 (abfd, diff_value,
                                 &contents[old_source_offset]);
                      break;
                    case R_XTENSA_DIFF16:
-                     diff_mask = 0x7fff;
                      bfd_put_signed_16 (abfd, diff_value,
                                  &contents[old_source_offset]);
                      break;
                    case R_XTENSA_DIFF32:
-                     diff_mask = 0x7fffffff;
                      bfd_put_signed_32 (abfd, diff_value,
                                  &contents[old_source_offset]);
                      break;
                    case R_XTENSA_PDIFF8:
                    case R_XTENSA_NDIFF8:
-                     diff_mask = 0xff;
                      bfd_put_8 (abfd, diff_value,
                                 &contents[old_source_offset]);
                      break;
                    case R_XTENSA_PDIFF16:
                    case R_XTENSA_NDIFF16:
-                     diff_mask = 0xffff;
                      bfd_put_16 (abfd, diff_value,
                                  &contents[old_source_offset]);
                      break;
                    case R_XTENSA_PDIFF32:
                    case R_XTENSA_NDIFF32:
-                     diff_mask = 0xffffffff;
                      bfd_put_32 (abfd, diff_value,
                                  &contents[old_source_offset]);
                      break;
                    }
 
-                 /* Check for overflow. Sign bits must be all zeroes or all ones */
-                 if ((diff_value & ~diff_mask) != 0 &&
-                     (diff_value & ~diff_mask) != (-1 & ~diff_mask))
+                 /* Check for overflow. Sign bits must be all zeroes or
+                    all ones.  When sign bits are all ones diff_value
+                    may not be zero.  */
+                 if (((diff_value & ~diff_mask) != 0
+                      && (diff_value & ~diff_mask) != ~diff_mask)
+                     || (diff_value && (bfd_vma) diff_value == ~diff_mask))
                    {
                      (*link_info->callbacks->reloc_dangerous)
                        (link_info, _("overflow after relaxation"),
index ae587dff11df53a2b853336a58270dfab447f085..43825ee4bbcd975bb91d6dc848f99a22eab8252d 100644 (file)
@@ -1,3 +1,12 @@
+2020-04-29  Max Filippov  <jcmvbkbc@gmail.com>
+
+       * testsuite/ld-xtensa/relax-diff1.d: New test definition.
+       * testsuite/ld-xtensa/relax-diff1.s: New test source.
+       * testsuite/ld-xtensa/relax-ndiff.d: New test definition.
+       * testsuite/ld-xtensa/relax-ndiff.s: New test source.
+       * testsuite/ld-xtensa/xtensa.exp: (relax-diff1)
+       (relax-ndiff): New tests.
+
 2020-04-29  Stephen Casner  <casner@acm.org>
 
        PR 25829
diff --git a/ld/testsuite/ld-xtensa/relax-diff1.d b/ld/testsuite/ld-xtensa/relax-diff1.d
new file mode 100644 (file)
index 0000000..900b55b
--- /dev/null
@@ -0,0 +1,6 @@
+#as: --text-section-literals
+#ld:
+#objdump: -s
+#...
+ 410154 06fa0006 fffa.*
+#...
diff --git a/ld/testsuite/ld-xtensa/relax-diff1.s b/ld/testsuite/ld-xtensa/relax-diff1.s
new file mode 100644 (file)
index 0000000..6cc8e2b
--- /dev/null
@@ -0,0 +1,18 @@
+       .globl  _start
+       .globl  _ResetVector
+       .text
+_ResetVector:
+_start:
+       .literal_position
+       movi    a2, 0x12345678
+       movi    a2, 0x12345678
+1:
+       .space  250
+2:
+       .space  65530
+3:
+       .align  4
+       .byte   1b - 2b
+       .byte   2b - 1b
+       .short  2b - 3b
+       .short  3b - 2b
diff --git a/ld/testsuite/ld-xtensa/relax-ndiff.d b/ld/testsuite/ld-xtensa/relax-ndiff.d
new file mode 100644 (file)
index 0000000..2a1cfd3
--- /dev/null
@@ -0,0 +1,6 @@
+#as: --text-section-literals
+#ld:
+#objdump: -s
+#...
+ 400074 fffffff6 0000000a fff6000a f60a.*
+#...
diff --git a/ld/testsuite/ld-xtensa/relax-ndiff.s b/ld/testsuite/ld-xtensa/relax-ndiff.s
new file mode 100644 (file)
index 0000000..4e4176b
--- /dev/null
@@ -0,0 +1,20 @@
+       .globl  _start
+       .globl  _ResetVector
+       .text
+_ResetVector:
+_start:
+       .literal_position
+       movi    a2, 0x12345678
+       movi    a2, 0x12345678
+1:
+       .space  10
+2:
+       .space  10
+3:
+       .align  4
+       .word   1b - 2b
+       .word   3b - 2b
+       .short  1b - 2b
+       .short  3b - 2b
+       .byte   1b - 2b
+       .byte   3b - 2b
index de39887936ad62855e843a6437d20f0e1d5b61d5..5334bc60df344b26dcfc204d750b9fc76f4010fb 100644 (file)
@@ -27,7 +27,9 @@ run_dump_test "call_overflow"
 run_dump_test "coalesce"
 run_dump_test "diff_overflow"
 run_dump_test "lcall"
+run_dump_test "relax-diff1"
 run_dump_test "relax-loc"
+run_dump_test "relax-ndiff"
 
 run_dump_test "relax-static-pie"
 run_dump_test "relax-static-local-pie"