/* read.c - read a source file -
- Copyright (C) 1986, 1987, 1990, 1991, 1993, 1994
+ Copyright (C) 1986, 87, 90, 91, 92, 93, 94, 95, 96, 1997
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+along with GAS; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
#if 0
#define MASK_CHAR (0xFF) /* If your chars aren't 8 bits, you will
#include "as.h"
#include "subsegs.h"
-
+#include "sb.h"
+#include "macro.h"
#include "obstack.h"
#include "listing.h"
+#include "ecoff.h"
#ifndef TC_START_LABEL
#define TC_START_LABEL(x,y) (x==':')
#define LEX_PCT 0
#endif
+#ifndef LEX_QM
+/* The PowerPC Windows NT assemblers permits ? inside label names. */
+#define LEX_QM 0
+#endif
+
+#ifndef LEX_DOLLAR
+/* The a29k assembler does not permits labels to start with $. */
+#define LEX_DOLLAR 3
+#endif
+
+#ifndef LEX_TILDE
+/* The Delta 68k assembler permits ~ at start of label names. */
+#define LEX_TILDE 0
+#endif
+
/* used by is_... macros. our ctype[] */
-const char lex_type[256] =
+char lex_type[256] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ABCDEFGHIJKLMNO */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* PQRSTUVWXYZ[\]^_ */
- 0, 0, 0, 0, 3, LEX_PCT, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, /* _!"#$%&'()*+,-./ */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 0123456789:;<=>? */
+ 0, 0, 0, 0, LEX_DOLLAR, LEX_PCT, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, /* _!"#$%&'()*+,-./ */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, LEX_QM, /* 0123456789:;<=>? */
LEX_AT, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* @ABCDEFGHIJKLMNO */
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, LEX_BR, 0, LEX_BR, 0, 3, /* PQRSTUVWXYZ[\]^_ */
0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* `abcdefghijklmno */
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, LEX_BR, 0, LEX_BR, 0, 0, /* pqrstuvwxyz{|}~. */
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, LEX_BR, 0, LEX_BR, LEX_TILDE, 0, /* pqrstuvwxyz{|}~. */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
static char *buffer; /* 1st char of each buffer of lines is here. */
static char *buffer_limit; /*->1 + last char in buffer. */
-#ifdef TARGET_BYTES_BIG_ENDIAN
-/* Hack to deal with tc-*.h defining TARGET_BYTES_BIG_ENDIAN to empty
- instead of to 0 or 1. */
-#if 5 - TARGET_BYTES_BIG_ENDIAN - 5 == 10
-#undef TARGET_BYTES_BIG_ENDIAN
-#define TARGET_BYTES_BIG_ENDIAN 1
-#endif
+/* TARGET_BYTES_BIG_ENDIAN is required to be defined to either 0 or 1 in the
+ tc-<CPU>.h file. See the "Porting GAS" section of the internals manual. */
int target_big_endian = TARGET_BYTES_BIG_ENDIAN;
-#else
-int target_big_endian /* = 0 */;
-#endif
static char *old_buffer; /* JF a hack */
static char *old_input;
int new_broken_words;
#endif
+/* The current offset into the absolute section. We don't try to
+ build frags in the absolute section, since no data can be stored
+ there. We just keep track of the current offset. */
+addressT abs_section_offset;
+
+/* If this line had an MRI style label, it is stored in this variable.
+ This is used by some of the MRI pseudo-ops. */
+symbolS *line_label;
+
+/* This global variable is used to support MRI common sections. We
+ translate such sections into a common symbol. This variable is
+ non-NULL when we are in an MRI common section. */
+symbolS *mri_common_symbol;
+
+/* In MRI mode, after a dc.b pseudo-op with an odd number of bytes, we
+ need to align to an even byte boundary unless the next pseudo-op is
+ dc.b, ds.b, or dcb.b. This variable is set to 1 if an alignment
+ may be needed. */
+static int mri_pending_align;
+
+static void cons_worker PARAMS ((int, int));
+static int scrub_from_string PARAMS ((char **));
+static void do_align PARAMS ((int, char *, int, int));
+static void s_align PARAMS ((int, int));
+static int hex_float PARAMS ((int, char *));
+static void do_org PARAMS ((segT, expressionS *, int));
char *demand_copy_string PARAMS ((int *lenP));
-int is_it_end_of_statement PARAMS ((void));
static segT get_segmented_expression PARAMS ((expressionS *expP));
static segT get_known_segmented_expression PARAMS ((expressionS * expP));
static void pobegin PARAMS ((void));
+static int get_line_sb PARAMS ((sb *));
\f
void
/* Something close -- but not too close -- to a multiple of 1024.
The debugging malloc I'm using has 24 bytes of overhead. */
- obstack_begin (¬es, 5090);
- obstack_begin (&cond_obstack, 990);
+ obstack_begin (¬es, chunksize);
+ obstack_begin (&cond_obstack, chunksize);
/* Use machine dependent syntax */
for (p = line_separator_chars; *p; p++)
is_end_of_line[(unsigned char) *p] = 1;
/* Use more. FIXME-SOMEDAY. */
+
+ if (flag_mri)
+ lex_type['?'] = 3;
}
\f
/* set up pseudo-op tables */
-struct hash_control *po_hash;
+static struct hash_control *po_hash;
static const pseudo_typeS potable[] =
{
{"ascii", stringer, 0},
{"asciz", stringer, 1},
{"balign", s_align_bytes, 0},
+ {"balignw", s_align_bytes, -2},
+ {"balignl", s_align_bytes, -4},
/* block */
{"byte", cons, 1},
{"comm", s_comm, 0},
+ {"common", s_mri_common, 0},
+ {"common.s", s_mri_common, 1},
{"data", s_data, 0},
+ {"dc", cons, 2},
+ {"dc.b", cons, 1},
+ {"dc.d", float_cons, 'd'},
+ {"dc.l", cons, 4},
+ {"dc.s", float_cons, 'f'},
+ {"dc.w", cons, 2},
+ {"dc.x", float_cons, 'x'},
+ {"dcb", s_space, 2},
+ {"dcb.b", s_space, 1},
+ {"dcb.d", s_float_space, 'd'},
+ {"dcb.l", s_space, 4},
+ {"dcb.s", s_float_space, 'f'},
+ {"dcb.w", s_space, 2},
+ {"dcb.x", s_float_space, 'x'},
+ {"ds", s_space, 2},
+ {"ds.b", s_space, 1},
+ {"ds.d", s_space, 8},
+ {"ds.l", s_space, 4},
+ {"ds.p", s_space, 12},
+ {"ds.s", s_space, 4},
+ {"ds.w", s_space, 2},
+ {"ds.x", s_space, 12},
+ {"debug", s_ignore, 0},
#ifdef S_SET_DESC
{"desc", s_desc, 0},
#endif
/* dsect */
{"eject", listing_eject, 0}, /* Formfeed listing */
{"else", s_else, 0},
+ {"elsec", s_else, 0},
{"end", s_end, 0},
+ {"endc", s_endif, 0},
{"endif", s_endif, 0},
/* endef */
{"equ", s_set, 0},
-/* err */
+ {"err", s_err, 0},
+ {"exitm", s_mexit, 0},
/* extend */
{"extern", s_ignore, 0}, /* We treat all undef as ext */
{"appfile", s_app_file, 1},
{"appline", s_app_line, 0},
+ {"fail", s_fail, 0},
{"file", s_app_file, 0},
{"fill", s_fill, 0},
{"float", float_cons, 'f'},
+ {"format", s_ignore, 0},
{"global", s_globl, 0},
{"globl", s_globl, 0},
{"hword", cons, 2},
- {"if", s_if, 0},
+ {"if", s_if, (int) O_ne},
+ {"ifc", s_ifc, 0},
{"ifdef", s_ifdef, 0},
+ {"ifeq", s_if, (int) O_eq},
{"ifeqs", s_ifeqs, 0},
+ {"ifge", s_if, (int) O_ge},
+ {"ifgt", s_if, (int) O_gt},
+ {"ifle", s_if, (int) O_le},
+ {"iflt", s_if, (int) O_lt},
+ {"ifnc", s_ifc, 1},
{"ifndef", s_ifdef, 1},
+ {"ifne", s_if, (int) O_ne},
{"ifnes", s_ifeqs, 1},
{"ifnotdef", s_ifdef, 1},
{"include", s_include, 0},
{"int", cons, 4},
+ {"irp", s_irp, 0},
+ {"irep", s_irp, 0},
+ {"irpc", s_irp, 1},
+ {"irepc", s_irp, 1},
{"lcomm", s_lcomm, 0},
{"lflags", listing_flags, 0}, /* Listing flags */
+ {"linkonce", s_linkonce, 0},
{"list", listing_list, 1}, /* Turn listing on */
+ {"llen", listing_psize, 1},
{"long", cons, 4},
{"lsym", s_lsym, 0},
+ {"macro", s_macro, 0},
+ {"mexit", s_mexit, 0},
+ {"mri", s_mri, 0},
+ {".mri", s_mri, 0}, /* Special case so .mri works in MRI mode. */
+ {"name", s_ignore, 0},
+ {"noformat", s_ignore, 0},
{"nolist", listing_list, 0}, /* Turn listing off */
+ {"nopage", listing_nopage, 0},
{"octa", cons, 16},
+ {"offset", s_struct, 0},
{"org", s_org, 0},
{"p2align", s_align_ptwo, 0},
+ {"p2alignw", s_align_ptwo, -2},
+ {"p2alignl", s_align_ptwo, -4},
+ {"page", listing_eject, 0},
+ {"plen", listing_psize, 0},
+ {"print", s_print, 0},
{"psize", listing_psize, 0}, /* set paper size */
-/* print */
+ {"purgem", s_purgem, 0},
{"quad", cons, 8},
+ {"rep", s_rept, 0},
+ {"rept", s_rept, 0},
+ {"rva", s_rva, 4},
{"sbttl", listing_title, 1}, /* Subtitle of listing */
/* scl */
/* sect */
{"single", float_cons, 'f'},
/* size */
{"space", s_space, 0},
+ {"skip", s_space, 0},
+ {"spc", s_ignore, 0},
{"stabd", s_stab, 'd'},
{"stabn", s_stab, 'n'},
{"stabs", s_stab, 's'},
{"string", stringer, 1},
+ {"struct", s_struct, 0},
/* tag */
{"text", s_text, 0},
{"this_gcc_requires_the_gnu_assembler", s_ignore, 0},
{"title", listing_title, 0}, /* Listing title */
+ {"ttl", listing_title, 0},
/* type */
/* use */
/* val */
+ {"xcom", s_comm, 0},
+ {"xdef", s_globl, 0},
+ {"xref", s_ignore, 0},
{"xstabs", s_xstab, 's'},
{"word", cons, 2},
{"zero", s_space, 0},
{
errtxt = hash_insert (po_hash, pop->poc_name, (char *) pop);
if (errtxt && (!pop_override_ok || strcmp (errtxt, "exists")))
- as_fatal ("error constructing %s pseudo-op table", pop_table_name);
+ as_fatal ("error constructing %s pseudo-op table: %s", pop_table_name,
+ errtxt);
}
}
}
+/* This function is used when scrubbing the characters between #APP
+ and #NO_APP. */
+
+static char *scrub_string;
+static char *scrub_string_end;
+
+static int
+scrub_from_string (from)
+ char **from;
+{
+ int size;
+
+ *from = scrub_string;
+ size = scrub_string_end - scrub_string;
+ scrub_string = scrub_string_end;
+ return size;
+}
+
/* read_a_source_file()
*
* We read the file, putting things into a web that
if (input_line_pointer[-1] == '\n')
bump_line_counters ();
-#if defined (MRI) || defined (LABELS_WITHOUT_COLONS)
- /* Text at the start of a line must be a label, we run down
- and stick a colon in. */
- if (is_name_beginner (*input_line_pointer))
+ line_label = NULL;
+
+ if (flag_m68k_mri
+#ifdef LABELS_WITHOUT_COLONS
+ || 1
+#endif
+ )
{
- char *line_start = input_line_pointer;
- char c = get_symbol_end ();
- colon (line_start);
- *input_line_pointer = c;
- if (c == ':')
- input_line_pointer++;
+ /* Text at the start of a line must be a label, we
+ run down and stick a colon in. */
+ if (is_name_beginner (*input_line_pointer))
+ {
+ char *line_start = input_line_pointer;
+ char c;
+ int mri_line_macro;
+
+ LISTING_NEWLINE ();
+ HANDLE_CONDITIONAL_ASSEMBLY ();
+
+ c = get_symbol_end ();
+
+ /* In MRI mode, the EQU and MACRO pseudoops must
+ be handled specially. */
+ mri_line_macro = 0;
+ if (flag_m68k_mri)
+ {
+ char *rest = input_line_pointer + 1;
+
+ if (*rest == ':')
+ ++rest;
+ if (*rest == ' ' || *rest == '\t')
+ ++rest;
+ if ((strncasecmp (rest, "EQU", 3) == 0
+ || strncasecmp (rest, "SET", 3) == 0)
+ && (rest[3] == ' ' || rest[3] == '\t'))
+ {
+ input_line_pointer = rest + 3;
+ equals (line_start,
+ strncasecmp (rest, "SET", 3) == 0);
+ continue;
+ }
+ if (strncasecmp (rest, "MACRO", 5) == 0
+ && (rest[5] == ' '
+ || rest[5] == '\t'
+ || is_end_of_line[(unsigned char) rest[5]]))
+ mri_line_macro = 1;
+ }
+
+ /* In MRI mode, we need to handle the MACRO
+ pseudo-op specially: we don't want to put the
+ symbol in the symbol table. */
+ if (! mri_line_macro)
+ line_label = colon (line_start);
+ else
+ line_label = symbol_create (line_start,
+ absolute_section,
+ (valueT) 0,
+ &zero_address_frag);
+ *input_line_pointer = c;
+ if (c == ':')
+ input_line_pointer++;
+ }
}
-#endif
}
-
/*
* We are at the begining of a line, or similar place.
* We expect a well-formed assembler statement.
*/
if (TC_START_LABEL(c, input_line_pointer))
{
- colon (s); /* user-defined label */
+ if (flag_m68k_mri)
+ {
+ char *rest = input_line_pointer + 1;
+
+ /* In MRI mode, \tsym: set 0 is permitted. */
+
+ if (*rest == ':')
+ ++rest;
+ if (*rest == ' ' || *rest == '\t')
+ ++rest;
+ if ((strncasecmp (rest, "EQU", 3) == 0
+ || strncasecmp (rest, "SET", 3) == 0)
+ && (rest[3] == ' ' || rest[3] == '\t'))
+ {
+ input_line_pointer = rest + 3;
+ equals (s, 1);
+ continue;
+ }
+ }
+
+ line_label = colon (s); /* user-defined label */
*input_line_pointer++ = ':'; /* Put ':' back for error messages' sake. */
/* Input_line_pointer->after ':'. */
SKIP_WHITESPACE ();
}
else if (c == '='
- || (input_line_pointer[1] == '='
+ || ((c == ' ' || c == '\t')
+ && input_line_pointer[1] == '='
#ifdef TC_EQUAL_IN_INSN
&& ! TC_EQUAL_IN_INSN (c, input_line_pointer)
#endif
))
{
- equals (s);
+ equals (s, 1);
demand_empty_rest_of_line ();
}
else
{ /* expect pseudo-op or machine instruction */
-#ifdef MRI
- if (!done_pseudo (s))
-
-#else
-
pop = NULL;
#define IGNORE_OPCODE_CASE
}
#endif
+ if (flag_m68k_mri
#ifdef NO_PSEUDO_DOT
- /* The m88k uses pseudo-ops without a period. */
- pop = (pseudo_typeS *) hash_find (po_hash, s);
- if (pop != NULL && pop->poc_handler == NULL)
- pop = NULL;
+ || 1
#endif
+ )
+ {
+ /* The MRI assembler and the m88k use pseudo-ops
+ without a period. */
+ pop = (pseudo_typeS *) hash_find (po_hash, s);
+ if (pop != NULL && pop->poc_handler == NULL)
+ pop = NULL;
+ }
- if (pop != NULL || *s == '.')
+ if (pop != NULL
+ || (! flag_m68k_mri && *s == '.'))
{
/*
* PSEUDO - OP.
if (pop == NULL)
pop = (pseudo_typeS *) hash_find (po_hash, s + 1);
+ /* In MRI mode, we may need to insert an
+ automatic alignment directive. What a hack
+ this is. */
+ if (mri_pending_align
+ && (pop == NULL
+ || ! ((pop->poc_handler == cons
+ && pop->poc_val == 1)
+ || (pop->poc_handler == s_space
+ && pop->poc_val == 1)
+#ifdef tc_conditional_pseudoop
+ || tc_conditional_pseudoop (pop)
+#endif
+ || pop->poc_handler == s_if
+ || pop->poc_handler == s_ifdef
+ || pop->poc_handler == s_ifc
+ || pop->poc_handler == s_ifeqs
+ || pop->poc_handler == s_else
+ || pop->poc_handler == s_endif
+ || pop->poc_handler == s_globl
+ || pop->poc_handler == s_ignore)))
+ {
+ do_align (1, (char *) NULL, 0, 0);
+ mri_pending_align = 0;
+ if (line_label != NULL)
+ {
+ line_label->sy_frag = frag_now;
+ S_SET_VALUE (line_label, frag_now_fix ());
+ }
+ }
+
/* Print the error msg now, while we still can */
if (pop == NULL)
{
* after pseudo-operation.
*/
(*pop->poc_handler) (pop->poc_val);
+
+ /* If that was .end, just get out now. */
+ if (pop->poc_handler == s_end)
+ goto quit;
}
else
-#endif
- { /* machine instruction */
+ {
+ int inquote = 0;
+
/* WARNING: c has char, which may be end-of-line. */
/* Also: input_line_pointer->`\0` where c was. */
*input_line_pointer = c;
while (!is_end_of_line[(unsigned char) *input_line_pointer]
+ || inquote
#ifdef TC_EOL_IN_INSN
|| TC_EOL_IN_INSN (input_line_pointer)
#endif
)
{
+ if (flag_m68k_mri && *input_line_pointer == '\'')
+ inquote = ! inquote;
input_line_pointer++;
}
}
#endif
+ if (macro_defined)
+ {
+ sb out;
+ const char *err;
+
+ if (check_macro (s, &out, '\0', &err))
+ {
+ if (err != NULL)
+ as_bad (err);
+ *input_line_pointer++ = c;
+ input_scrub_include_sb (&out,
+ input_line_pointer);
+ sb_kill (&out);
+ buffer_limit =
+ input_scrub_next_buffer (&input_line_pointer);
+ continue;
+ }
+ }
+
+ if (mri_pending_align)
+ {
+ do_align (1, (char *) NULL, 0, 0);
+ mri_pending_align = 0;
+ if (line_label != NULL)
+ {
+ line_label->sy_frag = frag_now;
+ S_SET_VALUE (line_label, frag_now_fix ());
+ }
+ }
+
md_assemble (s); /* Assemble 1 instruction. */
*input_line_pointer++ = c;
char *new_tmp;
unsigned int new_length;
char *tmp_buf = 0;
- extern char *scrub_string, *scrub_last_string;
bump_line_counters ();
s = input_line_pointer;
{
input_line_pointer = ends + 8;
}
- new_buf = xmalloc (100);
- new_length = 100;
- new_tmp = new_buf;
scrub_string = s;
- scrub_last_string = ends;
+ scrub_string_end = ends;
+
+ new_length = ends - s;
+ new_buf = (char *) xmalloc (new_length);
+ new_tmp = new_buf;
for (;;)
{
- int ch;
+ int space;
+ int size;
- ch = do_scrub_next_char (scrub_from_string, scrub_to_string);
- if (ch == EOF)
- break;
- *new_tmp++ = ch;
- if (new_tmp == new_buf + new_length)
+ space = (new_buf + new_length) - new_tmp;
+ size = do_scrub_chars (scrub_from_string, new_tmp, space);
+
+ if (size < space)
{
- new_buf = xrealloc (new_buf, new_length + 100);
- new_tmp = new_buf + new_length;
- new_length += 100;
+ new_tmp += size;
+ break;
}
+
+ new_buf = xrealloc (new_buf, new_length + 100);
+ new_tmp = new_buf + new_length;
+ new_length += 100;
}
if (tmp_buf)
HANDLE_CONDITIONAL_ASSEMBLY ();
+#ifdef tc_unrecognized_line
+ if (tc_unrecognized_line (c))
+ continue;
+#endif
+
/* as_warn("Junk character %d.",c); Now done by ignore_rest */
input_line_pointer--; /* Report unknown char as ignored. */
ignore_rest_of_line ();
if (old_buffer)
{
+ free (buffer);
bump_line_counters ();
if (old_input != 0)
{
}
}
} /* while (more buffers to scan) */
+
+ quit:
+
+#ifdef md_cleanup
+ md_cleanup();
+#endif
input_scrub_close (); /* Close the input file */
+}
+
+/* For most MRI pseudo-ops, the line actually ends at the first
+ nonquoted space. This function looks for that point, stuffs a null
+ in, and sets *STOPCP to the character that used to be there, and
+ returns the location.
+
+ Until I hear otherwise, I am going to assume that this is only true
+ for the m68k MRI assembler. */
+
+char *
+mri_comment_field (stopcp)
+ char *stopcp;
+{
+#ifdef TC_M68K
+
+ char *s;
+ int inquote = 0;
+
+ know (flag_m68k_mri);
+
+ for (s = input_line_pointer;
+ ((! is_end_of_line[(unsigned char) *s] && *s != ' ' && *s != '\t')
+ || inquote);
+ s++)
+ {
+ if (*s == '\'')
+ inquote = ! inquote;
+ }
+ *stopcp = *s;
+ *s = '\0';
+ return s;
+
+#else
+
+ char *s;
+
+ for (s = input_line_pointer; ! is_end_of_line[(unsigned char) *s]; s++)
+ ;
+ *stopcp = *s;
+ *s = '\0';
+ return s;
+
+#endif
+
+}
+
+/* Skip to the end of an MRI comment field. */
+
+void
+mri_comment_end (stop, stopc)
+ char *stop;
+ int stopc;
+{
+ know (flag_mri);
+ input_line_pointer = stop;
+ *stop = stopc;
+ while (! is_end_of_line[(unsigned char) *input_line_pointer])
+ ++input_line_pointer;
}
void
as_fatal (".abort detected. Abandoning ship.");
}
-/* Guts of .align directive. */
+/* Guts of .align directive. N is the power of two to which to align.
+ FILL may be NULL, or it may point to the bytes of the fill pattern.
+ LEN is the length of whatever FILL points to, if anything. MAX is
+ the maximum number of characters to skip when doing the alignment,
+ or 0 if there is no maximum. */
+
static void
-do_align (n, fill)
+do_align (n, fill, len, max)
int n;
char *fill;
+ int len;
+ int max;
{
+ char default_fill;
+
#ifdef md_do_align
- md_do_align (n, fill, just_record_alignment);
+ md_do_align (n, fill, len, max, just_record_alignment);
#endif
- if (!fill)
- {
- /* @@ Fix this right for BFD! */
- static char zero;
- static char nop_opcode = NOP_OPCODE;
+ if (fill == NULL)
+ {
+ /* FIXME: Fix this right for BFD! */
if (now_seg != data_section && now_seg != bss_section)
- {
- fill = &nop_opcode;
- }
+ default_fill = NOP_OPCODE;
else
- {
- fill = &zero;
- }
+ default_fill = 0;
+ fill = &default_fill;
+ len = 1;
}
+
/* Only make a frag if we HAVE to. . . */
- if (n && !need_pass_2)
- frag_align (n, *fill);
+ if (n != 0 && !need_pass_2)
+ {
+ if (len <= 1)
+ frag_align (n, *fill, max);
+ else
+ frag_align_pattern (n, fill, len, max);
+ }
#ifdef md_do_align
just_record_alignment:
record_alignment (now_seg, n);
}
-/* For machines where ".align 4" means align to a 4 byte boundary. */
-void
-s_align_bytes (arg)
+/* Handle the .align pseudo-op. A positive ARG is a default alignment
+ (in bytes). A negative ARG is the negative of the length of the
+ fill pattern. BYTES_P is non-zero if the alignment value should be
+ interpreted as the byte boundary, rather than the power of 2. */
+
+static void
+s_align (arg, bytes_p)
int arg;
+ int bytes_p;
{
- register unsigned int temp;
- char temp_fill;
- unsigned int i = 0;
- unsigned long max_alignment = 1 << 15;
+ register unsigned int align;
+ char *stop = NULL;
+ char stopc;
+ offsetT fill = 0;
+ int max;
+ int fill_p;
+
+ if (flag_mri)
+ stop = mri_comment_field (&stopc);
if (is_end_of_line[(unsigned char) *input_line_pointer])
- temp = arg; /* Default value from pseudo-op table */
+ {
+ if (arg < 0)
+ align = 0;
+ else
+ align = arg; /* Default value from pseudo-op table */
+ }
else
- temp = get_absolute_expression ();
+ {
+ align = get_absolute_expression ();
+ SKIP_WHITESPACE ();
+ }
- if (temp > max_alignment)
+ if (bytes_p)
{
- as_bad ("Alignment too large: %d. assumed.", temp = max_alignment);
+ /* Convert to a power of 2. */
+ if (align != 0)
+ {
+ unsigned int i;
+
+ for (i = 0; (align & 1) == 0; align >>= 1, ++i)
+ ;
+ if (align != 1)
+ as_bad ("Alignment not a power of 2");
+ align = i;
+ }
}
- /* For the sparc, `.align (1<<n)' actually means `.align n' so we
- have to convert it. */
- if (temp != 0)
+ if (align > 15)
{
- for (i = 0; (temp & 1) == 0; temp >>= 1, ++i)
- ;
+ align = 15;
+ as_bad ("Alignment too large: %u assumed", align);
}
- if (temp != 1)
- as_bad ("Alignment not a power of 2");
- temp = i;
- if (*input_line_pointer == ',')
+ if (*input_line_pointer != ',')
{
- input_line_pointer++;
- temp_fill = get_absolute_expression ();
- do_align (temp, &temp_fill);
+ fill_p = 0;
+ max = 0;
}
else
- do_align (temp, (char *) 0);
-
- demand_empty_rest_of_line ();
-}
+ {
+ ++input_line_pointer;
+ if (*input_line_pointer == ',')
+ fill_p = 0;
+ else
+ {
+ fill = get_absolute_expression ();
+ SKIP_WHITESPACE ();
+ fill_p = 1;
+ }
-/* For machines where ".align 4" means align to 2**4 boundary. */
-void
-s_align_ptwo (ignore)
- int ignore;
-{
- register int temp;
- char temp_fill;
- long max_alignment = 15;
+ if (*input_line_pointer != ',')
+ max = 0;
+ else
+ {
+ ++input_line_pointer;
+ max = get_absolute_expression ();
+ }
+ }
- temp = get_absolute_expression ();
- if (temp > max_alignment)
- as_bad ("Alignment too large: %d. assumed.", temp = max_alignment);
- else if (temp < 0)
+ if (! fill_p)
{
- as_bad ("Alignment negative. 0 assumed.");
- temp = 0;
+ if (arg < 0)
+ as_warn ("expected fill pattern missing");
+ do_align (align, (char *) NULL, 0, max);
}
- if (*input_line_pointer == ',')
+ else
{
- input_line_pointer++;
- temp_fill = get_absolute_expression ();
- do_align (temp, &temp_fill);
+ int fill_len;
+
+ if (arg >= 0)
+ fill_len = 1;
+ else
+ fill_len = - arg;
+ if (fill_len <= 1)
+ {
+ char fill_char;
+
+ fill_char = fill;
+ do_align (align, &fill_char, fill_len, max);
+ }
+ else
+ {
+ char ab[16];
+
+ if (fill_len > sizeof ab)
+ abort ();
+ md_number_to_chars (ab, fill, fill_len);
+ do_align (align, ab, fill_len, max);
+ }
}
- else
- do_align (temp, (char *) 0);
+
+ if (flag_mri)
+ mri_comment_end (stop, stopc);
demand_empty_rest_of_line ();
}
+/* Handle the .align pseudo-op on machines where ".align 4" means
+ align to a 4 byte boundary. */
+
+void
+s_align_bytes (arg)
+ int arg;
+{
+ s_align (arg, 1);
+}
+
+/* Handle the .align pseud-op on machines where ".align 4" means align
+ to a 2**4 boundary. */
+
+void
+s_align_ptwo (arg)
+ int arg;
+{
+ s_align (arg, 0);
+}
+
void
s_comm (ignore)
int ignore;
register char *p;
offsetT temp;
register symbolS *symbolP;
+ char *stop = NULL;
+ char stopc;
+
+ if (flag_mri)
+ stop = mri_comment_field (&stopc);
name = input_line_pointer;
c = get_symbol_end ();
if (*input_line_pointer != ',')
{
as_bad ("Expected comma after symbol-name: rest of line ignored.");
+ if (flag_mri)
+ mri_comment_end (stop, stopc);
ignore_rest_of_line ();
return;
}
if ((temp = get_absolute_expression ()) < 0)
{
as_warn (".COMMon length (%ld.) <0! Ignored.", (long) temp);
+ if (flag_mri)
+ mri_comment_end (stop, stopc);
ignore_rest_of_line ();
return;
}
{
as_bad ("Ignoring attempt to re-define symbol `%s'.",
S_GET_NAME (symbolP));
+ if (flag_mri)
+ mri_comment_end (stop, stopc);
ignore_rest_of_line ();
return;
}
}
#endif /* not OBJ_VMS */
know (symbolP->sy_frag == &zero_address_frag);
+
+ if (flag_mri)
+ mri_comment_end (stop, stopc);
+
demand_empty_rest_of_line ();
} /* s_comm() */
+/* The MRI COMMON pseudo-op. We handle this by creating a common
+ symbol with the appropriate name. We make s_space do the right
+ thing by increasing the size. */
+
+void
+s_mri_common (small)
+ int small;
+{
+ char *name;
+ char c;
+ char *alc = NULL;
+ symbolS *sym;
+ offsetT align;
+ char *stop = NULL;
+ char stopc;
+
+ if (! flag_mri)
+ {
+ s_comm (0);
+ return;
+ }
+
+ stop = mri_comment_field (&stopc);
+
+ SKIP_WHITESPACE ();
+
+ name = input_line_pointer;
+ if (! isdigit ((unsigned char) *name))
+ c = get_symbol_end ();
+ else
+ {
+ do
+ {
+ ++input_line_pointer;
+ }
+ while (isdigit ((unsigned char) *input_line_pointer));
+ c = *input_line_pointer;
+ *input_line_pointer = '\0';
+
+ if (line_label != NULL)
+ {
+ alc = (char *) xmalloc (strlen (S_GET_NAME (line_label))
+ + (input_line_pointer - name)
+ + 1);
+ sprintf (alc, "%s%s", name, S_GET_NAME (line_label));
+ name = alc;
+ }
+ }
+
+ sym = symbol_find_or_make (name);
+ *input_line_pointer = c;
+ if (alc != NULL)
+ free (alc);
+
+ if (*input_line_pointer != ',')
+ align = 0;
+ else
+ {
+ ++input_line_pointer;
+ align = get_absolute_expression ();
+ }
+
+ if (S_IS_DEFINED (sym))
+ {
+#if defined (S_IS_COMMON) || defined (BFD_ASSEMBLER)
+ if (! S_IS_COMMON (sym))
+#endif
+ {
+ as_bad ("attempt to re-define symbol `%s'", S_GET_NAME (sym));
+ mri_comment_end (stop, stopc);
+ ignore_rest_of_line ();
+ return;
+ }
+ }
+
+ S_SET_EXTERNAL (sym);
+ mri_common_symbol = sym;
+
+#ifdef S_SET_ALIGN
+ if (align != 0)
+ S_SET_ALIGN (sym, align);
+#endif
+
+ if (line_label != NULL)
+ {
+ line_label->sy_value.X_op = O_symbol;
+ line_label->sy_value.X_add_symbol = sym;
+ line_label->sy_value.X_add_number = S_GET_VALUE (sym);
+ line_label->sy_frag = &zero_address_frag;
+ S_SET_SEGMENT (line_label, expr_section);
+ }
+
+ /* FIXME: We just ignore the small argument, which distinguishes
+ COMMON and COMMON.S. I don't know what we can do about it. */
+
+ /* Ignore the type and hptype. */
+ if (*input_line_pointer == ',')
+ input_line_pointer += 2;
+ if (*input_line_pointer == ',')
+ input_line_pointer += 2;
+
+ mri_comment_end (stop, stopc);
+
+ demand_empty_rest_of_line ();
+}
+
void
s_data (ignore)
int ignore;
}
/* Handle the .appfile pseudo-op. This is automatically generated by
- do_scrub_next_char when a preprocessor # line comment is seen with
- a file name. This default definition may be overridden by the
- object or CPU specific pseudo-ops. This function is also the
- default definition for .file; the APPFILE argument is 1 for
- .appfile, 0 for .file. */
+ do_scrub_chars when a preprocessor # line comment is seen with a
+ file name. This default definition may be overridden by the object
+ or CPU specific pseudo-ops. This function is also the default
+ definition for .file; the APPFILE argument is 1 for .appfile, 0 for
+ .file. */
void
s_app_file (appfile)
the buffer. Passing -2 to new_logical_line tells it to
account for it. */
new_logical_line (s, appfile ? -2 : -1);
+
+ /* In MRI mode, the preprocessor may have inserted an extraneous
+ backquote. */
+ if (flag_m68k_mri
+ && *input_line_pointer == '\''
+ && is_end_of_line[(unsigned char) input_line_pointer[1]])
+ ++input_line_pointer;
+
demand_empty_rest_of_line ();
#ifdef LISTING
if (listing)
}
/* Handle the .appline pseudo-op. This is automatically generated by
- do_scrub_next_char when a preprocessor # line comment is seen.
- This default definition may be overridden by the object or CPU
- specific pseudo-ops. */
+ do_scrub_chars when a preprocessor # line comment is seen. This
+ default definition may be overridden by the object or CPU specific
+ pseudo-ops. */
void
s_app_line (ignore)
demand_empty_rest_of_line ();
}
-void
-s_fill (ignore)
+/* Handle the .end pseudo-op. Actually, the real work is done in
+ read_a_source_file. */
+
+void
+s_end (ignore)
int ignore;
{
- long temp_repeat = 0;
- long temp_size = 1;
- register long temp_fill = 0;
- char *p;
-
-
- temp_repeat = get_absolute_expression ();
- if (*input_line_pointer == ',')
+ if (flag_mri)
{
- input_line_pointer++;
- temp_size = get_absolute_expression ();
- if (*input_line_pointer == ',')
- {
- input_line_pointer++;
- temp_fill = get_absolute_expression ();
- }
+ /* The MRI assembler permits the start symbol to follow .end,
+ but we don't support that. */
+ SKIP_WHITESPACE ();
+ if (! is_end_of_line[(unsigned char) *input_line_pointer]
+ && *input_line_pointer != '*'
+ && *input_line_pointer != '!')
+ as_warn ("start address not supported");
}
- /* This is to be compatible with BSD 4.2 AS, not for any rational reason. */
-#define BSD_FILL_SIZE_CROCK_8 (8)
- if (temp_size > BSD_FILL_SIZE_CROCK_8)
- {
- as_warn (".fill size clamped to %d.", BSD_FILL_SIZE_CROCK_8);
+}
+
+/* Handle the .err pseudo-op. */
+
+void
+s_err (ignore)
+ int ignore;
+{
+ as_bad (".err encountered");
+ demand_empty_rest_of_line ();
+}
+
+/* Handle the MRI fail pseudo-op. */
+
+void
+s_fail (ignore)
+ int ignore;
+{
+ offsetT temp;
+ char *stop = NULL;
+ char stopc;
+
+ if (flag_mri)
+ stop = mri_comment_field (&stopc);
+
+ temp = get_absolute_expression ();
+ if (temp >= 500)
+ as_warn (".fail %ld encountered", (long) temp);
+ else
+ as_bad (".fail %ld encountered", (long) temp);
+
+ if (flag_mri)
+ mri_comment_end (stop, stopc);
+
+ demand_empty_rest_of_line ();
+}
+
+void
+s_fill (ignore)
+ int ignore;
+{
+ long temp_repeat = 0;
+ long temp_size = 1;
+ register long temp_fill = 0;
+ char *p;
+
+#ifdef md_flush_pending_output
+ md_flush_pending_output ();
+#endif
+
+ temp_repeat = get_absolute_expression ();
+ if (*input_line_pointer == ',')
+ {
+ input_line_pointer++;
+ temp_size = get_absolute_expression ();
+ if (*input_line_pointer == ',')
+ {
+ input_line_pointer++;
+ temp_fill = get_absolute_expression ();
+ }
+ }
+ /* This is to be compatible with BSD 4.2 AS, not for any rational reason. */
+#define BSD_FILL_SIZE_CROCK_8 (8)
+ if (temp_size > BSD_FILL_SIZE_CROCK_8)
+ {
+ as_warn (".fill size clamped to %d.", BSD_FILL_SIZE_CROCK_8);
temp_size = BSD_FILL_SIZE_CROCK_8;
}
if (temp_size < 0)
}
else if (temp_repeat <= 0)
{
- as_warn ("Repeat < 0, .fill ignored");
+ if (temp_repeat < 0)
+ as_warn ("Repeat < 0, .fill ignored");
temp_size = 0;
}
char *name;
int c;
symbolS *symbolP;
+ char *stop = NULL;
+ char stopc;
+
+ if (flag_mri)
+ stop = mri_comment_field (&stopc);
do
{
}
}
while (c == ',');
+
+ if (flag_mri)
+ mri_comment_end (stop, stopc);
+
+ demand_empty_rest_of_line ();
+}
+
+/* Handle the MRI IRP and IRPC pseudo-ops. */
+
+void
+s_irp (irpc)
+ int irpc;
+{
+ char *file;
+ unsigned int line;
+ sb s;
+ const char *err;
+ sb out;
+
+ as_where (&file, &line);
+
+ sb_new (&s);
+ while (! is_end_of_line[(unsigned char) *input_line_pointer])
+ sb_add_char (&s, *input_line_pointer++);
+
+ sb_new (&out);
+
+ err = expand_irp (irpc, 0, &s, &out, get_line_sb, '\0');
+ if (err != NULL)
+ as_bad_where (file, line, "%s", err);
+
+ sb_kill (&s);
+
+ input_scrub_include_sb (&out, input_line_pointer);
+ sb_kill (&out);
+ buffer_limit = input_scrub_next_buffer (&input_line_pointer);
+}
+
+/* Handle the .linkonce pseudo-op. This tells the assembler to mark
+ the section to only be linked once. However, this is not supported
+ by most object file formats. This takes an optional argument,
+ which is what to do about duplicates. */
+
+void
+s_linkonce (ignore)
+ int ignore;
+{
+ enum linkonce_type type;
+
+ SKIP_WHITESPACE ();
+
+ type = LINKONCE_DISCARD;
+
+ if (! is_end_of_line[(unsigned char) *input_line_pointer])
+ {
+ char *s;
+ char c;
+
+ s = input_line_pointer;
+ c = get_symbol_end ();
+ if (strcasecmp (s, "discard") == 0)
+ type = LINKONCE_DISCARD;
+ else if (strcasecmp (s, "one_only") == 0)
+ type = LINKONCE_ONE_ONLY;
+ else if (strcasecmp (s, "same_size") == 0)
+ type = LINKONCE_SAME_SIZE;
+ else if (strcasecmp (s, "same_contents") == 0)
+ type = LINKONCE_SAME_CONTENTS;
+ else
+ as_warn ("unrecognized .linkonce type `%s'", s);
+
+ *input_line_pointer = c;
+ }
+
+#ifdef obj_handle_link_once
+ obj_handle_link_once (type);
+#else /* ! defined (obj_handle_link_once) */
+#ifdef BFD_ASSEMBLER
+ {
+ flagword flags;
+
+ if ((bfd_applicable_section_flags (stdoutput) & SEC_LINK_ONCE) == 0)
+ as_warn (".linkonce is not supported for this object file format");
+
+ flags = bfd_get_section_flags (stdoutput, now_seg);
+ flags |= SEC_LINK_ONCE;
+ switch (type)
+ {
+ default:
+ abort ();
+ case LINKONCE_DISCARD:
+ flags |= SEC_LINK_DUPLICATES_DISCARD;
+ break;
+ case LINKONCE_ONE_ONLY:
+ flags |= SEC_LINK_DUPLICATES_ONE_ONLY;
+ break;
+ case LINKONCE_SAME_SIZE:
+ flags |= SEC_LINK_DUPLICATES_SAME_SIZE;
+ break;
+ case LINKONCE_SAME_CONTENTS:
+ flags |= SEC_LINK_DUPLICATES_SAME_CONTENTS;
+ break;
+ }
+ if (! bfd_set_section_flags (stdoutput, now_seg, flags))
+ as_bad ("bfd_set_section_flags: %s",
+ bfd_errmsg (bfd_get_error ()));
+ }
+#else /* ! defined (BFD_ASSEMBLER) */
+ as_warn (".linkonce is not supported for this object file format");
+#endif /* ! defined (BFD_ASSEMBLER) */
+#endif /* ! defined (obj_handle_link_once) */
+
demand_empty_rest_of_line ();
}
{
bss_seg = subseg_new (".sbss", 1);
seg_info (bss_seg)->bss = 1;
+#ifdef BFD_ASSEMBLER
+ if (! bfd_set_section_flags (stdoutput, bss_seg, SEC_ALLOC))
+ as_warn ("error setting flags for \".sbss\": %s",
+ bfd_errmsg (bfd_get_error ()));
+#endif
}
}
#endif
else if (temp >= 2)
align = 1;
else
- align = temp;
+ align = 0;
+
+#ifdef OBJ_EVAX
+ /* FIXME: This needs to be done in a more general fashion. */
+ align = 3;
+#endif
record_alignment(bss_seg, align);
}
else
{
/* Assume some objects may require alignment on some systems. */
-#ifdef TC_ALPHA
+#if defined (TC_ALPHA) && ! defined (VMS)
if (temp > 1)
{
align = ffs (temp) - 1;
subseg_set (bss_seg, 1);
if (align)
- frag_align (align, 0);
+ frag_align (align, 0, 0);
/* detach from old frag */
if (S_GET_SEGMENT (symbolP) == bss_seg)
symbolP->sy_frag->fr_symbol = NULL;
S_SET_STORAGE_CLASS (symbolP, C_STAT);
}
#endif /* OBJ_COFF */
+
+#ifdef S_SET_SIZE
+ S_SET_SIZE (symbolP, temp);
+#endif
}
else
as_bad ("Ignoring attempt to re-define symbol `%s'.",
demand_empty_rest_of_line ();
} /* s_lsym() */
+/* Read a line into an sb. */
+
+static int
+get_line_sb (line)
+ sb *line;
+{
+ char quote1, quote2, inquote;
+
+ if (input_line_pointer[-1] == '\n')
+ bump_line_counters ();
+
+ if (input_line_pointer >= buffer_limit)
+ {
+ buffer_limit = input_scrub_next_buffer (&input_line_pointer);
+ if (buffer_limit == 0)
+ return 0;
+ }
+
+ /* If app.c sets any other characters to LEX_IS_STRINGQUOTE, this
+ code needs to be changed. */
+ if (! flag_m68k_mri)
+ quote1 = '"';
+ else
+ quote1 = '\0';
+
+ quote2 = '\0';
+ if (flag_m68k_mri)
+ quote2 = '\'';
+#ifdef LEX_IS_STRINGQUOTE
+ quote2 = '\'';
+#endif
+
+ inquote = '\0';
+ while (! is_end_of_line[(unsigned char) *input_line_pointer]
+ || (inquote != '\0' && *input_line_pointer != '\n'))
+ {
+ if (inquote == *input_line_pointer)
+ inquote = '\0';
+ else if (inquote == '\0')
+ {
+ if (*input_line_pointer == quote1)
+ inquote = quote1;
+ else if (*input_line_pointer == quote2)
+ inquote = quote2;
+ }
+ sb_add_char (line, *input_line_pointer++);
+ }
+ while (input_line_pointer < buffer_limit && *input_line_pointer == '\n')
+ {
+ if (input_line_pointer[-1] == '\n')
+ bump_line_counters ();
+ ++input_line_pointer;
+ }
+ return 1;
+}
+
+/* Define a macro. This is an interface to macro.c, which is shared
+ between gas and gasp. */
+
+void
+s_macro (ignore)
+ int ignore;
+{
+ char *file;
+ unsigned int line;
+ sb s;
+ sb label;
+ const char *err;
+ const char *name;
+
+ as_where (&file, &line);
+
+ sb_new (&s);
+ while (! is_end_of_line[(unsigned char) *input_line_pointer])
+ sb_add_char (&s, *input_line_pointer++);
+
+ sb_new (&label);
+ if (line_label != NULL)
+ sb_add_string (&label, S_GET_NAME (line_label));
+
+ err = define_macro (0, &s, &label, get_line_sb, &name);
+ if (err != NULL)
+ as_bad_where (file, line, "%s", err);
+ else
+ {
+ if (line_label != NULL)
+ {
+ S_SET_SEGMENT (line_label, undefined_section);
+ S_SET_VALUE (line_label, 0);
+ line_label->sy_frag = &zero_address_frag;
+ }
+
+ if (((flag_m68k_mri
+#ifdef NO_PSEUDO_DOT
+ || 1
+#endif
+ )
+ && hash_find (po_hash, name) != NULL)
+ || (! flag_m68k_mri
+ && *name == '.'
+ && hash_find (po_hash, name + 1) != NULL))
+ as_warn ("attempt to redefine pseudo-op `%s' ignored",
+ name);
+ }
+
+ sb_kill (&s);
+}
+
+/* Handle the .mexit pseudo-op, which immediately exits a macro
+ expansion. */
+
+void
+s_mexit (ignore)
+ int ignore;
+{
+ buffer_limit = input_scrub_next_buffer (&input_line_pointer);
+}
+
+/* Switch in and out of MRI mode. */
+
+void
+s_mri (ignore)
+ int ignore;
+{
+ int on, old_flag;
+
+ on = get_absolute_expression ();
+ old_flag = flag_mri;
+ if (on != 0)
+ {
+ flag_mri = 1;
+#ifdef TC_M68K
+ flag_m68k_mri = 1;
+#endif
+ }
+ else
+ {
+ flag_mri = 0;
+ flag_m68k_mri = 0;
+ }
+
+#ifdef MRI_MODE_CHANGE
+ if (on != old_flag)
+ MRI_MODE_CHANGE (on);
+#endif
+
+ demand_empty_rest_of_line ();
+}
+
+/* Handle changing the location counter. */
+
+static void
+do_org (segment, exp, fill)
+ segT segment;
+ expressionS *exp;
+ int fill;
+{
+ if (segment != now_seg && segment != absolute_section)
+ as_bad ("invalid segment \"%s\"; segment \"%s\" assumed",
+ segment_name (segment), segment_name (now_seg));
+
+ if (now_seg == absolute_section)
+ {
+ if (fill != 0)
+ as_warn ("ignoring fill value in absolute section");
+ if (exp->X_op != O_constant)
+ {
+ as_bad ("only constant offsets supported in absolute section");
+ exp->X_add_number = 0;
+ }
+ abs_section_offset = exp->X_add_number;
+ }
+ else
+ {
+ char *p;
+
+ p = frag_var (rs_org, 1, 1, (relax_substateT) 0, exp->X_add_symbol,
+ exp->X_add_number, (char *) NULL);
+ *p = fill;
+ }
+}
+
void
s_org (ignore)
int ignore;
register segT segment;
expressionS exp;
register long temp_fill;
- register char *p;
+
+ /* The m68k MRI assembler has a different meaning for .org. It
+ means to create an absolute section at a given address. We can't
+ support that--use a linker script instead. */
+ if (flag_m68k_mri)
+ {
+ as_bad ("MRI style ORG pseudo-op not supported");
+ ignore_rest_of_line ();
+ return;
+ }
+
/* Don't believe the documentation of BSD 4.2 AS. There is no such
thing as a sub-segment-relative origin. Any absolute origin is
given a warning, then assumed to be segment-relative. Any
segmented origin expression ("foo+42") had better be in the right
segment or the .org is ignored.
- BSD 4.2 AS warns if you try to .org backwards. We cannot because
- we never know sub-segment sizes when we are reading code. BSD
- will crash trying to emit negative numbers of filler bytes in
- certain .orgs. We don't crash, but see as-write for that code.
+ BSD 4.2 AS warns if you try to .org backwards. We cannot because
+ we never know sub-segment sizes when we are reading code. BSD
+ will crash trying to emit negative numbers of filler bytes in
+ certain .orgs. We don't crash, but see as-write for that code.
+
+ Don't make frag if need_pass_2==1. */
+ segment = get_known_segmented_expression (&exp);
+ if (*input_line_pointer == ',')
+ {
+ input_line_pointer++;
+ temp_fill = get_absolute_expression ();
+ }
+ else
+ temp_fill = 0;
+
+ if (!need_pass_2)
+ do_org (segment, &exp, temp_fill);
+
+ demand_empty_rest_of_line ();
+} /* s_org() */
+
+/* Handle parsing for the MRI SECT/SECTION pseudo-op. This should be
+ called by the obj-format routine which handles section changing
+ when in MRI mode. It will create a new section, and return it. It
+ will set *TYPE to the section type: one of 'C' (code), 'D' (data),
+ 'M' (mixed), or 'R' (romable). If BFD_ASSEMBLER is defined, the
+ flags will be set in the section. */
+
+void
+s_mri_sect (type)
+ char *type;
+{
+#ifdef TC_M68K
+
+ char *name;
+ char c;
+ segT seg;
+
+ SKIP_WHITESPACE ();
+
+ name = input_line_pointer;
+ if (! isdigit ((unsigned char) *name))
+ c = get_symbol_end ();
+ else
+ {
+ do
+ {
+ ++input_line_pointer;
+ }
+ while (isdigit ((unsigned char) *input_line_pointer));
+ c = *input_line_pointer;
+ *input_line_pointer = '\0';
+ }
+
+ name = xstrdup (name);
+
+ *input_line_pointer = c;
+
+ seg = subseg_new (name, 0);
+
+ if (*input_line_pointer == ',')
+ {
+ int align;
+
+ ++input_line_pointer;
+ align = get_absolute_expression ();
+ record_alignment (seg, align);
+ }
+
+ *type = 'C';
+ if (*input_line_pointer == ',')
+ {
+ c = *++input_line_pointer;
+ c = toupper ((unsigned char) c);
+ if (c == 'C' || c == 'D' || c == 'M' || c == 'R')
+ *type = c;
+ else
+ as_bad ("unrecognized section type");
+ ++input_line_pointer;
+
+#ifdef BFD_ASSEMBLER
+ {
+ flagword flags;
+
+ flags = SEC_NO_FLAGS;
+ if (*type == 'C')
+ flags = SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE;
+ else if (*type == 'D' || *type == 'M')
+ flags = SEC_ALLOC | SEC_LOAD | SEC_DATA;
+ else if (*type == 'R')
+ flags = SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_READONLY | SEC_ROM;
+ if (flags != SEC_NO_FLAGS)
+ {
+ if (! bfd_set_section_flags (stdoutput, seg, flags))
+ as_warn ("error setting flags for \"%s\": %s",
+ bfd_section_name (stdoutput, seg),
+ bfd_errmsg (bfd_get_error ()));
+ }
+ }
+#endif
+ }
+
+ /* Ignore the HP type. */
+ if (*input_line_pointer == ',')
+ input_line_pointer += 2;
+
+ demand_empty_rest_of_line ();
+
+#else /* ! TC_M68K */
+#ifdef TC_I960
+
+ char *name;
+ char c;
+ segT seg;
+
+ SKIP_WHITESPACE ();
+
+ name = input_line_pointer;
+ c = get_symbol_end ();
+
+ name = xstrdup (name);
+
+ *input_line_pointer = c;
+
+ seg = subseg_new (name, 0);
+
+ if (*input_line_pointer != ',')
+ *type = 'C';
+ else
+ {
+ char *sectype;
+
+ ++input_line_pointer;
+ SKIP_WHITESPACE ();
+ sectype = input_line_pointer;
+ c = get_symbol_end ();
+ if (*sectype == '\0')
+ *type = 'C';
+ else if (strcasecmp (sectype, "text") == 0)
+ *type = 'C';
+ else if (strcasecmp (sectype, "data") == 0)
+ *type = 'D';
+ else if (strcasecmp (sectype, "romdata") == 0)
+ *type = 'R';
+ else
+ as_warn ("unrecognized section type `%s'", sectype);
+ *input_line_pointer = c;
+ }
+
+ if (*input_line_pointer == ',')
+ {
+ char *seccmd;
+
+ ++input_line_pointer;
+ SKIP_WHITESPACE ();
+ seccmd = input_line_pointer;
+ c = get_symbol_end ();
+ if (strcasecmp (seccmd, "absolute") == 0)
+ {
+ as_bad ("absolute sections are not supported");
+ *input_line_pointer = c;
+ ignore_rest_of_line ();
+ return;
+ }
+ else if (strcasecmp (seccmd, "align") == 0)
+ {
+ int align;
+
+ *input_line_pointer = c;
+ align = get_absolute_expression ();
+ record_alignment (seg, align);
+ }
+ else
+ {
+ as_warn ("unrecognized section command `%s'", seccmd);
+ *input_line_pointer = c;
+ }
+ }
+
+ demand_empty_rest_of_line ();
+
+#else /* ! TC_I960 */
+ /* The MRI assembler seems to use different forms of .sect for
+ different targets. */
+ abort ();
+#endif /* ! TC_I960 */
+#endif /* ! TC_M68K */
+}
+
+/* Handle the .print pseudo-op. */
+
+void
+s_print (ignore)
+ int ignore;
+{
+ char *s;
+ int len;
+
+ s = demand_copy_C_string (&len);
+ printf ("%s\n", s);
+ demand_empty_rest_of_line ();
+}
+
+/* Handle the .purgem pseudo-op. */
+
+void
+s_purgem (ignore)
+ int ignore;
+{
+ if (is_it_end_of_statement ())
+ {
+ demand_empty_rest_of_line ();
+ return;
+ }
+
+ do
+ {
+ char *name;
+ char c;
+
+ SKIP_WHITESPACE ();
+ name = input_line_pointer;
+ c = get_symbol_end ();
+ delete_macro (name);
+ *input_line_pointer = c;
+ SKIP_WHITESPACE ();
+ }
+ while (*input_line_pointer++ == ',');
+
+ --input_line_pointer;
+ demand_empty_rest_of_line ();
+}
- Don't make frag if need_pass_2==1. */
- segment = get_known_segmented_expression (&exp);
- if (*input_line_pointer == ',')
+/* Handle the .rept pseudo-op. */
+
+void
+s_rept (ignore)
+ int ignore;
+{
+ int count;
+ sb one;
+ sb many;
+
+ count = get_absolute_expression ();
+
+ sb_new (&one);
+ if (! buffer_and_nest ("REPT", "ENDR", &one, get_line_sb))
{
- input_line_pointer++;
- temp_fill = get_absolute_expression ();
+ as_bad ("rept without endr");
+ return;
}
- else
- temp_fill = 0;
- if (!need_pass_2)
- {
- if (segment != now_seg && segment != absolute_section)
- as_bad ("Invalid segment \"%s\". Segment \"%s\" assumed.",
- segment_name (segment), segment_name (now_seg));
- p = frag_var (rs_org, 1, 1, (relax_substateT) 0, exp.X_add_symbol,
- exp.X_add_number, (char *) 0);
- *p = temp_fill;
- } /* if (ok to make frag) */
- demand_empty_rest_of_line ();
-} /* s_org() */
+
+ sb_new (&many);
+ while (count-- > 0)
+ sb_add_sb (&many, &one);
+
+ sb_kill (&one);
+
+ input_scrub_include_sb (&many, input_line_pointer);
+ sb_kill (&many);
+ buffer_limit = input_scrub_next_buffer (&input_line_pointer);
+}
void
s_set (ignore)
/* Turn '. = mumble' into a .org mumble */
register segT segment;
expressionS exp;
- register char *ptr;
segment = get_known_segmented_expression (&exp);
if (!need_pass_2)
- {
- if (segment != now_seg && segment != absolute_section)
- as_bad ("Invalid segment \"%s\". Segment \"%s\" assumed.",
- segment_name (segment),
- segment_name (now_seg));
- ptr = frag_var (rs_org, 1, 1, (relax_substateT) 0, exp.X_add_symbol,
- exp.X_add_number, (char *) 0);
- *ptr = 0;
- } /* if (ok to make frag) */
+ do_org (segment, &exp, 0);
*end_name = delim;
return;
int mult;
{
expressionS exp;
- long temp_fill;
+ expressionS val;
char *p = 0;
+ char *stop = NULL;
+ char stopc;
+ int bytes;
#ifdef md_flush_pending_output
md_flush_pending_output ();
#endif
- /* Just like .fill, but temp_size = 1 */
- expression (&exp);
- if (exp.X_op == O_constant)
+ if (flag_mri)
+ stop = mri_comment_field (&stopc);
+
+ /* In m68k MRI mode, we need to align to a word boundary, unless
+ this is ds.b. */
+ if (flag_m68k_mri && mult > 1)
{
- long repeat;
+ if (now_seg == absolute_section)
+ {
+ abs_section_offset += abs_section_offset & 1;
+ if (line_label != NULL)
+ S_SET_VALUE (line_label, abs_section_offset);
+ }
+ else if (mri_common_symbol != NULL)
+ {
+ valueT val;
- repeat = exp.X_add_number;
- if (mult)
- repeat *= mult;
- if (repeat <= 0)
+ val = S_GET_VALUE (mri_common_symbol);
+ if ((val & 1) != 0)
+ {
+ S_SET_VALUE (mri_common_symbol, val + 1);
+ if (line_label != NULL)
+ {
+ know (line_label->sy_value.X_op == O_symbol);
+ know (line_label->sy_value.X_add_symbol == mri_common_symbol);
+ line_label->sy_value.X_add_number += 1;
+ }
+ }
+ }
+ else
{
- as_warn (".space repeat count is %s, ignored",
- repeat ? "negative" : "zero");
- ignore_rest_of_line ();
- return;
+ do_align (1, (char *) NULL, 0, 0);
+ if (line_label != NULL)
+ {
+ line_label->sy_frag = frag_now;
+ S_SET_VALUE (line_label, frag_now_fix ());
+ }
}
+ }
- if (!need_pass_2)
- p = frag_var (rs_fill, 1, 1, (relax_substateT) 0, (symbolS *) 0,
- repeat, (char *) 0);
+ bytes = mult;
+
+ expression (&exp);
+
+ SKIP_WHITESPACE ();
+ if (*input_line_pointer == ',')
+ {
+ ++input_line_pointer;
+ expression (&val);
}
else
{
- if (!need_pass_2)
- p = frag_var (rs_space, 1, 1, (relax_substateT) 0,
- make_expr_symbol (&exp), 0L, (char *) 0);
+ val.X_op = O_constant;
+ val.X_add_number = 0;
+ }
+
+ if (val.X_op != O_constant
+ || val.X_add_number < - 0x80
+ || val.X_add_number > 0xff
+ || (mult != 0 && mult != 1 && val.X_add_number != 0))
+ {
+ if (exp.X_op != O_constant)
+ as_bad ("Unsupported variable size or fill value");
+ else
+ {
+ offsetT i;
+
+ if (mult == 0)
+ mult = 1;
+ bytes = mult * exp.X_add_number;
+ for (i = 0; i < exp.X_add_number; i++)
+ emit_expr (&val, mult);
+ }
+ }
+ else
+ {
+ if (exp.X_op == O_constant)
+ {
+ long repeat;
+
+ repeat = exp.X_add_number;
+ if (mult)
+ repeat *= mult;
+ bytes = repeat;
+ if (repeat <= 0)
+ {
+ if (! flag_mri || repeat < 0)
+ as_warn (".space repeat count is %s, ignored",
+ repeat ? "negative" : "zero");
+ goto getout;
+ }
+
+ /* If we are in the absolute section, just bump the offset. */
+ if (now_seg == absolute_section)
+ {
+ abs_section_offset += repeat;
+ goto getout;
+ }
+
+ /* If we are secretly in an MRI common section, then
+ creating space just increases the size of the common
+ symbol. */
+ if (mri_common_symbol != NULL)
+ {
+ S_SET_VALUE (mri_common_symbol,
+ S_GET_VALUE (mri_common_symbol) + repeat);
+ goto getout;
+ }
+
+ if (!need_pass_2)
+ p = frag_var (rs_fill, 1, 1, (relax_substateT) 0, (symbolS *) 0,
+ repeat, (char *) 0);
+ }
+ else
+ {
+ if (now_seg == absolute_section)
+ {
+ as_bad ("space allocation too complex in absolute section");
+ subseg_set (text_section, 0);
+ }
+ if (mri_common_symbol != NULL)
+ {
+ as_bad ("space allocation too complex in common section");
+ mri_common_symbol = NULL;
+ }
+ if (!need_pass_2)
+ p = frag_var (rs_space, 1, 1, (relax_substateT) 0,
+ make_expr_symbol (&exp), 0L, (char *) 0);
+ }
+
+ if (p)
+ *p = val.X_add_number;
+ }
+
+ getout:
+
+ /* In MRI mode, after an odd number of bytes, we must align to an
+ even word boundary, unless the next instruction is a dc.b, ds.b
+ or dcb.b. */
+ if (flag_mri && (bytes & 1) != 0)
+ mri_pending_align = 1;
+
+ if (flag_mri)
+ mri_comment_end (stop, stopc);
+
+ demand_empty_rest_of_line ();
+}
+
+/* This is like s_space, but the value is a floating point number with
+ the given precision. This is for the MRI dcb.s pseudo-op and
+ friends. */
+
+void
+s_float_space (float_type)
+ int float_type;
+{
+ offsetT count;
+ int flen;
+ char temp[MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT];
+ char *stop = NULL;
+ char stopc;
+
+ if (flag_mri)
+ stop = mri_comment_field (&stopc);
+
+ count = get_absolute_expression ();
+
+ SKIP_WHITESPACE ();
+ if (*input_line_pointer != ',')
+ {
+ as_bad ("missing value");
+ if (flag_mri)
+ mri_comment_end (stop, stopc);
+ ignore_rest_of_line ();
+ return;
}
+
+ ++input_line_pointer;
+
SKIP_WHITESPACE ();
- if (*input_line_pointer == ',')
+
+ /* Skip any 0{letter} that may be present. Don't even check if the
+ * letter is legal. */
+ if (input_line_pointer[0] == '0' && isalpha (input_line_pointer[1]))
+ input_line_pointer += 2;
+
+ /* Accept :xxxx, where the x's are hex digits, for a floating point
+ with the exact digits specified. */
+ if (input_line_pointer[0] == ':')
{
- input_line_pointer++;
- temp_fill = get_absolute_expression ();
+ flen = hex_float (float_type, temp);
+ if (flen < 0)
+ {
+ if (flag_mri)
+ mri_comment_end (stop, stopc);
+ ignore_rest_of_line ();
+ return;
+ }
}
else
{
- temp_fill = 0;
+ char *err;
+
+ err = md_atof (float_type, temp, &flen);
+ know (flen <= MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT);
+ know (flen > 0);
+ if (err)
+ {
+ as_bad ("Bad floating literal: %s", err);
+ if (flag_mri)
+ mri_comment_end (stop, stopc);
+ ignore_rest_of_line ();
+ return;
+ }
}
- if (p)
+
+ while (--count >= 0)
{
- *p = temp_fill;
+ char *p;
+
+ p = frag_more (flen);
+ memcpy (p, temp, (unsigned int) flen);
}
+
+ if (flag_mri)
+ mri_comment_end (stop, stopc);
+
+ demand_empty_rest_of_line ();
+}
+
+/* Handle the .struct pseudo-op, as found in MIPS assemblers. */
+
+void
+s_struct (ignore)
+ int ignore;
+{
+ char *stop = NULL;
+ char stopc;
+
+ if (flag_mri)
+ stop = mri_comment_field (&stopc);
+ abs_section_offset = get_absolute_expression ();
+ subseg_set (absolute_section, 0);
+ if (flag_mri)
+ mri_comment_end (stop, stopc);
demand_empty_rest_of_line ();
}
are defined, which is the normal case, then only simple expressions
are permitted. */
+static void
+parse_mri_cons PARAMS ((expressionS *exp, unsigned int nbytes));
+
#ifndef TC_PARSE_CONS_EXPRESSION
#ifdef BITFIELD_CONS_EXPRESSIONS
#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) parse_bitfield_cons (EXP, NBYTES)
static void
parse_bitfield_cons PARAMS ((expressionS *exp, unsigned int nbytes));
#endif
-#ifdef MRI
-#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) parse_mri_cons (EXP)
-static void
-parse_mri_cons PARAMS ((expressionS *exp));
-#endif
#ifdef REPEAT_CONS_EXPRESSIONS
#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) parse_repeat_cons (EXP, NBYTES)
static void
/* worker to do .byte etc statements */
/* clobbers input_line_pointer, checks */
/* end-of-line. */
-void
-cons (nbytes)
+static void
+cons_worker (nbytes, rva)
register int nbytes; /* 1=.byte, 2=.word, 4=.long */
+ int rva;
{
+ int c;
expressionS exp;
+ char *stop = NULL;
+ char stopc;
#ifdef md_flush_pending_output
md_flush_pending_output ();
#endif
+ if (flag_mri)
+ stop = mri_comment_field (&stopc);
+
if (is_it_end_of_statement ())
{
+ if (flag_mri)
+ mri_comment_end (stop, stopc);
demand_empty_rest_of_line ();
return;
}
+#ifdef md_cons_align
+ md_cons_align (nbytes);
+#endif
+
+ c = 0;
do
{
- TC_PARSE_CONS_EXPRESSION (&exp, (unsigned int) nbytes);
+ if (flag_m68k_mri)
+ parse_mri_cons (&exp, (unsigned int) nbytes);
+ else
+ TC_PARSE_CONS_EXPRESSION (&exp, (unsigned int) nbytes);
+
+ if (rva)
+ {
+ if (exp.X_op == O_symbol)
+ exp.X_op = O_symbol_rva;
+ else
+ as_fatal ("rva without symbol");
+ }
emit_expr (&exp, (unsigned int) nbytes);
+ ++c;
}
while (*input_line_pointer++ == ',');
+ /* In MRI mode, after an odd number of bytes, we must align to an
+ even word boundary, unless the next instruction is a dc.b, ds.b
+ or dcb.b. */
+ if (flag_mri && nbytes == 1 && (c & 1) != 0)
+ mri_pending_align = 1;
+
input_line_pointer--; /* Put terminator back into stream. */
+
+ if (flag_mri)
+ mri_comment_end (stop, stopc);
+
demand_empty_rest_of_line ();
}
+
+void
+cons (size)
+ int size;
+{
+ cons_worker (size, 0);
+}
+
+void
+s_rva (size)
+ int size;
+{
+ cons_worker (size, 1);
+}
+
+
/* Put the contents of expression EXP into the object file using
NBYTES bytes. If need_pass_2 is 1, this does nothing. */
op = exp->X_op;
+ /* Allow `.word 0' in the absolute section. */
+ if (now_seg == absolute_section)
+ {
+ if (op != O_constant || exp->X_add_number != 0)
+ as_bad ("attempt to store value in absolute section");
+ abs_section_offset += nbytes;
+ return;
+ }
+
/* Handle a negative bignum. */
if (op == O_uminus
&& exp->X_add_number == 0
register valueT get;
register valueT use;
register valueT mask;
+ valueT hibit;
register valueT unmask;
/* JF << of >= number of bits in the object is undefined. In
particular SPARC (Sun 4) has problems */
if (nbytes >= sizeof (valueT))
- mask = 0;
+ {
+ mask = 0;
+ if (nbytes > sizeof (valueT))
+ hibit = 0;
+ else
+ hibit = (valueT) 1 << (nbytes * BITS_PER_CHAR - 1);
+ }
else
- mask = ~(valueT) 0 << (BITS_PER_CHAR * nbytes); /* Don't store these bits. */
+ {
+ /* Don't store these bits. */
+ mask = ~(valueT) 0 << (BITS_PER_CHAR * nbytes);
+ hibit = (valueT) 1 << (nbytes * BITS_PER_CHAR - 1);
+ }
unmask = ~mask; /* Do store these bits. */
get = exp->X_add_number;
use = get & unmask;
- if ((get & mask) != 0 && (get & mask) != mask)
+ if ((get & mask) != 0
+ && ((get & mask) != mask
+ || (get & hibit) == 0))
{ /* Leading bits contain both 0s & 1s. */
- as_warn ("Value 0x%lx truncated to 0x%lx.", get, use);
+ as_warn ("Value 0x%lx truncated to 0x%lx.",
+ (unsigned long) get, (unsigned long) use);
}
/* put bytes in right order. */
md_number_to_chars (p, use, (int) nbytes);
#ifdef TC_CONS_FIX_NEW
TC_CONS_FIX_NEW (frag_now, p - frag_now->fr_literal, nbytes, exp);
#else
- fix_new_exp (frag_now, p - frag_now->fr_literal, (int) nbytes, exp, 0,
- /* @@ Should look at CPU word size. */
- nbytes == 2 ? BFD_RELOC_16
- : nbytes == 8 ? BFD_RELOC_64
- : BFD_RELOC_32);
+ {
+ bfd_reloc_code_real_type r;
+
+ switch (nbytes)
+ {
+ case 1:
+ r = BFD_RELOC_8;
+ break;
+ case 2:
+ r = BFD_RELOC_16;
+ break;
+ case 4:
+ r = BFD_RELOC_32;
+ break;
+ case 8:
+ r = BFD_RELOC_64;
+ break;
+ default:
+ as_bad ("unsupported BFD relocation size %u", nbytes);
+ r = BFD_RELOC_32;
+ break;
+ }
+ fix_new_exp (frag_now, p - frag_now->fr_literal, (int) nbytes, exp,
+ 0, r);
+ }
#endif
#else
#ifdef TC_CONS_FIX_NEW
#endif /* BITFIELD_CONS_EXPRESSIONS */
\f
-#ifdef MRI
+/* Handle an MRI style string expression. */
static void
parse_mri_cons (exp, nbytes)
expressionS *exp;
unsigned int nbytes;
{
- if (*input_line_pointer == '\'')
+ if (*input_line_pointer != '\''
+ && (input_line_pointer[1] != '\''
+ || (*input_line_pointer != 'A'
+ && *input_line_pointer != 'E')))
+ TC_PARSE_CONS_EXPRESSION (exp, nbytes);
+ else
{
- /* An MRI style string, cut into as many bytes as will fit into
- a nbyte chunk, left justify if necessary, and separate with
- commas so we can try again later */
int scan = 0;
unsigned int result = 0;
+
+ /* An MRI style string. Cut into as many bytes as will fit into
+ a nbyte chunk, left justify if necessary, and separate with
+ commas so we can try again later. */
+ if (*input_line_pointer == 'A')
+ ++input_line_pointer;
+ else if (*input_line_pointer == 'E')
+ {
+ as_bad ("EBCDIC constants are not supported");
+ ++input_line_pointer;
+ }
+
input_line_pointer++;
for (scan = 0; scan < nbytes; scan++)
{
else
input_line_pointer++;
}
- else
- expression (&exp);
}
-
-#endif /* MRI */
\f
#ifdef REPEAT_CONS_EXPRESSIONS
#endif /* REPEAT_CONS_EXPRESSIONS */
\f
+/* Parse a floating point number represented as a hex constant. This
+ permits users to specify the exact bits they want in the floating
+ point number. */
+
+static int
+hex_float (float_type, bytes)
+ int float_type;
+ char *bytes;
+{
+ int length;
+ int i;
+
+ switch (float_type)
+ {
+ case 'f':
+ case 'F':
+ case 's':
+ case 'S':
+ length = 4;
+ break;
+
+ case 'd':
+ case 'D':
+ case 'r':
+ case 'R':
+ length = 8;
+ break;
+
+ case 'x':
+ case 'X':
+ length = 12;
+ break;
+
+ case 'p':
+ case 'P':
+ length = 12;
+ break;
+
+ default:
+ as_bad ("Unknown floating type type '%c'", float_type);
+ return -1;
+ }
+
+ /* It would be nice if we could go through expression to parse the
+ hex constant, but if we get a bignum it's a pain to sort it into
+ the buffer correctly. */
+ i = 0;
+ while (hex_p (*input_line_pointer) || *input_line_pointer == '_')
+ {
+ int d;
+
+ /* The MRI assembler accepts arbitrary underscores strewn about
+ through the hex constant, so we ignore them as well. */
+ if (*input_line_pointer == '_')
+ {
+ ++input_line_pointer;
+ continue;
+ }
+
+ if (i >= length)
+ {
+ as_warn ("Floating point constant too large");
+ return -1;
+ }
+ d = hex_value (*input_line_pointer) << 4;
+ ++input_line_pointer;
+ while (*input_line_pointer == '_')
+ ++input_line_pointer;
+ if (hex_p (*input_line_pointer))
+ {
+ d += hex_value (*input_line_pointer);
+ ++input_line_pointer;
+ }
+ if (target_big_endian)
+ bytes[i] = d;
+ else
+ bytes[length - i - 1] = d;
+ ++i;
+ }
+
+ if (i < length)
+ {
+ if (target_big_endian)
+ memset (bytes + i, 0, length - i);
+ else
+ memset (bytes, 0, length - i);
+ }
+
+ return length;
+}
+
/*
* float_cons()
*
return;
}
+#ifdef md_flush_pending_output
+ md_flush_pending_output ();
+#endif
+
do
{
/* input_line_pointer->1st char of a flonum (we hope!). */
if (input_line_pointer[0] == '0' && isalpha (input_line_pointer[1]))
input_line_pointer += 2;
- err = md_atof (float_type, temp, &length);
- know (length <= MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT);
- know (length > 0);
- if (err)
+ /* Accept :xxxx, where the x's are hex digits, for a floating
+ point with the exact digits specified. */
+ if (input_line_pointer[0] == ':')
{
- as_bad ("Bad floating literal: %s", err);
- ignore_rest_of_line ();
- return;
+ ++input_line_pointer;
+ length = hex_float (float_type, temp);
+ if (length < 0)
+ {
+ ignore_rest_of_line ();
+ return;
+ }
+ }
+ else
+ {
+ err = md_atof (float_type, temp, &length);
+ know (length <= MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT);
+ know (length > 0);
+ if (err)
+ {
+ as_bad ("Bad floating literal: %s", err);
+ ignore_rest_of_line ();
+ return;
+ }
}
if (!need_pass_2)
c = NOT_A_CHAR;
break;
+ case '\n':
+ as_warn ("Unterminated string: Newline inserted.");
+ bump_line_counters ();
+ break;
+
#ifndef NO_STRING_ESCAPES
case '\\':
switch (c = *input_line_pointer++)
/* To be compatible with BSD 4.2 as: give the luser a linefeed!! */
as_warn ("Unterminated string: Newline inserted.");
c = '\n';
+ bump_line_counters ();
break;
default:
{
register int len;
- for (len = *len_pointer;
- len > 0;
- len--)
+ for (len = *len_pointer; len > 0; len--)
{
if (*s == 0)
{
}
}
}
- return (s);
+ return s;
}
\f
/*
obstack_1grow (¬es, c);
len++;
}
- /* JF this next line is so demand_copy_C_string will return a null
- termanated string. */
+ /* JF this next line is so demand_copy_C_string will return a
+ null terminated string. */
obstack_1grow (¬es, '\0');
retval = obstack_finish (¬es);
}
} /* is_it_end_of_statement() */
void
-equals (sym_name)
+equals (sym_name, reassign)
char *sym_name;
+ int reassign;
{
register symbolS *symbolP; /* symbol we are working with */
+ char *stop;
+ char stopc;
input_line_pointer++;
if (*input_line_pointer == '=')
while (*input_line_pointer == ' ' || *input_line_pointer == '\t')
input_line_pointer++;
+ if (flag_mri)
+ stop = mri_comment_field (&stopc);
+
if (sym_name[0] == '.' && sym_name[1] == '\0')
{
/* Turn '. = mumble' into a .org mumble */
register segT segment;
expressionS exp;
- register char *p;
segment = get_known_segmented_expression (&exp);
if (!need_pass_2)
- {
- if (segment != now_seg && segment != absolute_section)
- as_warn ("Illegal segment \"%s\". Segment \"%s\" assumed.",
- segment_name (segment),
- segment_name (now_seg));
- p = frag_var (rs_org, 1, 1, (relax_substateT) 0, exp.X_add_symbol,
- exp.X_add_number, (char *) 0);
- *p = 0;
- } /* if (ok to make frag) */
+ do_org (segment, &exp, 0);
}
else
{
symbolP = symbol_find_or_make (sym_name);
+ /* Permit register names to be redefined. */
+ if (! reassign
+ && S_IS_DEFINED (symbolP)
+ && S_GET_SEGMENT (symbolP) != reg_section)
+ as_bad ("symbol `%s' already defined", S_GET_NAME (symbolP));
pseudo_set (symbolP);
}
+
+ if (flag_mri)
+ mri_comment_end (stop, stopc);
} /* equals() */
/* .include -- include a file at this point. */
FILE *try;
char *path;
- filename = demand_copy_string (&i);
+ if (! flag_m68k_mri)
+ filename = demand_copy_string (&i);
+ else
+ {
+ SKIP_WHITESPACE ();
+ i = 0;
+ while (! is_end_of_line[(unsigned char) *input_line_pointer]
+ && *input_line_pointer != ' '
+ && *input_line_pointer != '\t')
+ {
+ obstack_1grow (¬es, *input_line_pointer);
+ ++input_line_pointer;
+ ++i;
+ }
+ obstack_1grow (¬es, '\0');
+ filename = obstack_finish (¬es);
+ while (! is_end_of_line[(unsigned char) *input_line_pointer])
+ ++input_line_pointer;
+ }
demand_empty_rest_of_line ();
path = xmalloc ((unsigned long) i + include_dir_maxlen + 5 /* slop */ );
for (i = 0; i < include_dir_count; i++)
}
+void
+read_print_statistics (file)
+ FILE *file;
+{
+ hash_print_statistics (file, "pseudo-op table", po_hash);
+}
+
/* end of read.c */