This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: GAS i386 jmp generator .arch compliance


On Mon, 12 Feb 2001, Jan Kratochvil wrote:

> BTW is there any idea how to turn on/off automatic skip-over generator vs.
> warning message only?

I thought you weren't interested in fixing the branch problem (in the way 
I suggested), so went ahead and implemented it myself.  Anyway, it turned
out not quite so trivial, as I'd forgotten the necessity of changing the
relax table.

gas/ChangeLog
	* doc/c-i386.texi (i386-Arch): Add "jumps"/"nojumps" blurb.
	Mention effect of < 386 architectures on jump promotion.
	(i386-Jumps): xref above.  Don't assume long disp is 32 bits.

	* config/tc-i386.c (no_jump_promotion): New.
	(set_cpu_arch): Parse "jumps" arch modifier.
	(insn_size): Modify usage comment.
	(ENCODE_RELAX_STATE): Reformat and protect macro arg.
	(SIZE_FROM_RELAX_STATE): Rename to DISP_SIZE_FROM_RELAX_STATE.
	(TYPE_FROM_RELAX_STATE): New define.
	(UNCOND_JUMP, COND_JUMP): Renumber.
	(md_relax_table): Reorder to suit.
	(COND_JUMP86): New define.
	(md_relax_table): Handle COND_JUMP86 cases. Add a few comments.
	(md_assemble): Create frag var for jumps of max size, encode relax
	state for COND_JUMP86.
	(md_estimate_size_before_relax): Handle COND_JUMP86 cases, and
	leave jumps small if no_jump_promotion.
	(md_convert_frag): Likewise.

This hasn't been tested particularly well yet (but it does pass
"make check"), so I'll leave installing it until tomorrow.  I don't think
it should go on the 2.11 branch.

Alan Modra
-- 
Linuxcare.  Support for the Revolution.

Index: gas/config/tc-i386.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-i386.c,v
retrieving revision 1.83
diff -c -p -r1.83 tc-i386.c
*** tc-i386.c	2001/01/17 23:41:35	1.83
--- tc-i386.c	2001/02/12 12:01:13
*************** static const char *cpu_arch_name = NULL;
*** 273,287 ****
  /* CPU feature flags.  */
  static unsigned int cpu_arch_flags = CpuUnknownFlags|CpuNo64;
  
  /* Interface to relax_segment.
!    There are 2 relax states for 386 jump insns: one for conditional &
!    one for unconditional jumps.  This is because these two types of
!    jumps add different sizes to frags when we're figuring out what
!    sort of jump to choose to reach a given label.  */
  
  /* Types.  */
! #define COND_JUMP 1
! #define UNCOND_JUMP 2
  /* Sizes.  */
  #define CODE16	1
  #define SMALL	0
--- 273,292 ----
  /* CPU feature flags.  */
  static unsigned int cpu_arch_flags = CpuUnknownFlags|CpuNo64;
  
+ /* If set, jumps are not automatically promoted to handle larger than
+    a byte offset.  */
+ static unsigned int no_jump_promotion = 0;
+ 
  /* Interface to relax_segment.
!    There are 3 major relax states for 386 jump insns because the
!    different types of jumps add different sizes to frags when we're
!    figuring out what sort of jump to choose to reach a given label.  */
  
  /* Types.  */
! #define UNCOND_JUMP 1
! #define COND_JUMP 2
! #define COND_JUMP86 3
! 
  /* Sizes.  */
  #define CODE16	1
  #define SMALL	0
*************** static unsigned int cpu_arch_flags = Cpu
*** 297,306 ****
  #endif
  #endif
  
! #define ENCODE_RELAX_STATE(type,size) \
!   ((relax_substateT) ((type<<2) | (size)))
! #define SIZE_FROM_RELAX_STATE(s) \
!     ( (((s) & 0x3) == BIG ? 4 : (((s) & 0x3) == BIG16 ? 2 : 1)) )
  
  /* This table is used by relax_frag to promote short jumps to long
     ones where necessary.  SMALL (short) jumps may be promoted to BIG
--- 302,313 ----
  #endif
  #endif
  
! #define ENCODE_RELAX_STATE(type, size) \
!   ((relax_substateT) (((type) << 2) | (size)))
! #define TYPE_FROM_RELAX_STATE(s) \
!   ((s) >> 2)
! #define DISP_SIZE_FROM_RELAX_STATE(s) \
!     ((((s) & 3) == BIG ? 4 : (((s) & 3) == BIG16 ? 2 : 1)))
  
  /* This table is used by relax_frag to promote short jumps to long
     ones where necessary.  SMALL (short) jumps may be promoted to BIG
*************** const relax_typeS md_relax_table[] =
*** 322,327 ****
--- 329,345 ----
    {1, 1, 0, 0},
    {1, 1, 0, 0},
  
+   /* UNCOND_JUMP states.  */
+   {127 + 1, -128 + 1, 0, ENCODE_RELAX_STATE (UNCOND_JUMP, BIG)},
+   {127 + 1, -128 + 1, 0, ENCODE_RELAX_STATE (UNCOND_JUMP, BIG16)},
+   /* dword jmp adds 3 bytes to frag:
+      0 extra opcode bytes, 3 extra displacement bytes.  */
+   {0, 0, 3, 0},
+   /* word jmp adds 1 byte to frag:
+      0 extra opcode bytes, 1 extra displacement byte.  */
+   {0, 0, 1, 0},
+ 
+   /* COND_JUMP states.  */
    {127 + 1, -128 + 1, 0, ENCODE_RELAX_STATE (COND_JUMP, BIG)},
    {127 + 1, -128 + 1, 0, ENCODE_RELAX_STATE (COND_JUMP, BIG16)},
    /* dword conditionals adds 4 bytes to frag:
*************** const relax_typeS md_relax_table[] =
*** 330,345 ****
    /* word conditionals add 2 bytes to frag:
       1 extra opcode byte, 1 extra displacement byte.  */
    {0, 0, 2, 0},
- 
-   {127 + 1, -128 + 1, 0, ENCODE_RELAX_STATE (UNCOND_JUMP, BIG)},
-   {127 + 1, -128 + 1, 0, ENCODE_RELAX_STATE (UNCOND_JUMP, BIG16)},
-   /* dword jmp adds 3 bytes to frag:
-      0 extra opcode bytes, 3 extra displacement bytes.  */
-   {0, 0, 3, 0},
-   /* word jmp adds 1 byte to frag:
-      0 extra opcode bytes, 1 extra displacement byte.  */
-   {0, 0, 1, 0}
  
  };
  
  static const arch_entry cpu_arch[] = {
--- 348,363 ----
    /* word conditionals add 2 bytes to frag:
       1 extra opcode byte, 1 extra displacement byte.  */
    {0, 0, 2, 0},
  
+   /* COND_JUMP86 states.  */
+   {127 + 1, -128 + 1, 0, ENCODE_RELAX_STATE (COND_JUMP86, BIG)},
+   {127 + 1, -128 + 1, 0, ENCODE_RELAX_STATE (COND_JUMP86, BIG16)},
+   /* dword conditionals adds 4 bytes to frag:
+      1 extra opcode byte, 3 extra displacement bytes.  */
+   {0, 0, 4, 0},
+   /* word conditionals add 3 bytes to frag:
+      1 extra opcode byte, 2 extra displacement bytes.  */
+   {0, 0, 3, 0}
  };
  
  static const arch_entry cpu_arch[] = {
*************** set_cpu_arch (dummy)
*** 726,732 ****
  	  if (strcmp (string, cpu_arch[i].name) == 0)
  	    {
  	      cpu_arch_name = cpu_arch[i].name;
! 	      cpu_arch_flags = cpu_arch[i].flags | (flag_code == CODE_64BIT ? Cpu64 : CpuNo64);
  	      break;
  	    }
  	}
--- 744,751 ----
  	  if (strcmp (string, cpu_arch[i].name) == 0)
  	    {
  	      cpu_arch_name = cpu_arch[i].name;
! 	      cpu_arch_flags = (cpu_arch[i].flags
! 				| (flag_code == CODE_64BIT ? Cpu64 : CpuNo64));
  	      break;
  	    }
  	}
*************** set_cpu_arch (dummy)
*** 738,743 ****
--- 757,779 ----
    else
      as_bad (_("missing cpu architecture"));
  
+   no_jump_promotion = 0;
+   if (*input_line_pointer == ','
+       && ! is_end_of_line[(unsigned char) input_line_pointer[1]])
+     {
+       char *string = ++input_line_pointer;
+       int e = get_symbol_end ();
+ 
+       if (strcmp (string, "nojumps") == 0)
+ 	no_jump_promotion = 1;
+       else if (strcmp (string, "jumps") == 0)
+ 	no_jump_promotion = 0;
+       else
+ 	as_bad (_("no such architecture modifier: `%s'"), string);
+ 
+       *input_line_pointer = e;
+     }
+ 
    demand_empty_rest_of_line ();
  }
  
*************** md_assemble (line)
*** 1197,1203 ****
    /* Points to template once we've found it.  */
    const template *t;
  
!   /* Count the size of the instruction generated.  */
    int insn_size = 0;
  
    int j;
--- 1233,1240 ----
    /* Points to template once we've found it.  */
    const template *t;
  
!   /* Count the size of the instruction generated.  Does not include
!      variable part of jump insns before relax.  */
    int insn_size = 0;
  
    int j;
*************** md_assemble (line)
*** 2671,2677 ****
      /* Output jumps.  */
      if (i.tm.opcode_modifier & Jump)
        {
- 	int size;
  	int code16;
  	int prefix;
  
--- 2708,2713 ----
*************** md_assemble (line)
*** 2692,2701 ****
  	    i.prefixes--;
  	  }
  
- 	size = 4;
- 	if (code16)
- 	  size = 2;
- 
  	if (i.prefixes != 0 && !intel_syntax)
  	  as_warn (_("skipping prefixes on this instruction"));
  
--- 2728,2733 ----
*************** md_assemble (line)
*** 2704,2710 ****
  	   instruction we may generate in md_convert_frag.  This is 2
  	   bytes for the opcode and room for the prefix and largest
  	   displacement.  */
! 	frag_grow (prefix + 2 + size);
  	insn_size += prefix + 1;
  	/* Prefix and 1 opcode byte go in fr_fix.  */
  	p = frag_more (prefix + 1);
--- 2736,2742 ----
  	   instruction we may generate in md_convert_frag.  This is 2
  	   bytes for the opcode and room for the prefix and largest
  	   displacement.  */
! 	frag_grow (prefix + 2 + 4);
  	insn_size += prefix + 1;
  	/* Prefix and 1 opcode byte go in fr_fix.  */
  	p = frag_more (prefix + 1);
*************** md_assemble (line)
*** 2716,2726 ****
  	/* 1 possible extra opcode + displacement go in var part.
  	   Pass reloc in fr_var.  */
  	frag_var (rs_machine_dependent,
! 		  1 + size,
  		  i.disp_reloc[0],
  		  ((unsigned char) *p == JUMP_PC_RELATIVE
  		   ? ENCODE_RELAX_STATE (UNCOND_JUMP, SMALL) | code16
! 		   : ENCODE_RELAX_STATE (COND_JUMP, SMALL) | code16),
  		  i.op[0].disps->X_add_symbol,
  		  i.op[0].disps->X_add_number,
  		  p);
--- 2748,2760 ----
  	/* 1 possible extra opcode + displacement go in var part.
  	   Pass reloc in fr_var.  */
  	frag_var (rs_machine_dependent,
! 		  1 + 4,
  		  i.disp_reloc[0],
  		  ((unsigned char) *p == JUMP_PC_RELATIVE
  		   ? ENCODE_RELAX_STATE (UNCOND_JUMP, SMALL) | code16
! 		   : ((cpu_arch_flags & Cpu386) != 0
! 		      ? ENCODE_RELAX_STATE (COND_JUMP, SMALL) | code16
! 		      : ENCODE_RELAX_STATE (COND_JUMP86, SMALL) | code16)),
  		  i.op[0].disps->X_add_symbol,
  		  i.op[0].disps->X_add_number,
  		  p);
*************** md_estimate_size_before_relax (fragP, se
*** 3878,3889 ****
       check for un-relaxable symbols.  On an ELF system, we can't relax
       an externally visible symbol, because it may be overridden by a
       shared library.  */
!   if (S_GET_SEGMENT (fragP->fr_symbol) != segment
  #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
!       || S_IS_EXTERNAL (fragP->fr_symbol)
!       || S_IS_WEAK (fragP->fr_symbol)
  #endif
!       )
      {
        /* Symbol is undefined in this segment, or we need to keep a
  	 reloc so that weak symbols can be overridden.  */
--- 3912,3923 ----
       check for un-relaxable symbols.  On an ELF system, we can't relax
       an externally visible symbol, because it may be overridden by a
       shared library.  */
!   if ((S_GET_SEGMENT (fragP->fr_symbol) != segment
  #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
!        || S_IS_EXTERNAL (fragP->fr_symbol)
!        || S_IS_WEAK (fragP->fr_symbol))
  #endif
!       && !no_jump_promotion)
      {
        /* Symbol is undefined in this segment, or we need to keep a
  	 reloc so that weak symbols can be overridden.  */
*************** md_estimate_size_before_relax (fragP, se
*** 3906,3915 ****
        old_fr_fix = fragP->fr_fix;
        opcode = (unsigned char *) fragP->fr_opcode;
  
!       switch (opcode[0])
  	{
! 	case JUMP_PC_RELATIVE:
! 	  /* Make jmp (0xeb) a dword displacement jump.  */
  	  opcode[0] = 0xe9;
  	  fragP->fr_fix += size;
  	  fix_new (fragP, old_fr_fix, size,
--- 3940,3949 ----
        old_fr_fix = fragP->fr_fix;
        opcode = (unsigned char *) fragP->fr_opcode;
  
!       switch (TYPE_FROM_RELAX_STATE (fragP->fr_subtype))
  	{
! 	case UNCOND_JUMP:
! 	  /* Make jmp (0xeb) a (d)word displacement jump.  */
  	  opcode[0] = 0xe9;
  	  fragP->fr_fix += size;
  	  fix_new (fragP, old_fr_fix, size,
*************** md_estimate_size_before_relax (fragP, se
*** 3918,3926 ****
  		   reloc_type);
  	  break;
  
! 	default:
  	  /* This changes the byte-displacement jump 0x7N
! 	     to the dword-displacement jump 0x0f,0x8N.  */
  	  opcode[1] = opcode[0] + 0x10;
  	  opcode[0] = TWO_BYTE_OPCODE_ESCAPE;
  	  /* We've added an opcode byte.  */
--- 3952,3980 ----
  		   reloc_type);
  	  break;
  
! 	case COND_JUMP86:
! 	  if (size == 2)
! 	    {
! 	      /* Negate the condition, and branch past an
! 		 unconditional jump.  */
! 	      opcode[0] ^= 1;
! 	      opcode[1] = 3;
! 	      /* Insert an unconditional jump.  */
! 	      opcode[2] = 0xe9;
! 	      /* We added two extra opcode bytes, and have a two byte
! 		 offset.  */
! 	      fragP->fr_fix += 2 + 2;
! 	      fix_new (fragP, old_fr_fix + 2, 2,
! 		       fragP->fr_symbol,
! 		       fragP->fr_offset, 1,
! 		       reloc_type);
! 	      break;
! 	    }
! 	  /* Fall through.  */
! 
! 	case COND_JUMP:
  	  /* This changes the byte-displacement jump 0x7N
! 	     to the (d)word-displacement jump 0x0f,0x8N.  */
  	  opcode[1] = opcode[0] + 0x10;
  	  opcode[0] = TWO_BYTE_OPCODE_ESCAPE;
  	  /* We've added an opcode byte.  */
*************** md_estimate_size_before_relax (fragP, se
*** 3930,3935 ****
--- 3984,3993 ----
  		   fragP->fr_offset, 1,
  		   reloc_type);
  	  break;
+ 
+ 	default:
+ 	  BAD_CASE (fragP->fr_subtype);
+ 	  break;
  	}
        frag_wane (fragP);
        return fragP->fr_fix - old_fr_fix;
*************** md_convert_frag (abfd, sec, fragP)
*** 3983,4033 ****
    /* Displacement from opcode start to fill into instruction.  */
    displacement_from_opcode_start = target_address - opcode_address;
  
!   switch (fragP->fr_subtype)
      {
-     case ENCODE_RELAX_STATE (COND_JUMP, SMALL):
-     case ENCODE_RELAX_STATE (COND_JUMP, SMALL16):
-     case ENCODE_RELAX_STATE (UNCOND_JUMP, SMALL):
-     case ENCODE_RELAX_STATE (UNCOND_JUMP, SMALL16):
        /* Don't have to change opcode.  */
        extension = 1;		/* 1 opcode + 1 displacement  */
        where_to_put_displacement = &opcode[1];
!       break;
  
!     case ENCODE_RELAX_STATE (COND_JUMP, BIG):
!       extension = 5;		/* 2 opcode + 4 displacement  */
!       opcode[1] = opcode[0] + 0x10;
!       opcode[0] = TWO_BYTE_OPCODE_ESCAPE;
!       where_to_put_displacement = &opcode[2];
!       break;
  
!     case ENCODE_RELAX_STATE (UNCOND_JUMP, BIG):
!       extension = 4;		/* 1 opcode + 4 displacement  */
!       opcode[0] = 0xe9;
!       where_to_put_displacement = &opcode[1];
!       break;
  
!     case ENCODE_RELAX_STATE (COND_JUMP, BIG16):
!       extension = 3;		/* 2 opcode + 2 displacement  */
!       opcode[1] = opcode[0] + 0x10;
!       opcode[0] = TWO_BYTE_OPCODE_ESCAPE;
!       where_to_put_displacement = &opcode[2];
!       break;
  
!     case ENCODE_RELAX_STATE (UNCOND_JUMP, BIG16):
!       extension = 2;		/* 1 opcode + 2 displacement  */
!       opcode[0] = 0xe9;
!       where_to_put_displacement = &opcode[1];
!       break;
  
!     default:
!       BAD_CASE (fragP->fr_subtype);
!       break;
      }
    /* Now put displacement after opcode.  */
    md_number_to_chars ((char *) where_to_put_displacement,
  		      (valueT) (displacement_from_opcode_start - extension),
! 		      SIZE_FROM_RELAX_STATE (fragP->fr_subtype));
    fragP->fr_fix += extension;
  }
  
--- 4041,4104 ----
    /* Displacement from opcode start to fill into instruction.  */
    displacement_from_opcode_start = target_address - opcode_address;
  
!   if ((fragP->fr_subtype & BIG) == 0)
      {
        /* Don't have to change opcode.  */
        extension = 1;		/* 1 opcode + 1 displacement  */
        where_to_put_displacement = &opcode[1];
!     }
!   else
!     {
!       if (no_jump_promotion)
! 	as_warn_where (fragP->fr_file, fragP->fr_line, _("long jump required"));
  
!       switch (fragP->fr_subtype)
! 	{
! 	case ENCODE_RELAX_STATE (UNCOND_JUMP, BIG):
! 	  extension = 4;		/* 1 opcode + 4 displacement  */
! 	  opcode[0] = 0xe9;
! 	  where_to_put_displacement = &opcode[1];
! 	  break;
  
! 	case ENCODE_RELAX_STATE (UNCOND_JUMP, BIG16):
! 	  extension = 2;		/* 1 opcode + 2 displacement  */
! 	  opcode[0] = 0xe9;
! 	  where_to_put_displacement = &opcode[1];
! 	  break;
  
! 	case ENCODE_RELAX_STATE (COND_JUMP, BIG):
! 	case ENCODE_RELAX_STATE (COND_JUMP86, BIG):
! 	  extension = 5;		/* 2 opcode + 4 displacement  */
! 	  opcode[1] = opcode[0] + 0x10;
! 	  opcode[0] = TWO_BYTE_OPCODE_ESCAPE;
! 	  where_to_put_displacement = &opcode[2];
! 	  break;
  
! 	case ENCODE_RELAX_STATE (COND_JUMP, BIG16):
! 	  extension = 3;		/* 2 opcode + 2 displacement  */
! 	  opcode[1] = opcode[0] + 0x10;
! 	  opcode[0] = TWO_BYTE_OPCODE_ESCAPE;
! 	  where_to_put_displacement = &opcode[2];
! 	  break;
  
! 	case ENCODE_RELAX_STATE (COND_JUMP86, BIG16):
! 	  extension = 4;
! 	  opcode[0] ^= 1;
! 	  opcode[1] = 3;
! 	  opcode[2] = 0xe9;
! 	  where_to_put_displacement = &opcode[3];
! 	  break;
! 
! 	default:
! 	  BAD_CASE (fragP->fr_subtype);
! 	  break;
! 	}
      }
+ 
    /* Now put displacement after opcode.  */
    md_number_to_chars ((char *) where_to_put_displacement,
  		      (valueT) (displacement_from_opcode_start - extension),
! 		      DISP_SIZE_FROM_RELAX_STATE (fragP->fr_subtype));
    fragP->fr_fix += extension;
  }
  
Index: gas/doc/c-i386.texi
===================================================================
RCS file: /cvs/src/src/gas/doc/c-i386.texi,v
retrieving revision 1.5
diff -c -p -r1.5 c-i386.texi
*** c-i386.texi	2001/01/08 02:23:45	1.5
--- c-i386.texi	2001/02/12 12:01:18
*************** extending the Intel architecture to 64-b
*** 26,32 ****
  * i386-Regs::                   Register Naming
  * i386-Prefixes::               Instruction Prefixes
  * i386-Memory::                 Memory References
! * i386-jumps::                  Handling of Jump Instructions
  * i386-Float::                  Floating Point
  * i386-SIMD::                   Intel's MMX and AMD's 3DNow! SIMD Operations
  * i386-16bit::                  Writing 16-bit Code
--- 26,32 ----
  * i386-Regs::                   Register Naming
  * i386-Prefixes::               Instruction Prefixes
  * i386-Memory::                 Memory References
! * i386-Jumps::                  Handling of Jump Instructions
  * i386-Float::                  Floating Point
  * i386-SIMD::                   Intel's MMX and AMD's 3DNow! SIMD Operations
  * i386-16bit::                  Writing 16-bit Code
*************** the default absolute addressing.
*** 488,494 ****
  Other addressing modes remain unchanged in x86-64 architecture, except
  registers used are 64-bit instead of 32-bit.
  
! @node i386-jumps
  @section Handling of Jump Instructions
  
  @cindex jump optimization, i386
--- 488,494 ----
  Other addressing modes remain unchanged in x86-64 architecture, except
  registers used are 64-bit instead of 32-bit.
  
! @node i386-Jumps
  @section Handling of Jump Instructions
  
  @cindex jump optimization, i386
*************** registers used are 64-bit instead of 32-
*** 498,508 ****
  Jump instructions are always optimized to use the smallest possible
  displacements.  This is accomplished by using byte (8-bit) displacement
  jumps whenever the target is sufficiently close.  If a byte displacement
! is insufficient a long (32-bit) displacement is used.  We do not support
  word (16-bit) displacement jumps in 32-bit mode (i.e. prefixing the jump
  instruction with the @samp{data16} instruction prefix), since the 80386
  insists upon masking @samp{%eip} to 16 bits after the word displacement
! is added.
  
  Note that the @samp{jcxz}, @samp{jecxz}, @samp{loop}, @samp{loopz},
  @samp{loope}, @samp{loopnz} and @samp{loopne} instructions only come in byte
--- 498,508 ----
  Jump instructions are always optimized to use the smallest possible
  displacements.  This is accomplished by using byte (8-bit) displacement
  jumps whenever the target is sufficiently close.  If a byte displacement
! is insufficient a long displacement is used.  We do not support
  word (16-bit) displacement jumps in 32-bit mode (i.e. prefixing the jump
  instruction with the @samp{data16} instruction prefix), since the 80386
  insists upon masking @samp{%eip} to 16 bits after the word displacement
! is added. (See also @pxref{i386-Arch})
  
  Note that the @samp{jcxz}, @samp{jecxz}, @samp{loop}, @samp{loopz},
  @samp{loope}, @samp{loopnz} and @samp{loopne} instructions only come in byte
*************** supported on the CPU specified.  The cho
*** 696,708 ****
  @item @samp{sledgehammer}
  @end multitable
  
! Apart from the warning, there is only one other effect on
! @code{@value{AS}} operation;  If you specify a CPU other than
  @samp{i486}, then shift by one instructions such as @samp{sarl $1, %eax}
  will automatically use a two byte opcode sequence.  The larger three
  byte opcode sequence is used on the 486 (and when no architecture is
  specified) because it executes faster on the 486.  Note that you can
  explicitly request the two byte opcode by writing @samp{sarl %eax}.
  
  @node i386-Notes
  @section Notes
--- 696,725 ----
  @item @samp{sledgehammer}
  @end multitable
  
! Apart from the warning, there are only two other effects on
! @code{@value{AS}} operation;  Firstly, if you specify a CPU other than
  @samp{i486}, then shift by one instructions such as @samp{sarl $1, %eax}
  will automatically use a two byte opcode sequence.  The larger three
  byte opcode sequence is used on the 486 (and when no architecture is
  specified) because it executes faster on the 486.  Note that you can
  explicitly request the two byte opcode by writing @samp{sarl %eax}.
+ Secondly, if you specify @samp{i8086}, @samp{i186}, or @samp{i286},
+ @emph{and} @samp{.code16} or @samp{.code16gcc} then byte offset
+ conditional jumps will be promoted when necessary to a two instruction
+ sequence  consisting of a conditional jump of the opposite sense around
+ an unconditional jump to the target.
+ 
+ Following the CPU architecture, you may specify @samp{jumps} or
+ @samp{nojumps} to control automatic jump promotion.  (@pxref{i386-Jumps})
+ @samp{jumps} is the default, and enables jump promotion.  @samp{nojumps}
+ prevents byte offset external jumps from being promoted, and causes a
+ warning for non-external jumps that @code{@value{AS}} promotes.
+ 
+ For example
+ 
+ @smallexample
+  .arch i8086,nojumps
+ @end smallexample
  
  @node i386-Notes
  @section Notes


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]