X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=gas%2Fread.c;h=121c97ad1c574bab75c8c98aca693cb888f097b1;hb=97c4f2d9c95f8a9dcf3941010277428b3c0baf79;hp=5782f23dfd8993a63f07de064fd0743ef1a9ec81;hpb=05e9452c8210da86b07b621562f4a89bd6f637d4;p=binutils-gdb.git diff --git a/gas/read.c b/gas/read.c index 5782f23dfd8..121c97ad1c5 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, 2006, 2007 + 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 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. @@ -213,13 +213,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) @@ -267,8 +270,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}, @@ -339,6 +342,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}, @@ -410,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}, @@ -520,7 +530,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 \ @@ -607,8 +617,6 @@ 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) { /* We have more of this buffer to parse. */ @@ -697,19 +705,11 @@ 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++; - - 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 @@ -923,7 +923,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'; @@ -1276,13 +1276,14 @@ 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. */ - -#define ALIGN_LIMIT (stdoutput->arch_info->bits_per_address - 1) +#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 = 0; @@ -2043,6 +2044,120 @@ 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. */ +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 @@ -2063,7 +2178,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); @@ -2353,7 +2468,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; @@ -2367,7 +2482,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; @@ -2379,6 +2494,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 @@ -2403,11 +2530,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 @@ -2439,8 +2566,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. */ @@ -2808,7 +2940,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; @@ -3053,7 +3185,7 @@ s_space (int mult) if (exp.X_op == O_constant) { - long repeat; + offsetT repeat; repeat = exp.X_add_number; if (mult) @@ -3183,7 +3315,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); @@ -3334,14 +3466,15 @@ s_weakref (int ignore ATTRIBUTE_UNUSED) char *loop; loop = concat (S_GET_NAME (symbolP), - " => ", S_GET_NAME (symbolP2), NULL); + " => ", 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), NULL); + loop = concat (loop, " => ", S_GET_NAME (symp), + (const char *) NULL); free (old_loop); } @@ -3488,9 +3621,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: @@ -3995,8 +4137,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); @@ -4054,41 +4206,45 @@ 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. */ +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 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 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 - } } #ifdef BITFIELD_CONS_EXPRESSIONS @@ -4482,7 +4638,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); @@ -4845,16 +5001,52 @@ 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; char *start; #ifdef md_flush_pending_output @@ -4892,14 +5084,13 @@ stringer (/* 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 @@ -4926,11 +5117,10 @@ stringer (/* 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 ',': @@ -4942,7 +5132,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 @@ -5517,14 +5707,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 = 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; } @@ -5598,7 +5794,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; @@ -5609,6 +5806,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 == '\'') @@ -5636,5 +5840,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); }