X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;ds=sidebyside;f=gas%2Fread.c;h=b64203b5959a037fa919640e15799ba61ad07ead;hb=a9af5e04811eb19756c41a5e287973efd87e7f5a;hp=e1f1a077a0c0f846712f0674035446df65bf9666;hpb=a920b69312e45b31e5b005985c617f539459bf24;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/read.c b/gas/read.c index e1f1a077a0..b64203b595 100644 --- a/gas/read.c +++ b/gas/read.c @@ -1,5 +1,5 @@ /* read.c - read a source file - - Copyright (C) 1986, 1987, 1990, 1991, 1993, 1994 + Copyright (C) 1986, 87, 90, 91, 92, 93, 94, 95, 96, 97, 98, 1999 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -15,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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +along with GAS; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ #if 0 #define MASK_CHAR (0xFF) /* If your chars aren't 8 bits, you will @@ -42,9 +43,11 @@ the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307 #include "as.h" #include "subsegs.h" -#include "libiberty.h" +#include "sb.h" +#include "macro.h" #include "obstack.h" #include "listing.h" +#include "ecoff.h" #ifndef TC_START_LABEL #define TC_START_LABEL(x,y) (x==':') @@ -60,8 +63,6 @@ the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307 char *input_line_pointer; /*->next char of source file to parse. */ -int generate_asm_lineno = 0; /* flag to generate line stab for .s file */ - #if BITS_PER_CHAR != 8 /* The following table is indexed by[(char)] and will break if a char does not have exactly 256 states (hopefully 0:255!)! */ @@ -83,24 +84,44 @@ die horribly; #define LEX_PCT 0 #endif +#ifndef LEX_QM +/* The PowerPC Windows NT assemblers permits ? inside label names. */ +#define LEX_QM 0 +#endif + +#ifndef LEX_HASH +#define LEX_HASH 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[] */ char lex_type[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ABCDEFGHIJKLMNO */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* PQRSTUVWXYZ[\]^_ */ - 0, 0, 0, 0, 3, LEX_PCT, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, /* _!"#$%&'()*+,-./ */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 0123456789:;<=>? */ + 0, 0, 0, LEX_HASH, LEX_DOLLAR, LEX_PCT, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, /* _!"#$%&'()*+,-./ */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, LEX_QM, /* 0123456789:;<=>? */ LEX_AT, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* @ABCDEFGHIJKLMNO */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, LEX_BR, 0, LEX_BR, 0, 3, /* PQRSTUVWXYZ[\]^_ */ 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* `abcdefghijklmno */ - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, LEX_BR, 0, LEX_BR, 0, 0, /* pqrstuvwxyz{|}~. */ - 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, - 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, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, LEX_BR, 0, LEX_BR, LEX_TILDE, 0, /* pqrstuvwxyz{|}~. */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }; @@ -108,61 +129,53 @@ char lex_type[256] = * In: a character. * Out: 1 if this character ends a line. */ -#define _ (0) +#define Z_ (0) char is_end_of_line[256] = { #ifdef CR_EOL - _, _, _, _, _, _, _, _, _, _, 99, _, _, 99, _, _, /* @abcdefghijklmno */ + 99, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, 99, Z_, Z_, 99, Z_, Z_, /* @abcdefghijklmno */ #else - _, _, _, _, _, _, _, _, _, _, 99, _, _, _, _, _, /* @abcdefghijklmno */ + 99, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, 99, Z_, Z_, Z_, Z_, Z_, /* @abcdefghijklmno */ #endif - _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, /* */ #ifdef TC_HPPA - _,99, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* _!"#$%&'()*+,-./ */ - _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* 0123456789:;<=>? */ + Z_,99, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, /* _!"#$%&'()*+,-./ */ + Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, /* 0123456789:;<=>? */ #else - _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ - _, _, _, _, _, _, _, _, _, _, _, 99, _, _, _, _, /* 0123456789:;<=>? */ -#endif - _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ - _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ - _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ - _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ - _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ - _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ - _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ - _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ - _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, /* */ + Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, 99, Z_, Z_, Z_, Z_, /* 0123456789:;<=>? */ +#endif + Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, /* */ + Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, /* */ + Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, /* */ + Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, /* */ + Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, /* */ + Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, /* */ + Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, /* */ + Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, /* */ + Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, Z_, /* */ }; -#undef _ +#undef Z_ /* Functions private to this file. */ static char *buffer; /* 1st char of each buffer of lines is here. */ static char *buffer_limit; /*->1 + last char in buffer. */ -#ifdef TARGET_BYTES_BIG_ENDIAN -/* Hack to deal with tc-*.h defining TARGET_BYTES_BIG_ENDIAN to empty - instead of to 0 or 1. */ -#if 5 - TARGET_BYTES_BIG_ENDIAN - 5 == 10 -#undef TARGET_BYTES_BIG_ENDIAN -#define TARGET_BYTES_BIG_ENDIAN 1 -#endif +/* TARGET_BYTES_BIG_ENDIAN is required to be defined to either 0 or 1 in the + tc-.h file. See the "Porting GAS" section of the internals manual. */ int target_big_endian = TARGET_BYTES_BIG_ENDIAN; -#else -int target_big_endian /* = 0 */; -#endif static char *old_buffer; /* JF a hack */ static char *old_input; static char *old_limit; -/* Variables for handling include file directory list. */ +/* Variables for handling include file directory table. */ -char **include_dirs; /* List of pointers to directories to +char **include_dirs; /* Table of pointers to directories to search for .include's */ -int include_dir_count; /* How many are in the list */ -int include_dir_maxlen = 1;/* Length of longest in list */ +int include_dir_count; /* How many are in the table */ +int include_dir_maxlen = 1;/* Length of longest in table */ #ifndef WORKING_DOT_WORD struct broken_word *broken_words; @@ -176,7 +189,7 @@ 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 *mri_line_label; +symbolS *line_label; /* This global variable is used to support MRI common sections. We translate such sections into a common symbol. This variable is @@ -189,14 +202,35 @@ symbolS *mri_common_symbol; may be needed. */ static int mri_pending_align; -static void do_align PARAMS ((int, char *)); +#ifndef NO_LISTING +#ifdef OBJ_ELF +/* This variable is set to be non-zero if the next string we see might + be the name of the source file in DWARF debugging information. See + the comment in emit_expr for the format we look for. */ +static int dwarf_file_string; +#endif +#endif + +static void cons_worker PARAMS ((int, int)); +static int scrub_from_string PARAMS ((char *, int)); +static void do_align PARAMS ((int, char *, int, int)); +static void s_align PARAMS ((int, int)); +static void s_lcomm_internal PARAMS ((int, int)); static int hex_float PARAMS ((int, char *)); +static inline int sizeof_sleb128 PARAMS ((offsetT)); +static inline int sizeof_uleb128 PARAMS ((valueT)); +static inline int output_sleb128 PARAMS ((char *, offsetT)); +static inline int output_uleb128 PARAMS ((char *, valueT)); +static inline int output_big_sleb128 PARAMS ((char *, LITTLENUM_TYPE *, int)); +static inline int output_big_uleb128 PARAMS ((char *, LITTLENUM_TYPE *, int)); +static int output_big_leb128 PARAMS ((char *, LITTLENUM_TYPE *, int, int)); static void do_org PARAMS ((segT, expressionS *, int)); char *demand_copy_string PARAMS ((int *lenP)); -int is_it_end_of_statement PARAMS ((void)); static segT get_segmented_expression PARAMS ((expressionS *expP)); static segT get_known_segmented_expression PARAMS ((expressionS * expP)); static void pobegin PARAMS ((void)); +static int get_line_sb PARAMS ((sb *)); +static void generate_file_debug PARAMS ((void)); void @@ -209,8 +243,8 @@ 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++) @@ -232,6 +266,8 @@ static const pseudo_typeS potable[] = {"ascii", stringer, 0}, {"asciz", stringer, 1}, {"balign", s_align_bytes, 0}, + {"balignw", s_align_bytes, -2}, + {"balignl", s_align_bytes, -4}, /* block */ {"byte", cons, 1}, {"comm", s_comm, 0}, @@ -260,6 +296,7 @@ static const pseudo_typeS potable[] = {"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 @@ -271,10 +308,13 @@ static const pseudo_typeS potable[] = {"elsec", s_else, 0}, {"end", s_end, 0}, {"endc", s_endif, 0}, + {"endfunc", s_func, 1}, {"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}, @@ -284,10 +324,12 @@ static const pseudo_typeS potable[] = {"fill", s_fill, 0}, {"float", float_cons, 'f'}, {"format", s_ignore, 0}, + {"func", s_func, 0}, {"global", s_globl, 0}, {"globl", s_globl, 0}, {"hword", cons, 2}, {"if", s_if, (int) O_ne}, + {"ifc", s_ifc, 0}, {"ifdef", s_ifdef, 0}, {"ifeq", s_if, (int) O_eq}, {"ifeqs", s_ifeqs, 0}, @@ -295,18 +337,29 @@ static const pseudo_typeS potable[] = {"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}, @@ -314,11 +367,17 @@ static const pseudo_typeS potable[] = {"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 */ @@ -327,6 +386,9 @@ 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'}, @@ -346,14 +408,18 @@ static const pseudo_typeS potable[] = {"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 */ + {NULL, NULL, 0} /* end sentinel */ }; static int pop_override_ok = 0; @@ -369,7 +435,8 @@ pop_insert (table) { errtxt = hash_insert (po_hash, pop->poc_name, (char *) pop); if (errtxt && (!pop_override_ok || strcmp (errtxt, "exists"))) - as_fatal ("error constructing %s pseudo-op table", pop_table_name); + as_fatal (_("error constructing %s pseudo-op table: %s"), pop_table_name, + errtxt); } } @@ -410,6 +477,27 @@ 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 (buf, buflen) + char *buf; + int buflen; +{ + int copy; + + copy = scrub_string_end - scrub_string; + if (copy > buflen) + copy = buflen; + memcpy (buf, scrub_string, copy); + scrub_string += copy; + return copy; +} + /* read_a_source_file() * * We read the file, putting things into a web that @@ -427,7 +515,13 @@ read_a_source_file (name) buffer = input_scrub_new_file (name); listing_file (name); - listing_newline (""); + listing_newline (NULL); + register_dependency (name); + + /* Generate debugging information before we've read anything in to denote + this file as the "main" source file and not a subordinate one + (e.g. N_SO vs N_SOL in stabs). */ + generate_file_debug (); while ((buffer_limit = input_scrub_next_buffer (&input_line_pointer)) != 0) { /* We have another line to parse. */ @@ -453,43 +547,65 @@ read_a_source_file (name) if (input_line_pointer[-1] == '\n') bump_line_counters (); - if (flag_mri + line_label = NULL; + + if (flag_m68k_mri #ifdef LABELS_WITHOUT_COLONS || 1 #endif ) { - mri_line_label = NULL; - /* 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 = get_symbol_end (); + char c; + int mri_line_macro; + + LISTING_NEWLINE (); + HANDLE_CONDITIONAL_ASSEMBLY (); - if (! ignore_input ()) + c = get_symbol_end (); + + /* In MRI mode, the EQU and MACRO pseudoops must + be handled specially. */ + mri_line_macro = 0; + if (flag_m68k_mri) { - /* In MRI mode, the EQU pseudoop must be - handled specially. */ - if (flag_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')) { - if (((strncasecmp (input_line_pointer + 1, - "EQU", 3) == 0) - || (strncasecmp (input_line_pointer + 1, - "SET", 3) == 0)) - && (input_line_pointer[4] == ' ' - || input_line_pointer[4] == '\t')) - { - input_line_pointer += 4; - equals (line_start); - continue; - } + input_line_pointer = rest + 3; + equals (line_start, + strncasecmp (rest, "SET", 3) == 0); + continue; } - - mri_line_label = colon (line_start); + 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++; @@ -519,7 +635,39 @@ 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. @@ -540,7 +688,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 (); @@ -548,13 +716,14 @@ 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 @@ -567,14 +736,14 @@ read_a_source_file (name) char *s2 = s; while (*s2) { - if (isupper (*s2)) + if (isupper ((unsigned char) *s2)) *s2 = tolower (*s2); s2++; } } #endif - if (flag_mri + if (flag_m68k_mri #ifdef NO_PSEUDO_DOT || 1 #endif @@ -587,7 +756,8 @@ read_a_source_file (name) pop = NULL; } - if (pop != NULL || *s == '.') + if (pop != NULL + || (! flag_m68k_mri && *s == '.')) { /* * PSEUDO - OP. @@ -608,16 +778,32 @@ read_a_source_file (name) || ! ((pop->poc_handler == cons && pop->poc_val == 1) || (pop->poc_handler == s_space - && pop->poc_val == 1)))) + && 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); + do_align (1, (char *) NULL, 0, 0); mri_pending_align = 0; + if (line_label != NULL) + { + symbol_set_frag (line_label, 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); + as_bad (_("Unknown pseudo-op: `%s'"), s); *input_line_pointer = c; s_ignore (0); continue; @@ -642,43 +828,69 @@ read_a_source_file (name) goto quit; } else - { /* machine instruction */ - if (mri_pending_align) - { - do_align (1, (char *) NULL); - mri_pending_align = 0; - } + { + int inquote = 0; +#ifdef QUOTES_IN_INSN + int inescape = 0; +#endif /* 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; +#ifdef QUOTES_IN_INSN + if (inescape) + inescape = 0; + else if (*input_line_pointer == '"') + inquote = ! inquote; + else if (*input_line_pointer == '\\') + inescape = 1; +#endif input_line_pointer++; } c = *input_line_pointer; *input_line_pointer = '\0'; -#ifdef OBJ_GENERATE_ASM_LINENO - if (generate_asm_lineno == 0) + generate_lineno_debug (); + + if (macro_defined) { - if (ecoff_no_current_file ()) - generate_asm_lineno = 1; + 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 (generate_asm_lineno == 1) - { - unsigned int lineno; - char *s; - as_where (&s, &lineno); - OBJ_GENERATE_ASM_LINENO (s, lineno); - } -#endif + if (mri_pending_align) + { + do_align (1, (char *) NULL, 0, 0); + mri_pending_align = 0; + if (line_label != NULL) + { + symbol_set_frag (line_label, frag_now); + S_SET_VALUE (line_label, frag_now_fix ()); + } + } md_assemble (s); /* Assemble 1 instruction. */ @@ -697,7 +909,7 @@ read_a_source_file (name) continue; if ((LOCAL_LABELS_DOLLAR || LOCAL_LABELS_FB) - && isdigit (c)) + && isdigit ((unsigned char) c)) { /* local label ("4:") */ char *backup = input_line_pointer; @@ -706,7 +918,7 @@ read_a_source_file (name) temp = c - '0'; - while (isdigit (*input_line_pointer)) + while (isdigit ((unsigned char) *input_line_pointer)) { temp = (temp * 10) + *input_line_pointer - '0'; ++input_line_pointer; @@ -720,7 +932,7 @@ read_a_source_file (name) if (dollar_label_defined (temp)) { - as_fatal ("label \"%d$\" redefined", temp); + as_fatal (_("label \"%d$\" redefined"), temp); } define_dollar_label (temp); @@ -746,7 +958,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; @@ -798,26 +1009,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; - ch = do_scrub_next_char (scrub_from_string, scrub_to_string); - if (ch == EOF) - break; - *new_tmp++ = ch; - if (new_tmp == new_buf + new_length) + space = (new_buf + new_length) - new_tmp; + size = do_scrub_chars (scrub_from_string, new_tmp, space); + + if (size < space) { - new_buf = xrealloc (new_buf, new_length + 100); - new_tmp = new_buf + new_length; - new_length += 100; + new_tmp += size; + break; } + + new_buf = xrealloc (new_buf, new_length + 100); + new_tmp = new_buf + new_length; + new_length += 100; } if (tmp_buf) @@ -833,6 +1048,11 @@ 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 (); @@ -844,6 +1064,7 @@ read_a_source_file (name) if (old_buffer) { + free (buffer); bump_line_counters (); if (old_input != 0) { @@ -857,43 +1078,117 @@ read_a_source_file (name) } /* while (more buffers to scan) */ quit: + +#ifdef md_cleanup + md_cleanup(); +#endif input_scrub_close (); /* Close the input file */ } +/* For most MRI pseudo-ops, the line actually ends at the first + nonquoted space. This function looks for that point, stuffs a null + in, and sets *STOPCP to the character that used to be there, and + returns the location. + + Until I hear otherwise, I am going to assume that this is only true + for the m68k MRI assembler. */ + +char * +mri_comment_field (stopcp) + char *stopcp; +{ +#ifdef TC_M68K + + char *s; + int inquote = 0; + + know (flag_m68k_mri); + + for (s = input_line_pointer; + ((! is_end_of_line[(unsigned char) *s] && *s != ' ' && *s != '\t') + || inquote); + s++) + { + if (*s == '\'') + inquote = ! inquote; + } + *stopcp = *s; + *s = '\0'; + return s; + +#else + + char *s; + + for (s = input_line_pointer; ! is_end_of_line[(unsigned char) *s]; s++) + ; + *stopcp = *s; + *s = '\0'; + return s; + +#endif + +} + +/* Skip to the end of an MRI comment field. */ + +void +mri_comment_end (stop, stopc) + char *stop; + int stopc; +{ + know (flag_mri); + + input_line_pointer = stop; + *stop = stopc; + while (! is_end_of_line[(unsigned char) *input_line_pointer]) + ++input_line_pointer; +} + void s_abort (ignore) - int ignore; + int ignore ATTRIBUTE_UNUSED; { - as_fatal (".abort detected. Abandoning ship."); + as_fatal (_(".abort detected. Abandoning ship.")); } -/* Guts of .align directive. */ +/* Guts of .align directive. N is the power of two to which to align. + FILL may be NULL, or it may point to the bytes of the fill pattern. + LEN is the length of whatever FILL points to, if anything. MAX is + the maximum number of characters to skip when doing the alignment, + or 0 if there is no maximum. */ + static void -do_align (n, fill) +do_align (n, fill, len, max) int n; char *fill; + int len; + int max; { + char default_fill; + #ifdef md_do_align - md_do_align (n, fill, just_record_alignment); + md_do_align (n, fill, len, max, just_record_alignment); #endif - if (!fill) - { - /* @@ Fix this right for BFD! */ - static char zero; - static char nop_opcode = NOP_OPCODE; - if (now_seg != data_section && now_seg != bss_section) - { - fill = &nop_opcode; - } + if (fill == NULL) + { + if (subseg_text_p (now_seg)) + default_fill = NOP_OPCODE; else - { - fill = &zero; - } + default_fill = 0; + fill = &default_fill; + len = 1; } + /* Only make a frag if we HAVE to. . . */ - if (n && !need_pass_2) - frag_align (n, *fill); + if (n != 0 && !need_pass_2) + { + if (len <= 1) + frag_align (n, *fill, max); + else + frag_align_pattern (n, fill, len, max); + } #ifdef md_do_align just_record_alignment: @@ -902,87 +1197,158 @@ do_align (n, fill) record_alignment (now_seg, n); } -/* For machines where ".align 4" means align to a 4 byte boundary. */ -void -s_align_bytes (arg) +/* Handle the .align pseudo-op. A positive ARG is a default alignment + (in bytes). A negative ARG is the negative of the length of the + fill pattern. BYTES_P is non-zero if the alignment value should be + interpreted as the byte boundary, rather than the power of 2. */ + +static void +s_align (arg, bytes_p) int arg; + int bytes_p; { - register unsigned int temp; - char temp_fill; - unsigned int i = 0; - unsigned long max_alignment = 1 << 15; + register unsigned int align; + char *stop = NULL; + char stopc; + offsetT fill = 0; + int max; + int fill_p; + + if (flag_mri) + stop = mri_comment_field (&stopc); if (is_end_of_line[(unsigned char) *input_line_pointer]) - temp = arg; /* Default value from pseudo-op table */ + { + if (arg < 0) + align = 0; + else + align = arg; /* Default value from pseudo-op table */ + } else - temp = get_absolute_expression (); + { + align = get_absolute_expression (); + SKIP_WHITESPACE (); + } + + if (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 (temp > max_alignment) + if (align > 15) { - as_bad ("Alignment too large: %d. assumed.", temp = max_alignment); + align = 15; + as_bad (_("Alignment too large: %u assumed"), align); } - /* For the sparc, `.align (1<>= 1, ++i) - ; + fill_p = 0; + max = 0; } - if (temp != 1) - as_bad ("Alignment not a power of 2"); + else + { + ++input_line_pointer; + if (*input_line_pointer == ',') + fill_p = 0; + else + { + fill = get_absolute_expression (); + SKIP_WHITESPACE (); + fill_p = 1; + } - temp = i; - if (*input_line_pointer == ',') + if (*input_line_pointer != ',') + max = 0; + else + { + ++input_line_pointer; + max = get_absolute_expression (); + } + } + + if (! fill_p) { - input_line_pointer++; - temp_fill = get_absolute_expression (); - do_align (temp, &temp_fill); + if (arg < 0) + as_warn (_("expected fill pattern missing")); + do_align (align, (char *) NULL, 0, max); } else - do_align (temp, (char *) 0); + { + 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 ((size_t) fill_len > sizeof ab) + abort (); + md_number_to_chars (ab, fill, fill_len); + do_align (align, ab, fill_len, max); + } + } demand_empty_rest_of_line (); + + if (flag_mri) + mri_comment_end (stop, stopc); } -/* For machines where ".align 4" means align to 2**4 boundary. */ +/* Handle the .align pseudo-op on machines where ".align 4" means + align to a 4 byte boundary. */ + void -s_align_ptwo (ignore) - int ignore; +s_align_bytes (arg) + int arg; { - register int temp; - char temp_fill; - long max_alignment = 15; + s_align (arg, 1); +} - temp = get_absolute_expression (); - if (temp > max_alignment) - as_bad ("Alignment too large: %d. assumed.", temp = max_alignment); - else if (temp < 0) - { - as_bad ("Alignment negative. 0 assumed."); - temp = 0; - } - if (*input_line_pointer == ',') - { - input_line_pointer++; - temp_fill = get_absolute_expression (); - do_align (temp, &temp_fill); - } - else - do_align (temp, (char *) 0); +/* Handle the .align pseudo-op on machines where ".align 4" means align + to a 2**4 boundary. */ - demand_empty_rest_of_line (); +void +s_align_ptwo (arg) + int arg; +{ + s_align (arg, 0); } void s_comm (ignore) - int ignore; + int ignore ATTRIBUTE_UNUSED; { 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 (); @@ -992,31 +1358,37 @@ s_comm (ignore) SKIP_WHITESPACE (); if (*input_line_pointer != ',') { - as_bad ("Expected comma after symbol-name: rest of line ignored."); + as_bad (_("Expected comma after symbol-name: rest of line ignored.")); ignore_rest_of_line (); + if (flag_mri) + mri_comment_end (stop, stopc); return; } input_line_pointer++; /* skip ',' */ if ((temp = get_absolute_expression ()) < 0) { - as_warn (".COMMon length (%ld.) <0! Ignored.", (long) temp); + as_warn (_(".COMMon length (%ld.) <0! Ignored."), (long) temp); ignore_rest_of_line (); + if (flag_mri) + mri_comment_end (stop, stopc); return; } *p = 0; symbolP = symbol_find_or_make (name); *p = c; - if (S_IS_DEFINED (symbolP)) + if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP)) { - as_bad ("Ignoring attempt to re-define symbol `%s'.", + as_bad (_("Ignoring attempt to re-define symbol `%s'."), S_GET_NAME (symbolP)); ignore_rest_of_line (); + if (flag_mri) + mri_comment_end (stop, stopc); 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.", + as_bad (_("Length of .comm \"%s\" is already %ld. Not changed to %ld."), S_GET_NAME (symbolP), (long) S_GET_VALUE (symbolP), (long) temp); @@ -1034,7 +1406,11 @@ s_comm (ignore) } #endif /* not OBJ_VMS */ know (symbolP->sy_frag == &zero_address_frag); + demand_empty_rest_of_line (); + + if (flag_mri) + mri_comment_end (stop, stopc); } /* s_comm() */ /* The MRI COMMON pseudo-op. We handle this by creating a common @@ -1043,13 +1419,15 @@ s_comm (ignore) void s_mri_common (small) - int small; + int small ATTRIBUTE_UNUSED; { char *name; char c; char *alc = NULL; symbolS *sym; offsetT align; + char *stop = NULL; + char stopc; if (! flag_mri) { @@ -1057,6 +1435,8 @@ s_mri_common (small) return; } + stop = mri_comment_field (&stopc); + SKIP_WHITESPACE (); name = input_line_pointer; @@ -1072,12 +1452,12 @@ s_mri_common (small) c = *input_line_pointer; *input_line_pointer = '\0'; - if (mri_line_label != NULL) + if (line_label != NULL) { - alc = (char *) xmalloc (strlen (S_GET_NAME (mri_line_label)) + alc = (char *) xmalloc (strlen (S_GET_NAME (line_label)) + (input_line_pointer - name) + 1); - sprintf (alc, "%s%s", name, S_GET_NAME (mri_line_label)); + sprintf (alc, "%s%s", name, S_GET_NAME (line_label)); name = alc; } } @@ -1095,16 +1475,12 @@ s_mri_common (small) align = get_absolute_expression (); } - if (S_IS_DEFINED (sym)) + if (S_IS_DEFINED (sym) && ! S_IS_COMMON (sym)) { -#if defined (S_IS_COMMON) || defined (BFD_ASSEMBLER) - if (! S_IS_COMMON (sym)) -#endif - { - as_bad ("attempt to re-define symbol `%s'", S_GET_NAME (sym)); - ignore_rest_of_line (); - return; - } + as_bad (_("attempt to re-define symbol `%s'"), S_GET_NAME (sym)); + ignore_rest_of_line (); + mri_comment_end (stop, stopc); + return; } S_SET_EXTERNAL (sym); @@ -1115,13 +1491,15 @@ s_mri_common (small) S_SET_ALIGN (sym, align); #endif - if (mri_line_label != NULL) + if (line_label != NULL) { - mri_line_label->sy_value.X_op = O_symbol; - mri_line_label->sy_value.X_add_symbol = sym; - mri_line_label->sy_value.X_add_number = S_GET_VALUE (sym); - mri_line_label->sy_frag = &zero_address_frag; - S_SET_SEGMENT (mri_line_label, expr_section); + expressionS exp; + exp.X_op = O_symbol; + exp.X_add_symbol = sym; + exp.X_add_number = 0; + symbol_set_value_expression (line_label, &exp); + symbol_set_frag (line_label, &zero_address_frag); + S_SET_SEGMENT (line_label, expr_section); } /* FIXME: We just ignore the small argument, which distinguishes @@ -1132,12 +1510,15 @@ s_mri_common (small) input_line_pointer += 2; if (*input_line_pointer == ',') input_line_pointer += 2; + demand_empty_rest_of_line (); + + mri_comment_end (stop, stopc); } void s_data (ignore) - int ignore; + int ignore ATTRIBUTE_UNUSED; { segT section; register int temp; @@ -1160,11 +1541,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) @@ -1179,26 +1560,39 @@ 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 - } + register_dependency (s); #ifdef obj_app_file - obj_app_file (s); + 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) - int ignore; + int ignore ATTRIBUTE_UNUSED; { int l; @@ -1207,7 +1601,7 @@ s_app_line (ignore) 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); + as_warn (_("Line numbers must be positive; line number %d rejected."), l+1); else { new_logical_line ((char *) NULL, l); @@ -1224,87 +1618,144 @@ s_app_line (ignore) void s_end (ignore) - int ignore; + int ignore ATTRIBUTE_UNUSED; { 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]) - as_warn ("start address not supported"); + 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 ATTRIBUTE_UNUSED; +{ + as_bad (_(".err encountered")); + demand_empty_rest_of_line (); +} + /* Handle the MRI fail pseudo-op. */ void s_fail (ignore) - int ignore; + int ignore ATTRIBUTE_UNUSED; { 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); + as_warn (_(".fail %ld encountered"), (long) temp); else - as_bad (".fail %ld encountered", (long) temp); + as_bad (_(".fail %ld encountered"), (long) temp); + demand_empty_rest_of_line (); + + if (flag_mri) + mri_comment_end (stop, stopc); } void s_fill (ignore) - int ignore; + int ignore ATTRIBUTE_UNUSED; { - long temp_repeat = 0; - long temp_size = 1; - register long temp_fill = 0; + expressionS rep_exp; + long size = 1; + register long fill = 0; char *p; +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif - temp_repeat = get_absolute_expression (); + get_known_segmented_expression (&rep_exp); if (*input_line_pointer == ',') { input_line_pointer++; - temp_size = get_absolute_expression (); + size = get_absolute_expression (); if (*input_line_pointer == ',') { input_line_pointer++; - temp_fill = get_absolute_expression (); + fill = get_absolute_expression (); } } + /* This is to be compatible with BSD 4.2 AS, not for any rational reason. */ #define BSD_FILL_SIZE_CROCK_8 (8) - if (temp_size > BSD_FILL_SIZE_CROCK_8) + if (size > BSD_FILL_SIZE_CROCK_8) { - as_warn (".fill size clamped to %d.", BSD_FILL_SIZE_CROCK_8); - temp_size = BSD_FILL_SIZE_CROCK_8; + as_warn (_(".fill size clamped to %d."), BSD_FILL_SIZE_CROCK_8); + size = BSD_FILL_SIZE_CROCK_8; } - if (temp_size < 0) + if (size < 0) { - as_warn ("Size negative: .fill ignored."); - temp_size = 0; + as_warn (_("Size negative: .fill ignored.")); + size = 0; } - else if (temp_repeat <= 0) + else if (rep_exp.X_op == O_constant && rep_exp.X_add_number <= 0) { - as_warn ("Repeat < 0, .fill ignored"); - temp_size = 0; + if (rep_exp.X_add_number < 0) + as_warn (_("Repeat < 0, .fill ignored")); + size = 0; } - if (temp_size && !need_pass_2) + if (size && !need_pass_2) { - p = frag_var (rs_fill, (int) temp_size, (int) temp_size, (relax_substateT) 0, (symbolS *) 0, temp_repeat, (char *) 0); - memset (p, 0, (unsigned int) temp_size); + if (rep_exp.X_op == O_constant) + { + p = frag_var (rs_fill, (int) size, (int) size, + (relax_substateT) 0, (symbolS *) 0, + (offsetT) rep_exp.X_add_number, + (char *) 0); + } + else + { + /* We don't have a constant repeat count, so we can't use + rs_fill. We can get the same results out of rs_space, + but its argument is in bytes, so we must multiply the + repeat count by size. */ + + symbolS *rep_sym; + rep_sym = make_expr_symbol (&rep_exp); + if (size != 1) + { + expressionS size_exp; + size_exp.X_op = O_constant; + size_exp.X_add_number = size; + + rep_exp.X_op = O_multiply; + rep_exp.X_add_symbol = rep_sym; + rep_exp.X_op_symbol = make_expr_symbol (&size_exp); + rep_exp.X_add_number = 0; + rep_sym = make_expr_symbol (&rep_exp); + } + + p = frag_var (rs_space, (int) size, (int) size, + (relax_substateT) 0, rep_sym, (offsetT) 0, (char *) 0); + } + memset (p, 0, (unsigned int) size); /* The magic number BSD_FILL_SIZE_CROCK_4 is from BSD 4.2 VAX * flavoured AS. The following bizzare behaviour is to be * compatible with above. I guess they tried to take up to 8 * bytes from a 4-byte expression and they forgot to sign * extend. Un*x Sux. */ #define BSD_FILL_SIZE_CROCK_4 (4) - md_number_to_chars (p, (valueT) temp_fill, - (temp_size > BSD_FILL_SIZE_CROCK_4 + md_number_to_chars (p, (valueT) fill, + (size > BSD_FILL_SIZE_CROCK_4 ? BSD_FILL_SIZE_CROCK_4 - : (int) temp_size)); + : (int) size)); /* Note: .fill (),0 emits no frag (since we are asked to .fill 0 bytes) * but emits no error message because it seems a legal thing to do. * It is a degenerate case of .fill but could be emitted by a compiler. @@ -1315,20 +1766,27 @@ s_fill (ignore) void s_globl (ignore) - int ignore; + int ignore ATTRIBUTE_UNUSED; { char *name; int c; symbolS *symbolP; + char *stop = NULL; + char stopc; + + if (flag_mri) + stop = mri_comment_field (&stopc); do { name = input_line_pointer; c = get_symbol_end (); symbolP = symbol_find_or_make (name); + S_SET_EXTERNAL (symbolP); + *input_line_pointer = c; SKIP_WHITESPACE (); - S_SET_EXTERNAL (symbolP); + c = *input_line_pointer; if (c == ',') { input_line_pointer++; @@ -1338,22 +1796,137 @@ s_globl (ignore) } } while (c == ','); + demand_empty_rest_of_line (); + + if (flag_mri) + mri_comment_end (stop, stopc); } -void -s_lcomm (needs_align) - /* 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; +/* Handle the MRI IRP and IRPC pseudo-ops. */ + +void +s_irp (irpc) + int irpc; { - register char *name; - register char c; - register char *p; - register int temp; - register symbolS *symbolP; - segT current_seg = now_seg; - subsegT current_subseg = now_subseg; + 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 ATTRIBUTE_UNUSED; +{ + 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; + register char *p; + register int temp; + register symbolS *symbolP; + segT current_seg = now_seg; + subsegT current_subseg = now_subseg; const int max_alignment = 15; int align = 0; segT bss_seg = bss_section; @@ -1374,13 +1947,13 @@ s_lcomm (needs_align) if (*input_line_pointer == '\n') { - as_bad ("Missing size expression"); + as_bad (_("Missing size expression")); return; } if ((temp = get_absolute_expression ()) < 0) { - as_warn ("BSS length (%d.) <0! Ignored.", temp); + as_warn (_("BSS length (%d.) <0! Ignored."), temp); ignore_rest_of_line (); return; } @@ -1394,6 +1967,11 @@ s_lcomm (needs_align) { 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 @@ -1409,6 +1987,11 @@ s_lcomm (needs_align) 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); } @@ -1418,7 +2001,7 @@ s_lcomm (needs_align) SKIP_WHITESPACE (); if (*input_line_pointer != ',') { - as_bad ("Expected comma after size"); + as_bad (_("Expected comma after size")); ignore_rest_of_line (); return; } @@ -1426,26 +2009,40 @@ s_lcomm (needs_align) SKIP_WHITESPACE (); if (*input_line_pointer == '\n') { - as_bad ("Missing alignment"); + as_bad (_("Missing alignment")); 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; - as_warn ("Alignment too large: %d. assumed.", align); + as_warn (_("Alignment too large: %d. assumed."), align); } else if (align < 0) { align = 0; - as_warn ("Alignment negative. 0 assumed."); + as_warn (_("Alignment negative. 0 assumed.")); } record_alignment (bss_seg, align); } /* if needs align */ else { /* Assume some objects may require alignment on some systems. */ -#ifdef TC_ALPHA +#if defined (TC_ALPHA) && ! defined (VMS) if (temp > 1) { align = ffs (temp) - 1; @@ -1472,14 +2069,14 @@ 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; + symbol_get_frag (symbolP)->fr_symbol = NULL; - symbolP->sy_frag = frag_now; + symbol_set_frag (symbolP, 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); @@ -1493,19 +2090,36 @@ s_lcomm (needs_align) 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'.", + 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() */ +} /* 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; + int ignore ATTRIBUTE_UNUSED; { register char *name; register char c; @@ -1522,7 +2136,7 @@ s_lsym (ignore) if (*input_line_pointer != ',') { *p = 0; - as_bad ("Expected comma after name \"%s\"", name); + as_bad (_("Expected comma after name \"%s\""), name); *p = c; ignore_rest_of_line (); return; @@ -1532,7 +2146,7 @@ s_lsym (ignore) if (exp.X_op != O_constant && exp.X_op != O_register) { - as_bad ("bad expression"); + as_bad (_("bad expression")); ignore_rest_of_line (); return; } @@ -1559,12 +2173,169 @@ s_lsym (ignore) } else { - as_bad ("Symbol %s already defined", name); + 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 ATTRIBUTE_UNUSED; +{ + 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); + symbol_set_frag (line_label, &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 ATTRIBUTE_UNUSED; +{ + 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 ATTRIBUTE_UNUSED; +{ + 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 + macro_mri_mode (1); + } + else + { + flag_mri = 0; + flag_m68k_mri = 0; + macro_mri_mode (0); + } + + /* Operator precedence changes in m68k MRI mode, so we need to + update the operator rankings. */ + expr_set_precedence (); + +#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 @@ -1574,16 +2345,16 @@ do_org (segment, exp, fill) int fill; { if (segment != now_seg && segment != absolute_section) - as_bad ("invalid segment \"%s\"; segment \"%s\" assumed", + 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"); + as_warn (_("ignoring fill value in absolute section")); if (exp->X_op != O_constant) { - as_bad ("only constant offsets supported in absolute section"); + as_bad (_("only constant offsets supported in absolute section")); exp->X_add_number = 0; } abs_section_offset = exp->X_add_number; @@ -1600,18 +2371,22 @@ do_org (segment, exp, fill) void s_org (ignore) - int ignore; + int ignore ATTRIBUTE_UNUSED; { register segT segment; expressionS exp; register long temp_fill; - /* The 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_mri) +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + + /* 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"); + as_bad (_("MRI style ORG pseudo-op not supported")); ignore_rest_of_line (); return; } @@ -1643,9 +2418,256 @@ s_org (ignore) 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 ATTRIBUTE_UNUSED; +{ +#ifdef TC_M68K + + char *name; + char c; + segT seg; + + SKIP_WHITESPACE (); + + name = input_line_pointer; + if (! isdigit ((unsigned char) *name)) + c = get_symbol_end (); + else + { + do + { + ++input_line_pointer; + } + while (isdigit ((unsigned char) *input_line_pointer)); + c = *input_line_pointer; + *input_line_pointer = '\0'; + } + + name = xstrdup (name); + + *input_line_pointer = c; + + seg = subseg_new (name, 0); + + if (*input_line_pointer == ',') + { + int align; + + ++input_line_pointer; + align = get_absolute_expression (); + record_alignment (seg, align); + } + + *type = 'C'; + if (*input_line_pointer == ',') + { + c = *++input_line_pointer; + c = toupper ((unsigned char) c); + if (c == 'C' || c == 'D' || c == 'M' || c == 'R') + *type = c; + else + as_bad (_("unrecognized section type")); + ++input_line_pointer; + +#ifdef BFD_ASSEMBLER + { + flagword flags; + + flags = SEC_NO_FLAGS; + if (*type == 'C') + flags = SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE; + else if (*type == 'D' || *type == 'M') + flags = SEC_ALLOC | SEC_LOAD | SEC_DATA; + else if (*type == 'R') + flags = SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_READONLY | SEC_ROM; + if (flags != SEC_NO_FLAGS) + { + if (! bfd_set_section_flags (stdoutput, seg, flags)) + as_warn (_("error setting flags for \"%s\": %s"), + bfd_section_name (stdoutput, seg), + bfd_errmsg (bfd_get_error ())); + } + } +#endif + } + + /* Ignore the HP type. */ + if (*input_line_pointer == ',') + input_line_pointer += 2; + + demand_empty_rest_of_line (); + +#else /* ! TC_M68K */ +#ifdef TC_I960 + + char *name; + char c; + segT seg; + + SKIP_WHITESPACE (); + + name = input_line_pointer; + c = get_symbol_end (); + + name = xstrdup (name); + + *input_line_pointer = c; + + seg = subseg_new (name, 0); + + if (*input_line_pointer != ',') + *type = 'C'; + else + { + char *sectype; + + ++input_line_pointer; + SKIP_WHITESPACE (); + sectype = input_line_pointer; + c = get_symbol_end (); + if (*sectype == '\0') + *type = 'C'; + else if (strcasecmp (sectype, "text") == 0) + *type = 'C'; + else if (strcasecmp (sectype, "data") == 0) + *type = 'D'; + else if (strcasecmp (sectype, "romdata") == 0) + *type = 'R'; + else + as_warn (_("unrecognized section type `%s'"), sectype); + *input_line_pointer = c; + } + + if (*input_line_pointer == ',') + { + char *seccmd; + + ++input_line_pointer; + SKIP_WHITESPACE (); + seccmd = input_line_pointer; + c = get_symbol_end (); + if (strcasecmp (seccmd, "absolute") == 0) + { + as_bad (_("absolute sections are not supported")); + *input_line_pointer = c; + ignore_rest_of_line (); + return; + } + else if (strcasecmp (seccmd, "align") == 0) + { + int align; + + *input_line_pointer = c; + align = get_absolute_expression (); + record_alignment (seg, align); + } + else + { + as_warn (_("unrecognized section command `%s'"), seccmd); + *input_line_pointer = c; + } + } + + demand_empty_rest_of_line (); + +#else /* ! TC_I960 */ + /* The MRI assembler seems to use different forms of .sect for + different targets. */ + as_bad ("MRI mode not supported for this target"); + ignore_rest_of_line (); +#endif /* ! TC_I960 */ +#endif /* ! TC_M68K */ +} + +/* Handle the .print pseudo-op. */ + +void +s_print (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + char *s; + int len; + + s = demand_copy_C_string (&len); + printf ("%s\n", s); + demand_empty_rest_of_line (); +} + +/* Handle the .purgem pseudo-op. */ + +void +s_purgem (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + if (is_it_end_of_statement ()) + { + demand_empty_rest_of_line (); + return; + } + + do + { + char *name; + char c; + + SKIP_WHITESPACE (); + name = input_line_pointer; + c = get_symbol_end (); + delete_macro (name); + *input_line_pointer = c; + SKIP_WHITESPACE (); + } + while (*input_line_pointer++ == ','); + + --input_line_pointer; + demand_empty_rest_of_line (); +} + +/* Handle the .rept pseudo-op. */ + +void +s_rept (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + int count; + sb one; + sb many; + + count = get_absolute_expression (); + + sb_new (&one); + if (! buffer_and_nest ("REPT", "ENDR", &one, get_line_sb)) + { + as_bad (_("rept without endr")); + return; + } + + 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; @@ -1666,7 +2688,7 @@ s_set (ignore) if (*input_line_pointer != ',') { *end_name = 0; - as_bad ("Expected comma after name \"%s\"", name); + as_bad (_("Expected comma after name \"%s\""), name); *end_name = delim; ignore_rest_of_line (); return; @@ -1693,7 +2715,24 @@ s_set (ignore) if ((symbolP = symbol_find (name)) == NULL && (symbolP = md_undefined_symbol (name)) == NULL) { - symbolP = symbol_new (name, undefined_section, 0, &zero_address_frag); +#ifndef NO_LISTING + /* When doing symbol listings, play games with dummy fragments living + outside the normal fragment chain to record the file and line info + for this symbol. */ + if (listing & LISTING_SYMBOLS) + { + extern struct list_info_struct *listing_tail; + fragS *dummy_frag = (fragS *) xmalloc (sizeof(fragS)); + memset (dummy_frag, 0, sizeof(fragS)); + dummy_frag->fr_type = rs_fill; + dummy_frag->line = listing_tail; + symbolP = symbol_new (name, undefined_section, 0, dummy_frag); + dummy_frag->fr_symbol = symbolP; + } + else +#endif + symbolP = symbol_new (name, undefined_section, 0, &zero_address_frag); + #ifdef OBJ_COFF /* "set" symbols are local unless otherwise specified. */ SF_SET_LOCAL (symbolP); @@ -1704,6 +2743,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() */ @@ -1713,83 +2758,166 @@ s_space (mult) int mult; { expressionS exp; - long temp_fill; + expressionS val; char *p = 0; + char *stop = NULL; + char stopc; + int bytes; #ifdef md_flush_pending_output md_flush_pending_output (); #endif - /* Just like .fill, but temp_size = 1 */ - expression (&exp); - if (exp.X_op == O_constant) - { - long repeat; - - repeat = exp.X_add_number; - if (mult) - repeat *= mult; - if (repeat <= 0) - { - as_warn (".space repeat count is %s, ignored", - repeat ? "negative" : "zero"); - ignore_rest_of_line (); - return; - } + if (flag_mri) + stop = mri_comment_field (&stopc); - /* If we are in the absolute section, just bump the offset. */ + /* In m68k MRI mode, we need to align to a word boundary, unless + this is ds.b. */ + if (flag_m68k_mri && mult > 1) + { if (now_seg == absolute_section) { - abs_section_offset += repeat; - demand_empty_rest_of_line (); - return; + abs_section_offset += abs_section_offset & 1; + if (line_label != NULL) + S_SET_VALUE (line_label, abs_section_offset); } - - /* 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) + else if (mri_common_symbol != NULL) { - S_SET_VALUE (mri_common_symbol, - S_GET_VALUE (mri_common_symbol) + repeat); - demand_empty_rest_of_line (); - return; - } + valueT val; - if (!need_pass_2) - p = frag_var (rs_fill, 1, 1, (relax_substateT) 0, (symbolS *) 0, - repeat, (char *) 0); - } - else - { - if (now_seg == absolute_section) - { - as_bad ("space allocation too complex in absolute section"); - subseg_set (text_section, 0); + val = S_GET_VALUE (mri_common_symbol); + if ((val & 1) != 0) + { + S_SET_VALUE (mri_common_symbol, val + 1); + if (line_label != NULL) + { + expressionS *symexp; + + symexp = symbol_get_value_expression (line_label); + know (symexp->X_op == O_symbol); + know (symexp->X_add_symbol == mri_common_symbol); + symexp->X_add_number += 1; + } + } } - if (mri_common_symbol != NULL) + else { - as_bad ("space allocation too complex in common section"); - mri_common_symbol = NULL; + do_align (1, (char *) NULL, 0, 0); + if (line_label != NULL) + { + symbol_set_frag (line_label, frag_now); + S_SET_VALUE (line_label, frag_now_fix ()); + } } - if (!need_pass_2) - p = frag_var (rs_space, 1, 1, (relax_substateT) 0, - make_expr_symbol (&exp), 0L, (char *) 0); } + + bytes = mult; + + expression (&exp); + SKIP_WHITESPACE (); if (*input_line_pointer == ',') { - input_line_pointer++; - temp_fill = get_absolute_expression (); + ++input_line_pointer; + expression (&val); } else { - temp_fill = 0; + val.X_op = O_constant; + val.X_add_number = 0; } - if (p) + + 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)) { - *p = temp_fill; + if (exp.X_op != O_constant) + as_bad (_("Unsupported variable size or fill value")); + else + { + offsetT i; + + if (mult == 0) + mult = 1; + bytes = mult * exp.X_add_number; + for (i = 0; i < exp.X_add_number; i++) + emit_expr (&val, mult); + } } + else + { + if (exp.X_op == O_constant) + { + long repeat; + + repeat = exp.X_add_number; + if (mult) + repeat *= mult; + bytes = repeat; + if (repeat <= 0) + { + if (! flag_mri) + as_warn (_(".space repeat count is zero, ignored")); + else if (repeat < 0) + as_warn (_(".space repeat count is negative, ignored")); + 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; + } + + 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; + demand_empty_rest_of_line (); + + if (flag_mri) + mri_comment_end (stop, stopc); } /* This is like s_space, but the value is a floating point number with @@ -1803,14 +2931,21 @@ s_float_space (float_type) offsetT count; int flen; char temp[MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT]; + char *stop = NULL; + char stopc; + + if (flag_mri) + stop = mri_comment_field (&stopc); count = get_absolute_expression (); SKIP_WHITESPACE (); if (*input_line_pointer != ',') { - as_bad ("missing value"); + as_bad (_("missing value")); ignore_rest_of_line (); + if (flag_mri) + mri_comment_end (stop, stopc); return; } @@ -1820,7 +2955,8 @@ s_float_space (float_type) /* 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])) + if (input_line_pointer[0] == '0' + && isalpha ((unsigned char) input_line_pointer[1])) input_line_pointer += 2; /* Accept :xxxx, where the x's are hex digits, for a floating point @@ -1831,6 +2967,8 @@ s_float_space (float_type) if (flen < 0) { ignore_rest_of_line (); + if (flag_mri) + mri_comment_end (stop, stopc); return; } } @@ -1843,8 +2981,10 @@ s_float_space (float_type) know (flen > 0); if (err) { - as_bad ("Bad floating literal: %s", err); + as_bad (_("Bad floating literal: %s"), err); ignore_rest_of_line (); + if (flag_mri) + mri_comment_end (stop, stopc); return; } } @@ -1858,22 +2998,32 @@ s_float_space (float_type) } demand_empty_rest_of_line (); + + if (flag_mri) + mri_comment_end (stop, stopc); } /* Handle the .struct pseudo-op, as found in MIPS assemblers. */ void s_struct (ignore) - int ignore; + int ignore ATTRIBUTE_UNUSED; { + char *stop = NULL; + char stopc; + + if (flag_mri) + stop = mri_comment_field (&stopc); abs_section_offset = get_absolute_expression (); subseg_set (absolute_section, 0); demand_empty_rest_of_line (); + if (flag_mri) + mri_comment_end (stop, stopc); } void s_text (ignore) - int ignore; + int ignore ATTRIBUTE_UNUSED; { register int temp; @@ -1906,11 +3056,11 @@ ignore_rest_of_line () /* For suspect lines: gives warning. */ { if (!is_end_of_line[(unsigned char) *input_line_pointer]) { - if (isprint (*input_line_pointer)) - as_bad ("Rest of line ignored. First ignored character is `%c'.", + if (isprint ((unsigned char) *input_line_pointer)) + as_bad (_("Rest of line ignored. First ignored character is `%c'."), *input_line_pointer); else - as_bad ("Rest of line ignored. First ignored character valued 0x%x.", + as_bad (_("Rest of line ignored. First ignored character valued 0x%x."), *input_line_pointer); while (input_line_pointer < buffer_limit && !is_end_of_line[(unsigned char) *input_line_pointer]) @@ -1922,6 +3072,18 @@ ignore_rest_of_line () /* For suspect lines: gives warning. */ know (is_end_of_line[(unsigned char) input_line_pointer[-1]]); } +void +discard_rest_of_line () +{ + while (input_line_pointer < buffer_limit + && !is_end_of_line[(unsigned char) *input_line_pointer]) + { + input_line_pointer++; + } + input_line_pointer++; /* Return pointing just after end-of-line. */ + know (is_end_of_line[(unsigned char) input_line_pointer[-1]]); +} + /* * pseudo_set() * @@ -1949,17 +3111,22 @@ pseudo_set (symbolP) (void) expression (&exp); if (exp.X_op == O_illegal) - as_bad ("illegal expression; zero assumed"); + as_bad (_("illegal expression; zero assumed")); else if (exp.X_op == O_absent) - as_bad ("missing expression; zero assumed"); + as_bad (_("missing expression; zero assumed")); else if (exp.X_op == O_big) - as_bad ("%s number invalid; zero assumed", - exp.X_add_number > 0 ? "bignum" : "floating point"); + { + if (exp.X_add_number > 0) + as_bad (_("bignum invalid; zero assumed")); + else + as_bad (_("floating point number invalid; zero assumed")); + } else if (exp.X_op == O_subtract && (S_GET_SEGMENT (exp.X_add_symbol) == S_GET_SEGMENT (exp.X_op_symbol)) && SEG_NORMAL (S_GET_SEGMENT (exp.X_add_symbol)) - && exp.X_add_symbol->sy_frag == exp.X_op_symbol->sy_frag) + && (symbol_get_frag (exp.X_add_symbol) + == symbol_get_frag (exp.X_op_symbol))) { exp.X_op = O_constant; exp.X_add_number = (S_GET_VALUE (exp.X_add_symbol) @@ -1982,19 +3149,22 @@ pseudo_set (symbolP) S_CLEAR_EXTERNAL (symbolP); #endif /* OBJ_AOUT or OBJ_BOUT */ S_SET_VALUE (symbolP, (valueT) exp.X_add_number); - symbolP->sy_frag = &zero_address_frag; + if (exp.X_op != O_constant) + symbol_set_frag (symbolP, &zero_address_frag); break; case O_register: S_SET_SEGMENT (symbolP, reg_section); S_SET_VALUE (symbolP, (valueT) exp.X_add_number); - symbolP->sy_frag = &zero_address_frag; + symbol_set_frag (symbolP, &zero_address_frag); break; case O_symbol: if (S_GET_SEGMENT (exp.X_add_symbol) == undefined_section || exp.X_add_number != 0) - symbolP->sy_value = exp; + symbol_set_value_expression (symbolP, &exp); + else if (symbol_section_p (symbolP)) + as_bad ("invalid attempt to set value of section symbol"); else { symbolS *s = exp.X_add_symbol; @@ -2008,7 +3178,7 @@ pseudo_set (symbolP) #endif /* OBJ_AOUT or OBJ_BOUT */ S_SET_VALUE (symbolP, exp.X_add_number + S_GET_VALUE (s)); - symbolP->sy_frag = s->sy_frag; + symbol_set_frag (symbolP, symbol_get_frag (s)); copy_symbol_attributes (symbolP, s); } break; @@ -2016,7 +3186,7 @@ pseudo_set (symbolP) default: /* The value is some complex expression. FIXME: Should we set the segment to anything? */ - symbolP->sy_value = exp; + symbol_set_value_expression (symbolP, &exp); break; } } @@ -2070,30 +3240,50 @@ 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 ()) { demand_empty_rest_of_line (); + if (flag_mri) + mri_comment_end (stop, stopc); return; } +#ifdef md_cons_align + md_cons_align (nbytes); +#endif + c = 0; do { - if (flag_mri) + 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; } @@ -2106,7 +3296,26 @@ cons (nbytes) mri_pending_align = 1; input_line_pointer--; /* Put terminator back into stream. */ + demand_empty_rest_of_line (); + + if (flag_mri) + mri_comment_end (stop, stopc); +} + + +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 @@ -2121,8 +3330,75 @@ emit_expr (exp, nbytes) register char *p; valueT extra_digit = 0; - /* Don't do anything if we are going to make another pass. */ - if (need_pass_2) + /* Don't do anything if we are going to make another pass. */ + 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; + } + + /* When gcc emits DWARF 1 debugging pseudo-ops, a file name will + appear as a 2 byte TAG_compile_unit (0x11) followed by a 2 byte + AT_sibling (0x12) followed by a four byte address of the sibling + followed by a 2 byte AT_name (0x38) followed by the name of the + file. We look for that case here. */ + { + static int dwarf_file = 0; + + if (strcmp (segment_name (now_seg), ".debug") != 0) + dwarf_file = 0; + else if (dwarf_file == 0 + && nbytes == 2 + && exp->X_op == O_constant + && exp->X_add_number == 0x11) + dwarf_file = 1; + else if (dwarf_file == 1 + && nbytes == 2 + && exp->X_op == O_constant + && exp->X_add_number == 0x12) + dwarf_file = 2; + else if (dwarf_file == 2 + && nbytes == 4) + dwarf_file = 3; + else if (dwarf_file == 3 + && nbytes == 2 + && exp->X_op == O_constant + && exp->X_add_number == 0x38) + dwarf_file = 4; + else + dwarf_file = 0; + + /* The variable dwarf_file_string tells stringer that the string + may be the name of the source file. */ + if (dwarf_file == 4) + dwarf_file_string = 1; + else + dwarf_file_string = 0; + } +#endif +#endif + + if (check_eh_frame (exp, &nbytes)) return; op = exp->X_op; @@ -2131,7 +3407,7 @@ emit_expr (exp, nbytes) if (now_seg == absolute_section) { if (op != O_constant || exp->X_add_number != 0) - as_bad ("attempt to store value in absolute section"); + as_bad (_("attempt to store value in absolute section")); abs_section_offset += nbytes; return; } @@ -2139,13 +3415,13 @@ emit_expr (exp, nbytes) /* Handle a negative bignum. */ if (op == O_uminus && exp->X_add_number == 0 - && exp->X_add_symbol->sy_value.X_op == O_big - && exp->X_add_symbol->sy_value.X_add_number > 0) + && symbol_get_value_expression (exp->X_add_symbol)->X_op == O_big + && symbol_get_value_expression (exp->X_add_symbol)->X_add_number > 0) { int i; unsigned long carry; - exp = &exp->X_add_symbol->sy_value; + exp = symbol_get_value_expression (exp->X_add_symbol); /* Negate the bignum: one's complement each digit and add 1. */ carry = 1; @@ -2169,19 +3445,19 @@ emit_expr (exp, nbytes) if (op == O_absent || op == O_illegal) { - as_warn ("zero assumed for missing expression"); + 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"); + 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"); + as_warn (_("register value used as expression")); op = O_constant; } @@ -2197,6 +3473,8 @@ emit_expr (exp, nbytes) x = (struct broken_word *) xmalloc (sizeof (struct broken_word)); x->next_broken_word = broken_words; broken_words = x; + x->seg = now_seg; + x->subseg = now_subseg; x->frag = frag_now; x->word_goes_here = p; x->dispfrag = 0; @@ -2236,14 +3514,25 @@ emit_expr (exp, nbytes) register valueT get; register valueT use; register valueT mask; + valueT hibit; register valueT unmask; /* JF << of >= number of bits in the object is undefined. In particular SPARC (Sun 4) has problems */ if (nbytes >= sizeof (valueT)) - mask = 0; + { + mask = 0; + if (nbytes > sizeof (valueT)) + hibit = 0; + else + hibit = (valueT) 1 << (nbytes * BITS_PER_CHAR - 1); + } else - mask = ~(valueT) 0 << (BITS_PER_CHAR * nbytes); /* Don't store these bits. */ + { + /* Don't store these bits. */ + mask = ~(valueT) 0 << (BITS_PER_CHAR * nbytes); + hibit = (valueT) 1 << (nbytes * BITS_PER_CHAR - 1); + } unmask = ~mask; /* Do store these bits. */ @@ -2254,16 +3543,19 @@ 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, use, (int) nbytes); } else if (op == O_big) { - int size; + unsigned int size; LITTLENUM_TYPE *nums; know (nbytes % CHARS_PER_LITTLENUM == 0); @@ -2271,7 +3563,7 @@ emit_expr (exp, nbytes) size = exp->X_add_number * CHARS_PER_LITTLENUM; if (nbytes < size) { - as_warn ("Bignum truncated to %d bytes", nbytes); + as_warn (_("Bignum truncated to %d bytes"), nbytes); size = nbytes; } @@ -2330,11 +3622,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 @@ -2417,7 +3729,7 @@ parse_bitfield_cons (exp, nbytes) if (exp->X_op == O_absent) { - as_warn ("using a bit field width of zero"); + as_warn (_("using a bit field width of zero")); exp->X_add_number = 0; exp->X_op = O_constant; } /* implied zero width bitfield */ @@ -2425,7 +3737,7 @@ parse_bitfield_cons (exp, nbytes) if (exp->X_op != O_constant) { *input_line_pointer = '\0'; - as_bad ("field width \"%s\" too complex for a bitfield", hold); + as_bad (_("field width \"%s\" too complex for a bitfield"), hold); *input_line_pointer = ':'; demand_empty_rest_of_line (); return; @@ -2433,7 +3745,7 @@ parse_bitfield_cons (exp, nbytes) if ((width = exp->X_add_number) > (BITS_PER_CHAR * nbytes)) { - as_warn ("field width %lu too big to fit in %d bytes: truncated to %d bits", + as_warn (_("field width %lu too big to fit in %d bytes: truncated to %d bits"), width, nbytes, (BITS_PER_CHAR * nbytes)); width = BITS_PER_CHAR * nbytes; } /* too big */ @@ -2454,7 +3766,7 @@ parse_bitfield_cons (exp, nbytes) char cache = *input_line_pointer; *input_line_pointer = '\0'; - as_bad ("field value \"%s\" too complex for a bitfield", hold); + as_bad (_("field value \"%s\" too complex for a bitfield"), hold); *input_line_pointer = cache; demand_empty_rest_of_line (); return; @@ -2496,7 +3808,7 @@ parse_mri_cons (exp, nbytes) TC_PARSE_CONS_EXPRESSION (exp, nbytes); else { - int scan = 0; + unsigned int scan; unsigned int result = 0; /* An MRI style string. Cut into as many bytes as will fit into @@ -2506,7 +3818,7 @@ parse_mri_cons (exp, nbytes) ++input_line_pointer; else if (*input_line_pointer == 'E') { - as_bad ("EBCDIC constants are not supported"); + as_bad (_("EBCDIC constants are not supported")); ++input_line_pointer; } @@ -2576,7 +3888,7 @@ parse_repeat_cons (exp, nbytes) if (count.X_op != O_constant || count.X_add_number <= 0) { - as_warn ("Unresolvable or nonpositive repeat count; using 1"); + as_warn (_("Unresolvable or nonpositive repeat count; using 1")); return; } @@ -2627,7 +3939,7 @@ hex_float (float_type, bytes) break; default: - as_bad ("Unknown floating type type '%c'", float_type); + as_bad (_("Unknown floating type type '%c'"), float_type); return -1; } @@ -2649,7 +3961,7 @@ hex_float (float_type, bytes) if (i >= length) { - as_warn ("Floating point constant too large"); + as_warn (_("Floating point constant too large")); return -1; } d = hex_value (*input_line_pointer) << 4; @@ -2715,6 +4027,10 @@ float_cons (float_type) return; } +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + do { /* input_line_pointer->1st char of a flonum (we hope!). */ @@ -2725,7 +4041,8 @@ float_cons (float_type) * 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])) + if (input_line_pointer[0] == '0' + && isalpha ((unsigned char) input_line_pointer[1])) input_line_pointer += 2; /* Accept :xxxx, where the x's are hex digits, for a floating @@ -2747,7 +4064,7 @@ float_cons (float_type) know (length > 0); if (err) { - as_bad ("Bad floating literal: %s", err); + as_bad (_("Bad floating literal: %s"), err); ignore_rest_of_line (); return; } @@ -2769,7 +4086,7 @@ float_cons (float_type) if (count_exp.X_op != O_constant || count_exp.X_add_number <= 0) { - as_warn ("unresolvable or nonpositive repeat count; using 1"); + as_warn (_("unresolvable or nonpositive repeat count; using 1")); } else count = count_exp.X_add_number; @@ -2790,10 +4107,310 @@ float_cons (float_type) 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; +} + +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; +} + +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 inline int +output_big_sleb128 (p, bignum, size) + char *p; + LITTLENUM_TYPE *bignum; + int size; +{ + char *orig = p; + valueT val = 0; + 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 inline int +output_big_uleb128 (p, bignum, size) + char *p; + LITTLENUM_TYPE *bignum; + int size; +{ + char *orig = p; + valueT val = 0; + 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 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; + } + + if (op == O_constant) + { + /* If we've got a constant, emit the thing directly right now. */ + + valueT value = exp->X_add_number; + int size; + char *p; + + 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. */ + + int size; + char *p; + + 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. */ + + frag_var (rs_leb128, sizeof_uleb128 (~(valueT)0), 0, sign, + make_expr_symbol (exp), 0, (char *) NULL); + } +} + +/* Parse the .sleb128 and .uleb128 pseudos. */ + +void +s_leb128 (sign) + int sign; +{ + expressionS exp; + + do { + expression (&exp); + emit_leb128_expr (&exp, sign); + } while (*input_line_pointer++ == ','); + + input_line_pointer--; + demand_empty_rest_of_line (); +} + /* * stringer() * - * We read 0 or more ',' seperated, double-quoted strings. + * We read 0 or more ',' separated, double-quoted strings. * * Caller should have checked need_pass_2 is FALSE because we don't check it. */ @@ -2805,6 +4422,7 @@ 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 (); @@ -2812,7 +4430,7 @@ stringer (append_zero) /* Worker to do .ascii etc statements. */ /* * The following awkward logic is to parse ZERO or more strings, - * comma seperated. Recall a string expression includes spaces + * comma separated. Recall a string expression includes spaces * before the opening '\"' and spaces after the closing '\"'. * We fake a leading ',' if there is (supposed to be) * a 1st, expression. We keep demanding expressions for each @@ -2834,6 +4452,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); @@ -2843,6 +4462,27 @@ 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 section + after a sequence of constants. See the comment in + emit_expr for the sequence. emit_expr will set + dwarf_file_string to non-zero if this string might be a + source file name. */ + if (strcmp (segment_name (now_seg), ".debug") != 0) + dwarf_file_string = 0; + else if (dwarf_file_string) + { + 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++; @@ -2850,7 +4490,7 @@ stringer (append_zero) /* Worker to do .ascii etc statements. */ FRAG_APPEND_1_CHAR (c); if (*input_line_pointer != '>') { - as_bad ("Expected "); + as_bad (_("Expected ")); } input_line_pointer++; break; @@ -2882,6 +4522,11 @@ 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++) @@ -2961,14 +4606,15 @@ next_char_of_string () case '\n': /* To be compatible with BSD 4.2 as: give the luser a linefeed!! */ - as_warn ("Unterminated string: Newline inserted."); + as_warn (_("Unterminated string: Newline inserted.")); c = '\n'; + bump_line_counters (); break; default: #ifdef ONLY_STANDARD_ESCAPES - as_bad ("Bad escaped character in string, '?' assumed"); + as_bad (_("Bad escaped character in string, '?' assumed")); c = '?'; #endif /* ONLY_STANDARD_ESCAPES */ @@ -2994,7 +4640,7 @@ get_segmented_expression (expP) || expP->X_op == O_absent || expP->X_op == O_big) { - as_bad ("expected address expression; zero assumed"); + as_bad (_("expected address expression; zero assumed")); expP->X_op = O_constant; expP->X_add_number = 0; retval = absolute_section; @@ -3014,10 +4660,10 @@ get_known_segmented_expression (expP) expression. */ if (expP->X_add_symbol != NULL && S_GET_SEGMENT (expP->X_add_symbol) != expr_section) - as_warn ("symbol \"%s\" undefined; zero assumed", + as_warn (_("symbol \"%s\" undefined; zero assumed"), S_GET_NAME (expP->X_add_symbol)); else - as_warn ("some symbol undefined; zero assumed"); + as_warn (_("some symbol undefined; zero assumed")); retval = absolute_section; expP->X_op = O_constant; expP->X_add_number = 0; @@ -3035,7 +4681,7 @@ get_absolute_expression () if (exp.X_op != O_constant) { if (exp.X_op != O_absent) - as_bad ("bad or irreducible absolute expression; zero assumed"); + as_bad (_("bad or irreducible absolute expression; zero assumed")); exp.X_add_number = 0; } return exp.X_add_number; @@ -3066,20 +4712,18 @@ 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) { s = 0; len = 1; *len_pointer = 0; - as_bad ("This string may not contain \'\\0\'"); + as_bad (_("This string may not contain \'\\0\'")); } } } - return (s); + return s; } /* @@ -3107,14 +4751,14 @@ 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); } else { - as_warn ("Missing string"); + as_warn (_("Missing string")); retval = NULL; ignore_rest_of_line (); } @@ -3139,10 +4783,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 = NULL; + char stopc; input_line_pointer++; if (*input_line_pointer == '=') @@ -3151,6 +4798,9 @@ 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 */ @@ -3164,8 +4814,19 @@ equals (sym_name) 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) + { + ignore_rest_of_line (); /* check garbage after the expression */ + mri_comment_end (stop, stopc); + } } /* equals() */ /* .include -- include a file at this point. */ @@ -3173,7 +4834,7 @@ equals (sym_name) /* ARGSUSED */ void s_include (arg) - int arg; + int arg ATTRIBUTE_UNUSED; { char *newbuf; char *filename; @@ -3181,7 +4842,33 @@ s_include (arg) FILE *try; char *path; - filename = demand_copy_string (&i); + if (! flag_m68k_mri) + { + filename = demand_copy_string (&i); + if (filename == NULL) + { + /* demand_copy_string has already printed an error and + called ignore_rest_of_line. */ + return; + } + } + 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++) @@ -3199,6 +4886,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() */ @@ -3228,10 +4916,147 @@ add_include_dir (path) if (i > include_dir_maxlen) include_dir_maxlen = i; } /* add_include_dir() */ + +/* Output debugging information to denote the source file. */ + +static void +generate_file_debug () +{ + if (debug_type == DEBUG_STABS) + stabs_generate_asm_file (); +} + +/* Output line number debugging information for the current source line. */ + +void +generate_lineno_debug () +{ +#ifdef ECOFF_DEBUGGING + /* ECOFF assemblers automatically generate debugging information. + FIXME: This should probably be handled elsewhere. */ + if (debug_type == DEBUG_UNSPECIFIED) + { + if (ECOFF_DEBUGGING && ecoff_no_current_file ()) + debug_type = DEBUG_ECOFF; + else + debug_type = DEBUG_NONE; + } +#endif + + switch (debug_type) + { + case DEBUG_UNSPECIFIED: + case DEBUG_NONE: + break; + case DEBUG_STABS: + stabs_generate_asm_lineno (); + break; + case DEBUG_ECOFF: + ecoff_generate_asm_lineno (); + break; + case DEBUG_DWARF: + case DEBUG_DWARF2: + /* FIXME. */ + break; + } +} + +/* Output debugging information to mark a function entry point or end point. + END_P is zero for .func, and non-zero for .endfunc. */ + +void +s_func (end_p) + int end_p; +{ + do_s_func (end_p, NULL); +} + +/* Subroutine of s_func so targets can choose a different default prefix. + If DEFAULT_PREFIX is NULL, use the target's "leading char". */ + +void +do_s_func (end_p, default_prefix) + int end_p; + const char *default_prefix; +{ + /* Record the current function so that we can issue an error message for + misplaced .func,.endfunc, and also so that .endfunc needs no + arguments. */ + static char *current_name; + static char *current_label; + + if (end_p) + { + if (current_name == NULL) + { + as_bad (_("missing .func")); + ignore_rest_of_line (); + return; + } + + if (debug_type == DEBUG_STABS) + stabs_generate_asm_endfunc (current_name, current_label); + + current_name = current_label = NULL; + } + else /* ! end_p */ + { + char *name,*label; + char delim1,delim2; + + if (current_name != NULL) + { + as_bad (_(".endfunc missing for previous .func")); + ignore_rest_of_line (); + return; + } + + name = input_line_pointer; + delim1 = get_symbol_end (); + name = xstrdup (name); + *input_line_pointer = delim1; + SKIP_WHITESPACE (); + if (*input_line_pointer != ',') + { + if (default_prefix) + asprintf (&label, "%s%s", default_prefix, name); + else + { + char leading_char = 0; +#ifdef BFD_ASSEMBLER + leading_char = bfd_get_symbol_leading_char (stdoutput); +#endif + /* Missing entry point, use function's name with the leading + char prepended. */ + if (leading_char) + asprintf (&label, "%c%s", leading_char, name); + else + label = name; + } + } + else + { + ++input_line_pointer; + SKIP_WHITESPACE (); + label = input_line_pointer; + delim2 = get_symbol_end (); + label = xstrdup (label); + *input_line_pointer = delim2; + } + + if (debug_type == DEBUG_STABS) + stabs_generate_asm_func (name, label); + + current_name = name; + current_label = label; + } + demand_empty_rest_of_line (); +} + void s_ignore (arg) - int arg; + int arg ATTRIBUTE_UNUSED; { while (!is_end_of_line[(unsigned char) *input_line_pointer]) { @@ -3241,4 +5066,11 @@ s_ignore (arg) } +void +read_print_statistics (file) + FILE *file; +{ + hash_print_statistics (file, "pseudo-op table", po_hash); +} + /* end of read.c */