[binutils-gdb] gas: tighten get_single_number()

Jan Beulich jbeulich@sourceware.org
Fri Feb 20 07:40:11 GMT 2026


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=6121ea1e5d5bfdece18e03a455b19b1d9b7ff85e

commit 6121ea1e5d5bfdece18e03a455b19b1d9b7ff85e
Author: Jan Beulich <jbeulich@suse.com>
Date:   Fri Feb 20 08:36:55 2026 +0100

    gas: tighten get_single_number()
    
    Move what the function does closer to what its name says. Add some error
    checking, also in its sole caller (implementing entirely undocumented and
    - so far - entirely untested behavior).
    
    I really want the -f passed to gas in the new testcase, yet that means the
    odd-looking .if expression can't be commented upon
    ("NUMBERS_WITH_SUFFIX implies in particular no C-style octal numbers").

Diff:
---
 gas/expr.c                      | 56 ++++++++++++++++++++++++++++++++++++++++-
 gas/expr.h                      |  2 +-
 gas/read.c                      | 10 ++++++--
 gas/testsuite/gas/all/gas.exp   |  2 ++
 gas/testsuite/gas/all/string2.d | 11 ++++++++
 gas/testsuite/gas/all/string2.s | 15 +++++++++++
 6 files changed, 92 insertions(+), 4 deletions(-)

diff --git a/gas/expr.c b/gas/expr.c
index 87824b0ca1a..c965486bf04 100644
--- a/gas/expr.c
+++ b/gas/expr.c
@@ -2597,10 +2597,64 @@ restore_line_pointer (char c)
   return c;
 }
 
-unsigned int
+offsetT
 get_single_number (void)
 {
   expressionS exp;
+
+  SKIP_WHITESPACE ();
+
+  switch (*input_line_pointer)
+    {
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+    case '8':
+    case '9':
+      break;
+
+#if defined (TC_M68K)
+    case '%':
+    case '@':
+      if (!flag_m68k_mri)
+	goto bad;
+      break;
+#elif defined (LITERAL_PREFIXPERCENT_BIN)
+    case '%':
+      break;
+#endif
+
+    case '$':
+#if !defined (DOLLAR_DOT) && !defined (TC_M68K)
+      if (!literal_prefix_dollar_hex || input_line_pointer[1] == 'L')
+	goto bad;
+#else
+      if (!DOLLAR_AMBIGU
+#ifndef DOLLAR_DOT
+	  || !flag_m68k_mri
+#endif
+	  || !hex_p (input_line_pointer[1]))
+	goto bad;
+#endif
+      break;
+
+    default:
+      goto bad;
+    }
+
   operand (&exp, expr_normal);
+
+  if (exp.X_op != O_constant)
+    {
+  bad:
+      as_bad (_("bad number"));
+      exp.X_add_number = 0;
+    }
+
   return exp.X_add_number;
 }
diff --git a/gas/expr.h b/gas/expr.h
index 9097ff8b514..648f3238851 100644
--- a/gas/expr.h
+++ b/gas/expr.h
@@ -178,7 +178,7 @@ extern void expr_set_rank (operatorT, operator_rankT);
 extern void add_to_result (expressionS *, offsetT, int);
 extern void subtract_from_result (expressionS *, offsetT, int);
 extern segT expr (int, expressionS *, enum expr_mode);
-extern unsigned int get_single_number (void);
+extern offsetT get_single_number (void);
 extern symbolS *make_expr_symbol (const expressionS * expressionP);
 extern int expr_symbol_where (symbolS *, const char **, unsigned int *);
 extern void current_location (expressionS *, enum expr_mode);
diff --git a/gas/read.c b/gas/read.c
index 29dace68958..5905865a19a 100644
--- a/gas/read.c
+++ b/gas/read.c
@@ -6106,8 +6106,14 @@ stringer (int bits_appendzero)
 	  break;
 	case '<':
 	  input_line_pointer++;
-	  c = get_single_number ();
-	  stringer_append_char (c, bitsize);
+	  offsetT n = get_single_number ();
+	  if (n != (unsigned char) n)
+	    {
+	      as_bad (_("<nn> out of range"));
+	      ignore_rest_of_line ();
+	      return;
+	    }
+	  stringer_append_char (n, bitsize);
 	  if (*input_line_pointer != '>')
 	    {
 	      as_bad (_("expected <nn>"));
diff --git a/gas/testsuite/gas/all/gas.exp b/gas/testsuite/gas/all/gas.exp
index c51836b5821..b99ecdba241 100644
--- a/gas/testsuite/gas/all/gas.exp
+++ b/gas/testsuite/gas/all/gas.exp
@@ -509,6 +509,8 @@ run_dump_test base64
 run_dump_test base64-bad
 
 run_dump_test string
+run_dump_test string2
+
 if [is_elf_format] {
     run_dump_test none
 }
diff --git a/gas/testsuite/gas/all/string2.d b/gas/testsuite/gas/all/string2.d
new file mode 100644
index 00000000000..5f16f9e7b6c
--- /dev/null
+++ b/gas/testsuite/gas/all/string2.d
@@ -0,0 +1,11 @@
+#as: -f
+#objdump : -s -j .data -j "\$DATA\$"
+#name : .ascii w/ angle brackets
+# These have their own "stringer", not recognizing '<' / '>' as brackets.
+#xfail: tic4x-* tic54x-*
+
+.*: .*
+
+Contents of section (\.data|\$DATA\$):
+ 0000 213f5c21 213f5c21 .*
+#pass
diff --git a/gas/testsuite/gas/all/string2.s b/gas/testsuite/gas/all/string2.s
new file mode 100644
index 00000000000..a13db5d88f2
--- /dev/null
+++ b/gas/testsuite/gas/all/string2.s
@@ -0,0 +1,15 @@
+	.data
+
+	.if 077 == 77
+	.ascii <33D>
+	.ascii <3fH>
+	.ascii <134O>
+	.ascii <100001B>
+	.ascii <33D>,< 3fH ><134O> <100001B>
+	.else
+	.ascii <33>
+	.ascii <0x3f>
+	.ascii <0134>
+	.ascii <0b100001>
+	.ascii <33>,< 0x3f ><0134> <0b100001>
+	.endif


More information about the Binutils-cvs mailing list