X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fread.c;h=ad9363a60449f2f09756fefba889344df8b65a2a;hb=017257f8db5c860dd46d7ba45fa867a3a6a7c49e;hp=7b667077aa7ea9f1e799a8bc229ae2c1fa417de5;hpb=40a4d956e2fd1156b385db42f51ebec066e4f537;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/read.c b/gas/read.c index 7b667077aa..ad9363a604 100644 --- a/gas/read.c +++ b/gas/read.c @@ -1,24 +1,24 @@ /* read.c - read a source file - Copyright 1986, 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, - 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 - Free Software Foundation, Inc. + 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, + 2010 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, 51 Franklin Street - Fifth Floor, Boston, MA -02110-1301, 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 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. @@ -38,12 +38,11 @@ Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA #include "sb.h" #include "macro.h" #include "obstack.h" -#include "listing.h" #include "ecoff.h" #include "dw2gencfi.h" #ifndef TC_START_LABEL -#define TC_START_LABEL(x,y) (x == ':') +#define TC_START_LABEL(x,y,z) (x == ':') #endif /* Set by the object-format or the target. */ @@ -72,7 +71,6 @@ die horribly; #endif #ifndef LEX_AT -/* The m88k unfortunately uses @ as a label beginner. */ #define LEX_AT 0 #endif @@ -98,7 +96,6 @@ die horribly; #endif #ifndef LEX_DOLLAR -/* The a29k assembler does not permits labels to start with $. */ #define LEX_DOLLAR 3 #endif @@ -128,7 +125,8 @@ char lex_type[256] = { }; /* In: a character. - Out: 1 if this character ends a line. */ + Out: 1 if this character ends a line. + 2 if this character is a line separator. */ char is_end_of_line[256] = { #ifdef CR_EOL 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, /* @abcdefghijklmno */ @@ -216,12 +214,16 @@ 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 int get_non_macro_line_sb (sb *); static void generate_file_debug (void); -static char *_find_end_of_line (char *, int, int); +static char *_find_end_of_line (char *, int, int, int); void read_begin (void) @@ -238,7 +240,7 @@ read_begin (void) /* Use machine dependent syntax. */ for (p = line_separator_chars; *p; p++) - is_end_of_line[(unsigned char) *p] = 1; + is_end_of_line[(unsigned char) *p] = 2; /* Use more. FIXME-SOMEDAY. */ if (flag_mri) @@ -246,7 +248,6 @@ read_begin (void) } #ifndef TC_ADDRESS_BYTES -#ifdef BFD_ASSEMBLER #define TC_ADDRESS_BYTES address_bytes static inline int @@ -261,7 +262,6 @@ address_bytes (void) return n; } #endif -#endif /* Set up pseudo-op tables. */ @@ -271,8 +271,8 @@ static const pseudo_typeS potable[] = { {"abort", s_abort, 0}, {"align", s_align_ptwo, 0}, {"altmacro", s_altmacro, 1}, - {"ascii", stringer, 0}, - {"asciz", stringer, 1}, + {"ascii", stringer, 8+0}, + {"asciz", stringer, 8+1}, {"balign", s_align_bytes, 0}, {"balignw", s_align_bytes, -2}, {"balignl", s_align_bytes, -4}, @@ -327,13 +327,14 @@ static const pseudo_typeS potable[] = { /* 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}, @@ -342,6 +343,9 @@ 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}, @@ -367,7 +371,8 @@ static const pseudo_typeS potable[] = { {"irpc", s_irp, 1}, {"irepc", s_irp, 1}, {"lcomm", s_lcomm, 0}, - {"lflags", listing_flags, 0}, /* Listing flags. */ + {"lflags", s_ignore, 0}, /* Listing flags. */ + {"linefile", s_app_line, 0}, {"linkonce", s_linkonce, 0}, {"list", listing_list, 1}, /* Turn listing on. */ {"llen", listing_psize, 1}, @@ -394,6 +399,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}, @@ -411,7 +417,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}, @@ -437,6 +447,7 @@ static const pseudo_typeS potable[] = { {"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. */ @@ -445,7 +456,7 @@ static const pseudo_typeS potable[] = { static offsetT get_absolute_expr (expressionS *exp) { - expression (exp); + expression_and_evaluate (exp); if (exp->X_op != O_constant) { if (exp->X_op != O_absent) @@ -520,7 +531,7 @@ pobegin (void) #define HANDLE_CONDITIONAL_ASSEMBLY() \ if (ignore_input ()) \ { \ - char *eol = find_end_of_line (input_line_pointer, flag_m68k_mri); \ + 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 \ @@ -578,9 +589,9 @@ try_macro (char term, const char *line) void read_a_source_file (char *name) { - register char c; - register char *s; /* String of symbol, '\0' appended. */ - register int temp; + char c; + char *s; /* String of symbol, '\0' appended. */ + int temp; pseudo_typeS *pop; #ifdef WARN_COMMENTS @@ -607,23 +618,60 @@ read_a_source_file (char *name) last_eol = NULL; #endif - know (buffer_limit[-1] == '\n'); /* Must have a sentinel. */ - while (input_line_pointer < buffer_limit) { + bfd_boolean was_new_line; /* We have more of this buffer to parse. */ /* We now have input_line_pointer->1st char of next line. If input_line_pointer [-1] == '\n' then we just scanned another line: so bump line counters. */ - if (is_end_of_line[(unsigned char) input_line_pointer[-1]]) + was_new_line = is_end_of_line[(unsigned char) input_line_pointer[-1]]; + if (was_new_line) { + symbol_set_value_now (&dot_symbol); #ifdef md_start_line_hook md_start_line_hook (); #endif if (input_line_pointer[-1] == '\n') bump_line_counters (); + } + +#ifndef NO_LISTING + /* If listing is on, and we are expanding a macro, then give + the listing code the contents of the expanded line. */ + if (listing) + { + if ((listing & LISTING_MACEXP) && macro_nest > 0) + { + /* Find the end of the current expanded macro line. */ + s = find_end_of_line (input_line_pointer, flag_m68k_mri); + + if (s != last_eol) + { + char *copy; + int len; + + 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; + copy = (char *) xmalloc (len + macro_nest + 2); + memset (copy, '>', macro_nest); + copy[macro_nest] = ' '; + memcpy (copy + macro_nest + 1, input_line_pointer, len); + copy[macro_nest + 1 + len] = '\0'; + /* Install the line with the listing facility. */ + listing_newline (copy); + } + } + else + listing_newline (NULL); + } +#endif + if (was_new_line) + { line_label = NULL; if (LABELS_WITHOUT_COLONS || flag_m68k_mri) @@ -633,10 +681,8 @@ read_a_source_file (char *name) if (is_name_beginner (*input_line_pointer)) { char *line_start = input_line_pointer; - char c; int mri_line_macro; - LISTING_NEWLINE (); HANDLE_CONDITIONAL_ASSEMBLY (); c = get_symbol_end (); @@ -697,53 +743,12 @@ read_a_source_file (char *name) 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++; + while (c == '\t' || c == ' ' || c == '\f'); - know (c != ' '); /* No further leading whitespace. */ - -#ifndef NO_LISTING - /* If listing is on, and we are expanding a macro, then give - the listing code the contents of the expanded line. */ - if (listing) - { - if ((listing & LISTING_MACEXP) && macro_nest > 0) - { - char *copy; - int len; - - /* Find the end of the current expanded macro line. */ - s = find_end_of_line (input_line_pointer - 1, flag_m68k_mri); - - 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); - } -#endif /* C is the 1st significant character. Input_line_pointer points after that character. */ if (is_name_beginner (c)) @@ -759,7 +764,7 @@ read_a_source_file (char *name) 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 (TC_START_LABEL (c, s, input_line_pointer)) { if (flag_m68k_mri) { @@ -791,6 +796,14 @@ read_a_source_file (char *name) /* Input_line_pointer->after ':'. */ SKIP_WHITESPACE (); } + else if ((c == '=' && input_line_pointer[1] == '=') + || ((c == ' ' || c == '\t') + && input_line_pointer[1] == '=' + && input_line_pointer[2] == '=')) + { + equals (s, -1); + demand_empty_rest_of_line (); + } else if ((c == '=' || ((c == ' ' || c == '\t') && input_line_pointer[1] == '=')) @@ -823,8 +836,8 @@ read_a_source_file (char *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; @@ -915,7 +928,7 @@ read_a_source_file (char *name) /* WARNING: c has char, which may be end-of-line. */ /* Also: input_line_pointer->`\0` where c was. */ *input_line_pointer = c; - input_line_pointer = _find_end_of_line (input_line_pointer, flag_m68k_mri, 1); + input_line_pointer = _find_end_of_line (input_line_pointer, flag_m68k_mri, 1, 0); c = *input_line_pointer; *input_line_pointer = '\0'; @@ -1002,10 +1015,14 @@ read_a_source_file (char *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); @@ -1021,7 +1038,7 @@ read_a_source_file (char *name) that goes with this #APP There is one. The specs guarantee it... */ tmp_len = buffer_limit - s; - tmp_buf = xmalloc (tmp_len + 1); + tmp_buf = (char *) xmalloc (tmp_len + 1); memcpy (tmp_buf, s, tmp_len); do { @@ -1037,7 +1054,7 @@ read_a_source_file (char *name) else num = buffer_limit - buffer; - tmp_buf = xrealloc (tmp_buf, tmp_len + num); + tmp_buf = (char *) xrealloc (tmp_buf, tmp_len + num); memcpy (tmp_buf + tmp_len, buffer, num); tmp_len += num; } @@ -1074,7 +1091,7 @@ read_a_source_file (char *name) break; } - new_buf = xrealloc (new_buf, new_length + 100); + new_buf = (char *) xrealloc (new_buf, new_length + 100); new_tmp = new_buf + new_length; new_length += 100; } @@ -1104,7 +1121,7 @@ read_a_source_file (char *name) continue; #endif input_line_pointer--; - /* Report unknown char as ignored. */ + /* Report unknown char as error. */ demand_empty_rest_of_line (); } @@ -1112,6 +1129,7 @@ read_a_source_file (char *name) md_after_pass_hook (); #endif } + symbol_set_value_now (&dot_symbol); quit: @@ -1264,20 +1282,17 @@ do_align (int n, char *fill, int len, int 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. */ - -#ifdef BFD_ASSEMBLER -#define ALIGN_LIMIT (stdoutput->arch_info->bits_per_address - 1) -#else -#define ALIGN_LIMIT 15 +#ifndef TC_ALIGN_LIMIT +#define TC_ALIGN_LIMIT (stdoutput->arch_info->bits_per_address - 1) #endif static void s_align (int arg, int bytes_p) { - unsigned int align_limit = ALIGN_LIMIT; + 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; @@ -1421,7 +1436,7 @@ s_comm_internal (int param, offsetT temp, size; symbolS *symbolP = NULL; char *stop = NULL; - char stopc; + char stopc = 0; expressionS exp; if (flag_mri) @@ -1449,9 +1464,7 @@ s_comm_internal (int param, temp = get_absolute_expr (&exp); size = temp; -#ifdef BFD_ASSEMBLER size &= ((offsetT) 2 << (stdoutput->arch_info->bits_per_address - 1)) - 1; -#endif if (exp.X_op == O_absent) { as_bad (_("missing size expression")); @@ -1467,13 +1480,22 @@ s_comm_internal (int param, *p = 0; symbolP = symbol_find_or_make (name); - if (S_IS_DEFINED (symbolP) && !S_IS_COMMON (symbolP)) + if ((S_IS_DEFINED (symbolP) || symbol_equated_p (symbolP)) + && !S_IS_COMMON (symbolP)) { - symbolP = NULL; - as_bad (_("symbol `%s' is already defined"), name); - *p = c; - ignore_rest_of_line (); - goto out; + 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); } size = S_GET_VALUE (symbolP); @@ -1490,6 +1512,7 @@ s_comm_internal (int param, { 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; @@ -1525,7 +1548,7 @@ s_mri_common (int small ATTRIBUTE_UNUSED) symbolS *sym; offsetT align; char *stop = NULL; - char stopc; + char stopc = 0; if (!flag_mri) { @@ -1583,11 +1606,14 @@ s_mri_common (int small ATTRIBUTE_UNUSED) } S_SET_EXTERNAL (sym); + S_SET_SEGMENT (sym, bfd_com_section_ptr); mri_common_symbol = sym; #ifdef S_SET_ALIGN if (align != 0) S_SET_ALIGN (sym, align); +#else + (void) align; #endif if (line_label != NULL) @@ -1619,7 +1645,7 @@ void s_data (int ignore ATTRIBUTE_UNUSED) { segT section; - register int temp; + int temp; temp = get_absolute_expression (); if (flag_readonly_data_in_text) @@ -1661,17 +1687,14 @@ s_app_file_string (char *file, int appfile ATTRIBUTE_UNUSED) void s_app_file (int appfile) { - register char *s; + char *s; int length; /* 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. */ @@ -1686,32 +1709,123 @@ s_app_file (int 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 (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 @@ -1785,7 +1899,7 @@ s_fail (int ignore ATTRIBUTE_UNUSED) { offsetT temp; char *stop = NULL; - char stopc; + char stopc = 0; if (flag_mri) stop = mri_comment_field (&stopc); @@ -1807,13 +1921,17 @@ s_fill (int ignore ATTRIBUTE_UNUSED) { expressionS rep_exp; long size = 1; - register long fill = 0; + long fill = 0; char *p; #ifdef md_flush_pending_output md_flush_pending_output (); #endif +#ifdef md_cons_align + md_cons_align (1); +#endif + get_known_segmented_expression (&rep_exp); if (*input_line_pointer == ',') { @@ -1907,7 +2025,7 @@ s_globl (int ignore ATTRIBUTE_UNUSED) int c; symbolS *symbolP; char *stop = NULL; - char stopc; + char stopc = 0; if (flag_mri) stop = mri_comment_field (&stopc); @@ -1938,6 +2056,139 @@ s_globl (int ignore ATTRIBUTE_UNUSED) 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. + Returns the attribute number read, or zero on error. */ +int +s_vendor_attribute (int vendor) +{ + expressionS exp; + int type; + int tag; + unsigned int i = 0; + char *s = NULL; + + /* Read the first number or name. */ + skip_whitespace (input_line_pointer); + s = input_line_pointer; + if (ISDIGIT (*input_line_pointer)) + { + expression (& exp); + if (exp.X_op != O_constant) + goto bad; + tag = exp.X_add_number; + } + else + { + char *name; + + /* A name may contain '_', but no other punctuation. */ + for (; ISALNUM (*input_line_pointer) || *input_line_pointer == '_'; + ++input_line_pointer) + i++; + if (i == 0) + goto bad; + + name = (char *) alloca (i + 1); + memcpy (name, s, i); + name[i] = '\0'; + +#ifndef CONVERT_SYMBOLIC_ATTRIBUTE +#define CONVERT_SYMBOLIC_ATTRIBUTE(a) -1 +#endif + + tag = CONVERT_SYMBOLIC_ATTRIBUTE (name); + if (tag == -1) + { + as_bad (_("Attribute name not recognised: %s"), name); + ignore_rest_of_line (); + return 0; + } + } + + 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 0; + } + i = exp.X_add_number; + } + if ((type & 3) == 3 + && skip_past_comma (&input_line_pointer) == -1) + { + as_bad (_("expected comma")); + ignore_rest_of_line (); + return 0; + } + if (type & 2) + { + int len; + + skip_whitespace (input_line_pointer); + if (*input_line_pointer != '"') + goto bad_string; + s = demand_copy_C_string (&len); + } + + switch (type & 3) + { + case 3: + bfd_elf_add_obj_attr_int_string (stdoutput, vendor, tag, 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 (); + } + + demand_empty_rest_of_line (); + return tag; +bad_string: + as_bad (_("bad string constant")); + ignore_rest_of_line (); + return 0; +bad: + as_bad (_("expected , ")); + ignore_rest_of_line (); + return 0; +} + +/* 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 @@ -1958,7 +2209,7 @@ s_irp (int irpc) sb_new (&out); - err = expand_irp (irpc, 0, &s, &out, get_line_sb); + err = expand_irp (irpc, 0, &s, &out, get_non_macro_line_sb); if (err != NULL) as_bad_where (file, line, "%s", err); @@ -2007,7 +2258,6 @@ s_linkonce (int ignore ATTRIBUTE_UNUSED) #ifdef obj_handle_link_once obj_handle_link_once (type); #else /* ! defined (obj_handle_link_once) */ -#ifdef BFD_ASSEMBLER { flagword flags; @@ -2037,9 +2287,6 @@ s_linkonce (int ignore ATTRIBUTE_UNUSED) 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 (); @@ -2062,11 +2309,9 @@ bss_alloc (symbolS *symbolP, addressT size, int align) { bss_seg = subseg_new (".sbss", 1); seg_info (bss_seg)->bss = 1; -#ifdef BFD_ASSEMBLER if (!bfd_set_section_flags (stdoutput, bss_seg, SEC_ALLOC)) as_warn (_("error setting flags for \".sbss\": %s"), bfd_errmsg (bfd_get_error ())); -#endif } } #endif @@ -2187,11 +2432,11 @@ s_lcomm_bytes (int needs_align) void s_lsym (int ignore ATTRIBUTE_UNUSED) { - register char *name; - register char c; - register char *p; + char *name; + char c; + char *p; expressionS exp; - register symbolS *symbolP; + symbolS *symbolP; /* We permit ANY defined expression: BSD4.2 demands constants. */ name = input_line_pointer; @@ -2218,7 +2463,7 @@ s_lsym (int ignore ATTRIBUTE_UNUSED) } input_line_pointer++; - expression (&exp); + expression_and_evaluate (&exp); if (exp.X_op != O_constant && exp.X_op != O_register) @@ -2231,15 +2476,7 @@ s_lsym (int ignore ATTRIBUTE_UNUSED) *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. */ @@ -2262,7 +2499,7 @@ s_lsym (int ignore ATTRIBUTE_UNUSED) or zero if there are no more lines. */ static int -get_line_sb (sb *line) +get_line_sb (sb *line, int in_macro) { char *eol; @@ -2276,7 +2513,7 @@ get_line_sb (sb *line) return 0; } - eol = find_end_of_line (input_line_pointer, flag_m68k_mri); + eol = _find_end_of_line (input_line_pointer, flag_m68k_mri, 0, in_macro); sb_add_buffer (line, input_line_pointer, eol - input_line_pointer); input_line_pointer = eol; @@ -2288,6 +2525,18 @@ get_line_sb (sb *line) return *input_line_pointer++; } +static int +get_non_macro_line_sb (sb *line) +{ + return get_line_sb (line, 0); +} + +static int +get_macro_line_sb (sb *line) +{ + return get_line_sb (line, 1); +} + /* Define a macro. This is an interface to macro.c. */ void @@ -2312,11 +2561,11 @@ s_macro (int ignore ATTRIBUTE_UNUSED) sb_new (&label); sb_add_string (&label, S_GET_NAME (line_label)); - err = define_macro (0, &s, &label, get_line_sb, file, line, &name); + err = define_macro (0, &s, &label, get_macro_line_sb, file, line, &name); sb_kill (&label); } else - err = define_macro (0, &s, NULL, get_line_sb, file, line, &name); + err = define_macro (0, &s, NULL, get_macro_line_sb, file, line, &name); if (err != NULL) as_bad_where (file, line, err, name); else @@ -2348,8 +2597,13 @@ s_macro (int ignore ATTRIBUTE_UNUSED) void s_mexit (int ignore ATTRIBUTE_UNUSED) { - cond_exit_macro (macro_nest); - buffer_limit = input_scrub_next_buffer (&input_line_pointer); + if (macro_nest) + { + cond_exit_macro (macro_nest); + buffer_limit = input_scrub_next_buffer (&input_line_pointer); + } + else + as_warn (_("ignoring macro exit outside a macro definition.")); } /* Switch in and out of MRI mode. */ @@ -2357,10 +2611,15 @@ s_mexit (int ignore ATTRIBUTE_UNUSED) void s_mri (int ignore ATTRIBUTE_UNUSED) { - int on, old_flag; + int on; +#ifdef MRI_MODE_CHANGE + int old_flag; +#endif on = get_absolute_expression (); +#ifdef MRI_MODE_CHANGE old_flag = flag_mri; +#endif if (on != 0) { flag_mri = 1; @@ -2430,9 +2689,9 @@ do_org (segT segment, expressionS *exp, int fill) void s_org (int ignore ATTRIBUTE_UNUSED) { - register segT segment; + segT segment; expressionS exp; - register long temp_fill; + long temp_fill; #ifdef md_flush_pending_output md_flush_pending_output (); @@ -2479,8 +2738,7 @@ s_org (int ignore ATTRIBUTE_UNUSED) 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 (char *type ATTRIBUTE_UNUSED) @@ -2534,7 +2792,6 @@ s_mri_sect (char *type ATTRIBUTE_UNUSED) as_bad (_("unrecognized section type")); ++input_line_pointer; -#ifdef BFD_ASSEMBLER { flagword flags; @@ -2553,7 +2810,6 @@ s_mri_sect (char *type ATTRIBUTE_UNUSED) bfd_errmsg (bfd_get_error ())); } } -#endif } /* Ignore the HP type. */ @@ -2720,7 +2976,7 @@ do_repeat (int count, const char *start, const char *end) sb many; sb_new (&one); - if (!buffer_and_nest (start, end, &one, get_line_sb)) + if (!buffer_and_nest (start, end, &one, get_non_macro_line_sb)) { as_bad (_("%s without %s"), start, end); return; @@ -2737,6 +2993,57 @@ do_repeat (int count, const char *start, const char *end) buffer_limit = input_scrub_next_buffer (&input_line_pointer); } +/* Like do_repeat except that any text matching EXPANDER in the + block is replaced by the itteration count. */ + +void +do_repeat_with_expander (int count, + const char * start, + const char * end, + const char * expander) +{ + sb one; + sb many; + + sb_new (&one); + if (!buffer_and_nest (start, end, &one, get_non_macro_line_sb)) + { + as_bad (_("%s without %s"), start, end); + return; + } + + sb_new (&many); + + if (expander != NULL && strstr (one.ptr, expander) != NULL) + { + while (count -- > 0) + { + int len; + char * sub; + sb processed; + + sb_new (& processed); + sb_add_sb (& processed, & one); + sub = strstr (processed.ptr, expander); + len = sprintf (sub, "%d", count); + gas_assert (len < 8); + strcpy (sub + len, sub + 8); + processed.len -= (8 - len); + sb_add_sb (& many, & processed); + sb_kill (& processed); + } + } + else + while (count-- > 0) + sb_add_sb (&many, &one); + + sb_kill (&one); + + input_scrub_include_sb (&many, input_line_pointer, 1); + sb_kill (&many); + buffer_limit = input_scrub_next_buffer (&input_line_pointer); +} + /* Skip to end of current repeat loop; EXTRA indicates how many additional input buffers to skip. Assumes that conditionals preceding the loop end are properly nested. @@ -2754,7 +3061,7 @@ end_repeat (int extra) } static void -assign_symbol (char *name, int no_reassign) +assign_symbol (char *name, int mode) { symbolS *symbolP; @@ -2795,18 +3102,34 @@ assign_symbol (char *name, int no_reassign) #endif } - /* Permit register names to be redefined. */ - if (no_reassign - && S_IS_DEFINED (symbolP) - && S_GET_SEGMENT (symbolP) != reg_section) - as_bad (_("symbol `%s' is already defined"), name); + 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); + } + + if (mode == 0) + S_SET_VOLATILE (symbolP); + else if (mode < 0) + S_SET_FORWARD_REF (symbolP); pseudo_set (symbolP); } -/* 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. */ +/* 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) @@ -2857,13 +3180,17 @@ s_space (int mult) expressionS val; char *p = 0; char *stop = NULL; - char stopc; + char stopc = 0; int bytes; #ifdef md_flush_pending_output md_flush_pending_output (); #endif +#ifdef md_cons_align + md_cons_align (1); +#endif + if (flag_mri) stop = mri_comment_field (&stopc); @@ -2879,12 +3206,12 @@ s_space (int mult) } else if (mri_common_symbol != NULL) { - valueT val; + valueT mri_val; - val = S_GET_VALUE (mri_common_symbol); - if ((val & 1) != 0) + mri_val = S_GET_VALUE (mri_common_symbol); + if ((mri_val & 1) != 0) { - S_SET_VALUE (mri_common_symbol, val + 1); + S_SET_VALUE (mri_common_symbol, mri_val + 1); if (line_label != NULL) { expressionS *symexp; @@ -2928,6 +3255,7 @@ s_space (int 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 @@ -2943,9 +3271,12 @@ s_space (int mult) } else { + if (now_seg == absolute_section || mri_common_symbol != NULL) + resolve_expression (&exp); + if (exp.X_op == O_constant) { - long repeat; + offsetT repeat; repeat = exp.X_add_number; if (mult) @@ -3029,7 +3360,11 @@ s_float_space (int float_type) int flen; char temp[MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT]; char *stop = NULL; - char stopc; + char stopc = 0; + +#ifdef md_cons_align + md_cons_align (1); +#endif if (flag_mri) stop = mri_comment_field (&stopc); @@ -3075,7 +3410,7 @@ s_float_space (int 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); @@ -3106,11 +3441,17 @@ void 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) @@ -3120,7 +3461,7 @@ s_struct (int ignore ATTRIBUTE_UNUSED) void s_text (int ignore ATTRIBUTE_UNUSED) { - register int temp; + int temp; temp = get_absolute_expression (); subseg_set (text_section, (subsegT) temp); @@ -3129,6 +3470,138 @@ s_text (int ignore ATTRIBUTE_UNUSED) 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); + + gas_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), (const char *) 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), + (const char *) 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 @@ -3193,13 +3666,13 @@ pseudo_set (symbolS *symbolP) { expressionS exp; segT seg; -#if (defined (OBJ_AOUT) || defined (OBJ_BOUT)) && ! defined (BFD_ASSEMBLER) - int ext; -#endif /* OBJ_AOUT or OBJ_BOUT */ know (symbolP); /* NULL pointer is logic error. */ - (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")); @@ -3213,6 +3686,7 @@ pseudo_set (symbolS *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))) @@ -3227,9 +3701,6 @@ pseudo_set (symbolS *symbolP) as_bad ("attempt to set value of section symbol"); return; } -#if (defined (OBJ_AOUT) || defined (OBJ_BOUT)) && ! defined (BFD_ASSEMBLER) - ext = S_IS_EXTERNAL (symbolP); -#endif /* OBJ_AOUT or OBJ_BOUT */ switch (exp.X_op) { @@ -3245,9 +3716,18 @@ pseudo_set (symbolS *symbolP) break; case O_register: +#ifndef TC_GLOBAL_REGISTER_SYMBOL_OK + if (S_IS_EXTERNAL (symbolP)) + { + as_bad ("can't equate global symbol `%s' with register name", + S_GET_NAME (symbolP)); + return; + } +#endif S_SET_SEGMENT (symbolP, reg_section); S_SET_VALUE (symbolP, (valueT) exp.X_add_number); set_zero_frag (symbolP); + symbol_get_value_expression (symbolP)->X_op = O_register; break; case O_symbol: @@ -3262,7 +3742,7 @@ pseudo_set (symbolS *symbolP) *symbol_X_add_number (symbolP) += exp.X_add_number; break; } - else if (seg != undefined_section) + else if (!S_IS_FORWARD_REF (symbolP) && seg != undefined_section) { symbolS *s = exp.X_add_symbol; @@ -3276,23 +3756,19 @@ pseudo_set (symbolS *symbolP) copy_symbol_attributes (symbolP, s); break; } - /* Fall thru */ + S_SET_SEGMENT (symbolP, undefined_section); + symbol_set_value_expression (symbolP, &exp); + copy_symbol_attributes (symbolP, exp.X_add_symbol); + set_zero_frag (symbolP); + break; default: - /* The value is some complex expression. - Set segment and frag back to that of a newly created symbol. */ - S_SET_SEGMENT (symbolP, undefined_section); + /* The value is some complex expression. */ + S_SET_SEGMENT (symbolP, expr_section); symbol_set_value_expression (symbolP, &exp); set_zero_frag (symbolP); break; } - -#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 */ } /* cons() @@ -3353,13 +3829,13 @@ do_parse_cons_expression (expressionS *exp, Clobbers input_line_pointer and checks end-of-line. */ static void -cons_worker (register int nbytes, /* 1=.byte, 2=.word, 4=.long. */ +cons_worker (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 (); @@ -3393,7 +3869,15 @@ cons_worker (register int nbytes, /* 1=.byte, 2=.word, 4=.long. */ parse_mri_cons (&exp, (unsigned int) nbytes); else #endif - TC_PARSE_CONS_EXPRESSION (&exp, (unsigned int) nbytes); + { + if (*input_line_pointer == '"') + { + as_bad (_("unexpected `\"' in expression")); + ignore_rest_of_line (); + return; + } + TC_PARSE_CONS_EXPRESSION (&exp, (unsigned int) nbytes); + } if (rva) { @@ -3433,6 +3917,113 @@ 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 = (struct reloc_list *) 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 (&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. */ @@ -3440,13 +4031,16 @@ void emit_expr (expressionS *exp, unsigned int nbytes) { operatorT op; - register char *p; + char *p; valueT extra_digit = 0; /* Don't do anything if we are going to make another pass. */ if (need_pass_2) return; + /* Grow the current frag now so that dot_value does not get invalidated + if the frag were to fill up in the frag_more() call below. */ + frag_grow (nbytes); dot_value = frag_now_fix (); #ifndef NO_LISTING @@ -3614,11 +4208,11 @@ emit_expr (expressionS *exp, unsigned int nbytes) if (op == O_constant) { - register valueT get; - register valueT use; - register valueT mask; + valueT get; + valueT use; + valueT mask; valueT hibit; - register valueT unmask; + valueT unmask; /* JF << of >= number of bits in the object is undefined. In particular SPARC (Sun 4) has problems. */ @@ -3650,8 +4244,18 @@ emit_expr (expressionS *exp, unsigned int nbytes) && ((get & mask) != mask || (get & hibit) == 0)) { /* Leading bits contain both 0s & 1s. */ +#if defined (BFD64) && BFD_HOST_64BIT_LONG_LONG +#ifndef __MSVCRT__ + as_warn (_("value 0x%llx truncated to 0x%llx"), + (unsigned long long) get, (unsigned long long) use); +#else + as_warn (_("value 0x%I64x truncated to 0x%I64x"), + (unsigned long long) get, (unsigned long long) use); +#endif +#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); @@ -3661,15 +4265,32 @@ emit_expr (expressionS *exp, unsigned int nbytes) unsigned int size; LITTLENUM_TYPE *nums; - know (nbytes % CHARS_PER_LITTLENUM == 0); - size = exp->X_add_number * CHARS_PER_LITTLENUM; if (nbytes < size) { - as_warn (_("bignum truncated to %d bytes"), nbytes); + int i = nbytes / CHARS_PER_LITTLENUM; + if (i != 0) + { + LITTLENUM_TYPE sign = 0; + if ((generic_bignum[--i] + & (1 << (LITTLENUM_NUMBER_OF_BITS - 1))) != 0) + sign = ~(LITTLENUM_TYPE) 0; + while (++i < exp->X_add_number) + if (generic_bignum[i] != sign) + break; + } + if (i < exp->X_add_number) + as_warn (_("bignum truncated to %d bytes"), nbytes); size = nbytes; } + if (nbytes == 1) + { + md_number_to_chars (p, (valueT) generic_bignum[0], 1); + return; + } + know (nbytes % CHARS_PER_LITTLENUM == 0); + if (target_big_endian) { while (nbytes > size) @@ -3709,67 +4330,48 @@ emit_expr (expressionS *exp, unsigned int nbytes) } } else - { - memset (p, 0, nbytes); + emit_expr_fix (exp, nbytes, frag_now, p); +} - /* 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. */ +void +emit_expr_fix (expressionS *exp, unsigned int nbytes, fragS *frag, char *p) +{ + memset (p, 0, nbytes); + + /* 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); + TC_CONS_FIX_NEW (frag, p - frag->fr_literal, nbytes, exp); #else - { - bfd_reloc_code_real_type r; + { + bfd_reloc_code_real_type r; - switch (nbytes) - { - case 1: - r = BFD_RELOC_8; - break; - case 2: - r = BFD_RELOC_16; - break; - case 4: - r = BFD_RELOC_32; - break; - case 8: - r = BFD_RELOC_64; - break; - default: - as_bad (_("unsupported BFD relocation size %u"), nbytes); - r = BFD_RELOC_32; - break; - } - fix_new_exp (frag_now, p - frag_now->fr_literal, (int) nbytes, exp, - 0, r); + switch (nbytes) + { + case 1: + r = BFD_RELOC_8; + break; + case 2: + r = BFD_RELOC_16; + break; + case 3: + r = BFD_RELOC_24; + break; + case 4: + r = BFD_RELOC_32; + break; + case 8: + r = BFD_RELOC_64; + break; + default: + as_bad (_("unsupported BFD relocation size %u"), nbytes); + r = BFD_RELOC_32; + break; } + fix_new_exp (frag, p - frag->fr_literal, (int) nbytes, exp, + 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 */ - } } #ifdef BITFIELD_CONS_EXPRESSIONS @@ -3982,7 +4584,7 @@ parse_repeat_cons (exp, nbytes) unsigned int nbytes; { expressionS count; - register int i; + int i; expression (exp); @@ -4117,11 +4719,11 @@ hex_float (int float_type, char *bytes) void float_cons (/* Clobbers input_line-pointer, checks end-of-line. */ - register int float_type /* 'f':.ffloat ... 'F':.float ... */) + int float_type /* 'f':.ffloat ... 'F':.float ... */) { - register char *p; + char *p; int length; /* Number of chars in an object. */ - register char *err; /* Error from scanning floating literal. */ + char *err; /* Error from scanning floating literal. */ char temp[MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT]; if (is_it_end_of_statement ()) @@ -4134,6 +4736,10 @@ float_cons (/* Clobbers input_line-pointer, checks end-of-line. */ md_flush_pending_output (); #endif +#ifdef md_cons_align + md_cons_align (1); +#endif + do { /* input_line_pointer->1st char of a flonum (we hope!). */ @@ -4163,7 +4769,7 @@ float_cons (/* Clobbers input_line-pointer, checks end-of-line. */ { 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); @@ -4214,8 +4820,8 @@ float_cons (/* Clobbers input_line-pointer, checks end-of-line. */ static inline int sizeof_sleb128 (offsetT value) { - register int size = 0; - register unsigned byte; + int size = 0; + unsigned byte; do { @@ -4235,12 +4841,10 @@ sizeof_sleb128 (offsetT value) static inline int sizeof_uleb128 (valueT value) { - register int size = 0; - register unsigned byte; + int size = 0; do { - byte = (value & 0x7f); value >>= 7; size += 1; } @@ -4263,8 +4867,8 @@ sizeof_leb128 (valueT value, int sign) static inline int output_sleb128 (char *p, offsetT value) { - register char *orig = p; - register int more; + char *orig = p; + int more; do { @@ -4526,22 +5130,64 @@ s_leb128 (int 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 (/* 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; +#if !defined(NO_LISTING) && defined (OBJ_ELF) char *start; +#endif #ifdef md_flush_pending_output md_flush_pending_output (); #endif +#ifdef md_cons_align + md_cons_align (1); +#endif + /* The following awkward logic is to parse ZERO or more strings, comma separated. Recall a string expression includes spaces before the opening '\"' and spaces after the closing '\"'. @@ -4572,19 +5218,19 @@ stringer (/* Worker to do .ascii etc statements. */ { case '\"': ++input_line_pointer; /*->1st char of string. */ +#if !defined(NO_LISTING) && defined (OBJ_ELF) start = input_line_pointer; +#endif + 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 +#if !defined(NO_LISTING) && defined (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 @@ -4600,18 +5246,16 @@ stringer (/* Worker to do .ascii etc statements. */ listing_source_file (start); input_line_pointer[-1] = c; } -#endif #endif break; 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 ',': @@ -4623,7 +5267,7 @@ stringer (/* 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 @@ -4633,7 +5277,7 @@ stringer (/* Worker to do .ascii etc statements. */ unsigned int next_char_of_string (void) { - register unsigned int c; + unsigned int c; c = *input_line_pointer++ & CHAR_MASK; switch (c) @@ -4753,9 +5397,9 @@ next_char_of_string (void) } static segT -get_segmented_expression (register expressionS *expP) +get_segmented_expression (expressionS *expP) { - register segT retval; + segT retval; retval = expression (expP); if (expP->X_op == O_illegal @@ -4771,9 +5415,9 @@ get_segmented_expression (register expressionS *expP) } static segT -get_known_segmented_expression (register expressionS *expP) +get_known_segmented_expression (expressionS *expP) { - register segT retval; + segT retval; if ((retval = get_segmented_expression (expP)) == undefined_section) { @@ -4807,11 +5451,11 @@ get_absolute_expression_and_terminator (long *val_pointer /* Return value of exp char * demand_copy_C_string (int *len_pointer) { - register char *s; + char *s; if ((s = demand_copy_string (len_pointer)) != 0) { - register int len; + int len; for (len = *len_pointer; len > 0; len--) { @@ -4834,8 +5478,8 @@ demand_copy_C_string (int *len_pointer) char * demand_copy_string (int *lenP) { - register unsigned int c; - register int len; + unsigned int c; + int len; char *retval; len = 0; @@ -4852,7 +5496,7 @@ demand_copy_string (int *lenP) /* JF this next line is so demand_copy_C_string will return a null terminated string. */ obstack_1grow (¬es, '\0'); - retval = obstack_finish (¬es); + retval = (char *) obstack_finish (¬es); } else { @@ -4881,11 +5525,13 @@ void equals (char *sym_name, int reassign) { 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++; @@ -4893,7 +5539,7 @@ equals (char *sym_name, int reassign) if (flag_mri) stop = mri_comment_field (&stopc); - assign_symbol (sym_name, !reassign); + assign_symbol (sym_name, reassign >= 0 ? !reassign : reassign); if (flag_mri) { @@ -4920,6 +5566,10 @@ s_incbin (int x ATTRIBUTE_UNUSED) md_flush_pending_output (); #endif +#ifdef md_cons_align + md_cons_align (1); +#endif + SKIP_WHITESPACE (); filename = demand_copy_string (& len); if (filename == NULL) @@ -4955,7 +5605,7 @@ s_incbin (int x ATTRIBUTE_UNUSED) { int i; - path = xmalloc ((unsigned long) len + include_dir_maxlen + 5); + path = (char *) xmalloc ((unsigned long) len + include_dir_maxlen + 5); for (i = 0; i < include_dir_count; i++) { @@ -5025,7 +5675,7 @@ s_include (int arg ATTRIBUTE_UNUSED) { char *filename; int i; - FILE *try; + FILE *try_file; char *path; if (!flag_m68k_mri) @@ -5052,22 +5702,23 @@ s_include (int arg ATTRIBUTE_UNUSED) } obstack_1grow (¬es, '\0'); - filename = obstack_finish (¬es); + filename = (char *) obstack_finish (¬es); while (!is_end_of_line[(unsigned char) *input_line_pointer]) ++input_line_pointer; } demand_empty_rest_of_line (); - path = xmalloc ((unsigned long) i + include_dir_maxlen + 5 /* slop */ ); + path = (char *) xmalloc ((unsigned long) i + + include_dir_maxlen + 5 /* slop */ ); for (i = 0; i < include_dir_count; i++) { strcpy (path, include_dirs[i]); strcat (path, "/"); strcat (path, filename); - if (0 != (try = fopen (path, FOPEN_RT))) + if (0 != (try_file = fopen (path, FOPEN_RT))) { - fclose (try); + fclose (try_file); goto gotit; } } @@ -5196,17 +5847,20 @@ do_s_func (int end_p, const char *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; } @@ -5280,7 +5934,8 @@ input_scrub_insert_file (char *path) #endif static char * -_find_end_of_line (char *s, int mri_string, int insn ATTRIBUTE_UNUSED) +_find_end_of_line (char *s, int mri_string, int insn ATTRIBUTE_UNUSED, + int in_macro) { char inquote = '\0'; int inescape = 0; @@ -5291,6 +5946,13 @@ _find_end_of_line (char *s, int mri_string, int insn ATTRIBUTE_UNUSED) #ifdef TC_EOL_IN_INSN || (insn && TC_EOL_IN_INSN (s)) #endif + /* PR 6926: When we are parsing the body of a macro the sequence + \@ is special - it refers to the invocation count. If the @ + character happens to be registered as a line-separator character + by the target, then the is_end_of_line[] test above will have + returned true, but we need to ignore the line separating + semantics in this particular case. */ + || (in_macro && inescape && *s == '@') ) { if (mri_string && *s == '\'') @@ -5318,5 +5980,5 @@ _find_end_of_line (char *s, int mri_string, int insn ATTRIBUTE_UNUSED) char * find_end_of_line (char *s, int mri_string) { - return _find_end_of_line (s, mri_string, 0); + return _find_end_of_line (s, mri_string, 0, 0); }