Support for gcc to generate 16-bit i386 code. (.code16gcc)
authorAlan Modra <amodra@gmail.com>
Wed, 4 Aug 1999 10:07:41 +0000 (10:07 +0000)
committerAlan Modra <amodra@gmail.com>
Wed, 4 Aug 1999 10:07:41 +0000 (10:07 +0000)
gas/ChangeLog
gas/config/tc-i386.c
gas/config/tc-i386.h
gas/doc/c-i386.texi
include/opcode/ChangeLog
include/opcode/i386.h

index 81b29b7..9d39904 100644 (file)
@@ -1,3 +1,27 @@
+1999-08-04  Alan Modra  <alan@spri.levels.unisa.edu.au>
+
+       * config/tc-i386.c (i386_operand): No need to change
+       operand_string pointer in segment reg case before goto
+       do_memory_reference.  Initialise displacement_string_start and
+       displacement_string_end after do_memory_reference label.
+       (i386_index_check): Add operand_string param, and print error
+       message on failure here.
+       (i386_intel_memory_operand): Instead of here.
+       (i386_operand): And here.
+       (INFER_ADDR_PREFIX): Enable.
+
+       * doc/c-i386.texi (i386-16bit): Document .code16gcc.
+
+       * config/tc-i386.h (DefaultSize): Define.  Renumber following
+       opcode_modifier defines.
+
+       From Etienne Lorrain  <etienne.lorrain@ibm.net>
+       * config/tc-i386.c (stackop_size): New variable.
+       (set_16bit_code_flag): Clear it here.
+       (set_16bit_gcc_code_flag): New function.
+       (md_pseudo_table): Add "code16gcc" entry.
+       (md_assemble): Set i.suffix for insns with DefaultSize modifier.
+
 1999-08-03  Ian Lance Taylor  <ian@zembu.com>
 
        * config/obj-coff.c (coff_frob_symbol): Always update set_end with
index 8fb0aa7..5d60b4b 100644 (file)
@@ -41,7 +41,7 @@
 #endif
 
 #ifndef INFER_ADDR_PREFIX
-#define INFER_ADDR_PREFIX 0
+#define INFER_ADDR_PREFIX 1
 #endif
 
 #ifndef SCALE1_WHEN_NO_INDEX
@@ -63,6 +63,7 @@ static int fits_in_signed_word PARAMS ((long));
 static int smallest_imm_type PARAMS ((long));
 static int add_prefix PARAMS ((unsigned int));
 static void set_16bit_code_flag PARAMS ((int));
+static void set_16bit_gcc_code_flag PARAMS((int));
 static void set_intel_syntax PARAMS ((int));
 
 #ifdef BFD_ASSEMBLER
@@ -229,6 +230,10 @@ static int intel_syntax = 0;       /* 1 for intel syntax, 0 if att syntax */
 
 static int allow_naked_reg = 0;  /* 1 if register prefix % not required */
 
+static char stackop_size = '\0';  /* Used in 16 bit gcc mode to add an l
+                                    suffix to call, ret, enter, leave, push,
+                                    and pop instructions.  */
+
 /* Interface to relax_segment.
    There are 2 relax states for 386 jump insns: one for conditional &
    one for unconditional jumps.  This is because the these two types
@@ -516,14 +521,23 @@ add_prefix (prefix)
 
 static void
 set_16bit_code_flag (new_16bit_code_flag)
-       int new_16bit_code_flag;
+     int new_16bit_code_flag;
+{
+  flag_16bit_code = new_16bit_code_flag;
+  stackop_size = '\0';
+}
+
+static void
+set_16bit_gcc_code_flag (new_16bit_code_flag)
+     int new_16bit_code_flag;
 {
   flag_16bit_code = new_16bit_code_flag;
+  stackop_size = new_16bit_code_flag ? 'l' : '\0';
 }
 
 static void
 set_intel_syntax (syntax_flag)
-       int syntax_flag;
+     int syntax_flag;
 {
   /* Find out if register prefixing is specified.  */
   int ask_naked_reg = 0;
@@ -575,6 +589,7 @@ const pseudo_typeS md_pseudo_table[] =
   {"value", cons, 2},
   {"noopt", s_ignore, 0},
   {"optim", s_ignore, 0},
+  {"code16gcc", set_16bit_gcc_code_flag, 1},
   {"code16", set_16bit_code_flag, 1},
   {"code32", set_16bit_code_flag, 0},
   {"intel_syntax", set_intel_syntax, 1},
@@ -1632,6 +1647,10 @@ md_assemble (line)
        else
          abort();
       }
+    else if ((i.tm.opcode_modifier & DefaultSize) && !i.suffix)
+      {
+       i.suffix = stackop_size;
+      }
 
     /* Make still unresolved immediate matches conform to size of immediate
        given in i.suffix.  Note: overlap2 cannot be an immediate!  */
@@ -3064,13 +3083,18 @@ i386_parse_seg (op_string)
 
 }
 
-static int i386_index_check PARAMS((void));
+static int i386_index_check PARAMS((const char *));
 
+/* Make sure the memory operand we've been dealt is valid.
+   Returns 1 on success, 0 on a failure.
+*/
 static int
-i386_index_check ()
+i386_index_check (operand_string)
+     const char *operand_string;
 {
-  /* Make sure the memory operand we've been dealt is valid.  */
 #if INFER_ADDR_PREFIX
+  int fudged = 0;
+
  tryprefix:
 #endif
   if (flag_16bit_code ^ (i.prefix[ADDR_PREFIX] != 0) ?
@@ -3093,15 +3117,22 @@ i386_index_check ()
               != (Reg32|BaseIndex)))))
     {
 #if INFER_ADDR_PREFIX
-      if (i.prefix[ADDR_PREFIX] == 0)
+      if (i.prefix[ADDR_PREFIX] == 0 && stackop_size != '\0')
        {
          i.prefix[ADDR_PREFIX] = ADDR_PREFIX_OPCODE;
          i.prefixes += 1;
+         fudged = 1;
          goto tryprefix;
        }
-      else
 #endif
-       return 0;
+      if (fudged)
+       as_bad (_("`%s' is not a valid base/index expression"),
+               operand_string);
+      else
+       as_bad (_("`%s' is not a valid %s bit base/index expression"),
+               operand_string,
+               flag_16bit_code ^ (i.prefix[ADDR_PREFIX] != 0) ? "16" : "32");
+      return 0;
     }
   return 1;
 }
@@ -3240,12 +3271,8 @@ i386_intel_memory_operand (operand_string)
        }
     }
 
-  if (i386_index_check () == 0)
-    {
-      as_bad (_("`%s' is not a valid base/index expression"),
-             operand_string);
-      return 0;
-    }
+  if (i386_index_check (operand_string) == 0)
+    return 0;
 
   i.mem_operands++;
   return 1;
@@ -3411,8 +3438,6 @@ i386_operand (operand_string)
          if (is_space_char (*op_string))
            ++op_string;
 
-         /* Pretend given string starts here.  */
-         operand_string = op_string;
          if (!is_digit_char (*op_string)
              && !is_identifier_char (*op_string)
              && *op_string != '('
@@ -3461,10 +3486,12 @@ i386_operand (operand_string)
       int found_base_index_form;
 
       /* Start and end of displacement string expression (if found). */
-      char *displacement_string_start = NULL;
-      char *displacement_string_end = NULL;
+      char *displacement_string_start;
+      char *displacement_string_end;
 
     do_memory_reference:
+      displacement_string_start = NULL;
+      displacement_string_end = NULL;
 
       if ((i.mem_operands == 1
           && (current_templates->start->opcode_modifier & IsString) == 0)
@@ -3638,12 +3665,8 @@ i386_operand (operand_string)
          return 1;
        }
 
-      if (i386_index_check () == 0)
-       {
-         as_bad (_("`%s' is not a valid base/index expression"),
-                 operand_string);
-         return 0;
-       }
+      if (i386_index_check (operand_string) == 0)
+       return 0;
       i.mem_operands++;
     }
   else
index ef778c1..41ebb86 100644 (file)
@@ -344,17 +344,18 @@ typedef struct
 #define Size16         0x2000  /* needs size prefix if in 32-bit mode */
 #define Size32         0x4000  /* needs size prefix if in 16-bit mode */
 #define IgnoreSize     0x8000  /* instruction ignores operand size prefix */
-#define No_bSuf               0x10000  /* b suffix on instruction illegal */
-#define No_wSuf               0x20000  /* w suffix on instruction illegal */
-#define No_lSuf               0x40000  /* l suffix on instruction illegal */
-#define No_sSuf               0x80000  /* s suffix on instruction illegal */
-#define No_dSuf       0x100000  /* d suffix on instruction illegal */
-#define No_xSuf       0x200000  /* x suffix on instruction illegal */
-#define FWait        0x400000  /* instruction needs FWAIT */
-#define IsString      0x800000 /* quick test for string instructions */
-#define regKludge    0x1000000 /* fake an extra reg operand for clr, imul */
-#define IsPrefix     0x2000000 /* opcode is a prefix */
-#define ImmExt      0x4000000  /* instruction has extension in 8 bit imm */
+#define DefaultSize    0x10000  /* default insn size depends on mode */
+#define No_bSuf               0x20000  /* b suffix on instruction illegal */
+#define No_wSuf               0x40000  /* w suffix on instruction illegal */
+#define No_lSuf               0x80000  /* l suffix on instruction illegal */
+#define No_sSuf              0x100000  /* s suffix on instruction illegal */
+#define No_dSuf       0x200000  /* d suffix on instruction illegal */
+#define No_xSuf       0x400000  /* x suffix on instruction illegal */
+#define FWait        0x800000  /* instruction needs FWAIT */
+#define IsString     0x1000000 /* quick test for string instructions */
+#define regKludge    0x2000000 /* fake an extra reg operand for clr, imul */
+#define IsPrefix     0x4000000 /* opcode is a prefix */
+#define ImmExt      0x8000000  /* instruction has extension in 8 bit imm */
 #define Ugh        0x80000000  /* deprecated fp insn, gets a warning */
 
   /* operand_types[i] describes the type of operand i.  This is made
index e27893b..8a9c85a 100644 (file)
@@ -443,14 +443,25 @@ instructions is reversed from the Intel syntax.
 @cindex i386 16-bit code
 @cindex 16-bit code, i386
 @cindex real-mode code, i386
+@cindex @code{code16gcc} directive, i386
 @cindex @code{code16} directive, i386
 @cindex @code{code32} directive, i386
 While @code{@value{AS}} normally writes only ``pure'' 32-bit i386 code,
 it also supports writing code to run in real mode or in 16-bit protected
-mode code segments.  To do this, put a @samp{.code16} directive before
-the assembly language instructions to be run in 16-bit mode.  You can
-switch @code{@value{AS}} back to writing normal 32-bit code with the
-@samp{.code32} directive.
+mode code segments.  To do this, put a @samp{.code16} or
+@samp{.code16gcc} directive before the assembly language instructions to
+be run in 16-bit mode.  You can switch @code{@value{AS}} back to writing
+normal 32-bit code with the @samp{.code32} directive.
+
+@samp{.code16gcc} provides experimental support for generating 16-bit
+code from gcc, and differs from @samp{.code16} in that @samp{call},
+@samp{ret}, @samp{enter}, @samp{leave}, @samp{push}, @samp{pop},
+@samp{pusha}, @samp{popa}, @samp{pushf}, and @samp{popf} instructions
+default to 32-bit size.  This is so that the stack pointer is
+manipulated in the same way over function calls, allowing access to
+function parameters at the same stack offsets as in 32-bit mode.
+@samp{.code16gcc} also automatically adds address size prefixes where
+necessary to use the 32-bit addressing modes that gcc generates.
 
 The code which @code{@value{AS}} generates in 16-bit mode will not
 necessarily run on a 16-bit pre-80386 processor.  To write code that
index 735d700..48caf3c 100644 (file)
@@ -1,3 +1,9 @@
+1999-08-04  Alan Modra  <alan@spri.levels.unisa.edu.au>
+
+       * i386.h (i386_optab): Add DefaultSize modifier to all insns
+       that implicitly modify %esp.  #undef d_Suf, x_suf, sld_suf,
+       sldx_suf, bwld_Suf, d_FP, x_FP, sld_FP, sldx_FP at end of table.
+
 Wed Jul 28 02:04:24 1999  Jerry Quinn <jquinn@nortelnetworks.com>
                          Jeff Law <law@cygnus.com>
 
index e7e78c8..9d73ebd 100644 (file)
@@ -105,23 +105,23 @@ static const template i386_optab[] = {
 {"movzx",  2, 0x0fb6, X, b_Suf|Modrm,                  { Reg8|ByteMem, WordReg, 0} },
 
 /* push instructions */
-{"push",   1,  0x50, X, wl_Suf|ShortForm,      { WordReg, 0, 0 } },
-{"push",   1,  0xff, 6, wl_Suf|Modrm,          { WordReg|WordMem, 0, 0 } },
-{"push",   1,  0x6a, X, wl_Suf,                { Imm8S, 0, 0} },
-{"push",   1,  0x68, X, wl_Suf,                { Imm16|Imm32, 0, 0} },
-{"push",   1,  0x06, X, wl_Suf|Seg2ShortForm { SReg2, 0, 0 } },
-{"push",   1, 0x0fa0, X, wl_Suf|Seg3ShortForm, { SReg3, 0, 0 } },
+{"push",   1,  0x50, X, wl_Suf|ShortForm|DefaultSize,  { WordReg, 0, 0 } },
+{"push",   1,  0xff, 6, wl_Suf|Modrm|DefaultSize,      { WordReg|WordMem, 0, 0 } },
+{"push",   1,  0x6a, X, wl_Suf|DefaultSize,            { Imm8S, 0, 0} },
+{"push",   1,  0x68, X, wl_Suf|DefaultSize,            { Imm16|Imm32, 0, 0} },
+{"push",   1,  0x06, X, wl_Suf|Seg2ShortForm|DefaultSize, { SReg2, 0, 0 } },
+{"push",   1, 0x0fa0, X, wl_Suf|Seg3ShortForm|DefaultSize, { SReg3, 0, 0 } },
 /* push all */
-{"pusha",  0,  0x60, X, wl_Suf,                { 0, 0, 0 } },
+{"pusha",  0,  0x60, X, wl_Suf|DefaultSize,            { 0, 0, 0 } },
 
 /* pop instructions */
-{"pop",           1,   0x58, X, wl_Suf|ShortForm,      { WordReg, 0, 0 } },
-{"pop",           1,   0x8f, 0, wl_Suf|Modrm,          { WordReg|WordMem, 0, 0 } },
+{"pop",           1,   0x58, X, wl_Suf|ShortForm|DefaultSize,  { WordReg, 0, 0 } },
+{"pop",           1,   0x8f, 0, wl_Suf|Modrm|DefaultSize,      { WordReg|WordMem, 0, 0 } },
 #define POP_SEG_SHORT 0x07
-{"pop",           1,   0x07, X, wl_Suf|Seg2ShortForm { SReg2, 0, 0 } },
-{"pop",           1, 0x0fa1, X, wl_Suf|Seg3ShortForm { SReg3, 0, 0 } },
+{"pop",           1,   0x07, X, wl_Suf|Seg2ShortForm|DefaultSize, { SReg2, 0, 0 } },
+{"pop",           1, 0x0fa1, X, wl_Suf|Seg3ShortForm|DefaultSize, { SReg3, 0, 0 } },
 /* pop all */
-{"popa",   0,  0x61, X, wl_Suf,                { 0, 0, 0 } },
+{"popa",   0,  0x61, X, wl_Suf|DefaultSize,            { 0, 0, 0 } },
 
 /* xchg exchange instructions
    xchg commutes:  we allow both operand orders */
@@ -158,8 +158,8 @@ static const template i386_optab[] = {
 {"cmc",           0,   0xf5, X, NoSuf,                 { 0, 0, 0} },
 {"lahf",   0,  0x9f, X, NoSuf,                 { 0, 0, 0} },
 {"sahf",   0,  0x9e, X, NoSuf,                 { 0, 0, 0} },
-{"pushf",  0,  0x9c, X, wl_Suf,                { 0, 0, 0} },
-{"popf",   0,  0x9d, X, wl_Suf,                { 0, 0, 0} },
+{"pushf",  0,  0x9c, X, wl_Suf|DefaultSize,    { 0, 0, 0} },
+{"popf",   0,  0x9d, X, wl_Suf|DefaultSize,    { 0, 0, 0} },
 {"stc",           0,   0xf9, X, NoSuf,                 { 0, 0, 0} },
 {"std",           0,   0xfd, X, NoSuf,                 { 0, 0, 0} },
 {"sti",           0,   0xfb, X, NoSuf,                 { 0, 0, 0} },
@@ -311,12 +311,12 @@ static const template i386_optab[] = {
 {"sar",           1,   0xd0, 7, bwl_Suf|W|Modrm,       { Reg|AnyMem, 0, 0} },
 
 /* control transfer instructions */
-{"call",   1,  0xe8, X, wl_Suf|JumpDword,      { Disp16|Disp32, 0, 0} },
-{"call",   1,  0xff, 2, wl_Suf|Modrm,          { WordReg|WordMem|JumpAbsolute, 0, 0} },
+{"call",   1,  0xe8, X, wl_Suf|JumpDword|DefaultSize,  { Disp16|Disp32, 0, 0} },
+{"call",   1,  0xff, 2, wl_Suf|Modrm|DefaultSize,      { WordReg|WordMem|JumpAbsolute, 0, 0} },
 /* Intel Syntax */
-{"call",   2,  0x9a, X, wl_Suf|JumpInterSegment, { Imm16, Imm16|Imm32, 0} },
-{"lcall",  2,  0x9a, X, wl_Suf|JumpInterSegment, { Imm16, Imm16|Imm32, 0} },
-{"lcall",  1,  0xff, 3, wl_Suf|Modrm,          { WordMem, 0, 0} },
+{"call",   2,  0x9a, X, wl_Suf|JumpInterSegment|DefaultSize, { Imm16, Imm16|Imm32, 0} },
+{"lcall",  2,  0x9a, X, wl_Suf|JumpInterSegment|DefaultSize, { Imm16, Imm16|Imm32, 0} },
+{"lcall",  1,  0xff, 3, wl_Suf|Modrm|DefaultSize,      { WordMem, 0, 0} },
 
 #define JUMP_PC_RELATIVE 0xeb
 {"jmp",           1,   0xeb, X, NoSuf|Jump,            { Disp, 0, 0} },
@@ -327,12 +327,12 @@ static const template i386_optab[] = {
 {"ljmp",   2,  0xea, X, wl_Suf|JumpInterSegment, { Imm16, Imm16|Imm32, 0} },
 {"ljmp",   1,  0xff, 5, wl_Suf|Modrm,          { WordMem, 0, 0} },
 
-{"ret",           0,   0xc3, X, wl_Suf,                { 0, 0, 0} },
-{"ret",           1,   0xc2, X, wl_Suf,                { Imm16, 0, 0} },
-{"lret",   0,  0xcb, X, wl_Suf,                { 0, 0, 0} },
-{"lret",   1,  0xca, X, wl_Suf,                { Imm16, 0, 0} },
-{"enter",  2,  0xc8, X, wl_Suf,                { Imm16, Imm8, 0} },
-{"leave",  0,  0xc9, X, wl_Suf,                { 0, 0, 0} },
+{"ret",           0,   0xc3, X, wl_Suf|DefaultSize,    { 0, 0, 0} },
+{"ret",           1,   0xc2, X, wl_Suf|DefaultSize,    { Imm16, 0, 0} },
+{"lret",   0,  0xcb, X, wl_Suf|DefaultSize,    { 0, 0, 0} },
+{"lret",   1,  0xca, X, wl_Suf|DefaultSize,    { Imm16, 0, 0} },
+{"enter",  2,  0xc8, X, wl_Suf|DefaultSize,    { Imm16, Imm8, 0} },
+{"leave",  0,  0xc9, X, wl_Suf|DefaultSize,    { 0, 0, 0} },
 
 /* conditional jumps */
 {"jo",    1,   0x70, X, NoSuf|Jump,            { Disp, 0, 0} },
@@ -1035,14 +1035,23 @@ static const template i386_optab[] = {
 #undef b_Suf
 #undef w_Suf
 #undef l_Suf
+#undef d_Suf
+#undef x_Suf
 #undef bw_Suf
 #undef bl_Suf
 #undef wl_Suf
 #undef sl_Suf
+#undef sld_Suf
+#undef sldx_Suf
 #undef bwl_Suf
+#undef bwld_Suf
 #undef FP
 #undef l_FP
+#undef d_FP
+#undef x_FP
 #undef sl_FP
+#undef sld_FP
+#undef sldx_FP
 
 #define MAX_MNEM_SIZE 16       /* for parsing insn mnemonics from input */