X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fread.c;h=a940ff3af9291669a63cca10249d2564988fe7ba;hb=8b8c7c9f49992750f66f81b4601d593a3858d98c;hp=4afb190173e31d66abc56c79047e1f510c00f37e;hpb=175c8f46774560217f90a19eb0d1d71a4c7ee510;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/read.c b/gas/read.c index 4afb190173..a940ff3af9 100644 --- a/gas/read.c +++ b/gas/read.c @@ -1,7 +1,5 @@ /* 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, 2008, 2009, - 2010 Free Software Foundation, Inc. + Copyright (C) 1986-2016 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -40,9 +38,10 @@ #include "obstack.h" #include "ecoff.h" #include "dw2gencfi.h" +#include "wchar.h" #ifndef TC_START_LABEL -#define TC_START_LABEL(x,y,z) (x == ':') +#define TC_START_LABEL(STR, NUL_CHAR, NEXT_CHAR) (NEXT_CHAR == ':') #endif /* Set by the object-format or the target. */ @@ -167,7 +166,7 @@ int target_big_endian = TARGET_BYTES_BIG_ENDIAN; /* Variables for handling include file directory table. */ /* Table of pointers to directories to search for .include's. */ -char **include_dirs; +const char **include_dirs; /* How many are in the table. */ int include_dir_count; @@ -209,19 +208,44 @@ 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); -#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_non_macro_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, int); @@ -238,8 +262,11 @@ 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++) + for (p = tc_line_separator_chars; *p; p++) is_end_of_line[(unsigned char) *p] = 2; /* Use more. FIXME-SOMEDAY. */ @@ -277,6 +304,11 @@ static const pseudo_typeS potable[] = { {"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}, @@ -343,9 +375,6 @@ 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}, @@ -457,6 +486,7 @@ static offsetT get_absolute_expr (expressionS *exp) { expression_and_evaluate (exp); + if (exp->X_op != O_constant) { if (exp->X_op != O_absent) @@ -521,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 \ @@ -545,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) @@ -584,12 +614,205 @@ 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. */ + if (bundle_align_p2 > OCTETS_PER_BYTE_POWER) + 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 */ + +static bfd_boolean +in_bss (void) +{ + flagword flags = bfd_get_section_flags (stdoutput, now_seg); + + return (flags & SEC_ALLOC) && !(flags & (SEC_LOAD | SEC_HAS_CONTENTS)); +} + +/* Guts of .align directive: + N is the power of two to which to align. A value of zero is accepted but + ignored: the default alignment of the section will be at least this. + FILL may be NULL, or it may point to the bytes of the fill pattern. + LEN is the length of whatever FILL points to, if anything. If LEN is zero + but FILL is not NULL then LEN is treated as if it were one. + MAX is the maximum number of characters to skip when doing the alignment, + or 0 if there is no maximum. */ + +void +do_align (unsigned int n, char *fill, unsigned int len, unsigned int max) +{ + if (now_seg == absolute_section || in_bss ()) + { + if (fill != NULL) + while (len-- > 0) + if (*fill++ != '\0') + { + if (now_seg == absolute_section) + as_warn (_("ignoring fill value in absolute section")); + else + as_warn (_("ignoring fill value in section `%s'"), + segment_name (now_seg)); + break; + } + fill = NULL; + len = 0; + } + +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + +#ifdef md_do_align + md_do_align (n, fill, len, max, just_record_alignment); +#endif + + /* Only make a frag if we HAVE to... */ + if ((n > OCTETS_PER_BYTE_POWER) && !need_pass_2) + { + if (fill == NULL) + { + if (subseg_text_p (now_seg)) + frag_align_code (n, max); + else + frag_align (n, 0, max); + } + else if (len <= 1) + frag_align (n, *fill, max); + else + frag_align_pattern (n, fill, len, max); + } + +#ifdef md_do_align + just_record_alignment: ATTRIBUTE_UNUSED_LABEL +#endif + + if (n > OCTETS_PER_BYTE_POWER) + record_alignment (now_seg, n - OCTETS_PER_BYTE_POWER); +} + /* We read the file, putting things into a web that represents what we have been reading. */ void -read_a_source_file (char *name) +read_a_source_file (const char *name) { - char c; + char nul_char; + char next_char; char *s; /* String of symbol, '\0' appended. */ int temp; pseudo_typeS *pop; @@ -629,6 +852,7 @@ read_a_source_file (char *name) 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 @@ -655,7 +879,7 @@ read_a_source_file (char *name) /* 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); + copy = XNEWVEC (char, len + macro_nest + 2); memset (copy, '>', macro_nest); copy[macro_nest] = ' '; memcpy (copy + macro_nest + 1, input_line_pointer, len); @@ -675,16 +899,18 @@ read_a_source_file (char *name) 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 *line_start; int mri_line_macro; - 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. */ @@ -718,8 +944,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); @@ -729,8 +954,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++; } } @@ -745,30 +970,32 @@ read_a_source_file (char *name) Each test is independent of all other tests at the (top) level. */ do - c = *input_line_pointer++; - while (c == '\t' || c == ' ' || c == '\f'); + nul_char = next_char = *input_line_pointer++; + while (next_char == '\t' || next_char == ' ' || next_char == '\f'); /* 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, s, 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; @@ -787,29 +1014,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 ((c == '=' && input_line_pointer[1] == '=') - || ((c == ' ' || c == '\t') - && input_line_pointer[1] == '=' - && 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 (); @@ -847,7 +1074,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 '.'. */ @@ -892,25 +1119,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. @@ -924,16 +1151,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; + /* 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); - c = *input_line_pointer; + 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) @@ -947,9 +1174,14 @@ read_a_source_file (char *name) } } - md_assemble (s); /* Assemble 1 instruction. */ + assemble_one (s); /* Assemble 1 instruction. */ - *input_line_pointer++ = c; + /* PR 19630: The backend may have set ilp to NULL + if it encountered a catastrophic failure. */ + if (input_line_pointer == NULL) + as_fatal (_("unable to continue with assembly.")); + + *input_line_pointer++ = nul_char; /* We resume loop AFTER the end-of-line from this instruction. */ @@ -959,17 +1191,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)) @@ -1003,9 +1238,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; @@ -1024,7 +1259,6 @@ read_a_source_file (char *name) bump_line_counters (); s += 4; - sb_new (&sbuf); ends = strstr (s, "#NO_APP\n"); if (!ends) @@ -1037,7 +1271,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 = (char *) xmalloc (tmp_len + 1); + tmp_buf = XNEWVEC (char, tmp_len + 1); memcpy (tmp_buf, s, tmp_len); do { @@ -1053,7 +1287,7 @@ read_a_source_file (char *name) else num = buffer_limit - buffer; - tmp_buf = (char *) xrealloc (tmp_buf, tmp_len + num); + tmp_buf = XRESIZEVEC (char, tmp_buf, tmp_len + num); memcpy (tmp_buf + tmp_len, buffer, num); tmp_len += num; } @@ -1074,12 +1308,12 @@ read_a_source_file (char *name) scrub_string_end = ends; new_length = ends - s; - new_buf = (char *) xmalloc (new_length); + new_buf = XNEWVEC (char, new_length); 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); @@ -1090,7 +1324,7 @@ read_a_source_file (char *name) break; } - new_buf = (char *) xrealloc (new_buf, new_length + 100); + new_buf = XRESIZEVEC (char, new_buf, new_length + 100); new_tmp = new_buf + new_length; new_length += 100; } @@ -1105,7 +1339,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); @@ -1113,23 +1349,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 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 (); @@ -1146,10 +1390,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; @@ -1162,8 +1406,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; } @@ -1224,58 +1468,6 @@ s_abort (int ignore ATTRIBUTE_UNUSED) as_fatal (_(".abort detected. Abandoning ship.")); } -/* Guts of .align directive. N is the power of two to which to align. - FILL may be NULL, or it may point to the bytes of the fill pattern. - LEN is the length of whatever FILL points to, if anything. MAX is - the maximum number of characters to skip when doing the alignment, - or 0 if there is no maximum. */ - -static void -do_align (int n, char *fill, int len, int max) -{ - if (now_seg == absolute_section) - { - if (fill != NULL) - while (len-- > 0) - if (*fill++ != '\0') - { - as_warn (_("ignoring fill value in absolute section")); - break; - } - fill = NULL; - len = 0; - } - -#ifdef md_flush_pending_output - md_flush_pending_output (); -#endif -#ifdef md_do_align - md_do_align (n, fill, len, max, just_record_alignment); -#endif - - /* Only make a frag if we HAVE to... */ - if (n != 0 && !need_pass_2) - { - if (fill == NULL) - { - if (subseg_text_p (now_seg)) - frag_align_code (n, max); - else - frag_align (n, 0, max); - } - else if (len <= 1) - frag_align (n, *fill, max); - else - frag_align_pattern (n, fill, len, max); - } - -#ifdef md_do_align - just_record_alignment: ATTRIBUTE_UNUSED_LABEL -#endif - - record_alignment (now_seg, n - OCTETS_PER_BYTE_POWER); -} - /* Handle the .align pseudo-op. A positive ARG is a default alignment (in bytes). A negative ARG is the negative of the length of the fill pattern. BYTES_P is non-zero if the alignment value should be @@ -1285,14 +1477,14 @@ do_align (int n, char *fill, int len, int max) #endif static void -s_align (int arg, int bytes_p) +s_align (signed int arg, int bytes_p) { unsigned int align_limit = TC_ALIGN_LIMIT; unsigned int align; char *stop = NULL; char stopc = 0; offsetT fill = 0; - int max; + unsigned int max; int fill_p; if (flag_mri) @@ -1309,6 +1501,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) @@ -1367,15 +1564,16 @@ s_align (int arg, int bytes_p) } else { - int fill_len; + unsigned int fill_len; if (arg >= 0) fill_len = 1; else fill_len = -arg; + if (fill_len <= 1) { - char fill_char; + char fill_char = 0; fill_char = fill; do_align (align, &fill_char, fill_len, max); @@ -1385,7 +1583,12 @@ s_align (int arg, int bytes_p) char ab[16]; if ((size_t) fill_len > sizeof ab) - abort (); + { + as_warn (_("fill pattern too long, truncating to %u"), + (unsigned) sizeof ab); + fill_len = sizeof ab; + } + md_number_to_chars (ab, fill, fill_len); do_align (align, ab, fill_len, max); } @@ -1417,20 +1620,113 @@ 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 = XNEWVEC (char, 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 = XRESIZEVEC (char, 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 = XNEWVEC (char, 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; @@ -1440,20 +1736,8 @@ s_comm_internal (int param, 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. */ @@ -1462,7 +1746,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")); @@ -1476,7 +1760,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)) @@ -1485,7 +1768,6 @@ s_comm_internal (int param, { symbolP = NULL; as_bad (_("symbol `%s' is already defined"), name); - *p = c; ignore_rest_of_line (); goto out; } @@ -1503,7 +1785,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 @@ -1511,19 +1792,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; } @@ -1560,7 +1836,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 @@ -1574,16 +1850,15 @@ s_mri_common (int small ATTRIBUTE_UNUSED) if (line_label != NULL) { - alc = (char *) xmalloc (strlen (S_GET_NAME (line_label)) - + (input_line_pointer - name) - + 1); + alc = XNEWVEC (char, strlen (S_GET_NAME (line_label)) + + (input_line_pointer - name) + 1); sprintf (alc, "%s%s", name, S_GET_NAME (line_label)); name = alc; } } sym = symbol_find_or_make (name); - *input_line_pointer = c; + c = restore_line_pointer (c); if (alc != NULL) free (alc); @@ -1610,6 +1885,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) @@ -1654,9 +1931,6 @@ s_data (int ignore ATTRIBUTE_UNUSED) subseg_set (section, (subsegT) temp); -#ifdef OBJ_VMS - const_flag = 0; -#endif demand_empty_rest_of_line (); } @@ -1745,7 +2019,7 @@ s_app_line (int appline) 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 @@ -1774,7 +2048,7 @@ s_app_line (int appline) /* From GCC's cpp documentation: 1: start of a new file. 2: returning to a file after having included - another file. + another file. 3: following text comes from a system header file. 4: following text should be treated as extern "C". @@ -1862,7 +2136,7 @@ s_errwarn (int err) self-contained message, one that can be passed like the demand_copy_C_string return value, and with no assumption on the location of the name of the directive within the message. */ - char *msg + const char *msg = (err ? _(".error directive invoked in source file") : _(".warning directive invoked in source file")); @@ -1961,6 +2235,20 @@ s_fill (int ignore ATTRIBUTE_UNUSED) if (size && !need_pass_2) { + if (now_seg == absolute_section) + { + if (rep_exp.X_op != O_constant) + as_bad (_("non-constant fill count for absolute section")); + else if (fill && rep_exp.X_add_number != 0) + as_bad (_("attempt to fill absolute section with non-zero value")); + abs_section_offset += rep_exp.X_add_number * size; + } + else if (fill + && (rep_exp.X_op != O_constant || rep_exp.X_add_number != 0) + && in_bss ()) + as_bad (_("attempt to fill section `%s' with non-zero value"), + segment_name (now_seg)); + if (rep_exp.X_op == O_constant) { p = frag_var (rs_fill, (int) size, (int) size, @@ -2028,12 +2316,12 @@ s_globl (int ignore ATTRIBUTE_UNUSED) 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 == ',') @@ -2043,6 +2331,8 @@ s_globl (int ignore ATTRIBUTE_UNUSED) if (is_end_of_line[(unsigned char) *input_line_pointer]) c = '\n'; } + + free (name); } while (c == ','); @@ -2052,154 +2342,22 @@ s_globl (int ignore ATTRIBUTE_UNUSED) mri_comment_end (stop, stopc); } -#ifdef OBJ_ELF -#define skip_whitespace(str) do { if (*(str) == ' ') ++(str); } while (0) - -static inline int -skip_past_char (char ** str, char c) -{ - if (**str == c) - { - (*str)++; - return 0; - } - else - return -1; -} -#define skip_past_comma(str) skip_past_char (str, ',') - -/* Parse an attribute directive for VENDOR. - Returns the attribute number read, or zero on error. */ -int -s_vendor_attribute (int vendor) -{ - expressionS exp; - int type; - int tag; - unsigned int i = 0; - char *s = NULL; - - /* Read the first number or name. */ - skip_whitespace (input_line_pointer); - s = input_line_pointer; - if (ISDIGIT (*input_line_pointer)) - { - expression (& exp); - if (exp.X_op != O_constant) - goto bad; - tag = exp.X_add_number; - } - else - { - char *name; - - /* A name may contain '_', but no other punctuation. */ - for (; ISALNUM (*input_line_pointer) || *input_line_pointer == '_'; - ++input_line_pointer) - i++; - if (i == 0) - goto bad; - - name = (char *) alloca (i + 1); - memcpy (name, s, i); - name[i] = '\0'; - -#ifndef CONVERT_SYMBOLIC_ATTRIBUTE -#define CONVERT_SYMBOLIC_ATTRIBUTE(a) -1 -#endif - - tag = CONVERT_SYMBOLIC_ATTRIBUTE (name); - if (tag == -1) - { - as_bad (_("Attribute name not recognised: %s"), name); - ignore_rest_of_line (); - return 0; - } - } - - type = _bfd_elf_obj_attrs_arg_type (stdoutput, vendor, tag); - - if (skip_past_comma (&input_line_pointer) == -1) - goto bad; - if (type & 1) - { - expression (& exp); - if (exp.X_op != O_constant) - { - as_bad (_("expected numeric constant")); - ignore_rest_of_line (); - return 0; - } - i = exp.X_add_number; - } - if ((type & 3) == 3 - && skip_past_comma (&input_line_pointer) == -1) - { - as_bad (_("expected comma")); - ignore_rest_of_line (); - return 0; - } - if (type & 2) - { - int len; - - skip_whitespace (input_line_pointer); - if (*input_line_pointer != '"') - goto bad_string; - s = demand_copy_C_string (&len); - } - - switch (type & 3) - { - case 3: - bfd_elf_add_obj_attr_int_string (stdoutput, vendor, tag, i, s); - break; - case 2: - bfd_elf_add_obj_attr_string (stdoutput, vendor, tag, s); - break; - case 1: - bfd_elf_add_obj_attr_int (stdoutput, vendor, tag, i); - break; - default: - abort (); - } - - demand_empty_rest_of_line (); - return tag; -bad_string: - as_bad (_("bad string constant")); - ignore_rest_of_line (); - return 0; -bad: - as_bad (_("expected , ")); - ignore_rest_of_line (); - return 0; -} - -/* Parse a .gnu_attribute directive. */ - -static void -s_gnu_attribute (int ignored ATTRIBUTE_UNUSED) -{ - s_vendor_attribute (OBJ_ATTR_GNU); -} -#endif /* OBJ_ELF */ - /* Handle the MRI IRP and IRPC pseudo-ops. */ void s_irp (int irpc) { - char *file, *eol; + char * eol; + const char * file; unsigned int line; sb s; const char *err; sb out; - as_where (&file, &line); + file = as_where (&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; @@ -2235,8 +2393,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) @@ -2248,7 +2405,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 @@ -2289,7 +2446,7 @@ s_linkonce (int ignore ATTRIBUTE_UNUSED) } void -bss_alloc (symbolS *symbolP, addressT size, int align) +bss_alloc (symbolS *symbolP, addressT size, unsigned int align) { char *pfrag; segT current_seg = now_seg; @@ -2313,7 +2470,7 @@ bss_alloc (symbolS *symbolP, addressT size, int align) #endif subseg_set (bss_seg, 1); - if (align) + if (align > OCTETS_PER_BYTE_POWER) { record_alignment (bss_seg, align); frag_align (align, 0, 0); @@ -2429,33 +2586,17 @@ void s_lsym (int ignore ATTRIBUTE_UNUSED) { char *name; - char c; - char *p; expressionS exp; 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++; @@ -2465,11 +2606,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) @@ -2487,8 +2626,14 @@ 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 @@ -2521,13 +2666,13 @@ get_line_sb (sb *line, int in_macro) return *input_line_pointer++; } -static int +static size_t get_non_macro_line_sb (sb *line) { return get_line_sb (line, 0); } -static int +static size_t get_macro_line_sb (sb *line) { return get_line_sb (line, 1); @@ -2538,25 +2683,29 @@ get_macro_line_sb (sb *line) void s_macro (int ignore ATTRIBUTE_UNUSED) { - char *file, *eol; + char *eol; + const char * file; unsigned int line; sb s; const char *err; const char *name; - as_where (&file, &line); + file = as_where (&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)); + 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); } @@ -2650,7 +2799,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) @@ -2670,6 +2821,10 @@ do_org (segT segment, expressionS *exp, int fill) symbolS *sym = exp->X_add_symbol; offsetT off = exp->X_add_number * OCTETS_PER_BYTE; + if (fill && in_bss ()) + as_warn (_("ignoring fill value in section `%s'"), + segment_name (now_seg)); + if (exp->X_op != O_constant && exp->X_op != O_symbol) { /* Handle complex expressions. */ @@ -2749,7 +2904,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 @@ -2764,13 +2919,13 @@ 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; + unsigned int align; ++input_line_pointer; align = get_absolute_expression (); @@ -2823,16 +2978,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 { @@ -2840,8 +2994,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) @@ -2852,7 +3005,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 == ',') @@ -2861,8 +3014,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")); @@ -2872,16 +3024,16 @@ s_mri_sect (char *type ATTRIBUTE_UNUSED) } else if (strcasecmp (seccmd, "align") == 0) { - int align; + unsigned 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); } } @@ -2927,11 +3079,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++ == ','); @@ -2944,7 +3095,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 (); @@ -2978,7 +3129,7 @@ do_repeat (int count, const char *start, const char *end) return; } - sb_new (&many); + sb_build (&many, count * one.len); while (count-- > 0) sb_add_sb (&many, &one); @@ -3018,7 +3169,7 @@ do_repeat_with_expander (int count, char * sub; sb processed; - sb_new (& processed); + sb_build (& processed, one.len); sb_add_sb (& processed, & one); sub = strstr (processed.ptr, expander); len = sprintf (sub, "%d", count); @@ -3086,13 +3237,13 @@ assign_symbol (char *name, int mode) if (listing & LISTING_SYMBOLS) { extern struct list_info_struct *listing_tail; - fragS *dummy_frag = (fragS *) xcalloc (1, sizeof (fragS)); + fragS *dummy_frag = XCNEW (fragS); dummy_frag->line = listing_tail; dummy_frag->fr_symbol = symbolP; 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 @@ -3100,12 +3251,13 @@ 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); + ignore_rest_of_line (); + input_line_pointer--; + return; } /* If the symbol is volatile, copy the symbol and replace the original with the copy, so that previous uses of the symbol will @@ -3131,42 +3283,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 @@ -3246,10 +3381,11 @@ s_space (int mult) val.X_add_number = 0; } - if (val.X_op != O_constant - || val.X_add_number < - 0x80 - || val.X_add_number > 0xff - || (mult != 0 && mult != 1 && val.X_add_number != 0)) + if ((val.X_op != O_constant + || val.X_add_number < - 0x80 + || val.X_add_number > 0xff + || (mult != 0 && mult != 1 && val.X_add_number != 0)) + && (now_seg != absolute_section && !in_bss ())) { resolve_expression (&exp); if (exp.X_op != O_constant) @@ -3290,6 +3426,8 @@ s_space (int mult) /* If we are in the absolute section, just bump the offset. */ if (now_seg == absolute_section) { + if (val.X_op != O_constant || val.X_add_number != 0) + as_warn (_("ignoring fill value in absolute section")); abs_section_offset += repeat; goto getout; } @@ -3327,7 +3465,10 @@ s_space (int mult) make_expr_symbol (&exp), (offsetT) 0, (char *) 0); } - if (p) + if ((val.X_op != O_constant || val.X_add_number != 0) && in_bss ()) + as_warn (_("ignoring fill value in section `%s'"), + segment_name (now_seg)); + else if (p) *p = val.X_add_number; } @@ -3402,7 +3543,7 @@ s_float_space (int float_type) } else { - char *err; + const char *err; err = md_atof (float_type, temp, &flen); know (flen <= MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT); @@ -3462,9 +3603,6 @@ s_text (int ignore ATTRIBUTE_UNUSED) 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 @@ -3473,23 +3611,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); @@ -3498,41 +3625,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) @@ -3563,6 +3676,7 @@ s_weakref (int ignore ATTRIBUTE_UNUSED) while (symp != symbolP) { char *old_loop = loop; + symp = symbol_get_value_expression (symp)->X_add_symbol; loop = concat (loop, " => ", S_GET_NAME (symp), (const char *) NULL); @@ -3573,8 +3687,7 @@ s_weakref (int ignore ATTRIBUTE_UNUSED) S_GET_NAME (symbolP), loop); free (loop); - - *end_name = delim; + free (name); ignore_rest_of_line (); return; } @@ -3585,8 +3698,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; @@ -3597,6 +3708,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; } @@ -3619,7 +3737,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]]); } @@ -3797,19 +3915,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 @@ -3817,7 +3938,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); } @@ -3860,12 +3981,30 @@ cons_worker (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) { @@ -3874,7 +4013,10 @@ cons_worker (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++ == ','); @@ -3907,7 +4049,7 @@ s_rva (int size) /* .reloc offset, reloc_name, symbol+addend. */ -void +static void s_reloc (int ignore ATTRIBUTE_UNUSED) { char *stop = NULL; @@ -3916,8 +4058,17 @@ s_reloc (int ignore ATTRIBUTE_UNUSED) char *r_name; int c; struct reloc_list *reloc; + struct _bfd_rel { const 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)); + reloc = XNEW (struct reloc_list); if (flag_mri) stop = mri_comment_field (&stopc); @@ -3956,9 +4107,21 @@ s_reloc (int ignore ATTRIBUTE_UNUSED) ++input_line_pointer; SKIP_WHITESPACE (); - r_name = input_line_pointer; - c = get_symbol_end (); - reloc->u.a.howto = bfd_reloc_name_lookup (stdoutput, r_name); + 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) { @@ -3967,7 +4130,7 @@ s_reloc (int ignore ATTRIBUTE_UNUSED) } exp.X_op = O_absent; - SKIP_WHITESPACE (); + SKIP_WHITESPACE_AFTER_NAME (); if (*input_line_pointer == ',') { ++input_line_pointer; @@ -4003,7 +4166,7 @@ s_reloc (int ignore ATTRIBUTE_UNUSED) break; } - as_where (&reloc->file, &reloc->line); + reloc->file = as_where (&reloc->line); reloc->next = reloc_list; reloc_list = reloc; @@ -4017,6 +4180,14 @@ s_reloc (int ignore ATTRIBUTE_UNUSED) 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; char *p; @@ -4026,10 +4197,9 @@ emit_expr (expressionS *exp, unsigned int nbytes) if (need_pass_2) return; - /* Grow the current frag now so that dot_value does not get invalidated - if the frag were to fill up in the frag_more() call below. */ frag_grow (nbytes); dot_value = frag_now_fix (); + dot_frag = frag_now; #ifndef NO_LISTING #ifdef OBJ_ELF @@ -4100,15 +4270,6 @@ emit_expr (expressionS *exp, unsigned int nbytes) op = exp->X_op; - /* Allow `.word 0' in the absolute section. */ - if (now_seg == absolute_section) - { - if (op != O_constant || exp->X_add_number != 0) - as_bad (_("attempt to store value in absolute section")); - abs_section_offset += nbytes; - return; - } - /* Handle a negative bignum. */ if (op == O_uminus && exp->X_add_number == 0 @@ -4158,8 +4319,28 @@ emit_expr (expressionS *exp, unsigned int nbytes) op = O_constant; } + /* Allow `.word 0' in the absolute section. */ + if (now_seg == absolute_section) + { + if (op != O_constant || exp->X_add_number != 0) + as_bad (_("attempt to store value in absolute section")); + abs_section_offset += nbytes; + return; + } + + /* Allow `.word 0' in BSS style sections. */ + if ((op != O_constant || exp->X_add_number != 0) && in_bss ()) + as_bad (_("attempt to store non-zero value in section `%s'"), + segment_name (now_seg)); + 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. */ @@ -4167,7 +4348,7 @@ emit_expr (expressionS *exp, unsigned int nbytes) { struct broken_word *x; - x = (struct broken_word *) xmalloc (sizeof (struct broken_word)); + x = XNEW (struct broken_word); x->next_broken_word = broken_words; broken_words = x; x->seg = now_seg; @@ -4190,7 +4371,7 @@ 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; } @@ -4231,7 +4412,8 @@ emit_expr (expressionS *exp, unsigned int nbytes) if ((get & mask) != 0 && ((get & mask) != mask || (get & hibit) == 0)) - { /* Leading bits contain both 0s & 1s. */ + { + /* 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"), @@ -4253,15 +4435,50 @@ 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; + } + else if (nbytes == 1) + { + /* We have nbytes == 1 and CHARS_PER_LITTLENUM == 2 (probably). + Check that bits 8.. of generic_bignum[0] match bit 7 + and that they match all of generic_bignum[1..exp->X_add_number]. */ + LITTLENUM_TYPE sign = (generic_bignum[0] & (1 << 7)) ? -1 : 0; + LITTLENUM_TYPE himask = LITTLENUM_MASK & ~ 0xFF; + + if ((generic_bignum[0] & himask) == (sign & himask)) + { + 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) @@ -4301,23 +4518,41 @@ emit_expr (expressionS *exp, unsigned int nbytes) } } else - emit_expr_fix (exp, nbytes, frag_now, p); + emit_expr_fix (exp, nbytes, frag_now, p, TC_PARSE_CONS_RETURN_NONE); } void -emit_expr_fix (expressionS *exp, unsigned int nbytes, fragS *frag, char *p) +emit_expr_fix (expressionS *exp, unsigned int nbytes, fragS *frag, char *p, + TC_PARSE_CONS_RETURN_TYPE r ATTRIBUTE_UNUSED) { - memset (p, 0, nbytes); + 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, p - frag->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; + + reloc_howto = bfd_reloc_type_lookup (stdoutput, r); + size = bfd_get_reloc_size (reloc_howto); - switch (nbytes) + 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; @@ -4335,13 +4570,11 @@ emit_expr_fix (expressionS *exp, unsigned int nbytes, fragS *frag, char *p) r = BFD_RELOC_64; break; default: - as_bad (_("unsupported BFD relocation size %u"), nbytes); - r = BFD_RELOC_32; - break; + as_bad (_("unsupported BFD relocation size %u"), size); + return; } - fix_new_exp (frag, p - frag->fr_literal, (int) nbytes, exp, - 0, r); - } + fix_new_exp (frag, p - frag->fr_literal + offset, size, + exp, 0, r); #endif } @@ -4362,9 +4595,7 @@ emit_expr_fix (expressionS *exp, unsigned int nbytes, fragS *frag, char *p) BITFIELD_CONS_EXPRESSIONS. */ static void -parse_bitfield_cons (exp, nbytes) - expressionS *exp; - unsigned int nbytes; +parse_bitfield_cons (expressionS *exp, unsigned int nbytes) { unsigned int bits_available = BITS_PER_CHAR * nbytes; char *hold = input_line_pointer; @@ -4450,7 +4681,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 @@ -4467,6 +4698,7 @@ parse_bitfield_cons (exp, nbytes) exp->X_add_number = value; exp->X_op = O_constant; exp->X_unsigned = 1; + exp->X_extrabit = 0; } } @@ -4476,15 +4708,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; @@ -4550,9 +4780,7 @@ parse_mri_cons (exp, nbytes) To use this for a target, define REPEAT_CONS_EXPRESSIONS. */ static void -parse_repeat_cons (exp, nbytes) - expressionS *exp; - unsigned int nbytes; +parse_repeat_cons (expressionS *exp, unsigned int nbytes) { expressionS count; int i; @@ -4694,7 +4922,7 @@ float_cons (/* Clobbers input_line-pointer, checks end-of-line. */ { char *p; int length; /* Number of chars in an object. */ - char *err; /* Error from scanning floating literal. */ + const char *err; /* Error from scanning floating literal. */ char temp[MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT]; if (is_it_end_of_statement ()) @@ -4703,6 +4931,21 @@ float_cons (/* Clobbers input_line-pointer, checks end-of-line. */ return; } + if (now_seg == absolute_section) + { + as_bad (_("attempt to store float in absolute section")); + ignore_rest_of_line (); + return; + } + + if (in_bss ()) + { + as_bad (_("attempt to store float in section `%s'"), + segment_name (now_seg)); + ignore_rest_of_line (); + return; + } + #ifdef md_flush_pending_output md_flush_pending_output (); #endif @@ -4786,9 +5029,25 @@ float_cons (/* Clobbers input_line-pointer, checks end-of-line. */ demand_empty_rest_of_line (); } -/* Return the size of a LEB128 value. */ +/* LEB128 Encoding. -static inline int + Note - we are using the DWARF standard's definition of LEB128 encoding + where each 7-bit value is a stored in a byte, *not* an octet. This + means that on targets where a byte contains multiple octets there is + a *huge waste of space*. (This also means that we do not have to + have special versions of these functions for when OCTETS_PER_BYTE_POWER + is non-zero). + + If the 7-bit values were to be packed into N-bit bytes (where N > 8) + we would then have to consider whether multiple, successive LEB128 + values should be packed into the bytes without padding (bad idea) or + whether each LEB128 number is padded out to a whole number of bytes. + Plus you have to decide on the endianness of packing octets into a + byte. */ + +/* Return the size of a LEB128 value in bytes. */ + +static inline unsigned int sizeof_sleb128 (offsetT value) { int size = 0; @@ -4809,7 +5068,7 @@ sizeof_sleb128 (offsetT value) return size; } -static inline int +static inline unsigned int sizeof_uleb128 (valueT value) { int size = 0; @@ -4824,7 +5083,7 @@ sizeof_uleb128 (valueT value) return size; } -int +unsigned int sizeof_leb128 (valueT value, int sign) { if (sign) @@ -4833,9 +5092,9 @@ sizeof_leb128 (valueT value, int sign) return sizeof_uleb128 (value); } -/* Output a LEB128 value. */ +/* Output a LEB128 value. Returns the number of bytes used. */ -static inline int +static inline unsigned int output_sleb128 (char *p, offsetT value) { char *orig = p; @@ -4862,7 +5121,7 @@ output_sleb128 (char *p, offsetT value) return p - orig; } -static inline int +static inline unsigned int output_uleb128 (char *p, valueT value) { char *orig = p; @@ -4870,6 +5129,7 @@ output_uleb128 (char *p, valueT value) do { unsigned byte = (value & 0x7f); + value >>= 7; if (value != 0) /* More bytes to follow. */ @@ -4882,7 +5142,7 @@ output_uleb128 (char *p, valueT value) return p - orig; } -int +unsigned int output_leb128 (char *p, valueT value, int sign) { if (sign) @@ -4893,10 +5153,11 @@ output_leb128 (char *p, valueT value, int sign) /* Do the same for bignums. We combine sizeof with output here in that we don't output for NULL values of P. It isn't really as critical as - for "normal" values that this be streamlined. */ + for "normal" values that this be streamlined. Returns the number of + bytes used. */ -static inline int -output_big_sleb128 (char *p, LITTLENUM_TYPE *bignum, int size) +static inline unsigned int +output_big_sleb128 (char *p, LITTLENUM_TYPE *bignum, unsigned int size) { char *orig = p; valueT val = 0; @@ -4941,7 +5202,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++; @@ -4950,8 +5211,8 @@ output_big_sleb128 (char *p, LITTLENUM_TYPE *bignum, int size) return p - orig; } -static inline int -output_big_uleb128 (char *p, LITTLENUM_TYPE *bignum, int size) +static inline unsigned int +output_big_uleb128 (char *p, LITTLENUM_TYPE *bignum, unsigned int size) { char *orig = p; valueT val = 0; @@ -4989,8 +5250,8 @@ output_big_uleb128 (char *p, LITTLENUM_TYPE *bignum, int size) return p - orig; } -static int -output_big_leb128 (char *p, LITTLENUM_TYPE *bignum, int size, int sign) +static unsigned int +output_big_leb128 (char *p, LITTLENUM_TYPE *bignum, unsigned int size, int sign) { if (sign) return output_big_sleb128 (p, bignum, size); @@ -4999,7 +5260,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) @@ -5026,15 +5287,27 @@ 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; } + if (now_seg == absolute_section) + { + if (op != O_constant || exp->X_add_number != 0) + as_bad (_("attempt to store value in absolute section")); + abs_section_offset++; + return; + } + + if ((op != O_constant || exp->X_add_number != 0) && in_bss ()) + as_bad (_("attempt to store non-zero value in section `%s'"), + segment_name (now_seg)); + /* Let check_eh_frame know that data is being emitted. nbytes == -1 is a signal that this is leb128 data. It shouldn't optimize this away. */ nbytes = (unsigned int) -1; @@ -5051,23 +5324,25 @@ emit_leb128_expr (expressionS *exp, int sign) /* If we've got a constant, emit the thing directly right now. */ valueT value = exp->X_add_number; - int size; + unsigned int size; char *p; size = sizeof_leb128 (value, sign); p = frag_more (size); - output_leb128 (p, value, sign); + if (output_leb128 (p, value, sign) > size) + abort (); } else if (op == O_big) { /* O_big is a different sort of constant. */ - int size; + unsigned int size; char *p; size = output_big_leb128 (NULL, generic_bignum, exp->X_add_number, sign); p = frag_more (size); - output_big_leb128 (p, generic_bignum, exp->X_add_number, sign); + if (output_big_leb128 (p, generic_bignum, exp->X_add_number, sign) > size) + abort (); } else { @@ -5104,6 +5379,10 @@ s_leb128 (int sign) static void stringer_append_char (int c, int bitsize) { + if (c && in_bss ()) + as_bad (_("attempt to store non-empty string in section `%s'"), + segment_name (now_seg)); + if (!target_big_endian) FRAG_APPEND_1_CHAR (c); @@ -5147,7 +5426,9 @@ stringer (int bits_appendzero) 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 (); @@ -5157,6 +5438,15 @@ stringer (int bits_appendzero) md_cons_align (1); #endif + /* If we have been switched into the abs_section then we + will not have an obstack onto which we can hang strings. */ + if (now_seg == absolute_section) + { + as_bad (_("strings must be placed into a section")); + ignore_rest_of_line (); + return; + } + /* 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 '\"'. @@ -5171,14 +5461,6 @@ stringer (int bits_appendzero) { c = ','; /* Do loop. */ } - /* If we have been switched into the abs_section then we - will not have an obstack onto which we can hang strings. */ - if (now_seg == absolute_section) - { - as_bad (_("strings must be placed into a section")); - c = 0; - ignore_rest_of_line (); - } while (c == ',' || c == '<' || c == '"') { @@ -5187,7 +5469,9 @@ stringer (int bits_appendzero) { 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 ())) stringer_append_char (c, bitsize); @@ -5197,8 +5481,7 @@ stringer (int bits_appendzero) 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 @@ -5214,7 +5497,6 @@ stringer (int bits_appendzero) listing_source_file (start); input_line_pointer[-1] = c; } -#endif #endif break; @@ -5262,7 +5544,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'; @@ -5313,7 +5595,7 @@ next_char_of_string (void) number = number * 8 + c - '0'; } - c = number & 0xff; + c = number & CHAR_MASK; } --input_line_pointer; break; @@ -5335,7 +5617,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; @@ -5386,9 +5668,9 @@ get_segmented_expression (expressionS *expP) static segT get_known_segmented_expression (expressionS *expP) { - 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. */ @@ -5402,8 +5684,7 @@ get_known_segmented_expression (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. */ @@ -5574,7 +5855,7 @@ s_incbin (int x ATTRIBUTE_UNUSED) { int i; - path = (char *) xmalloc ((unsigned long) len + include_dir_maxlen + 5); + path = XNEWVEC (char, (unsigned long) len + include_dir_maxlen + 5); for (i = 0; i < include_dir_count; i++) { @@ -5677,8 +5958,8 @@ s_include (int arg ATTRIBUTE_UNUSED) } demand_empty_rest_of_line (); - path = (char *) xmalloc ((unsigned long) i - + include_dir_maxlen + 5 /* slop */ ); + path = XNEWVEC (char, (unsigned long) i + + include_dir_maxlen + 5 /* slop */ ); for (i = 0; i < include_dir_count; i++) { @@ -5707,16 +5988,15 @@ add_include_dir (char *path) if (include_dir_count == 0) { - include_dirs = (char **) xmalloc (2 * sizeof (*include_dirs)); + include_dirs = XNEWVEC (const char *, 2); include_dirs[0] = "."; /* Current dir. */ include_dir_count = 2; } else { include_dir_count++; - include_dirs = - (char **) realloc (include_dirs, - include_dir_count * sizeof (*include_dirs)); + include_dirs = XRESIZEVEC (const char *, include_dirs, + include_dir_count); } include_dirs[include_dir_count - 1] = path; /* New one. */ @@ -5808,11 +6088,10 @@ 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) @@ -5838,10 +6117,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) @@ -5854,6 +6132,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) { @@ -5879,8 +6231,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); @@ -5941,7 +6294,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; }