gas: fix overflow diagnostics
authorJan Beulich <jbeulich@suse.com>
Wed, 16 Jun 2021 06:55:20 +0000 (08:55 +0200)
committerJan Beulich <jbeulich@suse.com>
Wed, 16 Jun 2021 06:55:20 +0000 (08:55 +0200)
While the logic in fixup_segment() so far was off by 1 for fixups
dealing with quantities without known signedness, thus failing to report
an overflow when e.g. a byte-sized resulting value is -0x100, the logic
in emit_expr_with_reloc() reported an overflow even on large negative
values when the respective positive ones would not be warned
about, and when fixup_segment() wouldn't do so either. Such diagnostics
all ought to follow a similar pattern of what value range is acceptable.
(If expressions' X_unsigned was reliably set, emit_expr_with_reloc()'s
checking might make sense to tighten based on that flag.)

Note that with commit 80aab57939a0 ("Changes to let cons handle bignums
like general expressions") having added handling of nbytes >
sizeof(valueT) in the O_constant case, converting to O_big, the setting
to zero of "hibit" had become dead. With "hibit" no longer used, this
code now gets dropped altogether. But additionally a respective know()
gets inserted.

gas/ChangeLog
gas/read.c
gas/testsuite/gas/all/gas.exp
gas/testsuite/gas/all/overflow.l [new file with mode: 0644]
gas/testsuite/gas/all/overflow.s [new file with mode: 0644]
gas/write.c

index be9882a0d0ae888f51f68e774cb1128f7c52ba28..ebbf27f0b6635d95c26339f37e6c97141729fb1a 100644 (file)
@@ -1,3 +1,13 @@
+2021-06-16  Jan Beulich  <jbeulich@suse.com>
+
+       * read.c (emit_expr_with_reloc): Adjust overflow check. Drop
+       hibit local variable.
+       * write.c (fixup_segment): Differentiate signed and non-signed
+       relocs in overflow check.
+       * testsuite/gas/all/overflow.s,
+       testsuite/gas/all/overflow.l: New.
+       * testsuite/gas/all/gas.exp: Run new test.
+
 2021-06-15  Jan Beulich  <jbeulich@suse.com>
 
        * config/tc-i386.c (md_show_usage): Split ELF and PE/COFF parts
index 2f93e1bfd9625ff85b4eedb94f6283eae1222eec..db1011b6392be85939c53842b9fbaacb27f86a72 100644 (file)
@@ -4505,24 +4505,19 @@ emit_expr_with_reloc (expressionS *exp,
       valueT get;
       valueT use;
       valueT mask;
-      valueT hibit;
       valueT unmask;
 
       /* JF << of >= number of bits in the object is undefined.  In
         particular SPARC (Sun 4) has problems.  */
       if (nbytes >= sizeof (valueT))
        {
+         know (nbytes == sizeof (valueT));
          mask = 0;
-         if (nbytes > sizeof (valueT))
-           hibit = 0;
-         else
-           hibit = (valueT) 1 << (nbytes * BITS_PER_CHAR - 1);
        }
       else
        {
          /* Don't store these bits.  */
          mask = ~(valueT) 0 << (BITS_PER_CHAR * nbytes);
-         hibit = (valueT) 1 << (nbytes * BITS_PER_CHAR - 1);
        }
 
       unmask = ~mask;          /* Do store these bits.  */
@@ -4534,9 +4529,7 @@ emit_expr_with_reloc (expressionS *exp,
 
       get = exp->X_add_number;
       use = get & unmask;
-      if ((get & mask) != 0
-         && ((get & mask) != mask
-             || (get & hibit) == 0))
+      if ((get & mask) != 0 && (-get & mask) != 0)
        {
          /* Leading bits contain both 0s & 1s.  */
          as_warn (_("value 0x%" BFD_VMA_FMT "x truncated to 0x%" BFD_VMA_FMT "x"),
index e9648ffb221764cf41e5f17788c056f03e16b632..389634f616546a0fc4dea85649320e42625bbb2d 100644 (file)
@@ -372,6 +372,27 @@ switch -glob $target_triplet {
     }
 }
 
+# Various targets use too custom handling to be able to sensibly create
+# common expecations for this test.  Also .equ works differently on some
+# targets.
+if {    ![istarget avr-*-*]
+     && ![istarget bfin-*-*]
+     && ![istarget cris*-*-*]
+     && ![istarget dlx-*-*]
+     && ![istarget hppa*-*-*]
+     && ![istarget m68k-*-*]
+     && ![istarget nios2-*-*]
+     && ![istarget pj-*-*]
+     && ![istarget sh*-*-*]
+     && ![istarget *c4x-*-*]
+     && ![istarget *c54x-*-*]
+     && ![istarget *c6x-*-*]
+     && ![istarget z80-*-*] } then {
+    # Some further targets' custom handling fails to recognize the overflows.
+    setup_xfail "crx-*-*" "h8300-*-*" "mcore-*-*" "mn10200-*-*" "mn10300-*-*" "msp430-*-*" "ns32k-*-*"
+    run_list_test "overflow"
+}
+
 if {  ([istarget "i*86-*-*pe*"] && ![istarget "i*86-*-openbsd*"]) \
     || [istarget "i*86-*-cygwin*"] \
     || [istarget "i*86-*-mingw32*"] } {
diff --git a/gas/testsuite/gas/all/overflow.l b/gas/testsuite/gas/all/overflow.l
new file mode 100644 (file)
index 0000000..9630957
--- /dev/null
@@ -0,0 +1,9 @@
+.*: Assembler messages:
+.*:5: Warning: .* (0x)?100 truncated to (0x)?0
+.*:6: Warning: .* (0x)?101 truncated to (0x)?1
+.*:11: Warning: .* (0x)?f+00 truncated to (0x)?0
+.*:12: Warning: .* (0x)?f+eff truncated to (0x)?ff
+.*:17: Error: .* (256|(0x)?100) too large .*
+.*:18: Error: .* (257|(0x)?101) too large .*
+.*:23: Error: .* (0x)?f+00 too large .*
+.*:24: Error: .* (0x)?f+eff too large .*
diff --git a/gas/testsuite/gas/all/overflow.s b/gas/testsuite/gas/all/overflow.s
new file mode 100644 (file)
index 0000000..879f93a
--- /dev/null
@@ -0,0 +1,26 @@
+       .data
+       .dc.b +0x80
+       .dc.b +0x81
+       .dc.b +0xff
+       .dc.b +0x100
+       .dc.b +0x101
+
+       .dc.b -0x80
+       .dc.b -0x81
+       .dc.b -0xff
+       .dc.b -0x100
+       .dc.b -0x101
+
+       .dc.b zero+0x80
+       .dc.b zero+0x81
+       .dc.b zero+0xff
+       .dc.b zero+0x100
+       .dc.b zero+0x101
+
+       .dc.b zero-0x80
+       .dc.b zero-0x81
+       .dc.b zero-0xff
+       .dc.b zero-0x100
+       .dc.b zero-0x101
+
+       .equ zero, 0
index 682e28f3834658a0eeff211770b559bf6ae8a666..7dc78b7fe19f42c172d386dd62583c6078b5dd28 100644 (file)
@@ -1107,7 +1107,10 @@ fixup_segment (fixS *fixP, segT this_segment)
              mask = 0;
              mask--;           /* Set all bits to one.  */
              mask <<= fixP->fx_size * 8 - (fixP->fx_signed ? 1 : 0);
-             if ((add_number & mask) != 0 && (add_number & mask) != mask)
+             if ((add_number & mask) != 0
+                 && (fixP->fx_signed
+                     ? (add_number & mask) != mask
+                     : (-add_number & mask) != 0))
                {
                  char buf[50], buf2[50];
                  bfd_sprintf_vma (stdoutput, buf, fragP->fr_address + fixP->fx_where);