PR 34036 looping in symbol_equated_p chains

Message ID adA_eqVHgzURsaNW@squeak.grove.modra.org
State New
Headers
Series PR 34036 looping in symbol_equated_p chains |

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

Alan Modra April 3, 2026, 10:30 p.m. UTC
  This patch adds a new function for safely traversing a chain of equated
symbols to find the defining symbol.

	PR 34036
	* symbols.c (symbol_equated_to): New function.
	* symbols.h (symbol_equated_to): Declare.
	* expr.c (resolve_register): Use symbol_equated_to.
	* config/tc-i386.c (parse_register): Likewise.
	* config/tc-v850.c (reg_name_search): Likewise.
  

Patch

diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index edc44a37345..8d517146cfa 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -17062,19 +17062,13 @@  parse_register (const char *reg_string, char **end_op)
       char *save = input_line_pointer;
       char *buf = xstrdup (reg_string), *name;
       symbolS *symbolP;
+      offsetT off;
 
       input_line_pointer = buf;
       get_symbol_name (&name);
       symbolP = symbol_find (name);
-      while (symbolP && symbol_equated_p (symbolP))
-	{
-	  const expressionS *e = symbol_get_value_expression(symbolP);
-
-	  if (e->X_add_number)
-	    break;
-	  symbolP = e->X_add_symbol;
-	}
-      if (symbolP && S_GET_SEGMENT (symbolP) == reg_section)
+      symbolP = symbol_equated_to (symbolP, &off);
+      if (symbolP && off == 0 && S_GET_SEGMENT (symbolP) == reg_section)
 	{
 	  const expressionS *e = symbol_get_value_expression (symbolP);
 
diff --git a/gas/config/tc-v850.c b/gas/config/tc-v850.c
index 75df8a1ecd1..4373bd3cd2a 100644
--- a/gas/config/tc-v850.c
+++ b/gas/config/tc-v850.c
@@ -943,8 +943,13 @@  reg_name_search (const struct reg_name *regs,
       /* If the symbol is an alias for another name then use that.
 	 If the symbol is an alias for a number, then return the number.  */
       if (symbol_equated_p (symbolP))
-	name
-	  = S_GET_NAME (symbol_get_value_expression (symbolP)->X_add_symbol);
+	{
+	  offsetT off;
+	  symbolP = symbol_equated_to (symbolP, &off);
+	  if (symbolP == NULL || off != 0)
+	    return -1;
+	  name = S_GET_NAME (symbolP);
+	}
       else if (accept_numbers)
 	{
 	  int reg = S_GET_VALUE (symbolP);
diff --git a/gas/expr.c b/gas/expr.c
index 5b6828d391a..7108d7332c4 100644
--- a/gas/expr.c
+++ b/gas/expr.c
@@ -2473,22 +2473,19 @@  resolve_expression (expressionS *expressionP)
 void resolve_register (expressionS *expP)
 {
   symbolS *sym;
-  offsetT acc = 0;
-  const expressionS *e = expP;
+  offsetT acc;
+  const expressionS *e;
 
   if (expP->X_op != O_symbol)
     return;
 
-  do
-    {
-      if (!md_register_arithmetic && e->X_add_number)
-	break;
-      sym = e->X_add_symbol;
-      acc += e->X_add_number;
-      e = symbol_get_value_expression (sym);
-    }
-  while (symbol_equated_p (sym));
+  sym = symbol_equated_to (expP->X_add_symbol, &acc);
+  acc += expP->X_add_number;
+  if (sym == NULL
+      || (!md_register_arithmetic && acc != 0))
+    return;
 
+  e = symbol_get_value_expression (sym);
   if (e->X_op == O_register)
     {
       expr_copy (expP, e);
diff --git a/gas/symbols.c b/gas/symbols.c
index 5844439fd34..a0f8fcebeb8 100644
--- a/gas/symbols.c
+++ b/gas/symbols.c
@@ -3020,6 +3020,34 @@  symbol_equated_reloc_p (const symbolS *s)
 	      || S_IS_COMMON (s)));
 }
 
+/* Return the final symbol in a chain of equated symbols, and the offset
+   from that symbol.  If the chain has a loop, return NULL.
+   For a non-equated SYM, return SYM.  */
+
+symbolS *
+symbol_equated_to (symbolS *sym, offsetT *off)
+{
+  valueT add = 0;
+  symbolS *ret = sym;
+  while (ret && symbol_equated_p (ret))
+    {
+      const expressionS *e = symbol_get_value_expression (ret);
+      add += e->X_add_number;
+      ret->flags.resolving = 1;
+      ret = e->X_add_symbol;
+      if (ret->flags.resolving)
+	ret = NULL;
+    }
+  while (sym && sym->flags.resolving)
+    {
+      const expressionS *e = symbol_get_value_expression (sym);
+      sym->flags.resolving = 0;
+      sym = e->X_add_symbol;
+    }
+  *off = add;
+  return ret;
+}
+
 /* Return whether a symbol has a constant value.  */
 
 int
diff --git a/gas/symbols.h b/gas/symbols.h
index 382af5dfd24..6357237b7df 100644
--- a/gas/symbols.h
+++ b/gas/symbols.h
@@ -221,6 +221,7 @@  extern int symbol_resolving_p (const symbolS *);
 extern int symbol_section_p (const symbolS *);
 extern int symbol_equated_p (const symbolS *);
 extern int symbol_equated_reloc_p (const symbolS *);
+extern symbolS *symbol_equated_to (symbolS *, offsetT *);
 extern int symbol_constant_p (const symbolS *);
 extern int symbol_shadow_p (const symbolS *);
 extern symbolS *symbol_symbolS (symbolS *);