⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sparc.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/*- * This code is derived from software copyrighted by the Free Software * Foundation. * * Modified 1993 by Chris Torek at Lawrence Berkeley Laboratory. */#ifndef lintstatic char sccsid[] = "@(#)sparc.c	5.2 (Berkeley) 4/12/93";#endif /* not lint *//* sparc.c -- Assemble for the SPARC   Copyright (C) 1989 Free Software Foundation, Inc.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.  */#include <stdio.h>#include <ctype.h>#include "sparc-opcode.h"#include "as.h"#include "frags.h"#include "struc-symbol.h"#include "flonum.h"#include "expr.h"#include "hash.h"#include "md.h"#include "sparc.h"#include "write.h"#include "read.h"#include "symbols.h"void md_begin();void md_end();void md_number_to_chars();void md_assemble();char *md_atof();void md_convert_frag();void md_create_short_jump();void md_create_long_jump();int  md_estimate_size_before_relax();void md_number_to_imm();void md_number_to_disp();void md_number_to_field();void md_ri_to_chars();void emit_relocations();static void sparc_ip();const relax_typeS md_relax_table[] = { 0 };/* handle of the OPCODE hash table */static struct hash_control *op_hash = NULL;static void s_seg(), s_proc(), s_data1(), s_reserve(), s_common();extern void s_globl(), s_long(), s_short(), s_space(), cons();const pseudo_typeSmd_pseudo_table[] = {    { "common",     s_common,   0 },    { "global",     s_globl,    0 },    { "half",       cons,       2 },    { "proc",       s_proc,     0 },    { "reserve",    s_reserve,  0 },    { "seg",        s_seg,      0 },    { "skip",       s_space,    0 },    { "word",       cons,       4 },    { NULL,         0,          0 },};int md_short_jump_size = 4;int md_long_jump_size = 4;int omagic  =  (0x103 << 16) | OMAGIC;  /* Magic number for header *//* This array holds the chars that always start a comment.  If the    pre-processor is disabled, these aren't very useful */char comment_chars[] = "!";	/* JF removed '|' from comment_chars *//* 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 *//* Note that input_file.c hand checks for '#' at the beginning of the   first line of the input file.  This is because the compiler outputs   #NO_APP at the beginning of its output. *//* Also note that '/*' will always start a comment */char line_comment_chars[] = "#";/* Chars that can be used to separate mant from exp in floating point nums */char EXP_CHARS[] = "eE";/* Chars that mean this number is a floating point constant *//* As in 0f12.456 *//* or    0d1.2345e12 */char FLT_CHARS[] = "rRsSfFdDxXpP";/* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be   changed in read.c .  Ideally it shouldn't have to know about it at all,   but nothing is ideal around here. */int size_reloc_info = sizeof(struct reloc_info_sparc);static unsigned char octal[256];#define isoctal(c)  octal[c]static unsigned char toHex[256];/* *  anull bit - causes the branch delay slot instructions to not be executed  */#define ANNUL       (1 << 29)struct sparc_it {    char    *error;    unsigned long opcode;    struct nlist *nlistp;    expressionS exp;    int pcrel;    enum reloc_type reloc;} the_insn, set_insn;#ifdef __STDC__static void print_insn(struct sparc_it *insn);static int getExpression(char *str);#elsestatic void print_insn();static int getExpression();#endifstatic char *expr_end;static int special_case;#define SPECIAL_CASE_SET    1/* * sort of like s_lcomm * */static voids_reserve(){    char *name;    char c;    char *p;    int temp;    symbolS *symbolP;    name = input_line_pointer;    c = get_symbol_end();    p = input_line_pointer;    *p = c;    SKIP_WHITESPACE();    if ( * input_line_pointer != ',' ) {	as_warn("Expected comma after name");	ignore_rest_of_line();	return;    }    input_line_pointer ++;    if ((temp = get_absolute_expression()) < 0) {	as_warn("BSS length (%d.) <0! Ignored.", temp);	ignore_rest_of_line();	return;    }    *p = 0;    symbolP = symbol_find_or_make(name);    *p = c;    if (strncmp(input_line_pointer, ",\"bss\"", 6) != 0) {	as_warn("bad .reserve segment: `%s'", input_line_pointer);	return;    }    input_line_pointer += 6;    if (symbolP->sy_other == 0         && symbolP->sy_desc  == 0	&& ((symbolP->sy_type  == N_BSS	&& symbolP->sy_value == local_bss_counter)	|| ((symbolP->sy_type & N_TYPE) == N_UNDF	&& symbolP->sy_value == 0))) {	    symbolP->sy_value = local_bss_counter;	    symbolP->sy_type  = N_BSS;	    symbolP->sy_frag  = & bss_address_frag;	    local_bss_counter += temp;    } else {	as_warn( "Ignoring attempt to re-define symbol from %d. to %d.",	    symbolP->sy_value, local_bss_counter );    }    demand_empty_rest_of_line();    return;}static voids_common(){    register char *name;    register char c;    register char *p;    register int temp;    register symbolS *	symbolP;    name = input_line_pointer;    c = get_symbol_end();    /* just after name is now '\0' */    p = input_line_pointer;    *p = c;    SKIP_WHITESPACE();    if ( * input_line_pointer != ',' ) {	as_warn("Expected comma after symbol-name");	ignore_rest_of_line();	return;    }    input_line_pointer ++; /* skip ',' */    if ( (temp = get_absolute_expression ()) < 0 ) {	as_warn(".COMMon length (%d.) <0! Ignored.", temp);	ignore_rest_of_line();	return;    }    *p = 0;    symbolP = symbol_find_or_make (name);    *p = c;    if (   (symbolP->sy_type & N_TYPE) != N_UNDF ||        symbolP->sy_other != 0 || symbolP->sy_desc != 0) {	as_warn( "Ignoring attempt to re-define symbol");	ignore_rest_of_line();	return;    }    if (symbolP->sy_value) {	if (symbolP->sy_value != temp) {	    as_warn( "Length of .comm \"%s\" is already %d. Not changed to %d.",		symbolP->sy_name, symbolP->sy_value, temp);	}    } else {	symbolP->sy_value = temp;	symbolP->sy_type |= N_EXT;    }    know(symbolP->sy_frag == &zero_address_frag);    if (strncmp(input_line_pointer, ",\"bss\"", 6) != 0) {	p=input_line_pointer;	while(*p && *p!='\n')		p++;	c= *p;	*p='\0';	as_warn("bad .common segment: `%s'", input_line_pointer);	*p=c;	return;    }    input_line_pointer += 6;    demand_empty_rest_of_line();    return;}static voids_seg(){    if (strncmp(input_line_pointer, "\"text\"", 6) == 0) {	input_line_pointer += 6;	s_text();	return;    }    if (strncmp(input_line_pointer, "\"data\"", 6) == 0) {	input_line_pointer += 6;	s_data();	return;    }    if (strncmp(input_line_pointer, "\"data1\"", 7) == 0) {	input_line_pointer += 7;	s_data1();	return;    }    as_warn("Unknown segment type");    demand_empty_rest_of_line();    return;}static voids_data1(){    subseg_new(SEG_DATA, 1);    demand_empty_rest_of_line();    return;}static voids_proc(){    extern char is_end_of_line[];    while (!is_end_of_line[*input_line_pointer]) {	++input_line_pointer;    }    ++input_line_pointer;    return;}/* This function is called once, at assembler startup time.  It should   set up all the tables, etc. that the MD part of the assembler will need.  */voidmd_begin(){  register char *retval = NULL;  int lose = 0;  register unsigned int i = 0;  op_hash = hash_new();  if (op_hash == NULL)    as_fatal("Virtual memory exhausted");  while (i < NUMOPCODES)    {      const char *name = sparc_opcodes[i].name;      retval = hash_insert(op_hash, name, &sparc_opcodes[i]);      if(retval != NULL && *retval != '\0')	{	  fprintf (stderr, "internal error: can't hash `%s': %s\n",		   sparc_opcodes[i].name, retval);	  lose = 1;	}      do	{	  if (sparc_opcodes[i].match & sparc_opcodes[i].lose)	    {	      fprintf (stderr, "internal error: losing opcode: `%s' \"%s\"\n",		       sparc_opcodes[i].name, sparc_opcodes[i].args);	      lose = 1;	    }	  ++i;	} while (i < NUMOPCODES		 && !strcmp(sparc_opcodes[i].name, name));    }  if (lose)    as_fatal ("Broken assembler.  No assembly attempted.");  for (i = '0'; i < '8'; ++i)    octal[i] = 1;  for (i = '0'; i <= '9'; ++i)    toHex[i] = i - '0';  for (i = 'a'; i <= 'f'; ++i)    toHex[i] = i + 10 - 'a';  for (i = 'A'; i <= 'F'; ++i)    toHex[i] = i + 10 - 'A';}voidmd_end(){    return;}voidmd_assemble(str)    char *str;{    char *toP;    int rsd;    assert(str);    sparc_ip(str);    toP = frag_more(4);    /* put out the opcode */    md_number_to_chars(toP, the_insn.opcode, 4);    /* put out the symbol-dependent stuff */    if (the_insn.reloc != NO_RELOC) {	fix_new(	    frag_now,                           /* which frag */	    (toP - frag_now->fr_literal), /* where */	    4,                                  /* size */	    the_insn.exp.X_add_symbol,	    the_insn.exp.X_subtract_symbol,	    the_insn.exp.X_add_number,	    the_insn.pcrel,	    the_insn.reloc	);    }    switch (special_case) {    case SPECIAL_CASE_SET:	special_case = 0;	assert(the_insn.reloc == RELOC_HI22);	if (the_insn.exp.X_seg == SEG_ABSOLUTE &&	    the_insn.exp.X_add_symbol == 0 &&	    the_insn.exp.X_subtract_symbol == 0 &&	    (the_insn.exp.X_add_number & 0x3ff) == 0)		return;	toP = frag_more(4);	rsd = (the_insn.opcode >> 25) & 0x1f;	the_insn.opcode = 0x80102000 | (rsd << 25) | (rsd << 14);	md_number_to_chars(toP, the_insn.opcode, 4);	fix_new(	    frag_now,                           /* which frag */	    (toP - frag_now->fr_literal),       /* where */	    4,                                  /* size */	    the_insn.exp.X_add_symbol,	    the_insn.exp.X_subtract_symbol,	    the_insn.exp.X_add_number,	    the_insn.pcrel,	    RELOC_LO10	);	return;    case 0:	return;    default:	abort();    }}static voidsparc_ip(str)    char *str;{    char *s;    const char *args;    char c;    unsigned long i;    struct sparc_opcode *insn;    char *argsStart;    unsigned long   opcode;    unsigned int mask;    int match = FALSE;    int comma = 0;    for (s = str; islower(*s) || (*s >= '0' && *s <= '3'); ++s)	;    switch (*s) {    case '\0':	break;    case ',':	comma = 1;	/*FALLTHROUGH*/    case ' ':	*s++ = '\0';	break;    default:	    as_warn("Unknown opcode: `%s'", str);	    exit(1);    }    if ((insn = (struct sparc_opcode *) hash_find(op_hash, str)) == NULL) {	as_warn("Unknown opcode: `%s'", str);	return;    }    if (comma) {	*--s = ',';    }    argsStart = s;    for (;;) {	opcode = insn->match;	bzero(&the_insn, sizeof(the_insn));	the_insn.reloc = NO_RELOC;	/*	 * Build the opcode, checking as we go to make	 * sure that the operands match	 */	for (args = insn->args; ; ++args) {	    switch (*args) {	    case '\0':  /* end of args */		if (*s == '\0') {		    match = TRUE;		}		break;	    case '+':		if (*s == '+') {		    ++s;		    continue;		}		if (*s == '-') {		    continue;		}		break;	    case '[':   /* these must match exactly */	    case ']':	    case ',':	    case ' ':		if (*s++ == *args)		    continue;		break;	    case '#':   /* must be at least one digit */		if (isdigit(*s++)) {		    while (isdigit(*s)) {			++s;		    }		    continue;		}		break;	    case 'C':   /* coprocessor state register */		if (strncmp(s, "%csr", 4) == 0) {		    s += 4;		    continue;		}		break;	    case 'b':    /* next operand is a coprocessor register */	    case 'c':	    case 'D':	        if (*s++ == '%' && *s++ == 'c' && isdigit(*s)) {		    mask = *s++;		    if (isdigit(*s)) {			mask = 10 * (mask - '0') + (*s++ - '0');			if (mask >= 32) {			    break;			}		    } else {			mask -= '0';		    }		    switch (*args) {		    case 'b':			opcode |= mask << 14;			continue;		    case 'c':			opcode |= mask;			continue;		    case 'D':			opcode |= mask << 25;			continue;		    }		}		break;	    case 'r':   /* next operand must be a register */	    case 'R':	    case '1':	    case '2':	    case 'd':		if (*s++ == '%') {		    switch (c = *s++) {		    case 'f':   /* frame pointer */		        if (*s++ == 'p') {			    mask = 0x1e;			    break;			}			goto error;		    case 'g':   /* global register */			if (isoctal(c = *s++)) {			    mask = c - '0';			    break;			}			goto error;		    case 'i':   /* in register */			if (isoctal(c = *s++)) {			    mask = c - '0' + 24;			    break;			}			goto error;		    case 'l':   /* local register */			if (isoctal(c = *s++)) {			    mask= (c - '0' + 16) ;			    break;			}			goto error;		    case 'o':   /* out register */			if (isoctal(c = *s++)) {			    mask= (c - '0' + 8) ;			    break;			}			goto error;		    case 's':   /* stack pointer */		        if (*s++ == 'p') {			    mask= 0xe;			    break;			}			goto error;		    case 'r': /* any register */		        if (!isdigit(c = *s++)) {			    goto error;			}			/* FALLTHROUGH */		    case '0': case '1': case '2': case '3': case '4':		    case '5': case '6': case '7': case '8': case '9':			if (isdigit(*s)) {			    if ((c = 10 * (c - '0') + (*s++ - '0')) >= 32) {				goto error;			    }			} else {			    c -= '0';			}			mask= c;			break;		    default:			goto error;		    }		    /*		     * Got the register, now figure out where		     * it goes in the opcode.		     */		    switch (*args) {		    case '1':			opcode |= mask << 14;			continue;		    case '2':			opcode |= mask;			continue;		    case 'd':			opcode |= mask << 25;			continue;		    case 'r':			opcode |= (mask << 25) | (mask << 14);			continue;		    case 'R':			opcode |= (mask << 25) | mask;			continue;		    }		}		break;	    case 'e':    /* next operand is a floating point register */	    case 'f':	    case 'g':	        if (*s++ == '%' && *s++ == 'f' && isdigit(*s)) {		    mask = *s++;		    if (isdigit(*s)) {			mask = 10 * (mask - '0') + (*s++ - '0');

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -