(s_comm): Values read are type valueT.

This commit is contained in:
Ken Raeburn 1993-07-07 12:37:58 +00:00
parent 2fe8b7b003
commit 4032436291
1 changed files with 414 additions and 331 deletions

View File

@ -102,8 +102,13 @@ char is_end_of_line[256] =
_, _, _, _, _, _, _, _, _, _, 99, _, _, _, _, _, /* @abcdefghijklmno */
#endif
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
#ifdef TC_HPPA
_,99, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* _!"#$%&'()*+,-./ */
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* 0123456789:;<=>? */
#else
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
_, _, _, _, _, _, _, _, _, _, _, 99, _, _, _, _, /* 0123456789:;<=>? */
#endif
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
@ -330,7 +335,6 @@ read_a_source_file (name)
register char c;
register char *s; /* string of symbol, '\0' appended */
register int temp;
/* register struct frag * fragP; JF unused *//* a frag we just made */
pseudo_typeS *pop;
buffer = input_scrub_new_file (name);
@ -768,7 +772,7 @@ s_comm ()
register char *name;
register char c;
register char *p;
register int temp;
valueT temp;
register symbolS *symbolP;
name = input_line_pointer;
@ -868,7 +872,10 @@ s_app_file (appfile)
#ifdef OBJ_COFF
c_dot_file_symbol (s);
#endif /* OBJ_COFF */
} /* s_app_file() */
#ifdef OBJ_ELF
elf_file_symbol (s);
#endif
}
/* Handle the .appline pseudo-op. This is automatically generated by
do_scrub_next_char when a preprocessor # line comment is seen.
@ -953,9 +960,9 @@ s_fill ()
void
s_globl ()
{
register char *name;
register int c;
register symbolS *symbolP;
char *name;
int c;
symbolS *symbolP;
do
{
@ -975,7 +982,7 @@ s_globl ()
}
while (c == ',');
demand_empty_rest_of_line ();
} /* s_globl() */
}
void
s_lcomm (needs_align)
@ -1549,6 +1556,39 @@ pseudo_set (symbolP)
* in the case of a long. Not worth the crocks required to fix it.
*/
/* Select a parser for cons expressions. */
/* 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. */
#ifndef TC_PARSE_CONS_EXPRESSION
#ifdef BITFIELD_CONS_EXPRESSIONS
#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) parse_bitfield_cons (EXP, NBYTES)
static void
parse_bitfield_cons PARAMS ((expressionS *exp, unsigned int nbytes));
#endif
#ifdef MRI
#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) parse_mri_cons (EXP)
static void
parse_mri_cons PARAMS ((expressionS *exp));
#endif
#ifdef REPEAT_CONS_EXPRESSIONS
#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) parse_repeat_cons (EXP, NBYTES)
static void
parse_repeat_cons PARAMS ((expressionS *exp, unsigned int nbytes));
#endif
/* If we haven't gotten one yet, just call expression. */
#ifndef TC_PARSE_CONS_EXPRESSION
#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) expression (EXP)
#endif
#endif
/* worker to do .byte etc statements */
/* clobbers input_line_pointer, checks */
/* end-of-line. */
@ -1556,340 +1596,383 @@ void
cons (nbytes)
register unsigned int nbytes; /* 1=.byte, 2=.word, 4=.long */
{
register char c;
register long mask; /* High-order bits we will left-truncate, */
/* but includes sign bit also. */
register long get; /* what we get */
register long use; /* get after truncation. */
register long unmask; /* what bits we will store */
register char *p;
register segT segment;
expressionS exp;
/*
* Input_line_pointer->1st char after pseudo-op-code and could legally
* be a end-of-line. (Or, less legally an eof - which we cope with.)
*/
/* JF << of >= number of bits in the object is undefined. In particular
SPARC (Sun 4) has problems */
if (nbytes >= sizeof (long))
{
mask = 0;
}
else
{
mask = ~0 << (BITS_PER_CHAR * nbytes); /* Don't store these bits. */
} /* bigger than a long */
unmask = ~mask; /* Do store these bits. */
#ifdef NEVER
"Do this mod if you want every overflow check to assume SIGNED 2's complement data.";
mask = ~(unmask >> 1); /* Includes sign bit now. */
#endif
/*
* The following awkward logic is to parse ZERO or more expressions,
* comma seperated. Recall an expression includes its leading &
* trailing blanks. We fake a leading ',' if there is (supposed to
* be) a 1st expression, and keep demanding 1 expression for each ','.
*/
if (is_it_end_of_statement ())
{
c = 0; /* Skip loop. */
input_line_pointer++; /* Matches end-of-loop 'correction'. */
demand_empty_rest_of_line ();
return;
}
else
do
{
c = ',';
} /* if the end else fake it */
TC_PARSE_CONS_EXPRESSION (&exp, nbytes);
emit_expr (&exp, nbytes);
}
while (*input_line_pointer++ == ',');
/* Do loop. */
while (c == ',')
{
#ifdef WANT_BITFIELDS
unsigned int bits_available = BITS_PER_CHAR * nbytes;
/* used for error messages and rescanning */
char *hold = input_line_pointer;
#endif /* WANT_BITFIELDS */
#ifdef MRI
if (*input_line_pointer == '\'')
{
/* An MRI style string, cut into as many bytes as will fit
into a nbyte chunk, left justify if necessary, and sepatate
with commas so we can try again later */
int scan = 0;
unsigned int result = 0;
input_line_pointer++;
for (scan = 0; scan < nbytes; scan++)
{
if (*input_line_pointer == '\'')
{
if (input_line_pointer[1] == '\'')
{
input_line_pointer++;
}
else
break;
}
result = (result << 8) | (*input_line_pointer++);
}
/* Left justify */
while (scan < nbytes)
{
result <<= 8;
scan++;
}
/* Create correct expression */
exp.X_add_symbol = 0;
exp.X_add_number = result;
exp.X_seg = segment = absolute_section;
/* Fake it so that we can read the next char too */
if (input_line_pointer[0] != '\'' ||
(input_line_pointer[0] == '\'' && input_line_pointer[1] == '\''))
{
input_line_pointer -= 2;
input_line_pointer[0] = ',';
input_line_pointer[1] = '\'';
}
else
input_line_pointer++;
}
else
#endif
/* At least scan over the expression. */
segment = expression (&exp);
#ifdef WANT_BITFIELDS
/* Some other 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 significat 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".
FIXME-SOMEDAY: If this is considered generally
useful, this logic should probably be reworked.
xoxorich. */
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 (segment == absent_section)
{
as_warn ("Using a bit field width of zero.");
exp.X_add_number = 0;
segment = absolute_section;
} /* implied zero width bitfield */
if (segment != absolute_section)
{
*input_line_pointer = '\0';
as_bad ("Field width \"%s\" too complex for a bitfield.\n", 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 %d 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 */
hold = ++input_line_pointer; /* skip ':' */
if ((segment = expression (&exp)) != absolute_section)
{
char cache = *input_line_pointer;
*input_line_pointer = '\0';
as_bad ("Field value \"%s\" too complex for a bitfield.\n", 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;
segment = expression (&exp);
} /* forever loop */
exp.X_add_number = value;
segment = absolute_section;
} /* if looks like a bitfield */
#endif /* WANT_BITFIELDS */
if (!need_pass_2)
{ /* Still worthwhile making frags. */
/* Don't call this if we are going to junk this pass anyway! */
know (segment != pass1_section);
if (segment == diff_section && exp.X_add_symbol == NULL)
{
as_bad ("Subtracting symbol \"%s\"(segment\"%s\") is too hard. Absolute segment assumed.",
S_GET_NAME (exp.X_subtract_symbol),
segment_name (S_GET_SEGMENT (exp.X_subtract_symbol)));
segment = absolute_section;
/* Leave exp . X_add_number alone. */
}
p = frag_more (nbytes);
if (segment == big_section)
{
as_bad ("%s number invalid. Absolute 0 assumed.",
exp.X_add_number > 0 ? "Bignum" : "Floating-Point");
md_number_to_chars (p, (long) 0, nbytes);
}
else if (segment == absent_section)
{
as_warn ("0 assumed for missing expression");
exp.X_add_number = 0;
know (exp.X_add_symbol == NULL);
goto abs_sec;
}
else if (segment == absolute_section)
{
abs_sec:
get = exp.X_add_number;
use = get & unmask;
if ((get & mask) && (get & mask) != mask)
{ /* Leading bits contain both 0s & 1s. */
as_warn ("Value 0x%x truncated to 0x%x.", get, use);
}
md_number_to_chars (p, use, nbytes); /* put bytes in right order. */
}
else if (segment == diff_section)
{
#ifndef WORKING_DOT_WORD
if (nbytes == 2)
{
struct broken_word *x;
x = (struct broken_word *) xmalloc (sizeof (struct broken_word));
x->next_broken_word = broken_words;
broken_words = x;
x->frag = frag_now;
x->word_goes_here = p;
x->dispfrag = 0;
x->add = exp.X_add_symbol;
x->sub = exp.X_subtract_symbol;
x->addnum = exp.X_add_number;
x->added = 0;
new_broken_words++;
goto after_switch;
}
#endif
goto defalt;
}
else
/* undefined_section, others */
{
defalt:
md_number_to_chars (p, (long) 0, nbytes);
#ifdef BFD_ASSEMBLER
fix_new (frag_now, p - frag_now->fr_literal, nbytes,
exp.X_add_symbol, exp.X_subtract_symbol,
exp.X_add_number, 0,
/* @@ Should look at CPU word size. */
BFD_RELOC_32);
#else
#ifdef TC_NS32K
fix_new_ns32k (frag_now, p - frag_now->fr_literal, nbytes,
exp.X_add_symbol, exp.X_subtract_symbol,
exp.X_add_number, 0, 0, 2, 0, 0);
#else
#if defined(TC_SPARC) || defined(TC_A29K)
fix_new (frag_now, p - frag_now->fr_literal, nbytes,
exp.X_add_symbol, exp.X_subtract_symbol,
exp.X_add_number, 0, RELOC_32);
#else
#if defined(TC_H8300)
fix_new (frag_now, p - frag_now->fr_literal, nbytes,
exp.X_add_symbol, exp.X_subtract_symbol,
exp.X_add_number, 0, R_RELWORD);
#else
#ifdef NO_RELOC
fix_new (frag_now, p - frag_now->fr_literal, nbytes,
exp.X_add_symbol, exp.X_subtract_symbol,
exp.X_add_number, 0, NO_RELOC);
#else
fix_new (frag_now, p - frag_now->fr_literal, nbytes,
exp.X_add_symbol, exp.X_subtract_symbol,
exp.X_add_number, 0, 0);
#endif /* NO_RELOC */
#endif /* tc_h8300 */
#endif /* tc_sparc|tc_a29k */
#endif /* TC_NS32K */
#endif /* BFD_ASSEMBLER */
} /* switch(segment) */
after_switch:
;
} /* if (!need_pass_2) */
c = *input_line_pointer++;
} /* while(c==',') */
input_line_pointer--; /* Put terminator back into stream. */
demand_empty_rest_of_line ();
} /* cons() */
/* Put the contents of expression EXP into the object file using
NBYTES bytes. If need_pass_2 is 1, this does nothing. */
void
emit_expr (exp, nbytes)
expressionS *exp;
unsigned int nbytes;
{
segT segment;
register char *p;
/* Don't do anything if we are going to make another pass. */
if (need_pass_2)
return;
segment = exp->X_seg;
/* Don't call this if we are going to junk this pass anyway! */
know (segment != pass1_section);
if (segment == diff_section && exp->X_add_symbol == NULL)
{
as_bad ("Subtracting symbol \"%s\" (segment \"%s\") is too hard. Absolute segment assumed.",
S_GET_NAME (exp->X_subtract_symbol),
segment_name (S_GET_SEGMENT (exp->X_subtract_symbol)));
segment = absolute_section;
/* Leave exp->X_add_number alone. */
}
else if (segment == absent_section)
{
as_warn ("0 assumed for missing expression");
exp->X_add_number = 0;
know (exp->X_add_symbol == NULL);
segment = absolute_section;
}
else if (segment == big_section)
{
as_bad ("%s number invalid. Absolute 0 assumed.",
exp->X_add_number > 0 ? "Bignum" : "Floating-Point");
exp->X_add_number = 0;
segment = absolute_section;
}
p = frag_more (nbytes);
#ifndef WORKING_DOT_WORD
/* If we have the difference of two symbols in a word, save it on
the broken_words list. See the code in write.c. */
if (segment == diff_section && nbytes == 2)
{
struct broken_word *x;
x = (struct broken_word *) xmalloc (sizeof (struct broken_word));
x->next_broken_word = broken_words;
broken_words = x;
x->frag = frag_now;
x->word_goes_here = p;
x->dispfrag = 0;
x->add = exp->X_add_symbol;
x->sub = exp->X_subtract_symbol;
x->addnum = exp->X_add_number;
x->added = 0;
new_broken_words++;
return;
}
#endif
if (segment == absolute_section)
{
register long get;
register long use;
register long mask;
register long unmask;
/* JF << of >= number of bits in the object is undefined. In
particular SPARC (Sun 4) has problems */
if (nbytes >= sizeof (long))
mask = 0;
else
mask = ~0 << (BITS_PER_CHAR * nbytes); /* Don't store these bits. */
unmask = ~mask; /* Do store these bits. */
#ifdef NEVER
"Do this mod if you want every overflow check to assume SIGNED 2's complement data.";
mask = ~(unmask >> 1); /* Includes sign bit now. */
#endif
get = exp->X_add_number;
use = get & unmask;
if ((get & mask) != 0 && (get & mask) != mask)
{ /* Leading bits contain both 0s & 1s. */
as_warn ("Value 0x%x truncated to 0x%x.", get, use);
}
md_number_to_chars (p, use, nbytes); /* put bytes in right order. */
}
else
{
md_number_to_chars (p, (long) 0, nbytes);
/* Now we need to generate a fixS to record the symbol value.
This is easy for BFD. For other targets it can be more
complex. For very complex cases (currently, the HPPA and
NS32K), you can define TC_CONS_FIX_NEW to do whatever you
want. For simpler cases, you can define TC_CONS_RELOC to be
the name of the reloc code that should be stored in the fixS.
If neither is defined, the code uses NO_RELOC if it is
defined, and otherwise uses 0. */
#ifdef BFD_ASSEMBLER
fix_new (frag_now, p - frag_now->fr_literal, nbytes,
exp->X_add_symbol, exp->X_subtract_symbol,
exp->X_add_number, 0,
/* @@ Should look at CPU word size. */
BFD_RELOC_32);
#else
#ifdef TC_CONS_FIX_NEW
TC_CONS_FIX_NEW (frag_now, p - frag_now->fr_literal, nbytes, exp);
#else
/* Figure out which reloc number to use. Use TC_CONS_RELOC if
it is defined, otherwise use NO_RELOC if it is defined,
otherwise use 0. */
#ifndef TC_CONS_RELOC
#ifdef NO_RELOC
#define TC_CONS_RELOC NO_RELOC
#else
#define TC_CONS_RELOC 0
#endif
#endif
fix_new (frag_now, p - frag_now->fr_literal, nbytes,
exp->X_add_symbol, exp->X_subtract_symbol,
exp->X_add_number, 0, TC_CONS_RELOC);
#endif /* TC_CONS_FIX_NEW */
#endif /* BFD_ASSEMBLER */
}
}
#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 significat bit first, if a field doesn't
entirely fit, put it in the next unit. Overflowing the bitfield is
explicitly *not* even a warning. The bitwidth should be considered
a "mask".
To use this function the tc-XXX.h file should define
BITFIELD_CONS_EXPRESSIONS. */
static void
parse_bitfield_cons (exp, nbytes)
expressionS *exp;
unsigned int nbytes;
{
unsigned int bits_available = BITS_PER_CHAR * nbytes;
char *hold = input_line_pointer;
segT segment;
segment = 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 (segment == absent_section)
{
as_warn ("Using a bit field width of zero.");
exp->X_add_number = 0;
segment = absolute_section;
} /* implied zero width bitfield */
if (segment != absolute_section)
{
*input_line_pointer = '\0';
as_bad ("Field width \"%s\" too complex for a bitfield.\n", 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 %d 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 */
hold = ++input_line_pointer; /* skip ':' */
if ((segment = expression (exp)) != absolute_section)
{
char cache = *input_line_pointer;
*input_line_pointer = '\0';
as_bad ("Field value \"%s\" too complex for a bitfield.\n", 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;
segment = expression (exp);
} /* forever loop */
exp->X_add_number = value;
exp->X_seg = absolute_section;
} /* if looks like a bitfield */
} /* parse_bitfield_cons() */
#endif /* BITFIELD_CONS_EXPRESSIONS */
#ifdef MRI
static void
parse_mri_cons (exp, nbytes)
expressionS *exp;
unsigned int nbytes;
{
if (*input_line_pointer == '\'')
{
/* An MRI style string, cut into as many bytes as will fit into
a nbyte chunk, left justify if necessary, and separate with
commas so we can try again later */
int scan = 0;
unsigned int result = 0;
input_line_pointer++;
for (scan = 0; scan < nbytes; scan++)
{
if (*input_line_pointer == '\'')
{
if (input_line_pointer[1] == '\'')
{
input_line_pointer++;
}
else
break;
}
result = (result << 8) | (*input_line_pointer++);
}
/* Left justify */
while (scan < nbytes)
{
result <<= 8;
scan++;
}
/* Create correct expression */
exp->X_add_symbol = 0;
exp->X_add_number = result;
exp->X_seg = absolute_section;
/* Fake it so that we can read the next char too */
if (input_line_pointer[0] != '\'' ||
(input_line_pointer[0] == '\'' && input_line_pointer[1] == '\''))
{
input_line_pointer -= 2;
input_line_pointer[0] = ',';
input_line_pointer[1] = '\'';
}
else
input_line_pointer++;
}
else
expression (&exp);
}
#endif /* MRI */
#ifdef REPEAT_CONS_EXPRESSIONS
/* Parse a repeat expression for cons. This is used by the MIPS
assembler. The format is NUMBER:COUNT; NUMBER appears in the
object file COUNT times.
To use this for a target, define REPEAT_CONS_EXPRESSIONS. */
static void
parse_repeat_cons (exp, nbytes)
expressionS *exp;
unsigned int nbytes;
{
expressionS count;
segT segment;
register int i;
expression (exp);
if (*input_line_pointer != ':')
{
/* No repeat count. */
return;
}
++input_line_pointer;
segment = expression (&count);
if (segment != absolute_section
|| count.X_add_number <= 0)
{
as_warn ("Unresolvable or nonpositive repeat count; using 1");
return;
}
/* The cons function is going to output this expression once. So we
output it count - 1 times. */
for (i = count.X_add_number - 1; i > 0; i--)
emit_expr (exp, nbytes);
}
#endif /* REPEAT_CONS_EXPRESSIONS */
/*
* big_cons()