home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 5
/
FreshFish_July-August1994.bin
/
bbs
/
gnu
/
gas-1.38-src.lha
/
src
/
amiga
/
gas-1.38
/
i386.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-09-22
|
61KB
|
1,936 lines
/* i386.c -- Assemble code for the Intel 80386
Copyright (C) 1989, Free Software Foundation.
This file is part of GAS, the GNU Assembler.
GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GAS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GAS; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/*
Intel 80386 machine specific gas.
Written by Eliot Dresselhaus (eliot@mgm.mit.edu).
Bugs & suggestions are completely welcome. This is free software.
Please help us make it better.
*/
#include <stdio.h>
#include <varargs.h>
#include <ctype.h>
#ifdef __GNUC__
#define alloca __builtin_alloca
#else
extern char *alloca();
#endif
#ifdef USG
#define index strchr
#endif
#include "as.h"
#include "read.h"
#include "flonum.h"
#include "obstack.h"
#include "frags.h"
#include "struc-symbol.h"
#include "expr.h"
#include "symbols.h"
#include "hash.h"
#include "md.h"
#include "i386.h"
#include "i386-opcode.h"
long omagic = OMAGIC;
char FLT_CHARS[] = "fFdDxX";
char EXP_CHARS[] = "eE";
char line_comment_chars[] = "#";
char comment_chars[] = "#/";
/* tables for lexical analysis */
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];
/* lexical macros */
#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])
/* put here all non-digit non-letter charcters that may occur in an operand */
static char operand_special_chars[] = "%$-+(,)*._~/<>|&^!:";
static char *ordinal_names[] = { "first", "second", "third" }; /* for printfs */
/* md_assemble() always leaves the strings it's passed unaltered. To
effect this we maintain a stack of saved characters that we've smashed
with '\0's (indicating end of strings for various sub-fields of the
assembler instruction). */
static char save_stack[32];
static char *save_stack_p; /* stack pointer */
#define END_STRING_AND_SAVE(s) *save_stack_p++ = *s; *s = '\0'
#define RESTORE_END_STRING(s) *s = *--save_stack_p
/* The instruction we're assembling. */
static i386_insn i;
/* Per instruction expressionS buffers: 2 displacements & 2 immediate max. */
static expressionS disp_expressions[2], im_expressions[2];
/* pointers to ebp & esp entries in reg_hash hash table */
static reg_entry *ebp, *esp;
static int this_operand; /* current operand we are working on */
/*
Interface to relax_segment.
There are 2 relax states for 386 jump insns: one for conditional & one
for unconditional jumps. This is because the these two types of jumps
add different sizes to frags when we're figuring out what sort of jump
to choose to reach a given label. */
/* types */
#define COND_JUMP 1 /* conditional jump */
#define UNCOND_JUMP 2 /* unconditional jump */
/* sizes */
#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[] = {
/*
The fields are:
1) most positive reach of this state,
2) most negative reach of this state,
3) how many bytes this mode will add to the size of the current frag
4) which index into the table to try if we can't fit into this one.
*/
{1, 1, 0, 0},
{1, 1, 0, 0},
{1, 1, 0, 0},
{1, 1, 0, 0},
/* For now we don't use word displacement jumps: they may be
untrustworthy. */
{127+1, -128+1, 0, ENCODE_RELAX_STATE(COND_JUMP,DWORD) },
/* word conditionals add 3 bytes to frag:
2 opcode prefix; 1 displacement bytes */
{32767+2, -32768+2, 3, ENCODE_RELAX_STATE(COND_JUMP,DWORD) },
/* dword conditionals adds 4 bytes to frag:
1 opcode prefix; 3 displacement bytes */
{0, 0, 4, 0},
{1, 1, 0, 0},
{127+1, -128+1, 0, ENCODE_RELAX_STATE(UNCOND_JUMP,DWORD) },
/* word jmp adds 2 bytes to frag:
1 opcode prefix; 1 displacement bytes */
{32767+2, -32768+2, 2, ENCODE_RELAX_STATE(UNCOND_JUMP,DWORD) },
/* dword jmp adds 3 bytes to frag:
0 opcode prefix; 3 displacement bytes */
{0, 0, 3, 0},
{1, 1, 0, 0},
};
void float_cons (), cons ();
/* Ignore certain directives generated by gcc. This probably should
not be here. */
void dummy ()
{
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 },
{ "ident", dummy, 0 }, /* ignore these directives */
{ "def", dummy, 0 },
{ "optim", dummy, 0 }, /* For sun386i cc */
{ "version", dummy, 0 },
{ "ln", dummy, 0 },
{ 0, 0, 0 }
};
/* for interface with expression () */
extern char * input_line_pointer;
char * index ();
char * output_invalid ();
reg_entry * parse_register ();
/* obstack for constructing various things in md_begin */
struct obstack o;
/* hash table for opcode lookup */
static struct hash_control *op_hash = (struct hash_control *) 0;
/* hash table for register lookup */
static struct hash_control *reg_hash = (struct hash_control *) 0;
/* hash table for prefix lookup */
static struct hash_control *prefix_hash = (struct hash_control *) 0;
void md_begin ()
{
char * hash_err;
obstack_begin (&o,4096);
/* initialize op_hash hash table */
op_hash = hash_new(); /* xmalloc handles error */
{
register template *optab;
register templates *core_optab;
char *prev_name;
optab = i386_optab; /* setup for loop */
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)) {
/* same name as before --> append to current template list */
obstack_grow (&o, optab, sizeof(template));
} else {
/* different name --> ship out current template list;
add to hash table; & begin anew */
/* Note: end must be set before start! since obstack_next_free changes
upon opstack_finish */
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));
}
}
}
/* initialize reg_hash hash table */
reg_hash = hash_new();
{
register reg_entry *regtab;
for (regtab = i386_regtab; regtab < i386_regtab_end; regtab++) {
hash_err = hash_insert (reg_hash, regtab->reg_name, 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");
/* initialize reg_hash hash table */
prefix_hash = hash_new();
{
register prefix_entry *prefixtab;
for (prefixtab = i386_prefixtab;
prefixtab < i386_prefixtab_end; prefixtab++) {
hash_err = hash_insert (prefix_hash, prefixtab->prefix_name, prefixtab);
if (hash_err && *hash_err) goto hash_error;
}
}
/* fill in lexical tables: opcode_c