📄 i386.c
字号:
/*- * This code is derived from software copyrighted by the Free Software * Foundation. * * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. */#ifndef lintstatic char sccsid[] = "@(#)i386.c 6.4 (Berkeley) 5/8/91";#endif /* not lint *//* 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 modifyit under the terms of the GNU General Public License as published bythe 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 ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GAS; see the file COPYING. If not, write tothe 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#elseextern 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 & onefor unconditional jumps. This is because the these two types of jumpsadd different sizes to frags when we're figuring out what sort of jumpto 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_chars, operand_chars, space_chars */ { register unsigned int c; bzero (opcode_chars, sizeof(opcode_chars)); bzero (operand_chars, sizeof(operand_chars)); bzero (space_chars, sizeof(space_chars)); bzero (identifier_chars, sizeof(identifier_chars)); bzero (digit_chars, 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 && index(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() {} /* not much to do here. */#ifdef DEBUG386/* debugging routines for md_assemble */static void pi (), pte (), pt (), pe (), ps ();static void pi (line, x) 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 (t) 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"); }}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 (e) 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 (s) 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));}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 (t) 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 /* DEBUG386 *//* This is the guts of the machine-dependent assembler. LINE points to a machine dependent instruction. This funciton is supposed to emit the frags/bytes it assembles to. */void md_assemble (line) char *line;{ /* Holds temlate once we've found it. */ register template * t; /* Possible templates for current insn */ templates *current_templates = (templates *) 0; /* Initialize globals. */ bzero (&i, sizeof(i)); bzero (disp_expressions, sizeof(disp_expressions)); bzero (im_expressions, sizeof(im_expressions)); save_stack_p = save_stack; /* reset stack pointer */ /* Fist parse an opcode & call i386_operand for the operands. We assume that the scrubber has arranged it so that line[0] is the valid start of a (possibly prefixed) opcode. */ { register char *l = line; /* Fast place to put LINE. */ /* TRUE if operand is pending after ','. */ uint expecting_operand = 0; /* TRUE if we found a prefix only acceptable with string insns. */ uint expecting_string_instruction = 0; /* Non-zero if operand parens not balenced. */ 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]; /* fold case of opcodes */ l++; } else { /* this opcode's got a prefix */ 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -