tc-i386.c tidy
Alan Modra
amodra@bigpond.net.au
Fri Mar 8 21:36:00 GMT 2002
This is a long overdue tidy of tc-i386.c. Main feature of the patch
is to split the >1900 line md_assemble into 22 separate functions.
gas/ChangeLog
* config/tc-i386.h (REX_OPCODE): Define.
(REX_MODE64, REX_EXTX, REX_EXTY, REX_EXTZ): Define.
(rex_byte): typedef to int.
* config/tc-i386.c: Group prototypes and vars together.
Formatting fixes. Remove occurrences of "register" keyword.
(true): Delete.
(false): Delete.
(mode_from_disp_size): Add INLINE keyword to prototype.
(fits_in_signed_byte): Likewise.
(fits_in_unsigned_byte): Likewise.
(fits_in_unsigned_word): Likewise.
(fits_in_signed_word): Likewise.
(fits_in_unsigned_long): Likewise.
(fits_in_signed_long): Likewise.
(type_names): Constify.
(intel_float_operand): Constify param.
(add_prefix): Use REX_OPCODE.
(md_assemble): Likewise. Modify for changed rex_byte.
(parse_insn): Split out of md_assemble.
(parse_operands): Likewise.
(swap_operands): Likewise.
(optimize_imm): Likewise.
(optimize_disp): Likewise.
(match_template): Likewise.
(check_string): Likewise.
(process_suffix): Likewise.
(check_byte_reg): Likewise.
(check_long_reg): Likewise.
(check_qword_reg): Likewise.
(check_word_reg): Likewise.
(finalize_imm): Likewise.
(process_operands): Likewise.
(build_modrm_byte): Likewise.
(output_insn): Likewise.
(output_branch): Likewise.
(output_jump): Likewise.
(output_interseg_jump): Likewise.
(output_disp): Likewise.
(output_imm): Likewise.
--
Alan Modra
IBM OzLabs - Linux Technology Centre
Index: gas/config/tc-i386.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-i386.c,v
retrieving revision 1.112
diff -u -p -w -r1.112 tc-i386.c
--- tc-i386.c 2002/03/06 04:59:36 1.112
+++ tc-i386.c 2002/03/09 05:16:13
@@ -48,20 +48,23 @@
#define SCALE1_WHEN_NO_INDEX 1
#endif
-#ifndef true
-#define true 1
+#ifdef BFD_ASSEMBLER
+#define RELOC_ENUM enum bfd_reloc_code_real
+#else
+#define RELOC_ENUM int
#endif
-#ifndef false
-#define false 0
+
+#ifndef DEFAULT_ARCH
+#define DEFAULT_ARCH "i386"
#endif
-static unsigned int mode_from_disp_size PARAMS ((unsigned int));
-static int fits_in_signed_byte PARAMS ((offsetT));
-static int fits_in_unsigned_byte PARAMS ((offsetT));
-static int fits_in_unsigned_word PARAMS ((offsetT));
-static int fits_in_signed_word PARAMS ((offsetT));
-static int fits_in_unsigned_long PARAMS ((offsetT));
-static int fits_in_signed_long PARAMS ((offsetT));
+static INLINE unsigned int mode_from_disp_size PARAMS ((unsigned int));
+static INLINE int fits_in_signed_byte PARAMS ((offsetT));
+static INLINE int fits_in_unsigned_byte PARAMS ((offsetT));
+static INLINE int fits_in_unsigned_word PARAMS ((offsetT));
+static INLINE int fits_in_signed_word PARAMS ((offsetT));
+static INLINE int fits_in_unsigned_long PARAMS ((offsetT));
+static INLINE int fits_in_signed_long PARAMS ((offsetT));
static int smallest_imm_type PARAMS ((offsetT));
static offsetT offset_in_range PARAMS ((offsetT, int));
static int add_prefix PARAMS ((unsigned int));
@@ -69,18 +72,36 @@ static void set_code_flag PARAMS ((int))
static void set_16bit_gcc_code_flag PARAMS ((int));
static void set_intel_syntax PARAMS ((int));
static void set_cpu_arch PARAMS ((int));
-
-#ifdef BFD_ASSEMBLER
-static bfd_reloc_code_real_type reloc
- PARAMS ((int, int, int, bfd_reloc_code_real_type));
-#define RELOC_ENUM enum bfd_reloc_code_real
-#else
-#define RELOC_ENUM int
+static char *output_invalid PARAMS ((int c));
+static int i386_operand PARAMS ((char *operand_string));
+static int i386_intel_operand PARAMS ((char *operand_string, int got_a_float));
+static const reg_entry *parse_register PARAMS ((char *reg_string,
+ char **end_op));
+static char *parse_insn PARAMS ((char *, char *));
+static char *parse_operands PARAMS ((char *, const char *));
+static void swap_operands PARAMS ((void));
+static void optimize_imm PARAMS ((void));
+static void optimize_disp PARAMS ((void));
+static int match_template PARAMS ((void));
+static int check_string PARAMS ((void));
+static int process_suffix PARAMS ((void));
+static int check_byte_reg PARAMS ((void));
+static int check_long_reg PARAMS ((void));
+static int check_qword_reg PARAMS ((void));
+static int check_word_reg PARAMS ((void));
+static int finalize_imm PARAMS ((void));
+static int process_operands PARAMS ((void));
+static const seg_entry *build_modrm_byte PARAMS ((void));
+static void output_insn PARAMS ((void));
+static void output_branch PARAMS ((void));
+static void output_jump PARAMS ((void));
+static void output_interseg_jump PARAMS ((void));
+static void output_imm PARAMS ((void));
+static void output_disp PARAMS ((void));
+#ifndef I386COFF
+static void s_bss PARAMS ((int));
#endif
-#ifndef DEFAULT_ARCH
-#define DEFAULT_ARCH "i386"
-#endif
static const char *default_arch = DEFAULT_ARCH;
/* 'md_assemble ()' gathers together information and puts it into a
@@ -158,17 +179,15 @@ const char extra_symbol_chars[] = "*%-(@
const char extra_symbol_chars[] = "*%-(";
#endif
+#if (defined (TE_I386AIX) \
+ || ((defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) \
+ && !defined (TE_LINUX) \
+ && !defined (TE_FreeBSD) \
+ && !defined (TE_NetBSD)))
/* This array holds the chars that always start a comment. If the
pre-processor is disabled, these aren't very useful. */
-#if defined (TE_I386AIX) || ((defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) && ! defined (TE_LINUX) && !defined(TE_FreeBSD) && !defined(TE_NetBSD))
-/* Putting '/' here makes it impossible to use the divide operator.
- However, we need it for compatibility with SVR4 systems. */
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
a line. If the line seems to have the form '# 123 filename'
@@ -178,9 +197,14 @@ const char comment_chars[] = "#";
#NO_APP at the beginning of its output.
Also note that comments started like this one will always work if
'/' isn't otherwise defined. */
-#if defined (TE_I386AIX) || ((defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) && ! defined (TE_LINUX) && !defined(TE_FreeBSD) && !defined(TE_NetBSD))
const char line_comment_chars[] = "";
+
#else
+/* Putting '/' here makes it impossible to use the divide operator.
+ However, we need it for compatibility with SVR4 systems. */
+const char comment_chars[] = "#";
+#define PREFIX_SEPARATOR '/'
+
const char line_comment_chars[] = "/";
#endif
@@ -281,6 +305,9 @@ static unsigned int cpu_arch_flags = Cpu
larger than a byte offset. */
static unsigned int no_cond_jump_promotion = 0;
+/* Pre-defined "_GLOBAL_OFFSET_TABLE_". */
+symbolS *GOT_symbol;
+
/* Interface to relax_segment.
There are 3 major relax states for 386 jump insns because the
different types of jumps add different sizes to frags when we're
@@ -377,6 +404,43 @@ static const arch_entry cpu_arch[] = {
{NULL, 0 }
};
+const pseudo_typeS md_pseudo_table[] =
+{
+#if !defined(OBJ_AOUT) && !defined(USE_ALIGN_PTWO)
+ {"align", s_align_bytes, 0},
+#else
+ {"align", s_align_ptwo, 0},
+#endif
+ {"arch", set_cpu_arch, 0},
+#ifndef I386COFF
+ {"bss", s_bss, 0},
+#endif
+ {"ffloat", float_cons, 'f'},
+ {"dfloat", float_cons, 'd'},
+ {"tfloat", float_cons, 'x'},
+ {"value", cons, 2},
+ {"noopt", s_ignore, 0},
+ {"optim", s_ignore, 0},
+ {"code16gcc", set_16bit_gcc_code_flag, CODE_16BIT},
+ {"code16", set_code_flag, CODE_16BIT},
+ {"code32", set_code_flag, CODE_32BIT},
+ {"code64", set_code_flag, CODE_64BIT},
+ {"intel_syntax", set_intel_syntax, 1},
+ {"att_syntax", set_intel_syntax, 0},
+ {"file", dwarf2_directive_file, 0},
+ {"loc", dwarf2_directive_loc, 0},
+ {0, 0, 0}
+};
+
+/* For interface with expression (). */
+extern char *input_line_pointer;
+
+/* Hash table for instruction mnemonic lookup. */
+static struct hash_control *op_hash;
+
+/* Hash table for register lookup. */
+static struct hash_control *reg_hash;
+
void
i386_align_code (fragP, count)
fragS *fragP;
@@ -471,18 +535,6 @@ i386_align_code (fragP, count)
}
}
-static char *output_invalid PARAMS ((int c));
-static int i386_operand PARAMS ((char *operand_string));
-static int i386_intel_operand PARAMS ((char *operand_string, int got_a_float));
-static const reg_entry *parse_register PARAMS ((char *reg_string,
- char **end_op));
-
-#ifndef I386COFF
-static void s_bss PARAMS ((int));
-#endif
-
-symbolS *GOT_symbol; /* Pre-defined "_GLOBAL_OFFSET_TABLE_". */
-
static INLINE unsigned int
mode_from_disp_size (t)
unsigned int t;
@@ -610,7 +662,8 @@ add_prefix (prefix)
int ret = 1;
int q;
- if (prefix >= 0x40 && prefix < 0x50 && flag_code == CODE_64BIT)
+ if (prefix >= REX_OPCODE && prefix < REX_OPCODE + 16
+ && flag_code == CODE_64BIT)
q = REX_PREFIX;
else
switch (prefix)
@@ -648,7 +701,7 @@ add_prefix (prefix)
break;
}
- if (i.prefix[q])
+ if (i.prefix[q] != 0)
{
as_bad (_("same type of prefix used twice"));
return 0;
@@ -776,43 +829,6 @@ set_cpu_arch (dummy)
demand_empty_rest_of_line ();
}
-const pseudo_typeS md_pseudo_table[] =
-{
-#if !defined(OBJ_AOUT) && !defined(USE_ALIGN_PTWO)
- {"align", s_align_bytes, 0},
-#else
- {"align", s_align_ptwo, 0},
-#endif
- {"arch", set_cpu_arch, 0},
-#ifndef I386COFF
- {"bss", s_bss, 0},
-#endif
- {"ffloat", float_cons, 'f'},
- {"dfloat", float_cons, 'd'},
- {"tfloat", float_cons, 'x'},
- {"value", cons, 2},
- {"noopt", s_ignore, 0},
- {"optim", s_ignore, 0},
- {"code16gcc", set_16bit_gcc_code_flag, CODE_16BIT},
- {"code16", set_code_flag, CODE_16BIT},
- {"code32", set_code_flag, CODE_32BIT},
- {"code64", set_code_flag, CODE_64BIT},
- {"intel_syntax", set_intel_syntax, 1},
- {"att_syntax", set_intel_syntax, 0},
- {"file", dwarf2_directive_file, 0},
- {"loc", dwarf2_directive_loc, 0},
- {0, 0, 0}
-};
-
-/* For interface with expression (). */
-extern char *input_line_pointer;
-
-/* Hash table for instruction mnemonic lookup. */
-static struct hash_control *op_hash;
-
-/* Hash table for register lookup. */
-static struct hash_control *reg_hash;
-
#ifdef BFD_ASSEMBLER
unsigned long
i386_mach ()
@@ -835,8 +851,8 @@ md_begin ()
op_hash = hash_new ();
{
- register const template *optab;
- register templates *core_optab;
+ const template *optab;
+ templates *core_optab;
/* Setup for loop. */
optab = i386_optab;
@@ -872,7 +888,7 @@ md_begin ()
/* Initialize reg_hash hash table. */
reg_hash = hash_new ();
{
- register const reg_entry *regtab;
+ const reg_entry *regtab;
for (regtab = i386_regtab;
regtab < i386_regtab + sizeof (i386_regtab) / sizeof (i386_regtab[0]);
@@ -888,8 +904,8 @@ md_begin ()
/* Fill in lexical tables: mnemonic_chars, operand_chars. */
{
- register int c;
- register char *p;
+ int c;
+ char *p;
for (c = 0; c < 256; c++)
{
@@ -978,7 +994,10 @@ pi (line, x)
fprintf (stdout, " sib: base %x index %x scale %x\n",
x->sib.base, x->sib.index, x->sib.scale);
fprintf (stdout, " rex: 64bit %x extX %x extY %x extZ %x\n",
- x->rex.mode64, x->rex.extX, x->rex.extY, x->rex.extZ);
+ (x->rex & REX_MODE64) != 0,
+ (x->rex & REX_EXTX) != 0,
+ (x->rex & REX_EXTY) != 0,
+ (x->rex & REX_EXTZ) != 0);
for (i = 0; i < x->operands; i++)
{
fprintf (stdout, " #%d: ", i + 1);
@@ -1053,7 +1072,7 @@ struct type_name
char *tname;
}
-type_names[] =
+static const type_names[] =
{
{ Reg8, "r8" },
{ Reg16, "r16" },
@@ -1093,7 +1112,7 @@ static void
pt (t)
unsigned int t;
{
- register struct type_name *ty;
+ const struct type_name *ty;
for (ty = type_names; ty->mask; ty++)
if (t & ty->mask)
@@ -1119,6 +1138,8 @@ tc_i386_force_relocation (fixp)
}
#ifdef BFD_ASSEMBLER
+static bfd_reloc_code_real_type reloc
+ PARAMS ((int, int, int, bfd_reloc_code_real_type));
static bfd_reloc_code_real_type
reloc (size, pcrel, sign, other)
@@ -1212,11 +1233,11 @@ tc_i386_fix_adjustable (fixP)
#define BFD_RELOC_X86_64_GOTPCREL 0
#endif
-static int intel_float_operand PARAMS ((char *mnemonic));
+static int intel_float_operand PARAMS ((const char *mnemonic));
static int
intel_float_operand (mnemonic)
- char *mnemonic;
+ const char *mnemonic;
{
if (mnemonic[0] == 'f' && mnemonic[1] == 'i')
return 2;
@@ -1235,11 +1256,7 @@ void
md_assemble (line)
char *line;
{
- /* Points to template once we've found it. */
- const template *t;
-
int j;
-
char mnemonic[MAX_MNEM_SIZE];
/* Initialize globals. */
@@ -1253,82 +1270,248 @@ md_assemble (line)
/* First parse an instruction mnemonic & call i386_operand for the operands.
We assume that the scrubber has arranged it so that line[0] is the valid
start of a (possibly prefixed) mnemonic. */
- {
- char *l = line;
- char *token_start = l;
- char *mnem_p;
- /* Non-zero if we found a prefix only acceptable with string insns. */
- const char *expecting_string_instruction = NULL;
+ line = parse_insn (line, mnemonic);
+ if (line == NULL)
+ return;
- while (1)
- {
- mnem_p = mnemonic;
- while ((*mnem_p = mnemonic_chars[(unsigned char) *l]) != 0)
- {
- mnem_p++;
- if (mnem_p >= mnemonic + sizeof (mnemonic))
- {
- as_bad (_("no such instruction: `%s'"), token_start);
+ line = parse_operands (line, mnemonic);
+ if (line == NULL)
return;
- }
- l++;
- }
- if (!is_space_char (*l)
- && *l != END_OF_INSN
- && *l != PREFIX_SEPARATOR
- && *l != ',')
- {
- as_bad (_("invalid character %s in mnemonic"),
- output_invalid (*l));
+
+ /* Now we've parsed the mnemonic into a set of templates, and have the
+ operands at hand. */
+
+ /* All intel opcodes have reversed operands except for "bound" and
+ "enter". We also don't reverse intersegment "jmp" and "call"
+ instructions with 2 immediate operands so that the immediate segment
+ precedes the offset, as it does when in AT&T mode. "enter" and the
+ intersegment "jmp" and "call" instructions are the only ones that
+ have two immediate operands. */
+ if (intel_syntax && i.operands > 1
+ && (strcmp (mnemonic, "bound") != 0)
+ && !((i.types[0] & Imm) && (i.types[1] & Imm)))
+ swap_operands ();
+
+ if (i.imm_operands)
+ optimize_imm ();
+
+ if (i.disp_operands)
+ optimize_disp ();
+
+ /* Next, we find a template that matches the given insn,
+ making sure the overlap of the given operands types is consistent
+ with the template operand types. */
+
+ if (!match_template ())
return;
- }
- if (token_start == l)
+
+ /* Undo SYSV386_COMPAT brokenness when in Intel mode. See i386.h */
+ if (SYSV386_COMPAT
+ && intel_syntax
+ && (i.tm.base_opcode & 0xfffffde0) == 0xdce0)
+ i.tm.base_opcode ^= FloatR;
+
+ if (i.tm.opcode_modifier & FWait)
+ if (!add_prefix (FWAIT_OPCODE))
+ return;
+
+ /* Check string instruction segment overrides. */
+ if ((i.tm.opcode_modifier & IsString) != 0 && i.mem_operands != 0)
{
- if (*l == PREFIX_SEPARATOR)
- as_bad (_("expecting prefix; got nothing"));
- else
- as_bad (_("expecting mnemonic; got nothing"));
+ if (!check_string ())
return;
}
- /* Look up instruction (or prefix) via hash table. */
- current_templates = hash_find (op_hash, mnemonic);
+ if (!process_suffix ())
+ return;
- if (*l != END_OF_INSN
- && (! is_space_char (*l) || l[1] != END_OF_INSN)
- && current_templates
- && (current_templates->start->opcode_modifier & IsPrefix))
- {
- /* If we are in 16-bit mode, do not allow addr16 or data16.
- Similarly, in 32-bit mode, do not allow addr32 or data32. */
- if ((current_templates->start->opcode_modifier & (Size16 | Size32))
- && flag_code != CODE_64BIT
- && (((current_templates->start->opcode_modifier & Size32) != 0)
- ^ (flag_code == CODE_16BIT)))
- {
- as_bad (_("redundant %s prefix"),
- current_templates->start->name);
+ /* Make still unresolved immediate matches conform to size of immediate
+ given in i.suffix. */
+ if (!finalize_imm ())
return;
+
+ if (i.types[0] & Imm1)
+ i.imm_operands = 0; /* kludge for shift insns. */
+ if (i.types[0] & ImplicitRegister)
+ i.reg_operands--;
+ if (i.types[1] & ImplicitRegister)
+ i.reg_operands--;
+ if (i.types[2] & ImplicitRegister)
+ i.reg_operands--;
+
+ if (i.tm.opcode_modifier & ImmExt)
+ {
+ /* These AMD 3DNow! and Intel Katmai New Instructions have an
+ opcode suffix which is coded in the same place as an 8-bit
+ immediate field would be. Here we fake an 8-bit immediate
+ operand from the opcode suffix stored in tm.extension_opcode. */
+
+ expressionS *exp;
+
+ assert (i.imm_operands == 0 && i.operands <= 2 && 2 < MAX_OPERANDS);
+
+ exp = &im_expressions[i.imm_operands++];
+ i.op[i.operands].imms = exp;
+ i.types[i.operands++] = Imm8;
+ exp->X_op = O_constant;
+ exp->X_add_number = i.tm.extension_opcode;
+ i.tm.extension_opcode = None;
}
- /* Add prefix, checking for repeated prefixes. */
- switch (add_prefix (current_templates->start->base_opcode))
+
+ /* For insns with operands there are more diddles to do to the opcode. */
+ if (i.operands)
{
- case 0:
+ if (!process_operands ())
return;
- case 2:
- expecting_string_instruction = current_templates->start->name;
- break;
- }
- /* Skip past PREFIX_SEPARATOR and reset token_start. */
- token_start = ++l;
}
- else
- break;
+ else if (!quiet_warnings && (i.tm.opcode_modifier & Ugh) != 0)
+ {
+ /* UnixWare fsub no args is alias for fsubp, fadd -> faddp, etc. */
+ as_warn (_("translating to `%sp'"), i.tm.name);
}
- if (!current_templates)
- {
+ /* Handle conversion of 'int $3' --> special int3 insn. */
+ if (i.tm.base_opcode == INT_OPCODE && i.op[0].imms->X_add_number == 3)
+ {
+ i.tm.base_opcode = INT3_OPCODE;
+ i.imm_operands = 0;
+ }
+
+ if ((i.tm.opcode_modifier & (Jump | JumpByte | JumpDword))
+ && i.op[0].disps->X_op == O_constant)
+ {
+ /* Convert "jmp constant" (and "call constant") to a jump (call) to
+ the absolute address given by the constant. Since ix86 jumps and
+ calls are pc relative, we need to generate a reloc. */
+ i.op[0].disps->X_add_symbol = &abs_symbol;
+ i.op[0].disps->X_op = O_symbol;
+ }
+
+ if ((i.tm.opcode_modifier & Rex64) != 0)
+ i.rex |= REX_MODE64;
+
+ /* For 8 bit registers we need an empty rex prefix. Also if the
+ instruction already has a prefix, we need to convert old
+ registers to new ones. */
+
+ if (((i.types[0] & Reg8) != 0
+ && (i.op[0].regs->reg_flags & RegRex64) != 0)
+ || ((i.types[1] & Reg8) != 0
+ && (i.op[1].regs->reg_flags & RegRex64) != 0)
+ || (((i.types[0] & Reg8) != 0 || (i.types[1] & Reg8) != 0)
+ && i.rex != 0))
+ {
+ int x;
+
+ i.rex |= REX_OPCODE;
+ for (x = 0; x < 2; x++)
+ {
+ /* Look for 8 bit operand that uses old registers. */
+ if ((i.types[x] & Reg8) != 0
+ && (i.op[x].regs->reg_flags & RegRex64) == 0)
+ {
+ /* In case it is "hi" register, give up. */
+ if (i.op[x].regs->reg_num > 3)
+ as_bad (_("can't encode register '%%%s' in an instruction requiring REX prefix.\n"),
+ i.op[x].regs->reg_name);
+
+ /* Otherwise it is equivalent to the extended register.
+ Since the encoding doesn't change this is merely
+ cosmetic cleanup for debug output. */
+
+ i.op[x].regs = i.op[x].regs + 8;
+ }
+ }
+ }
+
+ if (i.rex != 0)
+ add_prefix (REX_OPCODE | i.rex);
+
+ /* We are ready to output the insn. */
+ output_insn ();
+}
+
+static char *
+parse_insn (line, mnemonic)
+ char *line;
+ char *mnemonic;
+{
+ char *l = line;
+ char *token_start = l;
+ char *mnem_p;
+
+ /* Non-zero if we found a prefix only acceptable with string insns. */
+ const char *expecting_string_instruction = NULL;
+
+ while (1)
+ {
+ mnem_p = mnemonic;
+ while ((*mnem_p = mnemonic_chars[(unsigned char) *l]) != 0)
+ {
+ mnem_p++;
+ if (mnem_p >= mnemonic + MAX_MNEM_SIZE)
+ {
+ as_bad (_("no such instruction: `%s'"), token_start);
+ return NULL;
+ }
+ l++;
+ }
+ if (!is_space_char (*l)
+ && *l != END_OF_INSN
+ && *l != PREFIX_SEPARATOR
+ && *l != ',')
+ {
+ as_bad (_("invalid character %s in mnemonic"),
+ output_invalid (*l));
+ return NULL;
+ }
+ if (token_start == l)
+ {
+ if (*l == PREFIX_SEPARATOR)
+ as_bad (_("expecting prefix; got nothing"));
+ else
+ as_bad (_("expecting mnemonic; got nothing"));
+ return NULL;
+ }
+
+ /* Look up instruction (or prefix) via hash table. */
+ current_templates = hash_find (op_hash, mnemonic);
+
+ if (*l != END_OF_INSN
+ && (!is_space_char (*l) || l[1] != END_OF_INSN)
+ && current_templates
+ && (current_templates->start->opcode_modifier & IsPrefix))
+ {
+ /* If we are in 16-bit mode, do not allow addr16 or data16.
+ Similarly, in 32-bit mode, do not allow addr32 or data32. */
+ if ((current_templates->start->opcode_modifier & (Size16 | Size32))
+ && flag_code != CODE_64BIT
+ && (((current_templates->start->opcode_modifier & Size32) != 0)
+ ^ (flag_code == CODE_16BIT)))
+ {
+ as_bad (_("redundant %s prefix"),
+ current_templates->start->name);
+ return NULL;
+ }
+ /* Add prefix, checking for repeated prefixes. */
+ switch (add_prefix (current_templates->start->base_opcode))
+ {
+ case 0:
+ return NULL;
+ case 2:
+ expecting_string_instruction = current_templates->start->name;
+ break;
+ }
+ /* Skip past PREFIX_SEPARATOR and reset token_start. */
+ token_start = ++l;
+ }
+ else
+ break;
+ }
+
+ if (!current_templates)
+ {
/* See if we can get a match by trimming off a suffix. */
switch (mnem_p[-1])
{
@@ -1365,7 +1548,7 @@ md_assemble (line)
if (!current_templates)
{
as_bad (_("no such instruction: `%s'"), token_start);
- return;
+ return NULL;
}
}
@@ -1382,13 +1565,13 @@ md_assemble (line)
if (l[2] == 't')
{
if (! add_prefix (DS_PREFIX_OPCODE))
- return;
+ return NULL;
l += 3;
}
else if (l[2] == 'n')
{
if (! add_prefix (CS_PREFIX_OPCODE))
- return;
+ return NULL;
l += 3;
}
}
@@ -1398,7 +1581,7 @@ md_assemble (line)
{
as_bad (_("invalid character %s in mnemonic"),
output_invalid (*l));
- return;
+ return NULL;
}
/* Check if instruction is supported on specified architecture. */
@@ -1419,19 +1602,26 @@ md_assemble (line)
{
as_bad (_("expecting string instruction after `%s'"),
expecting_string_instruction);
- return;
+ return NULL;
}
- /* There may be operands to parse. */
- if (*l != END_OF_INSN)
+ return l;
+}
+
+static char *
+parse_operands (l, mnemonic)
+ char *l;
+ const char *mnemonic;
{
+ char *token_start;
+
/* 1 if operand is pending after ','. */
unsigned int expecting_operand = 0;
/* Non-zero if operand parens not balanced. */
unsigned int paren_not_balanced;
- do
+ while (*l != END_OF_INSN)
{
/* Skip optional white space before operand. */
if (is_space_char (*l))
@@ -1441,7 +1631,7 @@ md_assemble (line)
as_bad (_("invalid character %s before operand %d"),
output_invalid (*l),
i.operands + 1);
- return;
+ return NULL;
}
token_start = l; /* after white space */
paren_not_balanced = 0;
@@ -1457,7 +1647,7 @@ md_assemble (line)
else
as_bad (_("unbalanced brackets in operand %d."),
i.operands + 1);
- return;
+ return NULL;
}
else
break; /* we are done */
@@ -1467,7 +1657,7 @@ md_assemble (line)
as_bad (_("invalid character %s in operand %d"),
output_invalid (*l),
i.operands + 1);
- return;
+ return NULL;
}
if (!intel_syntax)
{
@@ -1493,7 +1683,7 @@ md_assemble (line)
{
as_bad (_("spurious operands; (%d operands/instruction max)"),
MAX_OPERANDS);
- return;
+ return NULL;
}
/* Now parse operand adding info to 'i' as we go along. */
END_STRING_AND_SAVE (l);
@@ -1507,7 +1697,7 @@ md_assemble (line)
RESTORE_END_STRING (l);
if (!operand_ok)
- return;
+ return NULL;
}
else
{
@@ -1515,12 +1705,12 @@ md_assemble (line)
{
expecting_operand_after_comma:
as_bad (_("expecting operand after ','; got nothing"));
- return;
+ return NULL;
}
if (*l == ',')
{
as_bad (_("expecting operand before ','; got nothing"));
- return;
+ return NULL;
}
}
@@ -1534,45 +1724,12 @@ md_assemble (line)
}
expecting_operand = 1;
}
- }
- while (*l != END_OF_INSN);
}
+ return l;
}
-
- /* Now we've parsed the mnemonic into a set of templates, and have the
- operands at hand.
-
- Next, we find a template that matches the given insn,
- making sure the overlap of the given operands types is consistent
- with the template operand types. */
-
-#define MATCH(overlap, given, template) \
- ((overlap & ~JumpAbsolute) \
- && ((given) & (BaseIndex|JumpAbsolute)) == ((overlap) & (BaseIndex|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.
- Note that Acc in a template matches every size of reg. */
-#define CONSISTENT_REGISTER_MATCH(m0, g0, t0, m1, g1, t1) \
- ( ((g0) & Reg) == 0 || ((g1) & Reg) == 0 || \
- ((g0) & Reg) == ((g1) & Reg) || \
- ((((m0) & Acc) ? Reg : (t0)) & (((m1) & Acc) ? Reg : (t1)) & Reg) == 0 )
- {
- register unsigned int overlap0, overlap1;
- unsigned int overlap2;
- unsigned int found_reverse_match;
- int suffix_check;
-
- /* All intel opcodes have reversed operands except for "bound" and
- "enter". We also don't reverse intersegment "jmp" and "call"
- instructions with 2 immediate operands so that the immediate segment
- precedes the offset, as it does when in AT&T mode. "enter" and the
- intersegment "jmp" and "call" instructions are the only ones that
- have two immediate operands. */
- if (intel_syntax && i.operands > 1
- && (strcmp (mnemonic, "bound") != 0)
- && !((i.types[0] & Imm) && (i.types[1] & Imm)))
+static void
+swap_operands ()
{
union i386_op temp_op;
unsigned int temp_type;
@@ -1609,10 +1766,11 @@ md_assemble (line)
}
}
- if (i.imm_operands)
- {
/* Try to ensure constant immediates are represented in the smallest
opcode possible. */
+static void
+optimize_imm ()
+{
char guess_suffix = 0;
int op;
@@ -1673,19 +1831,25 @@ md_assemble (line)
(((i.op[op].imms->X_add_number & 0xffff) ^ 0x8000) - 0x8000);
}
if ((i.types[op] & Imm32)
- && (i.op[op].imms->X_add_number & ~(((offsetT) 2 << 31) - 1)) == 0)
+ && ((i.op[op].imms->X_add_number & ~(((offsetT) 2 << 31) - 1))
+ == 0))
{
- i.op[op].imms->X_add_number =
- (i.op[op].imms->X_add_number ^ ((offsetT) 1 << 31)) - ((addressT) 1 << 31);
+ i.op[op].imms->X_add_number = ((i.op[op].imms->X_add_number
+ ^ ((offsetT) 1 << 31))
+ - ((offsetT) 1 << 31));
}
i.types[op] |= smallest_imm_type (i.op[op].imms->X_add_number);
- /* We must avoid matching of Imm32 templates when 64bit only immediate is available. */
+
+ /* We must avoid matching of Imm32 templates when 64bit
+ only immediate is available. */
if (guess_suffix == QWORD_MNEM_SUFFIX)
i.types[op] &= ~Imm32;
break;
+
case O_absent:
case O_register:
abort ();
+
/* Symbols and expressions. */
default:
/* Convert symbolic operand to proper sizes for matching. */
@@ -1711,14 +1875,14 @@ md_assemble (line)
}
}
- if (i.disp_operands)
- {
/* Try to use the smallest displacement type too. */
+static void
+optimize_disp ()
+{
int op;
for (op = i.operands; --op >= 0;)
- if ((i.types[op] & Disp)
- && i.op[op].disps->X_op == O_constant)
+ if ((i.types[op] & Disp) && i.op[op].disps->X_op == O_constant)
{
offsetT disp = i.op[op].disps->X_add_number;
@@ -1752,6 +1916,28 @@ md_assemble (line)
}
}
+static int
+match_template ()
+{
+ /* Points to template once we've found it. */
+ const template *t;
+ unsigned int overlap0, overlap1, overlap2;
+ unsigned int found_reverse_match;
+ int suffix_check;
+
+#define MATCH(overlap, given, template) \
+ ((overlap & ~JumpAbsolute) \
+ && (((given) & (BaseIndex | JumpAbsolute)) \
+ == ((overlap) & (BaseIndex | 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.
+ Note that Acc in a template matches every size of reg. */
+#define CONSISTENT_REGISTER_MATCH(m0, g0, t0, m1, g1, t1) \
+ (((g0) & Reg) == 0 || ((g1) & Reg) == 0 \
+ || ((g0) & Reg) == ((g1) & Reg) \
+ || ((((m0) & Acc) ? Reg : (t0)) & (((m1) & Acc) ? Reg : (t1)) & Reg) == 0 )
+
overlap0 = 0;
overlap1 = 0;
overlap2 = 0;
@@ -1766,7 +1952,8 @@ md_assemble (line)
? No_lSuf
: (i.suffix == QWORD_MNEM_SUFFIX
? No_qSuf
- : (i.suffix == LONG_DOUBLE_MNEM_SUFFIX ? No_xSuf : 0))))));
+ : (i.suffix == LONG_DOUBLE_MNEM_SUFFIX
+ ? No_xSuf : 0))))));
for (t = current_templates->start;
t < current_templates->end;
@@ -1860,12 +2047,13 @@ md_assemble (line)
/* We've found a match; break out of loop. */
break;
}
+
if (t == current_templates->end)
{
/* We found no match. */
as_bad (_("suffix or operands invalid for `%s'"),
current_templates->start->name);
- return;
+ return 0;
}
if (!quiet_warnings)
@@ -1899,19 +2087,12 @@ md_assemble (line)
i.tm.operand_types[0] = t->operand_types[1];
i.tm.operand_types[1] = t->operand_types[0];
}
-
- /* Undo SYSV386_COMPAT brokenness when in Intel mode. See i386.h */
- if (SYSV386_COMPAT
- && intel_syntax
- && (i.tm.base_opcode & 0xfffffde0) == 0xdce0)
- i.tm.base_opcode ^= FloatR;
- if (i.tm.opcode_modifier & FWait)
- if (! add_prefix (FWAIT_OPCODE))
- return;
+ return 1;
+}
- /* Check string instruction segment overrides. */
- if ((i.tm.opcode_modifier & IsString) != 0 && i.mem_operands != 0)
+static int
+check_string ()
{
int mem_op = (i.types[0] & AnyMem) ? 0 : 1;
if ((i.tm.operand_types[mem_op] & EsSeg) != 0)
@@ -1921,7 +2102,7 @@ md_assemble (line)
as_bad (_("`%s' operand %d must use `%%es' segment"),
i.tm.name,
mem_op + 1);
- return;
+ return 0;
}
/* There's only ever one segment override allowed per instruction.
This instruction possibly has a legal segment override on the
@@ -1936,11 +2117,15 @@ md_assemble (line)
as_bad (_("`%s' operand %d must use `%%es' segment"),
i.tm.name,
mem_op + 2);
- return;
+ return 0;
}
}
+ return 1;
}
+static int
+process_suffix ()
+{
/* If matched instruction specifies an explicit instruction mnemonic
suffix, use it. */
if (i.tm.opcode_modifier & (Size16 | Size32 | Size64))
@@ -1975,12 +2160,121 @@ md_assemble (line)
}
else if (i.suffix == BYTE_MNEM_SUFFIX)
{
+ if (!check_byte_reg ())
+ return 0;
+ }
+ else if (i.suffix == LONG_MNEM_SUFFIX)
+ {
+ if (!check_long_reg ())
+ return 0;
+ }
+ else if (i.suffix == QWORD_MNEM_SUFFIX)
+ {
+ if (!check_qword_reg ())
+ return 0;
+ }
+ else if (i.suffix == WORD_MNEM_SUFFIX)
+ {
+ if (!check_word_reg ())
+ return 0;
+ }
+ else if (intel_syntax && (i.tm.opcode_modifier & IgnoreSize))
+ /* Do nothing if the instruction is going to ignore the prefix. */
+ ;
+ else
+ abort ();
+ }
+ else if ((i.tm.opcode_modifier & DefaultSize) && !i.suffix)
+ {
+ i.suffix = stackop_size;
+ }
+
+ /* Change the opcode based on the operand size given by i.suffix;
+ We need not change things for byte insns. */
+
+ if (!i.suffix && (i.tm.opcode_modifier & W))
+ {
+ as_bad (_("no instruction mnemonic suffix given and no register operands; can't size instruction"));
+ return 0;
+ }
+
+ /* For movzx and movsx, need to check the register type. */
+ if (intel_syntax
+ && (i.tm.base_opcode == 0xfb6 || i.tm.base_opcode == 0xfbe))
+ if (i.suffix && i.suffix == BYTE_MNEM_SUFFIX)
+ {
+ unsigned int prefix = DATA_PREFIX_OPCODE;
+
+ if ((i.op[1].regs->reg_type & Reg16) != 0)
+ if (!add_prefix (prefix))
+ return 0;
+ }
+
+ if (i.suffix && i.suffix != BYTE_MNEM_SUFFIX)
+ {
+ /* It's not a byte, select word/dword operation. */
+ if (i.tm.opcode_modifier & W)
+ {
+ if (i.tm.opcode_modifier & ShortForm)
+ i.tm.base_opcode |= 8;
+ else
+ i.tm.base_opcode |= 1;
+ }
+ /* Now select between word & dword operations via the operand
+ size prefix, except for instructions that will ignore this
+ prefix anyway. */
+ if (i.suffix != QWORD_MNEM_SUFFIX
+ && (i.suffix == LONG_MNEM_SUFFIX) == (flag_code == CODE_16BIT)
+ && !(i.tm.opcode_modifier & IgnoreSize))
+ {
+ unsigned int prefix = DATA_PREFIX_OPCODE;
+ if (i.tm.opcode_modifier & JumpByte) /* jcxz, loop */
+ prefix = ADDR_PREFIX_OPCODE;
+
+ if (!add_prefix (prefix))
+ return 0;
+ }
+
+ if (i.suffix != QWORD_MNEM_SUFFIX && (flag_code == CODE_64BIT)
+ && !(i.tm.opcode_modifier & IgnoreSize)
+ && (i.tm.opcode_modifier & JumpByte))
+ {
+ if (!add_prefix (ADDR_PREFIX_OPCODE))
+ return 0;
+ }
+
+ /* Set mode64 for an operand. */
+ if (i.suffix == QWORD_MNEM_SUFFIX
+ && (i.tm.opcode_modifier & NoRex64) == 0)
+ {
+ i.rex |= REX_MODE64;
+ if (flag_code < CODE_64BIT)
+ {
+ as_bad (_("64bit operations available only in 64bit modes."));
+ return 0;
+ }
+ }
+
+ /* Size floating point instruction. */
+ if (i.suffix == LONG_MNEM_SUFFIX)
+ {
+ if (i.tm.opcode_modifier & FloatMF)
+ i.tm.base_opcode ^= 4;
+ }
+ }
+
+ return 1;
+}
+
+static int
+check_byte_reg ()
+{
int op;
for (op = i.operands; --op >= 0;)
{
- /* If this is an eight bit register, it's OK. If it's
- the 16 or 32 bit version of an eight bit register,
- we will just use the low portion, and that's OK too. */
+ /* If this is an eight bit register, it's OK. If it's the 16 or
+ 32 bit version of an eight bit register, we will just use the
+ low portion, and that's OK too. */
if (i.types[op] & Reg8)
continue;
@@ -1995,26 +2289,28 @@ md_assemble (line)
if ((i.types[op] & WordReg) && i.op[op].regs->reg_num < 4
#if 0
- /* Check that the template allows eight bit regs
- This kills insns such as `orb $1,%edx', which
- maybe should be allowed. */
+ /* Check that the template allows eight bit regs. This
+ kills insns such as `orb $1,%edx', which maybe should be
+ allowed. */
&& (i.tm.operand_types[op] & (Reg8|InOutPortReg))
#endif
)
{
- /* Prohibit these changes in the 64bit mode, since
- the lowering is more complicated. */
+ /* Prohibit these changes in the 64bit mode, since the
+ lowering is more complicated. */
if (flag_code == CODE_64BIT
&& (i.tm.operand_types[op] & InOutPortReg) == 0)
+ {
as_bad (_("Incorrect register `%%%s' used with`%c' suffix"),
i.op[op].regs->reg_name,
i.suffix);
+ return 0;
+ }
#if REGISTER_WARNINGS
if (!quiet_warnings
&& (i.tm.operand_types[op] & InOutPortReg) == 0)
as_warn (_("using `%%%s' instead of `%%%s' due to `%c' suffix"),
- (i.op[op].regs
- + (i.types[op] & Reg16
+ (i.op[op].regs + (i.types[op] & Reg16
? REGNAM_AL - REGNAM_AX
: REGNAM_AL - REGNAM_EAX))->reg_name,
i.op[op].regs->reg_name,
@@ -2032,17 +2328,20 @@ md_assemble (line)
i.op[op].regs->reg_name,
i.tm.name,
i.suffix);
- return;
+ return 0;
}
}
+ return 1;
}
- else if (i.suffix == LONG_MNEM_SUFFIX)
+
+static int
+check_long_reg ()
{
int op;
for (op = i.operands; --op >= 0;)
- /* Reject eight bit registers, except where the template
- requires them. (eg. movzb) */
+ /* Reject eight bit registers, except where the template requires
+ them. (eg. movzb) */
if ((i.types[op] & Reg8) != 0
&& (i.tm.operand_types[op] & (Reg16 | Reg32 | Acc)) != 0)
{
@@ -2050,19 +2349,22 @@ md_assemble (line)
i.op[op].regs->reg_name,
i.tm.name,
i.suffix);
- return;
+ return 0;
}
/* Warn if the e prefix on a general reg is missing. */
else if ((!quiet_warnings || flag_code == CODE_64BIT)
&& (i.types[op] & Reg16) != 0
&& (i.tm.operand_types[op] & (Reg32|Acc)) != 0)
{
- /* Prohibit these changes in the 64bit mode, since
- the lowering is more complicated. */
+ /* Prohibit these changes in the 64bit mode, since the
+ lowering is more complicated. */
if (flag_code == CODE_64BIT)
+ {
as_bad (_("Incorrect register `%%%s' used with`%c' suffix"),
i.op[op].regs->reg_name,
i.suffix);
+ return 0;
+ }
#if REGISTER_WARNINGS
else
as_warn (_("using `%%%s' instead of `%%%s' due to `%c' suffix"),
@@ -2078,15 +2380,19 @@ md_assemble (line)
as_bad (_("Incorrect register `%%%s' used with`%c' suffix"),
i.op[op].regs->reg_name,
i.suffix);
+ return 0;
}
+ return 1;
}
- else if (i.suffix == QWORD_MNEM_SUFFIX)
+
+static int
+check_qword_reg ()
{
int op;
for (op = i.operands; --op >= 0; )
- /* Reject eight bit registers, except where the template
- requires them. (eg. movzb) */
+ /* Reject eight bit registers, except where the template requires
+ them. (eg. movzb) */
if ((i.types[op] & Reg8) != 0
&& (i.tm.operand_types[op] & (Reg16|Reg32|Acc)) != 0)
{
@@ -2094,26 +2400,30 @@ md_assemble (line)
i.op[op].regs->reg_name,
i.tm.name,
i.suffix);
- return;
+ return 0;
}
/* Warn if the e prefix on a general reg is missing. */
else if (((i.types[op] & Reg16) != 0
|| (i.types[op] & Reg32) != 0)
&& (i.tm.operand_types[op] & (Reg32|Acc)) != 0)
{
- /* Prohibit these changes in the 64bit mode, since
- the lowering is more complicated. */
+ /* Prohibit these changes in the 64bit mode, since the
+ lowering is more complicated. */
as_bad (_("Incorrect register `%%%s' used with`%c' suffix"),
i.op[op].regs->reg_name,
i.suffix);
+ return 0;
}
+ return 1;
}
- else if (i.suffix == WORD_MNEM_SUFFIX)
+
+static int
+check_word_reg ()
{
int op;
for (op = i.operands; --op >= 0;)
- /* Reject eight bit registers, except where the template
- requires them. (eg. movzb) */
+ /* Reject eight bit registers, except where the template requires
+ them. (eg. movzb) */
if ((i.types[op] & Reg8) != 0
&& (i.tm.operand_types[op] & (Reg16|Reg32|Acc)) != 0)
{
@@ -2121,19 +2431,22 @@ md_assemble (line)
i.op[op].regs->reg_name,
i.tm.name,
i.suffix);
- return;
+ return 0;
}
/* Warn if the e prefix on a general reg is present. */
else if ((!quiet_warnings || flag_code == CODE_64BIT)
&& (i.types[op] & Reg32) != 0
&& (i.tm.operand_types[op] & (Reg16|Acc)) != 0)
{
- /* Prohibit these changes in the 64bit mode, since
- the lowering is more complicated. */
+ /* Prohibit these changes in the 64bit mode, since the
+ lowering is more complicated. */
if (flag_code == CODE_64BIT)
+ {
as_bad (_("Incorrect register `%%%s' used with`%c' suffix"),
i.op[op].regs->reg_name,
i.suffix);
+ return 0;
+ }
else
#if REGISTER_WARNINGS
as_warn (_("using `%%%s' instead of `%%%s' due to `%c' suffix"),
@@ -2141,187 +2454,94 @@ md_assemble (line)
i.op[op].regs->reg_name,
i.suffix);
#endif
- }
- }
- else if (intel_syntax && (i.tm.opcode_modifier & IgnoreSize))
- /* Do nothing if the instruction is going to ignore the prefix. */
- ;
- 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! */
- if ((overlap0 & (Imm8 | Imm8S | Imm16 | Imm32 | Imm32S))
- && overlap0 != Imm8 && overlap0 != Imm8S
- && overlap0 != Imm16 && overlap0 != Imm32S
- && overlap0 != Imm32 && overlap0 != Imm64)
- {
- if (i.suffix)
- {
- overlap0 &= (i.suffix == BYTE_MNEM_SUFFIX ? (Imm8 | Imm8S) :
- (i.suffix == WORD_MNEM_SUFFIX ? Imm16 :
- (i.suffix == QWORD_MNEM_SUFFIX ? Imm64 | Imm32S : Imm32)));
- }
- else if (overlap0 == (Imm16 | Imm32S | Imm32)
- || overlap0 == (Imm16 | Imm32)
- || overlap0 == (Imm16 | Imm32S))
- {
- overlap0 =
- ((flag_code == CODE_16BIT) ^ (i.prefix[DATA_PREFIX] != 0)) ? Imm16 : Imm32S;
- }
- if (overlap0 != Imm8 && overlap0 != Imm8S
- && overlap0 != Imm16 && overlap0 != Imm32S
- && overlap0 != Imm32 && overlap0 != Imm64)
- {
- as_bad (_("no instruction mnemonic suffix given; can't determine immediate size"));
- return;
- }
- }
- if ((overlap1 & (Imm8 | Imm8S | Imm16 | Imm32S | Imm32))
- && overlap1 != Imm8 && overlap1 != Imm8S
- && overlap1 != Imm16 && overlap1 != Imm32S
- && overlap1 != Imm32 && overlap1 != Imm64)
- {
- if (i.suffix)
- {
- overlap1 &= (i.suffix == BYTE_MNEM_SUFFIX ? (Imm8 | Imm8S) :
- (i.suffix == WORD_MNEM_SUFFIX ? Imm16 :
- (i.suffix == QWORD_MNEM_SUFFIX ? Imm64 | Imm32S : Imm32)));
- }
- else if (overlap1 == (Imm16 | Imm32 | Imm32S)
- || overlap1 == (Imm16 | Imm32)
- || overlap1 == (Imm16 | Imm32S))
- {
- overlap1 =
- ((flag_code == CODE_16BIT) ^ (i.prefix[DATA_PREFIX] != 0)) ? Imm16 : Imm32S;
- }
- if (overlap1 != Imm8 && overlap1 != Imm8S
- && overlap1 != Imm16 && overlap1 != Imm32S
- && overlap1 != Imm32 && overlap1 != Imm64)
- {
- as_bad (_("no instruction mnemonic suffix given; can't determine immediate size %x %c"),overlap1, i.suffix);
- return;
- }
- }
- assert ((overlap2 & Imm) == 0);
-
- i.types[0] = overlap0;
- 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--;
-
- /* Finalize opcode. First, we change the opcode based on the operand
- size given by i.suffix: We need not change things for byte insns. */
-
- if (!i.suffix && (i.tm.opcode_modifier & W))
- {
- as_bad (_("no instruction mnemonic suffix given and no register operands; can't size instruction"));
- return;
- }
-
- /* For movzx and movsx, need to check the register type. */
- if (intel_syntax
- && (i.tm.base_opcode == 0xfb6 || i.tm.base_opcode == 0xfbe))
- if (i.suffix && i.suffix == BYTE_MNEM_SUFFIX)
- {
- unsigned int prefix = DATA_PREFIX_OPCODE;
-
- if ((i.op[1].regs->reg_type & Reg16) != 0)
- if (!add_prefix (prefix))
- return;
}
-
- if (i.suffix && i.suffix != BYTE_MNEM_SUFFIX)
- {
- /* It's not a byte, select word/dword operation. */
- if (i.tm.opcode_modifier & W)
- {
- if (i.tm.opcode_modifier & ShortForm)
- i.tm.base_opcode |= 8;
- else
- i.tm.base_opcode |= 1;
+ return 1;
}
- /* Now select between word & dword operations via the operand
- size prefix, except for instructions that will ignore this
- prefix anyway. */
- if (i.suffix != QWORD_MNEM_SUFFIX
- && (i.suffix == LONG_MNEM_SUFFIX) == (flag_code == CODE_16BIT)
- && !(i.tm.opcode_modifier & IgnoreSize))
- {
- unsigned int prefix = DATA_PREFIX_OPCODE;
- if (i.tm.opcode_modifier & JumpByte) /* jcxz, loop */
- prefix = ADDR_PREFIX_OPCODE;
- if (! add_prefix (prefix))
- return;
- }
+static int
+finalize_imm ()
+{
+ unsigned int overlap0, overlap1, overlap2;
- if (i.suffix != QWORD_MNEM_SUFFIX && (flag_code == CODE_64BIT)
- && !(i.tm.opcode_modifier & IgnoreSize)
- && (i.tm.opcode_modifier & JumpByte))
+ overlap0 = i.types[0] & i.tm.operand_types[0];
+ if ((overlap0 & (Imm8 | Imm8S | Imm16 | Imm32 | Imm32S))
+ && overlap0 != Imm8 && overlap0 != Imm8S
+ && overlap0 != Imm16 && overlap0 != Imm32S
+ && overlap0 != Imm32 && overlap0 != Imm64)
{
- if (! add_prefix (ADDR_PREFIX_OPCODE))
- return;
+ if (i.suffix)
+ {
+ overlap0 &= (i.suffix == BYTE_MNEM_SUFFIX
+ ? Imm8 | Imm8S
+ : (i.suffix == WORD_MNEM_SUFFIX
+ ? Imm16
+ : (i.suffix == QWORD_MNEM_SUFFIX
+ ? Imm64 | Imm32S
+ : Imm32)));
}
-
- /* Set mode64 for an operand. */
- if (i.suffix == QWORD_MNEM_SUFFIX
- && !(i.tm.opcode_modifier & NoRex64))
+ else if (overlap0 == (Imm16 | Imm32S | Imm32)
+ || overlap0 == (Imm16 | Imm32)
+ || overlap0 == (Imm16 | Imm32S))
{
- i.rex.mode64 = 1;
- if (flag_code < CODE_64BIT)
+ overlap0 = ((flag_code == CODE_16BIT) ^ (i.prefix[DATA_PREFIX] != 0)
+ ? Imm16 : Imm32S);
+ }
+ if (overlap0 != Imm8 && overlap0 != Imm8S
+ && overlap0 != Imm16 && overlap0 != Imm32S
+ && overlap0 != Imm32 && overlap0 != Imm64)
{
- as_bad (_("64bit operations available only in 64bit modes."));
- return;
+ as_bad (_("no instruction mnemonic suffix given; can't determine immediate size"));
+ return 0;
}
}
+ i.types[0] = overlap0;
- /* Size floating point instruction. */
- if (i.suffix == LONG_MNEM_SUFFIX)
+ overlap1 = i.types[1] & i.tm.operand_types[1];
+ if ((overlap1 & (Imm8 | Imm8S | Imm16 | Imm32S | Imm32))
+ && overlap1 != Imm8 && overlap1 != Imm8S
+ && overlap1 != Imm16 && overlap1 != Imm32S
+ && overlap1 != Imm32 && overlap1 != Imm64)
{
- if (i.tm.opcode_modifier & FloatMF)
- i.tm.base_opcode ^= 4;
+ if (i.suffix)
+ {
+ overlap1 &= (i.suffix == BYTE_MNEM_SUFFIX
+ ? Imm8 | Imm8S
+ : (i.suffix == WORD_MNEM_SUFFIX
+ ? Imm16
+ : (i.suffix == QWORD_MNEM_SUFFIX
+ ? Imm64 | Imm32S
+ : Imm32)));
}
+ else if (overlap1 == (Imm16 | Imm32 | Imm32S)
+ || overlap1 == (Imm16 | Imm32)
+ || overlap1 == (Imm16 | Imm32S))
+ {
+ overlap1 = ((flag_code == CODE_16BIT) ^ (i.prefix[DATA_PREFIX] != 0)
+ ? Imm16 : Imm32S);
}
-
- if (i.tm.opcode_modifier & ImmExt)
+ if (overlap1 != Imm8 && overlap1 != Imm8S
+ && overlap1 != Imm16 && overlap1 != Imm32S
+ && overlap1 != Imm32 && overlap1 != Imm64)
{
- /* These AMD 3DNow! and Intel Katmai New Instructions have an
- opcode suffix which is coded in the same place as an 8-bit
- immediate field would be. Here we fake an 8-bit immediate
- operand from the opcode suffix stored in tm.extension_opcode. */
-
- expressionS *exp;
+ as_bad (_("no instruction mnemonic suffix given; can't determine immediate size %x %c"),overlap1, i.suffix);
+ return 0;
+ }
+ }
+ i.types[1] = overlap1;
- assert (i.imm_operands == 0 && i.operands <= 2 && 2 < MAX_OPERANDS);
+ overlap2 = i.types[2] & i.tm.operand_types[2];
+ assert ((overlap2 & Imm) == 0);
+ i.types[2] = overlap2;
- exp = &im_expressions[i.imm_operands++];
- i.op[i.operands].imms = exp;
- i.types[i.operands++] = Imm8;
- exp->X_op = O_constant;
- exp->X_add_number = i.tm.extension_opcode;
- i.tm.extension_opcode = None;
+ return 1;
}
- /* For insns with operands there are more diddles to do to the opcode. */
- if (i.operands)
+static int
+process_operands ()
{
- /* Default segment register this instruction will use
- for memory accesses. 0 means unknown.
- This is only for optimizing out unnecessary segment overrides. */
+ /* Default segment register this instruction will use for memory
+ accesses. 0 means unknown. This is only for optimizing out
+ unnecessary segment overrides. */
const seg_entry *default_seg = 0;
/* The imul $imm, %reg instruction is converted into
@@ -2343,8 +2563,8 @@ md_assemble (line)
unsigned int op = (i.types[0] & (Reg | FloatReg)) ? 0 : 1;
/* Register goes in low 3 bits of opcode. */
i.tm.base_opcode |= i.op[op].regs->reg_num;
- if (i.op[op].regs->reg_flags & RegRex)
- i.rex.extZ = 1;
+ if ((i.op[op].regs->reg_flags & RegRex) != 0)
+ i.rex |= REX_EXTZ;
if (!quiet_warnings && (i.tm.opcode_modifier & Ugh) != 0)
{
/* Warn about some common errors, but press on regardless.
@@ -2371,6 +2591,50 @@ md_assemble (line)
Now, we make the modrm & index base bytes based on all the
info we've collected. */
+ default_seg = build_modrm_byte ();
+ }
+ else if (i.tm.opcode_modifier & (Seg2ShortForm | Seg3ShortForm))
+ {
+ if (i.tm.base_opcode == POP_SEG_SHORT
+ && i.op[0].regs->reg_num == 1)
+ {
+ as_bad (_("you can't `pop %%cs'"));
+ return 0;
+ }
+ i.tm.base_opcode |= (i.op[0].regs->reg_num << 3);
+ if ((i.op[0].regs->reg_flags & RegRex) != 0)
+ i.rex |= REX_EXTZ;
+ }
+ else if ((i.tm.base_opcode & ~(D | W)) == MOV_AX_DISP32)
+ {
+ default_seg = &ds;
+ }
+ else if ((i.tm.opcode_modifier & IsString) != 0)
+ {
+ /* For the string instructions that allow a segment override
+ on one of their operands, the default segment is ds. */
+ default_seg = &ds;
+ }
+
+ /* If a segment was explicitly specified,
+ and the specified segment is not the default,
+ use an opcode prefix to select it.
+ If we never figured out what the default segment is,
+ then default_seg will be zero at this point,
+ and the specified segment prefix will always be used. */
+ if ((i.seg[0]) && (i.seg[0] != default_seg))
+ {
+ if (!add_prefix (i.seg[0]->seg_prefix))
+ return 0;
+ }
+ return 1;
+}
+
+static const seg_entry *
+build_modrm_byte ()
+{
+ const seg_entry *default_seg = 0;
+
/* i.reg_operands MUST be the number of real register operands;
implicit registers do not count. */
if (i.reg_operands == 2)
@@ -2384,30 +2648,29 @@ md_assemble (line)
dest = source + 1;
i.rm.mode = 3;
- /* One of the register operands will be encoded in the
- i.tm.reg field, the other in the combined i.tm.mode
- and i.tm.regmem fields. If no form of this
- instruction supports a memory destination operand,
- then we assume the source operand may sometimes be
- a memory operand and so we need to store the
+ /* One of the register operands will be encoded in the i.tm.reg
+ field, the other in the combined i.tm.mode and i.tm.regmem
+ fields. If no form of this instruction supports a memory
+ destination operand, then we assume the source operand may
+ sometimes be a memory operand and so we need to store the
destination in the i.rm.reg field. */
if ((i.tm.operand_types[dest] & AnyMem) == 0)
{
i.rm.reg = i.op[dest].regs->reg_num;
i.rm.regmem = i.op[source].regs->reg_num;
- if (i.op[dest].regs->reg_flags & RegRex)
- i.rex.extX = 1;
- if (i.op[source].regs->reg_flags & RegRex)
- i.rex.extZ = 1;
+ if ((i.op[dest].regs->reg_flags & RegRex) != 0)
+ i.rex |= REX_EXTX;
+ if ((i.op[source].regs->reg_flags & RegRex) != 0)
+ i.rex |= REX_EXTZ;
}
else
{
i.rm.reg = i.op[source].regs->reg_num;
i.rm.regmem = i.op[dest].regs->reg_num;
- if (i.op[dest].regs->reg_flags & RegRex)
- i.rex.extZ = 1;
- if (i.op[source].regs->reg_flags & RegRex)
- i.rex.extX = 1;
+ if ((i.op[dest].regs->reg_flags & RegRex) != 0)
+ i.rex |= REX_EXTZ;
+ if ((i.op[source].regs->reg_flags & RegRex) != 0)
+ i.rex |= REX_EXTX;
}
}
else
@@ -2421,12 +2684,12 @@ md_assemble (line)
default_seg = &ds;
- if (! i.base_reg)
+ if (i.base_reg == 0)
{
i.rm.mode = 0;
if (! i.disp_operands)
fake_zero_displacement = 1;
- if (! i.index_reg)
+ if (i.index_reg == 0)
{
/* Operand is just <disp> */
if ((flag_code == CODE_16BIT) ^ (i.prefix[ADDR_PREFIX] != 0)
@@ -2445,12 +2708,10 @@ md_assemble (line)
}
else
{
- /* 64bit mode overwrites the 32bit
- absolute addressing by RIP relative
- addressing and absolute addressing
- is encoded by one of the redundant
- SIB forms. */
-
+ /* 64bit mode overwrites the 32bit absolute
+ addressing by RIP relative addressing and
+ absolute addressing is encoded by one of the
+ redundant SIB forms. */
i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
i.sib.base = NO_BASE_REGISTER;
i.sib.index = NO_INDEX_REGISTER;
@@ -2469,8 +2730,8 @@ md_assemble (line)
i.types[op] |= Disp32; /* Must be 32 bit */
else
i.types[op] |= Disp32S;
- if (i.index_reg->reg_flags & RegRex)
- i.rex.extY = 1;
+ if ((i.index_reg->reg_flags & RegRex) != 0)
+ i.rex |= REX_EXTY;
}
}
/* RIP addressing for 64bit mode. */
@@ -2486,14 +2747,14 @@ md_assemble (line)
switch (i.base_reg->reg_num)
{
case 3: /* (%bx) */
- if (! i.index_reg)
+ if (i.index_reg == 0)
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)
+ if (i.index_reg == 0)
{
i.rm.regmem = 6;
if ((i.types[op] & Disp) == 0)
@@ -2522,11 +2783,11 @@ md_assemble (line)
i.types[op] = Disp32S;
}
i.rm.regmem = i.base_reg->reg_num;
- if (i.base_reg->reg_flags & RegRex)
- i.rex.extZ = 1;
+ if ((i.base_reg->reg_flags & RegRex) != 0)
+ i.rex |= REX_EXTZ;
i.sib.base = i.base_reg->reg_num;
- /* x86-64 ignores REX prefix bit here to avoid
- decoder complications. */
+ /* x86-64 ignores REX prefix bit here to avoid decoder
+ complications. */
if ((i.base_reg->reg_num & 7) == EBP_REG_NUM)
{
default_seg = &ss;
@@ -2541,18 +2802,16 @@ md_assemble (line)
default_seg = &ss;
}
i.sib.scale = i.log2_scale_factor;
- if (! i.index_reg)
+ if (i.index_reg == 0)
{
- /* <disp>(%esp) becomes two byte modrm
- with no index register. We've already
- stored the code for esp in i.rm.regmem
- ie. ESCAPE_TO_TWO_BYTE_ADDRESSING. Any
- base register besides %esp will not use
- the extra modrm byte. */
+ /* <disp>(%esp) becomes two byte modrm with no index
+ register. We've already stored the code for esp
+ in i.rm.regmem ie. ESCAPE_TO_TWO_BYTE_ADDRESSING.
+ Any base register besides %esp will not use the
+ extra modrm byte. */
i.sib.index = NO_INDEX_REGISTER;
#if ! SCALE1_WHEN_NO_INDEX
- /* Another case where we force the second
- modrm byte. */
+ /* Another case where we force the second modrm byte. */
if (i.log2_scale_factor)
i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
#endif
@@ -2561,8 +2820,8 @@ md_assemble (line)
{
i.sib.index = i.index_reg->reg_num;
i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
- if (i.index_reg->reg_flags & RegRex)
- i.rex.extY = 1;
+ if ((i.index_reg->reg_flags & RegRex) != 0)
+ i.rex |= REX_EXTY;
}
i.rm.mode = mode_from_disp_size (i.types[op]);
}
@@ -2583,11 +2842,10 @@ md_assemble (line)
}
}
- /* Fill in i.rm.reg or i.rm.regmem field with register
- operand (if any) based on i.tm.extension_opcode.
- Again, we must be careful to make sure that
- segment/control/debug/test/MMX registers are coded
- into the i.rm.reg field. */
+ /* Fill in i.rm.reg or i.rm.regmem field with register operand
+ (if any) based on i.tm.extension_opcode. Again, we must be
+ careful to make sure that segment/control/debug/test/MMX
+ registers are coded into the i.rm.reg field. */
if (i.reg_operands)
{
unsigned int op =
@@ -2602,24 +2860,24 @@ md_assemble (line)
| Control | Debug | Test))
? 1
: 2));
- /* If there is an extension opcode to put here, the
- register number must be put into the regmem field. */
+ /* If there is an extension opcode to put here, the register
+ number must be put into the regmem field. */
if (i.tm.extension_opcode != None)
{
i.rm.regmem = i.op[op].regs->reg_num;
- if (i.op[op].regs->reg_flags & RegRex)
- i.rex.extZ = 1;
+ if ((i.op[op].regs->reg_flags & RegRex) != 0)
+ i.rex |= REX_EXTZ;
}
else
{
i.rm.reg = i.op[op].regs->reg_num;
- if (i.op[op].regs->reg_flags & RegRex)
- i.rex.extX = 1;
+ if ((i.op[op].regs->reg_flags & RegRex) != 0)
+ i.rex |= REX_EXTX;
}
- /* Now, if no memory operand has set i.rm.mode = 0, 1, 2
- we must set it to 3 to indicate this is a register
- operand in the regmem field. */
+ /* Now, if no memory operand has set i.rm.mode = 0, 1, 2 we
+ must set it to 3 to indicate this is a register operand
+ in the regmem field. */
if (!i.mem_operands)
i.rm.mode = 3;
}
@@ -2627,120 +2885,14 @@ md_assemble (line)
/* Fill in i.rm.reg field with extension opcode (if any). */
if (i.tm.extension_opcode != None)
i.rm.reg = i.tm.extension_opcode;
- }
- }
- else if (i.tm.opcode_modifier & (Seg2ShortForm | Seg3ShortForm))
- {
- if (i.tm.base_opcode == POP_SEG_SHORT
- && i.op[0].regs->reg_num == 1)
- {
- as_bad (_("you can't `pop %%cs'"));
- return;
- }
- i.tm.base_opcode |= (i.op[0].regs->reg_num << 3);
- if (i.op[0].regs->reg_flags & RegRex)
- i.rex.extZ = 1;
- }
- else if ((i.tm.base_opcode & ~(D|W)) == MOV_AX_DISP32)
- {
- default_seg = &ds;
- }
- else if ((i.tm.opcode_modifier & IsString) != 0)
- {
- /* For the string instructions that allow a segment override
- on one of their operands, the default segment is ds. */
- default_seg = &ds;
- }
-
- /* If a segment was explicitly specified,
- and the specified segment is not the default,
- use an opcode prefix to select it.
- If we never figured out what the default segment is,
- then default_seg will be zero at this point,
- and the specified segment prefix will always be used. */
- if ((i.seg[0]) && (i.seg[0] != default_seg))
- {
- if (! add_prefix (i.seg[0]->seg_prefix))
- return;
- }
- }
- else if (!quiet_warnings && (i.tm.opcode_modifier & Ugh) != 0)
- {
- /* UnixWare fsub no args is alias for fsubp, fadd -> faddp, etc. */
- as_warn (_("translating to `%sp'"), i.tm.name);
- }
- }
-
- /* Handle conversion of 'int $3' --> special int3 insn. */
- if (i.tm.base_opcode == INT_OPCODE && i.op[0].imms->X_add_number == 3)
- {
- i.tm.base_opcode = INT3_OPCODE;
- i.imm_operands = 0;
- }
-
- if ((i.tm.opcode_modifier & (Jump | JumpByte | JumpDword))
- && i.op[0].disps->X_op == O_constant)
- {
- /* Convert "jmp constant" (and "call constant") to a jump (call) to
- the absolute address given by the constant. Since ix86 jumps and
- calls are pc relative, we need to generate a reloc. */
- i.op[0].disps->X_add_symbol = &abs_symbol;
- i.op[0].disps->X_op = O_symbol;
- }
-
- if (i.tm.opcode_modifier & Rex64)
- i.rex.mode64 = 1;
-
- /* For 8bit registers we would need an empty rex prefix.
- Also in the case instruction is already having prefix,
- we need to convert old registers to new ones. */
-
- if (((i.types[0] & Reg8) && (i.op[0].regs->reg_flags & RegRex64))
- || ((i.types[1] & Reg8) && (i.op[1].regs->reg_flags & RegRex64))
- || ((i.rex.mode64 || i.rex.extX || i.rex.extY || i.rex.extZ || i.rex.empty)
- && ((i.types[0] & Reg8) || (i.types[1] & Reg8))))
- {
- int x;
- i.rex.empty = 1;
- for (x = 0; x < 2; x++)
- {
- /* Look for 8bit operand that does use old registers. */
- if (i.types[x] & Reg8
- && !(i.op[x].regs->reg_flags & RegRex64))
- {
- /* In case it is "hi" register, give up. */
- if (i.op[x].regs->reg_num > 3)
- as_bad (_("Can't encode registers '%%%s' in the instruction requiring REX prefix.\n"),
- i.op[x].regs->reg_name);
-
- /* Otherwise it is equivalent to the extended register.
- Since the encoding don't change this is merely cosmetical
- cleanup for debug output. */
-
- i.op[x].regs = i.op[x].regs + 8;
}
+ return default_seg;
}
- }
-
- if (i.rex.mode64 || i.rex.extX || i.rex.extY || i.rex.extZ || i.rex.empty)
- add_prefix (0x40
- | (i.rex.mode64 ? 8 : 0)
- | (i.rex.extX ? 4 : 0)
- | (i.rex.extY ? 2 : 0)
- | (i.rex.extZ ? 1 : 0));
-
- /* We are ready to output the insn. */
- {
- register char *p;
-
- /* Tie dwarf2 debug info to the address at the start of the insn.
- We can't do this after the insn has been output as the current
- frag may have been closed off. eg. by frag_var. */
- dwarf2_emit_insn (0);
- /* Output jumps. */
- if (i.tm.opcode_modifier & Jump)
+static void
+output_branch ()
{
+ char *p;
int code16;
int prefix;
relax_substateT subtype;
@@ -2752,7 +2904,7 @@ md_assemble (line)
code16 = CODE16;
prefix = 0;
- if (i.prefix[DATA_PREFIX])
+ if (i.prefix[DATA_PREFIX] != 0)
{
prefix = 1;
i.prefixes -= 1;
@@ -2765,7 +2917,7 @@ md_assemble (line)
prefix++;
i.prefixes--;
}
- if (i.prefix[REX_PREFIX])
+ if (i.prefix[REX_PREFIX] != 0)
{
prefix++;
i.prefixes--;
@@ -2782,12 +2934,12 @@ md_assemble (line)
frag_grow (prefix + 2 + 4);
/* Prefix and 1 opcode byte go in fr_fix. */
p = frag_more (prefix + 1);
- if (i.prefix[DATA_PREFIX])
+ if (i.prefix[DATA_PREFIX] != 0)
*p++ = DATA_PREFIX_OPCODE;
if (i.prefix[SEG_PREFIX] == CS_PREFIX_OPCODE
|| i.prefix[SEG_PREFIX] == DS_PREFIX_OPCODE)
*p++ = i.prefix[SEG_PREFIX];
- if (i.prefix[REX_PREFIX])
+ if (i.prefix[REX_PREFIX] != 0)
*p++ = i.prefix[REX_PREFIX];
*p = i.tm.base_opcode;
@@ -2814,15 +2966,18 @@ md_assemble (line)
Pass reloc in fr_var. */
frag_var (rs_machine_dependent, 5, i.reloc[0], subtype, sym, off, p);
}
- else if (i.tm.opcode_modifier & (JumpByte | JumpDword))
+
+static void
+output_jump ()
{
+ char *p;
int size;
if (i.tm.opcode_modifier & JumpByte)
{
/* This is a loop or jecxz type instruction. */
size = 1;
- if (i.prefix[ADDR_PREFIX])
+ if (i.prefix[ADDR_PREFIX] != 0)
{
FRAG_APPEND_1_CHAR (ADDR_PREFIX_OPCODE);
i.prefixes -= 1;
@@ -2843,7 +2998,7 @@ md_assemble (line)
if (flag_code == CODE_16BIT)
code16 = CODE16;
- if (i.prefix[DATA_PREFIX])
+ if (i.prefix[DATA_PREFIX] != 0)
{
FRAG_APPEND_1_CHAR (DATA_PREFIX_OPCODE);
i.prefixes -= 1;
@@ -2855,7 +3010,7 @@ md_assemble (line)
size = 2;
}
- if (i.prefix[REX_PREFIX])
+ if (i.prefix[REX_PREFIX] != 0)
{
FRAG_APPEND_1_CHAR (i.prefix[REX_PREFIX]);
i.prefixes -= 1;
@@ -2870,8 +3025,11 @@ md_assemble (line)
fix_new_exp (frag_now, p - frag_now->fr_literal, size,
i.op[0].disps, 1, reloc (size, 1, 1, i.reloc[0]));
}
- else if (i.tm.opcode_modifier & JumpInterSegment)
+
+static void
+output_interseg_jump ()
{
+ char *p;
int size;
int prefix;
int code16;
@@ -2881,13 +3039,13 @@ md_assemble (line)
code16 = CODE16;
prefix = 0;
- if (i.prefix[DATA_PREFIX])
+ if (i.prefix[DATA_PREFIX] != 0)
{
prefix = 1;
i.prefixes -= 1;
code16 ^= CODE16;
}
- if (i.prefix[REX_PREFIX])
+ if (i.prefix[REX_PREFIX] != 0)
{
prefix++;
i.prefixes -= 1;
@@ -2903,10 +3061,10 @@ md_assemble (line)
/* 1 opcode; 2 segment; offset */
p = frag_more (prefix + 1 + 2 + size);
- if (i.prefix[DATA_PREFIX])
+ if (i.prefix[DATA_PREFIX] != 0)
*p++ = DATA_PREFIX_OPCODE;
- if (i.prefix[REX_PREFIX])
+ if (i.prefix[REX_PREFIX] != 0)
*p++ = i.prefix[REX_PREFIX];
*p++ = i.tm.base_opcode;
@@ -2931,13 +3089,30 @@ md_assemble (line)
i.tm.name);
md_number_to_chars (p + size, (valueT) i.op[0].imms->X_add_number, 2);
}
+
+static void
+output_insn ()
+{
+ /* Tie dwarf2 debug info to the address at the start of the insn.
+ We can't do this after the insn has been output as the current
+ frag may have been closed off. eg. by frag_var. */
+ dwarf2_emit_insn (0);
+
+ /* Output jumps. */
+ if (i.tm.opcode_modifier & Jump)
+ output_branch ();
+ else if (i.tm.opcode_modifier & (JumpByte | JumpDword))
+ output_jump ();
+ else if (i.tm.opcode_modifier & JumpInterSegment)
+ output_interseg_jump ();
else
{
/* Output normal instructions here. */
+ char *p;
unsigned char *q;
- /* All opcodes on i386 have eighter 1 or 2 bytes. We may use third
- byte for the SSE instructions to specify prefix they require. */
+ /* All opcodes on i386 have either 1 or 2 bytes. We may use third
+ byte for the SSE instructions to specify a prefix they require. */
if (i.tm.base_opcode & 0xff0000)
add_prefix ((i.tm.base_opcode >> 16) & 0xff);
@@ -2993,8 +3168,25 @@ md_assemble (line)
}
if (i.disp_operands)
+ output_disp ();
+
+ if (i.imm_operands)
+ output_imm ();
+ }
+
+#ifdef DEBUG386
+ if (flag_debug)
+ {
+ pi (line, &i);
+ }
+#endif /* DEBUG386 */
+}
+
+static void
+output_disp ()
{
- register unsigned int n;
+ char *p;
+ unsigned int n;
for (n = 0; n < i.operands; n++)
{
@@ -3031,7 +3223,7 @@ md_assemble (line)
if (pcrel && i.imm_operands)
{
int imm_size = 4;
- register unsigned int n1;
+ unsigned int n1;
for (n1 = 0; n1 < i.operands; n1++)
if (i.types[n1] & Imm)
@@ -3071,10 +3263,11 @@ md_assemble (line)
}
}
- /* Output immediate. */
- if (i.imm_operands)
+static void
+output_imm ()
{
- register unsigned int n;
+ char *p;
+ unsigned int n;
for (n = 0; n < i.operands; n++)
{
@@ -3146,16 +3339,6 @@ md_assemble (line)
}
}
}
- }
-
-#ifdef DEBUG386
- if (flag_debug)
- {
- pi (line, &i);
- }
-#endif /* DEBUG386 */
- }
-}
#ifndef LEX_AT
static char *lex_got PARAMS ((RELOC_ENUM *, int *));
@@ -3426,7 +3609,7 @@ i386_scale (scale)
input_line_pointer = save;
return NULL;
}
- if (i.log2_scale_factor != 0 && ! i.index_reg)
+ if (i.log2_scale_factor != 0 && i.index_reg == 0)
{
as_warn (_("scale factor of %d without an index register"),
1 << i.log2_scale_factor);
@@ -3446,7 +3629,7 @@ i386_displacement (disp_start, disp_end)
char *disp_start;
char *disp_end;
{
- register expressionS *exp;
+ expressionS *exp;
segT exp_seg = 0;
char *save_input_line_pointer;
#ifndef LEX_AT
@@ -3456,7 +3639,7 @@ i386_displacement (disp_start, disp_end)
if (flag_code == CODE_64BIT)
{
- if (!i.prefix[ADDR_PREFIX])
+ if (i.prefix[ADDR_PREFIX] == 0)
bigdisp = Disp64;
}
else if ((flag_code == CODE_16BIT) ^ (i.prefix[ADDR_PREFIX] != 0))
@@ -3999,8 +4182,8 @@ i386_operand (operand_string)
int
md_estimate_size_before_relax (fragP, segment)
- register fragS *fragP;
- register segT segment;
+ fragS *fragP;
+ segT segment;
{
/* We've already got fragP->fr_subtype right; all we have to do is
check for un-relaxable symbols. On an ELF system, we can't relax
@@ -4113,16 +4296,16 @@ void
md_convert_frag (headers, sec, fragP)
object_headers *headers ATTRIBUTE_UNUSED;
segT sec ATTRIBUTE_UNUSED;
- register fragS *fragP;
+ fragS *fragP;
#else
void
md_convert_frag (abfd, sec, fragP)
bfd *abfd ATTRIBUTE_UNUSED;
segT sec ATTRIBUTE_UNUSED;
- register fragS *fragP;
+ fragS *fragP;
#endif
{
- register unsigned char *opcode;
+ unsigned char *opcode;
unsigned char *where_to_put_displacement = NULL;
offsetT target_address;
offsetT opcode_address;
@@ -4545,7 +4728,7 @@ parse_register (reg_string, end_op)
}
if (r != NULL
- && r->reg_flags & (RegRex64|RegRex)
+ && (r->reg_flags & (RegRex64 | RegRex)) != 0
&& flag_code != CODE_64BIT)
{
return (const reg_entry *) NULL;
@@ -4796,7 +4979,7 @@ static void
s_bss (ignore)
int ignore ATTRIBUTE_UNUSED;
{
- register int temp;
+ int temp;
temp = get_absolute_expression ();
subseg_set (bss_section, (subsegT) temp);
Index: gas/config/tc-i386.h
===================================================================
RCS file: /cvs/src/src/gas/config/tc-i386.h,v
retrieving revision 1.29
diff -u -p -w -r1.29 tc-i386.h
--- tc-i386.h 2001/11/15 21:28:55 1.29
+++ tc-i386.h 2002/03/09 05:16:13
@@ -467,15 +467,17 @@ typedef struct
modrm_byte;
/* x86-64 extension prefix. */
-typedef struct
- {
- unsigned int mode64;
- unsigned int extX; /* Used to extend modrm reg field. */
- unsigned int extY; /* Used to extend SIB index field. */
- unsigned int extZ; /* Used to extend modrm reg/mem, SIB base, modrm base fields. */
- unsigned int empty; /* Used to old-style byte registers to new style. */
- }
-rex_byte;
+typedef int rex_byte;
+#define REX_OPCODE 0x40
+
+/* Indicates 64 bit operand size. */
+#define REX_MODE64 8
+/* High extension to reg field of modrm byte. */
+#define REX_EXTX 4
+/* High extension to SIB index field. */
+#define REX_EXTY 2
+/* High extension to base field of modrm or SIB, or reg field of opcode. */
+#define REX_EXTZ 1
/* 386 opcode byte to code indirect addressing. */
typedef struct
More information about the Binutils
mailing list