/* read.c - read a source file -
- Copyright (C) 1986-2021 Free Software Foundation, Inc.
+ Copyright (C) 1986-2023 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
#include "obstack.h"
#include "ecoff.h"
#include "dw2gencfi.h"
+#include "codeview.h"
#include "wchar.h"
+#include "filenames.h"
#include <limits.h>
const char **include_dirs;
/* How many are in the table. */
-int include_dir_count;
+size_t include_dir_count;
/* Length of longest in table. */
-int include_dir_maxlen = 1;
+size_t include_dir_maxlen;
#ifndef WORKING_DOT_WORD
struct broken_word *broken_words;
may be needed. */
static int mri_pending_align;
+/* Record the current function so that we can issue an error message for
+ misplaced .func,.endfunc, and also so that .endfunc needs no
+ arguments. */
+static char *current_name;
+static char *current_label;
+
#ifndef NO_LISTING
#ifdef OBJ_ELF
+static int dwarf_file;
+static int dwarf_line;
+
/* This variable is set to be non-zero if the next string we see might
be the name of the source file in DWARF debugging information. See
the comment in emit_expr for the format we look for. */
static int hex_float (int, char *);
static segT get_known_segmented_expression (expressionS * expP);
static void pobegin (void);
+static void poend (void);
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);
pobegin ();
obj_read_begin_hook ();
- /* Something close -- but not too close -- to a multiple of 1024.
- The debugging malloc I'm using has 24 bytes of overhead. */
- obstack_begin (¬es, chunksize);
obstack_begin (&cond_obstack, chunksize);
#ifndef tc_line_separator_chars
if (flag_mri)
lex_type['?'] = 3;
+ stabs_begin ();
+
+#ifndef WORKING_DOT_WORD
+ broken_words = NULL;
+ new_broken_words = 0;
+#endif
+
+ abs_section_offset = 0;
+
+ line_label = NULL;
+ mri_common_symbol = NULL;
+ mri_pending_align = 0;
+
+ current_name = NULL;
+ current_label = NULL;
+
+#ifndef NO_LISTING
+#ifdef OBJ_ELF
+ dwarf_file = 0;
+ dwarf_line = -1;
+ dwarf_file_string = 0;
+#endif
+#endif
+
+#ifdef HANDLE_BUNDLE
+ bundle_align_p2 = 0;
+ bundle_lock_frag = NULL;
+ bundle_lock_frchain = NULL;
+ bundle_lock_depth = 0;
+#endif
+}
+
+void
+read_end (void)
+{
+ stabs_end ();
+ poend ();
+ _obstack_free (&cond_obstack, NULL);
+ free (current_name);
+ free (current_label);
}
\f
#ifndef TC_ADDRESS_BYTES
/* Set up pseudo-op tables. */
-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 htab_t po_hash;
static const pseudo_typeS potable[] = {
{"abort", s_abort, 0},
{"exitm", s_mexit, 0},
/* extend */
{"extern", s_ignore, 0}, /* We treat all undef as ext. */
- {"appfile", s_app_file, 1},
- {"appline", s_app_line, 1},
{"fail", s_fail, 0},
- {"file", s_app_file, 0},
+ {"file", s_file, 0},
{"fill", s_fill, 0},
{"float", float_cons, 'f'},
{"format", s_ignore, 0},
{"irepc", s_irp, 1},
{"lcomm", s_lcomm, 0},
{"lflags", s_ignore, 0}, /* Listing flags. */
- {"linefile", s_app_line, 0},
+ {"linefile", s_linefile, 0},
{"linkonce", s_linkonce, 0},
{"list", listing_list, 1}, /* Turn listing on. */
{"llen", listing_psize, 1},
return get_absolute_expr (&exp);
}
-static int pop_override_ok = 0;
+static int pop_override_ok;
static const char *pop_table_name;
void
const pseudo_typeS *pop;
for (pop = table; pop->poc_name; pop++)
{
- po_entry_t *elt = po_entry_alloc (pop->poc_name, pop);
- if (htab_insert (po_hash, elt, 0) != NULL)
+ if (str_hash_insert (po_hash, pop->poc_name, pop, 0) != NULL)
{
- free (elt);
if (!pop_override_ok)
as_fatal (_("error constructing %s pseudo-op table"),
pop_table_name);
static void
pobegin (void)
{
- po_hash = htab_create_alloc (16, hash_po_entry, eq_po_entry, NULL,
- xcalloc, xfree);
+ po_hash = str_htab_create ();
/* Do the target-specific pseudo ops. */
pop_table_name = "md";
+ pop_override_ok = 0;
md_pop_insert ();
/* Now object specific. Skip any that were in the target table. */
/* Now CFI ones. */
pop_table_name = "cfi";
- pop_override_ok = 1;
cfi_pop_insert ();
}
+
+static void
+poend (void)
+{
+ htab_delete (po_hash);
+}
\f
#define HANDLE_CONDITIONAL_ASSEMBLY(num_read) \
if (ignore_input ()) \
continue; \
}
-/* This function is used when scrubbing the characters between #APP
- and #NO_APP. */
-
-static char *scrub_string;
-static char *scrub_string_end;
-
-static size_t
-scrub_from_string (char *buf, size_t buflen)
-{
- size_t copy;
-
- copy = scrub_string_end - scrub_string;
- if (copy > buflen)
- copy = buflen;
- memcpy (buf, scrub_string, copy);
- scrub_string += copy;
- return copy;
-}
-
/* Helper function of read_a_source_file, which tries to expand a macro. */
static int
try_macro (char term, const char *line)
as_bad ("%s", err);
*input_line_pointer++ = term;
input_scrub_include_sb (&out,
- input_line_pointer, 1);
+ input_line_pointer, expanding_macro);
sb_kill (&out);
buffer_limit =
input_scrub_next_buffer (&input_line_pointer);
#ifndef NO_LISTING
/* In order to avoid listing macro expansion lines with labels
multiple times, keep track of which line was last issued. */
- static char *last_eol;
+ char *last_eol = NULL;
- last_eol = NULL;
#endif
while (input_line_pointer < buffer_limit)
{
/* Find the end of the current expanded macro line. */
s = find_end_of_line (input_line_pointer, flag_m68k_mri);
- if (s != last_eol)
+ if (s != last_eol
+ && !startswith (input_line_pointer,
+ !flag_m68k_mri ? " .linefile "
+ : " linefile "))
{
char *copy;
- int len;
+ size_t len;
last_eol = s;
/* Copy it for safe keeping. Also give an indication of
{
/* The MRI assembler uses pseudo-ops without
a period. */
- pop = po_entry_find (po_hash, s);
+ pop = str_hash_find (po_hash, s);
if (pop != NULL && pop->poc_handler == NULL)
pop = NULL;
}
already know that the pseudo-op begins with a '.'. */
if (pop == NULL)
- pop = po_entry_find (po_hash, s + 1);
+ pop = str_hash_find (po_hash, s + 1);
if (pop && !pop->poc_handler)
pop = NULL;
while (ISDIGIT (*input_line_pointer))
{
const long digit = *input_line_pointer - '0';
- if (temp > (LONG_MAX - digit) / 10)
+ if (temp > (INT_MAX - digit) / 10)
{
as_bad (_("local label too large near %s"), backup);
temp = -1;
{ /* Its a comment. Better say APP or NO_APP. */
sb sbuf;
char *ends;
- char *new_buf;
- char *new_tmp;
- unsigned int new_length;
- char *tmp_buf = 0;
+ size_t len;
s = input_line_pointer;
if (!startswith (s, "APP\n"))
s += 4;
ends = strstr (s, "#NO_APP\n");
+ len = ends ? ends - s : buffer_limit - s;
+ sb_build (&sbuf, len + 100);
+ sb_add_buffer (&sbuf, s, len);
if (!ends)
{
- unsigned int tmp_len;
- unsigned int num;
-
/* The end of the #APP wasn't in this buffer. We
keep reading in buffers until we find the #NO_APP
that goes with this #APP There is one. The specs
guarantee it... */
- tmp_len = buffer_limit - s;
- tmp_buf = XNEWVEC (char, tmp_len + 1);
- memcpy (tmp_buf, s, tmp_len);
do
{
- new_tmp = input_scrub_next_buffer (&buffer);
- if (!new_tmp)
+ buffer_limit = input_scrub_next_buffer (&buffer);
+ if (!buffer_limit)
break;
- else
- buffer_limit = new_tmp;
- input_line_pointer = buffer;
ends = strstr (buffer, "#NO_APP\n");
- if (ends)
- num = ends - buffer;
- else
- num = buffer_limit - buffer;
-
- tmp_buf = XRESIZEVEC (char, tmp_buf, tmp_len + num);
- memcpy (tmp_buf + tmp_len, buffer, num);
- tmp_len += num;
+ len = ends ? ends - buffer : buffer_limit - buffer;
+ sb_add_buffer (&sbuf, buffer, len);
}
while (!ends);
-
- input_line_pointer = ends ? ends + 8 : NULL;
-
- s = tmp_buf;
- ends = s + tmp_len;
-
- }
- else
- {
- input_line_pointer = ends + 8;
- }
-
- scrub_string = s;
- scrub_string_end = ends;
-
- new_length = ends - s;
- new_buf = XNEWVEC (char, new_length);
- new_tmp = new_buf;
- for (;;)
- {
- size_t space;
- size_t size;
-
- space = (new_buf + new_length) - new_tmp;
- size = do_scrub_chars (scrub_from_string, new_tmp, space);
-
- if (size < space)
- {
- new_tmp[size] = 0;
- break;
- }
-
- new_buf = XRESIZEVEC (char, new_buf, new_length + 100);
- new_tmp = new_buf + new_length;
- new_length += 100;
}
- free (tmp_buf);
-
- /* We've "scrubbed" input to the preferred format. In the
- process we may have consumed the whole of the remaining
- file (and included files). We handle this formatted
- input similar to that of macro expansion, letting
- actual macro expansion (possibly nested) and other
- input expansion work. Beware that in messages, line
- numbers and possibly file names will be incorrect. */
- 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);
+ input_line_pointer = ends ? ends + 8 : NULL;
+ input_scrub_include_sb (&sbuf, input_line_pointer, expanding_none);
sb_kill (&sbuf);
buffer_limit = input_scrub_next_buffer (&input_line_pointer);
- free (new_buf);
continue;
}
s_altmacro (int on)
{
demand_empty_rest_of_line ();
- macro_set_alternate (on);
+ flag_macro_alternate = on;
}
/* Read a symbol name from input_line_pointer.
/* 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)
+ /* PR 29447: mbstowcs ignores the third (length) parameter when
+ the first (destination) parameter is NULL. For clarity sake
+ therefore we pass 0 rather than 'len' as the third parameter. */
+ if (mbstowcs (NULL, name, 0) == (size_t) -1)
as_warn (_("symbol name not recognised in the current locale"));
}
else if (is_name_beginner (c) || (input_from_string && c == FAKE_LABEL_CHAR))
{
as_bad (_("expected symbol name"));
ignore_rest_of_line ();
+ free (start);
return NULL;
}
ignore_rest_of_line ();
goto out;
}
- else if (temp != size || !exp.X_unsigned)
+ else if (temp != size || (!exp.X_unsigned && exp.X_add_number < 0))
{
as_warn (_("size (%ld) out of range, ignored"), (long) temp);
ignore_rest_of_line ();
if (S_IS_DEFINED (sym) && !S_IS_COMMON (sym))
{
as_bad (_("symbol `%s' is already defined"), S_GET_NAME (sym));
- ignore_rest_of_line ();
mri_comment_end (stop, stopc);
return;
}
demand_empty_rest_of_line ();
}
-/* Handle the .appfile pseudo-op. This is automatically generated by
- do_scrub_chars when a preprocessor # line comment is seen with a
- file name. This default definition may be overridden by the object
- or CPU specific pseudo-ops. This function is also the default
- definition for .file; the APPFILE argument is 1 for .appfile, 0 for
- .file. */
+/* Handle the .file pseudo-op. This default definition may be overridden by
+ the object or CPU specific pseudo-ops. */
void
-s_app_file_string (char *file, int appfile ATTRIBUTE_UNUSED)
+s_file_string (char *file)
{
#ifdef LISTING
if (listing)
#endif
register_dependency (file);
#ifdef obj_app_file
- obj_app_file (file, appfile);
+ obj_app_file (file);
#endif
}
void
-s_app_file (int appfile)
+s_file (int ignore ATTRIBUTE_UNUSED)
{
char *s;
int length;
/* Some assemblers tolerate immediately following '"'. */
if ((s = demand_copy_string (&length)) != 0)
{
- int may_omit
- = (!new_logical_line_flags (s, -1, 1) && appfile);
+ new_logical_line_flags (s, -1, 1);
/* In MRI mode, the preprocessor may have inserted an extraneous
backquote. */
++input_line_pointer;
demand_empty_rest_of_line ();
- if (!may_omit)
- s_app_file_string (s, appfile);
+ s_file_string (s);
}
}
-static int
+static bool
get_linefile_number (int *flag)
{
+ expressionS exp;
+
SKIP_WHITESPACE ();
if (*input_line_pointer < '0' || *input_line_pointer > '9')
- return 0;
+ return false;
+
+ /* Don't mistakenly interpret octal numbers as line numbers. */
+ if (*input_line_pointer == '0')
+ {
+ *flag = 0;
+ ++input_line_pointer;
+ return true;
+ }
+
+ expression_and_evaluate (&exp);
+ if (exp.X_op != O_constant)
+ return false;
+
+#if defined (BFD64) || LONG_MAX > INT_MAX
+ if (exp.X_add_number < INT_MIN || exp.X_add_number > INT_MAX)
+ return false;
+#endif
- *flag = get_absolute_expression ();
+ *flag = exp.X_add_number;
- return 1;
+ return true;
}
-/* Handle the .appline pseudo-op. This is automatically generated by
+/* Handle the .linefile pseudo-op. This is automatically generated by
do_scrub_chars when a preprocessor # line comment is seen. This
default definition may be overridden by the object or CPU specific
pseudo-ops. */
void
-s_app_line (int appline)
+s_linefile (int ignore ATTRIBUTE_UNUSED)
{
char *file = NULL;
- int l;
+ int linenum, flags = 0;
/* The given number is that of the next line. */
- if (appline)
- l = get_absolute_expression ();
- else if (!get_linefile_number (&l))
+ if (!get_linefile_number (&linenum))
{
ignore_rest_of_line ();
return;
}
- l--;
-
- if (l < -1)
+ if (linenum < 0)
/* Some of the back ends can't deal with non-positive line numbers.
Besides, it's silly. GCC however will generate a line number of
zero when it is pre-processing builtins for assembler-with-cpp files:
in the GCC and GDB testsuites. So we check for negative line numbers
rather than non-positive line numbers. */
as_warn (_("line numbers must be positive; line number %d rejected"),
- l + 1);
+ linenum);
else
{
- int flags = 0;
int length = 0;
- if (!appline)
+ SKIP_WHITESPACE ();
+
+ if (*input_line_pointer == '"')
+ file = demand_copy_string (&length);
+ else if (*input_line_pointer == '.')
{
- SKIP_WHITESPACE ();
+ /* buffer_and_nest() may insert this form. */
+ ++input_line_pointer;
+ flags = 1 << 3;
+ }
- if (*input_line_pointer == '"')
- file = demand_copy_string (&length);
+ if (file)
+ {
+ int this_flag;
- if (file)
- {
- int this_flag;
+ while (get_linefile_number (&this_flag))
+ switch (this_flag)
+ {
+ /* From GCC's cpp documentation:
+ 1: start of a new file.
+ 2: returning to a file after having included another file.
+ 3: following text comes from a system header file.
+ 4: following text should be treated as extern "C".
+
+ 4 is nonsensical for the assembler; 3, we don't care about,
+ so we ignore it just in case a system header file is
+ included while preprocessing assembly. So 1 and 2 are all
+ we care about, and they are mutually incompatible.
+ new_logical_line_flags() demands this. */
+ case 1:
+ case 2:
+ if (flags && flags != (1 << this_flag))
+ as_warn (_("incompatible flag %i in line directive"),
+ this_flag);
+ else
+ flags |= 1 << this_flag;
+ break;
- while (get_linefile_number (&this_flag))
- switch (this_flag)
- {
- /* From GCC's cpp documentation:
- 1: start of a new file.
- 2: returning to a file after having included
- another file.
- 3: following text comes from a system header file.
- 4: following text should be treated as extern "C".
-
- 4 is nonsensical for the assembler; 3, we don't
- care about, so we ignore it just in case a
- system header file is included while
- preprocessing assembly. So 1 and 2 are all we
- care about, and they are mutually incompatible.
- new_logical_line_flags() demands this. */
- case 1:
- case 2:
- if (flags && flags != (1 << this_flag))
- as_warn (_("incompatible flag %i in line directive"),
- this_flag);
- else
- flags |= 1 << this_flag;
- break;
-
- case 3:
- case 4:
- /* We ignore these. */
- break;
-
- default:
- as_warn (_("unsupported flag %i in line directive"),
- this_flag);
- break;
- }
+ case 3:
+ case 4:
+ /* We ignore these. */
+ break;
- if (!is_end_of_line[(unsigned char)*input_line_pointer])
- file = 0;
- }
- }
+ default:
+ as_warn (_("unsupported flag %i in line directive"),
+ this_flag);
+ break;
+ }
- if (appline || file)
+ if (!is_end_of_line[(unsigned char)*input_line_pointer])
+ file = NULL;
+ }
+
+ if (file || flags)
{
- new_logical_line_flags (file, l, flags);
+ demand_empty_rest_of_line ();
+
+ /* read_a_source_file() will bump the line number only if the line
+ is terminated by '\n'. */
+ if (input_line_pointer[-1] == '\n')
+ linenum--;
+
+ new_logical_line_flags (file, linenum, flags);
#ifdef LISTING
if (listing)
- listing_source_line (l);
+ listing_source_line (linenum);
#endif
+ return;
}
}
- if (appline || file)
- demand_empty_rest_of_line ();
- else
- ignore_rest_of_line ();
+ ignore_rest_of_line ();
}
/* Handle the .end pseudo-op. Actually, the real work is done in
as_warn (_("repeat < 0; .fill ignored"));
size = 0;
}
-
- if (size && !need_pass_2)
+ else if (size && !need_pass_2)
{
- if (now_seg == absolute_section)
+ if (now_seg == absolute_section && rep_exp.X_op != O_constant)
{
- 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;
+ as_bad (_("non-constant fill count for absolute section"));
+ size = 0;
+ }
+ else if (now_seg == absolute_section && fill && rep_exp.X_add_number != 0)
+ {
+ as_bad (_("attempt to fill absolute section with non-zero value"));
+ size = 0;
}
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));
+ {
+ as_bad (_("attempt to fill section `%s' with non-zero value"),
+ segment_name (now_seg));
+ size = 0;
+ }
+ }
+
+ if (size && !need_pass_2)
+ {
+ if (now_seg == absolute_section)
+ abs_section_offset += rep_exp.X_add_number * size;
if (rep_exp.X_op == O_constant)
{
sb_kill (&s);
- input_scrub_include_sb (&out, input_line_pointer, 1);
+ input_scrub_include_sb (&out, input_line_pointer, expanding_repeat);
sb_kill (&out);
buffer_limit = input_scrub_next_buffer (&input_line_pointer);
}
if (exp.X_op == O_absent)
goto no_align;
- if (!exp.X_unsigned)
+ if (!exp.X_unsigned && exp.X_add_number < 0)
{
as_warn (_("alignment negative; 0 assumed"));
align = 0;
s_macro (int ignore ATTRIBUTE_UNUSED)
{
char *eol;
- const char * file;
- unsigned int line;
sb s;
- const char *err;
- const char *name;
-
- file = as_where (&line);
+ macro_entry *macro;
eol = find_end_of_line (input_line_pointer, 0);
sb_build (&s, eol - input_line_pointer);
{
sb label;
size_t len;
+ const char *name;
name = S_GET_NAME (line_label);
len = strlen (name);
sb_build (&label, len);
sb_add_buffer (&label, name, len);
- err = define_macro (0, &s, &label, get_macro_line_sb, file, line, &name);
+ macro = define_macro (&s, &label, get_macro_line_sb);
sb_kill (&label);
}
else
- err = define_macro (0, &s, NULL, get_macro_line_sb, file, line, &name);
- if (err != NULL)
- as_bad_where (file, line, err, name);
- else
+ macro = define_macro (&s, NULL, get_macro_line_sb);
+ if (macro != NULL)
{
if (line_label != NULL)
{
}
if (((NO_PSEUDO_DOT || flag_m68k_mri)
- && po_entry_find (po_hash, name) != NULL)
+ && str_hash_find (po_hash, macro->name) != NULL)
|| (!flag_m68k_mri
- && *name == '.'
- && po_entry_find (po_hash, name + 1) != NULL))
- as_warn_where (file,
- line,
- _("attempt to redefine pseudo-op `%s' ignored"),
- name);
+ && macro->name[0] == '.'
+ && str_hash_find (po_hash, macro->name + 1) != NULL))
+ {
+ as_warn_where (macro->file, macro->line,
+ _("attempt to redefine pseudo-op `%s' ignored"),
+ macro->name);
+ str_hash_delete (macro_hash, macro->name);
+ }
}
sb_kill (&s);
#ifdef TC_M68K
flag_m68k_mri = 1;
#endif
- macro_mri_mode (1);
}
else
{
#ifdef TC_M68K
flag_m68k_mri = 0;
#endif
- macro_mri_mode (0);
}
/* Operator precedence changes in m68k MRI mode, so we need to
count = (size_t) get_absolute_expression ();
- do_repeat (count, "REPT", "ENDR");
+ do_repeat (count, "REPT", "ENDR", NULL);
}
/* This function provides a generic repeat block implementation. It allows
- different directives to be used as the start/end keys. */
+ different directives to be used as the start/end keys. Any text matching
+ the optional EXPANDER in the block is replaced by the remaining iteration
+ count. */
void
-do_repeat (size_t count, const char *start, const char *end)
+do_repeat (size_t count, const char *start, const char *end,
+ const char *expander)
{
sb one;
sb many;
if (!buffer_and_nest (start, end, &one, get_non_macro_line_sb))
{
as_bad (_("%s without %s"), start, end);
+ sb_kill (&one);
return;
}
- sb_build (&many, count * one.len);
- while (count-- > 0)
- sb_add_sb (&many, &one);
-
- sb_kill (&one);
-
- input_scrub_include_sb (&many, input_line_pointer, 1);
- sb_kill (&many);
- buffer_limit = input_scrub_next_buffer (&input_line_pointer);
-}
-
-/* Like do_repeat except that any text matching EXPANDER in the
- block is replaced by the iteration count. */
-
-void
-do_repeat_with_expander (size_t count,
- const char * start,
- const char * end,
- const char * expander)
-{
- sb one;
- sb many;
-
- if (((ssize_t) count) < 0)
+ if (expander == NULL || strstr (one.ptr, expander) == NULL)
{
- as_bad (_("negative count for %s - ignored"), start);
- count = 0;
+ sb_build (&many, count * one.len);
+ while (count-- > 0)
+ sb_add_sb (&many, &one);
}
-
- sb_new (&one);
- if (!buffer_and_nest (start, end, &one, get_non_macro_line_sb))
+ else
{
- as_bad (_("%s without %s"), start, end);
- return;
- }
+ sb_new (&many);
- sb_new (&many);
-
- if (expander != NULL && strstr (one.ptr, expander) != NULL)
- {
while (count -- > 0)
{
int len;
sb_kill (& processed);
}
}
- else
- while (count-- > 0)
- sb_add_sb (&many, &one);
sb_kill (&one);
- input_scrub_include_sb (&many, input_line_pointer, 1);
+ input_scrub_include_sb (&many, input_line_pointer, expanding_repeat);
sb_kill (&many);
buffer_limit = input_scrub_next_buffer (&input_line_pointer);
}
if (listing & LISTING_SYMBOLS)
{
extern struct list_info_struct *listing_tail;
- fragS *dummy_frag = XCNEW (fragS);
+ fragS *dummy_frag = notes_calloc (1, sizeof (*dummy_frag));
dummy_frag->line = listing_tail;
dummy_frag->fr_symbol = symbolP;
symbol_set_frag (symbolP, dummy_frag);
if (exp.X_op == O_constant)
{
- offsetT repeat;
+ addressT repeat = exp.X_add_number;
+ addressT total;
- repeat = exp.X_add_number;
- if (mult)
- repeat *= mult;
- bytes = repeat;
- if (repeat <= 0)
+ bytes = 0;
+ if ((offsetT) repeat < 0)
+ {
+ as_warn (_(".space repeat count is negative, ignored"));
+ goto getout;
+ }
+ if (repeat == 0)
{
if (!flag_mri)
as_warn (_(".space repeat count is zero, ignored"));
- else if (repeat < 0)
- as_warn (_(".space repeat count is negative, ignored"));
goto getout;
}
+ if ((unsigned int) mult <= 1)
+ total = repeat;
+ else if (gas_mul_overflow (repeat, mult, &total)
+ || (offsetT) total < 0)
+ {
+ as_warn (_(".space repeat count overflow, ignored"));
+ goto getout;
+ }
+ bytes = total;
/* 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;
+ abs_section_offset += total;
goto getout;
}
if (mri_common_symbol != NULL)
{
S_SET_VALUE (mri_common_symbol,
- S_GET_VALUE (mri_common_symbol) + repeat);
+ S_GET_VALUE (mri_common_symbol) + total);
goto getout;
}
if (!need_pass_2)
p = frag_var (rs_fill, 1, 1, (relax_substateT) 0, (symbolS *) 0,
- (offsetT) repeat, (char *) 0);
+ (offsetT) total, (char *) 0);
}
else
{
*p = val.X_add_number;
}
+/* Obtain the size of a floating point number, given a type. */
+
+static int
+float_length (int float_type, int *pad_p)
+{
+ int length, pad = 0;
+
+ switch (float_type)
+ {
+ case 'b':
+ case 'B':
+ case 'h':
+ case 'H':
+ length = 2;
+ break;
+
+ case 'f':
+ case 'F':
+ case 's':
+ case 'S':
+ length = 4;
+ break;
+
+ case 'd':
+ case 'D':
+ case 'r':
+ case 'R':
+ length = 8;
+ break;
+
+ case 'x':
+ case 'X':
+#ifdef X_PRECISION
+ length = X_PRECISION * sizeof (LITTLENUM_TYPE);
+ pad = X_PRECISION_PAD * sizeof (LITTLENUM_TYPE);
+ if (!length)
+#endif
+ length = 12;
+ break;
+
+ case 'p':
+ case 'P':
+#ifdef P_PRECISION
+ length = P_PRECISION * sizeof (LITTLENUM_TYPE);
+ pad = P_PRECISION_PAD * sizeof (LITTLENUM_TYPE);
+ if (!length)
+#endif
+ length = 12;
+ break;
+
+ default:
+ as_bad (_("unknown floating type '%c'"), float_type);
+ length = -1;
+ break;
+ }
+
+ if (pad_p)
+ *pad_p = pad;
+
+ return length;
+}
+
static int
parse_one_float (int float_type, char temp[MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT])
{
SKIP_WHITESPACE ();
if (*input_line_pointer != ',')
{
- as_bad (_("missing value"));
- ignore_rest_of_line ();
- if (flag_mri)
- mri_comment_end (stop, stopc);
- return;
+ int pad;
+
+ flen = float_length (float_type, &pad);
+ if (flen >= 0)
+ memset (temp, 0, flen += pad);
}
+ else
+ {
+ ++input_line_pointer;
- ++input_line_pointer;
+ flen = parse_one_float (float_type, temp);
+ }
- flen = parse_one_float (float_type, temp);
if (flen < 0)
{
if (flag_mri)
\f
/* Verify that we are at the end of a line. If not, issue an error and
- skip to EOL. */
+ skip to EOL. This function may leave input_line_pointer one past
+ buffer_limit, so should not be called from places that may
+ dereference input_line_pointer unconditionally. Note that when the
+ gas parser is switched to handling a string (where buffer_limit
+ should be the size of the string excluding the NUL terminator) this
+ will be one past the NUL; is_end_of_line(0) returns true. */
void
demand_empty_rest_of_line (void)
{
SKIP_WHITESPACE ();
+ if (input_line_pointer > buffer_limit)
+ return;
if (is_end_of_line[(unsigned char) *input_line_pointer])
input_line_pointer++;
else
*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]]);
}
/* Silently advance to the end of line. Use this after already having
- issued an error about something bad. */
+ issued an error about something bad. Like demand_empty_rest_of_line,
+ this function may leave input_line_pointer one after buffer_limit;
+ Don't call it from within expression parsing code in an attempt to
+ silence further errors. */
void
ignore_rest_of_line (void)
{
- while (input_line_pointer < buffer_limit
- && !is_end_of_line[(unsigned char) *input_line_pointer])
- input_line_pointer++;
-
- input_line_pointer++;
-
+ while (input_line_pointer <= buffer_limit)
+ if (is_end_of_line[(unsigned char) *input_line_pointer++])
+ break;
/* Return pointing just after end-of-line. */
- 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
return;
}
#endif
+ /* Make sure symbol_equated_p() recognizes the symbol as an equate. */
+ exp.X_add_symbol = make_expr_symbol (&exp);
+ exp.X_add_number = 0;
+ exp.X_op = O_symbol;
+ symbol_set_value_expression (symbolP, &exp);
S_SET_SEGMENT (symbolP, reg_section);
- S_SET_VALUE (symbolP, (valueT) exp.X_add_number);
set_zero_frag (symbolP);
- symbol_get_value_expression (symbolP)->X_op = O_register;
break;
case O_symbol:
int c;
struct reloc_list *reloc;
struct _bfd_rel { const char * name; bfd_reloc_code_real_type code; };
- static struct _bfd_rel bfd_relocs[] =
+ static const struct _bfd_rel bfd_relocs[] =
{
{ "NONE", BFD_RELOC_NONE },
{ "8", BFD_RELOC_8 },
/* When gcc emits DWARF 1 debugging pseudo-ops, a line number will
appear as a four byte positive constant in the .line section,
followed by a 2 byte 0xffff. Look for that case here. */
- {
- static int dwarf_line = -1;
-
- if (strcmp (segment_name (now_seg), ".line") != 0)
- dwarf_line = -1;
- else if (dwarf_line >= 0
- && nbytes == 2
- && exp->X_op == O_constant
- && (exp->X_add_number == -1 || exp->X_add_number == 0xffff))
- listing_source_line ((unsigned int) dwarf_line);
- else if (nbytes == 4
- && exp->X_op == O_constant
- && exp->X_add_number >= 0)
- dwarf_line = exp->X_add_number;
- else
- dwarf_line = -1;
- }
+ if (strcmp (segment_name (now_seg), ".line") != 0)
+ dwarf_line = -1;
+ else if (dwarf_line >= 0
+ && nbytes == 2
+ && exp->X_op == O_constant
+ && (exp->X_add_number == -1 || exp->X_add_number == 0xffff))
+ listing_source_line ((unsigned int) dwarf_line);
+ else if (nbytes == 4
+ && exp->X_op == O_constant
+ && exp->X_add_number >= 0)
+ dwarf_line = exp->X_add_number;
+ else
+ dwarf_line = -1;
/* When gcc emits DWARF 1 debugging pseudo-ops, a file name will
appear as a 2 byte TAG_compile_unit (0x11) followed by a 2 byte
AT_sibling (0x12) followed by a four byte address of the sibling
followed by a 2 byte AT_name (0x38) followed by the name of the
file. We look for that case here. */
- {
- static int dwarf_file = 0;
-
- if (strcmp (segment_name (now_seg), ".debug") != 0)
- dwarf_file = 0;
- else if (dwarf_file == 0
- && nbytes == 2
- && exp->X_op == O_constant
- && exp->X_add_number == 0x11)
- dwarf_file = 1;
- else if (dwarf_file == 1
- && nbytes == 2
- && exp->X_op == O_constant
- && exp->X_add_number == 0x12)
- dwarf_file = 2;
- else if (dwarf_file == 2
- && nbytes == 4)
- dwarf_file = 3;
- else if (dwarf_file == 3
- && nbytes == 2
- && exp->X_op == O_constant
- && exp->X_add_number == 0x38)
- dwarf_file = 4;
- else
- dwarf_file = 0;
-
- /* The variable dwarf_file_string tells stringer that the string
- may be the name of the source file. */
- if (dwarf_file == 4)
- dwarf_file_string = 1;
- else
- dwarf_file_string = 0;
- }
+ if (strcmp (segment_name (now_seg), ".debug") != 0)
+ dwarf_file = 0;
+ else if (dwarf_file == 0
+ && nbytes == 2
+ && exp->X_op == O_constant
+ && exp->X_add_number == 0x11)
+ dwarf_file = 1;
+ else if (dwarf_file == 1
+ && nbytes == 2
+ && exp->X_op == O_constant
+ && exp->X_add_number == 0x12)
+ dwarf_file = 2;
+ else if (dwarf_file == 2
+ && nbytes == 4)
+ dwarf_file = 3;
+ else if (dwarf_file == 3
+ && nbytes == 2
+ && exp->X_op == O_constant
+ && exp->X_add_number == 0x38)
+ dwarf_file = 4;
+ else
+ dwarf_file = 0;
+
+ /* The variable dwarf_file_string tells stringer that the string
+ may be the name of the source file. */
+ if (dwarf_file == 4)
+ dwarf_file_string = 1;
+ else
+ dwarf_file_string = 0;
#endif
#endif
use = get & unmask;
if ((get & mask) != 0 && (-get & mask) != 0)
{
- char get_buf[128];
- char use_buf[128];
-
- /* These buffers help to ease the translation of the warning message. */
- sprintf_vma (get_buf, get);
- sprintf_vma (use_buf, use);
/* Leading bits contain both 0s & 1s. */
- as_warn (_("value 0x%s truncated to 0x%s"), get_buf, use_buf);
+ as_warn (_("value 0x%" PRIx64 " truncated to 0x%" PRIx64),
+ (uint64_t) get, (uint64_t) use);
}
/* Put bytes in right order. */
md_number_to_chars (p, use, (int) nbytes);
static int
hex_float (int float_type, char *bytes)
{
- int length, pad = 0;
+ int pad, length = float_length (float_type, &pad);
int i;
- switch (float_type)
- {
- case 'b':
- case 'B':
- case 'h':
- case 'H':
- length = 2;
- break;
-
- case 'f':
- case 'F':
- case 's':
- case 'S':
- length = 4;
- break;
-
- case 'd':
- case 'D':
- case 'r':
- case 'R':
- length = 8;
- break;
-
- case 'x':
- case 'X':
-#ifdef X_PRECISION
- length = X_PRECISION * sizeof (LITTLENUM_TYPE);
- pad = X_PRECISION_PAD * sizeof (LITTLENUM_TYPE);
- if (!length)
-#endif
- length = 12;
- break;
-
- case 'p':
- case 'P':
-#ifdef P_PRECISION
- length = P_PRECISION * sizeof (LITTLENUM_TYPE);
- pad = P_PRECISION_PAD * sizeof (LITTLENUM_TYPE);
- if (!length)
-#endif
- length = 12;
- break;
-
- default:
- as_bad (_("unknown floating type type '%c'"), float_type);
- return -1;
- }
+ if (length < 0)
+ return length;
/* It would be nice if we could go through expression to parse the
hex constant, but if we get a bignum it's a pain to sort it into
case '8':
case '9':
{
- long number;
+ unsigned number;
int i;
for (i = 0, number = 0;
case 'x':
case 'X':
{
- long number;
+ unsigned number;
number = 0;
c = *input_line_pointer++;
}
}
+/* Open FILENAME, first trying the unadorned file name, then if that
+ fails and the file name is not an absolute path, attempt to open
+ the file in current -I include paths. PATH is a preallocated
+ buffer which will be set to the file opened, or FILENAME if no file
+ is found. */
+
+FILE *
+search_and_open (const char *filename, char *path)
+{
+ FILE *f = fopen (filename, FOPEN_RB);
+ if (f == NULL && !IS_ABSOLUTE_PATH (filename))
+ {
+ for (size_t i = 0; i < include_dir_count; i++)
+ {
+ sprintf (path, "%s/%s", include_dirs[i], filename);
+ f = fopen (path, FOPEN_RB);
+ if (f != NULL)
+ return f;
+ }
+ }
+ strcpy (path, filename);
+ return f;
+}
+
/* .incbin -- include a file verbatim at the current location. */
void
demand_empty_rest_of_line ();
- /* Try opening absolute path first, then try include dirs. */
- binfile = fopen (filename, FOPEN_RB);
- if (binfile == NULL)
- {
- int i;
-
- path = XNEWVEC (char, (unsigned long) len + include_dir_maxlen + 5);
-
- for (i = 0; i < include_dir_count; i++)
- {
- sprintf (path, "%s/%s", include_dirs[i], filename);
+ path = XNEWVEC (char, len + include_dir_maxlen + 2);
+ binfile = search_and_open (filename, path);
- binfile = fopen (path, FOPEN_RB);
- if (binfile != NULL)
- break;
- }
-
- if (binfile == NULL)
- as_bad (_("file not found: %s"), filename);
- }
+ if (binfile == NULL)
+ as_bad (_("file not found: %s"), filename);
else
- path = xstrdup (filename);
-
- if (binfile)
{
long file_len;
struct stat filestat;
}
demand_empty_rest_of_line ();
- path = XNEWVEC (char, (unsigned long) i
- + include_dir_maxlen + 5 /* slop */ );
- for (i = 0; i < include_dir_count; i++)
- {
- strcpy (path, include_dirs[i]);
- strcat (path, "/");
- strcat (path, filename);
- if (0 != (try_file = fopen (path, FOPEN_RT)))
- {
- fclose (try_file);
- goto gotit;
- }
- }
+ path = notes_alloc (i + include_dir_maxlen + 2);
+ try_file = search_and_open (filename, path);
+ if (try_file)
+ fclose (try_file);
- free (path);
- path = filename;
- gotit:
- /* malloc Storage leak when file is found on path. FIXME-SOMEDAY. */
register_dependency (path);
input_scrub_insert_file (path);
}
void
-add_include_dir (char *path)
+init_include_dir (void)
{
- int i;
-
- if (include_dir_count == 0)
- {
- include_dirs = XNEWVEC (const char *, 2);
- include_dirs[0] = "."; /* Current dir. */
- include_dir_count = 2;
- }
- else
- {
- include_dir_count++;
- include_dirs = XRESIZEVEC (const char *, include_dirs,
- include_dir_count);
- }
+ include_dirs = XNEWVEC (const char *, 1);
+ include_dirs[0] = "."; /* Current dir. */
+ include_dir_count = 1;
+ include_dir_maxlen = 1;
+}
+void
+add_include_dir (char *path)
+{
+ include_dir_count++;
+ include_dirs = XRESIZEVEC (const char *, include_dirs, include_dir_count);
include_dirs[include_dir_count - 1] = path; /* New one. */
- i = strlen (path);
+ size_t i = strlen (path);
if (i > include_dir_maxlen)
include_dir_maxlen = i;
}
support that is required (calling dwarf2_emit_insn), we
let dwarf2dbg.c call as_where on its own. */
break;
+ case DEBUG_CODEVIEW:
+ codeview_generate_asm_lineno ();
+ break;
}
}
static void
do_s_func (int end_p, const char *default_prefix)
{
- /* Record the current function so that we can issue an error message for
- misplaced .func,.endfunc, and also so that .endfunc needs no
- arguments. */
- static char *current_name;
- static char *current_label;
-
if (end_p)
{
if (current_name == NULL)
if (debug_type == DEBUG_STABS)
stabs_generate_asm_endfunc (current_name, current_label);
+ free (current_name);
+ free (current_label);
current_name = current_label = NULL;
}
else /* ! end_p */
as_fatal ("%s", xstrerror (errno));
}
else
- label = name;
+ label = xstrdup (name);
}
}
else
size_t len = strlen (line);
sb_build (&newline, len);
sb_add_buffer (&newline, line, len);
- input_scrub_include_sb (&newline, input_line_pointer, 0);
+ input_scrub_include_sb (&newline, input_line_pointer, expanding_none);
sb_kill (&newline);
buffer_limit = input_scrub_next_buffer (&input_line_pointer);
}
return _find_end_of_line (s, mri_string, 0, 0);
}
-static char *saved_ilp = NULL;
+static char *saved_ilp;
static char *saved_limit;
/* Use BUF as a temporary input pointer for calling other functions in this