X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=gas%2Fread.c;h=db1011b6392be85939c53842b9fbaacb27f86a72;hb=4504a6346777d544a144683bd2a534b686fbac41;hp=22da1df3061de11ae896792fc64ef4d0b6369a9b;hpb=cd0bbe6ef9ca3d3db38a3a0f1ca993bbdc952053;p=binutils-gdb.git diff --git a/gas/read.c b/gas/read.c index 22da1df3061..db1011b6392 100644 --- a/gas/read.c +++ b/gas/read.c @@ -1,5 +1,5 @@ /* read.c - read a source file - - Copyright (C) 1986-2016 Free Software Foundation, Inc. + Copyright (C) 1986-2021 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -19,7 +19,7 @@ 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. + But then, GNU isn't supposed to run on your machine anyway. (RMS is so shortsighted sometimes.) */ #define MASK_CHAR ((int)(unsigned char) -1) @@ -40,6 +40,8 @@ #include "dw2gencfi.h" #include "wchar.h" +#include + #ifndef TC_START_LABEL #define TC_START_LABEL(STR, NUL_CHAR, NEXT_CHAR) (NEXT_CHAR == ':') #endif @@ -62,6 +64,7 @@ #endif char *input_line_pointer; /*->next char of source file to parse. */ +bool input_from_string = false; #if BITS_PER_CHAR != 8 /* The following table is indexed by[(char)] and will break if @@ -166,7 +169,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; @@ -292,7 +295,53 @@ address_bytes (void) /* Set up pseudo-op tables. */ -static struct hash_control *po_hash; +struct po_entry +{ + const char *poc_name; + + const pseudo_typeS *pop; +}; + +typedef struct po_entry po_entry_t; + +/* Hash function for a po_entry. */ + +static hashval_t +hash_po_entry (const void *e) +{ + const po_entry_t *entry = (const po_entry_t *) e; + return htab_hash_string (entry->poc_name); +} + +/* Equality function for a po_entry. */ + +static int +eq_po_entry (const void *a, const void *b) +{ + const po_entry_t *ea = (const po_entry_t *) a; + const po_entry_t *eb = (const po_entry_t *) b; + + return strcmp (ea->poc_name, eb->poc_name) == 0; +} + +static po_entry_t * +po_entry_alloc (const char *poc_name, const pseudo_typeS *pop) +{ + po_entry_t *entry = XNEW (po_entry_t); + entry->poc_name = poc_name; + entry->pop = pop; + return entry; +} + +static const pseudo_typeS * +po_entry_find (htab_t table, const char *poc_name) +{ + po_entry_t needle = { poc_name, NULL }; + po_entry_t *entry = htab_find (table, &needle); + return entry != NULL ? entry->pop : NULL; +} + +static struct htab *po_hash; static const pseudo_typeS potable[] = { {"abort", s_abort, 0}, @@ -315,9 +364,7 @@ static const pseudo_typeS potable[] = { {"common.s", s_mri_common, 1}, {"data", s_data, 0}, {"dc", cons, 2}, -#ifdef TC_ADDRESS_BYTES {"dc.a", cons, 0}, -#endif {"dc.b", cons, 1}, {"dc.d", float_cons, 'd'}, {"dc.l", cons, 4}, @@ -416,6 +463,8 @@ static const pseudo_typeS potable[] = { {"noformat", s_ignore, 0}, {"nolist", listing_list, 0}, /* Turn listing off. */ {"nopage", listing_nopage, 0}, + {"nop", s_nop, 0}, + {"nops", s_nops, 0}, {"octa", cons, 16}, {"offset", s_struct, 0}, {"org", s_org, 0}, @@ -479,6 +528,9 @@ static const pseudo_typeS potable[] = { {"weakref", s_weakref, 0}, {"word", cons, 2}, {"zero", s_space, 0}, + {"2byte", cons, 2}, + {"4byte", cons, 4}, + {"8byte", cons, 8}, {NULL, NULL, 0} /* End sentinel. */ }; @@ -510,14 +562,17 @@ static const char *pop_table_name; void pop_insert (const pseudo_typeS *table) { - const char *errtxt; const pseudo_typeS *pop; for (pop = table; pop->poc_name; pop++) { - errtxt = hash_insert (po_hash, pop->poc_name, (char *) pop); - if (errtxt && (!pop_override_ok || strcmp (errtxt, "exists"))) - as_fatal (_("error constructing %s pseudo-op table: %s"), pop_table_name, - errtxt); + po_entry_t *elt = po_entry_alloc (pop->poc_name, pop); + if (htab_insert (po_hash, elt, 0) != NULL) + { + free (elt); + if (!pop_override_ok) + as_fatal (_("error constructing %s pseudo-op table"), + pop_table_name); + } } } @@ -536,7 +591,8 @@ pop_insert (const pseudo_typeS *table) static void pobegin (void) { - po_hash = hash_new (); + po_hash = htab_create_alloc (16, hash_po_entry, eq_po_entry, NULL, + xcalloc, xfree); /* Do the target-specific pseudo ops. */ pop_table_name = "md"; @@ -713,19 +769,19 @@ assemble_one (char *line) /* 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"), + 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); + if (insn_size > 1U << bundle_align_p2) + as_bad (_("single instruction is %u bytes long, " + "but .bundle_align_mode limit is %u bytes"), + insn_size, 1U << bundle_align_p2); finish_bundle (insn_start_frag, insn_size); } @@ -737,10 +793,10 @@ single instruction is %u bytes long but .bundle_align_mode limit is %u"), #endif /* HANDLE_BUNDLE */ -static bfd_boolean +static bool in_bss (void) { - flagword flags = bfd_get_section_flags (stdoutput, now_seg); + flagword flags = bfd_section_flags (now_seg); return (flags & SEC_ALLOC) && !(flags & (SEC_LOAD | SEC_HAS_CONTENTS)); } @@ -754,7 +810,7 @@ in_bss (void) MAX is the maximum number of characters to skip when doing the alignment, or 0 if there is no maximum. */ -static void +void do_align (unsigned int n, char *fill, unsigned int len, unsigned int max) { if (now_seg == absolute_section || in_bss ()) @@ -809,13 +865,13 @@ do_align (unsigned int n, char *fill, unsigned int len, unsigned int max) /* 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 nul_char; char next_char; char *s; /* String of symbol, '\0' appended. */ - int temp; - pseudo_typeS *pop; + long temp; + const pseudo_typeS *pop; #ifdef WARN_COMMENTS found_comment = 0; @@ -843,7 +899,7 @@ read_a_source_file (char *name) #endif while (input_line_pointer < buffer_limit) { - bfd_boolean was_new_line; + bool was_new_line; /* We have more of this buffer to parse. */ /* We now have input_line_pointer->1st char of next line. @@ -879,7 +935,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); @@ -951,8 +1007,7 @@ read_a_source_file (char *name) else line_label = symbol_create (line_start, absolute_section, - (valueT) 0, - &zero_address_frag); + &zero_address_frag, 0); next_char = restore_line_pointer (nul_char); if (next_char == ':') @@ -1050,7 +1105,8 @@ read_a_source_file (char *name) { char *s2 = s; - strncpy (original_case_string, s2, sizeof (original_case_string)); + strncpy (original_case_string, s2, + sizeof (original_case_string) - 1); original_case_string[sizeof (original_case_string) - 1] = 0; while (*s2) @@ -1064,7 +1120,7 @@ read_a_source_file (char *name) { /* The MRI assembler uses pseudo-ops without a period. */ - pop = (pseudo_typeS *) hash_find (po_hash, s); + pop = po_entry_find (po_hash, s); if (pop != NULL && pop->poc_handler == NULL) pop = NULL; } @@ -1079,7 +1135,7 @@ read_a_source_file (char *name) already know that the pseudo-op begins with a '.'. */ if (pop == NULL) - pop = (pseudo_typeS *) hash_find (po_hash, s + 1); + pop = po_entry_find (po_hash, s + 1); if (pop && !pop->poc_handler) pop = NULL; @@ -1176,6 +1232,11 @@ read_a_source_file (char *name) assemble_one (s); /* Assemble 1 instruction. */ + /* 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 @@ -1204,10 +1265,24 @@ read_a_source_file (char *name) /* Read the whole number. */ while (ISDIGIT (*input_line_pointer)) { - temp = (temp * 10) + *input_line_pointer - '0'; + const long digit = *input_line_pointer - '0'; + if (temp > (LONG_MAX - digit) / 10) + { + as_bad (_("local label too large near %s"), backup); + temp = -1; + break; + } + temp = temp * 10 + digit; ++input_line_pointer; } + /* Overflow: stop processing the label. */ + if (temp == -1) + { + ignore_rest_of_line (); + continue; + } + if (LOCAL_LABELS_DOLLAR && *input_line_pointer == '$' && *(input_line_pointer + 1) == ':') @@ -1216,7 +1291,7 @@ read_a_source_file (char *name) if (dollar_label_defined (temp)) { - as_fatal (_("label \"%d$\" redefined"), temp); + as_fatal (_("label \"%ld$\" redefined"), temp); } define_dollar_label (temp); @@ -1245,7 +1320,7 @@ read_a_source_file (char *name) char *tmp_buf = 0; s = input_line_pointer; - if (strncmp (s, "APP\n", 4)) + if (!startswith (s, "APP\n")) { /* We ignore it. */ ignore_rest_of_line (); @@ -1266,7 +1341,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 { @@ -1282,7 +1357,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; } @@ -1303,7 +1378,7 @@ 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 (;;) { @@ -1319,13 +1394,12 @@ 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; } - if (tmp_buf) - free (tmp_buf); + free (tmp_buf); /* We've "scrubbed" input to the preferred format. In the process we may have consumed the whole of the remaining @@ -1475,7 +1549,7 @@ static void s_align (signed int arg, int bytes_p) { unsigned int align_limit = TC_ALIGN_LIMIT; - unsigned int align; + addressT align; char *stop = NULL; char stopc = 0; offsetT fill = 0; @@ -1522,7 +1596,7 @@ s_align (signed int arg, int bytes_p) if (align > align_limit) { align = align_limit; - as_warn (_("alignment too large: %u assumed"), align); + as_warn (_("alignment too large: %u assumed"), align_limit); } if (*input_line_pointer != ',') @@ -1652,7 +1726,7 @@ read_symbol_name (void) char * name_end; unsigned int C; - start = name = xmalloc (len + 1); + start = name = XNEWVEC (char, len + 1); name_end = name + SYM_NAME_CHUNK_LEN; @@ -1664,7 +1738,7 @@ read_symbol_name (void) sofar = name - start; len += SYM_NAME_CHUNK_LEN; - start = xrealloc (start, len + 1); + start = XRESIZEVEC (char, start, len + 1); name_end = start + len; name = start + sofar; } @@ -1679,20 +1753,20 @@ read_symbol_name (void) 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') + else if (is_name_beginner (c) || (input_from_string && c == FAKE_LABEL_CHAR)) { ptrdiff_t len; name = input_line_pointer - 1; - /* We accept \001 in a name in case this is + /* We accept FAKE_LABEL_CHAR in a name in case this is being called with a constructed string. */ while (is_part_of_name (c = *input_line_pointer++) - || c == '\001') + || (input_from_string && c == FAKE_LABEL_CHAR)) ; len = (input_line_pointer - name) - 1; - start = xmalloc (len + 1); + start = XNEWVEC (char, len + 1); memcpy (start, name, len); start[len] = 0; @@ -1793,8 +1867,7 @@ s_comm_internal (int param, out: if (flag_mri) mri_comment_end (stop, stopc); - if (name != NULL) - free (name); + free (name); return symbolP; } @@ -1845,9 +1918,8 @@ 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; } @@ -1855,8 +1927,7 @@ s_mri_common (int small ATTRIBUTE_UNUSED) sym = symbol_find_or_make (name); c = restore_line_pointer (c); - if (alc != NULL) - free (alc); + free (alc); if (*input_line_pointer != ',') align = 0; @@ -2132,7 +2203,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")); @@ -2198,7 +2269,7 @@ s_fill (int ignore ATTRIBUTE_UNUSED) md_cons_align (1); #endif - get_known_segmented_expression (&rep_exp); + expression (&rep_exp); if (*input_line_pointer == ',') { input_line_pointer++; @@ -2343,13 +2414,14 @@ s_globl (int ignore ATTRIBUTE_UNUSED) 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); eol = find_end_of_line (input_line_pointer, 0); sb_build (&s, eol - input_line_pointer); @@ -2412,7 +2484,7 @@ s_linkonce (int ignore ATTRIBUTE_UNUSED) if ((bfd_applicable_section_flags (stdoutput) & SEC_LINK_ONCE) == 0) as_warn (_(".linkonce is not supported for this object file format")); - flags = bfd_get_section_flags (stdoutput, now_seg); + flags = bfd_section_flags (now_seg); flags |= SEC_LINK_ONCE; switch (type) { @@ -2431,7 +2503,7 @@ s_linkonce (int ignore ATTRIBUTE_UNUSED) flags |= SEC_LINK_DUPLICATES_SAME_CONTENTS; break; } - if (!bfd_set_section_flags (stdoutput, now_seg, flags)) + if (!bfd_set_section_flags (now_seg, flags)) as_bad (_("bfd_set_section_flags: %s"), bfd_errmsg (bfd_get_error ())); } @@ -2457,7 +2529,7 @@ bss_alloc (symbolS *symbolP, addressT size, unsigned int align) { bss_seg = subseg_new (".sbss", 1); seg_info (bss_seg)->bss = 1; - if (!bfd_set_section_flags (stdoutput, bss_seg, SEC_ALLOC)) + if (!bfd_set_section_flags (bss_seg, SEC_ALLOC | SEC_SMALL_DATA)) as_warn (_("error setting flags for \".sbss\": %s"), bfd_errmsg (bfd_get_error ())); } @@ -2476,7 +2548,7 @@ bss_alloc (symbolS *symbolP, addressT size, unsigned int align) symbol_get_frag (symbolP)->fr_symbol = NULL; symbol_set_frag (symbolP, frag_now); - pfrag = frag_var (rs_org, 1, 1, 0, symbolP, size, NULL); + pfrag = frag_var (rs_org, 1, 1, 0, symbolP, size * OCTETS_PER_BYTE, NULL); *pfrag = 0; #ifdef S_SET_SIZE @@ -2678,13 +2750,14 @@ 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); eol = find_end_of_line (input_line_pointer, 0); sb_build (&s, eol - input_line_pointer); @@ -2717,10 +2790,10 @@ s_macro (int ignore ATTRIBUTE_UNUSED) } if (((NO_PSEUDO_DOT || flag_m68k_mri) - && hash_find (po_hash, name) != NULL) + && po_entry_find (po_hash, name) != NULL) || (!flag_m68k_mri && *name == '.' - && hash_find (po_hash, name + 1) != NULL)) + && po_entry_find (po_hash, name + 1) != NULL)) as_warn_where (file, line, _("attempt to redefine pseudo-op `%s' ignored"), @@ -2949,9 +3022,9 @@ s_mri_sect (char *type ATTRIBUTE_UNUSED) flags = SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_READONLY | SEC_ROM; if (flags != SEC_NO_FLAGS) { - if (!bfd_set_section_flags (stdoutput, seg, flags)) + if (!bfd_set_section_flags (seg, flags)) as_warn (_("error setting flags for \"%s\": %s"), - bfd_section_name (stdoutput, seg), + bfd_section_name (seg), bfd_errmsg (bfd_get_error ())); } } @@ -2964,81 +3037,10 @@ s_mri_sect (char *type ATTRIBUTE_UNUSED) demand_empty_rest_of_line (); #else /* ! TC_M68K */ -#ifdef TC_I960 - - char *name; - char c; - segT seg; - - SKIP_WHITESPACE (); - - c = get_symbol_name (& name); - - name = xstrdup (name); - - c = restore_line_pointer (c); - - seg = subseg_new (name, 0); - - if (c != ',') - *type = 'C'; - else - { - char *sectype; - - ++input_line_pointer; - SKIP_WHITESPACE (); - c = get_symbol_name (& sectype); - if (*sectype == '\0') - *type = 'C'; - else if (strcasecmp (sectype, "text") == 0) - *type = 'C'; - else if (strcasecmp (sectype, "data") == 0) - *type = 'D'; - else if (strcasecmp (sectype, "romdata") == 0) - *type = 'R'; - else - as_warn (_("unrecognized section type `%s'"), sectype); - (void) restore_line_pointer (c); - } - - if (*input_line_pointer == ',') - { - char *seccmd; - - ++input_line_pointer; - SKIP_WHITESPACE (); - c = get_symbol_name (& seccmd); - if (strcasecmp (seccmd, "absolute") == 0) - { - as_bad (_("absolute sections are not supported")); - *input_line_pointer = c; - ignore_rest_of_line (); - return; - } - else if (strcasecmp (seccmd, "align") == 0) - { - unsigned int align; - - (void) restore_line_pointer (c); - align = get_absolute_expression (); - record_alignment (seg, align); - } - else - { - as_warn (_("unrecognized section command `%s'"), seccmd); - (void) restore_line_pointer (c); - } - } - - demand_empty_rest_of_line (); - -#else /* ! TC_I960 */ /* The MRI assembler seems to use different forms of .sect for different targets. */ as_bad ("MRI mode not supported for this target"); ignore_rest_of_line (); -#endif /* ! TC_I960 */ #endif /* ! TC_M68K */ } @@ -3100,9 +3102,9 @@ s_bad_end (int endr) void s_rept (int ignore ATTRIBUTE_UNUSED) { - int count; + size_t count; - count = get_absolute_expression (); + count = (size_t) get_absolute_expression (); do_repeat (count, "REPT", "ENDR"); } @@ -3111,11 +3113,17 @@ s_rept (int ignore ATTRIBUTE_UNUSED) different directives to be used as the start/end keys. */ void -do_repeat (int count, const char *start, const char *end) +do_repeat (size_t count, const char *start, const char *end) { sb one; sb many; + if (((ssize_t) count) < 0) + { + as_bad (_("negative count for %s - ignored"), start); + count = 0; + } + sb_new (&one); if (!buffer_and_nest (start, end, &one, get_non_macro_line_sb)) { @@ -3135,10 +3143,10 @@ do_repeat (int count, const char *start, const char *end) } /* Like do_repeat except that any text matching EXPANDER in the - block is replaced by the itteration count. */ + block is replaced by the iteration count. */ void -do_repeat_with_expander (int count, +do_repeat_with_expander (size_t count, const char * start, const char * end, const char * expander) @@ -3146,6 +3154,12 @@ do_repeat_with_expander (int count, sb one; sb many; + if (((ssize_t) count) < 0) + { + as_bad (_("negative count for %s - ignored"), start); + count = 0; + } + sb_new (&one); if (!buffer_and_nest (start, end, &one, get_non_macro_line_sb)) { @@ -3166,9 +3180,10 @@ do_repeat_with_expander (int count, sb_build (& processed, one.len); sb_add_sb (& processed, & one); sub = strstr (processed.ptr, expander); - len = sprintf (sub, "%d", count); + len = sprintf (sub, "%lu", (unsigned long) count); gas_assert (len < 8); - strcpy (sub + len, sub + 8); + memmove (sub + len, sub + 8, + processed.ptr + processed.len - (sub + 8)); processed.len -= (8 - len); sb_add_sb (& many, & processed); sb_kill (& processed); @@ -3231,7 +3246,7 @@ 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); @@ -3249,7 +3264,9 @@ assign_symbol (char *name, int mode) && !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 @@ -3386,11 +3403,20 @@ s_space (int mult) { offsetT i; - if (mult == 0) - mult = 1; - bytes = mult * exp.X_add_number; - for (i = 0; i < exp.X_add_number; i++) - emit_expr (&val, mult); + /* PR 20901: Check for excessive values. + FIXME: 1<<10 is an arbitrary limit. Maybe use maxpagesize instead ? */ + if (exp.X_add_number < 0 || exp.X_add_number > (1 << 10)) + as_bad (_("size value for space directive too large: %lx"), + (long) exp.X_add_number); + else + { + if (mult == 0) + mult = 1; + bytes = mult * exp.X_add_number; + + for (i = 0; i < exp.X_add_number; i++) + emit_expr (&val, mult); + } } } else @@ -3478,6 +3504,118 @@ s_space (int mult) mri_comment_end (stop, stopc); } +void +s_nop (int ignore ATTRIBUTE_UNUSED) +{ + expressionS exp; + fragS *start; + addressT start_off; + offsetT frag_off; + +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + +#ifdef md_cons_align + md_cons_align (1); +#endif + + SKIP_WHITESPACE (); + expression (&exp); + demand_empty_rest_of_line (); + + start = frag_now; + start_off = frag_now_fix (); + do + { +#ifdef md_emit_single_noop + md_emit_single_noop; +#else + char *nop; + +#ifndef md_single_noop_insn +#define md_single_noop_insn "nop" +#endif + /* md_assemble might modify its argument, so + we must pass it a string that is writable. */ + if (asprintf (&nop, "%s", md_single_noop_insn) < 0) + as_fatal ("%s", xstrerror (errno)); + + /* Some targets assume that they can update input_line_pointer + inside md_assemble, and, worse, that they can leave it + assigned to the string pointer that was provided as an + argument. So preserve ilp here. */ + char *saved_ilp = input_line_pointer; + md_assemble (nop); + input_line_pointer = saved_ilp; + free (nop); +#endif +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + } while (exp.X_op == O_constant + && exp.X_add_number > 0 + && frag_offset_ignore_align_p (start, frag_now, &frag_off) + && frag_off + frag_now_fix () < start_off + exp.X_add_number); +} + +void +s_nops (int ignore ATTRIBUTE_UNUSED) +{ + expressionS exp; + expressionS val; + +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + +#ifdef md_cons_align + md_cons_align (1); +#endif + + SKIP_WHITESPACE (); + expression (&exp); + /* Note - this expression is tested for an absolute value in + write.c:relax_segment(). */ + + SKIP_WHITESPACE (); + if (*input_line_pointer == ',') + { + ++input_line_pointer; + expression (&val); + } + else + { + val.X_op = O_constant; + val.X_add_number = 0; + } + + if (val.X_op != O_constant) + { + as_bad (_("unsupported variable nop control in .nops directive")); + val.X_op = O_constant; + val.X_add_number = 0; + } + else if (val.X_add_number < 0) + { + as_warn (_("negative nop control byte, ignored")); + val.X_add_number = 0; + } + + demand_empty_rest_of_line (); + + if (need_pass_2) + /* Ignore this directive if we are going to perform a second pass. */ + return; + + /* Store the no-op instruction control byte in the first byte of frag. */ + char *p; + symbolS *sym = make_expr_symbol (&exp); + p = frag_var (rs_space_nop, 1, 1, (relax_substateT) 0, + sym, (offsetT) 0, (char *) 0); + *p = val.X_add_number; +} + /* This is like s_space, but the value is a floating point number with the given precision. This is for the MRI dcb.s pseudo-op and friends. */ @@ -3535,7 +3673,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); @@ -3747,7 +3885,8 @@ ignore_rest_of_line (void) input_line_pointer++; /* Return pointing just after end-of-line. */ - know (is_end_of_line[(unsigned char) input_line_pointer[-1]]); + if (input_line_pointer <= buffer_limit) + know (is_end_of_line[(unsigned char) input_line_pointer[-1]]); } /* Sets frag for given symbol to zero_address_frag, except when the @@ -3853,7 +3992,7 @@ pseudo_set (symbolS *symbolP) symbolS *s = exp.X_add_symbol; if (S_IS_COMMON (s)) - as_bad (_("`%s' can't be equated to common symbol '%s'"), + as_bad (_("`%s' can't be equated to common symbol `%s'"), S_GET_NAME (symbolP), S_GET_NAME (s)); S_SET_SEGMENT (symbolP, seg); @@ -3895,7 +4034,6 @@ pseudo_set (symbolS *symbolP) /* Some targets need to parse the expression in various fancy ways. You can define TC_PARSE_CONS_EXPRESSION to do whatever you like (for example, the HPPA does this). Otherwise, you can define - BITFIELD_CONS_EXPRESSIONS to permit bitfields to be specified, or REPEAT_CONS_EXPRESSIONS to permit repeat counts. If none of these are defined, which is the normal case, then only simple expressions are permitted. */ @@ -3906,12 +4044,6 @@ parse_mri_cons (expressionS *exp, unsigned int nbytes); #endif #ifndef TC_PARSE_CONS_EXPRESSION -#ifdef BITFIELD_CONS_EXPRESSIONS -#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) \ - (parse_bitfield_cons (EXP, NBYTES), 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), TC_PARSE_CONS_RETURN_NONE) @@ -3961,10 +4093,8 @@ cons_worker (int nbytes, /* 1=.byte, 2=.word, 4=.long. */ return; } -#ifdef TC_ADDRESS_BYTES if (nbytes == 0) nbytes = TC_ADDRESS_BYTES (); -#endif #ifdef md_cons_align md_cons_align (nbytes); @@ -4060,7 +4190,7 @@ s_reloc (int ignore ATTRIBUTE_UNUSED) { "64", BFD_RELOC_64 } }; - reloc = (struct reloc_list *) xmalloc (sizeof (*reloc)); + reloc = XNEW (struct reloc_list); if (flag_mri) stop = mri_comment_field (&stopc); @@ -4076,15 +4206,18 @@ s_reloc (int ignore ATTRIBUTE_UNUSED) goto err_out; case O_constant: exp.X_add_symbol = section_symbol (now_seg); + /* Mark the section symbol used in relocation so that it will be + included in the symbol table. */ + symbol_mark_used_in_reloc (exp.X_add_symbol); exp.X_op = O_symbol; - /* Fall thru */ + /* Fallthru */ case O_symbol: if (exp.X_add_number == 0) { reloc->u.a.offset_sym = exp.X_add_symbol; break; } - /* Fall thru */ + /* Fallthru */ default: reloc->u.a.offset_sym = make_expr_symbol (&exp); break; @@ -4158,7 +4291,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; @@ -4340,7 +4473,7 @@ emit_expr_with_reloc (expressionS *exp, { 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; @@ -4372,24 +4505,19 @@ emit_expr_with_reloc (expressionS *exp, valueT get; valueT use; valueT mask; - valueT hibit; valueT unmask; /* JF << of >= number of bits in the object is undefined. In particular SPARC (Sun 4) has problems. */ if (nbytes >= sizeof (valueT)) { + know (nbytes == sizeof (valueT)); mask = 0; - if (nbytes > sizeof (valueT)) - hibit = 0; - else - hibit = (valueT) 1 << (nbytes * BITS_PER_CHAR - 1); } else { /* Don't store these bits. */ mask = ~(valueT) 0 << (BITS_PER_CHAR * nbytes); - hibit = (valueT) 1 << (nbytes * BITS_PER_CHAR - 1); } unmask = ~mask; /* Do store these bits. */ @@ -4401,22 +4529,11 @@ emit_expr_with_reloc (expressionS *exp, get = exp->X_add_number; use = get & unmask; - if ((get & mask) != 0 - && ((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 + if ((get & mask) != 0 && (-get & mask) != 0) + { + /* Leading bits contain both 0s & 1s. */ + as_warn (_("value 0x%" BFD_VMA_FMT "x truncated to 0x%" BFD_VMA_FMT "x"), + get, use); } /* Put bytes in right order. */ md_number_to_chars (p, use, (int) nbytes); @@ -4430,18 +4547,39 @@ emit_expr_with_reloc (expressionS *exp, if (nbytes < size) { 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); + as_warn (ngettext ("bignum truncated to %d byte", + "bignum truncated to %d bytes", + nbytes), + nbytes); size = nbytes; } @@ -4517,7 +4655,9 @@ emit_expr_fix (expressionS *exp, unsigned int nbytes, fragS *frag, char *p, if (size > nbytes) { - as_bad (_("%s relocations do not fit in %u bytes\n"), + as_bad (ngettext ("%s relocations do not fit in %u byte", + "%s relocations do not fit in %u bytes", + nbytes), reloc_howto->name, nbytes); return; } @@ -4551,134 +4691,6 @@ emit_expr_fix (expressionS *exp, unsigned int nbytes, fragS *frag, char *p, #endif } -#ifdef BITFIELD_CONS_EXPRESSIONS - -/* i960 assemblers, (eg, asm960), allow bitfields after ".byte" as - w:x,y:z, where w and y are bitwidths and x and y are values. They - then pack them all together. We do a little better in that we allow - them in words, longs, etc. and we'll pack them in target byte order - for you. - - The rules are: pack least significant bit first, if a field doesn't - entirely fit, put it in the next unit. Overflowing the bitfield is - explicitly *not* even a warning. The bitwidth should be considered - a "mask". - - To use this function the tc-XXX.h file should define - BITFIELD_CONS_EXPRESSIONS. */ - -static void -parse_bitfield_cons (exp, nbytes) - expressionS *exp; - unsigned int nbytes; -{ - unsigned int bits_available = BITS_PER_CHAR * nbytes; - char *hold = input_line_pointer; - - (void) expression (exp); - - if (*input_line_pointer == ':') - { - /* Bitfields. */ - long value = 0; - - for (;;) - { - unsigned long width; - - if (*input_line_pointer != ':') - { - input_line_pointer = hold; - break; - } /* Next piece is not a bitfield. */ - - /* In the general case, we can't allow - full expressions with symbol - differences and such. The relocation - entries for symbols not defined in this - assembly would require arbitrary field - widths, positions, and masks which most - of our current object formats don't - support. - - In the specific case where a symbol - *is* defined in this assembly, we - *could* build fixups and track it, but - this could lead to confusion for the - backends. I'm lazy. I'll take any - SEG_ABSOLUTE. I think that means that - you can use a previous .set or - .equ type symbol. xoxorich. */ - - if (exp->X_op == O_absent) - { - as_warn (_("using a bit field width of zero")); - exp->X_add_number = 0; - exp->X_op = O_constant; - } /* Implied zero width bitfield. */ - - if (exp->X_op != O_constant) - { - *input_line_pointer = '\0'; - as_bad (_("field width \"%s\" too complex for a bitfield"), hold); - *input_line_pointer = ':'; - demand_empty_rest_of_line (); - return; - } /* Too complex. */ - - if ((width = exp->X_add_number) > (BITS_PER_CHAR * nbytes)) - { - as_warn (_("field width %lu too big to fit in %d bytes: truncated to %d bits"), - width, nbytes, (BITS_PER_CHAR * nbytes)); - width = BITS_PER_CHAR * nbytes; - } /* Too big. */ - - if (width > bits_available) - { - /* FIXME-SOMEDAY: backing up and reparsing is wasteful. */ - input_line_pointer = hold; - exp->X_add_number = value; - break; - } /* Won't fit. */ - - /* Skip ':'. */ - hold = ++input_line_pointer; - - (void) expression (exp); - if (exp->X_op != O_constant) - { - char cache = *input_line_pointer; - - *input_line_pointer = '\0'; - as_bad (_("field value \"%s\" too complex for a bitfield"), hold); - *input_line_pointer = cache; - demand_empty_rest_of_line (); - return; - } /* Too complex. */ - - value |= ((~(-(1 << width)) & exp->X_add_number) - << ((BITS_PER_CHAR * nbytes) - bits_available)); - - if ((bits_available -= width) == 0 - || is_it_end_of_statement () - || *input_line_pointer != ',') - { - break; - } /* All the bitfields we're gonna get. */ - - hold = ++input_line_pointer; - (void) expression (exp); - } - - exp->X_add_number = value; - exp->X_op = O_constant; - exp->X_unsigned = 1; - exp->X_extrabit = 0; - } -} - -#endif /* BITFIELD_CONS_EXPRESSIONS */ - /* Handle an MRI style string expression. */ #ifdef TC_M68K @@ -4755,9 +4767,7 @@ parse_mri_cons (expressionS *exp, unsigned int 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; @@ -4899,7 +4909,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 ()) @@ -5239,7 +5249,7 @@ output_big_leb128 (char *p, LITTLENUM_TYPE *bignum, unsigned int size, int sign) /* Generate the appropriate fragments for a given expression to emit a leb128 value. SIGN is 1 for sleb, 0 for uleb. */ -static void +void emit_leb128_expr (expressionS *exp, int sign) { operatorT op = exp->X_op; @@ -5312,13 +5322,21 @@ emit_leb128_expr (expressionS *exp, int sign) else if (op == O_big) { /* O_big is a different sort of constant. */ - + int nbr_digits = exp->X_add_number; unsigned int size; char *p; - size = output_big_leb128 (NULL, generic_bignum, exp->X_add_number, sign); + /* If the leading littenum is 0xffff, prepend a 0 to avoid confusion with + a signed number. Unary operators like - or ~ always extend the + bignum to its largest size. */ + if (exp->X_unsigned + && nbr_digits < SIZE_OF_LARGE_NUMBER + && generic_bignum[nbr_digits - 1] == LITTLENUM_MASK) + generic_bignum[nbr_digits++] = 0; + + size = output_big_leb128 (NULL, generic_bignum, nbr_digits, sign); p = frag_more (size); - if (output_big_leb128 (p, generic_bignum, exp->X_add_number, sign) > size) + if (output_big_leb128 (p, generic_bignum, nbr_digits, sign) > size) abort (); } else @@ -5453,11 +5471,14 @@ stringer (int bits_appendzero) while (is_a_char (c = next_char_of_string ())) stringer_append_char (c, bitsize); + /* Treat "a" "b" as "ab". Even if we are appending zeros. */ + SKIP_ALL_WHITESPACE (); + if (*input_line_pointer == '"') + break; + if (append_zero) stringer_append_char (0, bitsize); - know (input_line_pointer[-1] == '\"'); - #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 @@ -5482,8 +5503,11 @@ stringer (int bits_appendzero) c = get_single_number (); stringer_append_char (c, bitsize); if (*input_line_pointer != '>') - as_bad (_("expected ")); - + { + as_bad (_("expected ")); + ignore_rest_of_line (); + return; + } input_line_pointer++; break; case ',': @@ -5510,6 +5534,12 @@ next_char_of_string (void) c = *input_line_pointer++ & CHAR_MASK; switch (c) { + case 0: + /* PR 20902: Do not advance past the end of the buffer. */ + -- input_line_pointer; + c = NOT_A_CHAR; + break; + case '\"': c = NOT_A_CHAR; break; @@ -5519,8 +5549,9 @@ next_char_of_string (void) bump_line_counters (); break; -#ifndef NO_STRING_ESCAPES case '\\': + if (!TC_STRING_ESCAPES) + break; switch (c = *input_line_pointer++ & CHAR_MASK) { case 'b': @@ -5606,6 +5637,12 @@ next_char_of_string (void) bump_line_counters (); break; + case 0: + /* Do not advance past the end of the buffer. */ + -- input_line_pointer; + c = NOT_A_CHAR; + break; + default: #ifdef ONLY_STANDARD_ESCAPES @@ -5616,7 +5653,6 @@ next_char_of_string (void) break; } break; -#endif /* ! defined (NO_STRING_ESCAPES) */ default: break; @@ -5686,12 +5722,12 @@ demand_copy_C_string (int *len_pointer) for (len = *len_pointer; len > 0; len--) { - if (*s == 0) + if (s[len - 1] == 0) { s = 0; - len = 1; *len_pointer = 0; as_bad (_("this string may not contain \'\\0\'")); + break; } } } @@ -5832,7 +5868,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++) { @@ -5852,7 +5888,16 @@ s_incbin (int x ATTRIBUTE_UNUSED) if (binfile) { long file_len; + struct stat filestat; + if (fstat (fileno (binfile), &filestat) != 0 + || ! S_ISREG (filestat.st_mode) + || S_ISDIR (filestat.st_mode)) + { + as_bad (_("unable to include `%s'"), path); + goto done; + } + register_dependency (path); /* Compute the length of the file. */ @@ -5888,11 +5933,10 @@ s_incbin (int x ATTRIBUTE_UNUSED) as_warn (_("truncated file `%s', %ld of %ld bytes read"), path, bytes, count); } -done: + done: if (binfile != NULL) fclose (binfile); - if (path) - free (path); + free (path); } /* .include -- include a file at this point. */ @@ -5935,8 +5979,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++) { @@ -5952,7 +5996,7 @@ s_include (int arg ATTRIBUTE_UNUSED) free (path); path = filename; -gotit: + gotit: /* malloc Storage leak when file is found on path. FIXME-SOMEDAY. */ register_dependency (path); input_scrub_insert_file (path); @@ -5965,16 +6009,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 **) xrealloc (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. */ @@ -6172,9 +6215,10 @@ s_bundle_unlock (int arg ATTRIBUTE_UNUSED) 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); + if (size > 1U << bundle_align_p2) + as_bad (_(".bundle_lock sequence is %u bytes, " + "but bundle size is only %u bytes"), + size, 1u << bundle_align_p2); else finish_bundle (bundle_lock_frag, size); @@ -6193,7 +6237,7 @@ s_ignore (int arg ATTRIBUTE_UNUSED) void read_print_statistics (FILE *file) { - hash_print_statistics (file, "pseudo-op table", po_hash); + htab_print_statistics (file, "pseudo-op table", po_hash); } /* Inserts the given line into the input stream. @@ -6282,3 +6326,46 @@ find_end_of_line (char *s, int mri_string) { return _find_end_of_line (s, mri_string, 0, 0); } + +static char *saved_ilp = NULL; +static char *saved_limit; + +/* Use BUF as a temporary input pointer for calling other functions in this + file. BUF must be a C string, so that its end can be found by strlen. + Also sets the buffer_limit variable (local to this file) so that buffer + overruns should not occur. Saves the current input line pointer so that + it can be restored by calling restore_ilp(). + + Does not support recursion. */ + +void +temp_ilp (char *buf) +{ + gas_assert (saved_ilp == NULL); + gas_assert (buf != NULL); + + saved_ilp = input_line_pointer; + saved_limit = buffer_limit; + /* Prevent the assert in restore_ilp from triggering if + the input_line_pointer has not yet been initialised. */ + if (saved_ilp == NULL) + saved_limit = saved_ilp = (char *) ""; + + input_line_pointer = buf; + buffer_limit = buf + strlen (buf); + input_from_string = true; +} + +/* Restore a saved input line pointer. */ + +void +restore_ilp (void) +{ + gas_assert (saved_ilp != NULL); + + input_line_pointer = saved_ilp; + buffer_limit = saved_limit; + input_from_string = false; + + saved_ilp = NULL; +}