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
/
sparc.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-09-22
|
27KB
|
1,286 lines
/* 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 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. */
#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_typeS
md_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__
#if 0
static void print_insn(struct sparc_it *insn);
#endif
static int getExpression(char *str);
#else
#if 0
static void print_insn();
#endif
static int getExpression();
#endif
static char *expr_end;
static int special_case;
#define SPECIAL_CASE_SET 1
/*
* sort of like s_lcomm
*
*/
static void
s_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 void
s_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 void
s_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 void
s_data1()
{
subseg_new(SEG_DATA, 1);
demand_empty_rest_of_line();
return;
}
static void
s_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. */
void
md_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;
}