/* i386.c -- Assemble code for the Intel 80386
- Copyright (C) 1989, 91, 92, 93, 94, 95, 96, 97, 98, 1999
+ Copyright (C) 1989, 91, 92, 93, 94, 95, 96, 97, 98, 99, 2000
Free Software Foundation.
This file is part of GAS, the GNU Assembler.
#include "subsegs.h"
#include "opcode/i386.h"
-#ifndef TC_RELOC
-#define TC_RELOC(X,Y) (Y)
-#endif
-
#ifndef REGISTER_WARNINGS
#define REGISTER_WARNINGS 1
#endif
#define false 0
static unsigned int mode_from_disp_size PARAMS ((unsigned int));
-static int fits_in_signed_byte PARAMS ((long));
-static int fits_in_unsigned_byte PARAMS ((long));
-static int fits_in_unsigned_word PARAMS ((long));
-static int fits_in_signed_word PARAMS ((long));
-static int smallest_imm_type PARAMS ((long));
+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 smallest_imm_type PARAMS ((offsetT));
+static offsetT offset_in_range PARAMS ((offsetT, int));
static int add_prefix PARAMS ((unsigned int));
static void set_16bit_code_flag PARAMS ((int));
static void set_16bit_gcc_code_flag PARAMS((int));
/* 'md_assemble ()' gathers together information and puts it into a
i386_insn. */
+union i386_op
+ {
+ expressionS *disps;
+ expressionS *imms;
+ const reg_entry *regs;
+ };
+
struct _i386_insn
{
/* TM holds the template for the insn were currently assembling. */
(e.g. 'l' for 'movl') */
char suffix;
- /* Operands are coded with OPERANDS, TYPES, DISPS, IMMS, and REGS. */
-
/* OPERANDS gives the number of given operands. */
unsigned int operands;
unsigned int reg_operands, disp_operands, mem_operands, imm_operands;
/* TYPES [i] is the type (see above #defines) which tells us how to
- search through DISPS [i] & IMMS [i] & REGS [i] for the required
- operand. */
+ use OP[i] for the corresponding operand. */
unsigned int types[MAX_OPERANDS];
- /* Displacements (if given) for each operand. */
- expressionS *disps[MAX_OPERANDS];
+ /* Displacement expression, immediate expression, or register for each
+ operand. */
+ union i386_op op[MAX_OPERANDS];
/* Relocation type for operand */
#ifdef BFD_ASSEMBLER
int disp_reloc[MAX_OPERANDS];
#endif
- /* Immediate operands (if given) for each operand. */
- expressionS *imms[MAX_OPERANDS];
-
- /* Register operands (if given) for each operand. */
- const reg_entry *regs[MAX_OPERANDS];
-
/* BASE_REG, INDEX_REG, and LOG2_SCALE_FACTOR are used to encode
the base index byte below. */
const reg_entry *base_reg;
static char stackop_size = '\0'; /* Used in 16 bit gcc mode to add an l
suffix to call, ret, enter, leave, push,
- and pop instructions. */
+ and pop instructions so that gcc has the
+ same stack frame as in 32 bit mode. */
/* Interface to relax_segment.
There are 2 relax states for 386 jump insns: one for conditional &
- one for unconditional jumps. This is because the these two types
- of jumps add different sizes to frags when we're figuring out what
+ one for unconditional jumps. This is because these two types of
+ jumps add different sizes to frags when we're figuring out what
sort of jump to choose to reach a given label. */
/* types */
static INLINE int
fits_in_signed_byte (num)
- long num;
+ offsetT num;
{
return (num >= -128) && (num <= 127);
} /* fits_in_signed_byte() */
static INLINE int
fits_in_unsigned_byte (num)
- long num;
+ offsetT num;
{
return (num & 0xff) == num;
} /* fits_in_unsigned_byte() */
static INLINE int
fits_in_unsigned_word (num)
- long num;
+ offsetT num;
{
return (num & 0xffff) == num;
} /* fits_in_unsigned_word() */
static INLINE int
fits_in_signed_word (num)
- long num;
+ offsetT num;
{
return (-32768 <= num) && (num <= 32767);
} /* fits_in_signed_word() */
static int
smallest_imm_type (num)
- long num;
+ offsetT num;
{
#if 0
/* This code is disabled because all the Imm1 forms in the opcode table
: (Imm32));
} /* smallest_imm_type() */
+static offsetT
+offset_in_range (val, size)
+ offsetT val;
+ int size;
+{
+ bfd_vma mask;
+
+ switch (size)
+ {
+ case 1: mask = ((bfd_vma) 1 << 8) - 1; break;
+ case 2: mask = ((bfd_vma) 1 << 16) - 1; break;
+ case 4: mask = ((bfd_vma) 1 << 32) - 1; break;
+ default: abort();
+ }
+
+ /* If BFD64, sign extend val. */
+ if ((val & ~ (((bfd_vma) 1 << 32) - 1)) == 0)
+ val = (val ^ ((bfd_vma) 1 << 31)) - ((bfd_vma) 1 << 31);
+
+ if ((val & ~ mask) != 0 && (val & ~ mask) != ~ mask)
+ {
+ char buf1[40], buf2[40];
+
+ sprint_value (buf1, val);
+ sprint_value (buf2, val & mask);
+ as_warn (_("%s shortened to %s"), buf1, buf2);
+ }
+ return val & mask;
+}
+
/* Returns 0 if attempting to add a prefix where one from the same
class already exists, 1 if non rep/repne added, 2 if rep/repne
added. */
else if (strcmp(string, "noprefix") == 0)
ask_naked_reg = -1;
else
- as_bad (_("Bad argument to syntax directive."));
+ as_bad (_("bad argument to syntax directive."));
*input_line_pointer = e;
}
demand_empty_rest_of_line ();
fprintf (stdout, "\n");
if (x->types[i]
& (Reg | SReg2 | SReg3 | Control | Debug | Test | RegMMX | RegXMM))
- fprintf (stdout, "%s\n", x->regs[i]->reg_name);
+ fprintf (stdout, "%s\n", x->op[i].regs->reg_name);
if (x->types[i] & Imm)
- pe (x->imms[i]);
+ pe (x->op[i].imms);
if (x->types[i] & Disp)
- pe (x->disps[i]);
+ pe (x->op[i].disps);
}
}
return 0;
#else
/* For COFF */
- return fixp->fx_r_type==7;
+ return fixp->fx_r_type == 7;
#endif
}
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);
+ as_bad (_("can not do %d byte pc-relative relocation"), size);
}
else
{
case 2: return BFD_RELOC_16;
case 4: return BFD_RELOC_32;
}
- as_bad (_("Can not do %d byte relocation"), size);
+ as_bad (_("can not do %d byte relocation"), size);
}
return BFD_RELOC_NONE;
if (fixP->fx_r_type == BFD_RELOC_386_GOTOFF
|| fixP->fx_r_type == BFD_RELOC_386_PLT32
|| fixP->fx_r_type == BFD_RELOC_386_GOT32
+ || fixP->fx_r_type == BFD_RELOC_RVA
|| fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
|| fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
return 0;
char *mnemonic;
{
if (mnemonic[0] == 'f' && mnemonic[1] =='i')
- return 0;
+ return 2;
if (mnemonic[0] == 'f')
return 1;
/* See if we can get a match by trimming off a suffix. */
switch (mnem_p[-1])
{
- case DWORD_MNEM_SUFFIX:
case WORD_MNEM_SUFFIX:
case BYTE_MNEM_SUFFIX:
case SHORT_MNEM_SUFFIX:
-#if LONG_MNEM_SUFFIX != DWORD_MNEM_SUFFIX
case LONG_MNEM_SUFFIX:
-#endif
i.suffix = mnem_p[-1];
mnem_p[-1] = '\0';
current_templates = hash_find (op_hash, mnemonic);
break;
/* Intel Syntax */
- case INTEL_DWORD_MNEM_SUFFIX:
+ case DWORD_MNEM_SUFFIX:
if (intel_syntax)
{
i.suffix = mnem_p[-1];
with the template operand types. */
#define MATCH(overlap, given, template) \
- ((overlap) \
- && ((given) & BaseIndex) == ((overlap) & BaseIndex) \
- && ((given) & JumpAbsolute) == ((template) & JumpAbsolute))
+ ((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.
unsigned int found_reverse_match;
int suffix_check;
- /* All intel opcodes have reversed operands except for BOUND and ENTER */
- if (intel_syntax
- && (strcmp (mnemonic, "enter") != 0)
+ /* 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)
- && (strncmp (mnemonic, "fsub", 4) !=0)
- && (strncmp (mnemonic, "fdiv", 4) !=0))
+ && !((i.types[0] & Imm) && (i.types[1] & Imm)))
{
- const reg_entry *temp_reg = NULL;
- expressionS *temp_disp = NULL;
- expressionS *temp_imm = NULL;
+ union i386_op temp_op;
unsigned int temp_type;
int xchg1 = 0;
int xchg2 = 0;
xchg1 = 0;
xchg2 = 2;
}
-
- if (i.operands > 1)
+ temp_type = i.types[xchg2];
+ i.types[xchg2] = i.types[xchg1];
+ i.types[xchg1] = temp_type;
+ temp_op = i.op[xchg2];
+ i.op[xchg2] = i.op[xchg1];
+ i.op[xchg1] = temp_op;
+
+ if (i.mem_operands == 2)
{
- temp_type = i.types[xchg2];
- if (temp_type & (Reg | FloatReg))
- temp_reg = i.regs[xchg2];
- else if (temp_type & Imm)
- temp_imm = i.imms[xchg2];
- else if (temp_type & Disp)
- temp_disp = i.disps[xchg2];
-
- i.types[xchg2] = i.types[xchg1];
-
- if (i.types[xchg1] & (Reg | FloatReg))
- {
- i.regs[xchg2] = i.regs[xchg1];
- i.regs[xchg1] = NULL;
- }
- else if (i.types[xchg2] & Imm)
- {
- i.imms[xchg2] = i.imms[xchg1];
- i.imms[xchg1] = NULL;
- }
- else if (i.types[xchg2] & Disp)
- {
- i.disps[xchg2] = i.disps[xchg1];
- i.disps[xchg1] = NULL;
- }
+ const seg_entry *temp_seg;
+ temp_seg = i.seg[0];
+ i.seg[0] = i.seg[1];
+ i.seg[1] = temp_seg;
+ }
+ }
- if (temp_type & (Reg | FloatReg))
- {
- i.regs[xchg1] = temp_reg;
- if (! (i.types[xchg1] & (Reg | FloatReg)))
- i.regs[xchg2] = NULL;
- }
- else if (temp_type & Imm)
- {
- i.imms[xchg1] = temp_imm;
- if (! (i.types[xchg1] & Imm))
- i.imms[xchg2] = NULL;
- }
- else if (temp_type & Disp)
- {
- i.disps[xchg1] = temp_disp;
- if (! (i.types[xchg1] & Disp))
- i.disps[xchg2] = NULL;
- }
+ if (i.imm_operands)
+ {
+ /* Try to ensure constant immediates are represented in the smallest
+ opcode possible. */
+ char guess_suffix = 0;
+ int op;
- i.types[xchg1] = temp_type;
+ if (i.suffix)
+ guess_suffix = i.suffix;
+ else if (i.reg_operands)
+ {
+ /* Figure out a suffix from the last register operand specified.
+ We can't do this properly yet, ie. excluding InOutPortReg,
+ but the following works for instructions with immediates.
+ In any case, we can't set i.suffix yet. */
+ for (op = i.operands; --op >= 0; )
+ if (i.types[op] & Reg)
+ {
+ if (i.types[op] & Reg8)
+ guess_suffix = BYTE_MNEM_SUFFIX;
+ else if (i.types[op] & Reg16)
+ guess_suffix = WORD_MNEM_SUFFIX;
+ break;
+ }
}
- if (!strcmp(mnemonic,"jmp")
- || !strcmp (mnemonic, "call"))
- if ((i.types[0] & Reg) || i.types[0] & BaseIndex)
- i.types[0] |= JumpAbsolute;
+ else if (flag_16bit_code ^ (i.prefix[DATA_PREFIX] != 0))
+ guess_suffix = WORD_MNEM_SUFFIX;
+ for (op = i.operands; --op >= 0; )
+ if ((i.types[op] & Imm)
+ && i.op[op].imms->X_op == O_constant)
+ {
+ /* If a suffix is given, this operand may be shortened. */
+ switch (guess_suffix)
+ {
+ case WORD_MNEM_SUFFIX:
+ i.types[op] |= Imm16;
+ break;
+ case BYTE_MNEM_SUFFIX:
+ i.types[op] |= Imm16 | Imm8 | Imm8S;
+ break;
+ }
+
+ /* If this operand is at most 16 bits, convert it to a
+ signed 16 bit number before trying to see whether it will
+ fit in an even smaller size. This allows a 16-bit operand
+ such as $0xffe0 to be recognised as within Imm8S range. */
+ if ((i.types[op] & Imm16)
+ && (i.op[op].imms->X_add_number & ~(offsetT)0xffff) == 0)
+ {
+ i.op[op].imms->X_add_number =
+ (((i.op[op].imms->X_add_number & 0xffff) ^ 0x8000) - 0x8000);
+ }
+ i.types[op] |= smallest_imm_type ((long) i.op[op].imms->X_add_number);
+ }
}
+
overlap0 = 0;
overlap1 = 0;
overlap2 = 0;
? No_sSuf
: (i.suffix == LONG_MNEM_SUFFIX
? No_lSuf
- : (i.suffix == INTEL_DWORD_MNEM_SUFFIX
+ : (i.suffix == DWORD_MNEM_SUFFIX
? No_dSuf
: (i.suffix == LONG_DOUBLE_MNEM_SUFFIX ? No_xSuf : 0))))));
if (i.operands != t->operands)
continue;
- /* For some opcodes, don't check the suffix */
- if (intel_syntax)
- {
- if (strcmp (t->name, "fnstcw")
- && strcmp (t->name, "fldcw")
- && (t->opcode_modifier & suffix_check))
- continue;
- }
- /* Must not have disallowed suffix. */
- else if ((t->opcode_modifier & suffix_check))
+ /* Check the suffix, except for some instructions in intel mode. */
+ if ((t->opcode_modifier & suffix_check)
+ && !(intel_syntax
+ && t->base_opcode == 0xd9
+ && (t->extension_opcode == 5 /* 0xd9,5 "fldcw" */
+ || t->extension_opcode == 7))) /* 0xd9,7 "f{n}stcw" */
continue;
else if (!t->operands)
return;
}
+ if (!intel_syntax
+ && (i.types[0] & JumpAbsolute) != (t->operand_types[0] & JumpAbsolute))
+ {
+ as_warn (_("indirect %s without `*'"), t->name);
+ }
+
if ((t->opcode_modifier & (IsPrefix|IgnoreSize)) == (IsPrefix|IgnoreSize))
{
/* Warn them that a data or address size prefix doesn't affect
i.tm = *t;
if (found_reverse_match)
{
+ /* 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). */
+
+ i.tm.base_opcode ^= found_reverse_match;
+
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))
if (i.tm.opcode_modifier & Size16)
i.suffix = WORD_MNEM_SUFFIX;
else
- i.suffix = DWORD_MNEM_SUFFIX;
+ i.suffix = LONG_MNEM_SUFFIX;
}
else if (i.reg_operands)
{
register type. */
int op;
for (op = i.operands; --op >= 0; )
- if (i.types[op] & Reg)
+ if ((i.types[op] & Reg)
+ && !(i.tm.operand_types[op] & InOutPortReg))
{
i.suffix = ((i.types[op] & Reg8) ? BYTE_MNEM_SUFFIX :
(i.types[op] & Reg16) ? WORD_MNEM_SUFFIX :
- DWORD_MNEM_SUFFIX);
+ LONG_MNEM_SUFFIX);
break;
}
}
|| i.tm.base_opcode == 0xfbf))
continue;
- if ((i.types[op] & WordReg) && i.regs[op]->reg_num < 4
+ 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
#if REGISTER_WARNINGS
if ((i.tm.operand_types[op] & InOutPortReg) == 0)
as_warn (_("using `%%%s' instead of `%%%s' due to `%c' suffix"),
- (i.regs[op] - (i.types[op] & Reg16 ? 8 : 16))->reg_name,
- i.regs[op]->reg_name,
+ (i.op[op].regs - (i.types[op] & Reg16 ? 8 : 16))->reg_name,
+ i.op[op].regs->reg_name,
i.suffix);
#endif
continue;
| FloatReg | FloatAcc))
{
as_bad (_("`%%%s' not allowed with `%s%c'"),
- i.regs[op]->reg_name,
+ i.op[op].regs->reg_name,
i.tm.name,
i.suffix);
return;
}
}
}
- else if (i.suffix == DWORD_MNEM_SUFFIX)
+ else if (i.suffix == LONG_MNEM_SUFFIX)
{
int op;
for (op = i.operands; --op >= 0; )
&& (i.tm.operand_types[op] & (Reg16|Reg32|Acc)) != 0)
{
as_bad (_("`%%%s' not allowed with `%s%c'"),
- i.regs[op]->reg_name,
+ i.op[op].regs->reg_name,
i.tm.name,
i.suffix);
return;
&& (i.tm.operand_types[op] & (Reg32|Acc)) != 0)
{
as_warn (_("using `%%%s' instead of `%%%s' due to `%c' suffix"),
- (i.regs[op] + 8)->reg_name,
- i.regs[op]->reg_name,
+ (i.op[op].regs + 8)->reg_name,
+ i.op[op].regs->reg_name,
i.suffix);
}
#endif
&& (i.tm.operand_types[op] & (Reg16|Reg32|Acc)) != 0)
{
as_bad (_("`%%%s' not allowed with `%s%c'"),
- i.regs[op]->reg_name,
+ i.op[op].regs->reg_name,
i.tm.name,
i.suffix);
return;
&& (i.tm.operand_types[op] & (Reg16|Acc)) != 0)
{
as_warn (_("using `%%%s' instead of `%%%s' due to `%c' suffix"),
- (i.regs[op] - 8)->reg_name,
- i.regs[op]->reg_name,
+ (i.op[op].regs - 8)->reg_name,
+ i.op[op].regs->reg_name,
i.suffix);
}
#endif
{
unsigned int prefix = DATA_PREFIX_OPCODE;
- if ((i.regs[1]->reg_type & Reg16) != 0)
+ if ((i.op[1].regs->reg_type & Reg16) != 0)
if (!add_prefix (prefix))
return;
}
/* Now select between word & dword operations via the operand
size prefix, except for instructions that will ignore this
prefix anyway. */
- if (((intel_syntax && (i.suffix == INTEL_DWORD_MNEM_SUFFIX))
- || i.suffix == DWORD_MNEM_SUFFIX
+ if (((intel_syntax && (i.suffix == DWORD_MNEM_SUFFIX))
|| i.suffix == LONG_MNEM_SUFFIX) == flag_16bit_code
&& !(i.tm.opcode_modifier & IgnoreSize))
{
}
/* Size floating point instruction. */
if (i.suffix == LONG_MNEM_SUFFIX
- || (intel_syntax && i.suffix == INTEL_DWORD_MNEM_SUFFIX))
+ || (intel_syntax && i.suffix == DWORD_MNEM_SUFFIX))
{
if (i.tm.opcode_modifier & FloatMF)
i.tm.base_opcode ^= 4;
expressionS *exp;
- assert(i.imm_operands == 0 && i.operands <= 2);
+ assert(i.imm_operands == 0 && i.operands <= 2 && 2 < MAX_OPERANDS);
exp = &im_expressions[i.imm_operands++];
- i.imms[i.operands] = exp;
+ i.op[i.operands].imms = exp;
i.types[i.operands++] = Imm8;
exp->X_op = O_constant;
exp->X_add_number = i.tm.extension_opcode;
This is only for optimizing out unnecessary segment overrides. */
const seg_entry *default_seg = 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). */
-
- i.tm.base_opcode ^= found_reverse_match;
-
/* The imul $imm, %reg instruction is converted into
imul $imm, %reg, %reg, and the clr %reg instruction
is converted into xor %reg, %reg. */
{
unsigned int first_reg_op = (i.types[0] & Reg) ? 0 : 1;
/* Pretend we saw the extra register operand. */
- i.regs[first_reg_op+1] = i.regs[first_reg_op];
+ assert (i.op[first_reg_op+1].regs == 0);
+ i.op[first_reg_op+1].regs = i.op[first_reg_op].regs;
+ i.types[first_reg_op+1] = i.types[first_reg_op];
i.reg_operands = 2;
}
/* The register or float register operand is in operand 0 or 1. */
unsigned int op = (i.types[0] & (Reg | FloatReg)) ? 0 : 1;
/* Register goes in low 3 bits of opcode. */
- i.tm.base_opcode |= i.regs[op]->reg_num;
+ i.tm.base_opcode |= i.op[op].regs->reg_num;
if ((i.tm.opcode_modifier & Ugh) != 0)
{
/* Warn about some common errors, but press on regardless.
{
/* reversed arguments on faddp, fsubp, etc. */
as_warn (_("translating to `%s %%%s,%%%s'"), i.tm.name,
- i.regs[1]->reg_name,
- i.regs[0]->reg_name);
+ i.op[1].regs->reg_name,
+ i.op[0].regs->reg_name);
}
else
{
/* extraneous `l' suffix on fp insn */
as_warn (_("translating to `%s %%%s'"), i.tm.name,
- i.regs[0]->reg_name);
+ i.op[0].regs->reg_name);
}
}
}
destination in the i.rm.reg field. */
if ((i.tm.operand_types[dest] & AnyMem) == 0)
{
- i.rm.reg = i.regs[dest]->reg_num;
- i.rm.regmem = i.regs[source]->reg_num;
+ i.rm.reg = i.op[dest].regs->reg_num;
+ i.rm.regmem = i.op[source].regs->reg_num;
}
else
{
- i.rm.reg = i.regs[source]->reg_num;
- i.rm.regmem = i.regs[dest]->reg_num;
+ i.rm.reg = i.op[source].regs->reg_num;
+ i.rm.regmem = i.op[dest].regs->reg_num;
}
}
else
holds the correct displacement size. */
expressionS *exp;
+ assert (i.op[op].disps == 0);
exp = &disp_expressions[i.disp_operands++];
- i.disps[op] = exp;
+ i.op[op].disps = exp;
exp->X_op = O_constant;
exp->X_add_number = 0;
exp->X_add_symbol = (symbolS *) 0;
/* 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.regs[op]->reg_num;
+ i.rm.regmem = i.op[op].regs->reg_num;
else
- i.rm.reg = i.regs[op]->reg_num;
+ i.rm.reg = i.op[op].regs->reg_num;
/* 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
}
else if (i.tm.opcode_modifier & (Seg2ShortForm | Seg3ShortForm))
{
- if (i.tm.base_opcode == POP_SEG_SHORT && i.regs[0]->reg_num == 1)
+ 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.regs[0]->reg_num << 3);
+ i.tm.base_opcode |= (i.op[0].regs->reg_num << 3);
}
else if ((i.tm.base_opcode & ~(D|W)) == MOV_AX_DISP32)
{
}
/* Handle conversion of 'int $3' --> special int3 insn. */
- if (i.tm.base_opcode == INT_OPCODE && i.imms[0]->X_add_number == 3)
+ 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;
+ }
+
/* We are ready to output the insn. */
{
register char *p;
/* Output jumps. */
if (i.tm.opcode_modifier & Jump)
{
- long n = (long) i.disps[0]->X_add_number;
- int prefix = (i.prefix[DATA_PREFIX] != 0);
- int code16 = 0;
+ int size;
+ int code16;
+ int prefix;
- if (prefix)
+ code16 = 0;
+ if (flag_16bit_code)
+ code16 = CODE16;
+
+ prefix = 0;
+ if (i.prefix[DATA_PREFIX])
{
+ prefix = 1;
i.prefixes -= 1;
- code16 = CODE16;
+ code16 ^= CODE16;
}
- if (flag_16bit_code)
- code16 ^= CODE16;
- if (!intel_syntax && (i.prefixes != 0))
- as_warn (_("skipping prefixes on this instruction"));
+ size = 4;
+ if (code16)
+ size = 2;
- if (i.disps[0]->X_op == O_constant)
- {
- if (fits_in_signed_byte (n))
- {
- insn_size += 2;
- p = frag_more (2);
- p[0] = i.tm.base_opcode;
- p[1] = n;
- }
- else
- {
- /* 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 = code16 ? 2 : 4;
- if (code16 && !fits_in_signed_word (n))
- {
- as_bad (_("16-bit jump out of range"));
- return;
- }
+ if (i.prefixes != 0 && !intel_syntax)
+ as_warn (_("skipping prefixes on this instruction"));
- if (i.tm.base_opcode == JUMP_PC_RELATIVE)
- { /* pace */
- /* unconditional jump */
- 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 */
- 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
- {
- 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 (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,
- prefix + 2 + size, /* 2 opcode/prefix + displacement */
- 1,
- ((unsigned char) *p == JUMP_PC_RELATIVE
- ? ENCODE_RELAX_STATE (UNCOND_JUMP, SMALL) | code16
- : ENCODE_RELAX_STATE (COND_JUMP, SMALL) | code16),
- i.disps[0]->X_add_symbol,
- (offsetT) n, p);
- }
+ /* It's always a symbol; End frag & setup for relax.
+ Make sure there is enough room in this frag for the largest
+ instruction we may generate in md_convert_frag. This is 2
+ bytes for the opcode and room for the prefix and largest
+ displacement. */
+ frag_grow (prefix + 2 + size);
+ insn_size += prefix + 1;
+ /* Prefix and 1 opcode byte go in fr_fix. */
+ p = frag_more (prefix + 1);
+ if (prefix)
+ *p++ = DATA_PREFIX_OPCODE;
+ *p = i.tm.base_opcode;
+ /* 1 possible extra opcode + displacement go in fr_var. */
+ frag_var (rs_machine_dependent,
+ 1 + size,
+ 1,
+ ((unsigned char) *p == JUMP_PC_RELATIVE
+ ? ENCODE_RELAX_STATE (UNCOND_JUMP, SMALL) | code16
+ : ENCODE_RELAX_STATE (COND_JUMP, SMALL) | code16),
+ i.op[0].disps->X_add_symbol,
+ i.op[0].disps->X_add_number,
+ p);
}
else if (i.tm.opcode_modifier & (JumpByte | JumpDword))
{
- int size = (i.tm.opcode_modifier & JumpByte) ? 1 : 4;
- long n = (long) i.disps[0]->X_add_number;
+ int size;
- if (size == 1) /* then this is a loop or jecxz type instruction */
+ if (i.tm.opcode_modifier & JumpByte)
{
+ /* This is a loop or jecxz type instruction. */
+ size = 1;
if (i.prefix[ADDR_PREFIX])
{
insn_size += 1;
}
else
{
- int code16 = 0;
+ int code16;
+
+ code16 = 0;
+ if (flag_16bit_code)
+ code16 = CODE16;
if (i.prefix[DATA_PREFIX])
{
insn_size += 1;
FRAG_APPEND_1_CHAR (DATA_PREFIX_OPCODE);
i.prefixes -= 1;
- code16 = CODE16;
+ code16 ^= CODE16;
}
- if (flag_16bit_code)
- code16 ^= CODE16;
+ size = 4;
if (code16)
size = 2;
}
- if (!intel_syntax && (i.prefixes != 0))
+ if (i.prefixes != 0 && !intel_syntax)
as_warn (_("skipping prefixes on this instruction"));
if (fits_in_unsigned_byte (i.tm.base_opcode))
}
else
{
- insn_size += 2 + size; /* opcode can be at most two bytes */
+ /* opcode can be at most two bytes */
+ insn_size += 2 + size;
p = frag_more (2 + size);
*p++ = (i.tm.base_opcode >> 8) & 0xff;
}
*p++ = i.tm.base_opcode & 0xff;
- if (i.disps[0]->X_op == O_constant)
- {
- if (size == 1 && !fits_in_signed_byte (n))
- {
- as_bad (_("`%s' only takes byte displacement; %ld 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
- {
- fix_new_exp (frag_now, p - frag_now->fr_literal, size,
- i.disps[0], 1, reloc (size, 1, i.disp_reloc[0]));
-
- }
+ fix_new_exp (frag_now, p - frag_now->fr_literal, size,
+ i.op[0].disps, 1, reloc (size, 1, i.disp_reloc[0]));
}
else if (i.tm.opcode_modifier & JumpInterSegment)
{
int size;
- int reloc_type;
- int prefix = i.prefix[DATA_PREFIX] != 0;
- int code16 = 0;
+ int prefix;
+ int code16;
- if (prefix)
+ code16 = 0;
+ if (flag_16bit_code)
+ code16 = CODE16;
+
+ prefix = 0;
+ if (i.prefix[DATA_PREFIX])
{
- code16 = CODE16;
+ prefix = 1;
i.prefixes -= 1;
+ code16 ^= CODE16;
}
- if (flag_16bit_code)
- code16 ^= CODE16;
size = 4;
- reloc_type = BFD_RELOC_32;
if (code16)
- {
- size = 2;
- reloc_type = BFD_RELOC_16;
- }
+ size = 2;
- if (!intel_syntax && (i.prefixes != 0))
+ if (i.prefixes != 0 && !intel_syntax)
as_warn (_("skipping prefixes on this instruction"));
insn_size += prefix + 1 + 2 + size; /* 1 opcode; 2 segment; offset */
if (prefix)
*p++ = DATA_PREFIX_OPCODE;
*p++ = i.tm.base_opcode;
- if (i.imms[1]->X_op == O_constant)
+ if (i.op[1].imms->X_op == O_constant)
{
- long n = (long) i.imms[1]->X_add_number;
+ offsetT n = i.op[1].imms->X_add_number;
- if (size == 2 && !fits_in_unsigned_word (n))
+ if (size == 2
+ && !fits_in_unsigned_word (n)
+ && !fits_in_signed_word (n))
{
as_bad (_("16-bit jump out of range"));
return;
}
- md_number_to_chars (p, (valueT) n, size);
+ md_number_to_chars (p, n, size);
}
else
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)
+ i.op[1].imms, 0, reloc (size, 0, i.disp_reloc[0]));
+ if (i.op[0].imms->X_op != O_constant)
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);
+ md_number_to_chars (p + size, (valueT) i.op[0].imms->X_add_number, 2);
}
else
{
for (n = 0; n < i.operands; n++)
{
- if (i.disps[n])
+ if (i.types[n] & Disp)
{
- if (i.disps[n]->X_op == O_constant)
+ if (i.op[n].disps->X_op == O_constant)
{
- int size = 4;
- long val = (long) i.disps[n]->X_add_number;
+ int size;
+ offsetT val;
+ size = 4;
if (i.types[n] & (Disp8 | Disp16))
{
- long mask;
-
size = 2;
- mask = ~ (long) 0xffff;
if (i.types[n] & Disp8)
- {
- size = 1;
- mask = ~ (long) 0xff;
- }
-
- if ((val & mask) != 0 && (val & mask) != mask)
- as_warn (_("%ld shortened to %ld"),
- val, val & ~mask);
+ size = 1;
}
+ val = offset_in_range (i.op[n].disps->X_add_number,
+ size);
insn_size += size;
p = frag_more (size);
- md_number_to_chars (p, (valueT) val, size);
- }
- 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));
+ md_number_to_chars (p, val, size);
}
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));
+ {
+ int size = 4;
+
+ if (i.types[n] & Disp16)
+ size = 2;
+
+ insn_size += size;
+ p = frag_more (size);
+ fix_new_exp (frag_now, p - frag_now->fr_literal, size,
+ i.op[n].disps, 0,
+ reloc (size, 0, i.disp_reloc[n]));
}
}
}
for (n = 0; n < i.operands; n++)
{
- if (i.imms[n])
+ if (i.types[n] & Imm)
{
- if (i.imms[n]->X_op == O_constant)
+ if (i.op[n].imms->X_op == O_constant)
{
- int size = 4;
- long val = (long) i.imms[n]->X_add_number;
+ int size;
+ offsetT val;
+ size = 4;
if (i.types[n] & (Imm8 | Imm8S | Imm16))
{
- long mask;
-
size = 2;
- mask = ~ (long) 0xffff;
if (i.types[n] & (Imm8 | Imm8S))
- {
- size = 1;
- mask = ~ (long) 0xff;
- }
- if ((val & mask) != 0 && (val & mask) != mask)
- as_warn (_("%ld shortened to %ld"),
- val, val & ~mask);
+ size = 1;
}
+ val = offset_in_range (i.op[n].imms->X_add_number,
+ size);
insn_size += size;
p = frag_more (size);
- md_number_to_chars (p, (valueT) val, size);
+ md_number_to_chars (p, val, size);
}
else
{ /* not absolute_section */
/* Need a 32-bit fixup (don't support 8bit
- non-absolute ims). Try to support other
+ non-absolute imms). Try to support other
sizes ... */
- int r_type;
- int size;
- int pcrel = 0;
+#ifdef BFD_ASSEMBLER
+ enum bfd_reloc_code_real reloc_type;
+#else
+ int reloc_type;
+#endif
+ int size = 4;
- if (i.types[n] & (Imm8 | Imm8S))
- size = 1;
- else if (i.types[n] & Imm16)
+ if (i.types[n] & Imm16)
size = 2;
- else
- size = 4;
+ else if (i.types[n] & (Imm8 | Imm8S))
+ size = 1;
+
insn_size += size;
p = frag_more (size);
- r_type = reloc (size, 0, i.disp_reloc[0]);
+ reloc_type = reloc (size, 0, i.disp_reloc[0]);
#ifdef BFD_ASSEMBLER
- if (r_type == BFD_RELOC_32
+ if (reloc_type == BFD_RELOC_32
&& GOT_symbol
- && GOT_symbol == i.imms[n]->X_add_symbol
- && (i.imms[n]->X_op == O_symbol
- || (i.imms[n]->X_op == O_add
+ && GOT_symbol == i.op[n].imms->X_add_symbol
+ && (i.op[n].imms->X_op == O_symbol
+ || (i.op[n].imms->X_op == O_add
&& ((symbol_get_value_expression
- (i.imms[n]->X_op_symbol)->X_op)
+ (i.op[n].imms->X_op_symbol)->X_op)
== O_subtract))))
{
- r_type = BFD_RELOC_386_GOTPC;
- i.imms[n]->X_add_number += 3;
+ reloc_type = BFD_RELOC_386_GOTPC;
+ i.op[n].imms->X_add_number += 3;
}
#endif
fix_new_exp (frag_now, p - frag_now->fr_literal, size,
- i.imms[n], pcrel, r_type);
+ i.op[n].imms, 0, reloc_type);
}
}
}
if (i.imm_operands == MAX_IMMEDIATE_OPERANDS)
{
- as_bad (_("Only 1 or 2 immediate operands are allowed"));
+ as_bad (_("only 1 or 2 immediate operands are allowed"));
return 0;
}
exp = &im_expressions[i.imm_operands++];
- i.imms[this_operand] = exp;
+ i.op[this_operand].imms = exp;
if (is_space_char (*imm_start))
++imm_start;
len = 3;
}
else
- as_bad (_("Bad reloc specifier in expression"));
+ as_bad (_("bad reloc specifier in expression"));
/* Replace the relocation token with ' ', so that errors like
foo@GOTOFF1 will be detected. */
SKIP_WHITESPACE ();
if (*input_line_pointer)
- as_bad (_("Ignoring junk `%s' after expression"), input_line_pointer);
+ as_bad (_("ignoring junk `%s' after expression"), input_line_pointer);
input_line_pointer = save_input_line_pointer;
- if (exp->X_op == O_absent)
+ if (exp->X_op == O_absent || exp->X_op == O_big)
{
/* missing or bad expr becomes absolute 0 */
- as_bad (_("Missing or invalid immediate expression `%s' taken as 0"),
+ as_bad (_("missing or invalid immediate expression `%s' taken as 0"),
imm_start);
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] |= Imm;
}
- else if (exp->X_op == O_constant)
- {
- int bigimm = Imm32;
- if (flag_16bit_code ^ (i.prefix[DATA_PREFIX] != 0))
- bigimm = Imm16;
- i.types[this_operand] |=
- (bigimm | smallest_imm_type ((long) exp->X_add_number));
-
- /* If a suffix is given, this operand may be shortended. */
- switch (i.suffix)
- {
- case WORD_MNEM_SUFFIX:
- i.types[this_operand] |= Imm16;
- break;
- case BYTE_MNEM_SUFFIX:
- i.types[this_operand] |= Imm16 | Imm8 | Imm8S;
- break;
- }
+ if (exp->X_op == O_constant)
+ {
+ i.types[this_operand] |= Imm32; /* Size it properly later. */
}
-#ifdef OBJ_AOUT
- else if (exp_seg != text_section
+#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT))
+ else if (
+#ifdef BFD_ASSEMBLER
+ OUTPUT_FLAVOR == bfd_target_aout_flavour &&
+#endif
+ exp_seg != text_section
&& exp_seg != data_section
&& exp_seg != bss_section
&& exp_seg != undefined_section
#endif
)
{
- as_bad (_("Unimplemented segment type %d in operand"), exp_seg);
+#ifdef BFD_ASSEMBLER
+ as_bad (_("unimplemented segment %s in operand"), exp_seg->name);
+#else
+ as_bad (_("unimplemented segment type %d in operand"), exp_seg);
+#endif
return 0;
}
#endif
i.types[this_operand] |= bigdisp;
exp = &disp_expressions[i.disp_operands];
- i.disps[this_operand] = exp;
- i.disp_reloc[this_operand] = NO_RELOC;
+ i.op[this_operand].disps = exp;
i.disp_operands++;
save_input_line_pointer = input_line_pointer;
input_line_pointer = disp_start;
len = 3;
}
else
- as_bad (_("Bad reloc specifier in expression"));
+ as_bad (_("bad reloc specifier in expression"));
/* Replace the relocation token with ' ', so that errors like
foo@GOTOFF1 will be detected. */
SKIP_WHITESPACE ();
if (*input_line_pointer)
- as_bad (_("Ignoring junk `%s' after expression"),
+ as_bad (_("ignoring junk `%s' after expression"),
input_line_pointer);
#if GCC_ASM_O_HACK
RESTORE_END_STRING (disp_end + 1);
RESTORE_END_STRING (disp_end);
input_line_pointer = save_input_line_pointer;
+ if (exp->X_op == O_absent || exp->X_op == O_big)
+ {
+ /* missing or bad expr becomes absolute 0 */
+ as_bad (_("missing or invalid displacement expression `%s' taken as 0"),
+ disp_start);
+ exp->X_op = O_constant;
+ exp->X_add_number = 0;
+ exp->X_add_symbol = (symbolS *) 0;
+ exp->X_op_symbol = (symbolS *) 0;
+ }
+
if (exp->X_op == O_constant)
{
+ if (i.types[this_operand] & Disp16)
+ {
+ /* We know this operand is at most 16 bits, so convert to a
+ signed 16 bit number before trying to see whether it will
+ fit in an even smaller size. */
+ exp->X_add_number =
+ (((exp->X_add_number & 0xffff) ^ 0x8000) - 0x8000);
+ }
if (fits_in_signed_byte (exp->X_add_number))
i.types[this_operand] |= Disp8;
}
-#ifdef OBJ_AOUT
- else if (exp_seg != text_section
+#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT))
+ else if (
+#ifdef BFD_ASSEMBLER
+ OUTPUT_FLAVOR == bfd_target_aout_flavour &&
+#endif
+ exp_seg != text_section
&& exp_seg != data_section
&& exp_seg != bss_section
&& exp_seg != undefined_section)
{
- as_bad (_ ("Unimplemented segment type %d in operand"), exp_seg);
+#ifdef BFD_ASSEMBLER
+ as_bad (_("unimplemented segment %s in operand"), exp_seg->name);
+#else
+ as_bad (_("unimplemented segment type %d in operand"), exp_seg);
+#endif
return 0;
}
#endif
}
else if (!strncasecmp (*op_string, "WORD PTR", 8))
{
- i.suffix = WORD_MNEM_SUFFIX;
+ if (got_a_float == 2) /* "fi..." */
+ i.suffix = SHORT_MNEM_SUFFIX;
+ else
+ i.suffix = WORD_MNEM_SUFFIX;
*op_string += 8;
return WORD_PTR;
}
else if (!strncasecmp (*op_string, "DWORD PTR", 9))
{
- if (got_a_float)
+ if (got_a_float == 1) /* "f..." */
i.suffix = SHORT_MNEM_SUFFIX;
else
- i.suffix = DWORD_MNEM_SUFFIX;
+ i.suffix = LONG_MNEM_SUFFIX;
*op_string += 9;
return DWORD_PTR;
}
else if (!strncasecmp (*op_string, "QWORD PTR", 9))
{
- i.suffix = INTEL_DWORD_MNEM_SUFFIX;
+ i.suffix = DWORD_MNEM_SUFFIX;
*op_string += 9;
return QWORD_PTR;
}
temp_string[0] = '\0';
tc = end_of_operand_string = strchr (op_string, '[');
- if ( initial_disp && !end_of_operand_string)
+ if (initial_disp && !end_of_operand_string)
{
strcpy (temp_string, op_string);
- return (temp_string);
+ return temp_string;
}
/* Build the whole displacement string */
tryprefix:
#endif
- if (flag_16bit_code ^ (i.prefix[ADDR_PREFIX] != 0) ?
+ if (flag_16bit_code ^ (i.prefix[ADDR_PREFIX] != 0)
/* 16 bit mode checks */
- ((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)))) :
+ ? ((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))))
/* 32 bit mode checks */
- ((i.base_reg
- && (i.base_reg->reg_type & Reg32) == 0)
- || (i.index_reg
- && ((i.index_reg->reg_type & (Reg32|BaseIndex))
- != (Reg32|BaseIndex)))))
+ : ((i.base_reg
+ && (i.base_reg->reg_type & Reg32) == 0)
+ || (i.index_reg
+ && ((i.index_reg->reg_type & (Reg32|BaseIndex))
+ != (Reg32|BaseIndex)))))
{
#if INFER_ADDR_PREFIX
if (i.prefix[ADDR_PREFIX] == 0 && stackop_size != '\0')
fudged = 1;
goto tryprefix;
}
-#endif
if (fudged)
as_bad (_("`%s' is not a valid base/index expression"),
operand_string);
else
+#endif
as_bad (_("`%s' is not a valid %s bit base/index expression"),
operand_string,
flag_16bit_code ^ (i.prefix[ADDR_PREFIX] != 0) ? "16" : "32");
return 0;
}
- /* Look for displacement preceding open bracket */
+ /* First check for a segment override. */
if (*op_string != '[')
{
char *end_seg;
- char *temp_string;
end_seg = strchr (op_string, ':');
if (end_seg)
return 0;
op_string = end_seg + 1;
}
+ }
- temp_string = build_displacement_string (true, op_string);
+ /* Look for displacement preceding open bracket */
+ if (*op_string != '[')
+ {
+ char *temp_string;
- if (i.disp_operands == 0 &&
- !i386_displacement (temp_string, temp_string + strlen (temp_string)))
+ if (i.disp_operands)
return 0;
+ temp_string = build_displacement_string (true, op_string);
+
+ if (!i386_displacement (temp_string, temp_string + strlen (temp_string)))
+ {
+ free (temp_string);
+ return 0;
+ }
+ free (temp_string);
+
end_of_operand_string = strchr (op_string, '[');
if (!end_of_operand_string)
end_of_operand_string = op_string + strlen (op_string);
else if (is_digit_char (*op_string)
|| *op_string == '+' || *op_string == '-')
{
+ char *temp_str;
+
+ if (i.disp_operands != 0)
+ return 0;
+
temp_string = build_displacement_string (false, op_string);
- if (*temp_string == '+')
- ++temp_string;
+ temp_str = temp_string;
+ if (*temp_str == '+')
+ ++temp_str;
- if (i.disp_operands == 0 &&
- !i386_displacement (temp_string, temp_string + strlen (temp_string)))
- return 0;
+ if (!i386_displacement (temp_str, temp_str + strlen (temp_str)))
+ {
+ free (temp_string);
+ return 0;
+ }
+ free (temp_string);
++op_string;
end_of_operand_string = op_string;
}
i.types[this_operand] |= r->reg_type & ~BaseIndex;
- i.regs[this_operand] = r;
+ i.op[this_operand].regs = r;
i.reg_operands++;
}
else if (*op_string == REGISTER_PREFIX)
}
if (*op_string)
{
- as_bad (_("Junk `%s' after register"), op_string);
+ as_bad (_("junk `%s' after register"), op_string);
return 0;
}
i.types[this_operand] |= r->reg_type & ~BaseIndex;
- i.regs[this_operand] = r;
+ i.op[this_operand].regs = r;
i.reg_operands++;
}
else if (*op_string == REGISTER_PREFIX)
++op_string;
if (i.types[this_operand] & JumpAbsolute)
{
- as_bad (_("Immediate operand illegal with absolute jump"));
+ as_bad (_("immediate operand illegal with absolute jump"));
return 0;
}
if (!i386_immediate (op_string))
/* 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;
+#ifdef BFD_ASSEMBLER
+ enum bfd_reloc_code_real reloc_type;
+#else
+ int reloc_type;
+#endif
+
+ if (GOT_symbol /* Not quite right - we should switch on presence of
+ @PLT, but I cannot see how to get to that from
+ here. We should have done this in md_assemble to
+ really 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)
+ reloc_type = BFD_RELOC_386_PLT32;
+ else if (code16)
+ reloc_type = BFD_RELOC_16_PCREL;
+ else
+ reloc_type = BFD_RELOC_32_PCREL;
switch (opcode[0])
{
fix_new (fragP, old_fr_fix, size,
fragP->fr_symbol,
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. We should have
- done this in md_assemble to really
- 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 : pcrel_reloc);
+ reloc_type);
break;
default:
/* This changes the byte-displacement jump 0x7N
- to the dword-displacement jump 0x0f8N. */
+ to the dword-displacement jump 0x0f,0x8N. */
opcode[1] = opcode[0] + 0x10;
- opcode[0] = TWO_BYTE_OPCODE_ESCAPE; /* two-byte escape */
+ opcode[0] = TWO_BYTE_OPCODE_ESCAPE;
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,
- (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 : pcrel_reloc);
+ reloc_type);
break;
}
frag_wane (fragP);
{
register unsigned char *opcode;
unsigned char *where_to_put_displacement = NULL;
- unsigned int target_address;
- unsigned int opcode_address;
+ offsetT target_address;
+ offsetT opcode_address;
unsigned int extension = 0;
- int displacement_from_opcode_start;
+ offsetT displacement_from_opcode_start;
opcode = (unsigned char *) fragP->fr_opcode;
fragS *frag ATTRIBUTE_UNUSED;
symbolS *to_symbol ATTRIBUTE_UNUSED;
{
- long offset;
+ offsetT offset;
offset = to_addr - (from_addr + 2);
md_number_to_chars (ptr, (valueT) 0xeb, 1); /* opcode for byte-disp jump */
fragS *frag;
symbolS *to_symbol;
{
- long offset;
+ offsetT offset;
if (flag_do_long_jump)
{
value += fixP->fx_where + fixP->fx_frag->fr_address;
#endif
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
- if (OUTPUT_FLAVOR == bfd_target_elf_flavour
- && (S_GET_SEGMENT (fixP->fx_addsy) == seg
- || symbol_section_p (fixP->fx_addsy))
- && ! S_IS_EXTERNAL (fixP->fx_addsy)
- && ! S_IS_WEAK (fixP->fx_addsy)
- && S_IS_DEFINED (fixP->fx_addsy)
- && ! S_IS_COMMON (fixP->fx_addsy))
+ if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
{
- /* Yes, we add the values in twice. This is because
- bfd_perform_relocation subtracts them out again. I think
- bfd_perform_relocation is broken, but I don't dare change
- it. FIXME. */
- value += fixP->fx_where + fixP->fx_frag->fr_address;
+ segT fseg = S_GET_SEGMENT (fixP->fx_addsy);
+
+ if ((fseg == seg
+ || (symbol_section_p (fixP->fx_addsy)
+ && fseg != absolute_section))
+ && ! S_IS_EXTERNAL (fixP->fx_addsy)
+ && ! S_IS_WEAK (fixP->fx_addsy)
+ && S_IS_DEFINED (fixP->fx_addsy)
+ && ! S_IS_COMMON (fixP->fx_addsy))
+ {
+ /* Yes, we add the values in twice. This is because
+ bfd_perform_relocation subtracts them out again. I think
+ bfd_perform_relocation is broken, but I don't dare change
+ it. FIXME. */
+ value += fixP->fx_where + fixP->fx_frag->fr_address;
+ }
}
#endif
#if defined (OBJ_COFF) && defined (TE_PE)
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. */
- value = 0xfffffffc;
+ value = -4;
break;
case BFD_RELOC_386_GOTPC:
/*
return 1;
}
-
-#if 0
-/* This is never used. */
-long /* Knows about the byte order in a word. */
-md_chars_to_number (con, nbytes)
- unsigned char con[]; /* Low order byte 1st. */
- int nbytes; /* Number of bytes in the input. */
-{
- long retval;
- for (retval = 0, con += nbytes - 1; nbytes--; con--)
- {
- retval <<= BITS_PER_CHAR;
- retval |= *con;
- }
- return retval;
-}
-#endif /* 0 */
\f
#define MAX_LITTLENUMS 6
\f
char output_invalid_buf[8];
-static char * output_invalid PARAMS ((int));
-
static char *
output_invalid (c)
int c;
return r;
}
\f
-#ifdef OBJ_ELF
-CONST char *md_shortopts = "kmVQ:";
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+CONST char *md_shortopts = "kmVQ:sq";
#else
CONST char *md_shortopts = "m";
#endif
should be emitted or not. FIXME: Not implemented. */
case 'Q':
break;
+
+ case 's':
+ /* -s: On i386 Solaris, this tells the native assembler to use
+ .stab instead of .stab.excl. We always use .stab anyhow. */
+ break;
+
+ case 'q':
+ /* -q: On i386 Solaris, this tells the native assembler does
+ fewer checks. */
+ break;
#endif
default:
FILE *stream;
{
fprintf (stream, _("\
--m do long jump\n"));
+ -m do long jump\n"));
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+ fprintf (stream, _("\
+ -V print assembler version number\n\
+ -k ignored\n\
+ -Qy, -Qn ignored\n\
+ -q ignored\n\
+ -s ignored\n"));
+#endif
}
#ifdef BFD_ASSEMBLER
-#ifdef OBJ_MAYBE_ELF
-#ifdef OBJ_MAYBE_COFF
+#if ((defined (OBJ_MAYBE_ELF) && defined (OBJ_MAYBE_COFF)) \
+ || (defined (OBJ_MAYBE_ELF) && defined (OBJ_MAYBE_AOUT)) \
+ || (defined (OBJ_MAYBE_COFF) && defined (OBJ_MAYBE_AOUT)))
/* Pick the target format to use. */
{
switch (OUTPUT_FLAVOR)
{
+#ifdef OBJ_MAYBE_AOUT
+ case bfd_target_aout_flavour:
+ return AOUT_TARGET_FORMAT;
+#endif
+#ifdef OBJ_MAYBE_COFF
case bfd_target_coff_flavour:
return "coff-i386";
+#endif
+#ifdef OBJ_MAYBE_ELF
case bfd_target_elf_flavour:
return "elf32-i386";
+#endif
default:
abort ();
return NULL;
}
}
-#endif /* OBJ_MAYBE_COFF */
-#endif /* OBJ_MAYBE_ELF */
+#endif /* OBJ_MAYBE_ more than one */
#endif /* BFD_ASSEMBLER */
\f
-/* ARGSUSED */
symbolS *
md_undefined_symbol (name)
char *name;
segT segment ATTRIBUTE_UNUSED;
valueT size;
{
-#ifdef OBJ_AOUT
#ifdef BFD_ASSEMBLER
- /* For a.out, force the section size to be aligned. If we don't do
- this, BFD will align it for us, but it will not write out the
- final bytes of the section. This may be a bug in BFD, but it is
- easier to fix it here since that is how the other a.out targets
- work. */
- int align;
-
- align = bfd_get_section_alignment (stdoutput, segment);
- size = ((size + (1 << align) - 1) & ((valueT) -1 << align));
+#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT))
+ if (OUTPUT_FLAVOR == bfd_target_aout_flavour)
+ {
+ /* For a.out, force the section size to be aligned. If we don't do
+ this, BFD will align it for us, but it will not write out the
+ final bytes of the section. This may be a bug in BFD, but it is
+ easier to fix it here since that is how the other a.out targets
+ work. */
+ int align;
+
+ align = bfd_get_section_alignment (stdoutput, segment);
+ size = ((size + (1 << align) - 1) & ((valueT) -1 << align));
+ }
#endif
#endif
switch (fixp->fx_size)
{
default:
- as_bad (_("Can not do %d byte pc-relative relocation"),
+ as_bad (_("can not do %d byte pc-relative relocation"),
fixp->fx_size);
code = BFD_RELOC_32_PCREL;
break;
switch (fixp->fx_size)
{
default:
- as_bad (_("Can not do %d byte relocation"), fixp->fx_size);
+ as_bad (_("can not do %d byte relocation"), fixp->fx_size);
code = BFD_RELOC_32;
break;
case 1: code = BFD_RELOC_8; break;
if (rel->howto == NULL)
{
as_bad_where (fixp->fx_file, fixp->fx_line,
- _("Cannot represent relocation type %s"),
+ _("cannot represent relocation type %s"),
bfd_get_reloc_code_name (code));
/* Set howto to a garbage value so that we can keep going. */
rel->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32);