Support for gcc to generate 16-bit i386 code. (.code16gcc)

This commit is contained in:
Alan Modra 1999-08-04 10:07:41 +00:00
parent 23b255aadd
commit eecb386cd7
6 changed files with 139 additions and 65 deletions

View 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

View 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

View 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

View 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

View 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>

View 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 */