From 330172aea50d14c226d5d46f8356d5521c4d158d Mon Sep 17 00:00:00 2001 From: amodra Date: Wed, 4 Aug 1999 10:07:39 +0000 Subject: [PATCH] Support for gcc to generate 16-bit i386 code. (.code16gcc) --- gas/ChangeLog | 24 ++++++++++++++++ gas/config/tc-i386.c | 73 +++++++++++++++++++++++++++++++----------------- gas/config/tc-i386.h | 23 +++++++-------- gas/doc/c-i386.texi | 19 ++++++++++--- include/opcode/ChangeLog | 6 ++++ include/opcode/i386.h | 59 +++++++++++++++++++++----------------- 6 files changed, 139 insertions(+), 65 deletions(-) diff --git a/gas/ChangeLog b/gas/ChangeLog index 81b29b7fe9..9d399043ac 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,27 @@ +1999-08-04 Alan Modra + + * 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 + * 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 * config/obj-coff.c (coff_frob_symbol): Always update set_end with diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c index 8fb0aa7ec9..5d60b4bcf8 100644 --- a/gas/config/tc-i386.c +++ b/gas/config/tc-i386.c @@ -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 diff --git a/gas/config/tc-i386.h b/gas/config/tc-i386.h index ef778c158e..41ebb86e32 100644 --- a/gas/config/tc-i386.h +++ b/gas/config/tc-i386.h @@ -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 diff --git a/gas/doc/c-i386.texi b/gas/doc/c-i386.texi index e27893b892..8a9c85a678 100644 --- a/gas/doc/c-i386.texi +++ b/gas/doc/c-i386.texi @@ -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 diff --git a/include/opcode/ChangeLog b/include/opcode/ChangeLog index 735d700d35..48caf3cbb4 100644 --- a/include/opcode/ChangeLog +++ b/include/opcode/ChangeLog @@ -1,3 +1,9 @@ +1999-08-04 Alan Modra + + * 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 Jeff Law diff --git a/include/opcode/i386.h b/include/opcode/i386.h index e7e78c8ea8..9d73ebde79 100644 --- a/include/opcode/i386.h +++ b/include/opcode/i386.h @@ -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 */ -- 2.11.0