#define DATA_PREFIX 3
#define REP_PREFIX 4
#define HLE_PREFIX REP_PREFIX
+#define BND_PREFIX REP_PREFIX
#define LOCK_PREFIX 5
#define REX_PREFIX 6 /* must come last. */
#define MAX_PREFIXES 7 /* max prefixes per opcode */
static void set_intel_syntax (int);
static void set_intel_mnemonic (int);
static void set_allow_index_reg (int);
-static void set_sse_check (int);
+static void set_check (int);
static void set_cpu_arch (int);
#ifdef TE_PE
static void pe_directive_secrel (int);
unsupported_syntax,
unsupported,
invalid_vsib_address,
+ invalid_vector_register_set,
unsupported_vector_index_register
};
disp_encoding_32bit
} disp_encoding;
- /* Have HLE prefix. */
- unsigned int have_hle;
+ /* REP prefix. */
+ const char *rep_prefix;
+
+ /* HLE prefix. */
+ const char *hle_prefix;
+
+ /* Have BND prefix. */
+ const char *bnd_prefix;
/* Error message. */
enum i386_error error;
static enum x86_elf_abi x86_elf_abi = I386_ABI;
#endif
-/* The names used to print error messages. */
-static const char *flag_code_names[] =
- {
- "32",
- "16",
- "64"
- };
-
/* 1 for intel syntax,
0 if att syntax. */
static int intel_syntax = 0;
/* 1 if register prefix % not required. */
static int allow_naked_reg = 0;
+/* 1 if the assembler should add BND prefix for all control-tranferring
+ instructions supporting it, even if this prefix wasn't specified
+ explicitly. */
+static int add_bnd_prefix = 0;
+
/* 1 if pseudo index register, eiz/riz, is allowed . */
static int allow_index_reg = 0;
-static enum
+static enum check_kind
{
- sse_check_none = 0,
- sse_check_warning,
- sse_check_error
+ check_none = 0,
+ check_warning,
+ check_error
}
-sse_check;
+sse_check, operand_check = check_warning;
/* Register prefix used for error message. */
static const char *register_prefix = "%";
CPU_BDVER1_FLAGS, 0, 0 },
{ STRING_COMMA_LEN ("bdver2"), PROCESSOR_BD,
CPU_BDVER2_FLAGS, 0, 0 },
+ { STRING_COMMA_LEN ("bdver3"), PROCESSOR_BD,
+ CPU_BDVER3_FLAGS, 0, 0 },
+ { STRING_COMMA_LEN ("btver1"), PROCESSOR_BT,
+ CPU_BTVER1_FLAGS, 0, 0 },
+ { STRING_COMMA_LEN ("btver2"), PROCESSOR_BT,
+ CPU_BTVER2_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".8087"), PROCESSOR_UNKNOWN,
CPU_8087_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".287"), PROCESSOR_UNKNOWN,
CPU_LWP_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".movbe"), PROCESSOR_UNKNOWN,
CPU_MOVBE_FLAGS, 0, 0 },
+ { STRING_COMMA_LEN (".cx16"), PROCESSOR_UNKNOWN,
+ CPU_CX16_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".ept"), PROCESSOR_UNKNOWN,
CPU_EPT_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".lzcnt"), PROCESSOR_UNKNOWN,
CPU_BMI_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".tbm"), PROCESSOR_UNKNOWN,
CPU_TBM_FLAGS, 0, 0 },
+ { STRING_COMMA_LEN (".adx"), PROCESSOR_UNKNOWN,
+ CPU_ADX_FLAGS, 0, 0 },
+ { STRING_COMMA_LEN (".rdseed"), PROCESSOR_UNKNOWN,
+ CPU_RDSEED_FLAGS, 0, 0 },
+ { STRING_COMMA_LEN (".prfchw"), PROCESSOR_UNKNOWN,
+ CPU_PRFCHW_FLAGS, 0, 0 },
+ { STRING_COMMA_LEN (".smap"), PROCESSOR_UNKNOWN,
+ CPU_SMAP_FLAGS, 0, 0 },
+ { STRING_COMMA_LEN (".mpx"), PROCESSOR_UNKNOWN,
+ CPU_MPX_FLAGS, 0, 0 },
+ { STRING_COMMA_LEN (".sha"), PROCESSOR_UNKNOWN,
+ CPU_SHA_FLAGS, 0, 0 },
};
#ifdef I386COFF
{"att_mnemonic", set_intel_mnemonic, 0},
{"allow_index_reg", set_allow_index_reg, 1},
{"disallow_index_reg", set_allow_index_reg, 0},
- {"sse_check", set_sse_check, 0},
+ {"sse_check", set_check, 0},
+ {"operand_check", set_check, 1},
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
{"largecomm", handle_large_common, 0},
#else
PROCESSOR_CORE, PROCESSOR_CORE2, PROCESSOR_COREI7, and
PROCESSOR_GENERIC64, alt_long_patt will be used.
3. For PROCESSOR_ATHLON, PROCESSOR_K6, PROCESSOR_K8 and
- PROCESSOR_AMDFAM10, and PROCESSOR_BD, alt_short_patt
+ PROCESSOR_AMDFAM10, PROCESSOR_BD and PROCESSOR_BT, alt_short_patt
will be used.
When -mtune= isn't used, alt_long_patt will be used if
case PROCESSOR_K8:
case PROCESSOR_AMDFAM10:
case PROCESSOR_BD:
+ case PROCESSOR_BT:
patt = alt_short_patt;
break;
case PROCESSOR_I386:
case PROCESSOR_K8:
case PROCESSOR_AMDFAM10:
case PROCESSOR_BD:
+ case PROCESSOR_BT:
case PROCESSOR_GENERIC32:
/* We use cpu_arch_isa_flags to check if we CAN optimize
with nops. */
static const i386_operand_type imm16_32s = OPERAND_TYPE_IMM16_32S;
static const i386_operand_type imm16_32_32s = OPERAND_TYPE_IMM16_32_32S;
static const i386_operand_type vec_imm4 = OPERAND_TYPE_VEC_IMM4;
+static const i386_operand_type regbnd = OPERAND_TYPE_REGBND;
enum operand_type
{
return 0;
}
+static INLINE unsigned int
+register_number (const reg_entry *r)
+{
+ unsigned int nr = r->reg_num;
+
+ if (r->reg_flags & RegRex)
+ nr += 8;
+
+ return nr;
+}
+
static INLINE unsigned int
mode_from_disp_size (i386_operand_type t)
{
}
static void
-set_sse_check (int dummy ATTRIBUTE_UNUSED)
+set_check (int what)
{
+ enum check_kind *kind;
+ const char *str;
+
+ if (what)
+ {
+ kind = &operand_check;
+ str = "operand";
+ }
+ else
+ {
+ kind = &sse_check;
+ str = "sse";
+ }
+
SKIP_WHITESPACE ();
if (!is_end_of_line[(unsigned char) *input_line_pointer])
int e = get_symbol_end ();
if (strcmp (string, "none") == 0)
- sse_check = sse_check_none;
+ *kind = check_none;
else if (strcmp (string, "warning") == 0)
- sse_check = sse_check_warning;
+ *kind = check_warning;
else if (strcmp (string, "error") == 0)
- sse_check = sse_check_error;
+ *kind = check_error;
else
- as_bad (_("bad argument to sse_check directive."));
+ as_bad (_("bad argument to %s_check directive."), str);
*input_line_pointer = e;
}
else
- as_bad (_("missing argument for sse_check directive"));
+ as_bad (_("missing argument for %s_check directive"), str);
demand_empty_rest_of_line ();
}
(void *) core_optab);
if (hash_err)
{
- as_fatal (_("internal Error: Can't hash %s: %s"),
+ as_fatal (_("can't hash %s: %s"),
(optab - 1)->name,
hash_err);
}
{
hash_err = hash_insert (reg_hash, regtab->reg_name, (void *) regtab);
if (hash_err)
- as_fatal (_("internal Error: Can't hash %s: %s"),
+ as_fatal (_("can't hash %s: %s"),
regtab->reg_name,
hash_err);
}
operand_chars[(unsigned char) *p] = *p;
}
-#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
- if (IS_ELF)
- {
- record_alignment (text_section, 2);
- record_alignment (data_section, 2);
- record_alignment (bss_section, 2);
- }
-#endif
-
if (flag_code == CODE_64BIT)
{
#if defined (OBJ_COFF) && defined (TE_PE)
break;
}
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+ if (other == BFD_RELOC_SIZE32)
+ {
+ if (size == 8)
+ return BFD_RELOC_SIZE64;
+ if (pcrel)
+ as_bad (_("there are no pc-relative size relocations"));
+ }
+#endif
+
/* Sign-checking 4-byte relocations in 16-/32-bit code is pointless. */
if (size == 4 && (flag_code != CODE_64BIT || disallow_64bit_reloc))
sign = -1;
&& fixP->fx_r_type == BFD_RELOC_32_PCREL)
return 0;
- /* adjust_reloc_syms doesn't know about the GOT. */
- if (fixP->fx_r_type == BFD_RELOC_386_GOTOFF
+ /* Adjust_reloc_syms doesn't know about the GOT. Need to keep symbol
+ for size relocations. */
+ if (fixP->fx_r_type == BFD_RELOC_SIZE32
+ || fixP->fx_r_type == BFD_RELOC_SIZE64
+ || 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_386_TLS_GD
/* Check register specifier. */
if (i.vex.register_specifier)
- {
- register_specifier = i.vex.register_specifier->reg_num;
- if ((i.vex.register_specifier->reg_flags & RegRex))
- register_specifier += 8;
- register_specifier = ~register_specifier & 0xf;
- }
+ register_specifier = ~register_number (i.vex.register_specifier) & 0xf;
else
register_specifier = 0xf;
{
expressionS *exp;
- if (i.tm.cpu_flags.bitfield.cpusse3 && i.operands > 0)
+ if ((i.tm.cpu_flags.bitfield.cpusse3 || i.tm.cpu_flags.bitfield.cpusvme)
+ && i.operands > 0)
{
- /* SSE3 Instructions have the fixed operands with an opcode
- suffix which is coded in the same place as an 8-bit immediate
- field would be. Here we check those operands and remove them
- afterwards. */
+ /* MONITOR/MWAIT as well as SVME instructions have fixed operands
+ with an opcode suffix which is coded in the same place as an
+ 8-bit immediate field would be.
+ Here we check those operands and remove them afterwards. */
unsigned int x;
for (x = 0; x < i.operands; x++)
- if (i.op[x].regs->reg_num != x)
+ if (register_number (i.op[x].regs) != x)
as_bad (_("can't use register '%s%s' as operand %d in '%s'."),
register_prefix, i.op[x].regs->reg_name, x + 1,
i.tm.name);
default:
abort ();
case HLEPrefixNone:
- if (i.prefix[HLE_PREFIX] == XACQUIRE_PREFIX_OPCODE)
- as_bad (_("invalid instruction `%s' after `xacquire'"),
- i.tm.name);
- else
- as_bad (_("invalid instruction `%s' after `xrelease'"),
- i.tm.name);
+ as_bad (_("invalid instruction `%s' after `%s'"),
+ i.tm.name, i.hle_prefix);
return 0;
case HLEPrefixLock:
if (i.prefix[LOCK_PREFIX])
return 1;
- if (i.prefix[HLE_PREFIX] == XACQUIRE_PREFIX_OPCODE)
- as_bad (_("missing `lock' with `xacquire'"));
- else
- as_bad (_("missing `lock' with `xrelease'"));
+ as_bad (_("missing `lock' with `%s'"), i.hle_prefix);
return 0;
case HLEPrefixAny:
return 1;
if (!(t = match_template ()))
return;
- if (sse_check != sse_check_none
+ if (sse_check != check_none
&& !i.tm.opcode_modifier.noavx
&& (i.tm.cpu_flags.bitfield.cpusse
|| i.tm.cpu_flags.bitfield.cpusse2
|| i.tm.cpu_flags.bitfield.cpusse4_1
|| i.tm.cpu_flags.bitfield.cpusse4_2))
{
- (sse_check == sse_check_warning
+ (sse_check == check_warning
? as_warn
: as_bad) (_("SSE instruction `%s' is used"), i.tm.name);
}
if (!add_prefix (FWAIT_OPCODE))
return;
+ /* Check if REP prefix is OK. */
+ if (i.rep_prefix && !i.tm.opcode_modifier.repprefixok)
+ {
+ as_bad (_("invalid instruction `%s' after `%s'"),
+ i.tm.name, i.rep_prefix);
+ return;
+ }
+
/* Check for lock without a lockable instruction. Destination operand
must be memory unless it is xchg (0x86). */
if (i.prefix[LOCK_PREFIX]
}
/* Check if HLE prefix is OK. */
- if (i.have_hle && !check_hle ())
+ if (i.hle_prefix && !check_hle ())
return;
+ /* Check BND prefix. */
+ if (i.bnd_prefix && !i.tm.opcode_modifier.bndprefixok)
+ as_bad (_("expecting valid branch instruction after `bnd'"));
+
+ if (i.tm.cpu_flags.bitfield.cpumpx
+ && flag_code == CODE_64BIT
+ && i.prefix[ADDR_PREFIX])
+ as_bad (_("32-bit address isn't allowed in 64-bit MPX instructions."));
+
+ /* Insert BND prefix. */
+ if (add_bnd_prefix
+ && i.tm.opcode_modifier.bndprefixok
+ && !i.prefix[BND_PREFIX])
+ add_prefix (BND_PREFIX_OPCODE);
+
/* Check string instruction segment overrides. */
if (i.tm.opcode_modifier.isstring && i.mem_operands != 0)
{
const insn_template *t;
char *dot_p = NULL;
- /* Non-zero if we found a prefix only acceptable with string insns. */
- const char *expecting_string_instruction = NULL;
-
while (1)
{
mnem_p = mnemonic;
return NULL;
case PREFIX_REP:
if (current_templates->start->cpu_flags.bitfield.cpuhle)
- i.have_hle = 1;
+ i.hle_prefix = current_templates->start->name;
+ else if (current_templates->start->cpu_flags.bitfield.cpumpx)
+ i.bnd_prefix = current_templates->start->name;
else
- expecting_string_instruction = current_templates->start->name;
+ i.rep_prefix = current_templates->start->name;
break;
default:
break;
as_warn (_("use .code16 to ensure correct addressing mode"));
}
- /* Check for rep/repne without a string instruction. */
- if (expecting_string_instruction)
- {
- static templates override;
-
- for (t = current_templates->start; t < current_templates->end; ++t)
- if (t->opcode_modifier.isstring)
- break;
- if (t >= current_templates->end)
- {
- as_bad (_("expecting string instruction after `%s'"),
- expecting_string_instruction);
- return NULL;
- }
- for (override.start = t; t < current_templates->end; ++t)
- if (!t->opcode_modifier.isstring)
- break;
- override.end = t;
- current_templates = &override;
- }
-
return l;
}
return 1;
}
- /* For VSIB byte, we need a vector register for index and no PC
- relative addressing is allowed. */
- if (t->opcode_modifier.vecsib
- && (!i.index_reg
+ /* For VSIB byte, we need a vector register for index, and all vector
+ registers must be distinct. */
+ if (t->opcode_modifier.vecsib)
+ {
+ if (!i.index_reg
|| !((t->opcode_modifier.vecsib == VecSIB128
&& i.index_reg->reg_type.bitfield.regxmm)
|| (t->opcode_modifier.vecsib == VecSIB256
- && i.index_reg->reg_type.bitfield.regymm))
- || (i.base_reg && i.base_reg->reg_num == RegRip)))
- {
- i.error = invalid_vsib_address;
- return 1;
+ && i.index_reg->reg_type.bitfield.regymm)))
+ {
+ i.error = invalid_vsib_address;
+ return 1;
+ }
+
+ gas_assert (i.reg_operands == 2);
+ gas_assert (i.types[0].bitfield.regxmm
+ || i.types[0].bitfield.regymm);
+ gas_assert (i.types[2].bitfield.regxmm
+ || i.types[2].bitfield.regymm);
+
+ if (operand_check == check_none)
+ return 0;
+ if (register_number (i.op[0].regs) != register_number (i.index_reg)
+ && register_number (i.op[2].regs) != register_number (i.index_reg)
+ && register_number (i.op[0].regs) != register_number (i.op[2].regs))
+ return 0;
+ if (operand_check == check_error)
+ {
+ i.error = invalid_vector_register_set;
+ return 1;
+ }
+ as_warn (_("mask, index, and destination registers should be distinct"));
}
return 0;
unsigned int j;
unsigned int found_cpu_match;
unsigned int check_register;
+ enum i386_error specific_error = 0;
#if MAX_OPERANDS != 5
# error "MAX_OPERANDS must be 5."
continue;
}
- /* Check if vector operands are valid. */
- if (check_VecOperands (t))
- continue;
-
- /* Check if VEX operands are valid. */
- if (VEX_check_operands (t))
- continue;
+ /* Check if vector and VEX operands are valid. */
+ if (check_VecOperands (t) || VEX_check_operands (t))
+ {
+ specific_error = i.error;
+ continue;
+ }
/* We've found a match; break out of loop. */
break;
{
/* We found no match. */
const char *err_msg;
- switch (i.error)
+ switch (specific_error ? specific_error : i.error)
{
default:
abort ();
err_msg = _("invalid instruction suffix");
break;
case bad_imm4:
- err_msg = _("Imm4 isn't the first operand");
+ err_msg = _("constant doesn't fit in 4 bits");
break;
case old_gcc_only:
err_msg = _("only supported with old gcc");
case invalid_vsib_address:
err_msg = _("invalid VSIB address");
break;
+ case invalid_vector_register_set:
+ err_msg = _("mask, index, and destination registers must be distinct");
+ break;
case unsupported_vector_index_register:
err_msg = _("unsupported vector index register");
break;
if (i.types[op].bitfield.reg8)
continue;
+ /* I/O port address operands are OK too. */
+ if (i.tm.operand_types[op].bitfield.inoutportreg)
+ continue;
+
/* crc32 doesn't generate this warning. */
if (i.tm.base_opcode == 0xf20f38f0)
continue;
if ((i.types[op].bitfield.reg16
|| i.types[op].bitfield.reg32
|| i.types[op].bitfield.reg64)
- && i.op[op].regs->reg_num < 4)
+ && i.op[op].regs->reg_num < 4
+ /* Prohibit these changes in 64bit mode, since the lowering
+ would be more complicated. */
+ && flag_code != CODE_64BIT)
{
- /* Prohibit these changes in the 64bit mode, since the
- lowering is more complicated. */
- if (flag_code == CODE_64BIT
- && !i.tm.operand_types[op].bitfield.inoutportreg)
- {
- as_bad (_("incorrect register `%s%s' used with `%c' suffix"),
- register_prefix, i.op[op].regs->reg_name,
- i.suffix);
- return 0;
- }
#if REGISTER_WARNINGS
- if (!quiet_warnings
- && !i.tm.operand_types[op].bitfield.inoutportreg)
+ if (!quiet_warnings)
as_warn (_("using `%s%s' instead of `%s%s' due to `%c' suffix"),
register_prefix,
(i.op[op].regs + (i.types[op].bitfield.reg16
{
/* The first operand is implicit and must be xmm0. */
gas_assert (operand_type_equal (&i.types[0], ®xmm));
- if (i.op[0].regs->reg_num != 0)
+ if (register_number (i.op[0].regs) != 0)
return bad_implicit_operand (1);
if (i.tm.opcode_modifier.vexsources == VEX3SOURCES)
gas_assert (i.reg_operands
&& (operand_type_equal (&i.types[0], ®xmm)
|| operand_type_equal (&i.types[0], ®ymm)));
- if (i.op[0].regs->reg_num != 0)
+ if (register_number (i.op[0].regs) != 0)
return bad_implicit_operand (i.types[0].bitfield.regxmm);
for (j = 1; j < i.operands; j++)
|| operand_type_equal (&i.tm.operand_types[reg_slot],
®ymm));
exp->X_op = O_constant;
- exp->X_add_number
- = ((i.op[reg_slot].regs->reg_num
- + ((i.op[reg_slot].regs->reg_flags & RegRex) ? 8 : 0))
- << 4);
+ exp->X_add_number = register_number (i.op[reg_slot].regs) << 4;
}
else
{
|| operand_type_equal (&i.tm.operand_types[reg_slot],
®ymm));
i.op[imm_slot].imms->X_add_number
- |= ((i.op[reg_slot].regs->reg_num
- + ((i.op[reg_slot].regs->reg_flags & RegRex) ? 8 : 0))
- << 4);
+ |= register_number (i.op[reg_slot].regs) << 4;
}
gas_assert (operand_type_equal (&i.tm.operand_types[nds], ®xmm)
i.sib.base = i.base_reg->reg_num;
/* x86-64 ignores REX prefix bit here to avoid decoder
complications. */
- if ((i.base_reg->reg_num & 7) == EBP_REG_NUM)
- {
+ if (!(i.base_reg->reg_flags & RegRex)
+ && (i.base_reg->reg_num == EBP_REG_NUM
+ || i.base_reg->reg_num == ESP_REG_NUM))
default_seg = &ss;
- if (i.disp_operands == 0)
- {
- fake_zero_displacement = 1;
- i.types[op].bitfield.disp8 = 1;
- }
- }
- else if (i.base_reg->reg_num == ESP_REG_NUM)
+ if (i.base_reg->reg_num == 5 && i.disp_operands == 0)
{
- default_seg = &ss;
+ fake_zero_displacement = 1;
+ i.types[op].bitfield.disp8 = 1;
}
i.sib.scale = i.log2_scale_factor;
if (i.index_reg == 0)
|| i.types[op].bitfield.regmmx
|| i.types[op].bitfield.regxmm
|| i.types[op].bitfield.regymm
+ || i.types[op].bitfield.regbnd
|| i.types[op].bitfield.sreg2
|| i.types[op].bitfield.sreg3
|| i.types[op].bitfield.control
i.prefixes--;
}
+ /* BND prefixed jump. */
+ if (i.prefix[BND_PREFIX] != 0)
+ {
+ FRAG_APPEND_1_CHAR (i.prefix[BND_PREFIX]);
+ i.prefixes -= 1;
+ }
+
if (i.prefixes != 0 && !intel_syntax)
as_warn (_("skipping prefixes on this instruction"));
i.prefixes -= 1;
}
+ /* BND prefixed jump. */
+ if (i.prefix[BND_PREFIX] != 0)
+ {
+ FRAG_APPEND_1_CHAR (i.prefix[BND_PREFIX]);
+ i.prefixes -= 1;
+ }
+
if (i.prefixes != 0 && !intel_syntax)
as_warn (_("skipping prefixes on this instruction"));
fix_new_exp (frag, off, len, exp, 0, r);
}
+/* Export the ABI address size for use by TC_ADDRESS_BYTES for the
+ purpose of the `.dc.a' internal pseudo-op. */
+
+int
+x86_address_bytes (void)
+{
+ if ((stdoutput->arch_info->mach & bfd_mach_x64_32))
+ return 4;
+ return stdoutput->arch_info->bits_per_address / 8;
+}
+
#if !(defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) || defined (OBJ_MACH_O)) \
|| defined (LEX_AT)
# define lex_got(reloc, adjust, types) NULL
const enum bfd_reloc_code_real rel[2];
const i386_operand_type types64;
} gotrel[] = {
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+ { STRING_COMMA_LEN ("SIZE"), { BFD_RELOC_SIZE32,
+ BFD_RELOC_SIZE32 },
+ OPERAND_TYPE_IMM32_64 },
+#endif
{ STRING_COMMA_LEN ("PLTOFF"), { _dummy_first_bfd_reloc_code_real,
BFD_RELOC_X86_64_PLTOFF64 },
OPERAND_TYPE_IMM64 },
char *tmpbuf, *past_reloc;
*rel = gotrel[j].rel[object_64bit];
- if (adjust)
- *adjust = len;
if (types)
{
*types = gotrel[j].types64;
}
- if (GOT_symbol == NULL)
+ if (j != 0 && GOT_symbol == NULL)
GOT_symbol = symbol_find_or_make (GLOBAL_OFFSET_TABLE_NAME);
/* The length of the first part of our input line. */
/* Replace the relocation token with ' ', so that
errors like foo@GOTOFF1 will be detected. */
tmpbuf[first++] = ' ';
+ else
+ /* Increment length by 1 if the relocation token is
+ removed. */
+ len++;
+ if (adjust)
+ *adjust = len;
memcpy (tmpbuf + first, past_reloc, second);
tmpbuf[first + second] = '\0';
return tmpbuf;
}
#endif
+#ifdef TE_PE
+#ifdef lex_got
+#undef lex_got
+#endif
+/* Parse operands of the form
+ <symbol>@SECREL32+<nnn>
+
+ If we find one, set up the correct relocation in RELOC and copy the
+ input string, minus the `@SECREL32' into a malloc'd buffer for
+ parsing by the calling routine. Return this buffer, and if ADJUST
+ is non-null set it to the length of the string we removed from the
+ input line. Otherwise return NULL.
+
+ This function is copied from the ELF version above adjusted for PE targets. */
+
+static char *
+lex_got (enum bfd_reloc_code_real *rel ATTRIBUTE_UNUSED,
+ int *adjust ATTRIBUTE_UNUSED,
+ i386_operand_type *types ATTRIBUTE_UNUSED)
+{
+ static const struct
+ {
+ const char *str;
+ int len;
+ const enum bfd_reloc_code_real rel[2];
+ const i386_operand_type types64;
+ }
+ gotrel[] =
+ {
+ { STRING_COMMA_LEN ("SECREL32"), { BFD_RELOC_32_SECREL,
+ BFD_RELOC_32_SECREL },
+ OPERAND_TYPE_IMM32_32S_64_DISP32_64 },
+ };
+
+ char *cp;
+ unsigned j;
+
+ for (cp = input_line_pointer; *cp != '@'; cp++)
+ if (is_end_of_line[(unsigned char) *cp] || *cp == ',')
+ return NULL;
+
+ for (j = 0; j < ARRAY_SIZE (gotrel); j++)
+ {
+ int len = gotrel[j].len;
+
+ if (strncasecmp (cp + 1, gotrel[j].str, len) == 0)
+ {
+ if (gotrel[j].rel[object_64bit] != 0)
+ {
+ int first, second;
+ char *tmpbuf, *past_reloc;
+
+ *rel = gotrel[j].rel[object_64bit];
+ if (adjust)
+ *adjust = len;
+
+ if (types)
+ {
+ if (flag_code != CODE_64BIT)
+ {
+ types->bitfield.imm32 = 1;
+ types->bitfield.disp32 = 1;
+ }
+ else
+ *types = gotrel[j].types64;
+ }
+
+ /* The length of the first part of our input line. */
+ first = cp - input_line_pointer;
+
+ /* The second part goes from after the reloc token until
+ (and including) an end_of_line char or comma. */
+ past_reloc = cp + 1 + len;
+ cp = past_reloc;
+ while (!is_end_of_line[(unsigned char) *cp] && *cp != ',')
+ ++cp;
+ second = cp + 1 - past_reloc;
+
+ /* Allocate and copy string. The trailing NUL shouldn't
+ be necessary, but be safe. */
+ tmpbuf = (char *) xmalloc (first + second + 2);
+ memcpy (tmpbuf, input_line_pointer, first);
+ if (second != 0 && *past_reloc != ' ')
+ /* Replace the relocation token with ' ', so that
+ errors like foo@SECLREL321 will be detected. */
+ tmpbuf[first++] = ' ';
+ memcpy (tmpbuf + first, past_reloc, second);
+ tmpbuf[first + second] = '\0';
+ return tmpbuf;
+ }
+
+ as_bad (_("@%s reloc is not supported with %d-bit output format"),
+ gotrel[j].str, 1 << (5 + object_64bit));
+ return NULL;
+ }
+ }
+
+ /* Might be a symbol version string. Don't as_bad here. */
+ return NULL;
+}
+
+#endif /* TE_PE */
+
void
x86_cons (expressionS *exp, int size)
{
static int
i386_index_check (const char *operand_string)
{
- int ok;
const char *kind = "base/index";
+ enum flag_code addr_mode;
+
+ if (i.prefix[ADDR_PREFIX])
+ addr_mode = flag_code == CODE_32BIT ? CODE_16BIT : CODE_32BIT;
+ else
+ {
+ addr_mode = flag_code;
+
#if INFER_ADDR_PREFIX
- int fudged = 0;
+ if (i.mem_operands == 0)
+ {
+ /* Infer address prefix from the first memory operand. */
+ const reg_entry *addr_reg = i.base_reg;
+
+ if (addr_reg == NULL)
+ addr_reg = i.index_reg;
- tryprefix:
+ if (addr_reg)
+ {
+ if (addr_reg->reg_num == RegEip
+ || addr_reg->reg_num == RegEiz
+ || addr_reg->reg_type.bitfield.reg32)
+ addr_mode = CODE_32BIT;
+ else if (flag_code != CODE_64BIT
+ && addr_reg->reg_type.bitfield.reg16)
+ addr_mode = CODE_16BIT;
+
+ if (addr_mode != flag_code)
+ {
+ i.prefix[ADDR_PREFIX] = ADDR_PREFIX_OPCODE;
+ i.prefixes += 1;
+ /* Change the size of any displacement too. At most one
+ of Disp16 or Disp32 is set.
+ FIXME. There doesn't seem to be any real need for
+ separate Disp16 and Disp32 flags. The same goes for
+ Imm16 and Imm32. Removing them would probably clean
+ up the code quite a lot. */
+ if (flag_code != CODE_64BIT
+ && (i.types[this_operand].bitfield.disp16
+ || i.types[this_operand].bitfield.disp32))
+ i.types[this_operand]
+ = operand_type_xor (i.types[this_operand], disp16_32);
+ }
+ }
+ }
#endif
- ok = 1;
+ }
+
if (current_templates->start->opcode_modifier.isstring
&& !current_templates->start->opcode_modifier.immext
&& (current_templates->end[-1].opcode_modifier.isstring
{
/* Memory operands of string insns are special in that they only allow
a single register (rDI, rSI, or rBX) as their memory address. */
- unsigned int expected;
+ const reg_entry *expected_reg;
+ static const char *di_si[][2] =
+ {
+ { "esi", "edi" },
+ { "si", "di" },
+ { "rsi", "rdi" }
+ };
+ static const char *bx[] = { "ebx", "bx", "rbx" };
kind = "string address";
&& current_templates->end[-1].operand_types[1]
.bitfield.baseindex))
type = current_templates->end[-1].operand_types[1];
- expected = type.bitfield.esseg ? 7 /* rDI */ : 6 /* rSI */;
+ expected_reg = hash_find (reg_hash,
+ di_si[addr_mode][type.bitfield.esseg]);
+
}
else
- expected = 3 /* rBX */;
+ expected_reg = hash_find (reg_hash, bx[addr_mode]);
- if (!i.base_reg || i.index_reg
+ if (i.base_reg != expected_reg
+ || i.index_reg
|| operand_type_check (i.types[this_operand], disp))
- ok = -1;
- else if (!(flag_code == CODE_64BIT
- ? i.prefix[ADDR_PREFIX]
- ? i.base_reg->reg_type.bitfield.reg32
- : i.base_reg->reg_type.bitfield.reg64
- : (flag_code == CODE_16BIT) ^ !i.prefix[ADDR_PREFIX]
- ? i.base_reg->reg_type.bitfield.reg32
- : i.base_reg->reg_type.bitfield.reg16))
- ok = 0;
- else if (i.base_reg->reg_num != expected)
- ok = -1;
-
- if (ok < 0)
- {
- unsigned int j;
-
- for (j = 0; j < i386_regtab_size; ++j)
- if ((flag_code == CODE_64BIT
- ? i.prefix[ADDR_PREFIX]
- ? i386_regtab[j].reg_type.bitfield.reg32
- : i386_regtab[j].reg_type.bitfield.reg64
- : (flag_code == CODE_16BIT) ^ !i.prefix[ADDR_PREFIX]
- ? i386_regtab[j].reg_type.bitfield.reg32
- : i386_regtab[j].reg_type.bitfield.reg16)
- && i386_regtab[j].reg_num == expected)
- break;
- gas_assert (j < i386_regtab_size);
+ {
+ /* The second memory operand must have the same size as
+ the first one. */
+ if (i.mem_operands
+ && i.base_reg
+ && !((addr_mode == CODE_64BIT
+ && i.base_reg->reg_type.bitfield.reg64)
+ || (addr_mode == CODE_32BIT
+ ? i.base_reg->reg_type.bitfield.reg32
+ : i.base_reg->reg_type.bitfield.reg16)))
+ goto bad_address;
+
as_warn (_("`%s' is not valid here (expected `%c%s%s%c')"),
operand_string,
intel_syntax ? '[' : '(',
register_prefix,
- i386_regtab[j].reg_name,
+ expected_reg->reg_name,
intel_syntax ? ']' : ')');
- ok = 1;
- }
- }
- else if (flag_code == CODE_64BIT)
- {
- if ((i.base_reg
- && ((i.prefix[ADDR_PREFIX] == 0
- && !i.base_reg->reg_type.bitfield.reg64)
- || (i.prefix[ADDR_PREFIX]
- && !i.base_reg->reg_type.bitfield.reg32))
- && (i.index_reg
- || i.base_reg->reg_num !=
- (i.prefix[ADDR_PREFIX] == 0 ? RegRip : RegEip)))
- || (i.index_reg
- && !(i.index_reg->reg_type.bitfield.regxmm
- || i.index_reg->reg_type.bitfield.regymm)
- && (!i.index_reg->reg_type.bitfield.baseindex
- || (i.prefix[ADDR_PREFIX] == 0
- && i.index_reg->reg_num != RegRiz
- && !i.index_reg->reg_type.bitfield.reg64
- )
- || (i.prefix[ADDR_PREFIX]
- && i.index_reg->reg_num != RegEiz
- && !i.index_reg->reg_type.bitfield.reg32))))
- ok = 0;
+ return 1;
+ }
+ else
+ return 1;
+
+bad_address:
+ as_bad (_("`%s' is not a valid %s expression"),
+ operand_string, kind);
+ return 0;
}
else
{
- if ((flag_code == CODE_16BIT) ^ (i.prefix[ADDR_PREFIX] != 0))
+ if (addr_mode != CODE_16BIT)
+ {
+ /* 32-bit/64-bit checks. */
+ if ((i.base_reg
+ && (addr_mode == CODE_64BIT
+ ? !i.base_reg->reg_type.bitfield.reg64
+ : !i.base_reg->reg_type.bitfield.reg32)
+ && (i.index_reg
+ || (i.base_reg->reg_num
+ != (addr_mode == CODE_64BIT ? RegRip : RegEip))))
+ || (i.index_reg
+ && !i.index_reg->reg_type.bitfield.regxmm
+ && !i.index_reg->reg_type.bitfield.regymm
+ && ((addr_mode == CODE_64BIT
+ ? !(i.index_reg->reg_type.bitfield.reg64
+ || i.index_reg->reg_num == RegRiz)
+ : !(i.index_reg->reg_type.bitfield.reg32
+ || i.index_reg->reg_num == RegEiz))
+ || !i.index_reg->reg_type.bitfield.baseindex)))
+ goto bad_address;
+ }
+ else
{
- /* 16bit checks. */
+ /* 16-bit checks. */
if ((i.base_reg
&& (!i.base_reg->reg_type.bitfield.reg16
|| !i.base_reg->reg_type.bitfield.baseindex))
&& i.base_reg->reg_num < 6
&& i.index_reg->reg_num >= 6
&& i.log2_scale_factor == 0))))
- ok = 0;
- }
- else
- {
- /* 32bit checks. */
- if ((i.base_reg
- && !i.base_reg->reg_type.bitfield.reg32)
- || (i.index_reg
- && !i.index_reg->reg_type.bitfield.regxmm
- && !i.index_reg->reg_type.bitfield.regymm
- && ((!i.index_reg->reg_type.bitfield.reg32
- && i.index_reg->reg_num != RegEiz)
- || !i.index_reg->reg_type.bitfield.baseindex)))
- ok = 0;
+ goto bad_address;
}
}
- if (!ok)
- {
-#if INFER_ADDR_PREFIX
- if (!i.mem_operands && !i.prefix[ADDR_PREFIX])
- {
- i.prefix[ADDR_PREFIX] = ADDR_PREFIX_OPCODE;
- i.prefixes += 1;
- /* Change the size of any displacement too. At most one of
- Disp16 or Disp32 is set.
- FIXME. There doesn't seem to be any real need for separate
- Disp16 and Disp32 flags. The same goes for Imm16 and Imm32.
- Removing them would probably clean up the code quite a lot. */
- if (flag_code != CODE_64BIT
- && (i.types[this_operand].bitfield.disp16
- || i.types[this_operand].bitfield.disp32))
- i.types[this_operand]
- = operand_type_xor (i.types[this_operand], disp16_32);
- fudged = 1;
- goto tryprefix;
- }
- if (fudged)
- as_bad (_("`%s' is not a valid %s expression"),
- operand_string,
- kind);
- else
-#endif
- as_bad (_("`%s' is not a valid %s-bit %s expression"),
- operand_string,
- flag_code_names[i.prefix[ADDR_PREFIX]
- ? flag_code == CODE_32BIT
- ? CODE_16BIT
- : CODE_32BIT
- : flag_code],
- kind);
- }
- return ok;
+ return 1;
}
/* Parse OPERAND_STRING into the i386_insn structure I. Returns zero
}
else if (*base_string == REGISTER_PREFIX)
{
+ end_op = strchr (base_string, ',');
+ if (end_op)
+ *end_op = '\0';
as_bad (_("bad register name `%s'"), base_string);
return 0;
}
}
else if (*base_string == REGISTER_PREFIX)
{
+ end_op = strchr (base_string, ',');
+ if (end_op)
+ *end_op = '\0';
as_bad (_("bad register name `%s'"), base_string);
return 0;
}
#define OPTION_MOLD_GCC (OPTION_MD_BASE + 9)
#define OPTION_MSSE2AVX (OPTION_MD_BASE + 10)
#define OPTION_MSSE_CHECK (OPTION_MD_BASE + 11)
-#define OPTION_MAVXSCALAR (OPTION_MD_BASE + 12)
-#define OPTION_X32 (OPTION_MD_BASE + 13)
+#define OPTION_MOPERAND_CHECK (OPTION_MD_BASE + 12)
+#define OPTION_MAVXSCALAR (OPTION_MD_BASE + 13)
+#define OPTION_X32 (OPTION_MD_BASE + 14)
+#define OPTION_MADD_BND_PREFIX (OPTION_MD_BASE + 15)
struct option md_longopts[] =
{
{"mold-gcc", no_argument, NULL, OPTION_MOLD_GCC},
{"msse2avx", no_argument, NULL, OPTION_MSSE2AVX},
{"msse-check", required_argument, NULL, OPTION_MSSE_CHECK},
+ {"moperand-check", required_argument, NULL, OPTION_MOPERAND_CHECK},
{"mavxscalar", required_argument, NULL, OPTION_MAVXSCALAR},
+ {"madd-bnd-prefix", no_argument, NULL, OPTION_MADD_BND_PREFIX},
{NULL, no_argument, NULL, 0}
};
size_t md_longopts_size = sizeof (md_longopts);
case OPTION_MSSE_CHECK:
if (strcasecmp (arg, "error") == 0)
- sse_check = sse_check_error;
+ sse_check = check_error;
else if (strcasecmp (arg, "warning") == 0)
- sse_check = sse_check_warning;
+ sse_check = check_warning;
else if (strcasecmp (arg, "none") == 0)
- sse_check = sse_check_none;
+ sse_check = check_none;
else
as_fatal (_("invalid -msse-check= option: `%s'"), arg);
break;
+ case OPTION_MOPERAND_CHECK:
+ if (strcasecmp (arg, "error") == 0)
+ operand_check = check_error;
+ else if (strcasecmp (arg, "warning") == 0)
+ operand_check = check_warning;
+ else if (strcasecmp (arg, "none") == 0)
+ operand_check = check_none;
+ else
+ as_fatal (_("invalid -moperand-check= option: `%s'"), arg);
+ break;
+
case OPTION_MAVXSCALAR:
if (strcasecmp (arg, "128") == 0)
avxscalar = vex128;
as_fatal (_("invalid -mavxscalar= option: `%s'"), arg);
break;
+ case OPTION_MADD_BND_PREFIX:
+ add_bnd_prefix = 1;
+ break;
+
default:
return 0;
}
-msse-check=[none|error|warning]\n\
check SSE instructions\n"));
fprintf (stream, _("\
+ -moperand-check=[none|error|warning]\n\
+ check operand combinations for validity\n"));
+ fprintf (stream, _("\
-mavxscalar=[128|256] encode scalar AVX instructions with specific vector\n\
length\n"));
fprintf (stream, _("\
-mnaked-reg don't require `%%' prefix for registers\n"));
fprintf (stream, _("\
-mold-gcc support old (<= 2.8.1) versions of gcc\n"));
+ fprintf (stream, _("\
+ -madd-bnd-prefix add BND prefix for all valid branches\n"));
}
#if ((defined (OBJ_MAYBE_COFF) && defined (OBJ_MAYBE_AOUT)) \
switch (fixp->fx_r_type)
{
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+ case BFD_RELOC_SIZE32:
+ case BFD_RELOC_SIZE64:
+ if (S_IS_DEFINED (fixp->fx_addsy)
+ && !S_IS_EXTERNAL (fixp->fx_addsy))
+ {
+ /* Resolve size relocation against local symbol to size of
+ the symbol plus addend. */
+ valueT value = S_GET_SIZE (fixp->fx_addsy) + fixp->fx_offset;
+ if (fixp->fx_r_type == BFD_RELOC_SIZE32
+ && !fits_in_unsigned_long (value))
+ as_bad_where (fixp->fx_file, fixp->fx_line,
+ _("symbol size computation overflow"));
+ fixp->fx_addsy = NULL;
+ fixp->fx_subsy = NULL;
+ md_apply_fix (fixp, (valueT *) &value, NULL);
+ return NULL;
+ }
+#endif
+
case BFD_RELOC_X86_64_PLT32:
case BFD_RELOC_X86_64_GOT32:
case BFD_RELOC_X86_64_GOTPCREL:
if (disallow_64bit_reloc)
switch (code)
{
- case BFD_RELOC_64:
- /* Check addend overflow. */
- if (!fits_in_signed_long (fixp->fx_offset))
- {
- long long addend = fixp->fx_offset;
- if (addend < 0)
- as_bad_where (fixp->fx_file, fixp->fx_line,
- _("cannot represent relocation %s with "
- "addend -0x%llx in x32 mode"),
- bfd_get_reloc_code_name (code), -addend);
- else
- as_bad_where (fixp->fx_file, fixp->fx_line,
- _("cannot represent relocation %s with "
- "addend 0x%llx in x32 mode"),
- bfd_get_reloc_code_name (code), addend);
- }
- break;
case BFD_RELOC_X86_64_DTPOFF64:
case BFD_RELOC_X86_64_TPOFF64:
case BFD_RELOC_64_PCREL: