/* read.c - read a source file -
Copyright 1986, 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
- 2010 Free Software Foundation, Inc.
+ 2010, 2011, 2012 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
#include "obstack.h"
#include "ecoff.h"
#include "dw2gencfi.h"
+#include "wchar.h"
#ifndef TC_START_LABEL
#define TC_START_LABEL(x,y,z) (x == ':')
#endif
#endif
+/* If the target defines the md_frag_max_var hook then we know
+ enough to implement the .bundle_align_mode features. */
+#ifdef md_frag_max_var
+# define HANDLE_BUNDLE
+#endif
+
+#ifdef HANDLE_BUNDLE
+/* .bundle_align_mode sets this. Normally it's zero. When nonzero,
+ it's the exponent of the bundle size, and aligned instruction bundle
+ mode is in effect. */
+static unsigned int bundle_align_p2;
+
+/* These are set by .bundle_lock and .bundle_unlock. .bundle_lock sets
+ bundle_lock_frag to frag_now and then starts a new frag with
+ frag_align_code. At the same time, bundle_lock_frain gets frchain_now,
+ so that .bundle_unlock can verify that we didn't change segments.
+ .bundle_unlock resets both to NULL. If we detect a bundling violation,
+ then we reset bundle_lock_frchain to NULL as an indicator that we've
+ already diagnosed the error with as_bad and don't need a cascade of
+ redundant errors, but bundle_lock_frag remains set to indicate that
+ we are expecting to see .bundle_unlock. */
+static fragS *bundle_lock_frag;
+static frchainS *bundle_lock_frchain;
+
+/* This is incremented by .bundle_lock and decremented by .bundle_unlock,
+ to allow nesting. */
+static unsigned int bundle_lock_depth;
+#endif
+
static void do_s_func (int end_p, const char *default_prefix);
static void do_align (int, char *, int, int);
static void s_align (int, int);
static int hex_float (int, char *);
static segT get_known_segmented_expression (expressionS * expP);
static void pobegin (void);
-static int get_non_macro_line_sb (sb *);
+static size_t get_non_macro_line_sb (sb *);
static void generate_file_debug (void);
static char *_find_end_of_line (char *, int, int, int);
\f
{"balignw", s_align_bytes, -2},
{"balignl", s_align_bytes, -4},
/* block */
+#ifdef HANDLE_BUNDLE
+ {"bundle_align_mode", s_bundle_align_mode, 0},
+ {"bundle_lock", s_bundle_lock, 0},
+ {"bundle_unlock", s_bundle_unlock, 0},
+#endif
{"byte", cons, 1},
{"comm", s_comm, 0},
{"common", s_mri_common, 0},
pop_table_name = "standard";
pop_insert (potable);
-#ifdef TARGET_USE_CFIPOP
+ /* Now CFI ones. */
pop_table_name = "cfi";
pop_override_ok = 1;
cfi_pop_insert ();
-#endif
}
\f
#define HANDLE_CONDITIONAL_ASSEMBLY() \
static char *scrub_string;
static char *scrub_string_end;
-static int
-scrub_from_string (char *buf, int buflen)
+static size_t
+scrub_from_string (char *buf, size_t buflen)
{
- int copy;
+ size_t copy;
copy = scrub_string_end - scrub_string;
if (copy > buflen)
return 0;
}
+#ifdef HANDLE_BUNDLE
+/* Start a new instruction bundle. Returns the rs_align_code frag that
+ will be used to align the new bundle. */
+static fragS *
+start_bundle (void)
+{
+ fragS *frag = frag_now;
+
+ frag_align_code (0, 0);
+
+ while (frag->fr_type != rs_align_code)
+ frag = frag->fr_next;
+
+ gas_assert (frag != frag_now);
+
+ return frag;
+}
+
+/* Calculate the maximum size after relaxation of the region starting
+ at the given frag and extending through frag_now (which is unfinished). */
+static unsigned int
+pending_bundle_size (fragS *frag)
+{
+ unsigned int offset = frag->fr_fix;
+ unsigned int size = 0;
+
+ gas_assert (frag != frag_now);
+ gas_assert (frag->fr_type == rs_align_code);
+
+ while (frag != frag_now)
+ {
+ /* This should only happen in what will later become an error case. */
+ if (frag == NULL)
+ return 0;
+
+ size += frag->fr_fix;
+ if (frag->fr_type == rs_machine_dependent)
+ size += md_frag_max_var (frag);
+
+ frag = frag->fr_next;
+ }
+
+ gas_assert (frag == frag_now);
+ size += frag_now_fix ();
+ if (frag->fr_type == rs_machine_dependent)
+ size += md_frag_max_var (frag);
+
+ gas_assert (size >= offset);
+
+ return size - offset;
+}
+
+/* Finish off the frag created to ensure bundle alignment. */
+static void
+finish_bundle (fragS *frag, unsigned int size)
+{
+ gas_assert (bundle_align_p2 > 0);
+ gas_assert (frag->fr_type == rs_align_code);
+
+ if (size > 1)
+ {
+ /* If there is more than a single byte, then we need to set up the
+ alignment frag. Otherwise we leave it at its initial state from
+ calling frag_align_code (0, 0), so that it does nothing. */
+ frag->fr_offset = bundle_align_p2;
+ frag->fr_subtype = size - 1;
+ }
+
+ /* We do this every time rather than just in s_bundle_align_mode
+ so that we catch any affected section without needing hooks all
+ over for all paths that do section changes. It's cheap enough. */
+ record_alignment (now_seg, bundle_align_p2 - OCTETS_PER_BYTE_POWER);
+}
+
+/* Assemble one instruction. This takes care of the bundle features
+ around calling md_assemble. */
+static void
+assemble_one (char *line)
+{
+ fragS *insn_start_frag = NULL;
+
+ if (bundle_lock_frchain != NULL && bundle_lock_frchain != frchain_now)
+ {
+ as_bad (_("cannot change section or subsection inside .bundle_lock"));
+ /* Clearing this serves as a marker that we have already complained. */
+ bundle_lock_frchain = NULL;
+ }
+
+ if (bundle_lock_frchain == NULL && bundle_align_p2 > 0)
+ insn_start_frag = start_bundle ();
+
+ md_assemble (line);
+
+ if (bundle_lock_frchain != NULL)
+ {
+ /* Make sure this hasn't pushed the locked sequence
+ past the bundle size. */
+ unsigned int bundle_size = pending_bundle_size (bundle_lock_frag);
+ if (bundle_size > (1U << bundle_align_p2))
+ as_bad (_("\
+.bundle_lock sequence at %u bytes but .bundle_align_mode limit is %u bytes"),
+ bundle_size, 1U << bundle_align_p2);
+ }
+ else if (bundle_align_p2 > 0)
+ {
+ unsigned int insn_size = pending_bundle_size (insn_start_frag);
+
+ if (insn_size > (1U << bundle_align_p2))
+ as_bad (_("\
+single instruction is %u bytes long but .bundle_align_mode limit is %u"),
+ (unsigned int) insn_size, 1U << bundle_align_p2);
+
+ finish_bundle (insn_start_frag, insn_size);
+ }
+}
+
+#else /* !HANDLE_BUNDLE */
+
+# define assemble_one(line) md_assemble(line)
+
+#endif /* HANDLE_BUNDLE */
+
/* We read the file, putting things into a web that represents what we
have been reading. */
void
was_new_line = is_end_of_line[(unsigned char) input_line_pointer[-1]];
if (was_new_line)
{
+ symbol_set_value_now (&dot_symbol);
#ifdef md_start_line_hook
md_start_line_hook ();
#endif
/* Input_line_pointer->after ':'. */
SKIP_WHITESPACE ();
}
- else if ((c == '=' && input_line_pointer[1] == '=')
+ else if ((c == '=' && input_line_pointer[1] == '=')
|| ((c == ' ' || c == '\t')
&& input_line_pointer[1] == '='
&& input_line_pointer[2] == '='))
equals (s, -1);
demand_empty_rest_of_line ();
}
- else if ((c == '='
- || ((c == ' ' || c == '\t')
- && input_line_pointer[1] == '='))
+ else if ((c == '='
+ || ((c == ' ' || c == '\t')
+ && input_line_pointer[1] == '='))
#ifdef TC_EQUAL_IN_INSN
- && !TC_EQUAL_IN_INSN (c, s)
+ && !TC_EQUAL_IN_INSN (c, s)
#endif
- )
+ )
{
equals (s, 1);
demand_empty_rest_of_line ();
}
}
- md_assemble (s); /* Assemble 1 instruction. */
+ assemble_one (s); /* Assemble 1 instruction. */
*input_line_pointer++ = c;
bump_line_counters ();
s += 4;
- sb_new (&sbuf);
ends = strstr (s, "#NO_APP\n");
if (!ends)
new_tmp = new_buf;
for (;;)
{
- int space;
- int size;
+ size_t space;
+ size_t size;
space = (new_buf + new_length) - new_tmp;
size = do_scrub_chars (scrub_from_string, new_tmp, space);
actual macro expansion (possibly nested) and other
input expansion work. Beware that in messages, line
numbers and possibly file names will be incorrect. */
- sb_add_string (&sbuf, new_buf);
+ new_length = strlen (new_buf);
+ sb_build (&sbuf, new_length);
+ sb_add_buffer (&sbuf, new_buf, new_length);
input_scrub_include_sb (&sbuf, input_line_pointer, 0);
sb_kill (&sbuf);
buffer_limit = input_scrub_next_buffer (&input_line_pointer);
/* Report unknown char as error. */
demand_empty_rest_of_line ();
}
-
-#ifdef md_after_pass_hook
- md_after_pass_hook ();
-#endif
}
quit:
+ symbol_set_value_now (&dot_symbol);
+
+#ifdef HANDLE_BUNDLE
+ if (bundle_lock_frag != NULL)
+ {
+ as_bad_where (bundle_lock_frag->fr_file, bundle_lock_frag->fr_line,
+ _(".bundle_lock with no matching .bundle_unlock"));
+ bundle_lock_frag = NULL;
+ bundle_lock_frchain = NULL;
+ bundle_lock_depth = 0;
+ }
+#endif
#ifdef md_cleanup
md_cleanup ();
macro_set_alternate (on);
}
+/* Read a symbol name from input_line_pointer.
+
+ Stores the symbol name in a buffer and returns a pointer to this buffer.
+ The buffer is xalloc'ed. It is the caller's responsibility to free
+ this buffer.
+
+ The name is not left in the i_l_p buffer as it may need processing
+ to handle escape characters.
+
+ Advances i_l_p to the next non-whitespace character.
+
+ If a symbol name could not be read, the routine issues an error
+ messages, skips to the end of the line and returns NULL. */
+
+static char *
+read_symbol_name (void)
+{
+ char * name;
+ char * start;
+ char c;
+
+ c = *input_line_pointer++;
+
+ if (c == '"')
+ {
+#define SYM_NAME_CHUNK_LEN 128
+ ptrdiff_t len = SYM_NAME_CHUNK_LEN;
+ char * name_end;
+ unsigned int C;
+
+ start = name = xmalloc (len + 1);
+
+ name_end = name + SYM_NAME_CHUNK_LEN;
+
+ while (is_a_char (C = next_char_of_string ()))
+ {
+ if (name >= name_end)
+ {
+ ptrdiff_t sofar;
+
+ sofar = name - start;
+ len += SYM_NAME_CHUNK_LEN;
+ start = xrealloc (start, len + 1);
+ name_end = start + len;
+ name = start + sofar;
+ }
+
+ *name++ = (char) C;
+ }
+ *name = 0;
+
+ /* Since quoted symbol names can contain non-ASCII characters,
+ check the string and warn if it cannot be recognised by the
+ current character set. */
+ if (mbstowcs (NULL, name, len) == (size_t) -1)
+ as_warn (_("symbol name not recognised in the current locale"));
+ }
+ else if (is_name_beginner (c) || c == '\001')
+ {
+ ptrdiff_t len;
+
+ name = input_line_pointer - 1;
+
+ /* We accept \001 in a name in case this is
+ being called with a constructed string. */
+ while (is_part_of_name (c = *input_line_pointer++)
+ || c == '\001')
+ ;
+
+ len = (input_line_pointer - name) - 1;
+ start = xmalloc (len + 1);
+
+ memcpy (start, name, len);
+ start[len] = 0;
+
+ /* Skip a name ender char if one is present. */
+ if (! is_name_ender (c))
+ --input_line_pointer;
+ }
+ else
+ name = start = NULL;
+
+ if (name == start)
+ {
+ as_bad (_("expected symbol name"));
+ ignore_rest_of_line ();
+ return NULL;
+ }
+
+ SKIP_WHITESPACE ();
+
+ return start;
+}
+
+
symbolS *
s_comm_internal (int param,
symbolS *(*comm_parse_extra) (int, symbolS *, addressT))
{
char *name;
- char c;
- char *p;
offsetT temp, size;
symbolS *symbolP = NULL;
char *stop = NULL;
if (flag_mri)
stop = mri_comment_field (&stopc);
- name = input_line_pointer;
- c = get_symbol_end ();
- /* Just after name is now '\0'. */
- p = input_line_pointer;
- *p = c;
-
- if (name == p)
- {
- as_bad (_("expected symbol name"));
- ignore_rest_of_line ();
- goto out;
- }
-
- SKIP_WHITESPACE ();
+ if ((name = read_symbol_name ()) == NULL)
+ goto out;
/* Accept an optional comma after the name. The comma used to be
required, but Irix 5 cc does not generate it for .lcomm. */
goto out;
}
- *p = 0;
symbolP = symbol_find_or_make (name);
if ((S_IS_DEFINED (symbolP) || symbol_equated_p (symbolP))
&& !S_IS_COMMON (symbolP))
{
symbolP = NULL;
as_bad (_("symbol `%s' is already defined"), name);
- *p = c;
ignore_rest_of_line ();
goto out;
}
as_warn (_("size of \"%s\" is already %ld; not changing to %ld"),
name, (long) size, (long) temp);
- *p = c;
if (comm_parse_extra != NULL)
symbolP = (*comm_parse_extra) (param, symbolP, size);
else
S_SET_VALUE (symbolP, (valueT) size);
S_SET_EXTERNAL (symbolP);
S_SET_SEGMENT (symbolP, bfd_com_section_ptr);
-#ifdef OBJ_VMS
- {
- extern int flag_one;
- if (size == 0 || !flag_one)
- S_GET_OTHER (symbolP) = const_flag;
- }
-#endif
}
demand_empty_rest_of_line ();
out:
if (flag_mri)
mri_comment_end (stop, stopc);
+ if (name != NULL)
+ free (name);
return symbolP;
}
subseg_set (section, (subsegT) temp);
-#ifdef OBJ_VMS
- const_flag = 0;
-#endif
demand_empty_rest_of_line ();
}
Besides, it's silly. GCC however will generate a line number of
zero when it is pre-processing builtins for assembler-with-cpp files:
- # 0 "<built-in>"
+ # 0 "<built-in>"
We do not want to barf on this, especially since such files are used
in the GCC and GDB testsuites. So we check for negative line numbers
/* From GCC's cpp documentation:
1: start of a new file.
2: returning to a file after having included
- another file.
+ another file.
3: following text comes from a system header file.
4: following text should be treated as extern "C".
do
{
- name = input_line_pointer;
- c = get_symbol_end ();
+ if ((name = read_symbol_name ()) == NULL)
+ return;
+
symbolP = symbol_find_or_make (name);
S_SET_EXTERNAL (symbolP);
- *input_line_pointer = c;
SKIP_WHITESPACE ();
c = *input_line_pointer;
if (c == ',')
if (is_end_of_line[(unsigned char) *input_line_pointer])
c = '\n';
}
+
+ free (name);
}
while (c == ',');
as_where (&file, &line);
- sb_new (&s);
eol = find_end_of_line (input_line_pointer, 0);
+ sb_build (&s, eol - input_line_pointer);
sb_add_buffer (&s, input_line_pointer, eol - input_line_pointer);
input_line_pointer = eol;
s_lsym (int ignore ATTRIBUTE_UNUSED)
{
char *name;
- char c;
- char *p;
expressionS exp;
symbolS *symbolP;
/* We permit ANY defined expression: BSD4.2 demands constants. */
- name = input_line_pointer;
- c = get_symbol_end ();
- p = input_line_pointer;
- *p = c;
-
- if (name == p)
- {
- as_bad (_("expected symbol name"));
- ignore_rest_of_line ();
- return;
- }
-
- SKIP_WHITESPACE ();
+ if ((name = read_symbol_name ()) == NULL)
+ return;
if (*input_line_pointer != ',')
{
- *p = 0;
as_bad (_("expected comma after \"%s\""), name);
- *p = c;
- ignore_rest_of_line ();
- return;
+ goto err_out;
}
input_line_pointer++;
&& exp.X_op != O_register)
{
as_bad (_("bad expression"));
- ignore_rest_of_line ();
- return;
+ goto err_out;
}
- *p = 0;
symbolP = symbol_find_or_make (name);
if (S_GET_SEGMENT (symbolP) == undefined_section)
as_bad (_("symbol `%s' is already defined"), name);
}
- *p = c;
demand_empty_rest_of_line ();
+ free (name);
+ return;
+
+ err_out:
+ ignore_rest_of_line ();
+ free (name);
+ return;
}
/* Read a line into an sb. Returns the character that ended the line
return *input_line_pointer++;
}
-static int
+static size_t
get_non_macro_line_sb (sb *line)
{
return get_line_sb (line, 0);
}
-static int
+static size_t
get_macro_line_sb (sb *line)
{
return get_line_sb (line, 1);
as_where (&file, &line);
- sb_new (&s);
eol = find_end_of_line (input_line_pointer, 0);
+ sb_build (&s, eol - input_line_pointer);
sb_add_buffer (&s, input_line_pointer, eol - input_line_pointer);
input_line_pointer = eol;
if (line_label != NULL)
{
sb label;
+ size_t len;
- sb_new (&label);
- sb_add_string (&label, S_GET_NAME (line_label));
+ name = S_GET_NAME (line_label);
+ len = strlen (name);
+ sb_build (&label, len);
+ sb_add_buffer (&label, name, len);
err = define_macro (0, &s, &label, get_macro_line_sb, file, line, &name);
sb_kill (&label);
}
static void
do_org (segT segment, expressionS *exp, int fill)
{
- if (segment != now_seg && segment != absolute_section)
+ if (segment != now_seg
+ && segment != absolute_section
+ && segment != expr_section)
as_bad (_("invalid segment \"%s\""), segment_name (segment));
if (now_seg == absolute_section)
static void
s_bad_end (int endr)
{
- as_warn (_(".end%c encountered without preceeding %s"),
+ as_warn (_(".end%c encountered without preceding %s"),
endr ? 'r' : 'm',
endr ? ".rept, .irp, or .irpc" : ".macro");
demand_empty_rest_of_line ();
return;
}
- sb_new (&many);
+ sb_build (&many, count * one.len);
while (count-- > 0)
sb_add_sb (&many, &one);
char * sub;
sb processed;
- sb_new (& processed);
+ sb_build (& processed, one.len);
sb_add_sb (& processed, & one);
sub = strstr (processed.ptr, expander);
len = sprintf (sub, "%d", count);
if (S_IS_DEFINED (symbolP) || symbol_equated_p (symbolP))
{
- /* Permit register names to be redefined. */
if ((mode != 0 || !S_IS_VOLATILE (symbolP))
- && S_GET_SEGMENT (symbolP) != reg_section)
+ && !S_CAN_BE_REDEFINED (symbolP))
{
as_bad (_("symbol `%s' is already defined"), name);
symbolP = symbol_clone (symbolP, 0);
s_set (int equiv)
{
char *name;
- char delim;
- char *end_name;
/* Especial apologies for the random logic:
this just grew, and could be parsed much more simply!
Dean in haste. */
- name = input_line_pointer;
- delim = get_symbol_end ();
- end_name = input_line_pointer;
- *end_name = delim;
-
- if (name == end_name)
- {
- as_bad (_("expected symbol name"));
- ignore_rest_of_line ();
- return;
- }
-
- SKIP_WHITESPACE ();
+ if ((name = read_symbol_name ()) == NULL)
+ return;
if (*input_line_pointer != ',')
{
- *end_name = 0;
as_bad (_("expected comma after \"%s\""), name);
- *end_name = delim;
ignore_rest_of_line ();
+ free (name);
return;
}
input_line_pointer++;
- *end_name = 0;
-
assign_symbol (name, equiv);
- *end_name = delim;
-
demand_empty_rest_of_line ();
+ free (name);
}
void
temp = get_absolute_expression ();
subseg_set (text_section, (subsegT) temp);
demand_empty_rest_of_line ();
-#ifdef OBJ_VMS
- const_flag &= ~IN_DEFAULT_SECTION;
-#endif
}
/* .weakref x, y sets x as an alias to y that, as long as y is not
s_weakref (int ignore ATTRIBUTE_UNUSED)
{
char *name;
- char delim;
- char *end_name;
symbolS *symbolP;
symbolS *symbolP2;
expressionS exp;
- name = input_line_pointer;
- delim = get_symbol_end ();
- end_name = input_line_pointer;
-
- if (name == end_name)
- {
- as_bad (_("expected symbol name"));
- *end_name = delim;
- ignore_rest_of_line ();
- return;
- }
+ if ((name = read_symbol_name ()) == NULL)
+ return;
symbolP = symbol_find_or_make (name);
if (!S_IS_VOLATILE (symbolP))
{
as_bad (_("symbol `%s' is already defined"), name);
- *end_name = delim;
- ignore_rest_of_line ();
- return;
+ goto err_out;
}
symbolP = symbol_clone (symbolP, 1);
S_CLEAR_VOLATILE (symbolP);
}
- *end_name = delim;
-
SKIP_WHITESPACE ();
if (*input_line_pointer != ',')
{
- *end_name = 0;
as_bad (_("expected comma after \"%s\""), name);
- *end_name = delim;
- ignore_rest_of_line ();
- return;
+ goto err_out;
}
input_line_pointer++;
SKIP_WHITESPACE ();
+ free (name);
- name = input_line_pointer;
- delim = get_symbol_end ();
- end_name = input_line_pointer;
-
- if (name == end_name)
- {
- as_bad (_("expected symbol name"));
- ignore_rest_of_line ();
- return;
- }
+ if ((name = read_symbol_name ()) == NULL)
+ return;
if ((symbolP2 = symbol_find_noref (name, 1)) == NULL
&& (symbolP2 = md_undefined_symbol (name)) == NULL)
while (symp != symbolP)
{
char *old_loop = loop;
+
symp = symbol_get_value_expression (symp)->X_add_symbol;
loop = concat (loop, " => ", S_GET_NAME (symp),
(const char *) NULL);
S_GET_NAME (symbolP), loop);
free (loop);
-
- *end_name = delim;
+ free (name);
ignore_rest_of_line ();
return;
}
/* symbolP2 = symp; */
}
- *end_name = delim;
-
memset (&exp, 0, sizeof (exp));
exp.X_op = O_symbol;
exp.X_add_symbol = symbolP2;
S_SET_WEAKREFR (symbolP);
demand_empty_rest_of_line ();
+ free (name);
+ return;
+
+ err_out:
+ ignore_rest_of_line ();
+ free (name);
+ return;
}
\f
*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]]);
}
parse_mri_cons (&exp, (unsigned int) nbytes);
else
#endif
- {
+ {
if (*input_line_pointer == '"')
{
as_bad (_("unexpected `\"' in expression"));
unsigned int size;
LITTLENUM_TYPE *nums;
- know (nbytes % CHARS_PER_LITTLENUM == 0);
-
size = exp->X_add_number * CHARS_PER_LITTLENUM;
if (nbytes < size)
{
- as_warn (_("bignum truncated to %d bytes"), nbytes);
+ int i = nbytes / CHARS_PER_LITTLENUM;
+ if (i != 0)
+ {
+ LITTLENUM_TYPE sign = 0;
+ if ((generic_bignum[--i]
+ & (1 << (LITTLENUM_NUMBER_OF_BITS - 1))) != 0)
+ sign = ~(LITTLENUM_TYPE) 0;
+ while (++i < exp->X_add_number)
+ if (generic_bignum[i] != sign)
+ break;
+ }
+ if (i < exp->X_add_number)
+ as_warn (_("bignum truncated to %d bytes"), nbytes);
size = nbytes;
}
+ if (nbytes == 1)
+ {
+ md_number_to_chars (p, (valueT) generic_bignum[0], 1);
+ return;
+ }
+ know (nbytes % CHARS_PER_LITTLENUM == 0);
+
if (target_big_endian)
{
while (nbytes > size)
static segT
get_known_segmented_expression (expressionS *expP)
{
- segT retval;
+ segT retval = get_segmented_expression (expP);
- if ((retval = get_segmented_expression (expP)) == undefined_section)
+ if (retval == undefined_section)
{
/* There is no easy way to extract the undefined symbol from the
expression. */
expP->X_op = O_constant;
expP->X_add_number = 0;
}
- know (retval == absolute_section || SEG_NORMAL (retval));
- return (retval);
+ return retval;
}
char /* Return terminator. */
demand_empty_rest_of_line ();
path = (char *) xmalloc ((unsigned long) i
- + include_dir_maxlen + 5 /* slop */ );
+ + include_dir_maxlen + 5 /* slop */ );
for (i = 0; i < include_dir_count; i++)
{
demand_empty_rest_of_line ();
}
\f
+#ifdef HANDLE_BUNDLE
+
+void
+s_bundle_align_mode (int arg ATTRIBUTE_UNUSED)
+{
+ unsigned int align = get_absolute_expression ();
+ SKIP_WHITESPACE ();
+ demand_empty_rest_of_line ();
+
+ if (align > (unsigned int) TC_ALIGN_LIMIT)
+ as_fatal (_(".bundle_align_mode alignment too large (maximum %u)"),
+ (unsigned int) TC_ALIGN_LIMIT);
+
+ if (bundle_lock_frag != NULL)
+ {
+ as_bad (_("cannot change .bundle_align_mode inside .bundle_lock"));
+ return;
+ }
+
+ bundle_align_p2 = align;
+}
+
+void
+s_bundle_lock (int arg ATTRIBUTE_UNUSED)
+{
+ demand_empty_rest_of_line ();
+
+ if (bundle_align_p2 == 0)
+ {
+ as_bad (_(".bundle_lock is meaningless without .bundle_align_mode"));
+ return;
+ }
+
+ if (bundle_lock_depth == 0)
+ {
+ bundle_lock_frchain = frchain_now;
+ bundle_lock_frag = start_bundle ();
+ }
+ ++bundle_lock_depth;
+}
+
+void
+s_bundle_unlock (int arg ATTRIBUTE_UNUSED)
+{
+ unsigned int size;
+
+ demand_empty_rest_of_line ();
+
+ if (bundle_lock_frag == NULL)
+ {
+ as_bad (_(".bundle_unlock without preceding .bundle_lock"));
+ return;
+ }
+
+ gas_assert (bundle_align_p2 > 0);
+
+ gas_assert (bundle_lock_depth > 0);
+ if (--bundle_lock_depth > 0)
+ return;
+
+ size = pending_bundle_size (bundle_lock_frag);
+
+ if (size > (1U << bundle_align_p2))
+ as_bad (_(".bundle_lock sequence is %u bytes, but bundle size only %u"),
+ size, 1 << bundle_align_p2);
+ else
+ finish_bundle (bundle_lock_frag, size);
+
+ bundle_lock_frag = NULL;
+ bundle_lock_frchain = NULL;
+}
+
+#endif /* HANDLE_BUNDLE */
+\f
void
s_ignore (int arg ATTRIBUTE_UNUSED)
{
input_scrub_insert_line (const char *line)
{
sb newline;
- sb_new (&newline);
- sb_add_string (&newline, line);
+ size_t len = strlen (line);
+ sb_build (&newline, len);
+ sb_add_buffer (&newline, line, len);
input_scrub_include_sb (&newline, input_line_pointer, 0);
sb_kill (&newline);
buffer_limit = input_scrub_next_buffer (&input_line_pointer);