X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gas%2Fread.c;h=2f3b2383f22f983b1cc30deee2676b755b37acd5;hb=11ec4ba97796b1bdfc68b034ce3f719af81c3e48;hp=de405cc52fb39e832211d196434db6ea9bb099ef;hpb=8d548edbc907fc29e0d5d48b5c5f0004efeb52c9;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/read.c b/gas/read.c index de405cc52f..2f3b2383f2 100644 --- a/gas/read.c +++ b/gas/read.c @@ -1,38 +1,35 @@ /* read.c - read a source file - Copyright 1986, 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, - 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 + Free Software Foundation, Inc. -This file is part of GAS, the GNU Assembler. + This file is part of GAS, the GNU Assembler. -GAS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. -GAS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with GAS; see the file COPYING. If not, write to the Free -Software Foundation, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ + 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, 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ -#if 0 -/* If your chars aren't 8 bits, you will change this a bit. +/* If your chars aren't 8 bits, you will change this a bit (eg. to 0xFF). But then, GNU isn't spozed to run on your machine anyway. (RMS is so shortsighted sometimes.) */ -#define MASK_CHAR (0xFF) -#else #define MASK_CHAR ((int)(unsigned char) -1) -#endif /* This is the largest known floating point format (for now). It will grow when we do 4361 style flonums. */ #define MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT (16) -/* Routines that read assembler source text to build spagetti in memory. +/* Routines that read assembler source text to build spaghetti in memory. Another group of these functions is in the expr.c module. */ #include "as.h" @@ -41,7 +38,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "sb.h" #include "macro.h" #include "obstack.h" -#include "listing.h" #include "ecoff.h" #include "dw2gencfi.h" @@ -51,17 +47,17 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA /* Set by the object-format or the target. */ #ifndef TC_IMPLICIT_LCOMM_ALIGNMENT -#define TC_IMPLICIT_LCOMM_ALIGNMENT(SIZE, P2VAR) \ +#define TC_IMPLICIT_LCOMM_ALIGNMENT(SIZE, P2VAR) \ do \ - { \ - if ((SIZE) >= 8) \ - (P2VAR) = 3; \ - else if ((SIZE) >= 4) \ - (P2VAR) = 2; \ - else if ((SIZE) >= 2) \ - (P2VAR) = 1; \ - else \ - (P2VAR) = 0; \ + { \ + if ((SIZE) >= 8) \ + (P2VAR) = 3; \ + else if ((SIZE) >= 4) \ + (P2VAR) = 2; \ + else if ((SIZE) >= 2) \ + (P2VAR) = 1; \ + else \ + (P2VAR) = 0; \ } \ while (0) #endif @@ -75,7 +71,6 @@ die horribly; #endif #ifndef LEX_AT -/* The m88k unfortunately uses @ as a label beginner. */ #define LEX_AT 0 #endif @@ -101,7 +96,6 @@ die horribly; #endif #ifndef LEX_DOLLAR -/* The a29k assembler does not permits labels to start with $. */ #define LEX_DOLLAR 3 #endif @@ -155,7 +149,7 @@ char is_end_of_line[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* */ }; -#ifdef IGNORE_OPCODE_CASE +#ifndef TC_CASE_SENSITIVE char original_case_string[128]; #endif @@ -214,29 +208,24 @@ 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)); -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)); +static void do_s_func (int end_p, const char *default_prefix); +static void do_align (int, char *, int, int); +static void s_align (int, int); +static void s_altmacro (int); +static void s_bad_end (int); +#ifdef OBJ_ELF +static void s_gnu_attribute (int); +#endif +static void s_reloc (int); +static int hex_float (int, char *); +static segT get_known_segmented_expression (expressionS * expP); +static void pobegin (void); +static int get_line_sb (sb *); +static void generate_file_debug (void); +static char *_find_end_of_line (char *, int, int); void -read_begin () +read_begin (void) { const char *p; @@ -257,6 +246,22 @@ read_begin () lex_type['?'] = 3; } +#ifndef TC_ADDRESS_BYTES +#define TC_ADDRESS_BYTES address_bytes + +static inline int +address_bytes (void) +{ + /* Choose smallest of 1, 2, 4, 8 bytes that is large enough to + contain an address. */ + int n = (stdoutput->arch_info->bits_per_address - 1) / 8; + n |= n >> 1; + n |= n >> 2; + n += 1; + return n; +} +#endif + /* Set up pseudo-op tables. */ static struct hash_control *po_hash; @@ -264,8 +269,9 @@ static struct hash_control *po_hash; static const pseudo_typeS potable[] = { {"abort", s_abort, 0}, {"align", s_align_ptwo, 0}, - {"ascii", stringer, 0}, - {"asciz", stringer, 1}, + {"altmacro", s_altmacro, 1}, + {"ascii", stringer, 8+0}, + {"asciz", stringer, 8+1}, {"balign", s_align_bytes, 0}, {"balignw", s_align_bytes, -2}, {"balignl", s_align_bytes, -4}, @@ -276,6 +282,9 @@ static const pseudo_typeS potable[] = { {"common.s", s_mri_common, 1}, {"data", s_data, 0}, {"dc", cons, 2}, +#ifdef TC_ADDRESS_BYTES + {"dc.a", cons, 0}, +#endif {"dc.b", cons, 1}, {"dc.d", float_cons, 'd'}, {"dc.l", cons, 4}, @@ -312,16 +321,19 @@ static const pseudo_typeS potable[] = { {"endc", s_endif, 0}, {"endfunc", s_func, 1}, {"endif", s_endif, 0}, - {"endr", s_bad_endr, 0}, + {"endm", s_bad_end, 0}, + {"endr", s_bad_end, 1}, /* endef */ {"equ", s_set, 0}, {"equiv", s_set, 1}, + {"eqv", s_set, -1}, {"err", s_err, 0}, + {"error", s_errwarn, 1}, {"exitm", s_mexit, 0}, /* extend */ {"extern", s_ignore, 0}, /* We treat all undef as ext. */ {"appfile", s_app_file, 1}, - {"appline", s_app_line, 0}, + {"appline", s_app_line, 1}, {"fail", s_fail, 0}, {"file", s_app_file, 0}, {"fill", s_fill, 0}, @@ -330,8 +342,12 @@ static const pseudo_typeS potable[] = { {"func", s_func, 0}, {"global", s_globl, 0}, {"globl", s_globl, 0}, +#ifdef OBJ_ELF + {"gnu_attribute", s_gnu_attribute, 0}, +#endif {"hword", cons, 2}, {"if", s_if, (int) O_ne}, + {"ifb", s_ifb, 1}, {"ifc", s_ifc, 0}, {"ifdef", s_ifdef, 0}, {"ifeq", s_if, (int) O_eq}, @@ -340,6 +356,7 @@ static const pseudo_typeS potable[] = { {"ifgt", s_if, (int) O_gt}, {"ifle", s_if, (int) O_le}, {"iflt", s_if, (int) O_lt}, + {"ifnb", s_ifb, 0}, {"ifnc", s_ifc, 1}, {"ifndef", s_ifdef, 1}, {"ifne", s_if, (int) O_ne}, @@ -354,6 +371,7 @@ static const pseudo_typeS potable[] = { {"irepc", s_irp, 1}, {"lcomm", s_lcomm, 0}, {"lflags", listing_flags, 0}, /* Listing flags. */ + {"linefile", s_app_line, 0}, {"linkonce", s_linkonce, 0}, {"list", listing_list, 1}, /* Turn listing on. */ {"llen", listing_psize, 1}, @@ -364,6 +382,7 @@ static const pseudo_typeS potable[] = { {"mri", s_mri, 0}, {".mri", s_mri, 0}, /* Special case so .mri works in MRI mode. */ {"name", s_ignore, 0}, + {"noaltmacro", s_altmacro, 0}, {"noformat", s_ignore, 0}, {"nolist", listing_list, 0}, /* Turn listing off. */ {"nopage", listing_nopage, 0}, @@ -379,6 +398,7 @@ static const pseudo_typeS potable[] = { {"psize", listing_psize, 0}, /* Set paper size. */ {"purgem", s_purgem, 0}, {"quad", cons, 8}, + {"reloc", s_reloc, 0}, {"rep", s_rept, 0}, {"rept", s_rept, 0}, {"rva", s_rva, 4}, @@ -396,7 +416,11 @@ static const pseudo_typeS potable[] = { {"stabd", s_stab, 'd'}, {"stabn", s_stab, 'n'}, {"stabs", s_stab, 's'}, - {"string", stringer, 1}, + {"string", stringer, 8+1}, + {"string8", stringer, 8+1}, + {"string16", stringer, 16+1}, + {"string32", stringer, 32+1}, + {"string64", stringer, 64+1}, {"struct", s_struct, 0}, /* tag */ {"text", s_text, 0}, @@ -421,17 +445,39 @@ static const pseudo_typeS potable[] = { {"xdef", s_globl, 0}, {"xref", s_ignore, 0}, {"xstabs", s_xstab, 's'}, + {"warning", s_errwarn, 0}, + {"weakref", s_weakref, 0}, {"word", cons, 2}, {"zero", s_space, 0}, {NULL, NULL, 0} /* End sentinel. */ }; +static offsetT +get_absolute_expr (expressionS *exp) +{ + expression_and_evaluate (exp); + if (exp->X_op != O_constant) + { + if (exp->X_op != O_absent) + as_bad (_("bad or irreducible absolute expression")); + exp->X_add_number = 0; + } + return exp->X_add_number; +} + +offsetT +get_absolute_expression (void) +{ + expressionS exp; + + return get_absolute_expr (&exp); +} + static int pop_override_ok = 0; static const char *pop_table_name; void -pop_insert (table) - const pseudo_typeS *table; +pop_insert (const pseudo_typeS *table) { const char *errtxt; const pseudo_typeS *pop; @@ -457,7 +503,7 @@ pop_insert (table) #endif static void -pobegin () +pobegin (void) { po_hash = hash_new (); @@ -473,7 +519,7 @@ pobegin () /* Now portable ones. Skip any that we've seen already. */ pop_table_name = "standard"; pop_insert (potable); - + #ifdef TARGET_USE_CFIPOP pop_table_name = "cfi"; pop_override_ok = 1; @@ -484,9 +530,11 @@ pobegin () #define HANDLE_CONDITIONAL_ASSEMBLY() \ if (ignore_input ()) \ { \ - while (!is_end_of_line[(unsigned char) *input_line_pointer++]) \ - if (input_line_pointer == buffer_limit) \ - break; \ + char *eol = find_end_of_line (input_line_pointer, flag_m68k_mri); \ + input_line_pointer = (input_line_pointer <= buffer_limit \ + && eol >= buffer_limit) \ + ? buffer_limit \ + : eol + 1; \ continue; \ } @@ -497,9 +545,7 @@ static char *scrub_string; static char *scrub_string_end; static int -scrub_from_string (buf, buflen) - char *buf; - int buflen; +scrub_from_string (char *buf, int buflen) { int copy; @@ -511,11 +557,36 @@ scrub_from_string (buf, buflen) return copy; } +/* Helper function of read_a_source_file, which tries to expand a macro. */ +static int +try_macro (char term, const char *line) +{ + sb out; + const char *err; + macro_entry *macro; + + if (check_macro (line, &out, &err, ¯o)) + { + if (err != NULL) + as_bad ("%s", err); + *input_line_pointer++ = term; + input_scrub_include_sb (&out, + input_line_pointer, 1); + sb_kill (&out); + buffer_limit = + input_scrub_next_buffer (&input_line_pointer); +#ifdef md_macro_info + md_macro_info (macro); +#endif + return 1; + } + return 0; +} + /* We read the file, putting things into a web that represents what we have been reading. */ void -read_a_source_file (name) - char *name; +read_a_source_file (char *name) { register char c; register char *s; /* String of symbol, '\0' appended. */ @@ -539,8 +610,13 @@ read_a_source_file (name) while ((buffer_limit = input_scrub_next_buffer (&input_line_pointer)) != 0) { /* We have another line to parse. */ - know (buffer_limit[-1] == '\n'); /* Must have a sentinel. */ +#ifndef NO_LISTING + /* In order to avoid listing macro expansion lines with labels + multiple times, keep track of which line was last issued. */ + static char *last_eol; + last_eol = NULL; +#endif while (input_line_pointer < buffer_limit) { /* We have more of this buffer to parse. */ @@ -601,8 +677,8 @@ read_a_source_file (name) } /* In MRI mode, we need to handle the MACRO - pseudo-op specially: we don't want to put the - symbol in the symbol table. */ + pseudo-op specially: we don't want to put the + symbol in the symbol table. */ if (!mri_line_macro #ifdef TC_START_LABEL_WITHOUT_COLON && TC_START_LABEL_WITHOUT_COLON(c, @@ -623,25 +699,17 @@ read_a_source_file (name) } } - /* We are at the begining of a line, or similar place. + /* We are at the beginning of a line, or similar place. We expect a well-formed assembler statement. A "symbol-name:" is a statement. Depending on what compiler is used, the order of these tests may vary to catch most common case 1st. - Each test is independent of all other tests at the (top) level. - PLEASE make a compiler that doesn't use this assembler. - It is crufty to waste a compiler's time encoding things for this - assembler, which then wastes more time decoding it. - (And communicating via (linear) files is silly! - If you must pass stuff, please pass a tree!) */ - if ((c = *input_line_pointer++) == '\t' - || c == ' ' - || c == '\f' - || c == 0) + Each test is independent of all other tests at the (top) + level. */ + do c = *input_line_pointer++; - - know (c != ' '); /* No further leading whitespace. */ + while (c == '\t' || c == ' ' || c == '\f'); #ifndef NO_LISTING /* If listing is on, and we are expanding a macro, then give @@ -654,21 +722,23 @@ read_a_source_file (name) 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; + s = find_end_of_line (input_line_pointer - 1, flag_m68k_mri); - /* 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); + if (s != last_eol) + { + last_eol = s; + /* 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); @@ -685,10 +755,10 @@ read_a_source_file (name) c = get_symbol_end (); /* name's delimiter. */ /* C is character after symbol. - That character's place in the input line is now '\0'. - S points to the beginning of the symbol. - [In case of pseudo-op, s->'.'.] - Input_line_pointer->'\0' where c was. */ + That character's place in the input line is now '\0'. + S points to the beginning of the symbol. + [In case of pseudo-op, s->'.'.] + Input_line_pointer->'\0' where c was. */ if (TC_START_LABEL (c, input_line_pointer)) { if (flag_m68k_mri) @@ -721,13 +791,21 @@ read_a_source_file (name) /* Input_line_pointer->after ':'. */ SKIP_WHITESPACE (); } - else if (c == '=' - || ((c == ' ' || c == '\t') - && input_line_pointer[1] == '=' + else if (input_line_pointer[1] == '=' + && (c == '=' + || ((c == ' ' || c == '\t') + && input_line_pointer[2] == '='))) + { + equals (s, -1); + demand_empty_rest_of_line (); + } + else if ((c == '=' + || ((c == ' ' || c == '\t') + && input_line_pointer[1] == '=')) #ifdef TC_EQUAL_IN_INSN - && !TC_EQUAL_IN_INSN (c, input_line_pointer) + && !TC_EQUAL_IN_INSN (c, s) #endif - )) + ) { equals (s, 1); demand_empty_rest_of_line (); @@ -737,7 +815,7 @@ read_a_source_file (name) /* Expect pseudo-op or machine instruction. */ pop = NULL; -#ifdef IGNORE_OPCODE_CASE +#ifndef TC_CASE_SENSITIVE { char *s2 = s; @@ -753,8 +831,8 @@ read_a_source_file (name) #endif if (NO_PSEUDO_DOT || flag_m68k_mri) { - /* The MRI assembler and the m88k use pseudo-ops - without a period. */ + /* The MRI assembler uses pseudo-ops without + a period. */ pop = (pseudo_typeS *) hash_find (po_hash, s); if (pop != NULL && pop->poc_handler == NULL) pop = NULL; @@ -765,16 +843,18 @@ read_a_source_file (name) { /* PSEUDO - OP. - WARNING: c has next char, which may be end-of-line. - We lookup the pseudo-op table with s+1 because we - already know that the pseudo-op begins with a '.'. */ + WARNING: c has next char, which may be end-of-line. + We lookup the pseudo-op table with s+1 because we + already know that the pseudo-op begins with a '.'. */ if (pop == NULL) pop = (pseudo_typeS *) hash_find (po_hash, s + 1); + if (pop && !pop->poc_handler) + pop = NULL; /* In MRI mode, we may need to insert an - automatic alignment directive. What a hack - this is. */ + automatic alignment directive. What a hack + this is. */ if (mri_pending_align && (pop == NULL || !((pop->poc_handler == cons @@ -806,9 +886,18 @@ read_a_source_file (name) /* Print the error msg now, while we still can. */ if (pop == NULL) { - as_bad (_("unknown pseudo-op: `%s'"), s); + char *end = input_line_pointer; + *input_line_pointer = c; s_ignore (0); + c = *--input_line_pointer; + *input_line_pointer = '\0'; + if (! macro_defined || ! try_macro (c, s)) + { + *end = '\0'; + as_bad (_("unknown pseudo-op: `%s'"), s); + *input_line_pointer++ = c; + } continue; } @@ -821,8 +910,8 @@ read_a_source_file (name) input_line_pointer++; /* Input_line is restored. - Input_line_pointer->1st non-blank char - after pseudo-operation. */ + Input_line_pointer->1st non-blank char + after pseudo-operation. */ (*pop->poc_handler) (pop->poc_val); /* If that was .end, just get out now. */ @@ -831,61 +920,17 @@ read_a_source_file (name) } else { - 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++; - } - + input_line_pointer = _find_end_of_line (input_line_pointer, flag_m68k_mri, 1); c = *input_line_pointer; *input_line_pointer = '\0'; generate_lineno_debug (); - if (macro_defined) - { - sb out; - const char *err; - macro_entry *macro; - - if (check_macro (s, &out, &err, ¯o)) - { - if (err != NULL) - as_bad ("%s", err); - *input_line_pointer++ = c; - input_scrub_include_sb (&out, - input_line_pointer, 1); - sb_kill (&out); - buffer_limit = - input_scrub_next_buffer (&input_line_pointer); -#ifdef md_macro_info - md_macro_info (macro); -#endif - continue; - } - } + if (macro_defined && try_macro (c, s)) + continue; if (mri_pending_align) { @@ -965,10 +1010,14 @@ read_a_source_file (name) unsigned int new_length; char *tmp_buf = 0; - bump_line_counters (); s = input_line_pointer; if (strncmp (s, "APP\n", 4)) - continue; /* We ignore it */ + { + /* We ignore it. */ + ignore_rest_of_line (); + continue; + } + bump_line_counters (); s += 4; sb_new (&sbuf); @@ -982,7 +1031,7 @@ read_a_source_file (name) /* The end of the #APP wasn't in this buffer. We keep reading in buffers until we find the #NO_APP that goes with this #APP There is one. The specs - guarentee it... */ + guarantee it... */ tmp_len = buffer_limit - s; tmp_buf = xmalloc (tmp_len + 1); memcpy (tmp_buf, s, tmp_len); @@ -1067,8 +1116,8 @@ read_a_source_file (name) continue; #endif input_line_pointer--; - /* Report unknown char as ignored. */ - ignore_rest_of_line (); + /* Report unknown char as error. */ + demand_empty_rest_of_line (); } #ifdef md_after_pass_hook @@ -1092,6 +1141,29 @@ read_a_source_file (name) #endif } +/* Convert O_constant expression EXP into the equivalent O_big representation. + Take the sign of the number from X_unsigned rather than X_add_number. */ + +static void +convert_to_bignum (expressionS *exp) +{ + valueT value; + unsigned int i; + + value = exp->X_add_number; + for (i = 0; i < sizeof (exp->X_add_number) / CHARS_PER_LITTLENUM; i++) + { + generic_bignum[i] = value & LITTLENUM_MASK; + value >>= LITTLENUM_NUMBER_OF_BITS; + } + /* Add a sequence of sign bits if the top bit of X_add_number is not + the sign of the original value. */ + if ((exp->X_add_number < 0) != !exp->X_unsigned) + generic_bignum[i++] = exp->X_unsigned ? 0 : LITTLENUM_MASK; + exp->X_op = O_big; + exp->X_add_number = i; +} + /* 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 @@ -1101,8 +1173,7 @@ read_a_source_file (name) for the m68k MRI assembler. */ char * -mri_comment_field (stopcp) - char *stopcp; +mri_comment_field (char *stopcp) { char *s; #ifdef TC_M68K @@ -1133,9 +1204,7 @@ mri_comment_field (stopcp) /* Skip to the end of an MRI comment field. */ void -mri_comment_end (stop, stopc) - char *stop; - int stopc; +mri_comment_end (char *stop, int stopc) { know (flag_mri); @@ -1146,8 +1215,7 @@ mri_comment_end (stop, stopc) } void -s_abort (ignore) - int ignore ATTRIBUTE_UNUSED; +s_abort (int ignore ATTRIBUTE_UNUSED) { as_fatal (_(".abort detected. Abandoning ship.")); } @@ -1159,11 +1227,7 @@ s_abort (ignore) or 0 if there is no maximum. */ static void -do_align (n, fill, len, max) - int n; - char *fill; - int len; - int max; +do_align (int n, char *fill, int len, int max) { if (now_seg == absolute_section) { @@ -1178,6 +1242,9 @@ do_align (n, fill, len, max) len = 0; } +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif #ifdef md_do_align md_do_align (n, fill, len, max, just_record_alignment); #endif @@ -1209,15 +1276,17 @@ do_align (n, fill, len, max) (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. */ +#ifndef TC_ALIGN_LIMIT +#define TC_ALIGN_LIMIT (stdoutput->arch_info->bits_per_address - 1) +#endif static void -s_align (arg, bytes_p) - int arg; - int bytes_p; +s_align (int arg, int bytes_p) { - register unsigned int align; + unsigned int align_limit = TC_ALIGN_LIMIT; + unsigned int align; char *stop = NULL; - char stopc; + char stopc = 0; offsetT fill = 0; int max; int fill_p; @@ -1254,9 +1323,9 @@ s_align (arg, bytes_p) } } - if (align > 15) + if (align > align_limit) { - align = 15; + align = align_limit; as_warn (_("alignment too large: %u assumed"), align); } @@ -1328,8 +1397,7 @@ s_align (arg, bytes_p) align to a 4 byte boundary. */ void -s_align_bytes (arg) - int arg; +s_align_bytes (int arg) { s_align (arg, 1); } @@ -1338,23 +1406,32 @@ s_align_bytes (arg) to a 2**4 boundary. */ void -s_align_ptwo (arg) - int arg; +s_align_ptwo (int arg) { s_align (arg, 0); } +/* Switch in and out of alternate macro mode. */ + void -s_comm (ignore) - int ignore ATTRIBUTE_UNUSED; +s_altmacro (int on) { - register char *name; - register char c; - register char *p; - offsetT temp; - register symbolS *symbolP; + demand_empty_rest_of_line (); + macro_set_alternate (on); +} + +symbolS * +s_comm_internal (int param, + symbolS *(*comm_parse_extra) (int, symbolS *, addressT)) +{ + char *name; + char c; + char *p; + offsetT temp, size; + symbolS *symbolP = NULL; char *stop = NULL; - char stopc; + char stopc = 0; + expressionS exp; if (flag_mri) stop = mri_comment_field (&stopc); @@ -1368,84 +1445,96 @@ s_comm (ignore) if (name == p) { as_bad (_("expected symbol name")); - discard_rest_of_line (); - return; + ignore_rest_of_line (); + goto out; } SKIP_WHITESPACE (); - if (*input_line_pointer != ',') + /* Accept an optional comma after the name. The comma used to be + required, but Irix 5 cc does not generate it for .lcomm. */ + if (*input_line_pointer == ',') + input_line_pointer++; + + temp = get_absolute_expr (&exp); + size = temp; + size &= ((offsetT) 2 << (stdoutput->arch_info->bits_per_address - 1)) - 1; + if (exp.X_op == O_absent) { - *p = 0; - as_bad (_("expected comma after \"%s\""), name); - *p = c; + as_bad (_("missing size expression")); ignore_rest_of_line (); - if (flag_mri) - mri_comment_end (stop, stopc); - return; + goto out; } - - input_line_pointer++; /* skip ',' */ - - if ((temp = get_absolute_expression ()) < 0) + else if (temp != size || !exp.X_unsigned) { - as_warn (_(".COMMon length (%lu) out of range ignored"), - (unsigned long) temp); + as_warn (_("size (%ld) out of range, ignored"), (long) temp); ignore_rest_of_line (); - if (flag_mri) - mri_comment_end (stop, stopc); - return; + goto out; } *p = 0; symbolP = symbol_find_or_make (name); - *p = c; - - if (S_IS_DEFINED (symbolP) && !S_IS_COMMON (symbolP)) + if ((S_IS_DEFINED (symbolP) || symbol_equated_p (symbolP)) + && !S_IS_COMMON (symbolP)) { - as_bad (_("symbol `%s' is already defined"), - S_GET_NAME (symbolP)); - ignore_rest_of_line (); - if (flag_mri) - mri_comment_end (stop, stopc); - return; + if (!S_IS_VOLATILE (symbolP)) + { + symbolP = NULL; + as_bad (_("symbol `%s' is already defined"), name); + *p = c; + ignore_rest_of_line (); + goto out; + } + symbolP = symbol_clone (symbolP, 1); + S_SET_SEGMENT (symbolP, undefined_section); + S_SET_VALUE (symbolP, 0); + symbol_set_frag (symbolP, &zero_address_frag); + S_CLEAR_VOLATILE (symbolP); } - if (S_GET_VALUE (symbolP)) - { - if (S_GET_VALUE (symbolP) != (valueT) temp) - as_bad (_("length of .comm \"%s\" is already %ld; not changing to %ld"), - S_GET_NAME (symbolP), - (long) S_GET_VALUE (symbolP), - (long) temp); - } + size = S_GET_VALUE (symbolP); + if (size == 0) + size = temp; + else if (size != temp) + as_warn (_("size of \"%s\" is already %ld; not changing to %ld"), + name, (long) size, (long) temp); + + *p = c; + if (comm_parse_extra != NULL) + symbolP = (*comm_parse_extra) (param, symbolP, size); else { - S_SET_VALUE (symbolP, (valueT) temp); + S_SET_VALUE (symbolP, (valueT) size); S_SET_EXTERNAL (symbolP); - } + S_SET_SEGMENT (symbolP, bfd_com_section_ptr); #ifdef OBJ_VMS - { - extern int flag_one; - if (!temp || !flag_one) - S_GET_OTHER(symbolP) = const_flag; - } -#endif /* not OBJ_VMS */ - know (symbolP->sy_frag == &zero_address_frag); + { + extern int flag_one; + if (size == 0 || !flag_one) + S_GET_OTHER (symbolP) = const_flag; + } +#endif + } demand_empty_rest_of_line (); - + out: if (flag_mri) mri_comment_end (stop, stopc); -} /* s_comm() */ + return symbolP; +} + +void +s_comm (int ignore) +{ + s_comm_internal (ignore, NULL); +} /* The MRI COMMON pseudo-op. We handle this by creating a common symbol with the appropriate name. We make s_space do the right thing by increasing the size. */ void -s_mri_common (small) - int small ATTRIBUTE_UNUSED; +s_mri_common (int small ATTRIBUTE_UNUSED) { char *name; char c; @@ -1453,7 +1542,7 @@ s_mri_common (small) symbolS *sym; offsetT align; char *stop = NULL; - char stopc; + char stopc = 0; if (!flag_mri) { @@ -1511,6 +1600,7 @@ s_mri_common (small) } S_SET_EXTERNAL (sym); + S_SET_SEGMENT (sym, bfd_com_section_ptr); mri_common_symbol = sym; #ifdef S_SET_ALIGN @@ -1544,8 +1634,7 @@ s_mri_common (small) } void -s_data (ignore) - int ignore ATTRIBUTE_UNUSED; +s_data (int ignore ATTRIBUTE_UNUSED) { segT section; register int temp; @@ -1575,8 +1664,7 @@ s_data (ignore) .file. */ void -s_app_file_string (file) - char *file; +s_app_file_string (char *file, int appfile ATTRIBUTE_UNUSED) { #ifdef LISTING if (listing) @@ -1584,13 +1672,12 @@ s_app_file_string (file) #endif register_dependency (file); #ifdef obj_app_file - obj_app_file (file); + obj_app_file (file, appfile); #endif } void -s_app_file (appfile) - int appfile; +s_app_file (int appfile) { register char *s; int length; @@ -1598,14 +1685,11 @@ s_app_file (appfile) /* Some assemblers tolerate immediately following '"'. */ if ((s = demand_copy_string (&length)) != 0) { - /* 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. */ int may_omit - = (!new_logical_line (s, appfile ? -2 : -1) && appfile); + = (!new_logical_line_flags (s, -1, 1) && appfile); /* In MRI mode, the preprocessor may have inserted an extraneous - backquote. */ + backquote. */ if (flag_m68k_mri && *input_line_pointer == '\'' && is_end_of_line[(unsigned char) input_line_pointer[1]]) @@ -1613,50 +1697,139 @@ s_app_file (appfile) demand_empty_rest_of_line (); if (!may_omit) - s_app_file_string (s); + s_app_file_string (s, appfile); } } +static int +get_linefile_number (int *flag) +{ + SKIP_WHITESPACE (); + + if (*input_line_pointer < '0' || *input_line_pointer > '9') + return 0; + + *flag = get_absolute_expression (); + + return 1; +} + /* Handle the .appline pseudo-op. This is automatically generated by 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 ATTRIBUTE_UNUSED; +s_app_line (int appline) { + char *file = NULL; int l; /* The given number is that of the next line. */ - l = get_absolute_expression () - 1; - if (l < 0) + if (appline) + l = get_absolute_expression (); + else if (!get_linefile_number (&l)) + { + ignore_rest_of_line (); + return; + } + + l--; + + if (l < -1) /* Some of the back ends can't deal with non-positive line numbers. - Besides, it's silly. */ + Besides, it's silly. GCC however will generate a line number of + zero when it is pre-processing builtins for assembler-with-cpp files: + + # 0 "" + + We do not want to barf on this, especially since such files are used + in the GCC and GDB testsuites. So we check for negative line numbers + rather than non-positive line numbers. */ as_warn (_("line numbers must be positive; line number %d rejected"), l + 1); else { - new_logical_line ((char *) NULL, l); + int flags = 0; + int length = 0; + + if (!appline) + { + SKIP_WHITESPACE (); + + if (*input_line_pointer == '"') + file = demand_copy_string (&length); + + if (file) + { + int this_flag; + + while (get_linefile_number (&this_flag)) + switch (this_flag) + { + /* From GCC's cpp documentation: + 1: start of a new file. + 2: returning to a file after having included + another file. + 3: following text comes from a system header file. + 4: following text should be treated as extern "C". + + 4 is nonsensical for the assembler; 3, we don't + care about, so we ignore it just in case a + system header file is included while + preprocessing assembly. So 1 and 2 are all we + care about, and they are mutually incompatible. + new_logical_line_flags() demands this. */ + case 1: + case 2: + if (flags && flags != (1 << this_flag)) + as_warn (_("incompatible flag %i in line directive"), + this_flag); + else + flags |= 1 << this_flag; + break; + + case 3: + case 4: + /* We ignore these. */ + break; + + default: + as_warn (_("unsupported flag %i in line directive"), + this_flag); + break; + } + + if (!is_end_of_line[(unsigned char)*input_line_pointer]) + file = 0; + } + } + + if (appline || file) + { + new_logical_line_flags (file, l, flags); #ifdef LISTING - if (listing) - listing_source_line (l); + if (listing) + listing_source_line (l); #endif + } } - demand_empty_rest_of_line (); + if (appline || file) + demand_empty_rest_of_line (); + else + ignore_rest_of_line (); } /* Handle the .end pseudo-op. Actually, the real work is done in read_a_source_file. */ void -s_end (ignore) - int ignore ATTRIBUTE_UNUSED; +s_end (int ignore ATTRIBUTE_UNUSED) { if (flag_mri) { /* The MRI assembler permits the start symbol to follow .end, - but we don't support that. */ + but we don't support that. */ SKIP_WHITESPACE (); if (!is_end_of_line[(unsigned char) *input_line_pointer] && *input_line_pointer != '*' @@ -1668,22 +1841,57 @@ s_end (ignore) /* Handle the .err pseudo-op. */ void -s_err (ignore) - int ignore ATTRIBUTE_UNUSED; +s_err (int ignore ATTRIBUTE_UNUSED) { as_bad (_(".err encountered")); demand_empty_rest_of_line (); } +/* Handle the .error and .warning pseudo-ops. */ + +void +s_errwarn (int err) +{ + int len; + /* The purpose for the conditional assignment is not to + internationalize the directive itself, but that we need a + self-contained message, one that can be passed like the + demand_copy_C_string return value, and with no assumption on the + location of the name of the directive within the message. */ + char *msg + = (err ? _(".error directive invoked in source file") + : _(".warning directive invoked in source file")); + + if (!is_it_end_of_statement ()) + { + if (*input_line_pointer != '\"') + { + as_bad (_("%s argument must be a string"), + err ? ".error" : ".warning"); + ignore_rest_of_line (); + return; + } + + msg = demand_copy_C_string (&len); + if (msg == NULL) + return; + } + + if (err) + as_bad ("%s", msg); + else + as_warn ("%s", msg); + demand_empty_rest_of_line (); +} + /* Handle the MRI fail pseudo-op. */ void -s_fail (ignore) - int ignore ATTRIBUTE_UNUSED; +s_fail (int ignore ATTRIBUTE_UNUSED) { offsetT temp; char *stop = NULL; - char stopc; + char stopc = 0; if (flag_mri) stop = mri_comment_field (&stopc); @@ -1701,8 +1909,7 @@ s_fail (ignore) } void -s_fill (ignore) - int ignore ATTRIBUTE_UNUSED; +s_fill (int ignore ATTRIBUTE_UNUSED) { expressionS rep_exp; long size = 1; @@ -1782,32 +1989,31 @@ s_fill (ignore) memset (p, 0, (unsigned int) size); /* The magic number BSD_FILL_SIZE_CROCK_4 is from BSD 4.2 VAX - flavoured AS. The following bizarre 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. */ + flavoured AS. The following bizarre 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. */ #define BSD_FILL_SIZE_CROCK_4 (4) md_number_to_chars (p, (valueT) fill, (size > BSD_FILL_SIZE_CROCK_4 ? BSD_FILL_SIZE_CROCK_4 : (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 + 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. */ } demand_empty_rest_of_line (); } void -s_globl (ignore) - int ignore ATTRIBUTE_UNUSED; +s_globl (int ignore ATTRIBUTE_UNUSED) { char *name; int c; symbolS *symbolP; char *stop = NULL; - char stopc; + char stopc = 0; if (flag_mri) stop = mri_comment_field (&stopc); @@ -1838,13 +2044,126 @@ s_globl (ignore) mri_comment_end (stop, stopc); } +#ifdef OBJ_ELF +#define skip_whitespace(str) do { if (*(str) == ' ') ++(str); } while (0) + +static inline int +skip_past_char (char ** str, char c) +{ + if (**str == c) + { + (*str)++; + return 0; + } + else + return -1; +} +#define skip_past_comma(str) skip_past_char (str, ',') + +/* Parse an attribute directive for VENDOR. */ +void +s_vendor_attribute (int vendor) +{ + expressionS exp; + int type; + int tag; + unsigned int i = 0; + char *s = NULL; + char saved_char; + + expression (& exp); + if (exp.X_op != O_constant) + goto bad; + + tag = exp.X_add_number; + type = _bfd_elf_obj_attrs_arg_type (stdoutput, vendor, tag); + + if (skip_past_comma (&input_line_pointer) == -1) + goto bad; + if (type & 1) + { + expression (& exp); + if (exp.X_op != O_constant) + { + as_bad (_("expected numeric constant")); + ignore_rest_of_line (); + return; + } + i = exp.X_add_number; + } + if (type == 3 + && skip_past_comma (&input_line_pointer) == -1) + { + as_bad (_("expected comma")); + ignore_rest_of_line (); + return; + } + if (type & 2) + { + skip_whitespace(input_line_pointer); + if (*input_line_pointer != '"') + goto bad_string; + input_line_pointer++; + s = input_line_pointer; + while (*input_line_pointer && *input_line_pointer != '"') + input_line_pointer++; + if (*input_line_pointer != '"') + goto bad_string; + saved_char = *input_line_pointer; + *input_line_pointer = 0; + } + else + { + s = NULL; + saved_char = 0; + } + + switch (type) + { + case 3: + bfd_elf_add_obj_attr_compat (stdoutput, vendor, i, s); + break; + case 2: + bfd_elf_add_obj_attr_string (stdoutput, vendor, tag, s); + break; + case 1: + bfd_elf_add_obj_attr_int (stdoutput, vendor, tag, i); + break; + default: + abort (); + } + + if (s) + { + *input_line_pointer = saved_char; + input_line_pointer++; + } + demand_empty_rest_of_line (); + return; +bad_string: + as_bad (_("bad string constant")); + ignore_rest_of_line (); + return; +bad: + as_bad (_("expected , ")); + ignore_rest_of_line (); +} + +/* Parse a .gnu_attribute directive. */ + +static void +s_gnu_attribute (int ignored ATTRIBUTE_UNUSED) +{ + s_vendor_attribute (OBJ_ATTR_GNU); +} +#endif /* OBJ_ELF */ + /* Handle the MRI IRP and IRPC pseudo-ops. */ void -s_irp (irpc) - int irpc; +s_irp (int irpc) { - char *file; + char *file, *eol; unsigned int line; sb s; const char *err; @@ -1853,8 +2172,9 @@ s_irp (irpc) as_where (&file, &line); sb_new (&s); - while (!is_end_of_line[(unsigned char) *input_line_pointer]) - sb_add_char (&s, *input_line_pointer++); + eol = find_end_of_line (input_line_pointer, 0); + sb_add_buffer (&s, input_line_pointer, eol - input_line_pointer); + input_line_pointer = eol; sb_new (&out); @@ -1875,8 +2195,7 @@ s_irp (irpc) which is what to do about duplicates. */ void -s_linkonce (ignore) - int ignore ATTRIBUTE_UNUSED; +s_linkonce (int ignore ATTRIBUTE_UNUSED) { enum linkonce_type type; @@ -1908,7 +2227,6 @@ s_linkonce (ignore) #ifdef obj_handle_link_once obj_handle_link_once (type); #else /* ! defined (obj_handle_link_once) */ -#ifdef BFD_ASSEMBLER { flagword flags; @@ -1938,234 +2256,150 @@ s_linkonce (ignore) 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; +void +bss_alloc (symbolS *symbolP, addressT size, int align) { - register char *name; - register char c; - register char *p; - register int temp; - register symbolS *symbolP; + char *pfrag; segT current_seg = now_seg; subsegT current_subseg = now_subseg; - const int max_alignment = 15; - int align = 0; segT bss_seg = bss_section; - name = input_line_pointer; - c = get_symbol_end (); - p = input_line_pointer; - *p = c; - - if (name == p) - { - as_bad (_("expected symbol name")); - discard_rest_of_line (); - return; - } - - SKIP_WHITESPACE (); - - /* Accept an optional comma after the name. The comma used to be - required, but Irix 5 cc does not generate it. */ - if (*input_line_pointer == ',') - { - ++input_line_pointer; - SKIP_WHITESPACE (); - } - - if (is_end_of_line[(unsigned char) *input_line_pointer]) - { - as_bad (_("missing size expression")); - return; - } - - if ((temp = get_absolute_expression ()) < 0) - { - as_warn (_("BSS length (%d) < 0 ignored"), temp); - ignore_rest_of_line (); - return; - } - #if defined (TC_MIPS) || defined (TC_ALPHA) if (OUTPUT_FLAVOR == bfd_target_ecoff_flavour || OUTPUT_FLAVOR == bfd_target_elf_flavour) { /* For MIPS and Alpha ECOFF or ELF, small objects are put in .sbss. */ - if ((unsigned) temp <= bfd_get_gp_size (stdoutput)) + if (size <= bfd_get_gp_size (stdoutput)) { bss_seg = subseg_new (".sbss", 1); seg_info (bss_seg)->bss = 1; -#ifdef BFD_ASSEMBLER if (!bfd_set_section_flags (stdoutput, bss_seg, SEC_ALLOC)) as_warn (_("error setting flags for \".sbss\": %s"), bfd_errmsg (bfd_get_error ())); -#endif } } #endif + subseg_set (bss_seg, 1); - if (!needs_align) + if (align) { - TC_IMPLICIT_LCOMM_ALIGNMENT (temp, align); - - /* Still zero unless TC_IMPLICIT_LCOMM_ALIGNMENT set it. */ - if (align) - record_alignment (bss_seg, align); + record_alignment (bss_seg, align); + frag_align (align, 0, 0); } - if (needs_align) - { - align = 0; - SKIP_WHITESPACE (); + /* Detach from old frag. */ + if (S_GET_SEGMENT (symbolP) == bss_seg) + symbol_get_frag (symbolP)->fr_symbol = NULL; - if (*input_line_pointer != ',') - { - as_bad (_("expected comma after size")); - ignore_rest_of_line (); - return; - } + symbol_set_frag (symbolP, frag_now); + pfrag = frag_var (rs_org, 1, 1, 0, symbolP, size, NULL); + *pfrag = 0; - input_line_pointer++; - SKIP_WHITESPACE (); +#ifdef S_SET_SIZE + S_SET_SIZE (symbolP, size); +#endif + S_SET_SEGMENT (symbolP, bss_seg); - if (is_end_of_line[(unsigned char) *input_line_pointer]) - { - as_bad (_("missing alignment")); - return; - } +#ifdef OBJ_COFF + /* The symbol may already have been created with a preceding + ".globl" directive -- be careful not to step on storage class + in that case. Otherwise, set it to static. */ + if (S_GET_STORAGE_CLASS (symbolP) != C_EXT) + S_SET_STORAGE_CLASS (symbolP, C_STAT); +#endif /* OBJ_COFF */ - align = get_absolute_expression (); + subseg_set (current_seg, current_subseg); +} - if (bytes_p) - { - /* Convert to a power of 2. */ - if (align != 0) - { - unsigned int i; +offsetT +parse_align (int align_bytes) +{ + expressionS exp; + addressT align; - for (i = 0; (align & 1) == 0; align >>= 1, ++i) - ; - if (align != 1) - as_bad (_("alignment not a power of 2")); - align = i; - } - } + SKIP_WHITESPACE (); + if (*input_line_pointer != ',') + { + no_align: + as_bad (_("expected alignment after size")); + ignore_rest_of_line (); + return -1; + } - if (align > max_alignment) - { - align = max_alignment; - as_warn (_("alignment too large; %d assumed"), align); - } - else if (align < 0) - { - align = 0; - as_warn (_("alignment negative; 0 assumed")); - } + input_line_pointer++; + SKIP_WHITESPACE (); - record_alignment (bss_seg, align); + align = get_absolute_expr (&exp); + if (exp.X_op == O_absent) + goto no_align; + + if (!exp.X_unsigned) + { + as_warn (_("alignment negative; 0 assumed")); + align = 0; } - else + + if (align_bytes && align != 0) { - /* Assume some objects may require alignment on some systems. */ -#if defined (TC_ALPHA) && ! defined (VMS) - if (temp > 1) + /* convert to a power of 2 alignment */ + unsigned int alignp2 = 0; + while ((align & 1) == 0) + align >>= 1, ++alignp2; + if (align != 1) { - align = ffs (temp) - 1; - if (temp % (1 << align)) - abort (); + as_bad (_("alignment not a power of 2")); + ignore_rest_of_line (); + return -1; } -#endif + align = alignp2; } + return align; +} - *p = 0; - symbolP = symbol_find_or_make (name); - *p = c; - - if ( -#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT) \ - || defined (OBJ_BOUT) || defined (OBJ_MAYBE_BOUT)) -#ifdef BFD_ASSEMBLER - (OUTPUT_FLAVOR != bfd_target_aout_flavour - || (S_GET_OTHER (symbolP) == 0 && S_GET_DESC (symbolP) == 0)) && -#else - (S_GET_OTHER (symbolP) == 0 && S_GET_DESC (symbolP) == 0) && -#endif -#endif - (S_GET_SEGMENT (symbolP) == bss_seg - || (!S_IS_DEFINED (symbolP) && S_GET_VALUE (symbolP) == 0))) - { - char *pfrag; - - subseg_set (bss_seg, 1); - - if (align) - frag_align (align, 0, 0); - - /* Detach from old frag. */ - if (S_GET_SEGMENT (symbolP) == bss_seg) - symbol_get_frag (symbolP)->fr_symbol = NULL; - - symbol_set_frag (symbolP, frag_now); - pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, - (offsetT) temp, (char *) 0); - *pfrag = 0; - - S_SET_SEGMENT (symbolP, bss_seg); +/* Called from s_comm_internal after symbol name and size have been + parsed. NEEDS_ALIGN is 0 if it was an ".lcomm" (2 args only), + 1 if this was a ".bss" directive which has a 3rd argument + (alignment as a power of 2), or 2 if this was a ".bss" directive + with alignment in bytes. */ -#ifdef OBJ_COFF - /* The symbol may already have been created with a preceding - ".globl" directive -- be careful not to step on storage class - in that case. Otherwise, set it to static. */ - if (S_GET_STORAGE_CLASS (symbolP) != C_EXT) - { - S_SET_STORAGE_CLASS (symbolP, C_STAT); - } -#endif /* OBJ_COFF */ +symbolS * +s_lcomm_internal (int needs_align, symbolS *symbolP, addressT size) +{ + addressT align = 0; -#ifdef S_SET_SIZE - S_SET_SIZE (symbolP, temp); -#endif + if (needs_align) + { + align = parse_align (needs_align - 1); + if (align == (addressT) -1) + return NULL; } else - as_bad (_("symbol `%s' is already defined"), S_GET_NAME (symbolP)); + /* Assume some objects may require alignment on some systems. */ + TC_IMPLICIT_LCOMM_ALIGNMENT (size, align); - subseg_set (current_seg, current_subseg); - - demand_empty_rest_of_line (); + bss_alloc (symbolP, size, align); + return symbolP; } void -s_lcomm (needs_align) - int needs_align; +s_lcomm (int needs_align) { - s_lcomm_internal (needs_align, 0); + s_comm_internal (needs_align, s_lcomm_internal); } void -s_lcomm_bytes (needs_align) - int needs_align; +s_lcomm_bytes (int needs_align) { - s_lcomm_internal (needs_align, 1); + s_comm_internal (needs_align * 2, s_lcomm_internal); } void -s_lsym (ignore) - int ignore ATTRIBUTE_UNUSED; +s_lsym (int ignore ATTRIBUTE_UNUSED) { register char *name; register char c; @@ -2182,7 +2416,7 @@ s_lsym (ignore) if (name == p) { as_bad (_("expected symbol name")); - discard_rest_of_line (); + ignore_rest_of_line (); return; } @@ -2198,7 +2432,7 @@ s_lsym (ignore) } input_line_pointer++; - expression (&exp); + expression_and_evaluate (&exp); if (exp.X_op != O_constant && exp.X_op != O_register) @@ -2211,15 +2445,7 @@ s_lsym (ignore) *p = 0; symbolP = symbol_find_or_make (name); - /* FIXME-SOON I pulled a (&& symbolP->sy_other == 0 && - symbolP->sy_desc == 0) out of this test because coff doesn't have - those fields, and I can't see when they'd ever be tripped. I - don't think I understand why they were here so I may have - introduced a bug. As recently as 1.37 didn't have this test - anyway. xoxorich. */ - - if (S_GET_SEGMENT (symbolP) == undefined_section - && S_GET_VALUE (symbolP) == 0) + if (S_GET_SEGMENT (symbolP) == undefined_section) { /* The name might be an undefined .global symbol; be sure to keep the "external" bit. */ @@ -2242,11 +2468,9 @@ s_lsym (ignore) or zero if there are no more lines. */ static int -get_line_sb (line) - sb *line; +get_line_sb (sb *line) { - char quote1, quote2, inquote; - unsigned char c; + char *eol; if (input_line_pointer[-1] == '\n') bump_line_counters (); @@ -2258,78 +2482,54 @@ get_line_sb (line) 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 ((c = * input_line_pointer ++) != 0 - && (!is_end_of_line[c] - || (inquote != '\0' && c != '\n'))) - { - if (inquote == c) - inquote = '\0'; - else if (inquote == '\0') - { - if (c == quote1) - inquote = quote1; - else if (c == quote2) - inquote = quote2; - } - - sb_add_char (line, c); - } + eol = find_end_of_line (input_line_pointer, flag_m68k_mri); + sb_add_buffer (line, input_line_pointer, eol - input_line_pointer); + input_line_pointer = eol; /* Don't skip multiple end-of-line characters, because that breaks support for the IA-64 stop bit (;;) which looks like two consecutive end-of-line characters but isn't. Instead just skip one end of line character and return the character skipped so that the caller can re-insert it if necessary. */ - return c; + return *input_line_pointer++; } /* Define a macro. This is an interface to macro.c. */ void -s_macro (ignore) - int ignore ATTRIBUTE_UNUSED; +s_macro (int ignore ATTRIBUTE_UNUSED) { - char *file; + char *file, *eol; 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++); + eol = find_end_of_line (input_line_pointer, 0); + sb_add_buffer (&s, input_line_pointer, eol - input_line_pointer); + input_line_pointer = eol; - sb_new (&label); if (line_label != NULL) - sb_add_string (&label, S_GET_NAME (line_label)); + { + sb label; - err = define_macro (0, &s, &label, get_line_sb, &name); + sb_new (&label); + sb_add_string (&label, S_GET_NAME (line_label)); + err = define_macro (0, &s, &label, get_line_sb, file, line, &name); + sb_kill (&label); + } + else + err = define_macro (0, &s, NULL, get_line_sb, file, line, &name); if (err != NULL) - as_bad_where (file, line, "%s", err); + as_bad_where (file, line, err, name); else { if (line_label != NULL) { - S_SET_SEGMENT (line_label, undefined_section); + S_SET_SEGMENT (line_label, absolute_section); S_SET_VALUE (line_label, 0); symbol_set_frag (line_label, &zero_address_frag); } @@ -2339,7 +2539,9 @@ s_macro (ignore) || (!flag_m68k_mri && *name == '.' && hash_find (po_hash, name + 1) != NULL)) - as_warn (_("attempt to redefine pseudo-op `%s' ignored"), + as_warn_where (file, + line, + _("attempt to redefine pseudo-op `%s' ignored"), name); } @@ -2350,8 +2552,7 @@ s_macro (ignore) expansion. */ void -s_mexit (ignore) - int ignore ATTRIBUTE_UNUSED; +s_mexit (int ignore ATTRIBUTE_UNUSED) { cond_exit_macro (macro_nest); buffer_limit = input_scrub_next_buffer (&input_line_pointer); @@ -2360,8 +2561,7 @@ s_mexit (ignore) /* Switch in and out of MRI mode. */ void -s_mri (ignore) - int ignore ATTRIBUTE_UNUSED; +s_mri (int ignore ATTRIBUTE_UNUSED) { int on, old_flag; @@ -2399,10 +2599,7 @@ s_mri (ignore) /* Handle changing the location counter. */ static void -do_org (segment, exp, fill) - segT segment; - expressionS *exp; - int fill; +do_org (segT segment, expressionS *exp, int fill) { if (segment != now_seg && segment != absolute_section) as_bad (_("invalid segment \"%s\""), segment_name (segment)); @@ -2437,8 +2634,7 @@ do_org (segment, exp, fill) } void -s_org (ignore) - int ignore ATTRIBUTE_UNUSED; +s_org (int ignore ATTRIBUTE_UNUSED) { register segT segment; expressionS exp; @@ -2489,12 +2685,10 @@ s_org (ignore) 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. */ + 'M' (mixed), or 'R' (romable). The flags will be set in the section. */ void -s_mri_sect (type) - char *type ATTRIBUTE_UNUSED; +s_mri_sect (char *type ATTRIBUTE_UNUSED) { #ifdef TC_M68K @@ -2545,7 +2739,6 @@ s_mri_sect (type) as_bad (_("unrecognized section type")); ++input_line_pointer; -#ifdef BFD_ASSEMBLER { flagword flags; @@ -2564,7 +2757,6 @@ s_mri_sect (type) bfd_errmsg (bfd_get_error ())); } } -#endif } /* Ignore the HP type. */ @@ -2658,22 +2850,21 @@ s_mri_sect (type) /* Handle the .print pseudo-op. */ void -s_print (ignore) - int ignore ATTRIBUTE_UNUSED; +s_print (int ignore ATTRIBUTE_UNUSED) { char *s; int len; s = demand_copy_C_string (&len); - printf ("%s\n", s); + if (s != NULL) + printf ("%s\n", s); demand_empty_rest_of_line (); } /* Handle the .purgem pseudo-op. */ void -s_purgem (ignore) - int ignore ATTRIBUTE_UNUSED; +s_purgem (int ignore ATTRIBUTE_UNUSED) { if (is_it_end_of_statement ()) { @@ -2699,21 +2890,21 @@ s_purgem (ignore) demand_empty_rest_of_line (); } -/* Handle the .rept pseudo-op. */ +/* Handle the .endm/.endr pseudo-ops. */ -void -s_bad_endr (ignore) - int ignore ATTRIBUTE_UNUSED; +static void +s_bad_end (int endr) { - as_warn (_(".endr encountered without preceeding .rept, .irc, or .irp")); + as_warn (_(".end%c encountered without preceeding %s"), + endr ? 'r' : 'm', + endr ? ".rept, .irp, or .irpc" : ".macro"); demand_empty_rest_of_line (); } /* Handle the .rept pseudo-op. */ void -s_rept (ignore) - int ignore ATTRIBUTE_UNUSED; +s_rept (int ignore ATTRIBUTE_UNUSED) { int count; @@ -2726,10 +2917,7 @@ s_rept (ignore) different directives to be used as the start/end keys. */ void -do_repeat (count, start, end) - int count; - const char *start; - const char *end; +do_repeat (int count, const char *start, const char *end) { sb one; sb many; @@ -2761,60 +2949,22 @@ do_repeat (count, start, end) such as line substitutions. */ void -end_repeat (extra) - int extra; +end_repeat (int extra) { cond_exit_macro (macro_nest); while (extra-- >= 0) 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 (equiv) - int equiv; +static void +assign_symbol (char *name, int mode) { - register char *name; - register char delim; - register char *end_name; - register symbolS *symbolP; - - /* Especial apologies for the random logic: - this just grew, and could be parsed much more simply! - Dean in haste. */ - name = input_line_pointer; - delim = get_symbol_end (); - end_name = input_line_pointer; - *end_name = delim; - - if (name == end_name) - { - as_bad (_("expected symbol name")); - discard_rest_of_line (); - return; - } - - SKIP_WHITESPACE (); - - if (*input_line_pointer != ',') - { - *end_name = 0; - as_bad (_("expected comma after \"%s\""), name); - *end_name = delim; - ignore_rest_of_line (); - return; - } - - input_line_pointer++; - *end_name = 0; + symbolS *symbolP; if (name[0] == '.' && name[1] == '\0') { /* Turn '. = mumble' into a .org mumble. */ - register segT segment; + segT segment; expressionS exp; segment = get_known_segmented_expression (&exp); @@ -2822,59 +2972,111 @@ s_set (equiv) if (!need_pass_2) do_org (segment, &exp, 0); - *end_name = delim; return; } if ((symbolP = symbol_find (name)) == NULL && (symbolP = md_undefined_symbol (name)) == NULL) { + symbolP = symbol_find_or_make (name); #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. */ + 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; + fragS *dummy_frag = (fragS *) xcalloc (1, sizeof (fragS)); dummy_frag->line = listing_tail; - symbolP = symbol_new (name, undefined_section, 0, dummy_frag); dummy_frag->fr_symbol = symbolP; + symbol_set_frag (symbolP, dummy_frag); } - 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); -#endif /* OBJ_COFF */ +#endif + } + + if (S_IS_DEFINED (symbolP) || symbol_equated_p (symbolP)) + { + /* Permit register names to be redefined. */ + if ((mode != 0 || !S_IS_VOLATILE (symbolP)) + && S_GET_SEGMENT (symbolP) != reg_section) + { + as_bad (_("symbol `%s' is already defined"), name); + symbolP = symbol_clone (symbolP, 0); + } + /* If the symbol is volatile, copy the symbol and replace the + original with the copy, so that previous uses of the symbol will + retain the value of the symbol at the point of use. */ + else if (S_IS_VOLATILE (symbolP)) + symbolP = symbol_clone (symbolP, 1); } - symbol_table_insert (symbolP); + if (mode == 0) + S_SET_VOLATILE (symbolP); + else if (mode < 0) + S_SET_FORWARD_REF (symbolP); + + pseudo_set (symbolP); +} + +/* Handle the .equ, .equiv, .eqv, and .set directives. If EQUIV is 1, + then this is .equiv, and it is an error if the symbol is already + defined. If EQUIV is -1, the symbol additionally is a forward + reference. */ +void +s_set (int equiv) +{ + char *name; + char delim; + char *end_name; + + /* Especial apologies for the random logic: + this just grew, and could be parsed much more simply! + Dean in haste. */ + name = input_line_pointer; + delim = get_symbol_end (); + end_name = input_line_pointer; *end_name = delim; - if (equiv - && S_IS_DEFINED (symbolP) - && S_GET_SEGMENT (symbolP) != reg_section) - as_bad (_("symbol `%s' is already defined"), S_GET_NAME (symbolP)); + if (name == end_name) + { + as_bad (_("expected symbol name")); + ignore_rest_of_line (); + return; + } + + SKIP_WHITESPACE (); + + if (*input_line_pointer != ',') + { + *end_name = 0; + as_bad (_("expected comma after \"%s\""), name); + *end_name = delim; + ignore_rest_of_line (); + return; + } + + input_line_pointer++; + *end_name = 0; + + assign_symbol (name, equiv); + *end_name = delim; - pseudo_set (symbolP); demand_empty_rest_of_line (); } void -s_space (mult) - int mult; +s_space (int mult) { expressionS exp; expressionS val; char *p = 0; char *stop = NULL; - char stopc; + char stopc = 0; int bytes; #ifdef md_flush_pending_output @@ -2945,6 +3147,7 @@ s_space (mult) || val.X_add_number > 0xff || (mult != 0 && mult != 1 && val.X_add_number != 0)) { + resolve_expression (&exp); if (exp.X_op != O_constant) as_bad (_("unsupported variable size or fill value")); else @@ -2960,6 +3163,9 @@ s_space (mult) } else { + if (now_seg == absolute_section || mri_common_symbol != NULL) + resolve_expression (&exp); + if (exp.X_op == O_constant) { long repeat; @@ -2970,7 +3176,9 @@ s_space (mult) bytes = repeat; if (repeat <= 0) { - 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; } @@ -3038,14 +3246,13 @@ s_space (mult) friends. */ void -s_float_space (float_type) - int float_type; +s_float_space (int float_type) { offsetT count; int flen; char temp[MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT]; char *stop = NULL; - char stopc; + char stopc = 0; if (flag_mri) stop = mri_comment_field (&stopc); @@ -3091,7 +3298,7 @@ s_float_space (float_type) err = md_atof (float_type, temp, &flen); know (flen <= MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT); - know (flen > 0); + know (err != NULL || flen > 0); if (err) { as_bad (_("bad floating literal: %s"), err); @@ -3119,15 +3326,20 @@ s_float_space (float_type) /* Handle the .struct pseudo-op, as found in MIPS assemblers. */ void -s_struct (ignore) - int ignore ATTRIBUTE_UNUSED; +s_struct (int ignore ATTRIBUTE_UNUSED) { char *stop = NULL; - char stopc; + char stopc = 0; if (flag_mri) stop = mri_comment_field (&stopc); abs_section_offset = get_absolute_expression (); +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + /* The ELF backend needs to know that we are changing sections, so + that .previous works correctly. */ + if (IS_ELF) + obj_elf_section_change_hook (); +#endif subseg_set (absolute_section, 0); demand_empty_rest_of_line (); if (flag_mri) @@ -3135,57 +3347,179 @@ s_struct (ignore) } void -s_text (ignore) - int ignore ATTRIBUTE_UNUSED; +s_text (int ignore ATTRIBUTE_UNUSED) { register int temp; temp = get_absolute_expression (); subseg_set (text_section, (subsegT) temp); demand_empty_rest_of_line (); -#ifdef OBJ_VMS - const_flag &= ~IN_DEFAULT_SECTION; -#endif +#ifdef OBJ_VMS + const_flag &= ~IN_DEFAULT_SECTION; +#endif +} + +/* .weakref x, y sets x as an alias to y that, as long as y is not + referenced directly, will cause y to become a weak symbol. */ +void +s_weakref (int ignore ATTRIBUTE_UNUSED) +{ + char *name; + char delim; + char *end_name; + symbolS *symbolP; + symbolS *symbolP2; + expressionS exp; + + name = input_line_pointer; + delim = get_symbol_end (); + end_name = input_line_pointer; + + if (name == end_name) + { + as_bad (_("expected symbol name")); + *end_name = delim; + ignore_rest_of_line (); + return; + } + + symbolP = symbol_find_or_make (name); + + if (S_IS_DEFINED (symbolP) || symbol_equated_p (symbolP)) + { + if (!S_IS_VOLATILE (symbolP)) + { + as_bad (_("symbol `%s' is already defined"), name); + *end_name = delim; + ignore_rest_of_line (); + return; + } + symbolP = symbol_clone (symbolP, 1); + S_CLEAR_VOLATILE (symbolP); + } + + *end_name = delim; + + SKIP_WHITESPACE (); + + if (*input_line_pointer != ',') + { + *end_name = 0; + as_bad (_("expected comma after \"%s\""), name); + *end_name = delim; + ignore_rest_of_line (); + return; + } + + input_line_pointer++; + + SKIP_WHITESPACE (); + + name = input_line_pointer; + delim = get_symbol_end (); + end_name = input_line_pointer; + + if (name == end_name) + { + as_bad (_("expected symbol name")); + ignore_rest_of_line (); + return; + } + + if ((symbolP2 = symbol_find_noref (name, 1)) == NULL + && (symbolP2 = md_undefined_symbol (name)) == NULL) + { + symbolP2 = symbol_find_or_make (name); + S_SET_WEAKREFD (symbolP2); + } + else + { + symbolS *symp = symbolP2; + + while (S_IS_WEAKREFR (symp) && symp != symbolP) + { + expressionS *expP = symbol_get_value_expression (symp); + + assert (expP->X_op == O_symbol + && expP->X_add_number == 0); + symp = expP->X_add_symbol; + } + if (symp == symbolP) + { + char *loop; + + loop = concat (S_GET_NAME (symbolP), + " => ", S_GET_NAME (symbolP2), NULL); + + symp = symbolP2; + while (symp != symbolP) + { + char *old_loop = loop; + symp = symbol_get_value_expression (symp)->X_add_symbol; + loop = concat (loop, " => ", S_GET_NAME (symp), NULL); + free (old_loop); + } + + as_bad (_("%s: would close weakref loop: %s"), + S_GET_NAME (symbolP), loop); + + free (loop); + + *end_name = delim; + ignore_rest_of_line (); + return; + } + + /* Short-circuiting instead of just checking here might speed + things up a tiny little bit, but loop error messages would + miss intermediate links. */ + /* symbolP2 = symp; */ + } + + *end_name = delim; + + memset (&exp, 0, sizeof (exp)); + exp.X_op = O_symbol; + exp.X_add_symbol = symbolP2; + + S_SET_SEGMENT (symbolP, undefined_section); + symbol_set_value_expression (symbolP, &exp); + symbol_set_frag (symbolP, &zero_address_frag); + S_SET_WEAKREFR (symbolP); + + demand_empty_rest_of_line (); } + +/* Verify that we are at the end of a line. If not, issue an error and + skip to EOL. */ + void -demand_empty_rest_of_line () +demand_empty_rest_of_line (void) { SKIP_WHITESPACE (); if (is_end_of_line[(unsigned char) *input_line_pointer]) input_line_pointer++; else - ignore_rest_of_line (); - - /* Return having already swallowed end-of-line. */ -} - -void -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_warn (_("rest of line ignored; first ignored character is `%c'"), + as_bad (_("junk at end of line, first unrecognized character is `%c'"), *input_line_pointer); else - as_warn (_("rest of line ignored; first ignored character valued 0x%x"), + as_bad (_("junk at end of line, first unrecognized character valued 0x%x"), *input_line_pointer); - - while (input_line_pointer < buffer_limit - && !is_end_of_line[(unsigned char) *input_line_pointer]) - input_line_pointer++; + ignore_rest_of_line (); } - - input_line_pointer++; - + /* Return pointing just after end-of-line. */ know (is_end_of_line[(unsigned char) input_line_pointer[-1]]); } +/* Silently advance to the end of line. Use this after already having + issued an error about something bad. */ + void -discard_rest_of_line () +ignore_rest_of_line (void) { while (input_line_pointer < buffer_limit && !is_end_of_line[(unsigned char) *input_line_pointer]) @@ -3197,28 +3531,35 @@ discard_rest_of_line () know (is_end_of_line[(unsigned char) input_line_pointer[-1]]); } +/* Sets frag for given symbol to zero_address_frag, except when the + symbol frag is already set to a dummy listing frag. */ + +static void +set_zero_frag (symbolS *symbolP) +{ + if (symbol_get_frag (symbolP)->fr_type != rs_dummy) + symbol_set_frag (symbolP, &zero_address_frag); +} + /* In: Pointer to a symbol. - Input_line_pointer->expression. + Input_line_pointer->expression. Out: Input_line_pointer->just after any whitespace after expression. - Tried to set symbol to value of expression. - Will change symbols type, value, and frag; */ + Tried to set symbol to value of expression. + Will change symbols type, value, and frag; */ void -pseudo_set (symbolP) - symbolS *symbolP; +pseudo_set (symbolS *symbolP) { expressionS exp; -#if (defined (OBJ_AOUT) || defined (OBJ_BOUT)) && ! defined (BFD_ASSEMBLER) - int ext; -#endif /* OBJ_AOUT or OBJ_BOUT */ + segT seg; know (symbolP); /* NULL pointer is logic error. */ -#if (defined (OBJ_AOUT) || defined (OBJ_BOUT)) && ! defined (BFD_ASSEMBLER) - ext = S_IS_EXTERNAL (symbolP); -#endif /* OBJ_AOUT or OBJ_BOUT */ - (void) expression (&exp); + if (!S_IS_FORWARD_REF (symbolP)) + (void) expression (&exp); + else + (void) deferred_expression (&exp); if (exp.X_op == O_illegal) as_bad (_("illegal expression")); @@ -3232,6 +3573,7 @@ pseudo_set (symbolP) as_bad (_("floating point number invalid")); } else if (exp.X_op == O_subtract + && !S_IS_FORWARD_REF (symbolP) && SEG_NORMAL (S_GET_SEGMENT (exp.X_add_symbol)) && (symbol_get_frag (exp.X_add_symbol) == symbol_get_frag (exp.X_op_symbol))) @@ -3241,6 +3583,12 @@ pseudo_set (symbolP) - S_GET_VALUE (exp.X_op_symbol)); } + if (symbol_section_p (symbolP)) + { + as_bad ("attempt to set value of section symbol"); + return; + } + switch (exp.X_op) { case O_illegal: @@ -3250,56 +3598,58 @@ pseudo_set (symbolP) /* Fall through. */ case O_constant: S_SET_SEGMENT (symbolP, absolute_section); -#if (defined (OBJ_AOUT) || defined (OBJ_BOUT)) && ! defined (BFD_ASSEMBLER) - if (ext) - S_SET_EXTERNAL (symbolP); - else - S_CLEAR_EXTERNAL (symbolP); -#endif /* OBJ_AOUT or OBJ_BOUT */ S_SET_VALUE (symbolP, (valueT) exp.X_add_number); - if (exp.X_op != O_constant) - symbol_set_frag (symbolP, &zero_address_frag); + set_zero_frag (symbolP); break; case O_register: S_SET_SEGMENT (symbolP, reg_section); S_SET_VALUE (symbolP, (valueT) exp.X_add_number); - symbol_set_frag (symbolP, &zero_address_frag); + set_zero_frag (symbolP); + symbol_get_value_expression (symbolP)->X_op = O_register; break; case O_symbol: - if (S_GET_SEGMENT (exp.X_add_symbol) == undefined_section - || exp.X_add_number != 0) - symbol_set_value_expression (symbolP, &exp); - else if (symbol_section_p (symbolP)) - as_bad ("attempt to set value of section symbol"); - else + seg = S_GET_SEGMENT (exp.X_add_symbol); + /* For x=undef+const, create an expression symbol. + For x=x+const, just update x except when x is an undefined symbol + For x=defined+const, evaluate x. */ + if (symbolP == exp.X_add_symbol + && (seg != undefined_section + || !symbol_constant_p (symbolP))) + { + *symbol_X_add_number (symbolP) += exp.X_add_number; + break; + } + else if (!S_IS_FORWARD_REF (symbolP) && seg != undefined_section) { symbolS *s = exp.X_add_symbol; - S_SET_SEGMENT (symbolP, S_GET_SEGMENT (s)); -#if (defined (OBJ_AOUT) || defined (OBJ_BOUT)) && ! defined (BFD_ASSEMBLER) - if (ext) - S_SET_EXTERNAL (symbolP); - else - S_CLEAR_EXTERNAL (symbolP); -#endif /* OBJ_AOUT or OBJ_BOUT */ - S_SET_VALUE (symbolP, - exp.X_add_number + S_GET_VALUE (s)); + if (S_IS_COMMON (s)) + as_bad (_("`%s' can't be equated to common symbol '%s'"), + S_GET_NAME (symbolP), S_GET_NAME (s)); + + S_SET_SEGMENT (symbolP, seg); + S_SET_VALUE (symbolP, exp.X_add_number + S_GET_VALUE (s)); symbol_set_frag (symbolP, symbol_get_frag (s)); copy_symbol_attributes (symbolP, s); + break; } + S_SET_SEGMENT (symbolP, undefined_section); + symbol_set_value_expression (symbolP, &exp); + set_zero_frag (symbolP); break; default: - /* The value is some complex expression. - FIXME: Should we set the segment to anything? */ + /* The value is some complex expression. */ + S_SET_SEGMENT (symbolP, expr_section); symbol_set_value_expression (symbolP, &exp); + set_zero_frag (symbolP); break; } } -/* cons() +/* cons() CONStruct more frag of .bytes, or .words etc. Should need_pass_2 be 1 then emit no frag(s). @@ -3324,19 +3674,19 @@ pseudo_set (symbolP) #ifdef TC_M68K static void -parse_mri_cons PARAMS ((expressionS *exp, unsigned int nbytes)); +parse_mri_cons (expressionS *exp, unsigned int nbytes); #endif #ifndef TC_PARSE_CONS_EXPRESSION #ifdef BITFIELD_CONS_EXPRESSIONS #define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) parse_bitfield_cons (EXP, NBYTES) static void -parse_bitfield_cons PARAMS ((expressionS *exp, unsigned int nbytes)); +parse_bitfield_cons (expressionS *exp, unsigned int nbytes); #endif #ifdef REPEAT_CONS_EXPRESSIONS #define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) parse_repeat_cons (EXP, NBYTES) static void -parse_repeat_cons PARAMS ((expressionS *exp, unsigned int nbytes)); +parse_repeat_cons (expressionS *exp, unsigned int nbytes); #endif /* If we haven't gotten one yet, just call expression. */ @@ -3357,14 +3707,13 @@ do_parse_cons_expression (expressionS *exp, Clobbers input_line_pointer and checks end-of-line. */ static void -cons_worker (nbytes, rva) - register int nbytes; /* 1=.byte, 2=.word, 4=.long. */ - int rva; +cons_worker (register int nbytes, /* 1=.byte, 2=.word, 4=.long. */ + int rva) { int c; expressionS exp; char *stop = NULL; - char stopc; + char stopc = 0; #ifdef md_flush_pending_output md_flush_pending_output (); @@ -3381,6 +3730,11 @@ cons_worker (nbytes, rva) return; } +#ifdef TC_ADDRESS_BYTES + if (nbytes == 0) + nbytes = TC_ADDRESS_BYTES (); +#endif + #ifdef md_cons_align md_cons_align (nbytes); #endif @@ -3422,26 +3776,129 @@ cons_worker (nbytes, rva) } void -cons (size) - int size; +cons (int size) { cons_worker (size, 0); } void -s_rva (size) - int size; +s_rva (int size) { cons_worker (size, 1); } +/* .reloc offset, reloc_name, symbol+addend. */ + +void +s_reloc (int ignore ATTRIBUTE_UNUSED) +{ + char *stop = NULL; + char stopc = 0; + expressionS exp; + char *r_name; + int c; + struct reloc_list *reloc; + + reloc = xmalloc (sizeof (*reloc)); + + if (flag_mri) + stop = mri_comment_field (&stopc); + + expression (&exp); + switch (exp.X_op) + { + case O_illegal: + case O_absent: + case O_big: + case O_register: + as_bad (_("missing or bad offset expression")); + goto err_out; + case O_constant: + exp.X_add_symbol = section_symbol (now_seg); + exp.X_op = O_symbol; + /* Fall thru */ + case O_symbol: + if (exp.X_add_number == 0) + { + reloc->u.a.offset_sym = exp.X_add_symbol; + break; + } + /* Fall thru */ + default: + reloc->u.a.offset_sym = make_expr_symbol (&exp); + break; + } + + SKIP_WHITESPACE (); + if (*input_line_pointer != ',') + { + as_bad (_("missing reloc type")); + goto err_out; + } + + ++input_line_pointer; + SKIP_WHITESPACE (); + r_name = input_line_pointer; + c = get_symbol_end (); + reloc->u.a.howto = bfd_reloc_name_lookup (stdoutput, r_name); + *input_line_pointer = c; + if (reloc->u.a.howto == NULL) + { + as_bad (_("unrecognized reloc type")); + goto err_out; + } + + exp.X_op = O_absent; + SKIP_WHITESPACE (); + if (*input_line_pointer == ',') + { + ++input_line_pointer; + expression_and_evaluate (&exp); + } + switch (exp.X_op) + { + case O_illegal: + case O_big: + case O_register: + as_bad (_("bad reloc expression")); + err_out: + ignore_rest_of_line (); + free (reloc); + if (flag_mri) + mri_comment_end (stop, stopc); + return; + case O_absent: + reloc->u.a.sym = NULL; + reloc->u.a.addend = 0; + break; + case O_constant: + reloc->u.a.sym = NULL; + reloc->u.a.addend = exp.X_add_number; + break; + case O_symbol: + reloc->u.a.sym = exp.X_add_symbol; + reloc->u.a.addend = exp.X_add_number; + break; + default: + reloc->u.a.sym = make_expr_symbol (&exp); + reloc->u.a.addend = 0; + break; + } + + as_where (&reloc->file, &reloc->line); + reloc->next = reloc_list; + reloc_list = reloc; + + demand_empty_rest_of_line (); + if (flag_mri) + mri_comment_end (stop, stopc); +} + /* Put the contents of expression EXP into the object file using NBYTES bytes. If need_pass_2 is 1, this does nothing. */ void -emit_expr (exp, nbytes) - expressionS *exp; - unsigned int nbytes; +emit_expr (expressionS *exp, unsigned int nbytes) { operatorT op; register char *p; @@ -3611,22 +4068,9 @@ emit_expr (exp, nbytes) pass to md_number_to_chars, handle it as a bignum. */ if (op == O_constant && nbytes > sizeof (valueT)) { - valueT val; - int gencnt; - - if (!exp->X_unsigned && exp->X_add_number < 0) - extra_digit = (valueT) -1; - val = (valueT) exp->X_add_number; - gencnt = 0; - do - { - generic_bignum[gencnt] = val & LITTLENUM_MASK; - val >>= LITTLENUM_NUMBER_OF_BITS; - ++gencnt; - } - while (val != 0); - op = exp->X_op = O_big; - exp->X_add_number = gencnt; + extra_digit = exp->X_unsigned ? 0 : -1; + convert_to_bignum (exp); + op = O_big; } if (op == O_constant) @@ -3667,8 +4111,13 @@ emit_expr (exp, nbytes) && ((get & mask) != mask || (get & hibit) == 0)) { /* Leading bits contain both 0s & 1s. */ +#if defined (BFD64) && BFD_HOST_64BIT_LONG_LONG + as_warn (_("value 0x%llx truncated to 0x%llx"), + (unsigned long long) get, (unsigned long long) use); +#else as_warn (_("value 0x%lx truncated to 0x%lx"), (unsigned long) get, (unsigned long) use); +#endif } /* Put bytes in right order. */ md_number_to_chars (p, use, (int) nbytes); @@ -3729,16 +4178,8 @@ emit_expr (exp, nbytes) { memset (p, 0, nbytes); - /* Now we need to generate a fixS to record the symbol value. - This is easy for BFD. For other targets it can be more - complex. For very complex cases (currently, the HPPA and - NS32K), you can define TC_CONS_FIX_NEW to do whatever you - want. For simpler cases, you can define TC_CONS_RELOC to be - the name of the reloc code that should be stored in the fixS. - If neither is defined, the code uses NO_RELOC if it is - defined, and otherwise uses 0. */ + /* Now we need to generate a fixS to record the symbol value. */ -#ifdef BFD_ASSEMBLER #ifdef TC_CONS_FIX_NEW TC_CONS_FIX_NEW (frag_now, p - frag_now->fr_literal, nbytes, exp); #else @@ -3768,24 +4209,6 @@ emit_expr (exp, nbytes) 0, r); } #endif -#else -#ifdef TC_CONS_FIX_NEW - TC_CONS_FIX_NEW (frag_now, p - frag_now->fr_literal, nbytes, exp); -#else - /* Figure out which reloc number to use. Use TC_CONS_RELOC if - it is defined, otherwise use NO_RELOC if it is defined, - otherwise use 0. */ -#ifndef TC_CONS_RELOC -#ifdef NO_RELOC -#define TC_CONS_RELOC NO_RELOC -#else -#define TC_CONS_RELOC 0 -#endif -#endif - fix_new_exp (frag_now, p - frag_now->fr_literal, (int) nbytes, exp, 0, - TC_CONS_RELOC); -#endif /* TC_CONS_FIX_NEW */ -#endif /* BFD_ASSEMBLER */ } } @@ -3797,7 +4220,7 @@ emit_expr (exp, nbytes) them in words, longs, etc. and we'll pack them in target byte order for you. - The rules are: pack least significat bit first, if a field doesn't + The rules are: pack least significant bit first, if a field doesn't entirely fit, put it in the next unit. Overflowing the bitfield is explicitly *not* even a warning. The bitwidth should be considered a "mask". @@ -4031,9 +4454,7 @@ parse_repeat_cons (exp, nbytes) point number. */ static int -hex_float (float_type, bytes) - int float_type; - char *bytes; +hex_float (int float_type, char *bytes) { int length; int i; @@ -4117,7 +4538,7 @@ hex_float (float_type, bytes) return length; } -/* float_cons() +/* float_cons() CONStruct some more frag chars of .floats .ffloats etc. Makes 0 or more new frags. @@ -4128,16 +4549,15 @@ hex_float (float_type, bytes) by 0d 0f 0g or 0h. After observing the STRANGE way my BSD AS does its reading, I decided to be incompatible. This always tries to give you rounded bits to the precision of the pseudo-op. Former AS did premature - truncatation, restored noisy bits instead of trailing 0s AND gave you + truncation, restored noisy bits instead of trailing 0s AND gave you a choice of 2 flavours of noise according to which of 2 floating-point scanners you directed AS to use. In: input_line_pointer->whitespace before, or '0' of flonum. */ void -float_cons (float_type) - /* Clobbers input_line-pointer, checks end-of-line. */ - register int float_type; /* 'f':.ffloat ... 'F':.float ... */ +float_cons (/* Clobbers input_line-pointer, checks end-of-line. */ + register int float_type /* 'f':.ffloat ... 'F':.float ... */) { register char *p; int length; /* Number of chars in an object. */ @@ -4160,15 +4580,15 @@ float_cons (float_type) SKIP_WHITESPACE (); /* Skip any 0{letter} that may be present. Don't even check if the - letter is legal. Someone may invent a "z" format and this routine - has no use for such information. Lusers beware: you get - diagnostics if your input is ill-conditioned. */ + letter is legal. Someone may invent a "z" format and this routine + has no use for such information. Lusers beware: you get + diagnostics if your input is ill-conditioned. */ if (input_line_pointer[0] == '0' && ISALPHA (input_line_pointer[1])) input_line_pointer += 2; /* Accept :xxxx, where the x's are hex digits, for a floating - point with the exact digits specified. */ + point with the exact digits specified. */ if (input_line_pointer[0] == ':') { ++input_line_pointer; @@ -4183,7 +4603,7 @@ float_cons (float_type) { err = md_atof (float_type, temp, &length); know (length <= MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT); - know (length > 0); + know (err != NULL || length > 0); if (err) { as_bad (_("bad floating literal: %s"), err); @@ -4232,8 +4652,7 @@ float_cons (float_type) /* Return the size of a LEB128 value. */ static inline int -sizeof_sleb128 (value) - offsetT value; +sizeof_sleb128 (offsetT value) { register int size = 0; register unsigned byte; @@ -4254,8 +4673,7 @@ sizeof_sleb128 (value) } static inline int -sizeof_uleb128 (value) - valueT value; +sizeof_uleb128 (valueT value) { register int size = 0; register unsigned byte; @@ -4272,9 +4690,7 @@ sizeof_uleb128 (value) } int -sizeof_leb128 (value, sign) - valueT value; - int sign; +sizeof_leb128 (valueT value, int sign) { if (sign) return sizeof_sleb128 ((offsetT) value); @@ -4285,9 +4701,7 @@ sizeof_leb128 (value, sign) /* Output a LEB128 value. */ static inline int -output_sleb128 (p, value) - char *p; - offsetT value; +output_sleb128 (char *p, offsetT value) { register char *orig = p; register int more; @@ -4314,9 +4728,7 @@ output_sleb128 (p, value) } static inline int -output_uleb128 (p, value) - char *p; - valueT value; +output_uleb128 (char *p, valueT value) { char *orig = p; @@ -4336,10 +4748,7 @@ output_uleb128 (p, value) } int -output_leb128 (p, value, sign) - char *p; - valueT value; - int sign; +output_leb128 (char *p, valueT value, int sign) { if (sign) return output_sleb128 (p, (offsetT) value); @@ -4352,10 +4761,7 @@ output_leb128 (p, value, sign) for "normal" values that this be streamlined. */ static inline int -output_big_sleb128 (p, bignum, size) - char *p; - LITTLENUM_TYPE *bignum; - int size; +output_big_sleb128 (char *p, LITTLENUM_TYPE *bignum, int size) { char *orig = p; valueT val = 0; @@ -4363,45 +4769,54 @@ output_big_sleb128 (p, bignum, size) unsigned byte; /* Strip leading sign extensions off the bignum. */ - while (size > 0 && bignum[size - 1] == (LITTLENUM_TYPE) -1) + while (size > 1 + && bignum[size - 1] == LITTLENUM_MASK + && bignum[size - 2] > LITTLENUM_MASK / 2) size--; do { - if (loaded < 7 && size > 0) - { - val |= (*bignum << loaded); - loaded += 8 * CHARS_PER_LITTLENUM; - size--; - bignum++; - } - - byte = val & 0x7f; - loaded -= 7; - val >>= 7; + /* OR in the next part of the littlenum. */ + val |= (*bignum << loaded); + loaded += LITTLENUM_NUMBER_OF_BITS; + size--; + bignum++; - if (size == 0) + /* Add bytes until there are less than 7 bits left in VAL + or until every non-sign bit has been written. */ + do { - if ((val == 0 && (byte & 0x40) == 0) - || (~(val | ~(((valueT) 1 << loaded) - 1)) == 0 - && (byte & 0x40) != 0)) + byte = val & 0x7f; + loaded -= 7; + val >>= 7; + if (size > 0 + || val != ((byte & 0x40) == 0 ? 0 : ((valueT) 1 << loaded) - 1)) byte |= 0x80; + + if (orig) + *p = byte; + p++; } + while ((byte & 0x80) != 0 && loaded >= 7); + } + while (size > 0); + /* Mop up any left-over bits (of which there will be less than 7). */ + if ((byte & 0x80) != 0) + { + /* Sign-extend VAL. */ + if (val & (1 << (loaded - 1))) + val |= ~0 << loaded; if (orig) - *p = byte; + *p = val & 0x7f; p++; } - while (byte & 0x80); return p - orig; } static inline int -output_big_uleb128 (p, bignum, size) - char *p; - LITTLENUM_TYPE *bignum; - int size; +output_big_uleb128 (char *p, LITTLENUM_TYPE *bignum, int size) { char *orig = p; valueT val = 0; @@ -4440,10 +4855,7 @@ output_big_uleb128 (p, bignum, size) } static int -output_big_leb128 (p, bignum, size, sign) - char *p; - LITTLENUM_TYPE *bignum; - int size, sign; +output_big_leb128 (char *p, LITTLENUM_TYPE *bignum, int size, int sign) { if (sign) return output_big_sleb128 (p, bignum, size); @@ -4454,13 +4866,11 @@ output_big_leb128 (p, bignum, size, sign) /* Generate the appropriate fragments for a given expression to emit a leb128 value. */ -void -emit_leb128_expr (exp, sign) - expressionS *exp; - int sign; +static void +emit_leb128_expr (expressionS *exp, int sign) { operatorT op = exp->X_op; - int nbytes; + unsigned int nbytes; if (op == O_absent || op == O_illegal) { @@ -4479,10 +4889,20 @@ emit_leb128_expr (exp, sign) as_warn (_("register value used as expression")); op = O_constant; } + else if (op == O_constant + && sign + && (exp->X_add_number < 0) != !exp->X_unsigned) + { + /* We're outputting a signed leb128 and the sign of X_add_number + doesn't reflect the sign of the original value. Convert EXP + to a correctly-extended bignum instead. */ + convert_to_bignum (exp); + op = O_big; + } /* Let check_eh_frame know that data is being emitted. nbytes == -1 is a signal that this is leb128 data. It shouldn't optimize this away. */ - nbytes = -1; + nbytes = (unsigned int) -1; if (check_eh_frame (exp, &nbytes)) abort (); @@ -4527,11 +4947,14 @@ emit_leb128_expr (exp, sign) /* Parse the .sleb128 and .uleb128 pseudos. */ void -s_leb128 (sign) - int sign; +s_leb128 (int sign) { expressionS exp; +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + do { expression (&exp); @@ -4543,16 +4966,52 @@ s_leb128 (sign) demand_empty_rest_of_line (); } -/* We read 0 or more ',' separated, double-quoted strings. +static void +stringer_append_char (int c, int bitsize) +{ + if (!target_big_endian) + FRAG_APPEND_1_CHAR (c); + + switch (bitsize) + { + case 64: + FRAG_APPEND_1_CHAR (0); + FRAG_APPEND_1_CHAR (0); + FRAG_APPEND_1_CHAR (0); + FRAG_APPEND_1_CHAR (0); + /* Fall through. */ + case 32: + FRAG_APPEND_1_CHAR (0); + FRAG_APPEND_1_CHAR (0); + /* Fall through. */ + case 16: + FRAG_APPEND_1_CHAR (0); + /* Fall through. */ + case 8: + break; + default: + /* Called with invalid bitsize argument. */ + abort (); + break; + } + if (target_big_endian) + FRAG_APPEND_1_CHAR (c); +} + +/* Worker to do .ascii etc statements. + Reads 0 or more ',' separated, double-quoted strings. Caller should have checked need_pass_2 is FALSE because we don't - check it. */ + check it. + Checks for end-of-line. + BITS_APPENDZERO says how many bits are in a target char. + The bottom bit is set if a NUL char should be appended to the strings. */ void -stringer (append_zero) /* Worker to do .ascii etc statements. */ - /* Checks end-of-line. */ - register int append_zero; /* 0: don't append '\0', else 1. */ +stringer (int bits_appendzero) { - register unsigned int c; + const int bitsize = bits_appendzero & ~7; + const int append_zero = bits_appendzero & 1; + unsigned int c; char *start; #ifdef md_flush_pending_output @@ -4581,7 +5040,7 @@ stringer (append_zero) /* Worker to do .ascii etc statements. */ c = 0; ignore_rest_of_line (); } - + while (c == ',' || c == '<' || c == '"') { SKIP_WHITESPACE (); @@ -4590,24 +5049,23 @@ 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); - } + stringer_append_char (c, bitsize); + if (append_zero) - { - FRAG_APPEND_1_CHAR (0); - } + stringer_append_char (0, bitsize); + 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. */ + 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) @@ -4624,11 +5082,10 @@ stringer (append_zero) /* Worker to do .ascii etc statements. */ case '<': input_line_pointer++; c = get_single_number (); - FRAG_APPEND_1_CHAR (c); + stringer_append_char (c, bitsize); if (*input_line_pointer != '>') - { - as_bad (_("expected ")); - } + as_bad (_("expected ")); + input_line_pointer++; break; case ',': @@ -4640,7 +5097,7 @@ stringer (append_zero) /* Worker to do .ascii etc statements. */ } demand_empty_rest_of_line (); -} /* stringer() */ +} /* FIXME-SOMEDAY: I had trouble here on characters with the high bits set. We'll probably also have trouble with @@ -4648,7 +5105,7 @@ stringer (append_zero) /* Worker to do .ascii etc statements. */ returning values bigger than 1 byte. xoxorich. */ unsigned int -next_char_of_string () +next_char_of_string (void) { register unsigned int c; @@ -4770,8 +5227,7 @@ next_char_of_string () } static segT -get_segmented_expression (expP) - register expressionS *expP; +get_segmented_expression (register expressionS *expP) { register segT retval; @@ -4789,8 +5245,7 @@ get_segmented_expression (expP) } static segT -get_known_segmented_expression (expP) - register expressionS *expP; +get_known_segmented_expression (register expressionS *expP) { register segT retval; @@ -4812,31 +5267,8 @@ get_known_segmented_expression (expP) return (retval); } -offsetT -get_absolute_expr (exp) - expressionS *exp; -{ - expression (exp); - if (exp->X_op != O_constant) - { - if (exp->X_op != O_absent) - as_bad (_("bad or irreducible absolute expression")); - exp->X_add_number = 0; - } - return exp->X_add_number; -} - -offsetT -get_absolute_expression () -{ - expressionS exp; - - return get_absolute_expr (&exp); -} - char /* Return terminator. */ -get_absolute_expression_and_terminator (val_pointer) - long *val_pointer; /* Return value of expression. */ +get_absolute_expression_and_terminator (long *val_pointer /* Return value of expression. */) { /* FIXME: val_pointer should probably be offsetT *. */ *val_pointer = (long) get_absolute_expression (); @@ -4847,8 +5279,7 @@ get_absolute_expression_and_terminator (val_pointer) Give a warning if that happens. */ char * -demand_copy_C_string (len_pointer) - int *len_pointer; +demand_copy_C_string (int *len_pointer) { register char *s; @@ -4875,8 +5306,7 @@ demand_copy_C_string (len_pointer) Return NULL if we can't read a string here. */ char * -demand_copy_string (lenP) - int *lenP; +demand_copy_string (int *lenP) { register unsigned int c; register int len; @@ -4900,7 +5330,7 @@ demand_copy_string (lenP) } else { - as_warn (_("missing string")); + as_bad (_("missing string")); retval = NULL; ignore_rest_of_line (); } @@ -4915,24 +5345,23 @@ demand_copy_string (lenP) Out: 1 if input_line_pointer->end-of-line. */ int -is_it_end_of_statement () +is_it_end_of_statement (void) { SKIP_WHITESPACE (); return (is_end_of_line[(unsigned char) *input_line_pointer]); } void -equals (sym_name, reassign) - char *sym_name; - int reassign; +equals (char *sym_name, int reassign) { - register symbolS *symbolP; /* Symbol we are working with. */ char *stop = NULL; - char stopc; + char stopc = 0; input_line_pointer++; if (*input_line_pointer == '=') input_line_pointer++; + if (reassign < 0 && *input_line_pointer == '=') + input_line_pointer++; while (*input_line_pointer == ' ' || *input_line_pointer == '\t') input_line_pointer++; @@ -4940,45 +5369,11 @@ equals (sym_name, reassign) if (flag_mri) stop = mri_comment_field (&stopc); - if (sym_name[0] == '.' && sym_name[1] == '\0') - { - /* Turn '. = mumble' into a .org mumble. */ - register segT segment; - expressionS exp; - - segment = get_known_segmented_expression (&exp); - if (!need_pass_2) - do_org (segment, &exp, 0); - } - else - { -#ifdef OBJ_COFF - int local; - - symbolP = symbol_find (sym_name); - local = symbolP == NULL; - if (local) -#endif /* OBJ_COFF */ - 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' is already defined"), S_GET_NAME (symbolP)); - -#ifdef OBJ_COFF - /* "set" symbols are local unless otherwise specified. */ - if (local) - SF_SET_LOCAL (symbolP); -#endif /* OBJ_COFF */ - - pseudo_set (symbolP); - } + assign_symbol (sym_name, reassign >= 0 ? !reassign : reassign); if (flag_mri) { - /* Check garbage after the expression. */ - ignore_rest_of_line (); + demand_empty_rest_of_line (); mri_comment_end (stop, stopc); } } @@ -4986,8 +5381,7 @@ equals (sym_name, reassign) /* .incbin -- include a file verbatim at the current location. */ void -s_incbin (x) - int x ATTRIBUTE_UNUSED; +s_incbin (int x ATTRIBUTE_UNUSED) { FILE * binfile; char * path; @@ -5068,13 +5462,13 @@ s_incbin (x) } file_len = ftell (binfile); - /* If a count was not specified use the size of the file. */ + /* If a count was not specified use the remainder of the file. */ if (count == 0) - count = file_len; + count = file_len - skip; - if (skip + count > file_len) + if (skip < 0 || count < 0 || file_len < 0 || skip + count > file_len) { - as_bad (_("skip (%ld) + count (%ld) larger than file size (%ld)"), + as_bad (_("skip (%ld) or count (%ld) invalid for file size (%ld)"), skip, count, file_len); goto done; } @@ -5103,8 +5497,7 @@ done: /* .include -- include a file at this point. */ void -s_include (arg) - int arg ATTRIBUTE_UNUSED; +s_include (int arg ATTRIBUTE_UNUSED) { char *filename; int i; @@ -5117,7 +5510,7 @@ s_include (arg) if (filename == NULL) { /* demand_copy_string has already printed an error and - called ignore_rest_of_line. */ + called ignore_rest_of_line. */ return; } } @@ -5164,8 +5557,7 @@ gotit: } void -add_include_dir (path) - char *path; +add_include_dir (char *path) { int i; @@ -5193,7 +5585,7 @@ add_include_dir (path) /* Output debugging information to denote the source file. */ static void -generate_file_debug () +generate_file_debug (void) { if (debug_type == DEBUG_STABS) stabs_generate_asm_file (); @@ -5202,7 +5594,7 @@ generate_file_debug () /* Output line number debugging information for the current source line. */ void -generate_lineno_debug () +generate_lineno_debug (void) { switch (debug_type) { @@ -5229,8 +5621,7 @@ generate_lineno_debug () END_P is zero for .func, and non-zero for .endfunc. */ void -s_func (end_p) - int end_p; +s_func (int end_p) { do_s_func (end_p, NULL); } @@ -5238,10 +5629,8 @@ s_func (end_p) /* 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; +static void +do_s_func (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 @@ -5283,17 +5672,20 @@ do_s_func (end_p, default_prefix) if (*input_line_pointer != ',') { if (default_prefix) - asprintf (&label, "%s%s", default_prefix, name); + { + if (asprintf (&label, "%s%s", default_prefix, name) == -1) + as_fatal ("%s", xstrerror (errno)); + } else { - char leading_char = 0; -#ifdef BFD_ASSEMBLER - leading_char = bfd_get_symbol_leading_char (stdoutput); -#endif + char leading_char = bfd_get_symbol_leading_char (stdoutput); /* Missing entry point, use function's name with the leading char prepended. */ if (leading_char) - asprintf (&label, "%c%s", leading_char, name); + { + if (asprintf (&label, "%c%s", leading_char, name) == -1) + as_fatal ("%s", xstrerror (errno)); + } else label = name; } @@ -5319,19 +5711,13 @@ do_s_func (end_p, default_prefix) } void -s_ignore (arg) - int arg ATTRIBUTE_UNUSED; +s_ignore (int arg ATTRIBUTE_UNUSED) { - while (!is_end_of_line[(unsigned char) *input_line_pointer]) - { - ++input_line_pointer; - } - ++input_line_pointer; + ignore_rest_of_line (); } void -read_print_statistics (file) - FILE *file; +read_print_statistics (FILE *file) { hash_print_statistics (file, "pseudo-op table", po_hash); } @@ -5341,13 +5727,12 @@ read_print_statistics (file) This call avoids macro/conditionals nesting checking, since the contents of the line are assumed to replace the contents of a line already scanned. - An appropriate use of this function would be substition of input lines when + An appropriate use of this function would be substitution of input lines when called by md_start_line_hook(). The given line is assumed to already be properly scrubbed. */ void -input_scrub_insert_line (line) - const char *line; +input_scrub_insert_line (const char *line) { sb newline; sb_new (&newline); @@ -5361,9 +5746,56 @@ input_scrub_insert_line (line) file; no include path searching or dependency registering is performed. */ void -input_scrub_insert_file (path) - char *path; +input_scrub_insert_file (char *path) { input_scrub_include_file (path, input_line_pointer); buffer_limit = input_scrub_next_buffer (&input_line_pointer); } + +/* Find the end of a line, considering quotation and escaping of quotes. */ + +#if !defined(TC_SINGLE_QUOTE_STRINGS) && defined(SINGLE_QUOTE_STRINGS) +# define TC_SINGLE_QUOTE_STRINGS 1 +#endif + +static char * +_find_end_of_line (char *s, int mri_string, int insn ATTRIBUTE_UNUSED) +{ + char inquote = '\0'; + int inescape = 0; + + while (!is_end_of_line[(unsigned char) *s] + || (inquote && !ISCNTRL (*s)) + || (inquote == '\'' && flag_mri) +#ifdef TC_EOL_IN_INSN + || (insn && TC_EOL_IN_INSN (s)) +#endif + ) + { + if (mri_string && *s == '\'') + inquote ^= *s; + else if (inescape) + inescape = 0; + else if (*s == '\\') + inescape = 1; + else if (!inquote + ? *s == '"' +#ifdef TC_SINGLE_QUOTE_STRINGS + || (TC_SINGLE_QUOTE_STRINGS && *s == '\'') +#endif + : *s == inquote) + inquote ^= *s; + ++s; + } + if (inquote) + as_warn (_("missing closing `%c'"), inquote); + if (inescape) + as_warn (_("stray `\\'")); + return s; +} + +char * +find_end_of_line (char *s, int mri_string) +{ + return _find_end_of_line (s, mri_string, 0); +}