char *input_line_pointer; /*->next char of source file to parse. */
-int generate_asm_lineno = 0; /* flag to generate line stab for .s file */
-
#if BITS_PER_CHAR != 8
/* The following table is indexed by[(char)] and will break if
a char does not have exactly 256 states (hopefully 0:255!)! */
char is_end_of_line[256] =
{
#ifdef CR_EOL
- _, _, _, _, _, _, _, _, _, _, 99, _, _, 99, _, _, /* @abcdefghijklmno */
+ 99, _, _, _, _, _, _, _, _, _, 99, _, _, 99, _, _, /* @abcdefghijklmno */
#else
- _, _, _, _, _, _, _, _, _, _, 99, _, _, _, _, _, /* @abcdefghijklmno */
+ 99, _, _, _, _, _, _, _, _, _, 99, _, _, _, _, _, /* @abcdefghijklmno */
#endif
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
#ifdef TC_HPPA
{"endif", s_endif, 0},
/* endef */
{"equ", s_set, 0},
+ {"equiv", s_set, 1},
{"err", s_err, 0},
{"exitm", s_mexit, 0},
/* extend */
/* size */
{"space", s_space, 0},
{"skip", s_space, 0},
+ {"sleb128", s_leb128, 1},
{"spc", s_ignore, 0},
{"stabd", s_stab, 'd'},
{"stabn", s_stab, 'n'},
{"title", listing_title, 0}, /* Listing title */
{"ttl", listing_title, 0},
/* type */
+ {"uleb128", s_leb128, 0},
/* use */
/* val */
{"xcom", s_comm, 0},
buffer = input_scrub_new_file (name);
listing_file (name);
- listing_newline ("");
+ listing_newline (NULL);
+ register_dependency (name);
while ((buffer_limit = input_scrub_next_buffer (&input_line_pointer)) != 0)
{ /* We have another line to parse. */
c = *input_line_pointer++;
}
know (c != ' '); /* No further leading whitespace. */
- LISTING_NEWLINE ();
+
+#ifndef NO_LISTING
+ /* If listing is on, and we are expanding a macro, then give
+ the listing code the contents of the expanded line. */
+ if (listing)
+ {
+ if ((listing & LISTING_MACEXP) && macro_nest > 0)
+ {
+ char *copy;
+ int len;
+
+ /* Find the end of the current expanded macro line. */
+ for (s = input_line_pointer-1; *s ; ++s)
+ if (is_end_of_line[(unsigned char) *s])
+ break;
+
+ /* Copy it for safe keeping. Also give an indication of
+ how much macro nesting is involved at this point. */
+ len = s - (input_line_pointer-1);
+ copy = (char *) xmalloc (len + macro_nest + 2);
+ memset (copy, '>', macro_nest);
+ copy[macro_nest] = ' ';
+ memcpy (copy + macro_nest + 1, input_line_pointer-1, len);
+ copy[macro_nest+1+len] = '\0';
+
+ /* Install the line with the listing facility. */
+ listing_newline (copy);
+ }
+ else
+ listing_newline (NULL);
+ }
+#endif
+
/*
* C is the 1st significant character.
* Input_line_pointer points after that character.
c = *input_line_pointer;
*input_line_pointer = '\0';
+ if (debug_type == DEBUG_STABS)
+ stabs_generate_asm_lineno ();
+
#ifdef OBJ_GENERATE_ASM_LINENO
- if (generate_asm_lineno == 0)
+#ifdef ECOFF_DEBUGGING
+ /* ECOFF assemblers automatically generate
+ debugging information. FIXME: This should
+ probably be handled elsewhere. */
+ if (debug_type == DEBUG_NONE)
{
- if (ecoff_no_current_file ())
- generate_asm_lineno = 1;
+ if (ecoff_no_current_file ())
+ debug_type = DEBUG_ECOFF;
}
- if (generate_asm_lineno == 1)
+
+ if (debug_type == DEBUG_ECOFF)
{
unsigned int lineno;
char *s;
as_where (&s, &lineno);
OBJ_GENERATE_ASM_LINENO (s, lineno);
- }
+ }
+#endif
#endif
if (macro_defined)
if (fill == NULL)
{
- /* FIXME: Fix this right for BFD! */
+ int maybe_text;
+
+#ifdef BFD_ASSEMBLER
+ if ((bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE) != 0)
+ maybe_text = 1;
+ else
+ maybe_text = 0;
+#else
if (now_seg != data_section && now_seg != bss_section)
+ maybe_text = 1;
+ else
+ maybe_text = 0;
+#endif
+
+ if (maybe_text)
default_fill = NOP_OPCODE;
else
default_fill = 0;
s_align (arg, 1);
}
-/* Handle the .align pseud-op on machines where ".align 4" means align
+/* Handle the .align pseudo-op on machines where ".align 4" means align
to a 2**4 boundary. */
void
*p = 0;
symbolP = symbol_find_or_make (name);
*p = c;
- if (S_IS_DEFINED (symbolP))
+ if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP))
{
as_bad ("Ignoring attempt to re-define symbol `%s'.",
S_GET_NAME (symbolP));
align = get_absolute_expression ();
}
- if (S_IS_DEFINED (sym))
+ if (S_IS_DEFINED (sym) && ! S_IS_COMMON (sym))
{
-#if defined (S_IS_COMMON) || defined (BFD_ASSEMBLER)
- if (! S_IS_COMMON (sym))
-#endif
- {
- as_bad ("attempt to re-define symbol `%s'", S_GET_NAME (sym));
- mri_comment_end (stop, stopc);
- ignore_rest_of_line ();
- return;
- }
+ as_bad ("attempt to re-define symbol `%s'", S_GET_NAME (sym));
+ mri_comment_end (stop, stopc);
+ ignore_rest_of_line ();
+ return;
}
S_SET_EXTERNAL (sym);
/* If this is a fake .appfile, a fake newline was inserted into
the buffer. Passing -2 to new_logical_line tells it to
account for it. */
- new_logical_line (s, appfile ? -2 : -1);
+ int may_omit
+ = (! new_logical_line (s, appfile ? -2 : -1) && appfile);
/* In MRI mode, the preprocessor may have inserted an extraneous
backquote. */
++input_line_pointer;
demand_empty_rest_of_line ();
+ if (! may_omit)
+ {
#ifdef LISTING
- if (listing)
- listing_source_file (s);
+ if (listing)
+ listing_source_file (s);
#endif
- }
+ register_dependency (s);
#ifdef obj_app_file
- obj_app_file (s);
+ obj_app_file (s);
#endif
+ }
+ }
}
/* Handle the .appline pseudo-op. This is automatically generated by
if (temp_size && !need_pass_2)
{
- p = frag_var (rs_fill, (int) temp_size, (int) temp_size, (relax_substateT) 0, (symbolS *) 0, temp_repeat, (char *) 0);
+ p = frag_var (rs_fill, (int) temp_size, (int) temp_size,
+ (relax_substateT) 0, (symbolS *) 0, (offsetT) temp_repeat,
+ (char *) 0);
memset (p, 0, (unsigned int) temp_size);
/* The magic number BSD_FILL_SIZE_CROCK_4 is from BSD 4.2 VAX
* flavoured AS. The following bizzare behaviour is to be
demand_empty_rest_of_line ();
}
-void
-s_lcomm (needs_align)
+static void
+s_lcomm_internal (needs_align, bytes_p)
/* 1 if this was a ".bss" directive, which may require a 3rd argument
(alignment); 0 if it was an ".lcomm" (2 args only) */
int needs_align;
+ /* 1 if the alignment value should be interpreted as the byte boundary,
+ rather than the power of 2. */
+ int bytes_p;
{
register char *name;
register char c;
return;
}
align = get_absolute_expression ();
+ if (bytes_p)
+ {
+ /* Convert to a power of 2. */
+ if (align != 0)
+ {
+ unsigned int i;
+
+ for (i = 0; (align & 1) == 0; align >>= 1, ++i)
+ ;
+ if (align != 1)
+ as_bad ("Alignment not a power of 2");
+ align = i;
+ }
+ }
if (align > max_alignment)
{
align = max_alignment;
symbolP->sy_frag = frag_now;
pfrag = frag_var (rs_org, 1, 1, (relax_substateT)0, symbolP,
- temp, (char *)0);
+ (offsetT) temp, (char *) 0);
*pfrag = 0;
S_SET_SEGMENT (symbolP, bss_seg);
subseg_set (current_seg, current_subseg);
demand_empty_rest_of_line ();
-} /* s_lcomm() */
+} /* s_lcomm_internal() */
+
+void
+s_lcomm (needs_align)
+ int needs_align;
+{
+ s_lcomm_internal (needs_align, 0);
+}
+
+void s_lcomm_bytes (needs_align)
+ int needs_align;
+{
+ s_lcomm_internal (needs_align, 1);
+}
void
s_lsym (ignore)
}
sb_add_char (line, *input_line_pointer++);
}
- while (input_line_pointer < buffer_limit && *input_line_pointer == '\n')
+ while (input_line_pointer < buffer_limit
+ && is_end_of_line[(unsigned char) *input_line_pointer])
{
if (input_line_pointer[-1] == '\n')
bump_line_counters ();
s_mexit (ignore)
int ignore;
{
+ cond_exit_macro (macro_nest);
buffer_limit = input_scrub_next_buffer (&input_line_pointer);
}
buffer_limit = input_scrub_next_buffer (&input_line_pointer);
}
+/* Handle the .equ, .equiv and .set directives. If EQUIV is 1, then
+ this is .equiv, and it is an error if the symbol is already
+ defined. */
+
void
-s_set (ignore)
- int ignore;
+s_set (equiv)
+ int equiv;
{
register char *name;
register char delim;
symbol_table_insert (symbolP);
*end_name = delim;
+
+ if (equiv
+ && S_IS_DEFINED (symbolP)
+ && S_GET_SEGMENT (symbolP) != reg_section)
+ as_bad ("symbol `%s' already defined", S_GET_NAME (symbolP));
+
pseudo_set (symbolP);
demand_empty_rest_of_line ();
} /* s_set() */
if (!need_pass_2)
p = frag_var (rs_fill, 1, 1, (relax_substateT) 0, (symbolS *) 0,
- repeat, (char *) 0);
+ (offsetT) repeat, (char *) 0);
}
else
{
}
if (!need_pass_2)
p = frag_var (rs_space, 1, 1, (relax_substateT) 0,
- make_expr_symbol (&exp), 0L, (char *) 0);
+ make_expr_symbol (&exp), (offsetT) 0, (char *) 0);
}
if (p)
if (need_pass_2)
return;
+#ifndef NO_LISTING
+#ifdef OBJ_ELF
+ /* 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;
+ }
+#endif
+#endif
+
op = exp->X_op;
/* Allow `.word 0' in the absolute section. */
demand_empty_rest_of_line ();
} /* float_cons() */
\f
+/* Return the size of a LEB128 value */
+
+static inline int
+sizeof_sleb128 (value)
+ offsetT value;
+{
+ register int size = 0;
+ register unsigned byte;
+
+ do
+ {
+ byte = (value & 0x7f);
+ /* Sadly, we cannot rely on typical arithmetic right shift behaviour.
+ Fortunately, we can structure things so that the extra work reduces
+ to a noop on systems that do things "properly". */
+ value = (value >> 7) | ~(-(offsetT)1 >> 7);
+ size += 1;
+ }
+ while (!(((value == 0) && ((byte & 0x40) == 0))
+ || ((value == -1) && ((byte & 0x40) != 0))));
+
+ return size;
+}
+
+static inline int
+sizeof_uleb128 (value)
+ valueT value;
+{
+ register int size = 0;
+ register unsigned byte;
+
+ do
+ {
+ byte = (value & 0x7f);
+ value >>= 7;
+ size += 1;
+ }
+ while (value != 0);
+
+ return size;
+}
+
+inline int
+sizeof_leb128 (value, sign)
+ valueT value;
+ int sign;
+{
+ if (sign)
+ return sizeof_sleb128 ((offsetT) value);
+ else
+ return sizeof_uleb128 (value);
+}
+
+/* Output a LEB128 value. */
+
+static inline int
+output_sleb128 (p, value)
+ char *p;
+ offsetT value;
+{
+ register char *orig = p;
+ register int more;
+
+ do
+ {
+ unsigned byte = (value & 0x7f);
+
+ /* Sadly, we cannot rely on typical arithmetic right shift behaviour.
+ Fortunately, we can structure things so that the extra work reduces
+ to a noop on systems that do things "properly". */
+ value = (value >> 7) | ~(-(offsetT)1 >> 7);
+
+ more = !((((value == 0) && ((byte & 0x40) == 0))
+ || ((value == -1) && ((byte & 0x40) != 0))));
+ if (more)
+ byte |= 0x80;
+
+ *p++ = byte;
+ }
+ while (more);
+
+ return p - orig;
+}
+
+static inline int
+output_uleb128 (p, value)
+ char *p;
+ valueT value;
+{
+ char *orig = p;
+
+ do
+ {
+ unsigned byte = (value & 0x7f);
+ value >>= 7;
+ if (value != 0)
+ /* More bytes to follow. */
+ byte |= 0x80;
+
+ *p++ = byte;
+ }
+ while (value != 0);
+
+ return p - orig;
+}
+
+inline int
+output_leb128 (p, value, sign)
+ char *p;
+ valueT value;
+ int sign;
+{
+ if (sign)
+ return output_sleb128 (p, (offsetT) value);
+ else
+ return output_uleb128 (p, value);
+}
+
+/* Do the same for bignums. We combine sizeof with output here in that
+ we don't output for NULL values of P. It isn't really as critical as
+ for "normal" values that this be streamlined. */
+
+static int
+output_big_sleb128 (p, bignum, size)
+ char *p;
+ LITTLENUM_TYPE *bignum;
+ int size;
+{
+ char *orig = p;
+ valueT val;
+ int loaded = 0;
+ unsigned byte;
+
+ /* Strip leading sign extensions off the bignum. */
+ while (size > 0 && bignum[size-1] == (LITTLENUM_TYPE)-1)
+ size--;
+
+ do
+ {
+ if (loaded < 7 && size > 0)
+ {
+ val |= (*bignum << loaded);
+ loaded += 8 * CHARS_PER_LITTLENUM;
+ size--;
+ bignum++;
+ }
+
+ byte = val & 0x7f;
+ loaded -= 7;
+ val >>= 7;
+
+ if (size == 0)
+ {
+ if ((val == 0 && (byte & 0x40) == 0)
+ || (~(val | ~(((valueT)1 << loaded) - 1)) == 0
+ && (byte & 0x40) != 0))
+ byte |= 0x80;
+ }
+
+ if (orig)
+ *p = byte;
+ p++;
+ }
+ while (byte & 0x80);
+
+ return p - orig;
+}
+
+static int
+output_big_uleb128 (p, bignum, size)
+ char *p;
+ LITTLENUM_TYPE *bignum;
+ int size;
+{
+ char *orig = p;
+ valueT val;
+ int loaded = 0;
+ unsigned byte;
+
+ /* Strip leading zeros off the bignum. */
+ /* XXX: Is this needed? */
+ while (size > 0 && bignum[size-1] == 0)
+ size--;
+
+ do
+ {
+ if (loaded < 7 && size > 0)
+ {
+ val |= (*bignum << loaded);
+ loaded += 8 * CHARS_PER_LITTLENUM;
+ size--;
+ bignum++;
+ }
+
+ byte = val & 0x7f;
+ loaded -= 7;
+ val >>= 7;
+
+ if (size > 0 || val)
+ byte |= 0x80;
+
+ if (orig)
+ *p = byte;
+ p++;
+ }
+ while (byte & 0x80);
+
+ return p - orig;
+}
+
+static inline int
+output_big_leb128 (p, bignum, size, sign)
+ char *p;
+ LITTLENUM_TYPE *bignum;
+ int size, sign;
+{
+ if (sign)
+ return output_big_sleb128 (p, bignum, size);
+ else
+ return output_big_uleb128 (p, bignum, size);
+}
+
+/* Generate the appropriate fragments for a given expression to emit a
+ leb128 value. */
+
+void
+emit_leb128_expr(exp, sign)
+ expressionS *exp;
+ int sign;
+{
+ operatorT op = exp->X_op;
+
+ if (op == O_absent || op == O_illegal)
+ {
+ as_warn ("zero assumed for missing expression");
+ exp->X_add_number = 0;
+ op = O_constant;
+ }
+ else if (op == O_big && exp->X_add_number <= 0)
+ {
+ as_bad ("floating point number invalid; zero assumed");
+ exp->X_add_number = 0;
+ op = O_constant;
+ }
+ else if (op == O_register)
+ {
+ as_warn ("register value used as expression");
+ op = O_constant;
+ }
+
+ if (op == O_constant)
+ {
+ /* If we've got a constant, emit the thing directly right now. */
+
+ valueT value = exp->X_add_number;
+ int size;
+ char *p;
+
+ size = sizeof_leb128 (value, sign);
+ p = frag_more (size);
+ output_leb128 (p, value, sign);
+ }
+ else if (op == O_big)
+ {
+ /* O_big is a different sort of constant. */
+
+ int size;
+ char *p;
+
+ size = output_big_leb128 (NULL, generic_bignum, exp->X_add_number, sign);
+ p = frag_more (size);
+ output_big_leb128 (p, generic_bignum, exp->X_add_number, sign);
+ }
+ else
+ {
+ /* Otherwise, we have to create a variable sized fragment and
+ resolve things later. */
+
+ frag_var (rs_leb128, sizeof_uleb128 (~(valueT)0), 0, sign,
+ make_expr_symbol (exp), 0, (char *) NULL);
+ }
+}
+
+/* Parse the .sleb128 and .uleb128 pseudos. */
+
+void
+s_leb128 (sign)
+ int sign;
+{
+ expressionS exp;
+
+ do {
+ expression (&exp);
+ emit_leb128_expr (&exp, sign);
+ } while (*input_line_pointer++ == ',');
+
+ input_line_pointer--;
+ demand_empty_rest_of_line ();
+}
+\f
/*
* stringer()
*
register int append_zero; /* 0: don't append '\0', else 1 */
{
register unsigned int c;
+ char *start;
#ifdef md_flush_pending_output
md_flush_pending_output ();
{
case '\"':
++input_line_pointer; /*->1st char of string. */
+ start = input_line_pointer;
while (is_a_char (c = next_char_of_string ()))
{
FRAG_APPEND_1_CHAR (c);
FRAG_APPEND_1_CHAR (0);
}
know (input_line_pointer[-1] == '\"');
+
+#ifndef NO_LISTING
+#ifdef OBJ_ELF
+ /* In ELF, when gcc is emitting DWARF 1 debugging output, it
+ will emit .string with a filename in the .debug_sfnames
+ section to indicate a file name. I don't know if this
+ will work for compilers other than gcc, and I don't know
+ if it will work for DWARF 2. */
+ if (strcmp (segment_name (now_seg), ".debug_sfnames") == 0)
+ {
+ c = input_line_pointer[-1];
+ input_line_pointer[-1] = '\0';
+ listing_source_file (start);
+ input_line_pointer[-1] = c;
+ }
+#endif
+#endif
+
break;
case '<':
input_line_pointer++;
path = filename;
gotit:
/* malloc Storage leak when file is found on path. FIXME-SOMEDAY. */
+ register_dependency (path);
newbuf = input_scrub_include_file (path, input_line_pointer);
buffer_limit = input_scrub_next_buffer (&input_line_pointer);
} /* s_include() */