Support for gcc to generate 16-bit i386 code. (.code16gcc)
This commit is contained in:
parent
23b255aadd
commit
eecb386cd7
6 changed files with 139 additions and 65 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
@ -519,6 +524,15 @@ set_16bit_code_flag (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
|
||||
|
@ -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,14 +3117,21 @@ 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
|
||||
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);
|
||||
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);
|
||||
if (i386_index_check (operand_string) == 0)
|
||||
return 0;
|
||||
}
|
||||
i.mem_operands++;
|
||||
}
|
||||
else
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
Loading…
Reference in a new issue