]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
x86/Intel: don't modify equates' expressions
authorJan Beulich <jbeulich@suse.com>
Mon, 20 Apr 2026 06:38:35 +0000 (08:38 +0200)
committerJan Beulich <jbeulich@suse.com>
Mon, 20 Apr 2026 06:38:35 +0000 (08:38 +0200)
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.

gas/config/tc-i386-intel.c
gas/config/tc-i386.c
gas/testsuite/gas/i386/equ2.d [new file with mode: 0644]
gas/testsuite/gas/i386/i386.exp

index afa6bbf4d255b9c8d3b0a68196fb7c8eb327a005..e3c3613b8086b2942693cacc18f9a841b6423176 100644 (file)
@@ -378,30 +378,56 @@ i386_intel_simplify_register (expressionS *e)
   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);
+         newsym = i386_intel_simplify_symbol (e->X_add_symbol, in_equate);
+         if (newsym)
+           {
+             e->X_add_symbol = newsym;
 
-         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);
+             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, int got_a_float)
   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 ();
index 988b024f0b883399697f163f08c5951ae8b9788d..d3287513a7581d99a98dbef5fadd759667ceceec 100644 (file)
@@ -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 *);
+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);
@@ -13527,7 +13527,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
diff --git a/gas/testsuite/gas/i386/equ2.d b/gas/testsuite/gas/i386/equ2.d
new file mode 100644 (file)
index 0000000..8471def
--- /dev/null
@@ -0,0 +1,10 @@
+#source: equ.s
+#objdump: -t
+#name: i386 equates (symtab check)
+
+.*: +file format .*
+
+SYMBOL TABLE:
+.* \.text      .*
+!.* \*ABS\*    .*
+#pass
index fdf0e4ac0bea9c50355ca718ffc182256cfe87ed..0c964225f891da2dc3ab53c96bd7241482b17025 100644 (file)
@@ -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"