[PATCH 2/2] x86: permit non-immediate offset operands with direct far branches
Jan Beulich
jbeulich@suse.com
Mon Oct 14 06:39:42 GMT 2024
While Intel syntax permits such already (as can be observed by there
not being a need to prefix the respective operand with "offset"), AT&T
syntax so far strictly insists on two immediate operands. Multiple
(successive) immediate operands are somewhat problematic anyway, as
it's never really clear what their order ought to be. While there's no
apparent way of dealing with this for ENTER, EXTRQ, and INSERTQ, for
LCALL and LJMP we can aid programmers by permitting alternative forms,
with the offset operand being a "displacement" rather than an
"immediate". The order of the two operands the doesn't matter; they're
distinguished by type.
Mark the new templates AT&T-only; the original ones really should have
been so, too. For backwards compatibility reasons we can't really
correct that mistake ...
---
While the proper Intel syntax operand form is sel:offset, for some
reason we also support two (comma separated) operands. The ambiguity
there is being left alone, as the sel:offset form is enough to avoid it.
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -7061,13 +7061,16 @@ i386_assemble (char *line)
swap_operands ();
/* The order of the immediates should be reversed for 2-immediates EXTRQ
- and INSERTQ instructions. Also UWRMSR wants its immediate to be in the
- "canonical" place (first), despite it appearing last (in AT&T syntax, or
- because of the swapping above) in the incoming set of operands. */
+ and INSERTQ instructions. Also direct far branches and UWRMSR want their
+ immediate to be in the "canonical" place (first), despite it (possibly)
+ appearing last (in AT&T syntax, or because of the swapping above) in the
+ incoming set of operands. */
if ((i.imm_operands == 2
&& (t->mnem_off == MN_extrq || t->mnem_off == MN_insertq))
- || (t->mnem_off == MN_uwrmsr && i.imm_operands
- && i.operands > i.imm_operands))
+ || (((t->opcode_modifier.jump == JUMP_INTERSEGMENT
+ && !operand_type_check (i.types[0], imm))
+ || t->mnem_off == MN_uwrmsr)
+ && i.imm_operands && i.operands > i.imm_operands))
swap_2_operands (0, 1);
if (i.imm_operands)
@@ -11621,6 +11624,7 @@ output_interseg_jump (void)
int size;
int prefix;
int code16;
+ const expressionS *exp1;
code16 = 0;
if (flag_code == CODE_16BIT)
@@ -11659,9 +11663,11 @@ output_interseg_jump (void)
*p++ = i.prefix[REX_PREFIX];
*p++ = i.tm.base_opcode;
- if (i.op[1].imms->X_op == O_constant)
+ exp1 = operand_type_check (i.types[0], imm) ? i.op[1].imms
+ : i.op[1].disps;
+ if (exp1->X_op == O_constant)
{
- offsetT n = i.op[1].imms->X_add_number;
+ offsetT n = exp1->X_add_number;
if (size == 2
&& !fits_in_unsigned_word (n)
@@ -11674,7 +11680,7 @@ output_interseg_jump (void)
}
else
fix_new_exp (frag_now, p - frag_now->fr_literal, size,
- i.op[1].imms, 0, reloc (size, 0, 0, i.reloc[1]));
+ exp1, 0, reloc (size, 0, 0, i.reloc[1]));
p += size;
if (i.op[0].imms->X_op == O_constant)
--- a/gas/testsuite/gas/i386/jump.d
+++ b/gas/testsuite/gas/i386/jump.d
@@ -15,28 +15,32 @@ Disassembly of section .text:
[ ]*[a-f0-9]+: 66 ff 2c bd 00 00 00 00 ljmpw \*0x0\(,%edi,4\) 1c: (R_386_)?(dir)?32 xxx
[ ]*[a-f0-9]+: ff 2d 00 00 00 00 ljmp \*0x0 22: (R_386_)?(dir)?32 xxx
[ ]*[a-f0-9]+: 66 ff 2d 00 00 00 00 ljmpw \*0x0 29: (R_386_)?(dir)?32 xxx
-[ ]*[a-f0-9]+: ea 00 00 00 00 34 12 ljmp \$0x1234,\$0x0 2e: (R_386_)?(dir)?32 xxx
-[ ]*[a-f0-9]+: e8 c7 ff ff ff call (0x0|0 <.text>)
-[ ]*[a-f0-9]+: e8 ((fc|c2) ff ff ff|00 00 00 00) call (0x)?(0|3a|3e)( <.text(\+0x3e)?>)? 3a: (R_386_PC)?(DISP)?32 xxx
-[ ]*[a-f0-9]+: ff 15 00 00 00 00 call \*0x0 40: (R_386_)?(dir)?32 xxx
+[ ]*[a-f0-9]+: ea 00 00 00 00 34 12 ljmp \$0x1234,\$0x0[ ]+[a-f0-9]+: (R_386_|dir)?32 xxx
+[ ]*[a-f0-9]+: ea 00 00 00 00 34 12 ljmp \$0x1234,\$0x0[ ]+[a-f0-9]+: (R_386_|dir)?32 xxx
+[ ]*[a-f0-9]+: ea 00 00 00 00 34 12 ljmp \$0x1234,\$0x0[ ]+[a-f0-9]+: (R_386_|dir)?32 xxx
+[ ]*[a-f0-9]+: e8 b9 ff ff ff call (0x0|0 <.text>)
+[ ]*[a-f0-9]+: e8 ((fc|b4) ff ff ff|00 00 00 00) call (0x)?(0|48|4c)( <.text(\+0x4c)?>)?[ ]+[a-f0-9]+: (R_386_PC|DISP)32 xxx
+[ ]*[a-f0-9]+: ff 15 00 00 00 00 call \*0x0[ ]+[a-f0-9]+: (R_386_|dir)?32 xxx
[ ]*[a-f0-9]+: ff d7 call \*%edi
[ ]*[a-f0-9]+: ff 17 call \*\(%edi\)
-[ ]*[a-f0-9]+: ff 1c bd 00 00 00 00 lcall \*0x0\(,%edi,4\) 4b: (R_386_)?(dir)?32 xxx
-[ ]*[a-f0-9]+: 66 ff 1c bd 00 00 00 00 lcallw \*0x0\(,%edi,4\) 53: (R_386_)?(dir)?32 xxx
-[ ]*[a-f0-9]+: ff 1d 00 00 00 00 lcall \*0x0 59: (R_386_)?(dir)?32 xxx
-[ ]*[a-f0-9]+: 66 ff 1d 00 00 00 00 lcallw \*0x0 60: (R_386_)?(dir)?32 xxx
-[ ]*[a-f0-9]+: 9a 00 00 00 00 34 12 lcall \$0x1234,\$0x0 65: (R_386_)?(dir)?32 xxx
+[ ]*[a-f0-9]+: ff 1c bd 00 00 00 00 lcall \*0x0\(,%edi,4\)[ ]+[a-f0-9]+: (R_386_|dir)?32 xxx
+[ ]*[a-f0-9]+: 66 ff 1c bd 00 00 00 00 lcallw \*0x0\(,%edi,4\)[ ]+[a-f0-9]+: (R_386_|dir)?32 xxx
+[ ]*[a-f0-9]+: ff 1d 00 00 00 00 lcall \*0x0[ ]+[a-f0-9]+: (R_386_|dir)?32 xxx
+[ ]*[a-f0-9]+: 66 ff 1d 00 00 00 00 lcallw \*0x0[ ]+[a-f0-9]+: (R_386_|dir)?32 xxx
+[ ]*[a-f0-9]+: 9a 00 00 00 00 34 12 lcall \$0x1234,\$0x0[ ]+[a-f0-9]+: (R_386_|dir)?32 xxx
+[ ]*[a-f0-9]+: 9a 00 00 00 00 34 12 lcall \$0x1234,\$0x0[ ]+[a-f0-9]+: (R_386_|dir)?32 xxx
+[ ]*[a-f0-9]+: 9a 00 00 00 00 34 12 lcall \$0x1234,\$0x0[ ]+[a-f0-9]+: (R_386_|dir)?32 xxx
[ ]*[a-f0-9]+: 66 ff 13 callw \*\(%ebx\)
[ ]*[a-f0-9]+: ff 13 call \*\(%ebx\)
[ ]*[a-f0-9]+: ff 1b lcall \*\(%ebx\)
[ ]*[a-f0-9]+: 66 ff 23 jmpw \*\(%ebx\)
[ ]*[a-f0-9]+: ff 23 jmp \*\(%ebx\)
[ ]*[a-f0-9]+: ff 2b ljmp \*\(%ebx\)
-[ ]*[a-f0-9]+: eb 00 jmp (0x)?7b( <.text(\+0x7b)?>)?
+[ ]*[a-f0-9]+: eb 00 jmp (0x)?97( <.text(\+0x97)?>)?
[ ]*[a-f0-9]+: 90 nop
-[ ]*[a-f0-9]+: e3 00 jecxz (0x)?7e( <.text(\+0x7e)?>)?
+[ ]*[a-f0-9]+: e3 00 jecxz (0x)?9a( <.text(\+0x9a)?>)?
[ ]*[a-f0-9]+: 90 nop
-[ ]*[a-f0-9]+: eb 00 jmp (0x)?81( <.text(\+0x81)?>)?
+[ ]*[a-f0-9]+: eb 00 jmp (0x)?9d( <.text(\+0x9d)?>)?
[ ]*[a-f0-9]+: 90 nop
[ ]*[a-f0-9]+: 9a 90 90 90 90 90 90 lcall \$0x9090,\$0x90909090
[ ]*[a-f0-9]+: 9a 90 90 90 90 90 90 lcall \$0x9090,\$0x90909090
--- a/gas/testsuite/gas/i386/jump.s
+++ b/gas/testsuite/gas/i386/jump.s
@@ -13,6 +13,8 @@
ljmp *xxx
ljmpw *xxx
ljmp $0x1234,$xxx
+ ljmp $0x1234,xxx
+ ljmp xxx,$0x1234
call 1b
call xxx
@@ -24,6 +26,8 @@
lcall *xxx
lcallw *xxx
lcall $0x1234,$xxx
+ lcall $0x1234,xxx
+ lcall xxx,$0x1234
.intel_syntax noprefix
call word ptr [ebx]
--- a/opcodes/i386-opc.tbl
+++ b/opcodes/i386-opc.tbl
@@ -494,6 +494,7 @@ call, 0x9a, No64, JumpInterSegment|Impli
call, 0xff/3, 0, Amd64|Modrm|JumpAbsolute|ImplicitStackOp|DefaultSize|NoSuf, { Dword|Fword|BaseIndex }
call, 0xff/3, x64, Intel64|Modrm|JumpAbsolute|ImplicitStackOp|NoSuf, { Dword|Fword|Tbyte|BaseIndex }
lcall, 0x9a, No64, JumpInterSegment|DefaultSize|No_bSuf|No_sSuf|No_qSuf, { Imm16, Imm16|Imm32 }
+lcall, 0x9a, No64, JumpInterSegment|DefaultSize|No_bSuf|No_sSuf|No_qSuf|ATTSyntax, { Imm16, Disp16|Disp32 }
lcall, 0xff/3, 0, Amd64|Modrm|JumpAbsolute|DefaultSize|No_bSuf|No_sSuf|No_qSuf, { Unspecified|BaseIndex }
lcall, 0xff/3, x64, Intel64|Modrm|JumpAbsolute|No_bSuf|No_sSuf, { Unspecified|BaseIndex }
@@ -507,6 +508,7 @@ jmp, 0xea, No64, JumpInterSegment|No_bSu
jmp, 0xff/5, 0, Amd64|Modrm|JumpAbsolute|NoSuf, { Dword|Fword|BaseIndex }
jmp, 0xff/5, x64, Intel64|Modrm|JumpAbsolute|NoSuf, { Dword|Fword|Tbyte|BaseIndex }
ljmp, 0xea, No64, JumpInterSegment|No_bSuf|No_sSuf|No_qSuf, { Imm16, Imm16|Imm32 }
+ljmp, 0xea, No64, JumpInterSegment|No_bSuf|No_sSuf|No_qSuf|ATTSyntax, { Imm16, Disp16|Disp32 }
ljmp, 0xff/5, 0, Amd64|Modrm|JumpAbsolute|No_bSuf|No_sSuf|No_qSuf, { Unspecified|BaseIndex }
ljmp, 0xff/5, x64, Intel64|Modrm|JumpAbsolute|No_bSuf|No_sSuf, { Unspecified|BaseIndex }
More information about the Binutils
mailing list