[binutils-gdb] PR 34036 looping in symbol_equated_p chains

Alan Modra via Binutils-cvs <[email protected]>
Newsgroups gmane.comp.gnu.binutils.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=ea2b9ecdc80fade6db5046224b821390cfac06b5

commit ea2b9ecdc80fade6db5046224b821390cfac06b5
Author: Alan Modra <[email protected]>
Date:   Sat Apr 4 08:47:04 2026 +1030

    PR 34036 looping in symbol_equated_p chains
    
    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.

Diff:
---
 gas/config/tc-i386.c | 12 +++---------
 gas/config/tc-v850.c |  9 +++++++--
 gas/expr.c           | 19 ++++++++-----------
 gas/symbols.c        | 28 ++++++++++++++++++++++++++++
 gas/symbols.h        |  1 +
 5 files changed, 47 insertions(+), 22 deletions(-)

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 *);
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.