X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gas%2Fread.c;h=5c96735b12c65eb900f11fcd3a2a160ca6a94375;hb=80bc5d031a1b02e77d61e7e215e1c1492c98452c;hp=b198b50002da4bb6994ad09bfed9efbe189b5491;hpb=d4c8cbd8eff8e975f9d807bd0ec19def9cf610a1;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/read.c b/gas/read.c index b198b50002..5c96735b12 100644 --- a/gas/read.c +++ b/gas/read.c @@ -1,5 +1,6 @@ /* read.c - read a source file - - Copyright (C) 1986, 1987, 1990, 1991, 1993 Free Software Foundation, Inc. + 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. @@ -14,8 +15,9 @@ 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. */ +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 @@ -41,23 +43,11 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "as.h" #include "subsegs.h" - +#include "sb.h" +#include "macro.h" #include "obstack.h" #include "listing.h" - -/* We need this, despite the apparent object format dependency, since - it defines stab types, which all object formats can use now. */ - -#include "aout/stab_gnu.h" - -/* Allow backends to override the names used for the stab sections. */ -#ifndef STAB_SECTION_NAME -#define STAB_SECTION_NAME ".stab" -#endif - -#ifndef STAB_STRING_SECTION_NAME -#define STAB_STRING_SECTION_NAME ".stabstr" -#endif +#include "ecoff.h" #ifndef TC_START_LABEL #define TC_START_LABEL(x,y) (x==':') @@ -84,17 +74,42 @@ die horribly; #define LEX_AT 0 #endif +#ifndef LEX_BR +/* The RS/6000 assembler uses {,},[,] as parts of symbol names. */ +#define LEX_BR 0 +#endif + +#ifndef LEX_PCT +/* The Delta 68k assembler permits % inside label names. */ +#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, 0, 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, 3, 0, 0, 0, 3, /* PQRSTUVWXYZ[\]^_ */ + 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, 3, 0, 0, 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, @@ -113,9 +128,9 @@ const char lex_type[256] = char is_end_of_line[256] = { #ifdef CR_EOL - _, _, _, _, _, _, _, _, _, _, 99, _, _, 99, _, _, /* @abcdefghijklmno */ + 99, _, _, _, _, _, _, _, _, _, 99, _, _, 99, _, _, /* @abcdefghijklmno */ #else - _, _, _, _, _, _, _, _, _, _, 99, _, _, _, _, _, /* @abcdefghijklmno */ + 99, _, _, _, _, _, _, _, _, _, 99, _, _, _, _, _, /* @abcdefghijklmno */ #endif _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ #ifdef TC_HPPA @@ -142,7 +157,9 @@ char is_end_of_line[256] = static char *buffer; /* 1st char of each buffer of lines is here. */ static char *buffer_limit; /*->1 + last char in buffer. */ -int target_big_endian; +/* TARGET_BYTES_BIG_ENDIAN is required to be defined to either 0 or 1 in the + tc-.h file. See the "Porting GAS" section of the internals manual. */ +int target_big_endian = TARGET_BYTES_BIG_ENDIAN; static char *old_buffer; /* JF a hack */ static char *old_input; @@ -160,11 +177,37 @@ struct broken_word *broken_words; int new_broken_words; #endif -static char *demand_copy_string PARAMS ((int *lenP)); -int is_it_end_of_statement PARAMS ((void)); +/* 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)); 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 *)); void @@ -177,18 +220,21 @@ read_begin () /* 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; } /* set up pseudo-op tables */ -struct hash_control *po_hash; +static struct hash_control *po_hash; static const pseudo_typeS potable[] = { @@ -196,10 +242,38 @@ static const pseudo_typeS potable[] = {"align", s_align_ptwo, 0}, {"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 @@ -208,40 +282,77 @@ static const pseudo_typeS potable[] = /* 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 */ + {"equiv", s_set, 1}, + {"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 */ @@ -250,81 +361,86 @@ static const pseudo_typeS potable[] = {"single", float_cons, 'f'}, /* size */ {"space", s_space, 0}, + {"skip", s_space, 0}, + {"sleb128", s_leb128, 1}, + {"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 is for gcc to use. It's only just been added (2/94), so gcc + won't be able to use it for a while -- probably a year or more. + But once this has been released, check with gcc maintainers + before deleting it or even changing the spelling. */ + {"this_GCC_requires_the_GNU_assembler", s_ignore, 0}, + /* If we're folding case -- done for some targets, not necessarily + all -- the above string in an input file will be converted to + this one. Match it either way... */ + {"this_gcc_requires_the_gnu_assembler", s_ignore, 0}, + {"title", listing_title, 0}, /* Listing title */ + {"ttl", listing_title, 0}, /* type */ + {"uleb128", s_leb128, 0}, /* 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}, {NULL} /* end sentinel */ }; -static void -pobegin () +static int pop_override_ok = 0; +static const char *pop_table_name; + +void +pop_insert (table) + const pseudo_typeS *table; { - const char *errtxt; /* error text */ + const char *errtxt; const pseudo_typeS *pop; + for (pop = table; pop->poc_name; pop++) + { + 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: %s", pop_table_name, + errtxt); + } +} + +#ifndef md_pop_insert +#define md_pop_insert() pop_insert(md_pseudo_table) +#endif + +#ifndef obj_pop_insert +#define obj_pop_insert() pop_insert(obj_pseudo_table) +#endif +static void +pobegin () +{ po_hash = hash_new (); /* Do the target-specific pseudo ops. */ - for (pop = md_pseudo_table; pop->poc_name; pop++) - { - errtxt = hash_insert (po_hash, pop->poc_name, (char *) pop); - if (errtxt) - { - as_fatal ("error constructing md pseudo-op table"); - } /* on error */ - } /* for each op */ + pop_table_name = "md"; + md_pop_insert (); /* Now object specific. Skip any that were in the target table. */ - for (pop = obj_pseudo_table; pop->poc_name; pop++) - { - errtxt = hash_insert (po_hash, pop->poc_name, (char *) pop); - if (errtxt) - { - if (!strcmp (errtxt, "exists")) - { -#ifdef DIE_ON_OVERRIDES - as_fatal ("pseudo op \".%s\" overridden.\n", pop->poc_name); -#endif /* DIE_ON_OVERRIDES */ - continue; /* OK if target table overrides. */ - } - else - { - as_fatal ("error constructing obj pseudo-op table"); - } /* if overridden */ - } /* on error */ - } /* for each op */ + pop_table_name = "obj"; + pop_override_ok = 1; + obj_pop_insert (); /* Now portable ones. Skip any that we've seen already. */ - for (pop = potable; pop->poc_name; pop++) - { - errtxt = hash_insert (po_hash, pop->poc_name, (char *) pop); - if (errtxt) - { - if (!strcmp (errtxt, "exists")) - { -#ifdef DIE_ON_OVERRIDES - as_fatal ("pseudo op \".%s\" overridden.\n", pop->poc_name); -#endif /* DIE_ON_OVERRIDES */ - continue; /* OK if target table overrides. */ - } - else - { - as_fatal ("error constructing obj pseudo-op table"); - } /* if overridden */ - } /* on error */ - } /* for each op */ - - return; -} /* pobegin() */ + pop_table_name = "standard"; + pop_insert (potable); +} #define HANDLE_CONDITIONAL_ASSEMBLY() \ if (ignore_input ()) \ @@ -336,6 +452,24 @@ pobegin () } +/* 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 @@ -353,7 +487,8 @@ read_a_source_file (name) buffer = input_scrub_new_file (name); listing_file (name); - listing_newline (""); + listing_newline (NULL); + register_dependency (name); while ((buffer_limit = input_scrub_next_buffer (&input_line_pointer)) != 0) { /* We have another line to parse. */ @@ -370,26 +505,81 @@ read_a_source_file (name) * If input_line_pointer [-1] == '\n' then we just * scanned another line: so bump line counters. */ - if (input_line_pointer[-1] == '\n') + if (is_end_of_line[(unsigned char) input_line_pointer[-1]]) { - bump_line_counters (); +#ifdef md_start_line_hook + md_start_line_hook (); +#endif + + if (input_line_pointer[-1] == '\n') + bump_line_counters (); + + line_label = NULL; -#ifdef MRI - /* 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)) + 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. @@ -412,13 +602,46 @@ read_a_source_file (name) c = *input_line_pointer++; } know (c != ' '); /* No further leading whitespace. */ - LISTING_NEWLINE (); + +#ifndef NO_LISTING + /* If listing is on, and we are expanding a macro, then give + the listing code the contents of the expanded line. */ + if (listing) + { + if ((listing & LISTING_MACEXP) && macro_nest > 0) + { + char *copy; + int len; + + /* Find the end of the current expanded macro line. */ + for (s = input_line_pointer-1; *s ; ++s) + if (is_end_of_line[(unsigned char) *s]) + break; + + /* Copy it for safe keeping. Also give an indication of + how much macro nesting is involved at this point. */ + len = s - (input_line_pointer-1); + copy = (char *) xmalloc (len + macro_nest + 2); + memset (copy, '>', macro_nest); + copy[macro_nest] = ' '; + memcpy (copy + macro_nest + 1, input_line_pointer-1, len); + copy[macro_nest+1+len] = '\0'; + + /* Install the line with the listing facility. */ + listing_newline (copy); + } + else + listing_newline (NULL); + } +#endif + /* * C is the 1st significant character. * Input_line_pointer points after that character. */ if (is_name_beginner (c)) - { /* want user-defined label or pseudo/opcode */ + { + /* want user-defined label or pseudo/opcode */ HANDLE_CONDITIONAL_ASSEMBLY (); s = --input_line_pointer; @@ -432,7 +655,27 @@ read_a_source_file (name) */ 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 (); @@ -440,22 +683,18 @@ read_a_source_file (name) } 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 @@ -471,14 +710,21 @@ read_a_source_file (name) } #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. @@ -491,13 +737,43 @@ read_a_source_file (name) 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) { as_bad ("Unknown pseudo-op: `%s'", s); *input_line_pointer = c; s_ignore (0); - break; + continue; } /* Put it back for error messages etc. */ @@ -512,32 +788,89 @@ read_a_source_file (name) * Input_line_pointer->1st non-blank char * after pseudo-operation. */ - if (!pop) - { - ignore_rest_of_line (); - break; - } - else - (*pop->poc_handler) (pop->poc_val); + (*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++; } c = *input_line_pointer; *input_line_pointer = '\0'; + if (debug_type == DEBUG_STABS) + stabs_generate_asm_lineno (); + +#ifdef OBJ_GENERATE_ASM_LINENO +#ifdef ECOFF_DEBUGGING + /* ECOFF assemblers automatically generate + debugging information. FIXME: This should + probably be handled elsewhere. */ + if (debug_type == DEBUG_NONE) + { + if (ecoff_no_current_file ()) + debug_type = DEBUG_ECOFF; + } + + if (debug_type == DEBUG_ECOFF) + { + unsigned int lineno; + char *s; + + as_where (&s, &lineno); + OBJ_GENERATE_ASM_LINENO (s, lineno); + } +#endif +#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; @@ -554,8 +887,8 @@ read_a_source_file (name) if (is_end_of_line[(unsigned char) c]) continue; -#if defined(LOCAL_LABELS_DOLLAR) || defined(LOCAL_LABELS_FB) - if (isdigit (c)) + if ((LOCAL_LABELS_DOLLAR || LOCAL_LABELS_FB) + && isdigit (c)) { /* local label ("4:") */ char *backup = input_line_pointer; @@ -570,8 +903,8 @@ read_a_source_file (name) ++input_line_pointer; } /* read the whole number */ -#ifdef LOCAL_LABELS_DOLLAR - if (*input_line_pointer == '$' + if (LOCAL_LABELS_DOLLAR + && *input_line_pointer == '$' && *(input_line_pointer + 1) == ':') { input_line_pointer += 2; @@ -585,20 +918,17 @@ read_a_source_file (name) colon (dollar_label_name (temp, 0)); continue; } -#endif /* LOCAL_LABELS_DOLLAR */ -#ifdef LOCAL_LABELS_FB - if (*input_line_pointer++ == ':') + if (LOCAL_LABELS_FB + && *input_line_pointer++ == ':') { fb_label_instance_inc (temp); colon (fb_label_name (temp, 0)); continue; } -#endif /* LOCAL_LABELS_FB */ input_line_pointer = backup; } /* local label ("4:") */ -#endif /* LOCAL_LABELS_DOLLAR or LOCAL_LABELS_FB */ if (c && strchr (line_comment_chars, c)) { /* Its a comment. Better say APP or NO_APP */ @@ -607,7 +937,6 @@ read_a_source_file (name) 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; @@ -644,7 +973,7 @@ read_a_source_file (name) num = buffer_limit - buffer; tmp_buf = xrealloc (tmp_buf, tmp_len + num); - memcpy (tmp_buf, buffer + tmp_len, num); + memcpy (tmp_buf + tmp_len, buffer, num); tmp_len += num; } while (!ends); @@ -659,26 +988,30 @@ read_a_source_file (name) { 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; + + space = (new_buf + new_length) - new_tmp; + size = do_scrub_chars (scrub_from_string, new_tmp, space); - 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) + 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) @@ -694,12 +1027,23 @@ read_a_source_file (name) 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 (); } /* while (input_line_pointer max_alignment) - { - as_bad ("Alignment too large: %d. assumed.", temp = max_alignment); - } + know (flag_m68k_mri); - /* - * For the sparc, `.align (1<>= 1, ++i) - ; + if (*s == '\'') + inquote = ! inquote; } - if (temp != 1) - as_bad ("Alignment not a power of 2"); + *stopcp = *s; + *s = '\0'; + return s; - temp = i; - if (*input_line_pointer == ',') - { - input_line_pointer++; - temp_fill = get_absolute_expression (); - } - else if (now_seg != data_section && now_seg != bss_section) - temp_fill = NOP_OPCODE; - else - temp_fill = 0; - /* Only make a frag if we HAVE to. . . */ - if (temp && !need_pass_2) - frag_align ((int) temp, (int) temp_fill); +#else - record_alignment (now_seg, (int) temp); + char *s; - demand_empty_rest_of_line (); -} /* s_align_bytes() */ + 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; +} -/* For machines where ".align 4" means align to 2**4 boundary. */ void -s_align_ptwo (ignore) +s_abort (ignore) int ignore; { - register int temp; - register long temp_fill; - long max_alignment = 15; + as_fatal (".abort detected. Abandoning ship."); +} - temp = get_absolute_expression (); - if (temp > max_alignment) - as_bad ("Alignment too large: %d. assumed.", temp = max_alignment); - else if (temp < 0) +/* 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, len, max) + int n; + char *fill; + int len; + int max; +{ + char default_fill; + +#ifdef md_do_align + md_do_align (n, fill, len, max, just_record_alignment); +#endif + + if (fill == NULL) { - as_bad ("Alignment negative. 0 assumed."); - temp = 0; + int maybe_text; + +#ifdef BFD_ASSEMBLER + if ((bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE) != 0) + maybe_text = 1; + else + maybe_text = 0; +#else + if (now_seg != data_section && now_seg != bss_section) + maybe_text = 1; + else + maybe_text = 0; +#endif + + if (maybe_text) + default_fill = NOP_OPCODE; + else + default_fill = 0; + fill = &default_fill; + len = 1; } - if (*input_line_pointer == ',') + + /* Only make a frag if we HAVE to. . . */ + if (n != 0 && !need_pass_2) { - input_line_pointer++; - temp_fill = get_absolute_expression (); + if (len <= 1) + frag_align (n, *fill, max); + else + frag_align_pattern (n, fill, len, max); } - /* @@ Fix this right for BFD! */ - else if (now_seg != data_section && now_seg != bss_section) - temp_fill = NOP_OPCODE; - else - temp_fill = 0; - /* Only make a frag if we HAVE to. . . */ - if (temp && !need_pass_2) - frag_align (temp, (int) temp_fill); - record_alignment (now_seg, temp); +#ifdef md_do_align + just_record_alignment: +#endif - demand_empty_rest_of_line (); -} /* s_align_ptwo() */ + record_alignment (now_seg, n); +} -void -s_comm (ignore) - int ignore; +/* 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 char *name; - register char c; - register char *p; - offsetT temp; - register symbolS *symbolP; + register unsigned int align; + char *stop = NULL; + char stopc; + offsetT fill = 0; + int max; + int fill_p; - 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 != ',') + if (flag_mri) + stop = mri_comment_field (&stopc); + + if (is_end_of_line[(unsigned char) *input_line_pointer]) { - as_bad ("Expected comma after symbol-name: rest of line ignored."); - ignore_rest_of_line (); - return; + if (arg < 0) + align = 0; + else + align = arg; /* Default value from pseudo-op table */ } - input_line_pointer++; /* skip ',' */ - if ((temp = get_absolute_expression ()) < 0) + else { - as_warn (".COMMon length (%ld.) <0! Ignored.", (long) temp); - ignore_rest_of_line (); - return; + align = get_absolute_expression (); + SKIP_WHITESPACE (); } - *p = 0; - symbolP = symbol_find_or_make (name); - *p = c; - if (S_IS_DEFINED (symbolP)) + + if (bytes_p) { - as_bad ("Ignoring attempt to re-define symbol"); - ignore_rest_of_line (); - return; + /* 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; + } } - if (S_GET_VALUE (symbolP)) + + if (align > 15) { - if (S_GET_VALUE (symbolP) != (valueT) temp) - as_bad ("Length of .comm \"%s\" is already %ld. Not changed to %ld.", - S_GET_NAME (symbolP), - (long) S_GET_VALUE (symbolP), - (long) temp); + align = 15; + as_bad ("Alignment too large: %u assumed", align); + } + + if (*input_line_pointer != ',') + { + fill_p = 0; + max = 0; + } + else + { + ++input_line_pointer; + if (*input_line_pointer == ',') + fill_p = 0; + else + { + fill = get_absolute_expression (); + SKIP_WHITESPACE (); + fill_p = 1; + } + + if (*input_line_pointer != ',') + max = 0; + else + { + ++input_line_pointer; + max = get_absolute_expression (); + } + } + + if (! fill_p) + { + if (arg < 0) + as_warn ("expected fill pattern missing"); + do_align (align, (char *) NULL, 0, max); + } + else + { + 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); + } + } + + 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 pseudo-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 *name; + register char c; + 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 (); + /* just after name is now '\0' */ + p = input_line_pointer; + *p = c; + SKIP_WHITESPACE (); + 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; + } + input_line_pointer++; /* skip ',' */ + 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; + } + *p = 0; + symbolP = symbol_find_or_make (name); + *p = c; + if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP)) + { + 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; + } + if (S_GET_VALUE (symbolP)) + { + if (S_GET_VALUE (symbolP) != (valueT) temp) + as_bad ("Length of .comm \"%s\" is already %ld. Not changed to %ld.", + S_GET_NAME (symbolP), + (long) S_GET_VALUE (symbolP), + (long) temp); } else { @@ -861,13 +1392,121 @@ s_comm (ignore) S_SET_EXTERNAL (symbolP); } #ifdef OBJ_VMS - if ( (!temp) || !flagseen['1']) - S_GET_OTHER(symbolP) = const_flag; + { + extern int flag_one; + if ( (!temp) || !flag_one) + S_GET_OTHER(symbolP) = const_flag; + } #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) && ! S_IS_COMMON (sym)) + { + 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; @@ -876,7 +1515,7 @@ s_data (ignore) register int temp; temp = get_absolute_expression (); - if (flagseen['R']) + if (flag_readonly_data_in_text) { section = text_section; temp += 1000; @@ -893,11 +1532,11 @@ s_data (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) @@ -912,25 +1551,35 @@ s_app_file (appfile) /* If this is a fake .appfile, a fake newline was inserted into the buffer. Passing -2 to new_logical_line tells it to account for it. */ - new_logical_line (s, appfile ? -2 : -1); + int may_omit + = (! new_logical_line (s, appfile ? -2 : -1) && appfile); + + /* 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 (); + if (! may_omit) + { #ifdef LISTING - if (listing) - listing_source_file (s); + if (listing) + listing_source_file (s); #endif - } -#ifdef OBJ_COFF - c_dot_file_symbol (s); -#endif /* OBJ_COFF */ -#ifdef OBJ_ELF - elf_file_symbol (s); + register_dependency (s); +#ifdef obj_app_file + obj_app_file (s); #endif + } + } } /* 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) @@ -940,11 +1589,72 @@ s_app_line (ignore) /* The given number is that of the next line. */ l = get_absolute_expression () - 1; - new_logical_line ((char *) NULL, l); + if (l < 0) + /* Some of the back ends can't deal with non-positive line numbers. + Besides, it's silly. */ + as_warn ("Line numbers must be positive; line number %d rejected.", l+1); + else + { + new_logical_line ((char *) NULL, l); #ifdef LISTING - if (listing) - listing_source_line (l); + if (listing) + listing_source_line (l); #endif + } + demand_empty_rest_of_line (); +} + +/* Handle the .end pseudo-op. Actually, the real work is done in + read_a_source_file. */ + +void +s_end (ignore) + int ignore; +{ + if (flag_mri) + { + /* 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"); + } +} + +/* 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 (); } @@ -957,6 +1667,9 @@ s_fill (ignore) 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 == ',') @@ -983,13 +1696,16 @@ s_fill (ignore) } else if (temp_repeat <= 0) { - as_warn ("Repeat < 0, .fill ignored"); + if (temp_repeat < 0) + as_warn ("Repeat < 0, .fill ignored"); temp_size = 0; } if (temp_size && !need_pass_2) { - p = frag_var (rs_fill, (int) temp_size, (int) temp_size, (relax_substateT) 0, (symbolS *) 0, temp_repeat, (char *) 0); + p = frag_var (rs_fill, (int) temp_size, (int) temp_size, + (relax_substateT) 0, (symbolS *) 0, (offsetT) temp_repeat, + (char *) 0); memset (p, 0, (unsigned int) temp_size); /* The magic number BSD_FILL_SIZE_CROCK_4 is from BSD 4.2 VAX * flavoured AS. The following bizzare behaviour is to be @@ -1016,6 +1732,11 @@ s_globl (ignore) char *name; int c; symbolS *symbolP; + char *stop = NULL; + char stopc; + + if (flag_mri) + stop = mri_comment_field (&stopc); do { @@ -1034,14 +1755,129 @@ s_globl (ignore) } } while (c == ','); + + if (flag_mri) + mri_comment_end (stop, stopc); + demand_empty_rest_of_line (); } -void -s_lcomm (needs_align) +/* 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 (); +} + +static void +s_lcomm_internal (needs_align, bytes_p) /* 1 if this was a ".bss" directive, which may require a 3rd argument (alignment); 0 if it was an ".lcomm" (2 args only) */ int needs_align; + /* 1 if the alignment value should be interpreted as the byte boundary, + rather than the power of 2. */ + int bytes_p; { register char *name; register char c; @@ -1059,15 +1895,15 @@ s_lcomm (needs_align) p = input_line_pointer; *p = c; SKIP_WHITESPACE (); - if (*input_line_pointer != ',') + + /* Accept an optional comma after the name. The comma used to be + required, but Irix 5 cc does not generate it. */ + if (*input_line_pointer == ',') { - as_bad ("Expected comma after name"); - ignore_rest_of_line (); - return; + ++input_line_pointer; + SKIP_WHITESPACE (); } - ++input_line_pointer; - if (*input_line_pointer == '\n') { as_bad ("Missing size expression"); @@ -1081,13 +1917,42 @@ s_lcomm (needs_align) return; } -#ifdef TC_MIPS -#ifdef OBJ_ECOFF - /* For MIPS ECOFF, small objects are put in .sbss. */ - if (temp <= bfd_get_gp_size (stdoutput)) - bss_seg = subseg_new (".sbss", 1); +#if defined (TC_MIPS) || defined (TC_ALPHA) + if (OUTPUT_FLAVOR == bfd_target_ecoff_flavour + || OUTPUT_FLAVOR == bfd_target_elf_flavour) + { + /* For MIPS and Alpha ECOFF or ELF, small objects are put in .sbss. */ + if (temp <= bfd_get_gp_size (stdoutput)) + { + 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 + if (!needs_align) + { + /* FIXME. This needs to be machine independent. */ + if (temp >= 8) + align = 3; + else if (temp >= 4) + align = 2; + else if (temp >= 2) + align = 1; + else + align = 0; + +#ifdef OBJ_EVAX + /* FIXME: This needs to be done in a more general fashion. */ + align = 3; +#endif + + record_alignment(bss_seg, align); + } if (needs_align) { @@ -1107,6 +1972,20 @@ s_lcomm (needs_align) return; } align = get_absolute_expression (); + if (bytes_p) + { + /* 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; + } + } if (align > max_alignment) { align = max_alignment; @@ -1119,6 +1998,18 @@ s_lcomm (needs_align) } record_alignment (bss_seg, align); } /* if needs align */ + else + { + /* Assume some objects may require alignment on some systems. */ +#if defined (TC_ALPHA) && ! defined (VMS) + if (temp > 1) + { + align = ffs (temp) - 1; + if (temp % (1 << align)) + abort (); + } +#endif + } *p = 0; symbolP = symbol_find_or_make (name); @@ -1137,143 +2028,594 @@ s_lcomm (needs_align) 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; symbolP->sy_frag = frag_now; pfrag = frag_var (rs_org, 1, 1, (relax_substateT)0, symbolP, - temp, (char *)0); + (offsetT) temp, (char *) 0); *pfrag = 0; S_SET_SEGMENT (symbolP, bss_seg); -#ifdef OBJ_COFF - /* The symbol may already have been created with a preceding - ".globl" directive -- be careful not to step on storage class - in that case. Otherwise, set it to static. */ - if (S_GET_STORAGE_CLASS (symbolP) != C_EXT) +#ifdef OBJ_COFF + /* The symbol may already have been created with a preceding + ".globl" directive -- be careful not to step on storage class + in that case. Otherwise, set it to static. */ + if (S_GET_STORAGE_CLASS (symbolP) != C_EXT) + { + 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'.", + S_GET_NAME (symbolP)); + + subseg_set (current_seg, current_subseg); + + demand_empty_rest_of_line (); +} /* s_lcomm_internal() */ + +void +s_lcomm (needs_align) + int needs_align; +{ + s_lcomm_internal (needs_align, 0); +} + +void s_lcomm_bytes (needs_align) + int needs_align; +{ + s_lcomm_internal (needs_align, 1); +} + +void +s_lsym (ignore) + int ignore; +{ + register char *name; + register char c; + register char *p; + expressionS exp; + register symbolS *symbolP; + + /* we permit ANY defined expression: BSD4.2 demands constants */ + name = input_line_pointer; + c = get_symbol_end (); + p = input_line_pointer; + *p = c; + SKIP_WHITESPACE (); + if (*input_line_pointer != ',') + { + *p = 0; + as_bad ("Expected comma after name \"%s\"", name); + *p = c; + ignore_rest_of_line (); + return; + } + input_line_pointer++; + expression (&exp); + if (exp.X_op != O_constant + && exp.X_op != O_register) + { + as_bad ("bad expression"); + ignore_rest_of_line (); + return; + } + *p = 0; + symbolP = symbol_find_or_make (name); + + /* FIXME-SOON I pulled a (&& symbolP->sy_other == 0 && + symbolP->sy_desc == 0) out of this test because coff doesn't have + those fields, and I can't see when they'd ever be tripped. I + don't think I understand why they were here so I may have + introduced a bug. As recently as 1.37 didn't have this test + anyway. xoxorich. */ + + if (S_GET_SEGMENT (symbolP) == undefined_section + && S_GET_VALUE (symbolP) == 0) + { + /* The name might be an undefined .global symbol; be sure to + keep the "external" bit. */ + S_SET_SEGMENT (symbolP, + (exp.X_op == O_constant + ? absolute_section + : reg_section)); + S_SET_VALUE (symbolP, (valueT) exp.X_add_number); + } + else + { + as_bad ("Symbol %s already defined", name); + } + *p = c; + 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 + && is_end_of_line[(unsigned char) *input_line_pointer]) + { + 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; +{ + cond_exit_macro (macro_nest); + 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; + + /* 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. + + 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 { - S_SET_STORAGE_CLASS (symbolP, C_STAT); + as_warn ("unrecognized section command `%s'", seccmd); + *input_line_pointer = c; } -#endif /* OBJ_COFF */ - } - else - { - as_bad ("Ignoring attempt to re-define symbol %s.", name); } - subseg_set (current_seg, current_subseg); + demand_empty_rest_of_line (); - demand_empty_rest_of_line (); -} /* s_lcomm() */ +#else /* ! TC_I960 */ + /* The MRI assembler seems to use different forms of .sect for + different targets. */ + abort (); +#endif /* ! TC_I960 */ +#endif /* ! TC_M68K */ +} -void -s_lsym (ignore) +/* Handle the .print pseudo-op. */ + +void +s_print (ignore) int ignore; { - register char *name; - register char c; - register char *p; - expressionS exp; - register symbolS *symbolP; + char *s; + int len; - /* we permit ANY defined expression: BSD4.2 demands constants */ - name = input_line_pointer; - c = get_symbol_end (); - p = input_line_pointer; - *p = c; - SKIP_WHITESPACE (); - if (*input_line_pointer != ',') - { - *p = 0; - as_bad ("Expected comma after name \"%s\"", name); - *p = c; - ignore_rest_of_line (); - return; - } - input_line_pointer++; - expression (&exp); - if (exp.X_op != O_constant - && exp.X_op != O_register) - { - as_bad ("bad expression"); - ignore_rest_of_line (); - return; - } - *p = 0; - symbolP = symbol_find_or_make (name); + s = demand_copy_C_string (&len); + printf ("%s\n", s); + demand_empty_rest_of_line (); +} - /* FIXME-SOON I pulled a (&& symbolP->sy_other == 0 && - symbolP->sy_desc == 0) out of this test because coff doesn't have - those fields, and I can't see when they'd ever be tripped. I - don't think I understand why they were here so I may have - introduced a bug. As recently as 1.37 didn't have this test - anyway. xoxorich. */ +/* Handle the .purgem pseudo-op. */ - if (S_GET_SEGMENT (symbolP) == undefined_section - && S_GET_VALUE (symbolP) == 0) +void +s_purgem (ignore) + int ignore; +{ + if (is_it_end_of_statement ()) { - /* The name might be an undefined .global symbol; be sure to - keep the "external" bit. */ - S_SET_SEGMENT (symbolP, - (exp.X_op == O_constant - ? absolute_section - : reg_section)); - S_SET_VALUE (symbolP, (valueT) exp.X_add_number); + demand_empty_rest_of_line (); + return; } - else + + do { - as_bad ("Symbol %s already defined", name); + char *name; + char c; + + SKIP_WHITESPACE (); + name = input_line_pointer; + c = get_symbol_end (); + delete_macro (name); + *input_line_pointer = c; + SKIP_WHITESPACE (); } - *p = c; + while (*input_line_pointer++ == ','); + + --input_line_pointer; demand_empty_rest_of_line (); -} /* s_lsym() */ +} -void -s_org (ignore) +/* Handle the .rept pseudo-op. */ + +void +s_rept (ignore) int ignore; { - register segT segment; - expressionS exp; - register long temp_fill; - register char *p; - /* 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. + int count; + sb one; + sb many; - 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. + count = get_absolute_expression (); - Don't make frag if need_pass_2==1. */ - segment = get_known_segmented_expression (&exp); - if (*input_line_pointer == ',') + 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); +} + +/* Handle the .equ, .equiv and .set directives. If EQUIV is 1, then + this is .equiv, and it is an error if the symbol is already + defined. */ void -s_set (ignore) - int ignore; +s_set (equiv) + int equiv; { register char *name; register char delim; @@ -1308,20 +2650,11 @@ 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; @@ -1341,6 +2674,12 @@ s_set (ignore) symbol_table_insert (symbolP); *end_name = delim; + + if (equiv + && S_IS_DEFINED (symbolP) + && S_GET_SEGMENT (symbolP) != reg_section) + as_bad ("symbol `%s' already defined", S_GET_NAME (symbolP)); + pseudo_set (symbolP); demand_empty_rest_of_line (); } /* s_set() */ @@ -1349,38 +2688,264 @@ void s_space (mult) int mult; { - long temp_repeat; - register long temp_fill; - register char *p; + expressionS exp; + 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 */ - if (get_absolute_expression_and_terminator (&temp_repeat) == ',') + 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) { - temp_fill = get_absolute_expression (); + 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; + + 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 + { + 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 ()); + } + } + } + + bytes = mult; + + expression (&exp); + + SKIP_WHITESPACE (); + if (*input_line_pointer == ',') + { + ++input_line_pointer; + expression (&val); } else { - input_line_pointer--; /* Backup over what was not a ','. */ - temp_fill = 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); + } } - if (mult) + else { - temp_repeat *= mult; + 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, + (offsetT) 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), (offsetT) 0, (char *) 0); + } + + if (p) + *p = val.X_add_number; } - if (temp_repeat <= 0) + + 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_warn ("Repeat < 0, .space ignored"); + as_bad ("missing value"); + if (flag_mri) + mri_comment_end (stop, stopc); ignore_rest_of_line (); return; } - if (!need_pass_2) + + ++input_line_pointer; + + SKIP_WHITESPACE (); + + /* 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] == ':') + { + flen = hex_float (float_type, temp); + if (flen < 0) + { + if (flag_mri) + mri_comment_end (stop, stopc); + ignore_rest_of_line (); + return; + } + } + else + { + 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; + } + } + + while (--count >= 0) { - p = frag_var (rs_fill, 1, 1, (relax_substateT) 0, (symbolS *) 0, - temp_repeat, (char *) 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 (); -} /* s_space() */ +} void s_text (ignore) @@ -1391,6 +2956,9 @@ s_text (ignore) temp = get_absolute_expression (); subseg_set (text_section, (subsegT) temp); demand_empty_rest_of_line (); +#ifdef OBJ_VMS + const_flag &= ~IN_DEFAULT_SECTION; +#endif } /* s_text() */ @@ -1445,13 +3013,12 @@ pseudo_set (symbolP) symbolS *symbolP; { expressionS exp; -#if defined(OBJ_AOUT) | defined(OBJ_BOUT) +#if (defined (OBJ_AOUT) || defined (OBJ_BOUT)) && ! defined (BFD_ASSEMBLER) int ext; #endif /* OBJ_AOUT or OBJ_BOUT */ know (symbolP); /* NULL pointer is logic error. */ -#if defined(OBJ_AOUT) | defined(OBJ_BOUT) - /* @@ Fix this right for BFD. */ +#if (defined (OBJ_AOUT) || defined (OBJ_BOUT)) && ! defined (BFD_ASSEMBLER) ext = S_IS_EXTERNAL (symbolP); #endif /* OBJ_AOUT or OBJ_BOUT */ @@ -1484,8 +3051,7 @@ pseudo_set (symbolP) /* Fall through. */ case O_constant: S_SET_SEGMENT (symbolP, absolute_section); -#if defined(OBJ_AOUT) | defined(OBJ_BOUT) - /* @@ Fix this right for BFD. */ +#if (defined (OBJ_AOUT) || defined (OBJ_BOUT)) && ! defined (BFD_ASSEMBLER) if (ext) S_SET_EXTERNAL (symbolP); else @@ -1502,21 +3068,24 @@ pseudo_set (symbolP) break; case O_symbol: - if (S_GET_SEGMENT (exp.X_add_symbol) == undefined_section) + if (S_GET_SEGMENT (exp.X_add_symbol) == undefined_section + || exp.X_add_number != 0) symbolP->sy_value = exp; else { - S_SET_SEGMENT (symbolP, S_GET_SEGMENT (exp.X_add_symbol)); -#if defined(OBJ_AOUT) | defined(OBJ_BOUT) - /* @@ Fix this right for BFD! */ + symbolS *s = exp.X_add_symbol; + + S_SET_SEGMENT (symbolP, S_GET_SEGMENT (s)); +#if (defined (OBJ_AOUT) || defined (OBJ_BOUT)) && ! defined (BFD_ASSEMBLER) if (ext) S_SET_EXTERNAL (symbolP); else S_CLEAR_EXTERNAL (symbolP); #endif /* OBJ_AOUT or OBJ_BOUT */ S_SET_VALUE (symbolP, - exp.X_add_number + S_GET_VALUE (exp.X_add_symbol)); - symbolP->sy_frag = exp.X_add_symbol->sy_frag; + exp.X_add_number + S_GET_VALUE (s)); + symbolP->sy_frag = s->sy_frag; + copy_symbol_attributes (symbolP, s); } break; @@ -1553,17 +3122,15 @@ pseudo_set (symbolP) 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 @@ -1579,28 +3146,84 @@ parse_repeat_cons PARAMS ((expressionS *exp, unsigned int nbytes)); /* 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 (); -} /* cons() */ +} + + +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. */ @@ -1618,8 +3241,42 @@ emit_expr (exp, nbytes) if (need_pass_2) return; +#ifndef NO_LISTING +#ifdef OBJ_ELF + /* When gcc emits DWARF 1 debugging pseudo-ops, a line number will + appear as a four byte positive constant in the .line section, + followed by a 2 byte 0xffff. Look for that case here. */ + { + static int dwarf_line = -1; + + if (strcmp (segment_name (now_seg), ".line") != 0) + dwarf_line = -1; + else if (dwarf_line >= 0 + && nbytes == 2 + && exp->X_op == O_constant + && (exp->X_add_number == -1 || exp->X_add_number == 0xffff)) + listing_source_line ((unsigned int) dwarf_line); + else if (nbytes == 4 + && exp->X_op == O_constant + && exp->X_add_number >= 0) + dwarf_line = exp->X_add_number; + else + dwarf_line = -1; + } +#endif +#endif + 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 @@ -1717,17 +3374,28 @@ emit_expr (exp, nbytes) if (op == O_constant) { - register long get; - register long use; - register long mask; - register long unmask; + 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 (long)) - mask = 0; + if (nbytes >= sizeof (valueT)) + { + mask = 0; + if (nbytes > sizeof (valueT)) + hibit = 0; + else + hibit = (valueT) 1 << (nbytes * BITS_PER_CHAR - 1); + } else - mask = ~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. */ @@ -1738,12 +3406,15 @@ emit_expr (exp, nbytes) 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, (valueT) use, (int) nbytes); + md_number_to_chars (p, use, (int) nbytes); } else if (op == O_big) { @@ -1799,7 +3470,7 @@ emit_expr (exp, nbytes) } else { - md_number_to_chars (p, (valueT) 0, (int) nbytes); + memset (p, 0, nbytes); /* Now we need to generate a fixS to record the symbol value. This is easy for BFD. For other targets it can be more @@ -1814,11 +3485,31 @@ emit_expr (exp, 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 @@ -1889,7 +3580,7 @@ parse_bitfield_cons (exp, nbytes) widths, positions, and masks which most of our current object formats don't support. - + In the specific case where a symbol *is* defined in this assembly, we *could* build fixups and track it, but @@ -1966,20 +3657,34 @@ parse_bitfield_cons (exp, nbytes) #endif /* BITFIELD_CONS_EXPRESSIONS */ -#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++) { @@ -2015,11 +3720,7 @@ parse_mri_cons (exp, nbytes) else input_line_pointer++; } - else - expression (&exp); } - -#endif /* MRI */ #ifdef REPEAT_CONS_EXPRESSIONS @@ -2062,6 +3763,97 @@ parse_repeat_cons (exp, nbytes) #endif /* REPEAT_CONS_EXPRESSIONS */ +/* 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() * @@ -2094,69 +3886,388 @@ float_cons (float_type) if (is_it_end_of_statement ()) { - demand_empty_rest_of_line (); - return; + demand_empty_rest_of_line (); + return; + } + +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + + do + { + /* input_line_pointer->1st char of a flonum (we hope!). */ + SKIP_WHITESPACE (); + + /* Skip any 0{letter} that may be present. Don't even check if the + * letter is legal. Someone may invent a "z" format and this routine + * has no use for such information. Lusers beware: you get + * diagnostics if your input is ill-conditioned. + */ + 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; + 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) + { + int count; + + count = 1; + +#ifdef REPEAT_CONS_EXPRESSIONS + if (*input_line_pointer == ':') + { + expressionS count_exp; + + ++input_line_pointer; + expression (&count_exp); + if (count_exp.X_op != O_constant + || count_exp.X_add_number <= 0) + { + as_warn ("unresolvable or nonpositive repeat count; using 1"); + } + else + count = count_exp.X_add_number; + } +#endif + + while (--count >= 0) + { + p = frag_more (length); + memcpy (p, temp, (unsigned int) length); + } + } + SKIP_WHITESPACE (); + } + while (*input_line_pointer++ == ','); + + --input_line_pointer; /* Put terminator back into stream. */ + demand_empty_rest_of_line (); +} /* float_cons() */ + +/* Return the size of a LEB128 value */ + +static inline int +sizeof_sleb128 (value) + offsetT value; +{ + register int size = 0; + register unsigned byte; + + do + { + byte = (value & 0x7f); + /* Sadly, we cannot rely on typical arithmetic right shift behaviour. + Fortunately, we can structure things so that the extra work reduces + to a noop on systems that do things "properly". */ + value = (value >> 7) | ~(-(offsetT)1 >> 7); + size += 1; + } + while (!(((value == 0) && ((byte & 0x40) == 0)) + || ((value == -1) && ((byte & 0x40) != 0)))); + + return size; +} + +static inline int +sizeof_uleb128 (value) + valueT value; +{ + register int size = 0; + register unsigned byte; + + do + { + byte = (value & 0x7f); + value >>= 7; + size += 1; + } + while (value != 0); + + return size; +} + +inline int +sizeof_leb128 (value, sign) + valueT value; + int sign; +{ + if (sign) + return sizeof_sleb128 ((offsetT) value); + else + return sizeof_uleb128 (value); +} + +/* Output a LEB128 value. */ + +static inline int +output_sleb128 (p, value) + char *p; + offsetT value; +{ + register char *orig = p; + register int more; + + do + { + unsigned byte = (value & 0x7f); + + /* Sadly, we cannot rely on typical arithmetic right shift behaviour. + Fortunately, we can structure things so that the extra work reduces + to a noop on systems that do things "properly". */ + value = (value >> 7) | ~(-(offsetT)1 >> 7); + + more = !((((value == 0) && ((byte & 0x40) == 0)) + || ((value == -1) && ((byte & 0x40) != 0)))); + if (more) + byte |= 0x80; + + *p++ = byte; + } + while (more); + + return p - orig; +} + +static inline int +output_uleb128 (p, value) + char *p; + valueT value; +{ + char *orig = p; + + do + { + unsigned byte = (value & 0x7f); + value >>= 7; + if (value != 0) + /* More bytes to follow. */ + byte |= 0x80; + + *p++ = byte; + } + while (value != 0); + + return p - orig; +} + +inline int +output_leb128 (p, value, sign) + char *p; + valueT value; + int sign; +{ + if (sign) + return output_sleb128 (p, (offsetT) value); + else + return output_uleb128 (p, value); +} + +/* Do the same for bignums. We combine sizeof with output here in that + we don't output for NULL values of P. It isn't really as critical as + for "normal" values that this be streamlined. */ + +static int +output_big_sleb128 (p, bignum, size) + char *p; + LITTLENUM_TYPE *bignum; + int size; +{ + char *orig = p; + valueT val; + int loaded = 0; + unsigned byte; + + /* Strip leading sign extensions off the bignum. */ + while (size > 0 && bignum[size-1] == (LITTLENUM_TYPE)-1) + size--; + + do + { + if (loaded < 7 && size > 0) + { + val |= (*bignum << loaded); + loaded += 8 * CHARS_PER_LITTLENUM; + size--; + bignum++; + } + + byte = val & 0x7f; + loaded -= 7; + val >>= 7; + + if (size == 0) + { + if ((val == 0 && (byte & 0x40) == 0) + || (~(val | ~(((valueT)1 << loaded) - 1)) == 0 + && (byte & 0x40) != 0)) + byte |= 0x80; + } + + if (orig) + *p = byte; + p++; + } + while (byte & 0x80); + + return p - orig; +} + +static int +output_big_uleb128 (p, bignum, size) + char *p; + LITTLENUM_TYPE *bignum; + int size; +{ + char *orig = p; + valueT val; + int loaded = 0; + unsigned byte; + + /* Strip leading zeros off the bignum. */ + /* XXX: Is this needed? */ + while (size > 0 && bignum[size-1] == 0) + size--; + + do + { + if (loaded < 7 && size > 0) + { + val |= (*bignum << loaded); + loaded += 8 * CHARS_PER_LITTLENUM; + size--; + bignum++; + } + + byte = val & 0x7f; + loaded -= 7; + val >>= 7; + + if (size > 0 || val) + byte |= 0x80; + + if (orig) + *p = byte; + p++; + } + while (byte & 0x80); + + return p - orig; +} + +static inline int +output_big_leb128 (p, bignum, size, sign) + char *p; + LITTLENUM_TYPE *bignum; + int size, sign; +{ + if (sign) + return output_big_sleb128 (p, bignum, size); + else + return output_big_uleb128 (p, bignum, size); +} + +/* Generate the appropriate fragments for a given expression to emit a + leb128 value. */ + +void +emit_leb128_expr(exp, sign) + expressionS *exp; + int sign; +{ + operatorT op = exp->X_op; + + if (op == O_absent || op == O_illegal) + { + as_warn ("zero assumed for missing expression"); + exp->X_add_number = 0; + op = O_constant; + } + else if (op == O_big && exp->X_add_number <= 0) + { + as_bad ("floating point number invalid; zero assumed"); + exp->X_add_number = 0; + op = O_constant; + } + else if (op == O_register) + { + as_warn ("register value used as expression"); + op = O_constant; } - do + if (op == O_constant) { - /* input_line_pointer->1st char of a flonum (we hope!). */ - SKIP_WHITESPACE (); + /* If we've got a constant, emit the thing directly right now. */ - /* Skip any 0{letter} that may be present. Don't even check if the - * letter is legal. Someone may invent a "z" format and this routine - * has no use for such information. Lusers beware: you get - * diagnostics if your input is ill-conditioned. - */ - if (input_line_pointer[0] == '0' && isalpha (input_line_pointer[1])) - input_line_pointer += 2; + valueT value = exp->X_add_number; + int size; + char *p; - 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; - } + size = sizeof_leb128 (value, sign); + p = frag_more (size); + output_leb128 (p, value, sign); + } + else if (op == O_big) + { + /* O_big is a different sort of constant. */ - if (!need_pass_2) - { - int count; + int size; + char *p; - count = 1; + size = output_big_leb128 (NULL, generic_bignum, exp->X_add_number, sign); + p = frag_more (size); + output_big_leb128 (p, generic_bignum, exp->X_add_number, sign); + } + else + { + /* Otherwise, we have to create a variable sized fragment and + resolve things later. */ -#ifdef REPEAT_CONS_EXPRESSIONS - if (*input_line_pointer == ':') - { - expressionS count_exp; + frag_var (rs_leb128, sizeof_uleb128 (~(valueT)0), 0, sign, + make_expr_symbol (exp), 0, (char *) NULL); + } +} - ++input_line_pointer; - expression (&count_exp); - if (count_exp.X_op != O_constant - || count_exp.X_add_number <= 0) - { - as_warn ("unresolvable or nonpositive repeat count; using 1"); - } - else - count = count_exp.X_add_number; - } -#endif +/* Parse the .sleb128 and .uleb128 pseudos. */ - while (--count >= 0) - { - p = frag_more (length); - memcpy (p, temp, (unsigned int) length); - } - } - SKIP_WHITESPACE (); - } - while (*input_line_pointer++ == ','); +void +s_leb128 (sign) + int sign; +{ + expressionS exp; - --input_line_pointer; /* Put terminator back into stream. */ + do { + expression (&exp); + emit_leb128_expr (&exp, sign); + } while (*input_line_pointer++ == ','); + + input_line_pointer--; demand_empty_rest_of_line (); -} /* float_cons() */ +} /* * stringer() @@ -2173,6 +4284,11 @@ stringer (append_zero) /* Worker to do .ascii etc statements. */ register int append_zero; /* 0: don't append '\0', else 1 */ { register unsigned int c; + char *start; + +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif /* * The following awkward logic is to parse ZERO or more strings, @@ -2198,6 +4314,7 @@ stringer (append_zero) /* Worker to do .ascii etc statements. */ { case '\"': ++input_line_pointer; /*->1st char of string. */ + start = input_line_pointer; while (is_a_char (c = next_char_of_string ())) { FRAG_APPEND_1_CHAR (c); @@ -2207,6 +4324,24 @@ stringer (append_zero) /* Worker to do .ascii etc statements. */ FRAG_APPEND_1_CHAR (0); } know (input_line_pointer[-1] == '\"'); + +#ifndef NO_LISTING +#ifdef OBJ_ELF + /* In ELF, when gcc is emitting DWARF 1 debugging output, it + will emit .string with a filename in the .debug_sfnames + section to indicate a file name. I don't know if this + will work for compilers other than gcc, and I don't know + if it will work for DWARF 2. */ + if (strcmp (segment_name (now_seg), ".debug_sfnames") == 0) + { + c = input_line_pointer[-1]; + input_line_pointer[-1] = '\0'; + listing_source_file (start); + input_line_pointer[-1] = c; + } +#endif +#endif + break; case '<': input_line_pointer++; @@ -2246,6 +4381,12 @@ next_char_of_string () 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++) { @@ -2269,11 +4410,9 @@ next_char_of_string () c = '\t'; break; -#ifdef BACKSLASH_V case 'v': c = '\013'; break; -#endif case '\\': case '"': @@ -2328,6 +4467,7 @@ next_char_of_string () /* 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: @@ -2340,6 +4480,7 @@ next_char_of_string () break; } /* switch on escaped char */ break; +#endif /* ! defined (NO_STRING_ESCAPES) */ default: break; @@ -2399,7 +4540,7 @@ get_absolute_expression () if (exp.X_op != O_constant) { if (exp.X_op != O_absent) - as_bad ("bad absolute expression; zero assumed"); + as_bad ("bad or irreducible absolute expression; zero assumed"); exp.X_add_number = 0; } return exp.X_add_number; @@ -2430,9 +4571,7 @@ demand_copy_C_string (len_pointer) { register int len; - for (len = *len_pointer; - len > 0; - len--) + for (len = *len_pointer; len > 0; len--) { if (*s == 0) { @@ -2443,7 +4582,7 @@ demand_copy_C_string (len_pointer) } } } - return (s); + return s; } /* @@ -2452,7 +4591,7 @@ demand_copy_C_string (len_pointer) * Demand string, but return a safe (=private) copy of the string. * Return NULL if we can't read a string here. */ -static char * +char * demand_copy_string (lenP) int *lenP; { @@ -2471,8 +4610,8 @@ demand_copy_string (lenP) 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); } @@ -2503,10 +4642,13 @@ is_it_end_of_statement () } /* 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 == '=') @@ -2515,30 +4657,32 @@ equals (sym_name) 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. */ @@ -2554,7 +4698,25 @@ s_include (arg) 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++) @@ -2572,6 +4734,7 @@ s_include (arg) path = filename; gotit: /* malloc Storage leak when file is found on path. FIXME-SOMEDAY. */ + register_dependency (path); newbuf = input_scrub_include_file (path, input_line_pointer); buffer_limit = input_scrub_next_buffer (&input_line_pointer); } /* s_include() */ @@ -2611,354 +4774,14 @@ s_ignore (arg) ++input_line_pointer; } ++input_line_pointer; - - return; -} /* s_ignore() */ - -/* - * Handle .stabX directives, which used to be open-coded. - * So much creeping featurism overloaded the semantics that we decided - * to put all .stabX thinking in one place. Here. - * - * We try to make any .stabX directive legal. Other people's AS will often - * do assembly-time consistency checks: eg assigning meaning to n_type bits - * and "protecting" you from setting them to certain values. (They also zero - * certain bits before emitting symbols. Tut tut.) - * - * If an expression is not absolute we either gripe or use the relocation - * information. Other people's assemblers silently forget information they - * don't need and invent information they need that you didn't supply. - */ - -/* - * Build a string dictionary entry for a .stabX symbol. - * The symbol is added to the .str section. - */ - -#ifdef SEPARATE_STAB_SECTIONS - -unsigned int -get_stab_string_offset (string, stabstr_secname) - const char *string; - const char *stabstr_secname; -{ - unsigned int length; - unsigned int retval; - - retval = 0; - length = strlen (string); - if (length > 0) - { /* Ordinary case. */ - segT save_seg; - subsegT save_subseg; - char *newsecname; - segT seg; - int aligned; - char *p; - - save_seg = now_seg; - save_subseg = now_subseg; - - /* Create the stab string section. */ - newsecname = xmalloc ((unsigned long) (strlen (stabstr_secname) + 1)); - strcpy (newsecname, stabstr_secname); - - seg = subseg_new (newsecname, 0); - - retval = seg_info (seg)->stabu.stab_string_size; - if (retval > 0) - free (newsecname); - else - { - /* Make sure the first string is empty. */ - p = frag_more (1); - *p = 0; - retval = seg_info (seg)->stabu.stab_string_size = 1; -#ifdef BFD_ASSEMBLER - bfd_set_section_flags (stdoutput, seg, SEC_READONLY); -#else - free (newsecname); -#endif - } - - p = frag_more (length + 1); - strcpy (p, string); - - seg_info (seg)->stabu.stab_string_size += length + 1; - - subseg_set (save_seg, save_subseg); - } - - return retval; -} - -#endif /* SEPARATE_STAB_SECTIONS */ - -/* This can handle different kinds of stabs (s,n,d) and different - kinds of stab sections. */ - -static void -s_stab_generic (what, stab_secname, stabstr_secname) - int what; - char *stab_secname; - char *stabstr_secname; -{ - long longint; - char *string; - int type; - int other; - int desc; - - /* The general format is: - .stabs "STRING",TYPE,OTHER,DESC,VALUE - .stabn TYPE,OTHER,DESC,VALUE - .stabd TYPE,OTHER,DESC - At this point input_line_pointer points after the pseudo-op and - any trailing whitespace. The argument what is one of 's', 'n' or - 'd' indicating which type of .stab this is. */ - - if (what != 's') - string = ""; - else - { - int length; - - string = demand_copy_C_string (&length); - SKIP_WHITESPACE (); - if (*input_line_pointer == ',') - input_line_pointer++; - else - { - as_warn (".stabs: Missing comma"); - ignore_rest_of_line (); - return; - } - } - - if (get_absolute_expression_and_terminator (&longint) != ',') - { - as_warn (".stab%c: Missing comma", what); - ignore_rest_of_line (); - return; - } - type = longint; - - if (get_absolute_expression_and_terminator (&longint) != ',') - { - as_warn (".stab%c: Missing comma", what); - ignore_rest_of_line (); - return; - } - other = longint; - - desc = get_absolute_expression (); - if (what == 's' || what == 'n') - { - if (*input_line_pointer != ',') - { - as_warn (".stab%c: Missing comma", what); - ignore_rest_of_line (); - return; - } - input_line_pointer++; - SKIP_WHITESPACE (); - } - - /* We have not gathered the type, other, and desc information. For - .stabs or .stabn, input_line_pointer is now pointing at the - value. */ - -#ifdef SEPARATE_STAB_SECTIONS - /* Output the stab information in a separate section. This is used - at least for COFF and ELF. */ - { - segT saved_seg = now_seg; - subsegT saved_subseg = now_subseg; - fragS *saved_frag = frag_now; - valueT dot; - segT seg; - unsigned int stroff; - char *p; - - dot = frag_now_fix (); - - seg = subseg_new (stab_secname, 0); - - if (! seg_info (seg)->hadone) - { -#ifdef BFD_ASSEMBLER - bfd_set_section_flags (stdoutput, seg, SEC_READONLY | SEC_RELOC); -#endif -#ifdef INIT_STAB_SECTION - INIT_STAB_SECTION (seg); -#endif - seg_info (seg)->hadone = 1; - } - - stroff = get_stab_string_offset (string, stabstr_secname); - - /* At least for now, stabs in a special stab section are always - output as 12 byte blocks of information. */ - p = frag_more (8); - md_number_to_chars (p, (valueT) stroff, 4); - md_number_to_chars (p + 4, (valueT) type, 1); - md_number_to_chars (p + 5, (valueT) other, 1); - md_number_to_chars (p + 6, (valueT) desc, 2); - - if (what == 's' || what == 'n') - { - /* Pick up the value from the input line. */ - cons (4); - input_line_pointer--; - } - else - { - const char *fake; - symbolS *symbol; - expressionS exp; - - /* Arrange for a value representing the current location. */ - fake = FAKE_LABEL_NAME; - symbol = symbol_new (fake, saved_seg, dot, saved_frag); - - exp.X_op = O_symbol; - exp.X_add_symbol = symbol; - exp.X_add_number = 0; - - emit_expr (&exp, 4); - } - -#ifdef OBJ_PROCESS_STAB - OBJ_PROCESS_STAB (seg, string, stroff, type, other, desc); -#endif - - subseg_set (saved_seg, saved_subseg); - } -#else /* ! SEPARATE_STAB_SECTIONS */ -#ifdef OBJ_PROCESS_STAB - OBJ_PROCESS_STAB (what, string, type, other, desc); -#else - /* Put the stab information in the symbol table. */ - { - symbolS *symbol; - - symbol = symbol_new (string, undefined_section, 0, - (struct frag *) NULL); - if (what == 's' || what == 'n') - { - /* Pick up the value from the input line. */ - symbol->sy_frag = &zero_address_frag; - pseudo_set (symbol); - } - else - { - /* .stabd sets the name to NULL. Why? */ - S_SET_NAME (symbol, NULL); - symbol->sy_frag = frag_now; - S_SET_VALUE (symbol, (valueT) frag_now_fix ()); - } - - S_SET_TYPE (symbol, type); - S_SET_OTHER (symbol, other); - S_SET_DESC (symbol, desc); - } -#endif /* ! OBJ_PROCESS_STAB */ -#endif /* ! SEPARATE_STAB_SECTIONS */ - -#ifndef NO_LISTING - if (listing) - { - switch (type) - { - case N_SLINE: - listing_source_line ((unsigned int) desc); - break; - case N_SO: - case N_SOL: - listing_source_file (string); - break; - } - } -#endif /* ! NO_LISTING */ - - demand_empty_rest_of_line (); -} - -/* Regular stab directive. */ - -void -s_stab (what) - int what; -{ - s_stab_generic (what, STAB_SECTION_NAME, STAB_STRING_SECTION_NAME); } -/* "Extended stabs", used in Solaris only now. */ void -s_xstab (what) - int what; +read_print_statistics (file) + FILE *file; { - int length; - char *stab_secname, *stabstr_secname; - - stab_secname = demand_copy_C_string (&length); - SKIP_WHITESPACE (); - if (*input_line_pointer == ',') - input_line_pointer++; - else - { - as_bad ("comma missing in .xstabs"); - ignore_rest_of_line (); - return; - } - - /* To get the name of the stab string section, simply .str to - the stab section name. */ - stabstr_secname = alloca (strlen (stab_secname) + 4); - strcpy (stabstr_secname, stab_secname); - strcat (stabstr_secname, "str"); - s_stab_generic (what, stab_secname, stabstr_secname); + hash_print_statistics (file, "pseudo-op table", po_hash); } -#ifdef S_SET_DESC - -/* Frob invented at RMS' request. Set the n_desc of a symbol. */ - -void -s_desc (ignore) - int ignore; -{ - char *name; - char c; - char *p; - symbolS *symbolP; - int temp; - - name = input_line_pointer; - c = get_symbol_end (); - p = input_line_pointer; - *p = c; - SKIP_WHITESPACE (); - if (*input_line_pointer != ',') - { - *p = 0; - as_bad ("Expected comma after name \"%s\"", name); - *p = c; - ignore_rest_of_line (); - } - else - { - input_line_pointer++; - temp = get_absolute_expression (); - *p = 0; - symbolP = symbol_find_or_make (name); - *p = c; - S_SET_DESC (symbolP, temp); - } - demand_empty_rest_of_line (); -} /* s_desc() */ - -#endif /* defined (S_SET_DESC) */ - /* end of read.c */