/* read.c - read a source file -
- Copyright (C) 1986-2016 Free Software Foundation, Inc.
+ Copyright (C) 1986-2020 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
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)
#endif
char *input_line_pointer; /*->next char of source file to parse. */
+bfd_boolean input_from_string = FALSE;
#if BITS_PER_CHAR != 8
/* The following table is indexed by[(char)] and will break if
{"noformat", s_ignore, 0},
{"nolist", listing_list, 0}, /* Turn listing off. */
{"nopage", listing_nopage, 0},
+ {"nops", s_nops, 0},
{"octa", cons, 16},
{"offset", s_struct, 0},
{"org", s_org, 0},
/* 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);
}
static bfd_boolean
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));
}
{
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)
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;
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"));
md_cons_align (1);
#endif
- get_known_segmented_expression (&rep_exp);
+ expression (&rep_exp);
if (*input_line_pointer == ',')
{
input_line_pointer++;
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)
{
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 ()));
}
{
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 ()));
}
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 ()));
}
}
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 */
}
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");
}
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))
{
}
/* 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)
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))
{
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);
&& !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
{
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
mri_comment_end (stop, stopc);
}
+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
+
+ expression (&exp);
+
+ 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)
+ {
+ if (val.X_add_number < 0)
+ {
+ as_warn (_("negative nop control byte, ignored"));
+ val.X_add_number = 0;
+ }
+
+ if (!need_pass_2)
+ {
+ /* 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;
+ }
+ }
+ else
+ as_bad (_("unsupported variable nop control in .nops directive"));
+
+ demand_empty_rest_of_line ();
+}
+
/* 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. */
}
else
{
- char *err;
+ const char *err;
err = md_atof (float_type, temp, &flen);
know (flen <= MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT);
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
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);
/* 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. */
#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)
case O_constant:
exp.X_add_symbol = section_symbol (now_seg);
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;
}
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;
}
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;
}
#endif
}
\f
-#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 (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 */
-\f
/* Handle an MRI style string expression. */
#ifdef TC_M68K
{
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 ())
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
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
c = get_single_number ();
stringer_append_char (c, bitsize);
if (*input_line_pointer != '>')
- as_bad (_("expected <nn>"));
-
+ {
+ as_bad (_("expected <nn>"));
+ ignore_rest_of_line ();
+ return;
+ }
input_line_pointer++;
break;
case ',':
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;
bump_line_counters ();
break;
-#ifndef NO_STRING_ESCAPES
case '\\':
+ if (!TC_STRING_ESCAPES)
+ break;
switch (c = *input_line_pointer++ & CHAR_MASK)
{
case 'b':
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
break;
}
break;
-#endif /* ! defined (NO_STRING_ESCAPES) */
default:
break;
as_warn (_("truncated file `%s', %ld of %ld bytes read"),
path, bytes, count);
}
-done:
+ done:
if (binfile != NULL)
fclose (binfile);
if (path)
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);
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);
{
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;
+}