]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
x86/Intel: make PC-relative expressions work (again?)
authorJan Beulich <jbeulich@suse.com>
Mon, 20 Apr 2026 06:39:12 +0000 (08:39 +0200)
committerJan Beulich <jbeulich@suse.com>
Mon, 20 Apr 2026 06:39:12 +0000 (08:39 +0200)
Associating fixups with too complex expressions will prevent the detection
and conversion of expressions which are actually PC-relative. Such a
situation can arise when converting O_index expressions: An extra O_add
(with a constant) or O_symbol is already "too complex", let alone an
O_multiply by zero.

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

index e3c3613b8086b2942693cacc18f9a841b6423176..09248e8f8f90c52f62293f59772857bc496c7f00 100644 (file)
@@ -279,7 +279,9 @@ static INLINE int i386_intel_check (const reg_entry *rreg,
 static INLINE void i386_intel_fold (expressionS *e, symbolS *sym)
 {
   expressionS *exp = symbol_get_value_expression (sym);
-  if (S_GET_SEGMENT (sym) == absolute_section)
+
+  if (S_GET_SEGMENT (sym) == absolute_section
+      || S_GET_SEGMENT (sym) == expr_section)
     {
       offsetT val = e->X_add_number;
 
@@ -453,10 +455,22 @@ i386_intel_simplify (expressionS *e, bool in_equate)
       if (!newsym)
        return 0;
       e->X_op_symbol = newsym;
-      if (e->X_add_symbol)
-       e->X_op = O_add;
-      else
+      if (!e->X_add_symbol)
        i386_intel_fold (e, e->X_op_symbol);
+      else if (S_GET_SEGMENT (e->X_add_symbol) == expr_section
+              && (S_GET_SEGMENT (e->X_op_symbol) == absolute_section
+                  || S_GET_SEGMENT (e->X_op_symbol) == expr_section)
+              && symbol_get_value_expression (e->X_op_symbol)->X_op
+                 == O_constant)
+       {
+         offsetT val
+           = symbol_get_value_expression (e->X_op_symbol)->X_add_number;
+
+         i386_intel_fold (e, e->X_add_symbol);
+         e->X_add_number += val;
+       }
+      else
+       e->X_op = O_add;
       break;
 
     case O_offset:
@@ -528,10 +542,68 @@ i386_intel_simplify (expressionS *e, bool in_equate)
       i386_intel_fold (e, e->X_op_symbol);
       break;
 
+    case O_add:
+      if (this_operand >= 0 && intel_state.in_bracket)
+       {
+         expressionS *left = NULL, *right = NULL;
+         segT leftseg = NULL, rightseg = NULL;
+
+         newsym = i386_intel_simplify_symbol (e->X_add_symbol, in_equate);
+         if (newsym)
+           {
+             e->X_add_symbol = newsym;
+
+             if (base != intel_state.base || state_index != intel_state.index)
+               {
+                 base = intel_state.base;
+                 state_index = intel_state.index;
+                 left = symbol_get_value_expression (newsym);
+                 resolve_expression (left);
+                 leftseg = S_GET_SEGMENT (newsym);
+               }
+           }
+
+         newsym = i386_intel_simplify_symbol (e->X_op_symbol, in_equate);
+         if (newsym)
+           {
+             e->X_op_symbol = newsym;
+
+             if (base != intel_state.base || state_index != intel_state.index)
+               {
+                 base = intel_state.base;
+                 state_index = intel_state.index;
+                 right = symbol_get_value_expression (newsym);
+                 resolve_expression (right);
+                 rightseg = S_GET_SEGMENT (newsym);
+               }
+           }
+
+         if (left && right
+             && (leftseg == absolute_section || leftseg == expr_section)
+             && left->X_op == O_constant
+             && (rightseg == absolute_section || rightseg == expr_section)
+             && right->X_op == O_constant)
+           {
+              e->X_op = O_constant;
+              e->X_add_number += left->X_add_number + right->X_add_number;
+              e->X_add_symbol = NULL;
+              e->X_op_symbol = NULL;
+           }
+         else if (left
+                  && (leftseg == absolute_section || leftseg == expr_section)
+                  && left->X_op == O_constant)
+           i386_intel_fold (e, e->X_op_symbol);
+         else if (right
+                  && (rightseg == absolute_section || rightseg == expr_section)
+                  && right->X_op == O_constant)
+           i386_intel_fold (e, e->X_add_symbol);
+       }
+      goto fallthrough;
+
     case O_multiply:
       if (this_operand >= 0 && intel_state.in_bracket)
        {
-         expressionS *scale = NULL;
+         expressionS *scale = NULL, *other = NULL;
          int has_index = (intel_state.index != NULL);
 
          if (!intel_state.in_scale++)
@@ -543,7 +615,10 @@ i386_intel_simplify (expressionS *e, bool in_equate)
              e->X_add_symbol = newsym;
 
              if (!has_index && intel_state.index)
-               scale = symbol_get_value_expression (e->X_op_symbol);
+               {
+                 scale = symbol_get_value_expression (e->X_op_symbol);
+                 other = symbol_get_value_expression (e->X_add_symbol);
+               }
 
              newsym = i386_intel_simplify_symbol (e->X_op_symbol, in_equate);
            }
@@ -553,16 +628,32 @@ i386_intel_simplify (expressionS *e, bool in_equate)
              e->X_op_symbol = newsym;
 
              if (!scale && !has_index && intel_state.index)
-               scale = symbol_get_value_expression (e->X_add_symbol);
+               {
+                 scale = symbol_get_value_expression (e->X_add_symbol);
+                 other = symbol_get_value_expression (e->X_op_symbol);
+               }
            }
 
          if (newsym && scale)
            {
+             segT seg;
+
              resolve_expression (scale);
              if (scale->X_op != O_constant
                  || intel_state.index->reg_type.bitfield.word)
                scale->X_add_number = 0;
              intel_state.scale_factor *= scale->X_add_number;
+
+             resolve_expression (other);
+             seg = S_GET_SEGMENT (newsym);
+             if ((seg == absolute_section || seg == expr_section)
+                 && other->X_op == O_constant
+                 && other->X_add_number == 0)
+               {
+                 e->X_op = O_constant;
+                 e->X_add_symbol = NULL;
+                 e->X_op_symbol = NULL;
+               }
            }
 
          --intel_state.in_scale;
@@ -646,7 +737,7 @@ i386_intel_simplify (expressionS *e, bool in_equate)
 
   if (this_operand >= 0
       && e->X_op == O_symbol
-      && !intel_state.in_offset)
+      && !intel_state.has_offset)
     {
       segT seg = S_GET_SEGMENT (e->X_add_symbol);
 
index 0c964225f891da2dc3ab53c96bd7241482b17025..80ae827e0a29ecb9c50823511bda0cb22f8cda52 100644 (file)
@@ -67,6 +67,7 @@ if [gas_32_check] then {
     run_list_test "intelbad" ""
     run_dump_test "intelok"
     run_dump_test "intelok2"
+    run_dump_test "intelpcrel"
     run_dump_test "prefix"
     run_list_test "prefix32" "-al -march=+mpx"
     run_dump_test "insn-32"
diff --git a/gas/testsuite/gas/i386/intelpcrel.d b/gas/testsuite/gas/i386/intelpcrel.d
new file mode 100644 (file)
index 0000000..81548a0
--- /dev/null
@@ -0,0 +1,33 @@
+#objdump: -dwMintel
+#name: i386 intel-PC-rel
+#notarget: *-*-msdos* *-*-*go32* *-*-bsd* *-*-darwin*
+
+.*: +file format .*
+
+Disassembly of section .text:
+
+0+ <\.text>:
+[      ]*[0-9a-f]+:    b8 0[15] 00 00 00[      ]+mov[  ]+eax,(0x)?[15]
+[      ]*[0-9a-f]+:    b8 0[ae] 00 00 00[      ]+mov[  ]+eax,0x[ae]
+[      ]*[0-9a-f]+:    8d 91 (0c|10) 00 00 00[         ]+lea[  ]+edx,\[ecx\+0x(c|10)\]
+[      ]*[0-9a-f]+:    8d 91 1[6a] 00 00 00[   ]+lea[  ]+edx,\[ecx\+0x1[6a]\]
+[      ]*[0-9a-f]+:    8d 91 (1c|20) 00 00 00[         ]+lea[  ]+edx,\[ecx\+0x(1c|20)\]
+[      ]*[0-9a-f]+:    8d 14 8d (1f|23) 00 00 00[      ]+lea[  ]+edx,\[ecx\*4\+0x(1f|23)\]
+[      ]*[0-9a-f]+:    8d 14 8d 2[6a] 00 00 00[        ]+lea[  ]+edx,\[ecx\*4\+0x2[6a]\]
+[      ]*[0-9a-f]+:    8d 14 8d (2d|31) 00 00 00[      ]+lea[  ]+edx,\[ecx\*4\+0x(2d|31)\]
+[      ]*[0-9a-f]+:    8d 14 8d 3[48] 00 00 00[        ]+lea[  ]+edx,\[ecx\*4\+0x3[48]\]
+[      ]*[0-9a-f]+:    8d 14 8d 3[bf] 00 00 00[        ]+lea[  ]+edx,\[ecx\*4\+0x3[bf]\]
+[      ]*[0-9a-f]+:    8d 91 4[15] 00 00 00[   ]+lea[  ]+edx,\[ecx\+0x4[15]\]
+[      ]*[0-9a-f]+:    8d 91 4[7b] 00 00 00[   ]+lea[  ]+edx,\[ecx\+0x4[7b]\]
+[      ]*[0-9a-f]+:    8d 91 (4d|51) 00 00 00[         ]+lea[  ]+edx,\[ecx\+0x(4d|51)\]
+[      ]*[0-9a-f]+:    8d 91 5[37] 00 00 00[   ]+lea[  ]+edx,\[ecx\+0x5[37]\]
+[      ]*[0-9a-f]+:    8d 91 5[9d] 00 00 00[   ]+lea[  ]+edx,\[ecx\+0x5[9d]\]
+[      ]*[0-9a-f]+:    8d 14 8d 6[04] 00 00 00[        ]+lea[  ]+edx,\[ecx\*4\+0x6[04]\]
+[      ]*[0-9a-f]+:    8d 14 8d 6[7b] 00 00 00[        ]+lea[  ]+edx,\[ecx\*4\+0x6[7b]\]
+[      ]*[0-9a-f]+:    8d 14 8d (6e|72) 00 00 00[      ]+lea[  ]+edx,\[ecx\*4\+0x(6e|72)\]
+[      ]*[0-9a-f]+:    8d 14 8d 7[59] 00 00 00[        ]+lea[  ]+edx,\[ecx\*4\+0x7[59]\]
+[      ]*[0-9a-f]+:    8d 14 8d (7c|80) 00 00 00[      ]+lea[  ]+edx,\[ecx\*4\+0x(7c|80)\]
+[      ]*[0-9a-f]+:    8d 94 31 8[37] 00 00 00[        ]+lea[  ]+edx,\[ecx\+esi\*1\+0x8[37]\]
+[      ]*[0-9a-f]+:    8d 94 b1 8[ae] 00 00 00[        ]+lea[  ]+edx,\[ecx\+esi\*4\+0x8[ae]\]
+[      ]*[0-9a-f]+:    8d 94 b1 9[59] 00 00 00[        ]+lea[  ]+edx,\[ecx\+esi\*4\+0x9[59]\]
+#pass
diff --git a/gas/testsuite/gas/i386/intelpcrel.s b/gas/testsuite/gas/i386/intelpcrel.s
new file mode 100644 (file)
index 0000000..e5ca9f2
--- /dev/null
@@ -0,0 +1,36 @@
+       .intel_syntax noprefix
+
+       .data
+0:     .long 0
+1:     .long 0
+
+       .text
+.Lorg:
+       mov     eax, 0b - .Lorg
+       mov     eax, 1b - .Lorg
+
+       lea     edx, 0b - .Lorg[ecx]
+       lea     edx, 1b - .Lorg[ecx]
+       lea     edx, 0b - .Lorg[ecx][4]
+
+       lea     edx, 0b - .Lorg[ecx*4]
+       lea     edx, 0b - .Lorg[4*ecx]
+       lea     edx, 0b - .Lorg[2*2*ecx]
+       lea     edx, 0b - .Lorg[2*ecx*2]
+       lea     edx, 0b - .Lorg[ecx*2*2]
+
+       lea     edx, [(0b - .Lorg) + ecx]
+       lea     edx, [0b - .Lorg + ecx]
+       lea     edx, [ecx + (0b - .Lorg)]
+       lea     edx, [ecx + 0b - .Lorg]
+       lea     edx, [0b + ecx - .Lorg]
+
+       lea     edx, [(0b - .Lorg) + ecx*4]
+       lea     edx, [0b - .Lorg + ecx*4]
+       lea     edx, [ecx*4 + (0b - .Lorg)]
+       lea     edx, [ecx*4 + 0b - .Lorg]
+       lea     edx, [0b + ecx*4 - .Lorg]
+
+       lea     edx, 0b - .Lorg[ecx][esi]
+       lea     edx, 0b - .Lorg[ecx][esi*4]
+       lea     edx, 0b - .Lorg[ecx][esi*4][4]