#ifdef TE_PE
static void pe_directive_secrel PARAMS ((int));
#endif
+static void signed_cons PARAMS ((int));
static char *output_invalid PARAMS ((int c));
static int i386_operand PARAMS ((char *operand_string));
static int i386_intel_operand PARAMS ((char *operand_string, int got_a_float));
#if (defined (TE_I386AIX) \
|| ((defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) \
+ && !defined (TE_GNU) \
&& !defined (TE_LINUX) \
&& !defined (TE_NETWARE) \
&& !defined (TE_FreeBSD) \
&& !defined (TE_NetBSD)))
/* This array holds the chars that always start a comment. If the
- pre-processor is disabled, these aren't very useful. */
-const char comment_chars[] = "#/";
+ pre-processor is disabled, these aren't very useful. The option
+ --divide will remove '/' from this list. */
+const char *i386_comment_chars = "#/";
+#define SVR4_COMMENT_CHARS 1
#define PREFIX_SEPARATOR '\\'
+#else
+const char *i386_comment_chars = "#";
+#define PREFIX_SEPARATOR '/'
+#endif
+
/* This array holds the chars that only start a comment at the beginning of
a line. If the line seems to have the form '# 123 filename'
.line and .file directives will appear in the pre-processed output.
#NO_APP at the beginning of its output.
Also note that comments started like this one will always work if
'/' isn't otherwise defined. */
-const char line_comment_chars[] = "#";
-
-#else
-/* Putting '/' here makes it impossible to use the divide operator.
- However, we need it for compatibility with SVR4 systems. */
-const char comment_chars[] = "#";
-#define PREFIX_SEPARATOR '/'
-
-const char line_comment_chars[] = "/#";
-#endif
+const char line_comment_chars[] = "#/";
const char line_separator_chars[] = ";";
{"dfloat", float_cons, 'd'},
{"tfloat", float_cons, 'x'},
{"value", cons, 2},
+ {"slong", signed_cons, 4},
{"noopt", s_ignore, 0},
{"optim", s_ignore, 0},
{"code16gcc", set_16bit_gcc_code_flag, CODE_16BIT},
default:
break;
}
+
+ /* Sign-checking 4-byte relocations in 16-/32-bit code is pointless. */
+ if (size == 4 && flag_code != CODE_64BIT)
+ sign = -1;
+
reloc = bfd_reloc_type_lookup (stdoutput, other);
if (!reloc)
as_bad (_("unknown relocation (%u)"), other);
}
}
\f
+/* x86_cons_fix_new is called via the expression parsing code when a
+ reloc is needed. We use this hook to get the correct .got reloc. */
+static enum bfd_reloc_code_real got_reloc = NO_RELOC;
+static int cons_sign = -1;
+
+void
+x86_cons_fix_new (fragS *frag,
+ unsigned int off,
+ unsigned int len,
+ expressionS *exp)
+{
+ enum bfd_reloc_code_real r = reloc (len, 0, cons_sign, got_reloc);
+
+ got_reloc = NO_RELOC;
+
+#ifdef TE_PE
+ if (exp->X_op == O_secrel)
+ {
+ exp->X_op = O_symbol;
+ r = BFD_RELOC_32_SECREL;
+ }
+#endif
+
+ fix_new_exp (frag, off, len, exp, 0, r);
+}
+
#if (!defined (OBJ_ELF) && !defined (OBJ_MAYBE_ELF)) || defined (LEX_AT)
# define lex_got(reloc, adjust, types) NULL
#else
return NULL;
}
-/* x86_cons_fix_new is called via the expression parsing code when a
- reloc is needed. We use this hook to get the correct .got reloc. */
-static enum bfd_reloc_code_real got_reloc = NO_RELOC;
-
-void
-x86_cons_fix_new (frag, off, len, exp)
- fragS *frag;
- unsigned int off;
- unsigned int len;
- expressionS *exp;
-{
- enum bfd_reloc_code_real r = reloc (len, 0, -1, got_reloc);
- got_reloc = NO_RELOC;
- fix_new_exp (frag, off, len, exp, 0, r);
-}
-
void
x86_cons (exp, size)
expressionS *exp;
}
#endif
-#ifdef TE_PE
-
-void
-x86_pe_cons_fix_new (frag, off, len, exp)
- fragS *frag;
- unsigned int off;
- unsigned int len;
- expressionS *exp;
+static void signed_cons (int size)
{
- enum bfd_reloc_code_real r = reloc (len, 0, -1, NO_RELOC);
-
- if (exp->X_op == O_secrel)
- {
- exp->X_op = O_symbol;
- r = BFD_RELOC_32_SECREL;
- }
-
- fix_new_exp (frag, off, len, exp, 0, r);
+ if (flag_code == CODE_64BIT)
+ cons_sign = 1;
+ cons (size);
+ cons_sign = -1;
}
+#ifdef TE_PE
static void
pe_directive_secrel (dummy)
int dummy ATTRIBUTE_UNUSED;
input_line_pointer--;
demand_empty_rest_of_line ();
}
-
#endif
static int i386_immediate PARAMS ((char *));
segT exp_seg = 0;
char *save_input_line_pointer;
char *gotfree_input_line;
- int bigdisp = Disp32;
+ int bigdisp, override;
unsigned int types = Disp;
+ if ((i.types[this_operand] & JumpAbsolute)
+ || !(current_templates->start->opcode_modifier & (Jump | JumpDword)))
+ {
+ bigdisp = Disp32;
+ override = (i.prefix[ADDR_PREFIX] != 0);
+ }
+ else
+ {
+ /* For PC-relative branches, the width of the displacement
+ is dependent upon data size, not address size. */
+ bigdisp = 0;
+ override = (i.prefix[DATA_PREFIX] != 0);
+ }
if (flag_code == CODE_64BIT)
{
- if (i.prefix[ADDR_PREFIX] == 0)
+ if (!bigdisp)
+ bigdisp = (override || i.suffix == WORD_MNEM_SUFFIX)
+ ? Disp16
+ : Disp32S | Disp32;
+ else if (!override)
bigdisp = Disp64 | Disp32S | Disp32;
}
- else if ((flag_code == CODE_16BIT) ^ (i.prefix[ADDR_PREFIX] != 0))
- bigdisp = Disp16;
+ else
+ {
+ if (!bigdisp)
+ {
+ if (!override)
+ override = (i.suffix == (flag_code != CODE_16BIT
+ ? WORD_MNEM_SUFFIX
+ : LONG_MNEM_SUFFIX));
+ bigdisp = Disp32;
+ }
+ if ((flag_code == CODE_16BIT) ^ override)
+ bigdisp = Disp16;
+ }
i.types[this_operand] |= bigdisp;
exp = &disp_expressions[i.disp_operands];
}
/* Check if operand is a register. */
- if ((*op_string == REGISTER_PREFIX || allow_naked_reg)
- && (r = parse_register (op_string, &end_op)) != NULL)
+ if ((r = parse_register (op_string, &end_op)) != NULL)
{
/* Check for a segment override by searching for ':' after a
segment register. */
++base_string;
if (*base_string == ','
- || ((*base_string == REGISTER_PREFIX || allow_naked_reg)
- && (i.base_reg = parse_register (base_string, &end_op)) != NULL))
+ || ((i.base_reg = parse_register (base_string, &end_op)) != NULL))
{
displacement_string_end = temp_string;
if (is_space_char (*base_string))
++base_string;
- if ((*base_string == REGISTER_PREFIX || allow_naked_reg)
- && (i.index_reg = parse_register (base_string, &end_op)) != NULL)
+ if ((i.index_reg = parse_register (base_string, &end_op)) != NULL)
{
base_string = end_op;
if (is_space_char (*base_string))
/* REG_STRING starts *before* REGISTER_PREFIX. */
static const reg_entry *
-parse_register (reg_string, end_op)
- char *reg_string;
- char **end_op;
+parse_real_register (char *reg_string, char **end_op)
{
char *s = reg_string;
char *p;
return r;
}
+
+/* REG_STRING starts *before* REGISTER_PREFIX. */
+
+static const reg_entry *
+parse_register (char *reg_string, char **end_op)
+{
+ const reg_entry *r;
+
+ if (*reg_string == REGISTER_PREFIX || allow_naked_reg)
+ r = parse_real_register (reg_string, end_op);
+ else
+ r = NULL;
+ if (!r)
+ {
+ char *save = input_line_pointer;
+ char c;
+ symbolS *symbolP;
+
+ input_line_pointer = reg_string;
+ c = get_symbol_end ();
+ symbolP = symbol_find (reg_string);
+ if (symbolP && S_GET_SEGMENT (symbolP) == reg_section)
+ {
+ const expressionS *e = symbol_get_value_expression (symbolP);
+
+ know (e->X_op == O_register);
+ know (e->X_add_number >= 0 && (valueT) e->X_add_number < ARRAY_SIZE (i386_regtab));
+ r = i386_regtab + e->X_add_number;
+ *end_op = input_line_pointer;
+ }
+ *input_line_pointer = c;
+ input_line_pointer = save;
+ }
+ return r;
+}
+
+int
+i386_parse_name (char *name, expressionS *e, char *nextcharP)
+{
+ const reg_entry *r;
+ char *end = input_line_pointer;
+
+ *end = *nextcharP;
+ r = parse_register (name, &input_line_pointer);
+ if (r && end <= input_line_pointer)
+ {
+ *nextcharP = *input_line_pointer;
+ *input_line_pointer = 0;
+ e->X_op = O_register;
+ e->X_add_number = r - i386_regtab;
+ return 1;
+ }
+ input_line_pointer = end;
+ *end = 0;
+ return 0;
+}
+
+void
+md_operand (expressionS *e)
+{
+ if (*input_line_pointer == REGISTER_PREFIX)
+ {
+ char *end;
+ const reg_entry *r = parse_real_register (input_line_pointer, &end);
+
+ if (r)
+ {
+ e->X_op = O_register;
+ e->X_add_number = r - i386_regtab;
+ input_line_pointer = end;
+ }
+ }
+}
+
\f
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
const char *md_shortopts = "kVQ:sqn";
const char *md_shortopts = "qn";
#endif
-struct option md_longopts[] = {
#define OPTION_32 (OPTION_MD_BASE + 0)
+#define OPTION_64 (OPTION_MD_BASE + 1)
+#define OPTION_DIVIDE (OPTION_MD_BASE + 2)
+
+struct option md_longopts[] = {
{"32", no_argument, NULL, OPTION_32},
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
-#define OPTION_64 (OPTION_MD_BASE + 1)
{"64", no_argument, NULL, OPTION_64},
#endif
+ {"divide", no_argument, NULL, OPTION_DIVIDE},
{NULL, no_argument, NULL, 0}
};
size_t md_longopts_size = sizeof (md_longopts);
default_arch = "i386";
break;
+ case OPTION_DIVIDE:
+#ifdef SVR4_COMMENT_CHARS
+ {
+ char *n, *t;
+ const char *s;
+
+ n = (char *) xmalloc (strlen (i386_comment_chars) + 1);
+ t = n;
+ for (s = i386_comment_chars; *s != '\0'; s++)
+ if (*s != '/')
+ *t++ = *s;
+ *t = '\0';
+ i386_comment_chars = n;
+ }
+#endif
+ break;
+
default:
return 0;
}
fprintf (stream, _("\
-Q ignored\n\
-V print assembler version number\n\
- -k ignored\n\
+ -k ignored\n"));
+#endif
+ fprintf (stream, _("\
-n Do not optimize code alignment\n\
- -q quieten some warnings\n\
+ -q quieten some warnings\n"));
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+ fprintf (stream, _("\
-s ignored\n"));
+#endif
+#ifdef SVR4_COMMENT_CHARS
+ fprintf (stream, _("\
+ --divide do not treat `/' as a comment character\n"));
#else
fprintf (stream, _("\
- -n Do not optimize code alignment\n\
- -q quieten some warnings\n"));
+ --divide ignored\n"));
#endif
}
break;
}
- if ((code == BFD_RELOC_32 || code == BFD_RELOC_32_PCREL)
+ if ((code == BFD_RELOC_32
+ || code == BFD_RELOC_32_PCREL
+ || code == BFD_RELOC_X86_64_32S)
&& GOT_symbol
&& fixp->fx_addsy == GOT_symbol)
{
/* No scaling. If this is a memory operand, the register is either a
base register (first occurrence) or an index register (second
occurrence). */
- else if (intel_parser.in_bracket && !(reg->reg_type & (SReg2 | SReg3)))
+ else if (intel_parser.in_bracket)
{
if (!i.base_reg)
i.types[this_operand] |= BaseIndex;
}
- /* Offset modifier. Add the register to the displacement string to be
- parsed as an immediate expression after we're done. */
- else if (intel_parser.in_offset)
- {
- as_warn (_("Using register names in OFFSET expressions is deprecated"));
- strcat (intel_parser.disp, reg->reg_name);
- }
-
- /* It's neither base nor index nor offset. */
- else if (!intel_parser.is_mem)
+ /* It's neither base nor index. */
+ else if (!intel_parser.in_offset && !intel_parser.is_mem)
{
i.types[this_operand] |= reg->reg_type & ~BaseIndex;
i.op[this_operand].regs = reg;
new_token.code = T_ID;
}
- else if ((*intel_parser.op_string == REGISTER_PREFIX || allow_naked_reg)
- && ((reg = parse_register (intel_parser.op_string, &end_op)) != NULL))
+ else if ((reg = parse_register (intel_parser.op_string, &end_op)) != NULL)
{
+ size_t len = end_op - intel_parser.op_string;
+
new_token.code = T_REG;
new_token.reg = reg;
- if (*intel_parser.op_string == REGISTER_PREFIX)
- {
- new_token.str[0] = REGISTER_PREFIX;
- new_token.str[1] = '\0';
- }
-
- strcat (new_token.str, reg->reg_name);
+ memcpy (new_token.str, intel_parser.op_string, len);
+ new_token.str[len] = '\0';
}
else if (is_identifier_char (*intel_parser.op_string))