aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gas/ChangeLog62
-rw-r--r--gas/config/tc-i386.c898
-rw-r--r--gas/config/tc-i386.h34
3 files changed, 591 insertions, 403 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 7ac200a..9f933e4 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,65 @@
+Mon Jun 8 12:20:30 1998 Alan Modra <alan@spri.levels.unisa.edu.au>
+
+ * config/tc-i386.c: REPNE renamed to REPNE_PREFIX_OPCODE, and
+ likewise for REPE.
+
+ * config/tc-i386.c (reloc): Add braces.
+
+ * config/tc-i386.c (struct _i386_insn): Rename bi to sib to be
+ consistent with Intel naming.
+ * config/tc-i386.h (base_index_byte): Rename to sib_byte. Don't
+ use bitfields in sib_byte.
+ (modrm_byte): Don't use bitfields here either.
+
+ * config/tc-i386.c (current_templates): Add const.
+ (parse_register): Add const to return, param, and char *s.
+ (i386_operand): Add const to reg_entry *r.
+ * config/tc-i386.h (templates): Add const to start, end.
+
+ Inspired by code for 16 bit gas support from Martynas Kunigelis
+ <martynas@nm3.ktu.lt>:
+ * config/tc-i386.c (md_assemble): Add full support for 16 bit
+ modrm, and Jump, JumpByte, JumpDword, JumpInterSegment insns.
+ (uses_mem_addrmode): Remove.
+ (md_estimate_size_before_relax): Add support here too.
+ (md_relax_table): Rewrite interface to md_relax for 16 bit
+ support.
+ (BYTE, WORD, DWORD, UNKNOWN_SIZE): Remove.
+ (opcode_suffix_to_type): Remove.
+ (CODE16, SMALL, SMALL16, BIG, BIG16): Define.
+ (SIZE_FROM_RELAX_STATE): Modify to suit above.
+ (md_convert_frag): Likewise.
+ (i386_operand): Add support for 16 bit base/index regs,
+ immediates, and displacements. Remove some unnecessary casts, and
+ localise end_of_operand_string, displacement_string_start,
+ displacement_string_end variables. Add GCC_ASM_O_HACK.
+ * config/tc-i386.h (NO_BASE_REGISTER_16): Define.
+
+ * config/tc-i386.c (prefix_hash): Remove.
+ (md_begin): Rewrite without obstacks. Remove prefix hash table
+ handling. Rewrite lexical table handling.
+ (i386_print_statistics): Don't print prefix statistics.
+ (md_assemble): Rewrite instruction parser so that line is not
+ converted to lower case. Don't do a hash_find for prefixes,
+ instead recognise them via opcode modifier.
+ (expecting_operand, paren_not_balanced): Localise variables.
+ * config/tc-i386.h (IsPrefix): Define.
+ (prefix_entry): Remove.
+
+ * config/tc-i386.h (PREFIX_SEPERATOR): Don't define.
+ * config/tc-i386.c (PREFIX_SEPARATOR): Define here instead, using
+ '\\' in case where comment_chars contains '/'.
+
+ * config/tc-i386.c (MATCH): Ensure given operand and template
+ match for JumpAbsolute. Makes e.g. `ljmp table(%ebx)' invalid;
+ you must write `ljmp *table(%ebx)'.
+
+ From H.J. Lu <hjl@gnu.org>:
+ * config/tc-i386.c (BFD_RELOC_16, BFD_RELOC_16_PCREL): Define
+ as 0 ifndef BFD_ASSEMBLER.
+ (md_assemble): Allow immediate operands without suffix or
+ other reg operand to default in size to the current code size.
+
start-sanitize-v850e
Mon Jun 8 09:45:00 1998 Catherine Moore <clm@cygnus.com>
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index 0a393e2..ea2a984 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -30,8 +30,6 @@
#include "as.h"
#include "subsegs.h"
-
-#include "obstack.h"
#include "opcode/i386.h"
#ifndef TC_RELOC
@@ -120,11 +118,11 @@ struct _i386_insn
unsigned int prefixes;
unsigned char prefix[MAX_PREFIXES];
- /* RM and BI are the modrm byte and the base index byte where the
+ /* RM and SIB are the modrm byte and the sib byte where the
addressing modes of this insn are encoded. */
modrm_byte rm;
- base_index_byte bi;
+ sib_byte sib;
};
typedef struct _i386_insn i386_insn;
@@ -133,8 +131,10 @@ typedef struct _i386_insn i386_insn;
pre-processor is disabled, these aren't very useful */
#if defined (TE_I386AIX) || defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
const char comment_chars[] = "#/";
+#define PREFIX_SEPARATOR '\\'
#else
const char comment_chars[] = "#";
+#define PREFIX_SEPARATOR '/'
#endif
/* This array holds the chars that only start a comment at the beginning of
@@ -150,6 +150,7 @@ const char line_comment_chars[] = "";
#else
const char line_comment_chars[] = "/";
#endif
+
const char line_separator_chars[] = "";
/* Chars that can be used to separate mant from exp in floating point nums */
@@ -194,7 +195,7 @@ static char *save_stack_p; /* stack pointer */
static i386_insn i;
/* Possible templates for current insn. */
-static templates *current_templates;
+static const templates *current_templates;
/* Per instruction expressionS buffers: 2 displacements & 2 immediate max. */
static expressionS disp_expressions[2], im_expressions[2];
@@ -215,10 +216,11 @@ static int flag_16bit_code; /* 1 if we're writing 16-bit code, 0 if 32-bit */
#define COND_JUMP 1 /* conditional jump */
#define UNCOND_JUMP 2 /* unconditional jump */
/* sizes */
-#define BYTE 0
-#define WORD 1
-#define DWORD 2
-#define UNKNOWN_SIZE 3
+#define CODE16 1
+#define SMALL 0
+#define SMALL16 (SMALL|CODE16)
+#define BIG 2
+#define BIG16 (BIG|CODE16)
#ifndef INLINE
#ifdef __GNUC__
@@ -231,7 +233,15 @@ static int flag_16bit_code; /* 1 if we're writing 16-bit code, 0 if 32-bit */
#define ENCODE_RELAX_STATE(type,size) \
((relax_substateT)((type<<2) | (size)))
#define SIZE_FROM_RELAX_STATE(s) \
- ( (((s) & 0x3) == BYTE ? 1 : (((s) & 0x3) == WORD ? 2 : 4)) )
+ ( (((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
+ (32 bit long) ones, and SMALL16 jumps to BIG16 (16 bit long). We
+ don't allow a short jump in a 32 bit code segment to be promoted to
+ a 16 bit offset jump because it's slower (requires data size
+ prefix), and doesn't work, unless the destination is in the bottom
+ 64k of the code segment (The top 16 bits of eip are zeroed). */
const relax_typeS md_relax_table[] =
{
@@ -246,26 +256,23 @@ const relax_typeS md_relax_table[] =
{1, 1, 0, 0},
{1, 1, 0, 0},
- /* For now we don't use word displacement jumps; they will not work
- for destination addresses > 0xFFFF, since they clear the upper 16
- bits of %eip. */
- {127 + 1, -128 + 1, 0, ENCODE_RELAX_STATE (COND_JUMP, DWORD)},
- /* word conditionals add 3 bytes to frag:
- 2 opcode prefix; 1 displacement bytes */
- {32767 + 2, -32768 + 2, 3, ENCODE_RELAX_STATE (COND_JUMP, DWORD)},
+ {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:
- 1 opcode prefix; 3 displacement bytes */
+ 1 extra opcode byte, 3 extra displacement bytes. */
{0, 0, 4, 0},
- {1, 1, 0, 0},
+ /* 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, DWORD)},
- /* word jmp adds 2 bytes to frag:
- 1 opcode prefix; 1 displacement bytes */
- {32767 + 2, -32768 + 2, 2, ENCODE_RELAX_STATE (UNCOND_JUMP, DWORD)},
+ {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 opcode prefix; 3 displacement bytes */
+ 0 extra opcode bytes, 3 extra displacement bytes. */
{0, 0, 3, 0},
- {1, 1, 0, 0},
+ /* word jmp adds 1 byte to frag:
+ 0 extra opcode bytes, 1 extra displacement byte. */
+ {0, 0, 1, 0}
};
@@ -358,7 +365,7 @@ i386_align_code (fragP, count)
static char *output_invalid PARAMS ((int c));
static int i386_operand PARAMS ((char *operand_string));
-static reg_entry *parse_register PARAMS ((char *reg_string));
+static const reg_entry *parse_register PARAMS ((const char *reg_string));
#ifndef I386COFF
static void s_bss PARAMS ((int));
#endif
@@ -372,20 +379,6 @@ mode_from_disp_size (t)
return (t & Disp8) ? 1 : (t & (Disp16|Disp32)) ? 2 : 0;
}
-#if 0
-/* Not used. */
-/* convert opcode suffix ('b' 'w' 'l' typically) into type specifier */
-
-static INLINE unsigned long
-opcode_suffix_to_type (s)
- unsigned long s;
-{
- return (s == BYTE_OPCODE_SUFFIX
- ? Byte : (s == WORD_OPCODE_SUFFIX
- ? Word : DWord));
-} /* opcode_suffix_to_type() */
-#endif
-
static INLINE int
fits_in_signed_byte (num)
long num;
@@ -461,8 +454,8 @@ add_prefix (prefix)
q = SEG_PREFIX;
break;
- case REPNE:
- case REPE:
+ case REPNE_PREFIX_OPCODE:
+ case REPE_PREFIX_OPCODE:
ret = 2;
/* fall thru */
case LOCK_PREFIX_OPCODE:
@@ -524,15 +517,10 @@ const pseudo_typeS md_pseudo_table[] =
/* for interface with expression () */
extern char *input_line_pointer;
-/* obstack for constructing various things in md_begin */
-struct obstack o;
-
/* hash table for opcode lookup */
static struct hash_control *op_hash;
/* hash table for register lookup */
static struct hash_control *reg_hash;
-/* hash table for prefix lookup */
-static struct hash_control *prefix_hash;
void
@@ -540,46 +528,40 @@ md_begin ()
{
const char *hash_err;
- obstack_begin (&o, 4096);
-
/* initialize op_hash hash table */
op_hash = hash_new ();
{
register const template *optab;
register templates *core_optab;
- char *prev_name;
optab = i386_optab; /* setup for loop */
- prev_name = optab->name;
- obstack_grow (&o, optab, sizeof (template));
core_optab = (templates *) xmalloc (sizeof (templates));
+ core_optab->start = optab;
- for (optab++; optab < i386_optab_end; optab++)
+ while (1)
{
- if (!strcmp (optab->name, prev_name))
- {
- /* same name as before --> append to current template list */
- obstack_grow (&o, optab, sizeof (template));
- }
- else
+ ++optab;
+ if (optab->name == NULL
+ || strcmp (optab->name, (optab - 1)->name) != 0)
{
/* different name --> ship out current template list;
add to hash table; & begin anew */
- /* Note: end must be set before start! since obstack_next_free
- changes upon opstack_finish */
- core_optab->end = (template *) obstack_next_free (&o);
- core_optab->start = (template *) obstack_finish (&o);
- hash_err = hash_insert (op_hash, prev_name, (char *) core_optab);
+ core_optab->end = optab;
+ hash_err = hash_insert (op_hash,
+ (optab - 1)->name,
+ (PTR) core_optab);
if (hash_err)
{
hash_error:
- as_fatal (_("Internal Error: Can't hash %s: %s"), prev_name,
+ as_fatal (_("Internal Error: Can't hash %s: %s"),
+ (optab - 1)->name,
hash_err);
}
- prev_name = optab->name;
+ if (optab->name == NULL)
+ break;
core_optab = (templates *) xmalloc (sizeof (templates));
- obstack_grow (&o, optab, sizeof (template));
+ core_optab->start = optab;
}
}
}
@@ -589,7 +571,9 @@ md_begin ()
{
register const reg_entry *regtab;
- for (regtab = i386_regtab; regtab < i386_regtab_end; regtab++)
+ for (regtab = i386_regtab;
+ regtab < i386_regtab + sizeof (i386_regtab) / sizeof (i386_regtab[0]);
+ regtab++)
{
hash_err = hash_insert (reg_hash, regtab->reg_name, (PTR) regtab);
if (hash_err)
@@ -597,21 +581,6 @@ md_begin ()
}
}
- /* initialize reg_hash hash table */
- prefix_hash = hash_new ();
- {
- register const prefix_entry *prefixtab;
-
- for (prefixtab = i386_prefixtab;
- prefixtab < i386_prefixtab_end; prefixtab++)
- {
- hash_err = hash_insert (prefix_hash, prefixtab->prefix_name,
- (PTR) prefixtab);
- if (hash_err)
- goto hash_error;
- }
- }
-
/* fill in lexical tables: opcode_chars, operand_chars, space_chars */
{
register int c;
@@ -619,41 +588,40 @@ md_begin ()
for (c = 0; c < 256; c++)
{
- if (islower (c) || isdigit (c))
+ if (isdigit (c))
{
+ digit_chars[c] = c;
opcode_chars[c] = c;
register_chars[c] = c;
+ operand_chars[c] = c;
}
- else if (isupper (c))
- {
- opcode_chars[c] = tolower (c);
- register_chars[c] = opcode_chars[c];
- }
- else if (c == PREFIX_SEPERATOR)
+ else if (islower (c))
{
opcode_chars[c] = c;
+ register_chars[c] = c;
+ operand_chars[c] = c;
}
- else if (c == ')' || c == '(')
+ else if (isupper (c))
{
- register_chars[c] = c;
+ opcode_chars[c] = tolower (c);
+ register_chars[c] = opcode_chars[c];
+ operand_chars[c] = c;
}
- if (isupper (c) || islower (c) || isdigit (c))
- operand_chars[c] = c;
-
- if (isdigit (c) || c == '-')
- digit_chars[c] = c;
-
- if (isalpha (c) || c == '_' || c == '.' || isdigit (c))
+ if (isalpha (c) || isdigit (c))
identifier_chars[c] = c;
+ }
#ifdef LEX_AT
- identifier_chars['@'] = '@';
+ identifier_chars['@'] = '@';
#endif
-
- if (c == ' ' || c == '\t')
- space_chars[c] = c;
- }
+ register_chars[')'] = ')';
+ register_chars['('] = '(';
+ digit_chars['-'] = '-';
+ identifier_chars['_'] = '_';
+ identifier_chars['.'] = '.';
+ space_chars[' '] = ' ';
+ space_chars['\t'] = '\t';
for (p = operand_special_chars; *p != '\0'; p++)
operand_chars[(unsigned char) *p] = *p;
@@ -675,7 +643,6 @@ i386_print_statistics (file)
{
hash_print_statistics (file, "i386 opcode", op_hash);
hash_print_statistics (file, "i386 register", reg_hash);
- hash_print_statistics (file, "i386 prefix", prefix_hash);
}
@@ -838,24 +805,25 @@ reloc (size, pcrel, other)
if (other != NO_RELOC) return other;
if (pcrel)
- switch (size)
- {
- case 1: return BFD_RELOC_8_PCREL;
- case 2: return BFD_RELOC_16_PCREL;
- case 4: return BFD_RELOC_32_PCREL;
- }
- else
- switch (size)
- {
- case 1: return BFD_RELOC_8;
- case 2: return BFD_RELOC_16;
- case 4: return BFD_RELOC_32;
- }
-
- if (pcrel)
- as_bad (_("Can not do %d byte pc-relative relocation"), size);
+ {
+ switch (size)
+ {
+ case 1: return BFD_RELOC_8_PCREL;
+ case 2: return BFD_RELOC_16_PCREL;
+ case 4: return BFD_RELOC_32_PCREL;
+ }
+ as_bad (_("Can not do %d byte pc-relative relocation"), size);
+ }
else
- as_bad (_("Can not do %d byte relocation"), size);
+ {
+ switch (size)
+ {
+ case 1: return BFD_RELOC_8;
+ case 2: return BFD_RELOC_16;
+ case 4: return BFD_RELOC_32;
+ }
+ as_bad (_("Can not do %d byte relocation"), size);
+ }
return BFD_RELOC_NONE;
}
@@ -886,7 +854,9 @@ tc_i386_fix_adjustable(fixP)
}
#else
#define reloc(SIZE,PCREL,OTHER) 0
+#define BFD_RELOC_16 0
#define BFD_RELOC_32 0
+#define BFD_RELOC_16_PCREL 0
#define BFD_RELOC_32_PCREL 0
#define BFD_RELOC_386_PLT32 0
#define BFD_RELOC_386_GOT32 0
@@ -921,76 +891,72 @@ md_assemble (line)
We assume that the scrubber has arranged it so that line[0] is the valid
start of a (possibly prefixed) opcode. */
{
+ char opcode[MAX_OPCODE_SIZE];
char *l = line;
+ char *token_start = l;
+ char *opp;
- /* 1 if operand is pending after ','. */
- unsigned int expecting_operand = 0;
/* Non-zero if we found a prefix only acceptable with string insns. */
const char *expecting_string_instruction = NULL;
- /* Non-zero if operand parens not balanced. */
- unsigned int paren_not_balanced;
- char *token_start = l;
- while (!is_space_char (*l) && *l != END_OF_INSN)
+ while (1)
{
- if (!is_opcode_char (*l))
+ opp = opcode;
+ while ((*opp = opcode_chars[(unsigned char) *l]) != 0)
{
- as_bad (_("invalid character %s in opcode"), output_invalid (*l));
- return;
+ opp++;
+ if (opp >= opcode + sizeof (opcode))
+ {
+ as_bad (_("no such 386 instruction: `%s'"), token_start);
+ return;
+ }
+ l++;
}
- else if (*l != PREFIX_SEPERATOR)
+ if (!is_space_char (*l)
+ && *l != END_OF_INSN
+ && *l != PREFIX_SEPARATOR)
{
- *l = opcode_chars[(unsigned char) *l]; /* fold case of opcodes */
- l++;
+ as_bad (_("invalid character %s in opcode"),
+ output_invalid (*l));
+ return;
}
- else
+ if (token_start == l)
{
- /* This opcode's got a prefix. */
- prefix_entry *prefix;
+ if (*l == PREFIX_SEPARATOR)
+ as_bad (_("expecting prefix; got nothing"));
+ else
+ as_bad (_("expecting opcode; got nothing"));
+ return;
+ }
- if (l == token_start)
- {
- as_bad (_("expecting prefix; got nothing"));
- return;
- }
- END_STRING_AND_SAVE (l);
- prefix = (prefix_entry *) hash_find (prefix_hash, token_start);
- if (!prefix)
- {
- as_bad (_("no such opcode prefix `%s'"), token_start);
- RESTORE_END_STRING (l);
- return;
- }
- RESTORE_END_STRING (l);
- /* add prefix, checking for repeated prefixes */
- switch (add_prefix (prefix->prefix_code))
+ /* Look up instruction (or prefix) via hash table. */
+ current_templates = hash_find (op_hash, opcode);
+
+ if (*l != END_OF_INSN
+ && current_templates
+ && (current_templates->start->opcode_modifier & IsPrefix) != 0)
+ {
+ /* Add prefix, checking for repeated prefixes. */
+ switch (add_prefix (current_templates->start->base_opcode))
{
case 0:
return;
case 2:
- expecting_string_instruction = prefix->prefix_name;
+ expecting_string_instruction =
+ current_templates->start->name;
break;
}
/* Skip past PREFIX_SEPARATOR and reset token_start. */
token_start = ++l;
}
- }
- END_STRING_AND_SAVE (l);
- if (token_start == l)
- {
- as_bad (_("expecting opcode; got nothing"));
- RESTORE_END_STRING (l);
- return;
+ else
+ break;
}
- /* Lookup insn in hash; try intel & att naming conventions if appropriate;
- that is: we only use the opcode suffix 'b' 'w' or 'l' if we need to. */
- current_templates = (templates *) hash_find (op_hash, token_start);
if (!current_templates)
{
- int last_index = strlen (token_start) - 1;
- char last_char = token_start[last_index];
- switch (last_char)
+ /* See if we can get a match by trimming off a suffix. */
+ switch (opp[-1])
{
case DWORD_OPCODE_SUFFIX:
case WORD_OPCODE_SUFFIX:
@@ -999,19 +965,16 @@ md_assemble (line)
#if LONG_OPCODE_SUFFIX != DWORD_OPCODE_SUFFIX
case LONG_OPCODE_SUFFIX:
#endif
- token_start[last_index] = '\0';
- current_templates = (templates *) hash_find (op_hash, token_start);
- token_start[last_index] = last_char;
- i.suffix = last_char;
+ i.suffix = opp[-1];
+ opp[-1] = '\0';
+ current_templates = hash_find (op_hash, opcode);
}
if (!current_templates)
{
as_bad (_("no such 386 instruction: `%s'"), token_start);
- RESTORE_END_STRING (l);
return;
}
}
- RESTORE_END_STRING (l);
/* check for rep/repne without a string instruction */
if (expecting_string_instruction
@@ -1026,6 +989,13 @@ md_assemble (line)
if (*l != END_OF_INSN)
{
/* parse operands */
+
+ /* 1 if operand is pending after ','. */
+ unsigned int expecting_operand = 0;
+
+ /* Non-zero if operand parens not balanced. */
+ unsigned int paren_not_balanced;
+
do
{
/* skip optional white space before operand */
@@ -1123,9 +1093,8 @@ md_assemble (line)
#define MATCH(overlap, given, template) \
((overlap) \
- && (((overlap) & (JumpAbsolute|BaseIndex)) \
- == ((given) & (JumpAbsolute|BaseIndex))))
-
+ && ((given) & BaseIndex) == ((overlap) & BaseIndex) \
+ && ((given) & JumpAbsolute) == ((template) & JumpAbsolute))
/* If given types r0 and r1 are registers they must be of the same type
unless the expected operand type register overlap is null.
@@ -1408,39 +1377,56 @@ md_assemble (line)
&& overlap0 != Imm8 && overlap0 != Imm8S
&& overlap0 != Imm16 && overlap0 != Imm32)
{
- if (!i.suffix)
+ if (i.suffix)
+ {
+ overlap0 &= (i.suffix == BYTE_OPCODE_SUFFIX ? (Imm8 | Imm8S) :
+ (i.suffix == WORD_OPCODE_SUFFIX ? Imm16 : Imm32));
+ }
+ else if (overlap0 == (Imm16 | Imm32))
+ {
+ overlap0 =
+ (flag_16bit_code ^ (i.prefix[DATA_PREFIX] != 0)) ? Imm16 : Imm32;
+ }
+ else
{
as_bad (_("no opcode suffix given; can't determine immediate size"));
return;
}
- overlap0 &= (i.suffix == BYTE_OPCODE_SUFFIX ? (Imm8 | Imm8S) :
- (i.suffix == WORD_OPCODE_SUFFIX ? Imm16 : Imm32));
}
if ((overlap1 & (Imm8 | Imm8S | Imm16 | Imm32))
&& overlap1 != Imm8 && overlap1 != Imm8S
&& overlap1 != Imm16 && overlap1 != Imm32)
{
- if (!i.suffix)
+ if (i.suffix)
+ {
+ overlap1 &= (i.suffix == BYTE_OPCODE_SUFFIX ? (Imm8 | Imm8S) :
+ (i.suffix == WORD_OPCODE_SUFFIX ? Imm16 : Imm32));
+ }
+ else if (overlap1 == (Imm16 | Imm32))
+ {
+ overlap1 =
+ (flag_16bit_code ^ (i.prefix[DATA_PREFIX] != 0)) ? Imm16 : Imm32;
+ }
+ else
{
as_bad (_("no opcode suffix given; can't determine immediate size"));
return;
}
- overlap1 &= (i.suffix == BYTE_OPCODE_SUFFIX ? (Imm8 | Imm8S) :
- (i.suffix == WORD_OPCODE_SUFFIX ? Imm16 : Imm32));
}
i.types[0] = overlap0;
- i.types[1] = overlap1;
- i.types[2] = overlap2;
-
if (overlap0 & ImplicitRegister)
i.reg_operands--;
+ if (overlap0 & Imm1)
+ i.imm_operands = 0; /* kludge for shift insns */
+
+ i.types[1] = overlap1;
if (overlap1 & ImplicitRegister)
i.reg_operands--;
+
+ i.types[2] = overlap2;
if (overlap2 & ImplicitRegister)
i.reg_operands--;
- if (overlap0 & Imm1)
- i.imm_operands = 0; /* kludge for shift insns */
/* Finalize opcode. First, we change the opcode based on the operand
size given by i.suffix: we never have to change things for byte insns,
@@ -1492,11 +1478,6 @@ md_assemble (line)
This is only for optimizing out unnecessary segment overrides. */
const seg_entry *default_seg = 0;
- /* True if this instruction uses a memory addressing mode,
- and therefore may need an address-size prefix. */
- int uses_mem_addrmode = 0;
-
-
/* If we found a reverse match we must alter the opcode
direction bit. found_reverse_match holds bits to change
(different for int & float insns). */
@@ -1612,24 +1593,63 @@ md_assemble (line)
if (! i.index_reg)
{
/* Operand is just <disp> */
- i.rm.regmem = NO_BASE_REGISTER;
- i.types[op] &= ~Disp;
- i.types[op] |= Disp32;
+ if (flag_16bit_code ^ (i.prefix[ADDR_PREFIX] != 0))
+ {
+ i.rm.regmem = NO_BASE_REGISTER_16;
+ i.types[op] &= ~Disp;
+ i.types[op] |= Disp16;
+ }
+ else
+ {
+ i.rm.regmem = NO_BASE_REGISTER;
+ i.types[op] &= ~Disp;
+ i.types[op] |= Disp32;
+ }
}
- else
+ else /* ! i.base_reg && i.index_reg */
{
- i.bi.index = i.index_reg->reg_num;
- i.bi.base = NO_BASE_REGISTER;
- i.bi.scale = i.log2_scale_factor;
+ i.sib.index = i.index_reg->reg_num;
+ i.sib.base = NO_BASE_REGISTER;
+ i.sib.scale = i.log2_scale_factor;
i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
i.types[op] &= ~Disp;
i.types[op] |= Disp32; /* Must be 32 bit */
}
}
- else /* i.base_reg */
+ else if (i.base_reg->reg_type & Reg16)
+ {
+ switch (i.base_reg->reg_num)
+ {
+ case 3: /* (%bx) */
+ if (! i.index_reg)
+ i.rm.regmem = 7;
+ else /* (%bx,%si) -> 0, or (%bx,%di) -> 1 */
+ i.rm.regmem = i.index_reg->reg_num - 6;
+ break;
+ case 5: /* (%bp) */
+ default_seg = &ss;
+ if (! i.index_reg)
+ {
+ i.rm.regmem = 6;
+ if ((i.types[op] & Disp) == 0)
+ {
+ /* fake (%bp) into 0(%bp) */
+ i.types[op] |= Disp8;
+ fake_zero_displacement = 1;
+ }
+ }
+ else /* (%bp,%si) -> 2, or (%bp,%di) -> 3 */
+ i.rm.regmem = i.index_reg->reg_num - 6 + 2;
+ break;
+ default: /* (%si) -> 4 or (%di) -> 5 */
+ i.rm.regmem = i.base_reg->reg_num - 6 + 4;
+ }
+ i.rm.mode = mode_from_disp_size (i.types[op]);
+ }
+ else /* i.base_reg and 32 bit mode */
{
i.rm.regmem = i.base_reg->reg_num;
- i.bi.base = i.base_reg->reg_num;
+ i.sib.base = i.base_reg->reg_num;
if (i.base_reg->reg_num == EBP_REG_NUM)
{
default_seg = &ss;
@@ -1643,7 +1663,7 @@ md_assemble (line)
{
default_seg = &ss;
}
- i.bi.scale = i.log2_scale_factor;
+ i.sib.scale = i.log2_scale_factor;
if (! i.index_reg)
{
/* <disp>(%esp) becomes two byte modrm
@@ -1652,7 +1672,7 @@ md_assemble (line)
ie. ESCAPE_TO_TWO_BYTE_ADDRESSING. Any
base register besides %esp will not use
the extra modrm byte. */
- i.bi.index = NO_INDEX_REGISTER;
+ i.sib.index = NO_INDEX_REGISTER;
#if ! SCALE1_WHEN_NO_INDEX
/* Another case where we force the second
modrm byte. */
@@ -1662,7 +1682,7 @@ md_assemble (line)
}
else
{
- i.bi.index = i.index_reg->reg_num;
+ i.sib.index = i.index_reg->reg_num;
i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
}
i.rm.mode = mode_from_disp_size (i.types[op]);
@@ -1716,9 +1736,6 @@ md_assemble (line)
if (i.tm.extension_opcode != None)
i.rm.reg = i.tm.extension_opcode;
}
-
- if (i.rm.mode != 3)
- uses_mem_addrmode = 1;
}
else if (i.tm.opcode_modifier & (Seg2ShortForm | Seg3ShortForm))
{
@@ -1731,10 +1748,6 @@ md_assemble (line)
}
else if ((i.tm.base_opcode & ~(D|W)) == MOV_AX_DISP32)
{
- /* This is a special non-modrm instruction
- that addresses memory with a 32-bit displacement mode anyway,
- and thus requires an address-size prefix if in 16-bit mode. */
- uses_mem_addrmode = 1;
default_seg = &ds;
}
else if ((i.tm.opcode_modifier & IsString) != 0)
@@ -1744,15 +1757,6 @@ md_assemble (line)
default_seg = &ds;
}
- /* GAS currently doesn't support 16-bit memory addressing modes at all,
- so if we're writing 16-bit code and using a memory addressing mode,
- always spew out an address size prefix. */
- if (uses_mem_addrmode && flag_16bit_code)
- {
- if (! add_prefix (ADDR_PREFIX_OPCODE))
- return;
- }
-
/* If a segment was explicitly specified,
and the specified segment is not the default,
use an opcode prefix to select it.
@@ -1787,6 +1791,16 @@ md_assemble (line)
if (i.tm.opcode_modifier & Jump)
{
unsigned long n = i.disps[0]->X_add_number;
+ int prefix = (i.prefix[DATA_PREFIX] != 0);
+ int code16 = 0;
+
+ if (prefix)
+ {
+ i.prefixes -= 1;
+ code16 = CODE16;
+ }
+ if (flag_16bit_code)
+ code16 ^= CODE16;
if (i.prefixes != 0)
as_warn (_("skipping prefixes on this instruction"));
@@ -1795,20 +1809,19 @@ md_assemble (line)
{
if (fits_in_signed_byte (n))
{
- p = frag_more (2);
insn_size += 2;
+ p = frag_more (2);
p[0] = i.tm.base_opcode;
p[1] = n;
}
else
- { /* It's an absolute word/dword displacement. */
-
+ {
/* Use 16-bit jumps only for 16-bit code,
because text segments are limited to 64K anyway;
Use 32-bit jumps for 32-bit code, because they're faster,
and a 16-bit jump will clear the top 16 bits of %eip. */
- int jmp_size = flag_16bit_code ? 2 : 4;
- if (flag_16bit_code && !fits_in_signed_word (n))
+ int jmp_size = code16 ? 2 : 4;
+ if (code16 && !fits_in_signed_word (n))
{
as_bad (_("16-bit jump out of range"));
return;
@@ -1817,43 +1830,45 @@ md_assemble (line)
if (i.tm.base_opcode == JUMP_PC_RELATIVE)
{ /* pace */
/* unconditional jump */
- p = frag_more (1 + jmp_size);
- insn_size += 1 + jmp_size;
- p[0] = (char) 0xe9;
- md_number_to_chars (&p[1], (valueT) n, jmp_size);
+ insn_size += prefix + 1 + jmp_size;
+ p = frag_more (prefix + 1 + jmp_size);
+ if (prefix)
+ *p++ = DATA_PREFIX_OPCODE;
+ *p++ = (char) 0xe9;
+ md_number_to_chars (p, (valueT) n, jmp_size);
}
else
{
/* conditional jump */
- p = frag_more (2 + jmp_size);
- insn_size += 2 + jmp_size;
- p[0] = TWO_BYTE_OPCODE_ESCAPE;
- p[1] = i.tm.base_opcode + 0x10;
- md_number_to_chars (&p[2], (valueT) n, jmp_size);
+ insn_size += prefix + 2 + jmp_size;
+ p = frag_more (prefix + 2 + jmp_size);
+ if (prefix)
+ *p++ = DATA_PREFIX_OPCODE;
+ *p++ = TWO_BYTE_OPCODE_ESCAPE;
+ *p++ = i.tm.base_opcode + 0x10;
+ md_number_to_chars (p, (valueT) n, jmp_size);
}
}
}
else
{
- if (flag_16bit_code)
- {
- FRAG_APPEND_1_CHAR (DATA_PREFIX_OPCODE);
- insn_size += 1;
- }
+ int size = code16 ? 2 : 4;
/* It's a symbol; end frag & setup for relax.
Make sure there are more than 6 chars left in the current frag;
if not we'll have to start a new one. */
- frag_grow (7);
- p = frag_more (1);
- insn_size += 1;
- p[0] = i.tm.base_opcode;
+ frag_grow (prefix + 1 + 2 + size);
+ insn_size += 1 + prefix;
+ p = frag_more (1 + prefix);
+ if (prefix)
+ *p++ = DATA_PREFIX_OPCODE;
+ *p = i.tm.base_opcode;
frag_var (rs_machine_dependent,
- 6, /* 2 opcode/prefix + 4 displacement */
+ prefix + 2 + size, /* 2 opcode/prefix + displacement */
1,
((unsigned char) *p == JUMP_PC_RELATIVE
- ? ENCODE_RELAX_STATE (UNCOND_JUMP, BYTE)
- : ENCODE_RELAX_STATE (COND_JUMP, BYTE)),
+ ? ENCODE_RELAX_STATE (UNCOND_JUMP, SMALL) | code16
+ : ENCODE_RELAX_STATE (COND_JUMP, SMALL) | code16),
i.disps[0]->X_add_symbol,
(offsetT) n, p);
}
@@ -1867,45 +1882,58 @@ md_assemble (line)
{
if (i.prefix[ADDR_PREFIX])
{
+ insn_size += 1;
FRAG_APPEND_1_CHAR (ADDR_PREFIX_OPCODE);
+ i.prefixes -= 1;
+ }
+ }
+ else
+ {
+ int code16 = 0;
+
+ if (i.prefix[DATA_PREFIX])
+ {
insn_size += 1;
+ FRAG_APPEND_1_CHAR (DATA_PREFIX_OPCODE);
i.prefixes -= 1;
+ code16 = CODE16;
}
+ if (flag_16bit_code)
+ code16 ^= CODE16;
+
+ if (code16)
+ size = 2;
}
if (i.prefixes != 0)
as_warn (_("skipping prefixes on this instruction"));
- if (size == 4 && flag_16bit_code)
- {
- FRAG_APPEND_1_CHAR (DATA_PREFIX_OPCODE);
- insn_size += 1;
- }
-
if (fits_in_unsigned_byte (i.tm.base_opcode))
{
- FRAG_APPEND_1_CHAR (i.tm.base_opcode);
- insn_size += 1;
+ insn_size += 1 + size;
+ p = frag_more (1 + size);
}
else
{
- p = frag_more (2); /* opcode can be at most two bytes */
- insn_size += 2;
- /* put out high byte first: can't use md_number_to_chars! */
+ insn_size += 2 + size; /* opcode can be at most two bytes */
+ p = frag_more (2 + size);
*p++ = (i.tm.base_opcode >> 8) & 0xff;
- *p = i.tm.base_opcode & 0xff;
}
+ *p++ = i.tm.base_opcode & 0xff;
- p = frag_more (size);
- insn_size += size;
if (i.disps[0]->X_op == O_constant)
{
- md_number_to_chars (p, (valueT) n, size);
if (size == 1 && !fits_in_signed_byte (n))
{
as_bad (_("`%s' only takes byte displacement; %lu shortened to %d"),
i.tm.name, n, *p);
}
+ else if (size == 2 && !fits_in_signed_word (n))
+ {
+ as_bad (_("16-bit jump out of range"));
+ return;
+ }
+ md_number_to_chars (p, (valueT) n, size);
}
else
{
@@ -1916,26 +1944,52 @@ md_assemble (line)
}
else if (i.tm.opcode_modifier & JumpInterSegment)
{
- if (i.prefixes != 0)
- as_warn (_("skipping prefixes on this instruction"));
+ int size;
+ int reloc_type;
+ int prefix = i.prefix[DATA_PREFIX] != 0;
+ int code16 = 0;
+ if (prefix)
+ {
+ code16 = CODE16;
+ i.prefixes -= 1;
+ }
if (flag_16bit_code)
+ code16 ^= CODE16;
+
+ size = 4;
+ reloc_type = BFD_RELOC_32;
+ if (code16)
{
- FRAG_APPEND_1_CHAR (DATA_PREFIX_OPCODE);
- insn_size += 1;
+ size = 2;
+ reloc_type = BFD_RELOC_16;
}
- p = frag_more (1 + 2 + 4); /* 1 opcode; 2 segment; 4 offset */
- insn_size += 1 + 2 + 4;
- p[0] = i.tm.base_opcode;
+ if (i.prefixes != 0)
+ as_warn (_("skipping prefixes on this instruction"));
+
+ insn_size += prefix + 1 + 2 + size; /* 1 opcode; 2 segment; offset */
+ p = frag_more (prefix + 1 + 2 + size);
+ if (prefix)
+ *p++ = DATA_PREFIX_OPCODE;
+ *p++ = i.tm.base_opcode;
if (i.imms[1]->X_op == O_constant)
- md_number_to_chars (p + 1, (valueT) i.imms[1]->X_add_number, 4);
+ {
+ unsigned long n = i.imms[1]->X_add_number;
+ if (size == 2 && !fits_in_unsigned_word (n))
+ {
+ as_bad (_("16-bit jump out of range"));
+ return;
+ }
+ md_number_to_chars (p, (valueT) n, size);
+ }
else
- fix_new_exp (frag_now, p + 1 - frag_now->fr_literal, 4,
- i.imms[1], 0, BFD_RELOC_32);
+ fix_new_exp (frag_now, p - frag_now->fr_literal, size,
+ i.imms[1], 0, reloc_type);
if (i.imms[0]->X_op != O_constant)
- as_bad (_("can't handle non absolute segment in long call/jmp"));
- md_number_to_chars (p + 5, (valueT) i.imms[0]->X_add_number, 2);
+ as_bad (_("can't handle non absolute segment in `%s'"),
+ i.tm.name);
+ md_number_to_chars (p + size, (valueT) i.imms[0]->X_add_number, 2);
}
else
{
@@ -1949,8 +2003,8 @@ md_assemble (line)
{
if (*q)
{
- p = frag_more (1);
insn_size += 1;
+ p = frag_more (1);
md_number_to_chars (p, (valueT) *q, 1);
}
}
@@ -1958,13 +2012,13 @@ md_assemble (line)
/* Now the opcode; be careful about word order here! */
if (fits_in_unsigned_byte (i.tm.base_opcode))
{
- FRAG_APPEND_1_CHAR (i.tm.base_opcode);
insn_size += 1;
+ FRAG_APPEND_1_CHAR (i.tm.base_opcode);
}
else if (fits_in_unsigned_word (i.tm.base_opcode))
{
- p = frag_more (2);
insn_size += 2;
+ p = frag_more (2);
/* put out high byte first: can't use md_number_to_chars! */
*p++ = (i.tm.base_opcode >> 8) & 0xff;
*p = i.tm.base_opcode & 0xff;
@@ -1973,26 +2027,25 @@ md_assemble (line)
{ /* opcode is either 3 or 4 bytes */
if (i.tm.base_opcode & 0xff000000)
{
- p = frag_more (4);
insn_size += 4;
+ p = frag_more (4);
*p++ = (i.tm.base_opcode >> 24) & 0xff;
}
else
{
- p = frag_more (3);
insn_size += 3;
+ p = frag_more (3);
}
*p++ = (i.tm.base_opcode >> 16) & 0xff;
*p++ = (i.tm.base_opcode >> 8) & 0xff;
*p = (i.tm.base_opcode) & 0xff;
}
- /* Now the modrm byte and base index byte (if present). */
+ /* Now the modrm byte and sib byte (if present). */
if (i.tm.opcode_modifier & Modrm)
{
- p = frag_more (1);
insn_size += 1;
- /* md_number_to_chars (p, i.rm, 1); */
+ p = frag_more (1);
md_number_to_chars (p,
(valueT) (i.rm.regmem << 0
| i.rm.reg << 3
@@ -2000,16 +2053,18 @@ md_assemble (line)
1);
/* If i.rm.regmem == ESP (4)
&& i.rm.mode != (Register mode)
+ && not 16 bit
==> need second modrm byte. */
if (i.rm.regmem == ESCAPE_TO_TWO_BYTE_ADDRESSING
- && i.rm.mode != 3)
+ && i.rm.mode != 3
+ && !(i.base_reg && (i.base_reg->reg_type & Reg16) != 0))
{
- p = frag_more (1);
insn_size += 1;
- /* md_number_to_chars (p, i.bi, 1); */
- md_number_to_chars (p, (valueT) (i.bi.base << 0
- | i.bi.index << 3
- | i.bi.scale << 6),
+ p = frag_more (1);
+ md_number_to_chars (p,
+ (valueT) (i.sib.base << 0
+ | i.sib.index << 3
+ | i.sib.scale << 6),
1);
}
}
@@ -2026,37 +2081,44 @@ md_assemble (line)
{
if (i.types[n] & Disp8)
{
- p = frag_more (1);
insn_size += 1;
+ p = frag_more (1);
md_number_to_chars (p,
(valueT) i.disps[n]->X_add_number,
1);
}
else if (i.types[n] & Disp16)
{
- p = frag_more (2);
insn_size += 2;
+ p = frag_more (2);
md_number_to_chars (p,
(valueT) i.disps[n]->X_add_number,
2);
}
else
{ /* Disp32 */
- p = frag_more (4);
insn_size += 4;
+ p = frag_more (4);
md_number_to_chars (p,
(valueT) i.disps[n]->X_add_number,
4);
}
}
- else
- { /* not absolute_section */
- /* need a 32-bit fixup (don't support 8bit non-absolute disps) */
- p = frag_more (4);
+ else if (i.types[n] & Disp32)
+ {
insn_size += 4;
+ p = frag_more (4);
fix_new_exp (frag_now, p - frag_now->fr_literal, 4,
- i.disps[n], 0,
- TC_RELOC(i.disp_reloc[n], BFD_RELOC_32));
+ i.disps[n], 0,
+ TC_RELOC (i.disp_reloc[n], BFD_RELOC_32));
+ }
+ else
+ { /* must be Disp16 */
+ insn_size += 2;
+ p = frag_more (2);
+ fix_new_exp (frag_now, p - frag_now->fr_literal, 2,
+ i.disps[n], 0,
+ TC_RELOC (i.disp_reloc[n], BFD_RELOC_16));
}
}
}
@@ -2075,24 +2137,24 @@ md_assemble (line)
{
if (i.types[n] & (Imm8 | Imm8S))
{
- p = frag_more (1);
insn_size += 1;
+ p = frag_more (1);
md_number_to_chars (p,
(valueT) i.imms[n]->X_add_number,
1);
}
else if (i.types[n] & Imm16)
{
- p = frag_more (2);
insn_size += 2;
+ p = frag_more (2);
md_number_to_chars (p,
(valueT) i.imms[n]->X_add_number,
2);
}
else
{
- p = frag_more (4);
insn_size += 4;
+ p = frag_more (4);
md_number_to_chars (p,
(valueT) i.imms[n]->X_add_number,
4);
@@ -2113,9 +2175,9 @@ md_assemble (line)
size = 2;
else
size = 4;
- r_type = reloc (size, 0, i.disp_reloc[0]);
- p = frag_more (size);
insn_size += size;
+ p = frag_more (size);
+ r_type = reloc (size, 0, i.disp_reloc[0]);
#ifdef BFD_ASSEMBLER
if (r_type == BFD_RELOC_32
&& GOT_symbol
@@ -2155,13 +2217,6 @@ i386_operand (operand_string)
{
register char *op_string = operand_string;
- /* Address of '\0' at end of operand_string. */
- char *end_of_operand_string = operand_string + strlen (operand_string);
-
- /* Start and end of displacement string expression (if found). */
- char *displacement_string_start = NULL;
- char *displacement_string_end = NULL;
-
/* We check for an absolute prefix (differentiating,
for example, 'jmp pc_relative_label' from 'jmp *absolute_label'. */
if (*op_string == ABSOLUTE_PREFIX)
@@ -2173,7 +2228,7 @@ i386_operand (operand_string)
/* Check if operand is a register. */
if (*op_string == REGISTER_PREFIX)
{
- register reg_entry *r;
+ register const reg_entry *r;
if (!(r = parse_register (op_string)))
{
as_bad (_("bad register name `%s'"), op_string);
@@ -2186,22 +2241,22 @@ i386_operand (operand_string)
switch (r->reg_num)
{
case 0:
- i.seg[i.mem_operands] = (seg_entry *) & es;
+ i.seg[i.mem_operands] = &es;
break;
case 1:
- i.seg[i.mem_operands] = (seg_entry *) & cs;
+ i.seg[i.mem_operands] = &cs;
break;
case 2:
- i.seg[i.mem_operands] = (seg_entry *) & ss;
+ i.seg[i.mem_operands] = &ss;
break;
case 3:
- i.seg[i.mem_operands] = (seg_entry *) & ds;
+ i.seg[i.mem_operands] = &ds;
break;
case 4:
- i.seg[i.mem_operands] = (seg_entry *) & fs;
+ i.seg[i.mem_operands] = &fs;
break;
case 5:
- i.seg[i.mem_operands] = (seg_entry *) & gs;
+ i.seg[i.mem_operands] = &gs;
break;
}
op_string += 4; /* skip % <x> s : */
@@ -2268,7 +2323,7 @@ i386_operand (operand_string)
else if (exp->X_op == O_constant)
{
i.types[this_operand] |=
- smallest_imm_type ((unsigned long) exp->X_add_number);
+ smallest_imm_type ((long) exp->X_add_number);
}
#ifdef OBJ_AOUT
else if (exp_seg != text_section
@@ -2287,8 +2342,9 @@ i386_operand (operand_string)
#endif
else
{
- /* this is an address ==> 32bit */
- i.types[this_operand] |= Imm32;
+ /* This is an address. */
+ i.types[this_operand] |=
+ (flag_16bit_code ^ (i.prefix[DATA_PREFIX] != 0)) ? Imm16 : Imm32;
}
/* shorten this type of this operand if the instruction wants
* fewer bits than are present in the immediate. The bit field
@@ -2309,9 +2365,14 @@ i386_operand (operand_string)
|| *op_string == '(')
{
/* This is a memory reference of some sort. */
+ char *end_of_operand_string;
register char *base_string;
int found_base_index_form;
+ /* Start and end of displacement string expression (if found). */
+ char *displacement_string_start;
+ char *displacement_string_end;
+
do_memory_reference:
if ((i.mem_operands == 1
&& (current_templates->start->opcode_modifier & IsString) == 0)
@@ -2326,8 +2387,9 @@ i386_operand (operand_string)
looking for an ')' at the end of the operand, searching
for the '(' matching it, and finding a REGISTER_PREFIX or ','
after it. */
- base_string = end_of_operand_string - 1;
found_base_index_form = 0;
+ end_of_operand_string = op_string + strlen (op_string);
+ base_string = end_of_operand_string - 1;
if (*base_string == ')')
{
unsigned int parens_balanced = 1;
@@ -2363,6 +2425,7 @@ i386_operand (operand_string)
i.types[this_operand] |= BaseIndex;
/* If there is a displacement set-up for it to be parsed later. */
+ displacement_string_start = NULL;
if (base_string != op_string + 1)
{
displacement_string_start = op_string;
@@ -2483,6 +2546,11 @@ i386_operand (operand_string)
register expressionS *exp;
segT exp_seg = 0;
char *save_input_line_pointer;
+ int bigdisp = Disp32;
+
+ if (flag_16bit_code ^ (i.prefix[ADDR_PREFIX] != 0))
+ bigdisp = Disp16;
+ i.types[this_operand] |= bigdisp;
exp = &disp_expressions[i.disp_operands];
i.disps[this_operand] = exp;
@@ -2491,7 +2559,51 @@ i386_operand (operand_string)
save_input_line_pointer = input_line_pointer;
input_line_pointer = displacement_string_start;
END_STRING_AND_SAVE (displacement_string_end);
+#ifndef GCC_ASM_O_HACK
+#define GCC_ASM_O_HACK 0
+#endif
+#if GCC_ASM_O_HACK
+ END_STRING_AND_SAVE (displacement_string_end + 1);
+ if ((i.types[this_operand] & BaseIndex) != 0
+ && displacement_string_end[-1] == '+')
+ {
+ /* This hack is to avoid a warning when using the "o"
+ constraint within gcc asm statements.
+ For instance:
+
+ #define _set_tssldt_desc(n,addr,limit,type) \
+ __asm__ __volatile__ ( \
+ "movw %w2,%0\n\t" \
+ "movw %w1,2+%0\n\t" \
+ "rorl $16,%1\n\t" \
+ "movb %b1,4+%0\n\t" \
+ "movb %4,5+%0\n\t" \
+ "movb $0,6+%0\n\t" \
+ "movb %h1,7+%0\n\t" \
+ "rorl $16,%1" \
+ : "=o"(*(n)) : "q" (addr), "ri"(limit), "i"(type))
+
+ This works great except that the output assembler ends
+ up looking a bit weird if it turns out that there is
+ no offset. You end up producing code that looks like:
+
+ #APP
+ movw $235,(%eax)
+ movw %dx,2+(%eax)
+ rorl $16,%edx
+ movb %dl,4+(%eax)
+ movb $137,5+(%eax)
+ movb $0,6+(%eax)
+ movb %dh,7+(%eax)
+ rorl $16,%edx
+ #NO_APP
+
+ So here we provide the missing zero.
+ */
+ *displacement_string_end = '0';
+ }
+#endif
#ifndef LEX_AT
{
/*
@@ -2539,6 +2651,10 @@ i386_operand (operand_string)
else
as_bad (_("Bad reloc specifier `%s' in expression"), cp + 1);
+ /* GOT relocations are not supported in 16 bit mode */
+ if (flag_16bit_code)
+ as_bad (_("GOT relocations not supported in 16 bit mode"));
+
input_line_pointer = tmpbuf;
}
}
@@ -2565,6 +2681,9 @@ i386_operand (operand_string)
if (*input_line_pointer)
as_bad (_("Ignoring junk `%s' after expression"),
input_line_pointer);
+#if GCC_ASM_O_HACK
+ RESTORE_END_STRING (displacement_string_end + 1);
+#endif
RESTORE_END_STRING (displacement_string_end);
input_line_pointer = save_input_line_pointer;
@@ -2574,33 +2693,28 @@ i386_operand (operand_string)
/* missing expr becomes absolute 0 */
as_bad (_("missing or invalid displacement `%s' taken as 0"),
operand_string);
- i.types[this_operand] |= Disp;
exp->X_op = O_constant;
exp->X_add_number = 0;
exp->X_add_symbol = (symbolS *) 0;
exp->X_op_symbol = (symbolS *) 0;
+ i.types[this_operand] |= Disp8;
}
else
#endif
if (exp->X_op == O_constant)
{
- i.types[this_operand] |= SMALLEST_DISP_TYPE (exp->X_add_number);
- }
- else if (exp_seg == text_section
- || exp_seg == data_section
- || exp_seg == bss_section
- || exp_seg == undefined_section)
- {
- i.types[this_operand] |= Disp32;
+ if (fits_in_signed_byte (exp->X_add_number))
+ i.types[this_operand] |= Disp8;
}
- else
+#ifdef OBJ_AOUT
+ else if (exp_seg != text_section
+ && exp_seg != data_section
+ && exp_seg != bss_section
+ && exp_seg != undefined_section)
{
-#ifndef OBJ_AOUT
- i.types[this_operand] |= Disp32;
-#else
goto seg_unimplemented;
-#endif
}
+#endif
}
/* Special case for (%dx) while doing input/output op. */
@@ -2615,15 +2729,36 @@ i386_operand (operand_string)
return 1;
}
/* Make sure the memory operand we've been dealt is valid. */
- if ((i.base_reg
- && (i.base_reg->reg_type & Reg32) == 0)
- || (i.index_reg
- && ((i.index_reg->reg_type & (Reg32|BaseIndex))
- != (Reg32|BaseIndex))))
+ if (flag_16bit_code ^ (i.prefix[ADDR_PREFIX] != 0))
{
- as_bad (_("`%s' is not a valid %s bit base/index expression"),
- operand_string, "32");
- return 0;
+ if ((i.base_reg
+ && ((i.base_reg->reg_type & (Reg16|BaseIndex))
+ != (Reg16|BaseIndex)))
+ || (i.index_reg
+ && (((i.index_reg->reg_type & (Reg16|BaseIndex))
+ != (Reg16|BaseIndex))
+ || ! (i.base_reg
+ && i.base_reg->reg_num < 6
+ && i.index_reg->reg_num >= 6
+ && i.log2_scale_factor == 0))))
+ {
+ as_bad (_("`%s' is not a valid %s bit base/index expression"),
+ operand_string, "16");
+ return 0;
+ }
+ }
+ else
+ {
+ if ((i.base_reg
+ && (i.base_reg->reg_type & Reg32) == 0)
+ || (i.index_reg
+ && ((i.index_reg->reg_type & (Reg32|BaseIndex))
+ != (Reg32|BaseIndex))))
+ {
+ as_bad (_("`%s' is not a valid %s bit base/index expression"),
+ operand_string, "32");
+ return 0;
+ }
}
i.mem_operands++;
}
@@ -2665,12 +2800,16 @@ md_estimate_size_before_relax (fragP, segment)
if (S_GET_SEGMENT (fragP->fr_symbol) != segment)
{
/* symbol is undefined in this segment */
+ int code16 = fragP->fr_subtype & CODE16;
+ int size = code16 ? 2 : 4;
+ int pcrel_reloc = code16 ? BFD_RELOC_16_PCREL : BFD_RELOC_32_PCREL;
+
switch (opcode[0])
{
case JUMP_PC_RELATIVE: /* make jmp (0xeb) a dword displacement jump */
opcode[0] = 0xe9; /* dword disp jmp */
- fragP->fr_fix += 4;
- fix_new (fragP, old_fr_fix, 4,
+ fragP->fr_fix += size;
+ fix_new (fragP, old_fr_fix, size,
fragP->fr_symbol,
fragP->fr_offset, 1,
(GOT_symbol && /* Not quite right - we should switch on
@@ -2680,8 +2819,8 @@ md_estimate_size_before_relax (fragP, segment)
get it right all of the time, but I
think it does not matter that much, as
this will be right most of the time. ERY*/
- S_GET_SEGMENT(fragP->fr_symbol) == undefined_section)?
- BFD_RELOC_386_PLT32 : BFD_RELOC_32_PCREL);
+ S_GET_SEGMENT(fragP->fr_symbol) == undefined_section)
+ ? BFD_RELOC_386_PLT32 : pcrel_reloc);
break;
default:
@@ -2689,15 +2828,15 @@ md_estimate_size_before_relax (fragP, segment)
the dword-displacement jump 0x0f8N */
opcode[1] = opcode[0] + 0x10;
opcode[0] = TWO_BYTE_OPCODE_ESCAPE; /* two-byte escape */
- fragP->fr_fix += 1 + 4; /* we've added an opcode byte */
- fix_new (fragP, old_fr_fix + 1, 4,
+ fragP->fr_fix += 1 + size; /* we've added an opcode byte */
+ fix_new (fragP, old_fr_fix + 1, size,
fragP->fr_symbol,
- fragP->fr_offset, 1,
+ fragP->fr_offset, 1,
(GOT_symbol && /* Not quite right - we should switch on
presence of @PLT, but I cannot see how
to get to that from here. ERY */
- S_GET_SEGMENT(fragP->fr_symbol) == undefined_section)?
- BFD_RELOC_386_PLT32 : BFD_RELOC_32_PCREL);
+ S_GET_SEGMENT(fragP->fr_symbol) == undefined_section)
+ ? BFD_RELOC_386_PLT32 : pcrel_reloc);
break;
}
frag_wane (fragP);
@@ -2753,38 +2892,38 @@ md_convert_frag (abfd, sec, fragP)
switch (fragP->fr_subtype)
{
- case ENCODE_RELAX_STATE (COND_JUMP, BYTE):
- case ENCODE_RELAX_STATE (UNCOND_JUMP, BYTE):
+ 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, WORD):
- opcode[1] = TWO_BYTE_OPCODE_ESCAPE;
- opcode[2] = opcode[0] + 0x10;
- opcode[0] = DATA_PREFIX_OPCODE;
- extension = 4; /* 3 opcode + 2 displacement */
- where_to_put_displacement = &opcode[3];
+ 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, WORD):
- opcode[1] = 0xe9;
- opcode[0] = DATA_PREFIX_OPCODE;
- extension = 3; /* 2 opcode + 2 displacement */
- where_to_put_displacement = &opcode[2];
+ 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, DWORD):
+ case ENCODE_RELAX_STATE (COND_JUMP, BIG16):
+ extension = 3; /* 2 opcode + 2 displacement */
opcode[1] = opcode[0] + 0x10;
opcode[0] = TWO_BYTE_OPCODE_ESCAPE;
- extension = 5; /* 2 opcode + 4 displacement */
where_to_put_displacement = &opcode[2];
break;
- case ENCODE_RELAX_STATE (UNCOND_JUMP, DWORD):
+ case ENCODE_RELAX_STATE (UNCOND_JUMP, BIG16):
+ extension = 2; /* 1 opcode + 2 displacement */
opcode[0] = 0xe9;
- extension = 4; /* 1 opcode + 4 displacement */
where_to_put_displacement = &opcode[1];
break;
@@ -2903,7 +3042,7 @@ md_apply_fix3 (fixP, valp, seg)
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
if (OUTPUT_FLAVOR == bfd_target_elf_flavour
&& fixP->fx_addsy)
- switch(fixP->fx_r_type) {
+ switch (fixP->fx_r_type) {
case BFD_RELOC_386_PLT32:
/* Make the jump instruction point to the address of the operand. At
runtime we merely add the offset to the actual PLT entry. */
@@ -3051,23 +3190,22 @@ output_invalid (c)
}
/* reg_string starts *before* REGISTER_PREFIX */
-static reg_entry *
+static const reg_entry *
parse_register (reg_string)
- char *reg_string;
+ const char *reg_string;
{
- register char *s = reg_string;
+ register const char *s = reg_string;
register char *p;
char reg_name_given[MAX_REG_NAME_SIZE];
s++; /* skip REGISTER_PREFIX */
- for (p = reg_name_given; is_register_char (*s); p++, s++)
+ p = reg_name_given;
+ while ((*p++ = register_chars[(unsigned char) *s++]) != '\0')
{
- *p = register_chars[(unsigned char) *s];
if (p >= reg_name_given + MAX_REG_NAME_SIZE)
- return (reg_entry *) 0;
+ return (const reg_entry *) NULL;
}
- *p = '\0';
- return (reg_entry *) hash_find (reg_hash, reg_name_given);
+ return (const reg_entry *) hash_find (reg_hash, reg_name_given);
}
#ifdef OBJ_ELF
@@ -3078,7 +3216,7 @@ CONST char *md_shortopts = "m";
struct option md_longopts[] = {
{NULL, no_argument, NULL, 0}
};
-size_t md_longopts_size = sizeof(md_longopts);
+size_t md_longopts_size = sizeof (md_longopts);
int
md_parse_option (c, arg)
@@ -3154,11 +3292,11 @@ md_undefined_symbol (name)
if (*name == '_' && *(name+1) == 'G'
&& strcmp(name, GLOBAL_OFFSET_TABLE_NAME) == 0)
{
- if(!GOT_symbol)
+ if (!GOT_symbol)
{
- if(symbol_find(name))
+ if (symbol_find (name))
as_bad (_("GOT already in symbol table"));
- GOT_symbol = symbol_new (name, undefined_section,
+ GOT_symbol = symbol_new (name, undefined_section,
(valueT) 0, &zero_address_frag);
};
return GOT_symbol;
diff --git a/gas/config/tc-i386.h b/gas/config/tc-i386.h
index 34c8bb7..11a4d32 100644
--- a/gas/config/tc-i386.h
+++ b/gas/config/tc-i386.h
@@ -179,7 +179,6 @@ extern int tc_coff_sizemachdep PARAMS ((fragS *frag));
#define REGISTER_PREFIX '%'
#define IMMEDIATE_PREFIX '$'
#define ABSOLUTE_PREFIX '*'
-#define PREFIX_SEPERATOR '/'
#define TWO_BYTE_OPCODE_ESCAPE 0x0f
#define NOP_OPCODE (char) 0x90
@@ -194,6 +193,7 @@ extern int tc_coff_sizemachdep PARAMS ((fragS *frag));
#define NO_INDEX_REGISTER ESP_REG_NUM
/* index_base_byte.base for no base register addressing */
#define NO_BASE_REGISTER EBP_REG_NUM
+#define NO_BASE_REGISTER_16 6
/* these are the opcode suffixes, making movl --> mov, for example */
#define DWORD_OPCODE_SUFFIX 'l'
@@ -322,6 +322,7 @@ typedef struct
#define FWait 0x100000 /* instruction needs FWAIT */
#define IsString 0x200000 /* quick test for string instructions */
#define regKludge 0x400000 /* fake an extra reg operand for clr, imul */
+#define IsPrefix 0x800000 /* opcode is a prefix */
#define Ugh 0x80000000 /* deprecated fp insn, gets a warning */
/* operand_types[i] describes the type of operand i. This is made
@@ -341,8 +342,8 @@ template;
*/
typedef struct
{
- template *start;
- template *end;
+ const template *start;
+ const template *end;
} templates;
/* these are for register name --> number & type hash lookup */
@@ -352,7 +353,6 @@ typedef struct
unsigned int reg_type;
unsigned int reg_num;
}
-
reg_entry;
typedef struct
@@ -360,37 +360,25 @@ typedef struct
char *seg_name;
unsigned int seg_prefix;
}
-
seg_entry;
-/* these are for prefix name --> prefix code hash lookup */
-typedef struct
- {
- char *prefix_name;
- unsigned char prefix_code;
- }
-
-prefix_entry;
-
/* 386 operand encoding bytes: see 386 book for details of this. */
typedef struct
{
- unsigned regmem:3; /* codes register or memory operand */
- unsigned reg:3; /* codes register operand (or extended opcode) */
- unsigned mode:2; /* how to interpret regmem & reg */
+ unsigned int regmem; /* codes register or memory operand */
+ unsigned int reg; /* codes register operand (or extended opcode) */
+ unsigned int mode; /* how to interpret regmem & reg */
}
-
modrm_byte;
/* 386 opcode byte to code indirect addressing. */
typedef struct
{
- unsigned base:3;
- unsigned index:3;
- unsigned scale:2;
+ unsigned base;
+ unsigned index;
+ unsigned scale;
}
-
-base_index_byte;
+sib_byte;
/* The name of the global offset table generated by the compiler. Allow
this to be overridden if need be. */