X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gas%2Fread.c;h=1718aaa4d63fa53a612fa146b87bf9aeb724be40;hb=e896287c1643b8b47080c4a8ddbe9a92d9fa585b;hp=d51835e3cecfcc22f8f5af4d7c62f438a0533eb2;hpb=89cdfe5739c7646eaba0f004158522d39c0808aa;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/read.c b/gas/read.c index d51835e3ce..1718aaa4d6 100644 --- a/gas/read.c +++ b/gas/read.c @@ -1,24 +1,22 @@ /* 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 - Free Software Foundation, Inc. + Copyright (C) 1986-2015 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 +36,12 @@ 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" +#include "wchar.h" #ifndef TC_START_LABEL -#define TC_START_LABEL(x,y) (x == ':') +#define TC_START_LABEL(STR, NUL_CHAR, NEXT_CHAR) (NEXT_CHAR == ':') #endif /* Set by the object-format or the target. */ @@ -126,7 +124,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 */ @@ -209,17 +208,47 @@ static int dwarf_file_string; #endif #endif +/* If the target defines the md_frag_max_var hook then we know + enough to implement the .bundle_align_mode features. */ +#ifdef md_frag_max_var +# define HANDLE_BUNDLE +#endif + +#ifdef HANDLE_BUNDLE +/* .bundle_align_mode sets this. Normally it's zero. When nonzero, + it's the exponent of the bundle size, and aligned instruction bundle + mode is in effect. */ +static unsigned int bundle_align_p2; + +/* These are set by .bundle_lock and .bundle_unlock. .bundle_lock sets + bundle_lock_frag to frag_now and then starts a new frag with + frag_align_code. At the same time, bundle_lock_frain gets frchain_now, + so that .bundle_unlock can verify that we didn't change segments. + .bundle_unlock resets both to NULL. If we detect a bundling violation, + then we reset bundle_lock_frchain to NULL as an indicator that we've + already diagnosed the error with as_bad and don't need a cascade of + redundant errors, but bundle_lock_frag remains set to indicate that + we are expecting to see .bundle_unlock. */ +static fragS *bundle_lock_frag; +static frchainS *bundle_lock_frchain; + +/* This is incremented by .bundle_lock and decremented by .bundle_unlock, + to allow nesting. */ +static unsigned int bundle_lock_depth; +#endif + 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); +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 size_t 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) @@ -234,9 +263,12 @@ read_begin (void) obstack_begin (¬es, chunksize); obstack_begin (&cond_obstack, chunksize); +#ifndef tc_line_separator_chars +#define tc_line_separator_chars line_separator_chars +#endif /* Use machine dependent syntax. */ - for (p = line_separator_chars; *p; p++) - is_end_of_line[(unsigned char) *p] = 1; + for (p = tc_line_separator_chars; *p; p++) + is_end_of_line[(unsigned char) *p] = 2; /* Use more. FIXME-SOMEDAY. */ if (flag_mri) @@ -267,12 +299,17 @@ 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}, /* block */ +#ifdef HANDLE_BUNDLE + {"bundle_align_mode", s_bundle_align_mode, 0}, + {"bundle_lock", s_bundle_lock, 0}, + {"bundle_unlock", s_bundle_unlock, 0}, +#endif {"byte", cons, 1}, {"comm", s_comm, 0}, {"common", s_mri_common, 0}, @@ -330,7 +367,7 @@ static const pseudo_typeS potable[] = { /* 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}, @@ -364,7 +401,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}, @@ -391,6 +429,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}, @@ -408,7 +447,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}, @@ -508,17 +551,17 @@ pobegin (void) pop_table_name = "standard"; pop_insert (potable); -#ifdef TARGET_USE_CFIPOP + /* Now CFI ones. */ pop_table_name = "cfi"; pop_override_ok = 1; cfi_pop_insert (); -#endif } -#define HANDLE_CONDITIONAL_ASSEMBLY() \ +#define HANDLE_CONDITIONAL_ASSEMBLY(num_read) \ if (ignore_input ()) \ { \ - char *eol = find_end_of_line (input_line_pointer, flag_m68k_mri); \ + char *eol = find_end_of_line (input_line_pointer - (num_read), \ + flag_m68k_mri); \ input_line_pointer = (input_line_pointer <= buffer_limit \ && eol >= buffer_limit) \ ? buffer_limit \ @@ -532,10 +575,10 @@ pobegin (void) static char *scrub_string; static char *scrub_string_end; -static int -scrub_from_string (char *buf, int buflen) +static size_t +scrub_from_string (char *buf, size_t buflen) { - int copy; + size_t copy; copy = scrub_string_end - scrub_string; if (copy > buflen) @@ -571,14 +614,137 @@ try_macro (char term, const char *line) return 0; } +#ifdef HANDLE_BUNDLE +/* Start a new instruction bundle. Returns the rs_align_code frag that + will be used to align the new bundle. */ +static fragS * +start_bundle (void) +{ + fragS *frag = frag_now; + + frag_align_code (0, 0); + + while (frag->fr_type != rs_align_code) + frag = frag->fr_next; + + gas_assert (frag != frag_now); + + return frag; +} + +/* Calculate the maximum size after relaxation of the region starting + at the given frag and extending through frag_now (which is unfinished). */ +static unsigned int +pending_bundle_size (fragS *frag) +{ + unsigned int offset = frag->fr_fix; + unsigned int size = 0; + + gas_assert (frag != frag_now); + gas_assert (frag->fr_type == rs_align_code); + + while (frag != frag_now) + { + /* This should only happen in what will later become an error case. */ + if (frag == NULL) + return 0; + + size += frag->fr_fix; + if (frag->fr_type == rs_machine_dependent) + size += md_frag_max_var (frag); + + frag = frag->fr_next; + } + + gas_assert (frag == frag_now); + size += frag_now_fix (); + if (frag->fr_type == rs_machine_dependent) + size += md_frag_max_var (frag); + + gas_assert (size >= offset); + + return size - offset; +} + +/* Finish off the frag created to ensure bundle alignment. */ +static void +finish_bundle (fragS *frag, unsigned int size) +{ + gas_assert (bundle_align_p2 > 0); + gas_assert (frag->fr_type == rs_align_code); + + if (size > 1) + { + /* If there is more than a single byte, then we need to set up the + alignment frag. Otherwise we leave it at its initial state from + calling frag_align_code (0, 0), so that it does nothing. */ + frag->fr_offset = bundle_align_p2; + frag->fr_subtype = size - 1; + } + + /* We do this every time rather than just in s_bundle_align_mode + so that we catch any affected section without needing hooks all + over for all paths that do section changes. It's cheap enough. */ + record_alignment (now_seg, bundle_align_p2 - OCTETS_PER_BYTE_POWER); +} + +/* Assemble one instruction. This takes care of the bundle features + around calling md_assemble. */ +static void +assemble_one (char *line) +{ + fragS *insn_start_frag = NULL; + + if (bundle_lock_frchain != NULL && bundle_lock_frchain != frchain_now) + { + as_bad (_("cannot change section or subsection inside .bundle_lock")); + /* Clearing this serves as a marker that we have already complained. */ + bundle_lock_frchain = NULL; + } + + if (bundle_lock_frchain == NULL && bundle_align_p2 > 0) + insn_start_frag = start_bundle (); + + md_assemble (line); + + if (bundle_lock_frchain != NULL) + { + /* Make sure this hasn't pushed the locked sequence + past the bundle size. */ + unsigned int bundle_size = pending_bundle_size (bundle_lock_frag); + if (bundle_size > (1U << bundle_align_p2)) + as_bad (_("\ +.bundle_lock sequence at %u bytes but .bundle_align_mode limit is %u bytes"), + bundle_size, 1U << bundle_align_p2); + } + else if (bundle_align_p2 > 0) + { + unsigned int insn_size = pending_bundle_size (insn_start_frag); + + if (insn_size > (1U << bundle_align_p2)) + as_bad (_("\ +single instruction is %u bytes long but .bundle_align_mode limit is %u"), + (unsigned int) insn_size, 1U << bundle_align_p2); + + finish_bundle (insn_start_frag, insn_size); + } +} + +#else /* !HANDLE_BUNDLE */ + +# define assemble_one(line) md_assemble(line) + +#endif /* HANDLE_BUNDLE */ + /* We read the file, putting things into a web that represents what we have been reading. */ void read_a_source_file (char *name) { - register char c; - register char *s; /* String of symbol, '\0' appended. */ - register int temp; + char nul_char; + char next_char; + char *s; /* String of symbol, '\0' appended. */ + int temp; pseudo_typeS *pop; #ifdef WARN_COMMENTS @@ -605,39 +771,76 @@ 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) { + next_char = * input_line_pointer; /* Text at the start of a line must be a label, we run down and stick a colon in. */ - if (is_name_beginner (*input_line_pointer)) + if (is_name_beginner (next_char) || next_char == '"') { - char *line_start = input_line_pointer; - char c; + char *line_start; int mri_line_macro; - LISTING_NEWLINE (); - HANDLE_CONDITIONAL_ASSEMBLY (); + HANDLE_CONDITIONAL_ASSEMBLY (0); - c = get_symbol_end (); + nul_char = get_symbol_name (& line_start); + next_char = (nul_char == '"' ? input_line_pointer[1] : nul_char); /* In MRI mode, the EQU and MACRO pseudoops must be handled specially. */ @@ -671,8 +874,7 @@ read_a_source_file (char *name) symbol in the symbol table. */ if (!mri_line_macro #ifdef TC_START_LABEL_WITHOUT_COLON - && TC_START_LABEL_WITHOUT_COLON(c, - input_line_pointer) + && TC_START_LABEL_WITHOUT_COLON (nul_char, next_char) #endif ) line_label = colon (line_start); @@ -682,8 +884,8 @@ read_a_source_file (char *name) (valueT) 0, &zero_address_frag); - *input_line_pointer = c; - if (c == ':') + next_char = restore_line_pointer (nul_char); + if (next_char == ':') input_line_pointer++; } } @@ -695,74 +897,35 @@ 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) - c = *input_line_pointer++; - - 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'; + Each test is independent of all other tests at the (top) + level. */ + do + nul_char = next_char = *input_line_pointer++; + while (next_char == '\t' || next_char == ' ' || next_char == '\f'); - /* 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)) + if (is_name_beginner (next_char) || next_char == '"') { + char *rest; + /* Want user-defined label or pseudo/opcode. */ - HANDLE_CONDITIONAL_ASSEMBLY (); + HANDLE_CONDITIONAL_ASSEMBLY (1); - s = --input_line_pointer; - c = get_symbol_end (); /* name's delimiter. */ + --input_line_pointer; + nul_char = get_symbol_name (& s); /* name's delimiter. */ + next_char = (nul_char == '"' ? input_line_pointer[1] : nul_char); + rest = input_line_pointer + (nul_char == '"' ? 2 : 1); - /* C is character after symbol. - That character's place in the input line is now '\0'. + /* NEXT_CHAR is character after symbol. + The end of symbol 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)) + Input_line_pointer->'\0' where NUL_CHAR was. */ + if (TC_START_LABEL (s, nul_char, next_char)) { if (flag_m68k_mri) { - char *rest = input_line_pointer + 1; - /* In MRI mode, \tsym: set 0 is permitted. */ if (*rest == ':') ++rest; @@ -781,29 +944,29 @@ read_a_source_file (char *name) } line_label = colon (s); /* User-defined label. */ - /* Put ':' back for error messages' sake. */ - *input_line_pointer++ = ':'; + restore_line_pointer (nul_char); + ++ input_line_pointer; #ifdef tc_check_label tc_check_label (line_label); #endif /* Input_line_pointer->after ':'. */ SKIP_WHITESPACE (); } - else if (input_line_pointer[1] == '=' - && (c == '=' - || ((c == ' ' || c == '\t') - && input_line_pointer[2] == '='))) + else if ((next_char == '=' && *rest == '=') + || ((next_char == ' ' || next_char == '\t') + && rest[0] == '=' + && rest[1] == '=')) { equals (s, -1); demand_empty_rest_of_line (); } - else if ((c == '=' - || ((c == ' ' || c == '\t') - && input_line_pointer[1] == '=')) + else if ((next_char == '=' + || ((next_char == ' ' || next_char == '\t') + && *rest == '=')) #ifdef TC_EQUAL_IN_INSN - && !TC_EQUAL_IN_INSN (c, s) + && !TC_EQUAL_IN_INSN (next_char, s) #endif - ) + ) { equals (s, 1); demand_empty_rest_of_line (); @@ -841,7 +1004,7 @@ read_a_source_file (char *name) { /* PSEUDO - OP. - WARNING: c has next char, which may be end-of-line. + WARNING: next_char 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 '.'. */ @@ -886,25 +1049,25 @@ read_a_source_file (char *name) { char *end = input_line_pointer; - *input_line_pointer = c; + (void) restore_line_pointer (nul_char); s_ignore (0); - c = *--input_line_pointer; + nul_char = next_char = *--input_line_pointer; *input_line_pointer = '\0'; - if (! macro_defined || ! try_macro (c, s)) + if (! macro_defined || ! try_macro (next_char, s)) { *end = '\0'; as_bad (_("unknown pseudo-op: `%s'"), s); - *input_line_pointer++ = c; + *input_line_pointer++ = nul_char; } continue; } /* Put it back for error messages etc. */ - *input_line_pointer = c; + next_char = restore_line_pointer (nul_char); /* The following skip of whitespace is compulsory. A well shaped space is sometimes all that separates keyword from operands. */ - if (c == ' ' || c == '\t') + if (next_char == ' ' || next_char == '\t') input_line_pointer++; /* Input_line is restored. @@ -918,16 +1081,16 @@ read_a_source_file (char *name) } else { - /* 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); - c = *input_line_pointer; + /* WARNING: next_char may be end-of-line. */ + /* Also: input_line_pointer->`\0` where nul_char was. */ + (void) restore_line_pointer (nul_char); + input_line_pointer = _find_end_of_line (input_line_pointer, flag_m68k_mri, 1, 0); + next_char = nul_char = *input_line_pointer; *input_line_pointer = '\0'; generate_lineno_debug (); - if (macro_defined && try_macro (c, s)) + if (macro_defined && try_macro (next_char, s)) continue; if (mri_pending_align) @@ -941,9 +1104,9 @@ read_a_source_file (char *name) } } - md_assemble (s); /* Assemble 1 instruction. */ + assemble_one (s); /* Assemble 1 instruction. */ - *input_line_pointer++ = c; + *input_line_pointer++ = nul_char; /* We resume loop AFTER the end-of-line from this instruction. */ @@ -953,17 +1116,20 @@ read_a_source_file (char *name) } /* Empty statement? */ - if (is_end_of_line[(unsigned char) c]) + if (is_end_of_line[(unsigned char) next_char]) continue; - if ((LOCAL_LABELS_DOLLAR || LOCAL_LABELS_FB) && ISDIGIT (c)) + if ((LOCAL_LABELS_DOLLAR || LOCAL_LABELS_FB) && ISDIGIT (next_char)) { /* local label ("4:") */ char *backup = input_line_pointer; - HANDLE_CONDITIONAL_ASSEMBLY (); + HANDLE_CONDITIONAL_ASSEMBLY (1); + + temp = next_char - '0'; - temp = c - '0'; + if (nul_char == '"') + ++ input_line_pointer; /* Read the whole number. */ while (ISDIGIT (*input_line_pointer)) @@ -997,9 +1163,9 @@ read_a_source_file (char *name) } input_line_pointer = backup; - } /* local label ("4:") */ + } - if (c && strchr (line_comment_chars, c)) + if (next_char && strchr (line_comment_chars, next_char)) { /* Its a comment. Better say APP or NO_APP. */ sb sbuf; char *ends; @@ -1008,13 +1174,16 @@ 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); ends = strstr (s, "#NO_APP\n"); if (!ends) @@ -1027,7 +1196,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 { @@ -1043,7 +1212,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; } @@ -1068,8 +1237,8 @@ read_a_source_file (char *name) new_tmp = new_buf; for (;;) { - int space; - int size; + size_t space; + size_t size; space = (new_buf + new_length) - new_tmp; size = do_scrub_chars (scrub_from_string, new_tmp, space); @@ -1080,7 +1249,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; } @@ -1095,7 +1264,9 @@ read_a_source_file (char *name) actual macro expansion (possibly nested) and other input expansion work. Beware that in messages, line numbers and possibly file names will be incorrect. */ - sb_add_string (&sbuf, new_buf); + new_length = strlen (new_buf); + sb_build (&sbuf, new_length); + sb_add_buffer (&sbuf, new_buf, new_length); input_scrub_include_sb (&sbuf, input_line_pointer, 0); sb_kill (&sbuf); buffer_limit = input_scrub_next_buffer (&input_line_pointer); @@ -1103,23 +1274,31 @@ read_a_source_file (char *name) continue; } - HANDLE_CONDITIONAL_ASSEMBLY (); + HANDLE_CONDITIONAL_ASSEMBLY (1); #ifdef tc_unrecognized_line - if (tc_unrecognized_line (c)) + if (tc_unrecognized_line (next_char)) continue; #endif input_line_pointer--; - /* Report unknown char as ignored. */ + /* Report unknown char as error. */ demand_empty_rest_of_line (); } - -#ifdef md_after_pass_hook - md_after_pass_hook (); -#endif } quit: + symbol_set_value_now (&dot_symbol); + +#ifdef HANDLE_BUNDLE + if (bundle_lock_frag != NULL) + { + as_bad_where (bundle_lock_frag->fr_file, bundle_lock_frag->fr_line, + _(".bundle_lock with no matching .bundle_unlock")); + bundle_lock_frag = NULL; + bundle_lock_frchain = NULL; + bundle_lock_depth = 0; + } +#endif #ifdef md_cleanup md_cleanup (); @@ -1136,10 +1315,10 @@ read_a_source_file (char *name) } /* 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. */ + Take the sign of the number from SIGN rather than X_add_number. */ static void -convert_to_bignum (expressionS *exp) +convert_to_bignum (expressionS *exp, int sign) { valueT value; unsigned int i; @@ -1152,8 +1331,8 @@ convert_to_bignum (expressionS *exp) } /* 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; + if ((exp->X_add_number < 0) == !sign) + generic_bignum[i++] = sign ? LITTLENUM_MASK : 0; exp->X_op = O_big; exp->X_add_number = i; } @@ -1270,16 +1449,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. */ - -#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; + char stopc = 0; offsetT fill = 0; int max; int fill_p; @@ -1298,6 +1478,11 @@ s_align (int arg, int bytes_p) { align = get_absolute_expression (); SKIP_WHITESPACE (); + +#ifdef TC_ALIGN_ZERO_IS_DEFAULT + if (arg > 0 && align == 0) + align = arg; +#endif } if (bytes_p) @@ -1406,43 +1591,124 @@ s_align_ptwo (int arg) /* Switch in and out of alternate macro mode. */ -void +static void s_altmacro (int on) { demand_empty_rest_of_line (); macro_set_alternate (on); } +/* Read a symbol name from input_line_pointer. + + Stores the symbol name in a buffer and returns a pointer to this buffer. + The buffer is xalloc'ed. It is the caller's responsibility to free + this buffer. + + The name is not left in the i_l_p buffer as it may need processing + to handle escape characters. + + Advances i_l_p to the next non-whitespace character. + + If a symbol name could not be read, the routine issues an error + messages, skips to the end of the line and returns NULL. */ + +char * +read_symbol_name (void) +{ + char * name; + char * start; + char c; + + c = *input_line_pointer++; + + if (c == '"') + { +#define SYM_NAME_CHUNK_LEN 128 + ptrdiff_t len = SYM_NAME_CHUNK_LEN; + char * name_end; + unsigned int C; + + start = name = xmalloc (len + 1); + + name_end = name + SYM_NAME_CHUNK_LEN; + + while (is_a_char (C = next_char_of_string ())) + { + if (name >= name_end) + { + ptrdiff_t sofar; + + sofar = name - start; + len += SYM_NAME_CHUNK_LEN; + start = xrealloc (start, len + 1); + name_end = start + len; + name = start + sofar; + } + + *name++ = (char) C; + } + *name = 0; + + /* Since quoted symbol names can contain non-ASCII characters, + check the string and warn if it cannot be recognised by the + current character set. */ + if (mbstowcs (NULL, name, len) == (size_t) -1) + as_warn (_("symbol name not recognised in the current locale")); + } + else if (is_name_beginner (c) || c == '\001') + { + ptrdiff_t len; + + name = input_line_pointer - 1; + + /* We accept \001 in a name in case this is + being called with a constructed string. */ + while (is_part_of_name (c = *input_line_pointer++) + || c == '\001') + ; + + len = (input_line_pointer - name) - 1; + start = xmalloc (len + 1); + + memcpy (start, name, len); + start[len] = 0; + + /* Skip a name ender char if one is present. */ + if (! is_name_ender (c)) + --input_line_pointer; + } + else + name = start = NULL; + + if (name == start) + { + as_bad (_("expected symbol name")); + ignore_rest_of_line (); + return NULL; + } + + SKIP_WHITESPACE (); + + return start; +} + + 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); - name = input_line_pointer; - c = get_symbol_end (); - /* Just after name is now '\0'. */ - p = input_line_pointer; - *p = c; - - if (name == p) - { - as_bad (_("expected symbol name")); - ignore_rest_of_line (); - goto out; - } - - SKIP_WHITESPACE (); + if ((name = read_symbol_name ()) == NULL) + goto out; /* Accept an optional comma after the name. The comma used to be required, but Irix 5 cc does not generate it for .lcomm. */ @@ -1451,7 +1717,7 @@ s_comm_internal (int param, temp = get_absolute_expr (&exp); size = temp; - size &= ((offsetT) 2 << (stdoutput->arch_info->bits_per_address - 1)) - 1; + size &= ((addressT) 2 << (stdoutput->arch_info->bits_per_address - 1)) - 1; if (exp.X_op == O_absent) { as_bad (_("missing size expression")); @@ -1465,7 +1731,6 @@ s_comm_internal (int param, goto out; } - *p = 0; symbolP = symbol_find_or_make (name); if ((S_IS_DEFINED (symbolP) || symbol_equated_p (symbolP)) && !S_IS_COMMON (symbolP)) @@ -1474,7 +1739,6 @@ s_comm_internal (int param, { symbolP = NULL; as_bad (_("symbol `%s' is already defined"), name); - *p = c; ignore_rest_of_line (); goto out; } @@ -1492,7 +1756,6 @@ s_comm_internal (int param, 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 @@ -1500,19 +1763,14 @@ 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; - 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); + if (name != NULL) + free (name); return symbolP; } @@ -1535,7 +1793,7 @@ s_mri_common (int small ATTRIBUTE_UNUSED) symbolS *sym; offsetT align; char *stop = NULL; - char stopc; + char stopc = 0; if (!flag_mri) { @@ -1549,7 +1807,7 @@ s_mri_common (int small ATTRIBUTE_UNUSED) name = input_line_pointer; if (!ISDIGIT (*name)) - c = get_symbol_end (); + c = get_symbol_name (& name); else { do @@ -1572,7 +1830,7 @@ s_mri_common (int small ATTRIBUTE_UNUSED) } sym = symbol_find_or_make (name); - *input_line_pointer = c; + c = restore_line_pointer (c); if (alc != NULL) free (alc); @@ -1599,6 +1857,8 @@ s_mri_common (int small ATTRIBUTE_UNUSED) #ifdef S_SET_ALIGN if (align != 0) S_SET_ALIGN (sym, align); +#else + (void) align; #endif if (line_label != NULL) @@ -1630,7 +1890,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) @@ -1643,9 +1903,6 @@ s_data (int ignore ATTRIBUTE_UNUSED) subseg_set (section, (subsegT) temp); -#ifdef OBJ_VMS - const_flag = 0; -#endif demand_empty_rest_of_line (); } @@ -1672,17 +1929,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. */ @@ -1697,25 +1951,47 @@ 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 (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. GCC however will generate a line number of zero when it is pre-processing builtins for assembler-with-cpp files: - # 0 "" + # 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 @@ -1724,13 +2000,74 @@ s_app_line (int ignore ATTRIBUTE_UNUSED) 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 @@ -1804,7 +2141,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); @@ -1826,13 +2163,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 == ',') { @@ -1926,19 +2267,19 @@ 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); do { - name = input_line_pointer; - c = get_symbol_end (); + if ((name = read_symbol_name ()) == NULL) + return; + symbolP = symbol_find_or_make (name); S_SET_EXTERNAL (symbolP); - *input_line_pointer = c; SKIP_WHITESPACE (); c = *input_line_pointer; if (c == ',') @@ -1948,6 +2289,8 @@ s_globl (int ignore ATTRIBUTE_UNUSED) if (is_end_of_line[(unsigned char) *input_line_pointer]) c = '\n'; } + + free (name); } while (c == ','); @@ -1970,14 +2313,14 @@ s_irp (int irpc) as_where (&file, &line); - sb_new (&s); eol = find_end_of_line (input_line_pointer, 0); + sb_build (&s, eol - input_line_pointer); sb_add_buffer (&s, input_line_pointer, eol - input_line_pointer); input_line_pointer = eol; 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,8 +2350,7 @@ s_linkonce (int ignore ATTRIBUTE_UNUSED) char *s; char c; - s = input_line_pointer; - c = get_symbol_end (); + c = get_symbol_name (& s); if (strcasecmp (s, "discard") == 0) type = LINKONCE_DISCARD; else if (strcasecmp (s, "one_only") == 0) @@ -2020,7 +2362,7 @@ s_linkonce (int ignore ATTRIBUTE_UNUSED) else as_warn (_("unrecognized .linkonce type `%s'"), s); - *input_line_pointer = c; + (void) restore_line_pointer (c); } #ifdef obj_handle_link_once @@ -2200,34 +2542,18 @@ s_lcomm_bytes (int needs_align) void s_lsym (int ignore ATTRIBUTE_UNUSED) { - register char *name; - register char c; - register char *p; + char *name; expressionS exp; - register symbolS *symbolP; + symbolS *symbolP; /* We permit ANY defined expression: BSD4.2 demands constants. */ - name = input_line_pointer; - c = get_symbol_end (); - p = input_line_pointer; - *p = c; - - if (name == p) - { - as_bad (_("expected symbol name")); - ignore_rest_of_line (); - return; - } - - SKIP_WHITESPACE (); + if ((name = read_symbol_name ()) == NULL) + return; if (*input_line_pointer != ',') { - *p = 0; as_bad (_("expected comma after \"%s\""), name); - *p = c; - ignore_rest_of_line (); - return; + goto err_out; } input_line_pointer++; @@ -2237,11 +2563,9 @@ s_lsym (int ignore ATTRIBUTE_UNUSED) && exp.X_op != O_register) { as_bad (_("bad expression")); - ignore_rest_of_line (); - return; + goto err_out; } - *p = 0; symbolP = symbol_find_or_make (name); if (S_GET_SEGMENT (symbolP) == undefined_section) @@ -2259,15 +2583,21 @@ s_lsym (int ignore ATTRIBUTE_UNUSED) as_bad (_("symbol `%s' is already defined"), name); } - *p = c; demand_empty_rest_of_line (); + free (name); + return; + + err_out: + ignore_rest_of_line (); + free (name); + return; } /* Read a line into an sb. Returns the character that ended the line 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; @@ -2281,7 +2611,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; @@ -2293,6 +2623,18 @@ get_line_sb (sb *line) return *input_line_pointer++; } +static size_t +get_non_macro_line_sb (sb *line) +{ + return get_line_sb (line, 0); +} + +static size_t +get_macro_line_sb (sb *line) +{ + return get_line_sb (line, 1); +} + /* Define a macro. This is an interface to macro.c. */ void @@ -2306,22 +2648,25 @@ s_macro (int ignore ATTRIBUTE_UNUSED) as_where (&file, &line); - sb_new (&s); eol = find_end_of_line (input_line_pointer, 0); + sb_build (&s, eol - input_line_pointer); sb_add_buffer (&s, input_line_pointer, eol - input_line_pointer); input_line_pointer = eol; if (line_label != NULL) { sb label; + size_t len; - sb_new (&label); - sb_add_string (&label, S_GET_NAME (line_label)); - err = define_macro (0, &s, &label, get_line_sb, file, line, &name); + name = S_GET_NAME (line_label); + len = strlen (name); + sb_build (&label, len); + sb_add_buffer (&label, name, len); + 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 @@ -2353,8 +2698,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. */ @@ -2362,10 +2712,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; @@ -2400,7 +2755,9 @@ s_mri (int ignore ATTRIBUTE_UNUSED) static void do_org (segT segment, expressionS *exp, int fill) { - if (segment != now_seg && segment != absolute_section) + if (segment != now_seg + && segment != absolute_section + && segment != expr_section) as_bad (_("invalid segment \"%s\""), segment_name (segment)); if (now_seg == absolute_section) @@ -2435,9 +2792,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 (); @@ -2499,7 +2856,7 @@ s_mri_sect (char *type ATTRIBUTE_UNUSED) name = input_line_pointer; if (!ISDIGIT (*name)) - c = get_symbol_end (); + c = get_symbol_name (& name); else { do @@ -2514,11 +2871,11 @@ s_mri_sect (char *type ATTRIBUTE_UNUSED) name = xstrdup (name); - *input_line_pointer = c; + c = restore_line_pointer (c); seg = subseg_new (name, 0); - if (*input_line_pointer == ',') + if (c == ',') { int align; @@ -2573,16 +2930,15 @@ s_mri_sect (char *type ATTRIBUTE_UNUSED) SKIP_WHITESPACE (); - name = input_line_pointer; - c = get_symbol_end (); + c = get_symbol_name (& name); name = xstrdup (name); - *input_line_pointer = c; + c = restore_line_pointer (c); seg = subseg_new (name, 0); - if (*input_line_pointer != ',') + if (c != ',') *type = 'C'; else { @@ -2590,8 +2946,7 @@ s_mri_sect (char *type ATTRIBUTE_UNUSED) ++input_line_pointer; SKIP_WHITESPACE (); - sectype = input_line_pointer; - c = get_symbol_end (); + c = get_symbol_name (& sectype); if (*sectype == '\0') *type = 'C'; else if (strcasecmp (sectype, "text") == 0) @@ -2602,7 +2957,7 @@ s_mri_sect (char *type ATTRIBUTE_UNUSED) *type = 'R'; else as_warn (_("unrecognized section type `%s'"), sectype); - *input_line_pointer = c; + (void) restore_line_pointer (c); } if (*input_line_pointer == ',') @@ -2611,8 +2966,7 @@ s_mri_sect (char *type ATTRIBUTE_UNUSED) ++input_line_pointer; SKIP_WHITESPACE (); - seccmd = input_line_pointer; - c = get_symbol_end (); + c = get_symbol_name (& seccmd); if (strcasecmp (seccmd, "absolute") == 0) { as_bad (_("absolute sections are not supported")); @@ -2624,14 +2978,14 @@ s_mri_sect (char *type ATTRIBUTE_UNUSED) { int align; - *input_line_pointer = c; + (void) restore_line_pointer (c); align = get_absolute_expression (); record_alignment (seg, align); } else { as_warn (_("unrecognized section command `%s'"), seccmd); - *input_line_pointer = c; + (void) restore_line_pointer (c); } } @@ -2677,11 +3031,10 @@ s_purgem (int ignore ATTRIBUTE_UNUSED) char c; SKIP_WHITESPACE (); - name = input_line_pointer; - c = get_symbol_end (); + c = get_symbol_name (& name); delete_macro (name); *input_line_pointer = c; - SKIP_WHITESPACE (); + SKIP_WHITESPACE_AFTER_NAME (); } while (*input_line_pointer++ == ','); @@ -2694,7 +3047,7 @@ s_purgem (int ignore ATTRIBUTE_UNUSED) static void s_bad_end (int endr) { - as_warn (_(".end%c encountered without preceeding %s"), + as_warn (_(".end%c encountered without preceding %s"), endr ? 'r' : 'm', endr ? ".rept, .irp, or .irpc" : ".macro"); demand_empty_rest_of_line (); @@ -2722,13 +3075,13 @@ 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; } - sb_new (&many); + sb_build (&many, count * one.len); while (count-- > 0) sb_add_sb (&many, &one); @@ -2739,6 +3092,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_build (& processed, one.len); + 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. @@ -2791,7 +3195,7 @@ assign_symbol (char *name, int mode) symbol_set_frag (symbolP, dummy_frag); } #endif -#ifdef OBJ_COFF +#if defined (OBJ_COFF) && !defined (TE_PE) /* "set" symbols are local unless otherwise specified. */ SF_SET_LOCAL (symbolP); #endif @@ -2799,9 +3203,8 @@ assign_symbol (char *name, int mode) 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) + && !S_CAN_BE_REDEFINED (symbolP)) { as_bad (_("symbol `%s' is already defined"), name); symbolP = symbol_clone (symbolP, 0); @@ -2830,42 +3233,25 @@ 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 (name == end_name) - { - as_bad (_("expected symbol name")); - ignore_rest_of_line (); - return; - } - - SKIP_WHITESPACE (); + if ((name = read_symbol_name ()) == NULL) + return; if (*input_line_pointer != ',') { - *end_name = 0; as_bad (_("expected comma after \"%s\""), name); - *end_name = delim; ignore_rest_of_line (); + free (name); return; } input_line_pointer++; - *end_name = 0; - assign_symbol (name, equiv); - *end_name = delim; - demand_empty_rest_of_line (); + free (name); } void @@ -2875,13 +3261,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); @@ -2897,12 +3287,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; @@ -2967,7 +3357,7 @@ s_space (int mult) if (exp.X_op == O_constant) { - long repeat; + offsetT repeat; repeat = exp.X_add_number; if (mult) @@ -3051,7 +3441,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); @@ -3097,7 +3491,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); @@ -3128,11 +3522,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) @@ -3142,14 +3542,11 @@ 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); demand_empty_rest_of_line (); -#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 @@ -3158,23 +3555,12 @@ 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; - } + if ((name = read_symbol_name ()) == NULL) + return; symbolP = symbol_find_or_make (name); @@ -3183,41 +3569,27 @@ s_weakref (int ignore ATTRIBUTE_UNUSED) if (!S_IS_VOLATILE (symbolP)) { as_bad (_("symbol `%s' is already defined"), name); - *end_name = delim; - ignore_rest_of_line (); - return; + goto err_out; } 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; + goto err_out; } input_line_pointer++; SKIP_WHITESPACE (); + free (name); - 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 ((name = read_symbol_name ()) == NULL) + return; if ((symbolP2 = symbol_find_noref (name, 1)) == NULL && (symbolP2 = md_undefined_symbol (name)) == NULL) @@ -3233,7 +3605,7 @@ s_weakref (int ignore ATTRIBUTE_UNUSED) { expressionS *expP = symbol_get_value_expression (symp); - assert (expP->X_op == O_symbol + gas_assert (expP->X_op == O_symbol && expP->X_add_number == 0); symp = expP->X_add_symbol; } @@ -3242,14 +3614,16 @@ 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); } @@ -3257,8 +3631,7 @@ s_weakref (int ignore ATTRIBUTE_UNUSED) S_GET_NAME (symbolP), loop); free (loop); - - *end_name = delim; + free (name); ignore_rest_of_line (); return; } @@ -3269,8 +3642,6 @@ s_weakref (int ignore ATTRIBUTE_UNUSED) /* symbolP2 = symp; */ } - *end_name = delim; - memset (&exp, 0, sizeof (exp)); exp.X_op = O_symbol; exp.X_add_symbol = symbolP2; @@ -3281,6 +3652,13 @@ s_weakref (int ignore ATTRIBUTE_UNUSED) S_SET_WEAKREFR (symbolP); demand_empty_rest_of_line (); + free (name); + return; + + err_out: + ignore_rest_of_line (); + free (name); + return; } @@ -3303,7 +3681,7 @@ demand_empty_rest_of_line (void) *input_line_pointer); ignore_rest_of_line (); } - + /* Return pointing just after end-of-line. */ know (is_end_of_line[(unsigned char) input_line_pointer[-1]]); } @@ -3396,9 +3774,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: @@ -3429,6 +3816,7 @@ pseudo_set (symbolS *symbolP) } 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; @@ -3471,19 +3859,22 @@ parse_mri_cons (expressionS *exp, unsigned int nbytes); #ifndef TC_PARSE_CONS_EXPRESSION #ifdef BITFIELD_CONS_EXPRESSIONS -#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) parse_bitfield_cons (EXP, NBYTES) +#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) \ + (parse_bitfield_cons (EXP, NBYTES), TC_PARSE_CONS_RETURN_NONE) static void 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) +#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) \ + (parse_repeat_cons (EXP, NBYTES), TC_PARSE_CONS_RETURN_NONE) static void parse_repeat_cons (expressionS *exp, unsigned int nbytes); #endif /* If we haven't gotten one yet, just call expression. */ #ifndef TC_PARSE_CONS_EXPRESSION -#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) expression (EXP) +#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) \ + (expression (EXP), TC_PARSE_CONS_RETURN_NONE) #endif #endif @@ -3491,7 +3882,7 @@ void do_parse_cons_expression (expressionS *exp, int nbytes ATTRIBUTE_UNUSED) { - TC_PARSE_CONS_EXPRESSION (exp, nbytes); + (void) TC_PARSE_CONS_EXPRESSION (exp, nbytes); } @@ -3499,13 +3890,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 (); @@ -3534,12 +3925,30 @@ cons_worker (register int nbytes, /* 1=.byte, 2=.word, 4=.long. */ c = 0; do { + TC_PARSE_CONS_RETURN_TYPE ret = TC_PARSE_CONS_RETURN_NONE; +#ifdef TC_CONS_FIX_CHECK + fixS **cur_fix = &frchain_now->fix_tail; + + if (*cur_fix != NULL) + cur_fix = &(*cur_fix)->fx_next; +#endif + #ifdef TC_M68K if (flag_m68k_mri) parse_mri_cons (&exp, (unsigned int) nbytes); else #endif - TC_PARSE_CONS_EXPRESSION (&exp, (unsigned int) nbytes); + { +#if 0 + if (*input_line_pointer == '"') + { + as_bad (_("unexpected `\"' in expression")); + ignore_rest_of_line (); + return; + } +#endif + ret = TC_PARSE_CONS_EXPRESSION (&exp, (unsigned int) nbytes); + } if (rva) { @@ -3548,7 +3957,10 @@ cons_worker (register int nbytes, /* 1=.byte, 2=.word, 4=.long. */ else as_fatal (_("rva without symbol")); } - emit_expr (&exp, (unsigned int) nbytes); + emit_expr_with_reloc (&exp, (unsigned int) nbytes, ret); +#ifdef TC_CONS_FIX_CHECK + TC_CONS_FIX_CHECK (&exp, nbytes, *cur_fix); +#endif ++c; } while (*input_line_pointer++ == ','); @@ -3579,21 +3991,158 @@ s_rva (int size) cons_worker (size, 1); } +/* .reloc offset, reloc_name, symbol+addend. */ + +static void +s_reloc (int ignore ATTRIBUTE_UNUSED) +{ + char *stop = NULL; + char stopc = 0; + expressionS exp; + char *r_name; + int c; + struct reloc_list *reloc; + struct _bfd_rel { char *name; bfd_reloc_code_real_type code; }; + static struct _bfd_rel bfd_relocs[] = { + { "NONE", BFD_RELOC_NONE }, + { "8", BFD_RELOC_8 }, + { "16", BFD_RELOC_16 }, + { "32", BFD_RELOC_32 }, + { "64", BFD_RELOC_64 } + }; + + 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 (); + c = get_symbol_name (& r_name); + if (strncasecmp (r_name, "BFD_RELOC_", 10) == 0) + { + unsigned int i; + + for (reloc->u.a.howto = NULL, i = 0; i < ARRAY_SIZE (bfd_relocs); i++) + if (strcasecmp (r_name + 10, bfd_relocs[i].name) == 0) + { + reloc->u.a.howto = bfd_reloc_type_lookup (stdoutput, + bfd_relocs[i].code); + break; + } + } + else + 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_AFTER_NAME (); + 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. */ void emit_expr (expressionS *exp, unsigned int nbytes) +{ + emit_expr_with_reloc (exp, nbytes, TC_PARSE_CONS_RETURN_NONE); +} + +void +emit_expr_with_reloc (expressionS *exp, + unsigned int nbytes, + TC_PARSE_CONS_RETURN_TYPE reloc) { 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; + frag_grow (nbytes); dot_value = frag_now_fix (); + dot_frag = frag_now; #ifndef NO_LISTING #ifdef OBJ_ELF @@ -3724,6 +4273,12 @@ emit_expr (expressionS *exp, unsigned int nbytes) p = frag_more ((int) nbytes); + if (reloc != TC_PARSE_CONS_RETURN_NONE) + { + emit_expr_fix (exp, nbytes, frag_now, p, reloc); + return; + } + #ifndef WORKING_DOT_WORD /* If we have the difference of two symbols in a word, save it on the broken_words list. See the code in write.c. */ @@ -3754,17 +4309,17 @@ emit_expr (expressionS *exp, unsigned int nbytes) if (op == O_constant && nbytes > sizeof (valueT)) { extra_digit = exp->X_unsigned ? 0 : -1; - convert_to_bignum (exp); + convert_to_bignum (exp, !exp->X_unsigned); op = O_big; } 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. */ @@ -3796,8 +4351,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); @@ -3807,15 +4372,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) @@ -3855,41 +4437,64 @@ emit_expr (expressionS *exp, unsigned int nbytes) } } else - { - memset (p, 0, nbytes); + emit_expr_fix (exp, nbytes, frag_now, p, TC_PARSE_CONS_RETURN_NONE); +} - /* 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, + TC_PARSE_CONS_RETURN_TYPE r ATTRIBUTE_UNUSED) +{ + int offset = 0; + unsigned int size = nbytes; + + memset (p, 0, size); + + /* 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 + offset, size, exp, r); #else - { - bfd_reloc_code_real_type r; + if (r != TC_PARSE_CONS_RETURN_NONE) + { + reloc_howto_type *reloc_howto; - 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); + reloc_howto = bfd_reloc_type_lookup (stdoutput, r); + size = bfd_get_reloc_size (reloc_howto); + + if (size > nbytes) + { + as_bad (_("%s relocations do not fit in %u bytes\n"), + reloc_howto->name, nbytes); + return; + } + else if (target_big_endian) + offset = nbytes - size; + } + else + switch (size) + { + 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"), size); + return; } + fix_new_exp (frag, p - frag->fr_literal + offset, size, + exp, 0, r); #endif - } } #ifdef BITFIELD_CONS_EXPRESSIONS @@ -3997,7 +4602,7 @@ parse_bitfield_cons (exp, nbytes) return; } /* Too complex. */ - value |= ((~(-1 << width) & exp->X_add_number) + value |= ((~(-(1 << width)) & exp->X_add_number) << ((BITS_PER_CHAR * nbytes) - bits_available)); if ((bits_available -= width) == 0 @@ -4014,6 +4619,7 @@ parse_bitfield_cons (exp, nbytes) exp->X_add_number = value; exp->X_op = O_constant; exp->X_unsigned = 1; + exp->X_extrabit = 0; } } @@ -4023,15 +4629,13 @@ parse_bitfield_cons (exp, nbytes) #ifdef TC_M68K static void -parse_mri_cons (exp, nbytes) - expressionS *exp; - unsigned int nbytes; +parse_mri_cons (expressionS *exp, unsigned int nbytes) { if (*input_line_pointer != '\'' && (input_line_pointer[1] != '\'' || (*input_line_pointer != 'A' && *input_line_pointer != 'E'))) - TC_PARSE_CONS_EXPRESSION (exp, nbytes); + (void) TC_PARSE_CONS_EXPRESSION (exp, nbytes); else { unsigned int scan; @@ -4102,7 +4706,7 @@ parse_repeat_cons (exp, nbytes) unsigned int nbytes; { expressionS count; - register int i; + int i; expression (exp); @@ -4237,11 +4841,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 ()) @@ -4254,6 +4858,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!). */ @@ -4283,7 +4891,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); @@ -4334,8 +4942,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 { @@ -4355,12 +4963,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; } @@ -4383,8 +4989,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 { @@ -4486,7 +5092,7 @@ output_big_sleb128 (char *p, LITTLENUM_TYPE *bignum, int size) { /* Sign-extend VAL. */ if (val & (1 << (loaded - 1))) - val |= ~0 << loaded; + val |= ~0U << loaded; if (orig) *p = val & 0x7f; p++; @@ -4544,7 +5150,7 @@ output_big_leb128 (char *p, LITTLENUM_TYPE *bignum, int size, int sign) } /* Generate the appropriate fragments for a given expression to emit a - leb128 value. */ + leb128 value. SIGN is 1 for sleb, 0 for uleb. */ static void emit_leb128_expr (expressionS *exp, int sign) @@ -4571,12 +5177,12 @@ emit_leb128_expr (expressionS *exp, int sign) } else if (op == O_constant && sign - && (exp->X_add_number < 0) != !exp->X_unsigned) + && (exp->X_add_number < 0) == !exp->X_extrabit) { /* 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); + convert_to_bignum (exp, exp->X_extrabit); op = O_big; } @@ -4646,22 +5252,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 '\"'. @@ -4692,19 +5340,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 @@ -4720,18 +5368,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 ',': @@ -4743,7 +5389,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 @@ -4753,7 +5399,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) @@ -4769,7 +5415,7 @@ next_char_of_string (void) #ifndef NO_STRING_ESCAPES case '\\': - switch (c = *input_line_pointer++) + switch (c = *input_line_pointer++ & CHAR_MASK) { case 'b': c = '\b'; @@ -4820,7 +5466,7 @@ next_char_of_string (void) number = number * 8 + c - '0'; } - c = number & 0xff; + c = number & CHAR_MASK; } --input_line_pointer; break; @@ -4842,7 +5488,7 @@ next_char_of_string (void) number = number * 16 + c - 'a' + 10; c = *input_line_pointer++; } - c = number & 0xff; + c = number & CHAR_MASK; --input_line_pointer; } break; @@ -4873,9 +5519,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 @@ -4891,11 +5537,11 @@ 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 = get_segmented_expression (expP); - if ((retval = get_segmented_expression (expP)) == undefined_section) + if (retval == undefined_section) { /* There is no easy way to extract the undefined symbol from the expression. */ @@ -4909,8 +5555,7 @@ get_known_segmented_expression (register expressionS *expP) expP->X_op = O_constant; expP->X_add_number = 0; } - know (retval == absolute_section || SEG_NORMAL (retval)); - return (retval); + return retval; } char /* Return terminator. */ @@ -4927,11 +5572,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--) { @@ -4954,8 +5599,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; @@ -4972,7 +5617,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 { @@ -5001,7 +5646,7 @@ void equals (char *sym_name, int reassign) { char *stop = NULL; - char stopc; + char stopc = 0; input_line_pointer++; if (*input_line_pointer == '=') @@ -5042,6 +5687,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) @@ -5077,7 +5726,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++) { @@ -5147,7 +5796,7 @@ s_include (int arg ATTRIBUTE_UNUSED) { char *filename; int i; - FILE *try; + FILE *try_file; char *path; if (!flag_m68k_mri) @@ -5174,22 +5823,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; } } @@ -5217,8 +5867,8 @@ add_include_dir (char *path) { include_dir_count++; include_dirs = - (char **) realloc (include_dirs, - include_dir_count * sizeof (*include_dirs)); + (char **) xrealloc (include_dirs, + include_dir_count * sizeof (*include_dirs)); } include_dirs[include_dir_count - 1] = path; /* New one. */ @@ -5310,22 +5960,27 @@ do_s_func (int end_p, const char *default_prefix) return; } - name = input_line_pointer; - delim1 = get_symbol_end (); + delim1 = get_symbol_name (& name); name = xstrdup (name); *input_line_pointer = delim1; - SKIP_WHITESPACE (); + SKIP_WHITESPACE_AFTER_NAME (); 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; } @@ -5334,10 +5989,9 @@ do_s_func (int end_p, const char *default_prefix) { ++input_line_pointer; SKIP_WHITESPACE (); - label = input_line_pointer; - delim2 = get_symbol_end (); + delim2 = get_symbol_name (& label); label = xstrdup (label); - *input_line_pointer = delim2; + restore_line_pointer (delim2); } if (debug_type == DEBUG_STABS) @@ -5350,6 +6004,80 @@ do_s_func (int end_p, const char *default_prefix) demand_empty_rest_of_line (); } +#ifdef HANDLE_BUNDLE + +void +s_bundle_align_mode (int arg ATTRIBUTE_UNUSED) +{ + unsigned int align = get_absolute_expression (); + SKIP_WHITESPACE (); + demand_empty_rest_of_line (); + + if (align > (unsigned int) TC_ALIGN_LIMIT) + as_fatal (_(".bundle_align_mode alignment too large (maximum %u)"), + (unsigned int) TC_ALIGN_LIMIT); + + if (bundle_lock_frag != NULL) + { + as_bad (_("cannot change .bundle_align_mode inside .bundle_lock")); + return; + } + + bundle_align_p2 = align; +} + +void +s_bundle_lock (int arg ATTRIBUTE_UNUSED) +{ + demand_empty_rest_of_line (); + + if (bundle_align_p2 == 0) + { + as_bad (_(".bundle_lock is meaningless without .bundle_align_mode")); + return; + } + + if (bundle_lock_depth == 0) + { + bundle_lock_frchain = frchain_now; + bundle_lock_frag = start_bundle (); + } + ++bundle_lock_depth; +} + +void +s_bundle_unlock (int arg ATTRIBUTE_UNUSED) +{ + unsigned int size; + + demand_empty_rest_of_line (); + + if (bundle_lock_frag == NULL) + { + as_bad (_(".bundle_unlock without preceding .bundle_lock")); + return; + } + + gas_assert (bundle_align_p2 > 0); + + gas_assert (bundle_lock_depth > 0); + if (--bundle_lock_depth > 0) + return; + + size = pending_bundle_size (bundle_lock_frag); + + if (size > (1U << bundle_align_p2)) + as_bad (_(".bundle_lock sequence is %u bytes, but bundle size only %u"), + size, 1 << bundle_align_p2); + else + finish_bundle (bundle_lock_frag, size); + + bundle_lock_frag = NULL; + bundle_lock_frchain = NULL; +} + +#endif /* HANDLE_BUNDLE */ + void s_ignore (int arg ATTRIBUTE_UNUSED) { @@ -5375,8 +6103,9 @@ void input_scrub_insert_line (const char *line) { sb newline; - sb_new (&newline); - sb_add_string (&newline, line); + size_t len = strlen (line); + sb_build (&newline, len); + sb_add_buffer (&newline, line, len); input_scrub_include_sb (&newline, input_line_pointer, 0); sb_kill (&newline); buffer_limit = input_scrub_next_buffer (&input_line_pointer); @@ -5399,7 +6128,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; @@ -5410,6 +6140,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 == '\'') @@ -5429,7 +6166,7 @@ _find_end_of_line (char *s, int mri_string, int insn ATTRIBUTE_UNUSED) } if (inquote) as_warn (_("missing closing `%c'"), inquote); - if (inescape) + if (inescape && !ignore_input ()) as_warn (_("stray `\\'")); return s; } @@ -5437,5 +6174,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); }