static char register_chars[256];
static char operand_chars[256];
static char identifier_chars[256];
-static char digit_chars[256];
/* Lexical macros. */
#define is_mnemonic_char(x) (mnemonic_chars[(unsigned char) x])
#define is_register_char(x) (register_chars[(unsigned char) x])
#define is_space_char(x) ((x) == ' ')
#define is_identifier_char(x) (identifier_chars[(unsigned char) x])
-#define is_digit_char(x) (digit_chars[(unsigned char) x])
/* All non-digit non-letter characters that may occur in an operand. */
static char operand_special_chars[] = "%$-+(,)*._~/<>|&^!:[@]";
return x;
}
-static const i386_operand_type disp16 = OPERAND_TYPE_DISP16;
-static const i386_operand_type disp32 = OPERAND_TYPE_DISP32;
-static const i386_operand_type disp32s = OPERAND_TYPE_DISP32S;
static const i386_operand_type disp16_32 = OPERAND_TYPE_DISP16_32;
static const i386_operand_type anydisp = OPERAND_TYPE_ANYDISP;
static const i386_operand_type anyimm = OPERAND_TYPE_ANYIMM;
#endif
} /* fits_in_unsigned_long() */
+static INLINE valueT extend_to_32bit_address (addressT num)
+{
+#ifdef BFD64
+ if (fits_in_unsigned_long(num))
+ return (num ^ ((addressT) 1 << 31)) - ((addressT) 1 << 31);
+
+ if (!fits_in_signed_long (num))
+ return num & 0xffffffff;
+#endif
+
+ return num;
+}
+
static INLINE int
fits_in_disp8 (offsetT num)
{
{
case 1: mask = ((addressT) 1 << 8) - 1; break;
case 2: mask = ((addressT) 1 << 16) - 1; break;
- case 4: mask = ((addressT) 2 << 31) - 1; break;
#ifdef BFD64
- case 8: mask = ((addressT) 2 << 63) - 1; break;
+ case 4: mask = ((addressT) 1 << 32) - 1; break;
#endif
+ case sizeof (val): return val;
default: abort ();
}
- if ((val & ~mask) != 0 && (val & ~mask) != ~mask)
- {
- char buf1[40], buf2[40];
+ if ((val & ~mask) != 0 && (-val & ~mask) != 0)
+ as_warn (_("%"BFD_VMA_FMT"x shortened to %"BFD_VMA_FMT"x"),
+ val, val & mask);
- bfd_sprintf_vma (stdoutput, buf1, val);
- bfd_sprintf_vma (stdoutput, buf2, val & mask);
- as_warn (_("%s shortened to %s"), buf1, buf2);
- }
return val & mask;
}
for (c = 0; c < 256; c++)
{
- if (ISDIGIT (c))
- {
- digit_chars[c] = c;
- mnemonic_chars[c] = c;
- register_chars[c] = c;
- operand_chars[c] = c;
- }
- else if (ISLOWER (c))
+ if (ISDIGIT (c) || ISLOWER (c))
{
mnemonic_chars[c] = c;
register_chars[c] = c;
identifier_chars['?'] = '?';
operand_chars['?'] = '?';
#endif
- digit_chars['-'] = '-';
mnemonic_chars['_'] = '_';
mnemonic_chars['-'] = '-';
mnemonic_chars['.'] = '.';
? i.op[1].regs->reg_type.bitfield.dword
: i.op[1].regs->reg_type.bitfield.word)))
return;
+ /* In 16-bit mode converting LEA with 16-bit addressing and a 32-bit
+ destination is going to grow encoding size. */
+ else if (flag_code == CODE_16BIT
+ && (optimize <= 1 || optimize_for_space)
+ && !i.prefix[ADDR_PREFIX]
+ && i.op[1].regs->reg_type.bitfield.dword)
+ return;
else
{
i.tm.base_opcode = 0xb8;
/* 1 if operand is pending after ','. */
unsigned int expecting_operand = 0;
- /* Non-zero if operand parens not balanced. */
- unsigned int paren_not_balanced;
-
while (*l != END_OF_INSN)
{
+ /* Non-zero if operand parens not balanced. */
+ unsigned int paren_not_balanced = 0;
+ /* True if inside double quotes. */
+ bool in_quotes = false;
+
/* Skip optional white space before operand. */
if (is_space_char (*l))
++l;
return NULL;
}
token_start = l; /* After white space. */
- paren_not_balanced = 0;
- while (paren_not_balanced || *l != ',')
+ while (in_quotes || paren_not_balanced || *l != ',')
{
if (*l == END_OF_INSN)
{
+ if (in_quotes)
+ {
+ as_bad (_("unbalanced double quotes in operand %d."),
+ i.operands + 1);
+ return NULL;
+ }
if (paren_not_balanced)
{
- if (!intel_syntax)
- as_bad (_("unbalanced parenthesis in operand %d."),
- i.operands + 1);
- else
- as_bad (_("unbalanced brackets in operand %d."),
- i.operands + 1);
+ know (!intel_syntax);
+ as_bad (_("unbalanced parenthesis in operand %d."),
+ i.operands + 1);
return NULL;
}
else
break; /* we are done */
}
- else if (!is_operand_char (*l) && !is_space_char (*l) && *l != '"')
+ else if (*l == '\\' && l[1] == '"')
+ ++l;
+ else if (*l == '"')
+ in_quotes = !in_quotes;
+ else if (!in_quotes && !is_operand_char (*l) && !is_space_char (*l))
{
as_bad (_("invalid character %s in operand %d"),
output_invalid (*l),
i.operands + 1);
return NULL;
}
- if (!intel_syntax)
+ if (!intel_syntax && !in_quotes)
{
if (*l == '(')
++paren_not_balanced;
if (*l == ')')
--paren_not_balanced;
}
- else
- {
- if (*l == '[')
- ++paren_not_balanced;
- if (*l == ']')
- --paren_not_balanced;
- }
l++;
}
if (l != token_start)
This allows a 16-bit operand such as $0xffe0 to
be recognised as within Imm8S range. */
if ((i.types[op].bitfield.imm16)
- && (i.op[op].imms->X_add_number & ~(offsetT) 0xffff) == 0)
+ && fits_in_unsigned_word (i.op[op].imms->X_add_number))
{
i.op[op].imms->X_add_number = ((i.op[op].imms->X_add_number
^ 0x8000) - 0x8000);
#ifdef BFD64
/* Store 32-bit immediate in 64-bit for 64-bit BFD. */
if ((i.types[op].bitfield.imm32)
- && ((i.op[op].imms->X_add_number & ~(((offsetT) 2 << 31) - 1))
- == 0))
+ && fits_in_unsigned_long (i.op[op].imms->X_add_number))
{
i.op[op].imms->X_add_number = ((i.op[op].imms->X_add_number
^ ((offsetT) 1 << 31))
{
offsetT op_disp = i.op[op].disps->X_add_number;
+ if (!op_disp && i.types[op].bitfield.baseindex)
+ {
+ i.types[op] = operand_type_and_not (i.types[op], anydisp);
+ i.op[op].disps = NULL;
+ i.disp_operands--;
+ continue;
+ }
+
if (i.types[op].bitfield.disp16
- && (op_disp & ~(offsetT) 0xffff) == 0)
+ && fits_in_unsigned_word (op_disp))
{
/* If this operand is at most 16 bits, convert
to a signed 16 bit number and don't use 64bit
displacement. */
- op_disp = (((op_disp & 0xffff) ^ 0x8000) - 0x8000);
+ op_disp = ((op_disp ^ 0x8000) - 0x8000);
i.types[op].bitfield.disp64 = 0;
}
- if (!op_disp && i.types[op].bitfield.baseindex)
+
+#ifdef BFD64
+ /* Optimize 64-bit displacement to 32-bit for 64-bit BFD. */
+ if ((i.types[op].bitfield.disp32
+ || (flag_code == CODE_64BIT
+ && want_disp32 (current_templates->start)))
+ && fits_in_unsigned_long (op_disp))
{
- i.types[op].bitfield.disp8 = 0;
- i.types[op].bitfield.disp16 = 0;
- i.types[op].bitfield.disp32 = 0;
- i.types[op].bitfield.disp32s = 0;
+ /* If this operand is at most 32 bits, convert
+ to a signed 32 bit number and don't use 64bit
+ displacement. */
+ op_disp = (op_disp ^ ((offsetT) 1 << 31)) - ((addressT) 1 << 31);
i.types[op].bitfield.disp64 = 0;
- i.op[op].disps = 0;
- i.disp_operands--;
+ i.types[op].bitfield.disp32 = 1;
}
-#ifdef BFD64
- else if (flag_code == CODE_64BIT)
- {
- if (want_disp32 (current_templates->start)
- && fits_in_unsigned_long (op_disp))
- i.types[op].bitfield.disp32 = 1;
- /* Optimize 64-bit displacement to 32-bit for 64-bit BFD. */
- if (i.types[op].bitfield.disp32
- && (op_disp & ~(((offsetT) 2 << 31) - 1)) == 0)
- {
- /* If this operand is at most 32 bits, convert
- to a signed 32 bit number and don't use 64bit
- displacement. */
- op_disp &= (((offsetT) 2 << 31) - 1);
- op_disp = (op_disp ^ ((offsetT) 1 << 31)) - ((addressT) 1 << 31);
- i.types[op].bitfield.disp64 = 0;
- }
-
- if (fits_in_signed_long (op_disp))
- {
- i.types[op].bitfield.disp64 = 0;
- i.types[op].bitfield.disp32s = 1;
- }
+ if (flag_code == CODE_64BIT && fits_in_signed_long (op_disp))
+ {
+ i.types[op].bitfield.disp64 = 0;
+ i.types[op].bitfield.disp32s = 1;
}
#endif
if ((i.types[op].bitfield.disp32
|| i.types[op].bitfield.disp16)
&& fits_in_disp8 (op_disp))
i.types[op].bitfield.disp8 = 1;
+
+ i.op[op].disps->X_add_number = op_disp;
}
else if (i.reloc[op] == BFD_RELOC_386_TLS_DESC_CALL
|| i.reloc[op] == BFD_RELOC_X86_64_TLSDESC_CALL)
{
fix_new_exp (frag_now, frag_more (0) - frag_now->fr_literal, 0,
i.op[op].disps, 0, i.reloc[op]);
- i.types[op].bitfield.disp8 = 0;
- i.types[op].bitfield.disp16 = 0;
- i.types[op].bitfield.disp32 = 0;
- i.types[op].bitfield.disp32s = 0;
- i.types[op].bitfield.disp64 = 0;
+ i.types[op] = operand_type_and_not (i.types[op], anydisp);
}
else
/* We only support 64bit displacement on constants. */
{
i.sib.base = NO_BASE_REGISTER;
i.sib.scale = i.log2_scale_factor;
- i.types[op].bitfield.disp8 = 0;
- i.types[op].bitfield.disp16 = 0;
- i.types[op].bitfield.disp64 = 0;
+ i.types[op] = operand_type_and_not (i.types[op], anydisp);
if (want_disp32 (&i.tm))
- {
- /* Must be 32 bit */
- i.types[op].bitfield.disp32 = 1;
- i.types[op].bitfield.disp32s = 0;
- }
+ i.types[op].bitfield.disp32 = 1;
else
- {
- i.types[op].bitfield.disp32 = 0;
- i.types[op].bitfield.disp32s = 1;
- }
+ i.types[op].bitfield.disp32s = 1;
}
/* Since the mandatory SIB always has index register, so
fake_zero_displacement = 1;
if (i.index_reg == 0)
{
- i386_operand_type newdisp;
-
/* Both check for VSIB and mandatory non-vector SIB. */
gas_assert (!i.tm.opcode_modifier.sib
|| i.tm.opcode_modifier.sib == SIBMEM);
/* Operand is just <disp> */
+ i.types[op] = operand_type_and_not (i.types[op], anydisp);
if (flag_code == CODE_64BIT)
{
/* 64bit mode overwrites the 32bit absolute
i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
i.sib.base = NO_BASE_REGISTER;
i.sib.index = NO_INDEX_REGISTER;
- newdisp = (want_disp32(&i.tm) ? disp32 : disp32s);
+ if (want_disp32 (&i.tm))
+ i.types[op].bitfield.disp32 = 1;
+ else
+ i.types[op].bitfield.disp32s = 1;
}
else if ((flag_code == CODE_16BIT)
^ (i.prefix[ADDR_PREFIX] != 0))
{
i.rm.regmem = NO_BASE_REGISTER_16;
- newdisp = disp16;
+ i.types[op].bitfield.disp16 = 1;
}
else
{
i.rm.regmem = NO_BASE_REGISTER;
- newdisp = disp32;
+ i.types[op].bitfield.disp32 = 1;
}
- i.types[op] = operand_type_and_not (i.types[op], anydisp);
- i.types[op] = operand_type_or (i.types[op], newdisp);
}
else if (!i.tm.opcode_modifier.sib)
{
i.sib.base = NO_BASE_REGISTER;
i.sib.scale = i.log2_scale_factor;
i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
- i.types[op].bitfield.disp8 = 0;
- i.types[op].bitfield.disp16 = 0;
- i.types[op].bitfield.disp64 = 0;
+ i.types[op] = operand_type_and_not (i.types[op], anydisp);
if (want_disp32 (&i.tm))
- {
- /* Must be 32 bit */
- i.types[op].bitfield.disp32 = 1;
- i.types[op].bitfield.disp32s = 0;
- }
+ i.types[op].bitfield.disp32 = 1;
else
- {
- i.types[op].bitfield.disp32 = 0;
- i.types[op].bitfield.disp32s = 1;
- }
+ i.types[op].bitfield.disp32s = 1;
if ((i.index_reg->reg_flags & RegRex) != 0)
i.rex |= REX_X;
}
{
bfd_reloc_code_real_type got_reloc = NO_RELOC;
+#if ((defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) \
+ && !defined (LEX_AT)) \
+ || defined (TE_PE)
intel_syntax = -intel_syntax;
exp->X_md = 0;
if (intel_syntax)
i386_intel_simplify (exp);
+#else
+ expression (exp);
+#endif
+
+ /* If not 64bit, massage value, to account for wraparound when !BFD64. */
+ if (size == 4 && exp->X_op == O_constant && !object_64bit)
+ exp->X_add_number = extend_to_32bit_address (exp->X_add_number);
return got_reloc;
}
static void
signed_cons (int size)
{
- if (flag_code == CODE_64BIT)
+ if (object_64bit)
cons_sign = 1;
cons (size);
cons_sign = -1;
/* Handle Vector operations. */
static char *
-check_VecOperations (char *op_string, char *op_end)
+check_VecOperations (char *op_string)
{
const reg_entry *mask;
const char *saved;
char *end_op;
- while (*op_string
- && (op_end == NULL || op_string < op_end))
+ while (*op_string)
{
saved = op_string;
if (*op_string == '{')
exp_seg = expression (exp);
SKIP_WHITESPACE ();
-
- /* Handle vector operations. */
- if (*input_line_pointer == '{')
- {
- input_line_pointer = check_VecOperations (input_line_pointer,
- NULL);
- if (input_line_pointer == NULL)
- return 0;
- }
-
if (*input_line_pointer)
as_bad (_("junk `%s' after expression"), input_line_pointer);
{
/* Size it properly later. */
i.types[this_operand].bitfield.imm64 = 1;
- /* If not 64bit, sign extend val. */
- if (flag_code != CODE_64BIT
- && (exp->X_add_number & ~(((addressT) 2 << 31) - 1)) == 0)
- exp->X_add_number
- = (exp->X_add_number ^ ((addressT) 1 << 31)) - ((addressT) 1 << 31);
+
+ /* If not 64bit, sign/zero extend val, to account for wraparound
+ when !BFD64. */
+ if (flag_code != CODE_64BIT)
+ exp->X_add_number = extend_to_32bit_address (exp->X_add_number);
}
#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT))
else if (OUTPUT_FLAVOR == bfd_target_aout_flavour
ret = 0;
}
+ else if (exp->X_op == O_constant)
+ {
+ /* Sizing gets taken care of by optimize_disp().
+
+ If not 64bit, sign/zero extend val, to account for wraparound
+ when !BFD64. */
+ if (flag_code != CODE_64BIT)
+ exp->X_add_number = extend_to_32bit_address (exp->X_add_number);
+ }
+
#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT))
- else if (exp->X_op != O_constant
- && OUTPUT_FLAVOR == bfd_target_aout_flavour
+ else if (OUTPUT_FLAVOR == bfd_target_aout_flavour
&& exp_seg != absolute_section
&& exp_seg != text_section
&& exp_seg != data_section
}
#endif
- if (current_templates->start->opcode_modifier.jump == JUMP_BYTE
- /* Constants get taken care of by optimize_disp(). */
- && exp->X_op != O_constant)
+ else if (current_templates->start->opcode_modifier.jump == JUMP_BYTE)
i.types[this_operand].bitfield.disp8 = 1;
/* Check if this is a displacement only operand. */
- bigdisp = i.types[this_operand];
- bigdisp.bitfield.disp8 = 0;
- bigdisp.bitfield.disp16 = 0;
- bigdisp.bitfield.disp32 = 0;
- bigdisp.bitfield.disp32s = 0;
- bigdisp.bitfield.disp64 = 0;
+ bigdisp = operand_type_and_not (i.types[this_operand], anydisp);
if (operand_type_all_zero (&bigdisp))
i.types[this_operand] = operand_type_and (i.types[this_operand],
types);
return 1;
}
+static INLINE bool starts_memory_operand (char c)
+{
+ return ISDIGIT (c)
+ || is_identifier_char (c)
+ || strchr ("([\"+-!~", c);
+}
+
/* Parse OPERAND_STRING into the i386_insn structure I. Returns zero
on error. */
if (is_space_char (*op_string))
++op_string;
- if (!is_digit_char (*op_string)
- && !is_identifier_char (*op_string)
- && *op_string != '('
- && *op_string != ABSOLUTE_PREFIX)
- {
- as_bad (_("bad memory operand `%s'"), op_string);
- return 0;
- }
/* Handle case of %es:*foo. */
- if (*op_string == ABSOLUTE_PREFIX)
+ if (!i.jumpabsolute && *op_string == ABSOLUTE_PREFIX)
{
++op_string;
if (is_space_char (*op_string))
++op_string;
i.jumpabsolute = true;
}
+
+ if (!starts_memory_operand (*op_string))
+ {
+ as_bad (_("bad memory operand `%s'"), op_string);
+ return 0;
+ }
goto do_memory_reference;
}
/* Handle vector operations. */
if (*op_string == '{')
{
- op_string = check_VecOperations (op_string, NULL);
+ op_string = check_VecOperations (op_string);
if (op_string == NULL)
return 0;
}
/* If it is a RC or SAE immediate, do nothing. */
;
}
- else if (is_digit_char (*op_string)
- || is_identifier_char (*op_string)
- || *op_string == '"'
- || *op_string == '(')
+ else if (starts_memory_operand (*op_string))
{
/* This is a memory reference of some sort. */
char *base_string;
/* Start and end of displacement string expression (if found). */
char *displacement_string_start;
char *displacement_string_end;
- char *vop_start;
do_memory_reference:
if (i.mem_operands == 1 && !maybe_adjust_templates ())
base_string = op_string + strlen (op_string);
/* Handle vector operations. */
- vop_start = strchr (op_string, '{');
- if (vop_start && vop_start < base_string)
- {
- if (check_VecOperations (vop_start, base_string) == NULL)
- return 0;
- base_string = vop_start;
- }
-
--base_string;
if (is_space_char (*base_string))
--base_string;
+ if (*base_string == '}')
+ {
+ char *vop_start = NULL;
+
+ while (base_string-- > op_string)
+ {
+ if (*base_string == '"')
+ break;
+ if (*base_string != '{')
+ continue;
+
+ vop_start = base_string;
+
+ --base_string;
+ if (is_space_char (*base_string))
+ --base_string;
+
+ if (*base_string != '}')
+ break;
+
+ vop_start = NULL;
+ }
+
+ if (!vop_start)
+ {
+ as_bad (_("unbalanced figure braces"));
+ return 0;
+ }
+
+ if (check_VecOperations (vop_start) == NULL)
+ return 0;
+ }
+
/* If we only have a displacement, set-up for it to be parsed later. */
displacement_string_start = op_string;
displacement_string_end = base_string + 1;
if (*base_string == ')')
{
char *temp_string;
- unsigned int parens_balanced = 1;
+ unsigned int parens_not_balanced = 1;
+
/* We've already checked that the number of left & right ()'s are
equal, so this loop will not be infinite. */
do
{
base_string--;
if (*base_string == ')')
- parens_balanced++;
+ parens_not_balanced++;
if (*base_string == '(')
- parens_balanced--;
+ parens_not_balanced--;
}
- while (parens_balanced);
+ while (parens_not_balanced && *base_string != '"');
temp_string = base_string;
/* Skip past '(' and whitespace. */
- ++base_string;
+ if (*base_string == '(')
+ ++base_string;
if (is_space_char (*base_string))
++base_string;
break;
}
#endif /* defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) */
+
+ /* If not 64bit, massage value, to account for wraparound when !BFD64. */
+ if (!object_64bit)
+ value = extend_to_32bit_address (value);
+
*valP = value;
#endif /* !defined (TE_Mach) */