(s_comm): Values read are type valueT.
This commit is contained in:
parent
2fe8b7b003
commit
4032436291
745
gas/read.c
745
gas/read.c
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue