From 4504a6346777d544a144683bd2a534b686fbac41 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Wed, 16 Jun 2021 08:55:20 +0200 Subject: [PATCH] gas: fix overflow diagnostics 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 | 10 ++++++++++ gas/read.c | 11 ++--------- gas/testsuite/gas/all/gas.exp | 21 +++++++++++++++++++++ gas/testsuite/gas/all/overflow.l | 9 +++++++++ gas/testsuite/gas/all/overflow.s | 26 ++++++++++++++++++++++++++ gas/write.c | 5 ++++- 6 files changed, 72 insertions(+), 10 deletions(-) create mode 100644 gas/testsuite/gas/all/overflow.l create mode 100644 gas/testsuite/gas/all/overflow.s diff --git a/gas/ChangeLog b/gas/ChangeLog index be9882a0d0a..ebbf27f0b66 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,13 @@ +2021-06-16 Jan Beulich + + * 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 * config/tc-i386.c (md_show_usage): Split ELF and PE/COFF parts diff --git a/gas/read.c b/gas/read.c index 2f93e1bfd96..db1011b6392 100644 --- a/gas/read.c +++ b/gas/read.c @@ -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"), diff --git a/gas/testsuite/gas/all/gas.exp b/gas/testsuite/gas/all/gas.exp index e9648ffb221..389634f6165 100644 --- a/gas/testsuite/gas/all/gas.exp +++ b/gas/testsuite/gas/all/gas.exp @@ -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 index 00000000000..96309570ef0 --- /dev/null +++ b/gas/testsuite/gas/all/overflow.l @@ -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 index 00000000000..879f93abe39 --- /dev/null +++ b/gas/testsuite/gas/all/overflow.s @@ -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 diff --git a/gas/write.c b/gas/write.c index 682e28f3834..7dc78b7fe19 100644 --- a/gas/write.c +++ b/gas/write.c @@ -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); -- 2.30.2