#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "as.h"
#include "struc-symbol.h"
#include "flonum.h"
#include "expr.h"
#include "read.h"
#include "obstack.h"
#include "frags.h"
#include "symbols.h"
#include "fixes.h"
#include "md.h"
#include "xmalloc.h"
#include "messages.h"
#include "i386.h"
#include "i386-opcode.h"
#include "sections.h"
#include "input-scrub.h"
const cpu_type_t md_cputype = CPU_TYPE_I386;
cpu_subtype_t md_cpusubtype = CPU_SUBTYPE_I386_ALL;
const enum byte_sex md_target_byte_sex = LITTLE_ENDIAN_BYTE_SEX;
const char md_FLT_CHARS[] = "fFdDxX";
const char md_EXP_CHARS[] = "eE";
const char md_line_comment_chars[] = "#";
const char md_comment_chars[] = "#";
static char opcode_chars[256];
static char register_chars[256];
static char operand_chars[256];
static char space_chars[256];
static char identifier_chars[256];
static char digit_chars[256];
#define is_opcode_char(x) (opcode_chars[(unsigned char) x])
#define is_operand_char(x) (operand_chars[(unsigned char) x])
#define is_register_char(x) (register_chars[(unsigned char) x])
#define is_space_char(x) (space_chars[(unsigned char) x])
#define is_identifier_char(x) (identifier_chars[(unsigned char) x])
#define is_digit_char(x) (digit_chars[(unsigned char) x])
#ifdef NeXT_MOD
static char operand_special_chars[] = "%$-+(,)*._~/<>|&^!:\"";
#else
static char operand_special_chars[] = "%$-+(,)*._~/<>|&^!:";
#endif
static char *ordinal_names[] = { "first", "second", "third" };
static char save_stack[32];
static char *save_stack_p;
#define END_STRING_AND_SAVE(s) *save_stack_p++ = *s; *s = '\0'
#define RESTORE_END_STRING(s) *s = *--save_stack_p
static i386_insn i;
static expressionS disp_expressions[2], im_expressions[2];
static reg_entry *ebp, *esp;
static int this_operand;
#define COND_JUMP 1
#define UNCOND_JUMP 2
#define BYTE 0
#define WORD 1
#define DWORD 2
#define UNKNOWN_SIZE 3
#define ENCODE_RELAX_STATE(type,size) ((type<<2) | (size))
#define SIZE_FROM_RELAX_STATE(s) \
( (((s) & 0x3) == BYTE ? 1 : (((s) & 0x3) == WORD ? 2 : 4)) )
const relax_typeS md_relax_table[] = {
{1, 1, 0, 0},
{1, 1, 0, 0},
{1, 1, 0, 0},
{1, 1, 0, 0},
{127+1, -128+1, 0, ENCODE_RELAX_STATE(COND_JUMP,DWORD) },
{32767+2, -32768+2, 3, ENCODE_RELAX_STATE(COND_JUMP,DWORD) },
{0, 0, 4, 0},
{1, 1, 0, 0},
{127+1, -128+1, 0, ENCODE_RELAX_STATE(UNCOND_JUMP,DWORD) },
{32767+2, -32768+2, 2, ENCODE_RELAX_STATE(UNCOND_JUMP,DWORD) },
{0, 0, 3, 0},
{1, 1, 0, 0},
};
static
void
dummy(
int value)
{
while (*input_line_pointer && *input_line_pointer != '\n')
input_line_pointer++;
}
const pseudo_typeS md_pseudo_table[] = {
{ "ffloat", float_cons, 'f' },
{ "dfloat", float_cons, 'd' },
{ "tfloat", float_cons, 'x' },
{ "value", cons, 2 },
{ "word", cons, 2 },
{ "ident", dummy, 0 },
{ "def", dummy, 0 },
{ "optim", dummy, 0 },
{ "version", dummy, 0 },
{ "ln", dummy, 0 },
{ 0, 0, 0 }
};
static int i386_operand(
char *operand_string);
static char *output_invalid(
char c);
static reg_entry *parse_register(
char *reg_string);
#ifdef NeXT_MOD
static int is_local_symbol(
struct symbol *sym);
static int add_seg_prefix(
int seg_prefix);
#endif
static struct obstack o;
static struct hash_control *op_hash = (struct hash_control *) 0;
static struct hash_control *reg_hash = (struct hash_control *) 0;
static struct hash_control *prefix_hash = (struct hash_control *) 0;
void
md_begin(
void)
{
char * hash_err;
obstack_begin (&o,4096);
op_hash = hash_new();
{
register const template *optab;
register templates *core_optab;
char *prev_name;
optab = i386_optab;
prev_name = optab->name;
obstack_grow (&o, optab, sizeof(template));
core_optab = (templates *) xmalloc (sizeof (templates));
for (optab++; optab < i386_optab_end; optab++) {
if (! strcmp (optab->name, prev_name)) {
obstack_grow (&o, optab, sizeof(template));
} else {
core_optab->end = (template *) obstack_next_free(&o);
core_optab->start = (template *) obstack_finish(&o);
hash_err = hash_insert (op_hash, prev_name, (char *) core_optab);
if (hash_err && *hash_err) {
hash_error:
as_fatal("Internal Error: Can't hash %s: %s",prev_name, hash_err);
}
prev_name = optab->name;
core_optab = (templates *) xmalloc (sizeof(templates));
obstack_grow (&o, optab, sizeof(template));
}
}
}
reg_hash = hash_new();
{
register const reg_entry *regtab;
for (regtab = i386_regtab; regtab < i386_regtab_end; regtab++) {
hash_err = hash_insert (reg_hash, regtab->reg_name, (char *)regtab);
if (hash_err && *hash_err) goto hash_error;
}
}
esp = (reg_entry *) hash_find (reg_hash, "esp");
ebp = (reg_entry *) hash_find (reg_hash, "ebp");
prefix_hash = hash_new();
{
register const prefix_entry *prefixtab;
for (prefixtab = i386_prefixtab;
prefixtab < i386_prefixtab_end; prefixtab++) {
hash_err = hash_insert (prefix_hash, prefixtab->prefix_name, (char *)prefixtab);
if (hash_err && *hash_err) goto hash_error;
}
}
{
register unsigned int c;
memset(opcode_chars, '\0', sizeof(opcode_chars));
memset(operand_chars, '\0', sizeof(operand_chars));
memset(space_chars, '\0', sizeof(space_chars));
memset(identifier_chars, '\0', sizeof(identifier_chars));
memset(digit_chars, '\0', sizeof(digit_chars));
for (c = 0; c < 256; c++) {
if (islower(c) || isdigit(c)) {
opcode_chars[c] = c;
register_chars[c] = c;
} else if (isupper(c)) {
opcode_chars[c] = tolower(c);
register_chars[c] = opcode_chars[c];
} else if (c == PREFIX_SEPERATOR) {
opcode_chars[c] = c;
} else if (c == ')' || c == '(') {
register_chars[c] = c;
}
if (isupper(c) || islower(c) || isdigit(c))
operand_chars[c] = c;
else if (c && strchr(operand_special_chars, c))
operand_chars[c] = c;
if (isdigit(c) || c == '-') digit_chars[c] = c;
if (isalpha(c) || c == '_' || c == '.' || isdigit(c))
identifier_chars[c] = c;
if (c == ' ' || c == '\t') space_chars[c] = c;
}
}
}
void
md_end(
void)
{}
#ifdef DEBUG386
static void pi(
char *line,
i386_insn *x);
static void pte(
template *t);
static void pe(
expressionS *e);
static void ps(
symbolS *s);
static void pt(
uint t);
static
void
pi(
char *line,
i386_insn *x)
{
register template *p;
int i;
fprintf (stdout, "%s: template ", line);
pte (&x->tm);
fprintf (stdout, " modrm: mode %x reg %x reg/mem %x",
x->rm.mode, x->rm.reg, x->rm.regmem);
fprintf (stdout, " base %x index %x scale %x\n",
x->bi.base, x->bi.index, x->bi.scale);
for (i = 0; i < x->operands; i++) {
fprintf (stdout, " #%d: ", i+1);
pt (x->types[i]);
fprintf (stdout, "\n");
if (x->types[i] & Reg) fprintf (stdout, "%s\n", x->regs[i]->reg_name);
if (x->types[i] & Imm) pe (x->imms[i]);
if (x->types[i] & (Disp|Abs)) pe (x->disps[i]);
}
}
static
void
pte(
template *t)
{
int i;
fprintf (stdout, " %d operands ", t->operands);
fprintf (stdout, "opcode %x ",
t->base_opcode);
if (t->extension_opcode != None)
fprintf (stdout, "ext %x ", t->extension_opcode);
if (t->opcode_modifier&D)
fprintf (stdout, "D");
if (t->opcode_modifier&W)
fprintf (stdout, "W");
fprintf (stdout, "\n");
for (i = 0; i < t->operands; i++) {
fprintf (stdout, " #%d type ", i+1);
pt (t->operand_types[i]);
fprintf (stdout, "\n");
}
}
static char *seg_names[] = {
"SEG_ABSOLUTE", "SEG_TEXT", "SEG_DATA", "SEG_BSS", "SEG_UNKNOWN",
"SEG_NONE", "SEG_PASS1", "SEG_GOOF", "SEG_BIG", "SEG_DIFFERENCE" };
static
void
pe(
expressionS *e)
{
fprintf (stdout, " segment %s\n", seg_names[(int) e->X_seg]);
fprintf (stdout, " add_number %d (%x)\n",
e->X_add_number, e->X_add_number);
if (e->X_add_symbol) {
fprintf (stdout, " add_symbol ");
ps (e->X_add_symbol);
fprintf (stdout, "\n");
}
if (e->X_subtract_symbol) {
fprintf (stdout, " sub_symbol ");
ps (e->X_subtract_symbol);
fprintf (stdout, "\n");
}
}
#define SYMBOL_TYPE(t) \
(((t&N_TYPE) == N_UNDF) ? "UNDEFINED" : \
(((t&N_TYPE) == N_ABS) ? "ABSOLUTE" : \
(((t&N_TYPE) == N_TEXT) ? "TEXT" : \
(((t&N_TYPE) == N_DATA) ? "DATA" : \
(((t&N_TYPE) == N_BSS) ? "BSS" : "Bad n_type!")))))
static
void
ps(
symbolS *s)
{
fprintf (stdout, "%s type %s%s",
s->sy_nlist.n_un.n_name,
(s->sy_nlist.n_type&N_EXT) ? "EXTERNAL " : "",
SYMBOL_TYPE (s->sy_nlist.n_type));
}
static struct type_name {
uint mask;
char *tname;
} type_names[] = {
{ Reg8, "r8" }, { Reg16, "r16" }, { Reg32, "r32" }, { Imm8, "i8" },
{ Imm8S, "i8s" },
{ Imm16, "i16" }, { Imm32, "i32" }, { Mem8, "Mem8"}, { Mem16, "Mem16"},
{ Mem32, "Mem32"}, { BaseIndex, "BaseIndex" },
{ Abs8, "Abs8" }, { Abs16, "Abs16" }, { Abs32, "Abs32" },
{ Disp8, "d8" }, { Disp16, "d16" },
{ Disp32, "d32" }, { SReg2, "SReg2" }, { SReg3, "SReg3" }, { Acc, "Acc" },
{ InOutPortReg, "InOutPortReg" }, { ShiftCount, "ShiftCount" },
{ Imm1, "i1" }, { Control, "control reg" }, {Test, "test reg"},
{ FloatReg, "FReg"}, {FloatAcc, "FAcc"},
{ JumpAbsolute, "Jump Absolute"},
{ 0, "" }
};
static
void
pt(
uint t)
{
register struct type_name *ty;
if (t == Unknown) {
fprintf (stdout, "Unknown");
} else {
for (ty = type_names; ty->mask; ty++)
if (t & ty->mask) fprintf (stdout, "%s, ", ty->tname);
}
fflush (stdout);
}
#endif
void
md_assemble(
char *line)
{
register template * t;
templates *current_templates = (templates *) 0;
memset(&i, '\0', sizeof(i));
memset(disp_expressions, '\0', sizeof(disp_expressions));
memset(im_expressions, '\0', sizeof(im_expressions));
save_stack_p = save_stack;
{
register char *l = line;
uint expecting_operand = 0;
uint expecting_string_instruction = 0;
uint paren_not_balenced;
char * token_start = l;
while (! is_space_char(*l) && *l != END_OF_INSN) {
if (! is_opcode_char(*l)) {
as_bad ("invalid character %s in opcode", output_invalid(*l));
return;
} else if (*l != PREFIX_SEPERATOR) {
*l = opcode_chars[(unsigned char) *l];
l++;
} else {
register int q;
register prefix_entry * prefix;
if (l == token_start) {
as_bad ("expecting prefix; got nothing");
return;
}
END_STRING_AND_SAVE (l);
prefix = (prefix_entry *) hash_find (prefix_hash, token_start);
if (! prefix) {
as_bad ("no such opcode prefix ('%s')", token_start);
return;
}
RESTORE_END_STRING (l);
for (q = 0; q < i.prefixes; q++)
if (i.prefix[q] == (char)prefix->prefix_code) {
as_bad ("same prefix used twice; you don't really want this!");
return;
}
if (i.prefixes == MAX_PREFIXES) {
as_bad ("too many opcode prefixes");
return;
}
i.prefix[i.prefixes++] = prefix->prefix_code;
if (prefix->prefix_code == REPE || prefix->prefix_code == REPNE)
expecting_string_instruction = TRUE;
token_start = ++l;
}
}
END_STRING_AND_SAVE (l);
if (token_start == l) {
as_bad ("expecting opcode; got nothing");
return;
}
current_templates = (templates *) hash_find (op_hash, token_start);
if (! current_templates) {
int last_index = strlen(token_start) - 1;
char last_char = token_start[last_index];
switch (last_char) {
case DWORD_OPCODE_SUFFIX:
case WORD_OPCODE_SUFFIX:
case BYTE_OPCODE_SUFFIX:
token_start[last_index] = '\0';
current_templates = (templates *) hash_find (op_hash, token_start);
token_start[last_index] = last_char;
i.suffix = last_char;
}
if (!current_templates) {
as_bad ("no such 386 instruction: `%s'", token_start); return;
}
}
RESTORE_END_STRING (l);
if (expecting_string_instruction &&
! IS_STRING_INSTRUCTION (current_templates->
start->base_opcode)) {
as_bad ("expecting string instruction after rep/repne");
return;
}
#ifdef NeXT_MOD
if (*l != END_OF_INSN)
#else
if (*l != END_OF_INSN &&
! IS_STRING_INSTRUCTION (current_templates->
start->base_opcode))
#endif
{
do {
while (! is_operand_char(*l) && *l != END_OF_INSN) {
if (! is_space_char(*l)) {
as_bad ("invalid character %s before %s operand",
output_invalid(*l),
ordinal_names[i.operands]);
return;
}
l++;
}
token_start = l;
paren_not_balenced = 0;
while (paren_not_balenced || *l != ',') {
if (*l == END_OF_INSN) {
if (paren_not_balenced) {
as_bad ("unbalenced parenthesis in %s operand.",
ordinal_names[i.operands]);
return;
} else break;
#ifdef NeXT_MOD
} else if (*l == '"') {
char *p = l;
l++;
while (*l != '"' && *l != END_OF_INSN) {
l++;
}
if (*l != '"')
as_bad ("invalid operand %s (missing ending \")", p);
#endif
} else if (! is_operand_char(*l)) {
as_bad ("invalid character %s in %s operand",
output_invalid(*l),
ordinal_names[i.operands]);
return;
}
if (*l == '(') ++paren_not_balenced;
if (*l == ')') --paren_not_balenced;
l++;
}
if (l != token_start) {
uint operand_ok;
this_operand = i.operands++;
if (i.operands > MAX_OPERANDS) {
as_bad ("spurious operands; (%d operands/instruction max)",
MAX_OPERANDS);
return;
}
END_STRING_AND_SAVE (l);
operand_ok = i386_operand (token_start);
RESTORE_END_STRING (l);
if (!operand_ok) return;
} else {
if (expecting_operand) {
expecting_operand_after_comma:
as_bad ("expecting operand after ','; got nothing");
return;
}
if (*l == ',') {
as_bad ("expecting operand before ','; got nothing");
return;
}
}
if (*l == ',') {
if (*++l == END_OF_INSN) {
goto expecting_operand_after_comma;
}
expecting_operand = TRUE;
}
} while (*l != END_OF_INSN);
}
}
#define MATCH(overlap,given_type) \
(overlap && \
(overlap & (JumpAbsolute|BaseIndex|Mem8)) \
== (given_type & (JumpAbsolute|BaseIndex|Mem8)))
#define CONSISTENT_REGISTER_MATCH(m0, m1, t0, t1) \
( ((m0 & (Reg)) && (m1 & (Reg))) ? \
( ((t0 & t1 & (Reg)) == 0 && (m0 & m1 & (Reg)) == 0) || \
((t0 & t1) & (m0 & m1) & (Reg)) \
) : 1)
{
register uint overlap0, overlap1;
expressionS * exp;
uint overlap2;
uint found_reverse_match;
overlap0 = overlap1 = overlap2 = found_reverse_match = 0;
for (t = current_templates->start;
t < current_templates->end;
t++) {
if (i.operands != t->operands) continue;
else if (!t->operands) break;
overlap0 = i.types[0] & t->operand_types[0];
switch (t->operands) {
case 1:
if (! MATCH (overlap0,i.types[0])) continue;
break;
case 2: case 3:
overlap1 = i.types[1] & t->operand_types[1];
if (! MATCH (overlap0,i.types[0]) ||
! MATCH (overlap1,i.types[1]) ||
! CONSISTENT_REGISTER_MATCH(overlap0, overlap1,
t->operand_types[0],
t->operand_types[1])) {
if (! (t->opcode_modifier & COMES_IN_BOTH_DIRECTIONS))
continue;
overlap0 = i.types[0] & t->operand_types[1];
overlap1 = i.types[1] & t->operand_types[0];
if (! MATCH (overlap0,i.types[0]) ||
! MATCH (overlap1,i.types[1]) ||
! CONSISTENT_REGISTER_MATCH (overlap0, overlap1,
t->operand_types[0],
t->operand_types[1])) {
continue;
}
found_reverse_match = t->opcode_modifier & COMES_IN_BOTH_DIRECTIONS;
}
if (t->operands == 3) {
overlap2 = i.types[2] & t->operand_types[2];
if (! MATCH (overlap2,i.types[2]) ||
! CONSISTENT_REGISTER_MATCH (overlap0, overlap2,
t->operand_types[0],
t->operand_types[2]) ||
! CONSISTENT_REGISTER_MATCH (overlap1, overlap2,
t->operand_types[1],
t->operand_types[2]))
continue;
}
}
break;
}
if (t == current_templates->end) {
#ifdef NeXT_MOD
string_instruction_bad_match:
#endif
as_bad ("operands given don't match any known 386 instruction");
return;
}
#ifdef NeXT_MOD
if(IS_STRING_INSTRUCTION((t->base_opcode)) && i.operands != 0){
if(i.operands == 2){
if(t->base_opcode == MOVS_OPCODE ||
t->base_opcode == CMPS_OPCODE){
if(i.base_reg != (reg_entry *)hash_find(reg_hash, "esi") ||
i.base_reg2nd != (reg_entry *)hash_find(reg_hash, "edi"))
goto string_instruction_bad_match;
if(i.seg2nd && i.seg2nd != &es)
goto string_instruction_bad_match;
if(i.seg)
if(add_seg_prefix(i.seg->seg_prefix))
return;
}
else if(t->base_opcode == LODS_OPCODE){
if(i.base_reg != (reg_entry *)hash_find(reg_hash, "esi"))
goto string_instruction_bad_match;
if(i.seg)
if(add_seg_prefix(i.seg->seg_prefix))
return;
}
else if(t->base_opcode == SCAS_OPCODE ||
t->base_opcode == STOS_OPCODE){
if(i.base_reg != (reg_entry *)hash_find(reg_hash, "edi"))
goto string_instruction_bad_match;
if(i.seg)
if(add_seg_prefix(i.seg->seg_prefix))
return;
}
if(i.index_reg || i.index_reg2nd)
goto string_instruction_bad_match;
if(i.disps[0]){
if(i.disps[0]->X_add_symbol || i.disps[0]->X_subtract_symbol ||
i.disps[0]->X_seg != SEG_ABSOLUTE || i.disps[0]->X_add_number != 0)
goto string_instruction_bad_match;
}
if(i.disps[1]){
if(i.disps[1]->X_add_symbol || i.disps[1]->X_subtract_symbol ||
i.disps[1]->X_seg != SEG_ABSOLUTE || i.disps[1]->X_add_number != 0)
goto string_instruction_bad_match;
}
}
i.seg = 0;
i.base_reg = 0;
i.base_reg2nd = 0;
i.disp_operands = 0;
i.disps[0] = 0;
i.disps[1] = 0;
}
#endif
#ifdef NeXT_MOD
if(t->cpus && !force_cpusubtype_ALL){
if(*(t->cpus) == '5'){
if(archflag_cpusubtype == CPU_SUBTYPE_486 ||
archflag_cpusubtype == CPU_SUBTYPE_486SX)
as_bad("pentium instruction not allowed with -arch i486 or "
"-arch i486SX");
md_cpusubtype = CPU_SUBTYPE_PENT;
}
else if(*(t->cpus) == '4' &&
(md_cpusubtype != CPU_SUBTYPE_PENT &&
md_cpusubtype != CPU_SUBTYPE_PENTPRO &&
md_cpusubtype != CPU_SUBTYPE_PENTII_M3 &&
md_cpusubtype != CPU_SUBTYPE_PENTII_M5))
if(md_cpusubtype != CPU_SUBTYPE_486SX)
md_cpusubtype = CPU_SUBTYPE_486;
}
#endif
memcpy(&i.tm, t, sizeof (template));
t = &i.tm;
if (! i.suffix && i.reg_operands) {
int o;
for (o = 0; o < MAX_OPERANDS; o++)
if (i.types[o] & Reg) {
#ifdef NeXT_MOD
i.suffix = ((i.types[o] & Reg) == Reg8) ? BYTE_OPCODE_SUFFIX :
((i.types[o] & Reg) == Reg16) ? WORD_OPCODE_SUFFIX :
DWORD_OPCODE_SUFFIX;
#else
i.suffix = (i.types[o] == Reg8) ? BYTE_OPCODE_SUFFIX :
(i.types[o] == Reg16) ? WORD_OPCODE_SUFFIX :
DWORD_OPCODE_SUFFIX;
#endif
}
}
#ifdef NeXT_MOD
if(overlap0 & (Imm8|Imm8S|Imm16|Imm32)){
if(i.suffix == BYTE_OPCODE_SUFFIX && (overlap0 & (Imm8|Imm8S)) == 0)
overlap0 = Imm8|Imm8S;
else if(i.suffix == WORD_OPCODE_SUFFIX &&
(overlap0 & (Imm16|Imm8|Imm8S)) == 0)
overlap0 = Imm16;
}
#endif
if ((overlap0 & (Imm8|Imm8S|Imm16|Imm32))
&& overlap0 != Imm8 && overlap0 != Imm8S
&& overlap0 != Imm16 && overlap0 != Imm32) {
if (! i.suffix) {
as_bad ("no opcode suffix given; can't determine immediate size");
return;
}
overlap0 &= (i.suffix == BYTE_OPCODE_SUFFIX ? (Imm8|Imm8S) :
(i.suffix == WORD_OPCODE_SUFFIX ? Imm16 : Imm32));
}
#ifdef NeXT_MOD
if(overlap1 & (Imm8|Imm8S|Imm16|Imm32)){
if(i.suffix == BYTE_OPCODE_SUFFIX && (overlap1 & (Imm8|Imm8S)) == 0)
overlap1 = Imm8|Imm8S;
else if(i.suffix == WORD_OPCODE_SUFFIX &&
(overlap0 & (Imm16|Imm8|Imm8S)) == 0)
overlap1 = Imm16;
}
#endif
if ((overlap1 & (Imm8|Imm8S|Imm16|Imm32))
&& overlap1 != Imm8 && overlap1 != Imm8S
&& overlap1 != Imm16 && overlap1 != Imm32) {
if (! i.suffix) {
as_bad ("no opcode suffix given; can't determine immediate size");
return;
}
overlap1 &= (i.suffix == BYTE_OPCODE_SUFFIX ? (Imm8|Imm8S) :
(i.suffix == WORD_OPCODE_SUFFIX ? Imm16 : Imm32));
}
i.types[0] = overlap0;
i.types[1] = overlap1;
i.types[2] = overlap2;
if (overlap0 & ImplicitRegister) i.reg_operands--;
if (overlap1 & ImplicitRegister) i.reg_operands--;
if (overlap2 & ImplicitRegister) i.reg_operands--;
if (overlap0 & Imm1) i.imm_operands = 0;
if (found_reverse_match) {
uint save;
save = t->operand_types[0];
t->operand_types[0] = t->operand_types[1];
t->operand_types[1] = save;
}
if (! i.suffix && (t->opcode_modifier & W)) {
as_bad ("no opcode suffix given and no register operands; can't size instruction");
return;
}
if (i.suffix && i.suffix != BYTE_OPCODE_SUFFIX) {
if (t->opcode_modifier & W)
t->base_opcode |= W;
if (i.suffix == WORD_OPCODE_SUFFIX) {
if (i.prefixes == MAX_PREFIXES) {
as_bad ("%d prefixes given and 'w' opcode suffix gives too many prefixes",
MAX_PREFIXES);
return;
}
i.prefix[i.prefixes++] = WORD_PREFIX_OPCODE;
}
}
if (i.operands) {
if (found_reverse_match) {
t->base_opcode |= found_reverse_match;
}
#if defined(i486) || defined (i586)
if (t->base_opcode == BSWAP_OPCODE) {
t->base_opcode |= i.regs[0]->reg_num;
}
#endif
if (t->opcode_modifier & imulKludge) {
i.regs[2] = i.regs[1];
i.reg_operands = 2;
}
if ((t->opcode_modifier & ReverseRegRegmem) && i.reg_operands == 2) {
uint first_reg_operand = (i.types[0] & Reg) ? 0 : 1;
uint second_reg_operand = first_reg_operand + 1;
reg_entry *tmp = i.regs[first_reg_operand];
i.regs[first_reg_operand] = i.regs[second_reg_operand];
i.regs[second_reg_operand] = tmp;
}
if (t->opcode_modifier & ShortForm) {
uint o = (i.types[0] & (Reg|FloatReg)) ? 0 : 1;
t->base_opcode |= i.regs[o]->reg_num;
} else if (t->opcode_modifier & ShortFormW) {
t->base_opcode |= i.regs[1]->reg_num;
if (i.suffix == WORD_OPCODE_SUFFIX ||
i.suffix == DWORD_OPCODE_SUFFIX)
t->base_opcode |= 0x8;
} else if (t->opcode_modifier & Seg2ShortForm) {
if (t->base_opcode == POP_SEG_SHORT && i.regs[0]->reg_num == 1) {
as_bad ("you can't 'pop cs' on the 386.");
return;
}
t->base_opcode |= (i.regs[0]->reg_num << 3);
} else if (t->opcode_modifier & Seg3ShortForm) {
if (i.regs[0]->reg_num == 5)
t->base_opcode |= 0x08;
} else if (t->opcode_modifier & Modrm) {
if (i.reg_operands == 2) {
uint source, dest;
source = (i.types[0] & (Reg|SReg2|SReg3|Control|Debug|Test)) ? 0 : 1;
dest = source + 1;
i.rm.mode = 3;
if (i.regs[dest]->reg_type & (SReg2|SReg3|Control|Debug|Test)) {
i.rm.reg = i.regs[dest]->reg_num;
i.rm.regmem = i.regs[source]->reg_num;
} else {
i.rm.reg = i.regs[source]->reg_num;
i.rm.regmem = i.regs[dest]->reg_num;
}
} else {
if (i.mem_operands) {
uint fake_zero_displacement = FALSE;
uint o = (i.types[0] & Mem) ? 0 : ((i.types[1] & Mem) ? 1 : 2);
if (i.base_reg == esp && ! i.index_reg) {
i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
i.rm.mode = MODE_FROM_DISP_SIZE (i.types[o]);
i.bi.base = ESP_REG_NUM;
i.bi.index = NO_INDEX_REGISTER;
i.bi.scale = 0;
} else if (i.base_reg == ebp && !i.index_reg) {
if (! (i.types[o] & Disp)) {
fake_zero_displacement = TRUE;
i.types[o] |= Disp8;
}
i.rm.mode = MODE_FROM_DISP_SIZE (i.types[o]);
i.rm.regmem = EBP_REG_NUM;
} else if (! i.base_reg && (i.types[o] & BaseIndex)) {
i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
i.rm.mode = 0;
i.bi.base = NO_BASE_REGISTER;
i.types[o] &= ~Disp;
i.types[o] |= Disp32;
if (i.index_reg) {
i.bi.index = i.index_reg->reg_num;
i.bi.scale = i.log2_scale_factor;
if (i.disp_operands == 0)
fake_zero_displacement = TRUE;
} else {
i.bi.index = NO_INDEX_REGISTER;
i.bi.scale = 0;
}
} else if (i.disp_operands && !i.base_reg && !i.index_reg) {
i.rm.regmem = EBP_REG_NUM;
i.rm.mode = 0;
i.types[o] &= ~Disp;
i.types[o] |= Disp32;
} else {
i.rm.regmem = i.base_reg->reg_num;
i.rm.mode = MODE_FROM_DISP_SIZE (i.types[o]);
if (i.index_reg) {
i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
i.bi.base = i.base_reg->reg_num;
i.bi.index = i.index_reg->reg_num;
i.bi.scale = i.log2_scale_factor;
if (i.base_reg == ebp && i.disp_operands == 0) {
fake_zero_displacement = TRUE;
i.types[o] |= Disp8;
i.rm.mode = MODE_FROM_DISP_SIZE (i.types[o]);
}
}
}
if (fake_zero_displacement) {
exp = &disp_expressions[i.disp_operands++];
i.disps[o] = exp;
exp->X_seg = SEG_ABSOLUTE;
exp->X_add_number = 0;
exp->X_add_symbol = (symbolS *) 0;
exp->X_subtract_symbol = (symbolS *) 0;
}
if (i.seg) {
uint seg_index;
const seg_entry * default_seg;
if (i.rm.regmem == ESCAPE_TO_TWO_BYTE_ADDRESSING) {
seg_index = (i.rm.mode<<3) | i.bi.base;
default_seg = two_byte_segment_defaults [seg_index];
} else {
seg_index = (i.rm.mode<<3) | i.rm.regmem;
default_seg = one_byte_segment_defaults [seg_index];
}
if (i.seg != default_seg) {
if (i.prefixes == MAX_PREFIXES) {
as_bad ("%d prefixes given and %s segment override gives too many prefixes",
MAX_PREFIXES, i.seg->seg_name);
return;
}
#ifdef NeXT_MOD
if(add_seg_prefix(i.seg->seg_prefix))
return;
#else
i.prefix[i.prefixes++] = i.seg->seg_prefix;
#endif
}
}
}
if (i.reg_operands) {
uint o =
(i.types[0] & (Reg|SReg2|SReg3|Control|Debug|Test)) ? 0 :
(i.types[1] & (Reg|SReg2|SReg3|Control|Debug|Test)) ? 1 : 2;
if (t->extension_opcode != None)
i.rm.regmem = i.regs[o]->reg_num;
else i.rm.reg = i.regs[o]->reg_num;
if (! i.mem_operands) i.rm.mode = 3;
}
if (t->extension_opcode != None)
i.rm.reg = t->extension_opcode;
}
#ifdef NeXT_MOD
} else if (i.seg) {
if (i.prefixes == MAX_PREFIXES) {
as_bad ("%d prefixes given and %s segment override gives too many "
" prefixes", MAX_PREFIXES, i.seg->seg_name);
return;
}
if(add_seg_prefix(i.seg->seg_prefix))
return;
#endif
}
}
}
if (t->base_opcode == INT_OPCODE && i.imms[0]->X_add_number == 3) {
t->base_opcode = INT3_OPCODE;
i.imm_operands = 0;
}
#ifdef NeXT_MOD
if (flagseen['g'] && frchain_now->frch_nsect == text_nsect) {
(void)symbol_new(
"",
68 ,
text_nsect,
logical_input_line ,
obstack_next_free(&frags) - frag_now->fr_literal,
frag_now);
}
#endif
#ifdef NeXT_MOD
frchain_now->frch_section.flags |= S_ATTR_SOME_INSTRUCTIONS;
#endif
{
register char * p;
if (t->opcode_modifier & Jump) {
int n = i.disps[0]->X_add_number;
switch (i.disps[0]->X_seg) {
case SEG_ABSOLUTE:
#ifndef NeXT_MOD
if (FITS_IN_SIGNED_BYTE (n)) {
p = frag_more (2);
p[0] = t->base_opcode;
p[1] = n;
#if 0
} else if (FITS_IN_SIGNED_WORD (n)) {
p = frag_more (4);
p[0] = WORD_PREFIX_OPCODE;
p[1] = t->base_opcode;
md_number_to_chars (&p[2], n, 2);
#endif
} else
#endif
{
if (t->base_opcode == JUMP_PC_RELATIVE) {
p = frag_more (5);
p[0] = 0xe9;
md_number_to_chars (&p[1], n , 4);
#ifdef NeXT_MOD
fix_new(frag_now, p - frag_now->fr_literal + 1, 4, 0, 0, n, 1, 1, 0);
#endif
} else {
p = frag_more (6);
p[0] = TWO_BYTE_OPCODE_ESCAPE;
p[1] = t->base_opcode + 0x10;
md_number_to_chars (&p[2], n, 4);
#ifdef NeXT_MOD
fix_new(frag_now, p - frag_now->fr_literal + 2, 4, 0, 0, n, 1, 1, 0);
#endif
}
}
break;
default:
if (obstack_room (&frags) <= 6) {
frag_wane(frag_now);
frag_new (0);
}
#ifdef NeXT_MOD
if (!is_local_symbol(i.disps[0]->X_add_symbol)) {
if (t->base_opcode == JUMP_PC_RELATIVE) {
p = frag_more(1);
*p = 0xe9;
} else {
p = frag_more (2);
*p++ = TWO_BYTE_OPCODE_ESCAPE;
*p = (t->base_opcode + 0x10) & 0xff;
}
p = frag_more (4);
fix_new (frag_now, p - frag_now->fr_literal, 4,
i.disps[0]->X_add_symbol, i.disps[0]->X_subtract_symbol,
i.disps[0]->X_add_number, 1, 1, 0);
} else
#endif
{
p = frag_more (1);
p[0] = t->base_opcode;
frag_var (rs_machine_dependent,
6,
1,
((uchar) *p == JUMP_PC_RELATIVE
? ENCODE_RELAX_STATE (UNCOND_JUMP, BYTE)
: ENCODE_RELAX_STATE (COND_JUMP, BYTE)),
i.disps[0]->X_add_symbol,
n, p);
}
break;
}
} else if (t->opcode_modifier & (JumpByte|JumpDword)) {
int size = (t->opcode_modifier & JumpByte) ? 1 : 4;
int n = i.disps[0]->X_add_number;
#ifdef NeXT_MOD
register char *q;
if((t->opcode_modifier & JumpByte) == 0 && i.suffix == 'w')
size = 2;
for (q = i.prefix; q < i.prefix + i.prefixes; q++) {
p = frag_more (1);
md_number_to_chars (p, (uint) *q, 1);
}
#endif
if (FITS_IN_UNSIGNED_BYTE((int)t->base_opcode)) {
FRAG_APPEND_1_CHAR (t->base_opcode);
} else {
p = frag_more (2);
*p++ = (t->base_opcode >> 8) & 0xff;
*p = t->base_opcode & 0xff;
}
p = frag_more (size);
switch (i.disps[0]->X_seg) {
case SEG_ABSOLUTE:
#ifdef NeXT_MOD
md_number_to_chars (p, n -
(obstack_next_free(&frags) - frag_now->fr_literal), size);
#else
md_number_to_chars (p, n, size);
#endif
if (size == 1 && ! FITS_IN_SIGNED_BYTE (n)) {
as_bad ("loop/jecx only takes byte displacement; %d shortened to %d",
n, *p);
}
#ifndef NeXT_MOD
break;
#endif
default:
{
if(i.disps[0]->X_add_symbol != NULL &&
(i.disps[0]->X_subtract_symbol != NULL ||
i.disps[0]->X_add_symbol->sy_name[0] != 'L' ||
flagseen ['L']))
fix_new (frag_now, p - frag_now->fr_literal, size,
i.disps[0]->X_add_symbol, i.disps[0]->X_subtract_symbol,
i.disps[0]->X_add_number, 1, 1, 0);
else
fix_new (frag_now, p - frag_now->fr_literal, size,
i.disps[0]->X_add_symbol, i.disps[0]->X_subtract_symbol,
i.disps[0]->X_add_number, 1, 0, 0);
}
break;
}
} else if (t->opcode_modifier & JumpInterSegment) {
p = frag_more (1 + 2 + 4);
p[0] = t->base_opcode;
if (i.imms[1]->X_seg == SEG_ABSOLUTE)
md_number_to_chars (p + 1, i.imms[1]->X_add_number, 4);
else
fix_new (frag_now, p + 1 - frag_now->fr_literal, 4,
i.imms[1]->X_add_symbol,
i.imms[1]->X_subtract_symbol,
i.imms[1]->X_add_number, 0, 0, 0);
if (i.imms[0]->X_seg != SEG_ABSOLUTE)
as_bad ("can't handle non absolute segment in long call/jmp");
md_number_to_chars (p + 5, i.imms[0]->X_add_number, 2);
} else {
register char *q;
for (q = i.prefix; q < i.prefix + i.prefixes; q++) {
p = frag_more (1);
md_number_to_chars (p, (uint) *q, 1);
}
if (FITS_IN_UNSIGNED_BYTE((int)t->base_opcode)) {
FRAG_APPEND_1_CHAR (t->base_opcode);
} else if (FITS_IN_UNSIGNED_WORD((int)t->base_opcode)) {
p = frag_more (2);
*p++ = (t->base_opcode >> 8) & 0xff;
*p = t->base_opcode & 0xff;
} else {
if (t->base_opcode & 0xff000000) {
p = frag_more (4);
*p++ = (t->base_opcode >> 24) & 0xff;
} else p = frag_more (3);
*p++ = (t->base_opcode >> 16) & 0xff;
*p++ = (t->base_opcode >> 8) & 0xff;
*p = (t->base_opcode ) & 0xff;
}
if (t->opcode_modifier & Modrm) {
p = frag_more (1);
md_number_to_chars (p, (i.rm.regmem<<0 | i.rm.reg<<3 | i.rm.mode<<6), 1);
if (i.rm.regmem == ESCAPE_TO_TWO_BYTE_ADDRESSING && i.rm.mode != 3) {
p = frag_more (1);
md_number_to_chars (p,(i.bi.base<<0 | i.bi.index<<3 | i.bi.scale<<6), 1);
}
}
if (i.disp_operands) {
register int n;
for (n = 0; n < i.operands; n++) {
if (i.disps[n]) {
if (i.disps[n]->X_seg == SEG_ABSOLUTE) {
if (i.types[n] & (Disp8|Abs8)) {
p = frag_more (1);
md_number_to_chars (p, i.disps[n]->X_add_number, 1);
} else if (i.types[n] & (Disp16|Abs16)) {
p = frag_more (2);
md_number_to_chars (p, i.disps[n]->X_add_number, 2);
} else {
p = frag_more (4);
md_number_to_chars (p, i.disps[n]->X_add_number, 4);
}
} else {
p = frag_more (4);
fix_new (frag_now, p - frag_now->fr_literal, 4,
i.disps[n]->X_add_symbol, i.disps[n]->X_subtract_symbol,
i.disps[n]->X_add_number, 0, 0, 0);
}
}
}
}
if (i.imm_operands) {
register int n;
for (n = 0; n < i.operands; n++) {
if (i.imms[n]) {
if (i.imms[n]->X_seg == SEG_ABSOLUTE) {
if (i.types[n] & (Imm8|Imm8S)) {
p = frag_more (1);
md_number_to_chars (p, i.imms[n]->X_add_number, 1);
} else if (i.types[n] & Imm16) {
p = frag_more (2);
md_number_to_chars (p, i.imms[n]->X_add_number, 2);
} else {
p = frag_more (4);
md_number_to_chars (p, i.imms[n]->X_add_number, 4);
}
} else {
int size;
if (i.types[n] & (Imm8|Imm8S))
size = 1;
else if (i.types[n] & Imm16)
size = 2;
else
size = 4;
p = frag_more (size);
fix_new (frag_now, p - frag_now->fr_literal, size,
i.imms[n]->X_add_symbol, i.imms[n]->X_subtract_symbol,
i.imms[n]->X_add_number, 0, 0, 0);
}
}
}
}
}
#ifdef DEBUG386
if (flagseen ['D']) {
pi (line, &i);
}
#endif
}
return;
}
static
int
i386_operand(
char *operand_string)
{
register char *op_string = operand_string;
char * end_of_operand_string = operand_string + strlen(operand_string);
char * displacement_string_start = 0;
char * displacement_string_end = 0;
if (*op_string == ABSOLUTE_PREFIX) {
op_string++;
i.types[this_operand] |= JumpAbsolute;
}
if (*op_string == REGISTER_PREFIX) {
register reg_entry * r;
if (! (r = parse_register (op_string))) {
as_bad ("bad register name ('%s')", op_string);
return 0;
}
if ((r->reg_type & (SReg2|SReg3)) && op_string[3] == ':') {
switch (r->reg_num) {
case 0:
#ifdef NeXT_MOD
if(i.mem_operands != 0) i.seg2nd = &es; else
#endif
i.seg = &es; break;
case 1:
#ifdef NeXT_MOD
if(i.mem_operands != 0) i.seg2nd = &cs; else
#endif
i.seg = &cs; break;
case 2:
#ifdef NeXT_MOD
if(i.mem_operands != 0) i.seg2nd = &ss; else
#endif
i.seg = &ss; break;
case 3:
#ifdef NeXT_MOD
if(i.mem_operands != 0) i.seg2nd = &ds; else
#endif
i.seg = &ds; break;
case 4:
#ifdef NeXT_MOD
if(i.mem_operands != 0) i.seg2nd = &fs; else
#endif
i.seg = &fs; break;
case 5:
#ifdef NeXT_MOD
if(i.mem_operands != 0) i.seg2nd = &gs; else
#endif
i.seg = &gs; break;
}
op_string += 4;
operand_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 after segment override");
return 0;
}
if (*op_string == ABSOLUTE_PREFIX) {
op_string++;
i.types[this_operand] |= JumpAbsolute;
}
goto do_memory_reference;
}
i.types[this_operand] |= r->reg_type;
i.regs[this_operand] = r;
i.reg_operands++;
} else if (*op_string == IMMEDIATE_PREFIX) {
char * save_input_line_pointer;
register expressionS *exp;
segT exp_seg;
if (i.imm_operands == MAX_IMMEDIATE_OPERANDS) {
as_bad ("only 1 or 2 immediate operands are allowed");
return 0;
}
exp = &im_expressions[i.imm_operands++];
i.imms [this_operand] = exp;
save_input_line_pointer = input_line_pointer;
input_line_pointer = ++op_string;
exp_seg = expression (exp);
input_line_pointer = save_input_line_pointer;
switch (exp_seg) {
case SEG_NONE:
as_bad ("missing or invalid immediate expression '%s' taken as 0",
operand_string);
exp->X_seg = SEG_ABSOLUTE;
exp->X_add_number = 0;
exp->X_add_symbol = (symbolS *) 0;
exp->X_subtract_symbol = (symbolS *) 0;
i.types[this_operand] |= Imm;
break;
case SEG_ABSOLUTE:
i.types[this_operand] |= SMALLEST_IMM_TYPE (exp->X_add_number);
break;
case SEG_SECT:
case SEG_UNKNOWN:
case SEG_DIFFSECT:
i.types[this_operand] |= Imm32;
break;
default:
as_bad ("Unimplemented segment type %d in parse_operand", exp_seg);
return 0;
}
switch (i.suffix) {
case WORD_OPCODE_SUFFIX:
i.types[this_operand] |= Imm16;
break;
case BYTE_OPCODE_SUFFIX:
i.types[this_operand] |= Imm16 | Imm8 | Imm8S;
break;
}
} else if (is_digit_char(*op_string) || is_identifier_char(*op_string)
|| *op_string == '(' || *op_string == '"') {
register char * base_string;
uint found_base_index_form;
do_memory_reference:
if (i.mem_operands == MAX_MEMORY_OPERANDS) {
as_bad ("more than 1 memory reference in instruction");
return 0;
}
i.mem_operands++;
switch (i.suffix) {
case BYTE_OPCODE_SUFFIX:
i.types[this_operand] |= Mem8;
break;
case WORD_OPCODE_SUFFIX:
i.types[this_operand] |= Mem16;
break;
case DWORD_OPCODE_SUFFIX:
default:
i.types[this_operand] |= Mem32;
}
base_string = end_of_operand_string - 1;
found_base_index_form = FALSE;
if (*base_string == ')') {
uint parens_balenced = 1;
do {
base_string--;
if (*base_string == ')') parens_balenced++;
if (*base_string == '(') parens_balenced--;
} while (parens_balenced);
base_string++;
if (*base_string == REGISTER_PREFIX || *base_string == ',')
found_base_index_form = TRUE;
}
if (! found_base_index_form) {
displacement_string_start = op_string;
displacement_string_end = end_of_operand_string;
} else {
char *base_reg_name, *index_reg_name, *num_string;
int num;
i.types[this_operand] |= BaseIndex;
if (base_string != op_string + 1) {
displacement_string_start = op_string;
displacement_string_end = base_string - 1;
}
if (*base_string != ',') {
base_reg_name = base_string++;
while (isalpha(*base_string)) base_string++;
if (base_string == base_reg_name+1) {
as_bad ("can't find base register name after '(%c'",
REGISTER_PREFIX);
return 0;
}
END_STRING_AND_SAVE (base_string);
#ifdef NeXT_MOD
if (i.base_reg){
if (! (i.base_reg2nd = parse_register (base_reg_name))) {
as_bad ("bad base register name ('%s')", base_reg_name);
return 0;
}
}
else
#endif
if (! (i.base_reg = parse_register (base_reg_name))) {
as_bad ("bad base register name ('%s')", base_reg_name);
return 0;
}
RESTORE_END_STRING (base_string);
}
if (*base_string != ',' && *base_string != ')') {
as_bad ("expecting ',' or ')' after base register in `%s'",
operand_string);
return 0;
}
if (*base_string == ',' && *(base_string+1) == REGISTER_PREFIX) {
index_reg_name = ++base_string;
while (isalpha(*++base_string));
END_STRING_AND_SAVE (base_string);
#ifdef NeXT_MOD
if (i.index_reg) {
if(! (i.index_reg2nd = parse_register(index_reg_name))) {
as_bad ("bad index register name ('%s')", index_reg_name);
return 0;
}
}
else
#endif
if (! (i.index_reg = parse_register(index_reg_name))) {
as_bad ("bad index register name ('%s')", index_reg_name);
return 0;
}
RESTORE_END_STRING (base_string);
}
if (*base_string == ',' && isdigit(*(base_string+1))) {
num_string = ++base_string;
while (is_digit_char(*base_string)) base_string++;
if (base_string == num_string) {
as_bad ("can't find a scale factor after ','");
return 0;
}
END_STRING_AND_SAVE (base_string);
if (! sscanf (num_string, "%d", &num)) {
as_bad ("can't parse scale factor from '%s'", num_string);
return 0;
}
RESTORE_END_STRING (base_string);
switch (num) {
case 1:
#ifdef NeXT_MOD
if (i.index_reg2nd) i.log2_scale_factor2nd = 0; else
#endif
i.log2_scale_factor = 0; break;
case 2:
#ifdef NeXT_MOD
if (i.index_reg2nd) i.log2_scale_factor2nd = 1; else
#endif
i.log2_scale_factor = 1; break;
case 4:
#ifdef NeXT_MOD
if (i.index_reg2nd) i.log2_scale_factor2nd = 2; else
#endif
i.log2_scale_factor = 2; break;
case 8:
#ifdef NeXT_MOD
if (i.index_reg2nd) i.log2_scale_factor2nd = 3; else
#endif
i.log2_scale_factor = 3; break;
default:
as_bad ("expecting scale factor of 1, 2, 4, 8; got %d", num);
return 0;
}
} else {
if (! i.index_reg && *base_string == ',') {
as_bad ("expecting index register or scale factor after ','; got '%c'",
*(base_string+1));
return 0;
}
}
}
if (displacement_string_start) {
register expressionS * exp;
segT exp_seg;
char * save_input_line_pointer;
exp = &disp_expressions[i.disp_operands];
i.disps [this_operand] = exp;
i.disp_operands++;
save_input_line_pointer = input_line_pointer;
input_line_pointer = displacement_string_start;
END_STRING_AND_SAVE (displacement_string_end);
exp_seg = expression (exp);
if(*input_line_pointer)
as_bad("Ignoring junk '%s' after expression",input_line_pointer);
RESTORE_END_STRING (displacement_string_end);
input_line_pointer = save_input_line_pointer;
switch (exp_seg) {
case SEG_NONE:
as_bad ("missing or invalid displacement '%s' taken as 0",
operand_string);
i.types[this_operand] |= (Disp|Abs);
exp->X_seg = SEG_ABSOLUTE;
exp->X_add_number = 0;
exp->X_add_symbol = (symbolS *) 0;
exp->X_subtract_symbol = (symbolS *) 0;
break;
case SEG_ABSOLUTE:
i.types[this_operand] |= SMALLEST_DISP_TYPE (exp->X_add_number);
break;
case SEG_SECT:
case SEG_DIFFSECT:
case SEG_UNKNOWN:
i.types[this_operand] |= Disp32;
break;
default:
as_bad ("Unimplemented segment type %d in parse_operand", exp_seg);
return 0;
}
}
if (i.base_reg && i.index_reg &&
! (i.base_reg->reg_type & i.index_reg->reg_type & Reg)) {
as_bad ("register size mismatch in (base,index,scale) expression");
return 0;
}
if ((i.base_reg && (i.base_reg->reg_type & Reg32) == 0) ||
(i.index_reg && (i.index_reg->reg_type & Reg32) == 0)) {
as_bad ("base/index register must be 32 bit register");
return 0;
}
if (i.index_reg && i.index_reg == esp) {
as_bad ("%s may not be used as an index register", esp->reg_name);
return 0;
}
} else {
as_bad ("invalid char %s begining %s operand '%s'",
output_invalid(*op_string), ordinal_names[this_operand],
op_string);
return 0;
}
return 1;
}
int
md_estimate_size_before_relax (fragP, segment_type)
register fragS * fragP;
register int segment_type;
{
register uchar * opcode;
register int old_fr_fix;
old_fr_fix = fragP -> fr_fix;
opcode = (uchar *) fragP -> fr_opcode;
#ifdef NeXT_MOD
if ((fragP -> fr_symbol -> sy_type & N_TYPE) != N_SECT ||
fragP -> fr_symbol -> sy_other != segment_type)
#else
if ((fragP -> fr_symbol -> sy_type & N_TYPE) != segment_type)
#endif
{
switch (opcode[0]) {
case JUMP_PC_RELATIVE:
opcode[0] = 0xe9;
fragP -> fr_fix += 4;
fix_new (fragP, old_fr_fix, 4,
fragP -> fr_symbol,
(symbolS *) 0,
fragP -> fr_offset, 1, 1, 0);
break;
default:
opcode[1] = opcode[0] + 0x10;
opcode[0] = TWO_BYTE_OPCODE_ESCAPE;
fragP -> fr_fix += 1 + 4;
fix_new (fragP, old_fr_fix + 1, 4,
fragP -> fr_symbol,
(symbolS *) 0,
fragP -> fr_offset, 1, 1, 0);
break;
}
frag_wane (fragP);
}
return (fragP -> fr_var + fragP -> fr_fix - old_fr_fix);
}
void
md_convert_frag(
fragS *fragP)
{
register uchar * opcode;
uchar * where_to_put_displacement = 0;
uint target_address, opcode_address;
uint extension = 0;
int displacement_from_opcode_start;
opcode = (uchar *) fragP -> fr_opcode;
target_address = fragP->fr_symbol->sy_value + fragP->fr_offset;
opcode_address = fragP->fr_address + fragP->fr_fix;
displacement_from_opcode_start = target_address - opcode_address;
switch (fragP->fr_subtype) {
case ENCODE_RELAX_STATE (COND_JUMP, BYTE):
case ENCODE_RELAX_STATE (UNCOND_JUMP, BYTE):
extension = 1;
where_to_put_displacement = &opcode[1];
break;
case ENCODE_RELAX_STATE (COND_JUMP, WORD):
opcode[1] = TWO_BYTE_OPCODE_ESCAPE;
opcode[2] = opcode[0] + 0x10;
opcode[0] = WORD_PREFIX_OPCODE;
extension = 4;
where_to_put_displacement = &opcode[3];
break;
case ENCODE_RELAX_STATE (UNCOND_JUMP, WORD):
opcode[1] = 0xe9;
opcode[0] = WORD_PREFIX_OPCODE;
extension = 3;
where_to_put_displacement = &opcode[2];
break;
case ENCODE_RELAX_STATE (COND_JUMP, DWORD):
opcode[1] = opcode[0] + 0x10;
opcode[0] = TWO_BYTE_OPCODE_ESCAPE;
extension = 5;
where_to_put_displacement = &opcode[2];
break;
case ENCODE_RELAX_STATE (UNCOND_JUMP, DWORD):
opcode[0] = 0xe9;
extension = 4;
where_to_put_displacement = &opcode[1];
break;
default:
BAD_CASE(((int)fragP -> fr_subtype));
break;
}
md_number_to_chars ((char *)where_to_put_displacement,
displacement_from_opcode_start - extension,
SIZE_FROM_RELAX_STATE (fragP->fr_subtype));
fragP -> fr_fix += extension;
}
int
md_parse_option(
char **argP,
int *cntP,
char ***vecP)
{
return 1;
}
void
md_number_to_chars(
char *con,
long value,
int nbytes)
{
register char * p = con;
switch (nbytes) {
case 1:
p[0] = value & 0xff;
break;
case 2:
p[0] = value & 0xff;
p[1] = (value >> 8) & 0xff;
break;
case 4:
p[0] = value & 0xff;
p[1] = (value>>8) & 0xff;
p[2] = (value>>16) & 0xff;
p[3] = (value>>24) & 0xff;
break;
default:
BAD_CASE (nbytes);
}
}
void
md_number_to_imm(
unsigned char *con,
long value,
int nbytes,
fixS *fixP,
int nsect)
{
char * answer = alloca (nbytes);
register char * p = answer;
switch (nbytes) {
case 1:
*p = value;
break;
case 2:
*p++ = value;
*p = (value>>8);
break;
case 4:
*p++ = value;
*p++ = (value>>8);
*p++ = (value>>16);
*p = (value>>24);
break;
default:
BAD_CASE (nbytes);
}
memcpy(con, answer, nbytes);
}
#define MAX_LITTLENUMS 6
char *
md_atof(
int type,
char *litP,
int *sizeP)
{
int prec;
LITTLENUM_TYPE words[MAX_LITTLENUMS];
LITTLENUM_TYPE *wordP;
char *t;
char *atof_ieee();
switch(type) {
case 'f':
case 'F':
prec = 2;
break;
case 'd':
case 'D':
prec = 4;
break;
case 'x':
case 'X':
prec = 5;
break;
default:
*sizeP=0;
return "Bad call to md_atof ()";
}
t = atof_ieee (input_line_pointer,type,words);
if(t)
input_line_pointer=t;
*sizeP = prec * sizeof(LITTLENUM_TYPE);
for(wordP = words + prec - 1;prec--;) {
md_number_to_chars (litP, (long) (*wordP--), sizeof(LITTLENUM_TYPE));
litP += sizeof(LITTLENUM_TYPE);
}
return "";
}
static char output_invalid_buf[8];
static
char *
output_invalid(
char c)
{
if (isprint(c)) sprintf (output_invalid_buf, "'%c'", c);
else sprintf (output_invalid_buf, "(0x%x)", c);
return output_invalid_buf;
}
static
reg_entry *
parse_register(
char *reg_string)
{
register char *s = reg_string;
register char *p;
char reg_name_given[MAX_REG_NAME_SIZE];
s++;
for (p = reg_name_given; is_register_char (*s); p++, s++) {
*p = register_chars [(int)*s];
if (p >= reg_name_given + MAX_REG_NAME_SIZE)
return (reg_entry *) 0;
}
*p = '\0';
return (reg_entry *) hash_find (reg_hash, reg_name_given);
}
#ifdef NeXT_MOD
static
int
is_local_symbol(
struct symbol *sym)
{
if (sym->sy_name[0] == 'L') {
return 1;
}
return 0;
}
static
int
add_seg_prefix(
int seg_prefix)
{
unsigned long j;
for(j = 0; j < i.prefixes; j++){
if(i.prefix[j] == 0x2e ||
i.prefix[j] == 0x3e ||
i.prefix[j] == 0x26 ||
i.prefix[j] == 0x64 ||
i.prefix[j] == 0x65 ||
i.prefix[j] == 0x36){
as_bad ("segment override specified more than once");
return(1);
}
}
if (i.prefixes == MAX_PREFIXES) {
as_bad ("too many opcode prefixes");
return(1);
}
i.prefix[i.prefixes++] = seg_prefix;
return(0);
}
#endif