From: Jan Beulich Date: Mon, 20 Apr 2026 06:39:12 +0000 (+0200) Subject: x86/Intel: make PC-relative expressions work (again?) X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b0a3af6eb0a19eee3565877218f38ee31bfe7c55;p=thirdparty%2Fbinutils-gdb.git x86/Intel: make PC-relative expressions work (again?) 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. --- diff --git a/gas/config/tc-i386-intel.c b/gas/config/tc-i386-intel.c index e3c3613b808..09248e8f8f9 100644 --- a/gas/config/tc-i386-intel.c +++ b/gas/config/tc-i386-intel.c @@ -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); diff --git a/gas/testsuite/gas/i386/i386.exp b/gas/testsuite/gas/i386/i386.exp index 0c964225f89..80ae827e0a2 100644 --- a/gas/testsuite/gas/i386/i386.exp +++ b/gas/testsuite/gas/i386/i386.exp @@ -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 index 00000000000..81548a05222 --- /dev/null +++ b/gas/testsuite/gas/i386/intelpcrel.d @@ -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 index 00000000000..e5ca9f21a25 --- /dev/null +++ b/gas/testsuite/gas/i386/intelpcrel.s @@ -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]