[7/8] x86/Intel: don't modify equates' expressions

Message ID 583fea87-7fb4-4644-a39b-e1169acb1398@suse.com
State New
Headers
Series gas/x86: towards better Intel syntax expression evaluation |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_binutils_build--master-arm fail Patch failed to apply
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 fail Patch failed to apply

Commit Message

Jan Beulich March 27, 2026, 2:14 p.m. UTC
  Equates involving registers were mis-treated when parsing insn operand
expressions: When "pulling out" the register(s), they would have got
converted to O_constant. While other (local) parsing code was able to cope
with this, the generic part of the assembler was misled. A visible bad
effect would be that local absolute symbols would appear in the symbol
table, when really that should be register symbols (which wouldn't be put
in the symbol table at all).

Clone symbols / expressions as necessary before modifying them.
  

Patch

--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -167,7 +167,7 @@  static int i386_finalize_displacement (s
 				       const char *);
 static int i386_att_operand (char *);
 static int i386_intel_operand (char *, int);
-static int i386_intel_simplify (expressionS *);
+static int i386_intel_simplify (expressionS *, bool);
 static int i386_intel_parse_name (const char *, expressionS *, enum expr_mode);
 static const reg_entry *parse_register (const char *, char **);
 static const char *parse_insn (const char *, char *, enum parse_mode);
@@ -13526,7 +13526,7 @@  x86_cons (expressionS *exp, int size)
   intel_syntax = -intel_syntax;
 
   if (intel_syntax)
-    i386_intel_simplify (exp);
+    i386_intel_simplify (exp, false);
 
   /* If not 64bit, massage value, to account for wraparound when !BFD64.  */
   if (size <= 4 && expr_mode == expr_operator_present
--- a/gas/config/tc-i386-intel.c
+++ b/gas/config/tc-i386-intel.c
@@ -378,30 +378,56 @@  i386_intel_simplify_register (expression
   return 2;
 }
 
-static int
-i386_intel_simplify_symbol (symbolS *sym)
+static symbolS *
+i386_intel_simplify_symbol (symbolS *sym, bool in_equate)
 {
   if (symbol_resolving_p (sym))
-    return 1;
+    return sym;
 
-  symbol_mark_resolving (sym);
-  int ret = i386_intel_simplify (symbol_get_value_expression (sym));
-  if (ret == 2)
+  segT seg = S_GET_SEGMENT (sym);
+  if (seg != expr_section && seg != reg_section && !symbol_equated_p(sym))
+    return sym;
+
+  for (;;)
     {
-      S_SET_SEGMENT (sym, absolute_section);
-      ret = 1;
+      /* While we're after equates, symbol_equated_p() isn't suitable here.  */
+      if (symbol_on_chain(sym, symbol_rootP, symbol_lastP))
+	{
+	  in_equate = true;
+	  sym = symbol_clone (sym, 0);
+	}
+      else if (in_equate)
+	{
+	  expressionS *e = symbol_get_value_expression (sym);
+
+	  if (e->X_op == O_symbol && !e->X_add_number)
+	    {
+	      sym = e->X_add_symbol;
+	      continue;
+	    }
+	  sym = make_expr_symbol (e);
+	}
+
+      break;
     }
+
+  symbol_mark_resolving (sym);
+  int ret = i386_intel_simplify (symbol_get_value_expression (sym), in_equate);
+  if (ret == 2)
+    S_SET_SEGMENT (sym, absolute_section);
   symbol_clear_resolving (sym);
-  return ret;
+
+  return ret ? sym : NULL;
 }
 
 static int
-i386_intel_simplify (expressionS *e)
+i386_intel_simplify (expressionS *e, bool in_equate)
 {
   const reg_entry *the_reg = (this_operand >= 0
 			      ? i.op[this_operand].regs : NULL);
   const reg_entry *base = intel_state.base;
   const reg_entry *state_index = intel_state.index;
+  symbolS *newsym;
   int ret;
 
   if (!intel_syntax)
@@ -412,18 +438,21 @@  i386_intel_simplify (expressionS *e)
     case O_index:
       if (e->X_add_symbol)
 	{
-	  if (!i386_intel_simplify_symbol (e->X_add_symbol)
+	  newsym = i386_intel_simplify_symbol (e->X_add_symbol, in_equate);
+	  if (!newsym
 	      || !i386_intel_check(the_reg, intel_state.base,
 				   intel_state.index))
 	    return 0;
+	  e->X_add_symbol = newsym;
 	}
       if (!intel_state.in_offset)
 	++intel_state.in_bracket;
-      ret = i386_intel_simplify_symbol (e->X_op_symbol);
+      newsym = i386_intel_simplify_symbol (e->X_op_symbol, in_equate);
       if (!intel_state.in_offset)
 	--intel_state.in_bracket;
-      if (!ret)
+      if (!newsym)
 	return 0;
+      e->X_op_symbol = newsym;
       if (e->X_add_symbol)
 	e->X_op = O_add;
       else
@@ -433,12 +462,13 @@  i386_intel_simplify (expressionS *e)
     case O_offset:
       intel_state.has_offset = 1;
       ++intel_state.in_offset;
-      ret = i386_intel_simplify_symbol (e->X_add_symbol);
+      newsym = i386_intel_simplify_symbol (e->X_add_symbol, in_equate);
       --intel_state.in_offset;
-      if (!ret || !i386_intel_check(the_reg, base, state_index))
+      if (!newsym || !i386_intel_check(the_reg, base, state_index))
 	return 0;
+      e->X_add_symbol = newsym;
       i386_intel_fold (e, e->X_add_symbol);
-      return ret;
+      return 1;
 
     case O_byte_ptr:
     case O_word_ptr:
@@ -461,8 +491,10 @@  i386_intel_simplify (expressionS *e)
 	  as_bad (_("invalid use of register"));
 	  return 0;
 	}
-      if (!i386_intel_simplify_symbol (e->X_add_symbol))
+      newsym = i386_intel_simplify_symbol (e->X_add_symbol, in_equate);
+      if (!newsym)
 	return 0;
+      e->X_add_symbol = newsym;
       i386_intel_fold (e, e->X_add_symbol);
       break;
 
@@ -473,10 +505,12 @@  i386_intel_simplify (expressionS *e)
 	  as_bad (_("invalid use of register"));
 	  return 0;
 	}
-      if (!i386_intel_simplify_symbol (e->X_op_symbol)
+      newsym = i386_intel_simplify_symbol (e->X_op_symbol, in_equate);
+      if (!newsym
 	  || !i386_intel_check(the_reg, intel_state.base,
 			       intel_state.index))
 	return 0;
+      e->X_op_symbol = newsym;
       if (!intel_state.in_offset)
 	{
 	  if (!intel_state.seg)
@@ -503,16 +537,26 @@  i386_intel_simplify (expressionS *e)
 	  if (!intel_state.in_scale++)
 	    intel_state.scale_factor = 1;
 
-	  ret = i386_intel_simplify_symbol (e->X_add_symbol);
-	  if (ret && !has_index && intel_state.index)
-	    scale = symbol_get_value_expression (e->X_op_symbol);
-
-	  if (ret)
-	    ret = i386_intel_simplify_symbol (e->X_op_symbol);
-	  if (ret && !scale && !has_index && intel_state.index)
-	    scale = symbol_get_value_expression (e->X_add_symbol);
+	  newsym = i386_intel_simplify_symbol (e->X_add_symbol, in_equate);
+	  if (newsym)
+	    {
+	      e->X_add_symbol = newsym;
+
+	      if (!has_index && intel_state.index)
+		scale = symbol_get_value_expression (e->X_op_symbol);
+
+	      newsym = i386_intel_simplify_symbol (e->X_op_symbol, in_equate);
+	    }
+
+	  if (newsym)
+	    {
+	      e->X_op_symbol = newsym;
+
+	      if (!scale && !has_index && intel_state.index)
+		scale = symbol_get_value_expression (e->X_add_symbol);
+	    }
 
-	  if (ret && scale)
+	  if (newsym && scale)
 	    {
 	      resolve_expression (scale);
 	      if (scale->X_op != O_constant
@@ -522,7 +566,7 @@  i386_intel_simplify (expressionS *e)
 	    }
 
 	  --intel_state.in_scale;
-	  if (!ret)
+	  if (!newsym)
 	    return 0;
 
 	  if (!intel_state.in_scale)
@@ -568,9 +612,13 @@  i386_intel_simplify (expressionS *e)
       /* FALLTHROUGH */
     default:
     fallthrough:
-      if (e->X_add_symbol
-	  && !i386_intel_simplify_symbol (e->X_add_symbol))
-	return 0;
+      if (e->X_add_symbol)
+	{
+	  newsym = i386_intel_simplify_symbol (e->X_add_symbol, in_equate);
+	  if (!newsym)
+	    return 0;
+	  e->X_add_symbol = newsym;
+	}
       if (!the_reg && this_operand >= 0
 	  && e->X_op == O_symbol && !e->X_add_number)
 	the_reg = i.op[this_operand].regs;
@@ -579,14 +627,19 @@  i386_intel_simplify (expressionS *e)
 	  base = intel_state.base;
 	  state_index = intel_state.index;
 	}
-      if (!i386_intel_check (the_reg, base, state_index)
-	  || (e->X_op_symbol
-	      && !i386_intel_simplify_symbol (e->X_op_symbol))
-	  || !i386_intel_check (the_reg,
-				(e->X_op != O_add
-				 ? base : intel_state.base),
-				(e->X_op != O_add
-				 ? state_index : intel_state.index)))
+      if (!i386_intel_check (the_reg, base, state_index))
+	return 0;
+      if (e->X_op_symbol)
+	{
+	  newsym = i386_intel_simplify_symbol (e->X_op_symbol, in_equate);
+	  if (!newsym)
+	    return 0;
+	  e->X_op_symbol = newsym;
+	}
+      if (!i386_intel_check (the_reg,
+			     e->X_op != O_add ? base : intel_state.base,
+			     (e->X_op != O_add ? state_index
+					       : intel_state.index)))
 	return 0;
       break;
     }
@@ -654,7 +707,7 @@  i386_intel_operand (char *operand_string
   expr_mode = expr_operator_none;
   memset (&exp, 0, sizeof(exp));
   exp_seg = expression (&exp);
-  ret = i386_intel_simplify (&exp);
+  ret = i386_intel_simplify (&exp, false);
   intel_syntax = 1;
 
   SKIP_WHITESPACE ();
--- /dev/null
+++ b/gas/testsuite/gas/i386/equ2.d
@@ -0,0 +1,10 @@ 
+#source: equ.s
+#objdump: -t
+#name: i386 equates (symtab check)
+
+.*: +file format .*
+
+SYMBOL TABLE:
+.* \.text	.*
+!.* \*ABS\*	.*
+#pass
--- a/gas/testsuite/gas/i386/i386.exp
+++ b/gas/testsuite/gas/i386/i386.exp
@@ -726,6 +726,7 @@  if [gas_32_check] then {
 	run_dump_test "pcrel-elf"
 	run_dump_test "relax"
 	run_dump_test "gotpc"
+	run_dump_test "equ2"
 	run_dump_test "tlsd"
 	run_dump_test "tlspic"
 	run_dump_test "tlsnopic"