[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