From 40324362910ee927688083d63e7b8d3341e630f9 Mon Sep 17 00:00:00 2001 From: Ken Raeburn Date: Wed, 7 Jul 1993 12:37:58 +0000 Subject: [PATCH] (s_comm): Values read are type valueT. --- gas/read.c | 745 +++++++++++++++++++++++++++++------------------------ 1 file changed, 414 insertions(+), 331 deletions(-) diff --git a/gas/read.c b/gas/read.c index d50ed86147..afe9023214 100644 --- a/gas/read.c +++ b/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()