[PATCH v2] x86/Intel: avoid infinite recursion in i386_intel_simplify_symbol() (again)

Alan Modra amodra@gmail.com
Tue May 19 23:44:23 GMT 2026


I poked at this problem a little yesterday, and came up with the
following patch that passes for all the testcases I threw at it.

===
Commit 22f8905d9f38 reintroduced pr30308.  This fix resolves equates
safely in the presence of symbol loops by using symbol_equated_to.
Symbols aren't prematurely modified by copying their value
expressions before i386_intel_simplify does its work.  I figure that
it is safer to do this for all symbols rather than just the particular
case of equates, so the in_equate parameter can disappear.

diff --git a/gas/config/tc-i386-intel.c b/gas/config/tc-i386-intel.c
index 09248e8f8f9..dca33d3262a 100644
--- a/gas/config/tc-i386-intel.c
+++ b/gas/config/tc-i386-intel.c
@@ -381,49 +381,38 @@ i386_intel_simplify_register (expressionS *e)
 }
 
 static symbolS *
-i386_intel_simplify_symbol (symbolS *sym, bool in_equate)
+i386_intel_simplify_symbol (symbolS *sym)
 {
-  if (symbol_resolving_p (sym))
-    return sym;
+  symbolS *orig = sym;
+  offsetT off;
+  sym = symbol_equated_to (sym, &off);
+  if (sym == NULL || off != 0)
+    return orig;
 
   segT seg = S_GET_SEGMENT (sym);
-  if (seg != expr_section && seg != reg_section && !symbol_equated_p(sym))
+  if (seg == undefined_section
+      || (seg != expr_section && seg != reg_section && sym == orig))
     return sym;
 
-  for (;;)
-    {
-      /* 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);
+  /* i386_intel_simplify modifies its arg.  We don't want to make
+     premature changes to symbols here, particularly for a symbol
+     equate.  Changing a symbol may affect future uses of that
+     symbol.  So copy the symbol value and make a new symbol after
+     i386_intel_simplify has done its work.  */
+  expressionS *e = symbol_get_value_expression (sym);
+  expressionS exp;
+  memcpy (&exp, e, sizeof exp);
+  int ret = i386_intel_simplify (&exp);
+  if (ret == 0)
+    return NULL;
 
-  return ret ? sym : NULL;
+  if (memcmp (&exp, e, sizeof exp))
+    sym = make_expr_symbol (&exp);
+  return sym;
 }
 
 static int
-i386_intel_simplify (expressionS *e, bool in_equate)
+i386_intel_simplify (expressionS *e)
 {
   const reg_entry *the_reg = (this_operand >= 0
 			      ? i.op[this_operand].regs : NULL);
@@ -440,7 +429,7 @@ i386_intel_simplify (expressionS *e, bool in_equate)
     case O_index:
       if (e->X_add_symbol)
 	{
-	  newsym = i386_intel_simplify_symbol (e->X_add_symbol, in_equate);
+	  newsym = i386_intel_simplify_symbol (e->X_add_symbol);
 	  if (!newsym
 	      || !i386_intel_check(the_reg, intel_state.base,
 				   intel_state.index))
@@ -449,7 +438,7 @@ i386_intel_simplify (expressionS *e, bool in_equate)
 	}
       if (!intel_state.in_offset)
 	++intel_state.in_bracket;
-      newsym = i386_intel_simplify_symbol (e->X_op_symbol, in_equate);
+      newsym = i386_intel_simplify_symbol (e->X_op_symbol);
       if (!intel_state.in_offset)
 	--intel_state.in_bracket;
       if (!newsym)
@@ -476,7 +465,7 @@ i386_intel_simplify (expressionS *e, bool in_equate)
     case O_offset:
       intel_state.has_offset = 1;
       ++intel_state.in_offset;
-      newsym = i386_intel_simplify_symbol (e->X_add_symbol, in_equate);
+      newsym = i386_intel_simplify_symbol (e->X_add_symbol);
       --intel_state.in_offset;
       if (!newsym || !i386_intel_check(the_reg, base, state_index))
 	return 0;
@@ -505,7 +494,7 @@ i386_intel_simplify (expressionS *e, bool in_equate)
 	  as_bad (_("invalid use of register"));
 	  return 0;
 	}
-      newsym = i386_intel_simplify_symbol (e->X_add_symbol, in_equate);
+      newsym = i386_intel_simplify_symbol (e->X_add_symbol);
       if (!newsym)
 	return 0;
       e->X_add_symbol = newsym;
@@ -519,7 +508,7 @@ i386_intel_simplify (expressionS *e, bool in_equate)
 	  as_bad (_("invalid use of register"));
 	  return 0;
 	}
-      newsym = i386_intel_simplify_symbol (e->X_op_symbol, in_equate);
+      newsym = i386_intel_simplify_symbol (e->X_op_symbol);
       if (!newsym
 	  || !i386_intel_check(the_reg, intel_state.base,
 			       intel_state.index))
@@ -548,7 +537,7 @@ i386_intel_simplify (expressionS *e, bool in_equate)
 	  expressionS *left = NULL, *right = NULL;
 	  segT leftseg = NULL, rightseg = NULL;
 
-	  newsym = i386_intel_simplify_symbol (e->X_add_symbol, in_equate);
+	  newsym = i386_intel_simplify_symbol (e->X_add_symbol);
 	  if (newsym)
 	    {
 	      e->X_add_symbol = newsym;
@@ -563,7 +552,7 @@ i386_intel_simplify (expressionS *e, bool in_equate)
 		}
 	    }
 
-	  newsym = i386_intel_simplify_symbol (e->X_op_symbol, in_equate);
+	  newsym = i386_intel_simplify_symbol (e->X_op_symbol);
 	  if (newsym)
 	    {
 	      e->X_op_symbol = newsym;
@@ -609,7 +598,7 @@ i386_intel_simplify (expressionS *e, bool in_equate)
 	  if (!intel_state.in_scale++)
 	    intel_state.scale_factor = 1;
 
-	  newsym = i386_intel_simplify_symbol (e->X_add_symbol, in_equate);
+	  newsym = i386_intel_simplify_symbol (e->X_add_symbol);
 	  if (newsym)
 	    {
 	      e->X_add_symbol = newsym;
@@ -620,7 +609,7 @@ i386_intel_simplify (expressionS *e, bool in_equate)
 		  other = symbol_get_value_expression (e->X_add_symbol);
 		}
 
-	      newsym = i386_intel_simplify_symbol (e->X_op_symbol, in_equate);
+	      newsym = i386_intel_simplify_symbol (e->X_op_symbol);
 	    }
 
 	  if (newsym)
@@ -705,7 +694,7 @@ i386_intel_simplify (expressionS *e, bool in_equate)
     fallthrough:
       if (e->X_add_symbol)
 	{
-	  newsym = i386_intel_simplify_symbol (e->X_add_symbol, in_equate);
+	  newsym = i386_intel_simplify_symbol (e->X_add_symbol);
 	  if (!newsym)
 	    return 0;
 	  e->X_add_symbol = newsym;
@@ -722,7 +711,7 @@ i386_intel_simplify (expressionS *e, bool in_equate)
 	return 0;
       if (e->X_op_symbol)
 	{
-	  newsym = i386_intel_simplify_symbol (e->X_op_symbol, in_equate);
+	  newsym = i386_intel_simplify_symbol (e->X_op_symbol);
 	  if (!newsym)
 	    return 0;
 	  e->X_op_symbol = newsym;
@@ -798,7 +787,7 @@ i386_intel_operand (char *operand_string, int got_a_float)
   expr_mode = expr_operator_none;
   memset (&exp, 0, sizeof(exp));
   exp_seg = expression (&exp);
-  ret = i386_intel_simplify (&exp, false);
+  ret = i386_intel_simplify (&exp);
   intel_syntax = 1;
 
   SKIP_WHITESPACE ();
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index d3287513a75..988b024f0b8 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -167,7 +167,7 @@ static int i386_finalize_displacement (segT, expressionS *, i386_operand_type,
 				       const char *);
 static int i386_att_operand (char *);
 static int i386_intel_operand (char *, int);
-static int i386_intel_simplify (expressionS *, bool);
+static int i386_intel_simplify (expressionS *);
 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);
@@ -13527,7 +13527,7 @@ x86_cons (expressionS *exp, int size)
   intel_syntax = -intel_syntax;
 
   if (intel_syntax)
-    i386_intel_simplify (exp, false);
+    i386_intel_simplify (exp);
 
   /* If not 64bit, massage value, to account for wraparound when !BFD64.  */
   if (size <= 4 && expr_mode == expr_operator_present

-- 
Alan Modra


More information about the Binutils mailing list