X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-mmix.c;h=d3d971de8ee663dbca6cb8eef96d4fc58cb4c4b2;hb=4179a6a209f22354a605413e0de9ac10331c108b;hp=c2b3789f74856f69ad2fe1bb507a743cd7bd2640;hpb=1afc8defa6693f44bfe41ac49d62c2d6b4e62f69;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-mmix.c b/gas/config/tc-mmix.c index c2b3789f74..d3d971de8e 100644 --- a/gas/config/tc-mmix.c +++ b/gas/config/tc-mmix.c @@ -1,6 +1,5 @@ /* tc-mmix.c -- Assembler for Don Knuth's MMIX. - Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 - Free Software Foundation. + Copyright (C) 2001-2016 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -27,8 +26,8 @@ compatible syntax, but the main purpose is to serve GCC. */ -#include #include "as.h" +#include #include "subsegs.h" #include "elf/mmix.h" #include "opcode/mmix.h" @@ -40,11 +39,11 @@ for example assert something of what it became or make a relocation. */ enum mmix_fixup_action - { - mmix_fixup_byte, - mmix_fixup_register, - mmix_fixup_register_or_adjust_for_byte - }; +{ + mmix_fixup_byte, + mmix_fixup_register, + mmix_fixup_register_or_adjust_for_byte +}; static int get_spec_regno (char *); static int get_operands (int, char *, expressionS *); @@ -109,6 +108,14 @@ static struct expressionS exp; } mmix_raw_gregs[MAX_GREGS]; +static struct loc_assert_s + { + segT old_seg; + symbolS *loc_sym; + fragS *frag; + struct loc_assert_s *next; + } *loc_asserts = NULL; + /* Fixups for all unique GREG registers. We store the fixups here in md_convert_frag, then we use the array to convert BFD_RELOC_MMIX_BASE_PLUS_OFFSET fixups in tc_gen_reloc. The index is @@ -179,7 +186,7 @@ int mmix_next_semicolon_is_eoln = 1; /* Do we have a BSPEC in progress? */ static int doing_bspec = 0; -static char *bspec_file; +static const char *bspec_file; static unsigned int bspec_line; struct option md_longopts[] = @@ -388,9 +395,9 @@ const char line_comment_chars[] = "*#"; const char line_separator_chars[] = ";"; -const char mmix_exp_chars[] = "eE"; +const char EXP_CHARS[] = "eE"; -const char mmix_flt_chars[] = "rf"; +const char FLT_CHARS[] = "rf"; /* Fill in the offset-related part of GETA or Bcc. */ @@ -580,8 +587,10 @@ get_putget_operands (struct mmix_opcode *insn, char *operands, p++; sregp = p; input_line_pointer = sregp; - c = get_symbol_end (); + c = get_symbol_name (&sregp); sregend = input_line_pointer; + if (c == '"') + ++ input_line_pointer; } } else @@ -589,10 +598,10 @@ get_putget_operands (struct mmix_opcode *insn, char *operands, expp_sreg = &exp[0]; expp_reg = &exp[1]; - sregp = p; - c = get_symbol_end (); - sregend = p = input_line_pointer; - *p = c; + c = get_symbol_name (&sregp); + sregend = input_line_pointer; + restore_line_pointer (c); + p = input_line_pointer; /* Skip whitespace */ while (*p == ' ' || *p == '\t') @@ -631,7 +640,7 @@ get_putget_operands (struct mmix_opcode *insn, char *operands, /* Handle MMIX-specific option. */ int -md_parse_option (int c, char *arg ATTRIBUTE_UNUSED) +md_parse_option (int c, const char *arg ATTRIBUTE_UNUSED) { switch (c) { @@ -1365,6 +1374,9 @@ md_assemble (char *str) pass expressions as symbols and use fix_new, not fix_new_exp. */ sym = make_expr_symbol (exp + 1); + /* Mark the symbol as being OK for a reloc. */ + symbol_get_bfdsym (sym)->flags |= BSF_KEEP; + /* Now we know it can be a "base address plus offset". Add proper fixup types so we can handle this later, when we've parsed everything. */ @@ -1465,8 +1477,8 @@ md_assemble (char *str) && ((exp[1].X_op == O_register && exp[1].X_add_number < 512) || (exp[1].X_op == O_constant - && exp[1].X_add_number < 0 - && exp[1].X_add_number > 4) + && (exp[1].X_add_number < 0 + || exp[1].X_add_number > 4)) || (exp[1].X_op != O_register && exp[1].X_op != O_constant)))) { @@ -1670,7 +1682,10 @@ md_assemble (char *str) break; case mmix_operands_xyz_opt: - /* SWYM, TRIP, TRAP: zero, one, two or three operands. */ + /* SWYM, TRIP, TRAP: zero, one, two or three operands. It's + unspecified whether operands are registers or constants, but + when we find register syntax, we require operands to be literal and + within 0..255. */ if (n_operands == 0 && ! mmix_gnu_syntax) /* Zeros are in place - nothing needs to be done for zero operands. We don't allow this in GNU syntax mode, because it @@ -1681,7 +1696,7 @@ md_assemble (char *str) { if (exp[0].X_op == O_constant) { - if (exp[0].X_add_number > 255*255*255 + if (exp[0].X_add_number > 255*256*256 || exp[0].X_add_number < 0) { as_bad (_("invalid operands to opcode %s: `%s'"), @@ -1723,7 +1738,7 @@ md_assemble (char *str) if (exp[1].X_op == O_constant) { - if (exp[1].X_add_number > 255*255 + if (exp[1].X_add_number > 255*256 || exp[1].X_add_number < 0) { as_bad (_("invalid operands to opcode %s: `%s'"), @@ -1795,12 +1810,15 @@ md_assemble (char *str) fix_new_exp (opc_fragP, opcodep - opc_fragP->fr_literal + 3, 1, exp + 2, 0, BFD_RELOC_8); } - else if (n_operands <= 3 - && (strcmp (instruction->name, "trip") == 0 - || strcmp (instruction->name, "trap") == 0)) + else { - /* The meaning of operands to TRIP and TRAP are not defined, so - we add combinations not handled above here as we find them. */ + /* We can't get here for other cases. */ + gas_assert (n_operands <= 3); + + /* The meaning of operands to TRIP and TRAP is not defined (and + SWYM operands aren't enforced in mmixal, so let's avoid + that). We add combinations not handled above here as we find + them and as they're reported. */ if (n_operands == 3) { /* Don't require non-register operands. Always generate @@ -1808,49 +1826,48 @@ md_assemble (char *str) maintenance problems. TRIP is supposed to be a rare instruction, so the overhead should not matter. We aren't allowed to fix_new_exp for an expression which is - an O_register at this point, however. */ + an O_register at this point, however. + + Don't use BFD_RELOC_MMIX_REG_OR_BYTE as that modifies + the insn for a register in the Z field and we want + consistency. */ if (exp[0].X_op == O_register) opcodep[1] = exp[0].X_add_number; else fix_new_exp (opc_fragP, opcodep - opc_fragP->fr_literal + 1, - 1, exp, 0, BFD_RELOC_MMIX_REG_OR_BYTE); + 1, exp, 0, BFD_RELOC_8); if (exp[1].X_op == O_register) opcodep[2] = exp[1].X_add_number; else fix_new_exp (opc_fragP, opcodep - opc_fragP->fr_literal + 2, - 1, exp + 1, 0, BFD_RELOC_MMIX_REG_OR_BYTE); + 1, exp + 1, 0, BFD_RELOC_8); if (exp[2].X_op == O_register) opcodep[3] = exp[2].X_add_number; else fix_new_exp (opc_fragP, opcodep - opc_fragP->fr_literal + 3, - 1, exp + 2, 0, BFD_RELOC_MMIX_REG_OR_BYTE); + 1, exp + 2, 0, BFD_RELOC_8); } else if (n_operands == 2) { if (exp[0].X_op == O_register) - opcodep[2] = exp[0].X_add_number; + opcodep[1] = exp[0].X_add_number; else - fix_new_exp (opc_fragP, opcodep - opc_fragP->fr_literal + 2, - 1, exp, 0, BFD_RELOC_MMIX_REG_OR_BYTE); + fix_new_exp (opc_fragP, opcodep - opc_fragP->fr_literal + 1, + 1, exp, 0, BFD_RELOC_8); if (exp[1].X_op == O_register) opcodep[3] = exp[1].X_add_number; else - fix_new_exp (opc_fragP, opcodep - opc_fragP->fr_literal + 3, - 1, exp + 1, 0, BFD_RELOC_MMIX_REG_OR_BYTE); + fix_new_exp (opc_fragP, opcodep - opc_fragP->fr_literal + 2, + 2, exp + 1, 0, BFD_RELOC_16); } else { - as_bad (_("unsupported operands to %s: `%s'"), - instruction->name, operands); - return; + /* We can't get here for other cases. */ + gas_assert (n_operands == 1 && exp[0].X_op == O_register); + + opcodep[3] = exp[0].X_add_number; } } - else - { - as_bad (_("invalid operands to opcode %s: `%s'"), - instruction->name, operands); - return; - } break; case mmix_operands_resume: @@ -1924,10 +1941,8 @@ s_prefix (int unused ATTRIBUTE_UNUSED) SKIP_WHITESPACE (); - p = input_line_pointer; - - c = get_symbol_end (); - + c = get_symbol_name (&p); + /* Reseting prefix? */ if (*p == ':' && p[1] == 0) mmix_current_prefix = NULL; @@ -1946,7 +1961,7 @@ s_prefix (int unused ATTRIBUTE_UNUSED) mmix_current_prefix = p; } - *input_line_pointer = c; + (void) restore_line_pointer (c); mmix_handle_rest_of_empty_line (); } @@ -1986,10 +2001,11 @@ static void mmix_greg_internal (char *label) { expressionS *expP = &mmix_raw_gregs[n_of_raw_gregs].exp; + segT section; /* Don't set the section to register contents section before the expression has been parsed; it may refer to the current position. */ - expression (expP); + section = expression (expP); /* FIXME: Check that no expression refers to the register contents section. May need to be done in elf64-mmix.c. */ @@ -2003,6 +2019,24 @@ mmix_greg_internal (char *label) expP->X_op_symbol = NULL; } + if (section == undefined_section) + { + /* This is an error or a LOC with an expression involving + forward references. For the expression to be correctly + evaluated, we need to force a proper symbol; gas loses track + of the segment for "local symbols". */ + if (expP->X_op == O_add) + { + symbol_get_value_expression (expP->X_op_symbol); + symbol_get_value_expression (expP->X_add_symbol); + } + else + { + gas_assert (expP->X_op == O_symbol); + symbol_get_value_expression (expP->X_add_symbol); + } + } + /* We must handle prefixes here, as we save the labels and expressions to be output later. */ mmix_raw_gregs[n_of_raw_gregs].label @@ -2023,13 +2057,15 @@ s_greg (int unused ATTRIBUTE_UNUSED) { char *p; char c; - p = input_line_pointer; /* This will skip over what can be a symbol and zero out the next character, which we assume is a ',' or other meaningful delimiter. What comes after that is the initializer expression for the register. */ - c = get_symbol_end (); + c = get_symbol_name (&p); + + if (c == '"') + c = * ++ input_line_pointer; if (! is_end_of_line[(unsigned char) c]) input_line_pointer++; @@ -2105,7 +2141,7 @@ s_bspec (int unused ATTRIBUTE_UNUSED) subseg_set (sec, 0); /* Save position for missing ESPEC. */ - as_where (&bspec_file, &bspec_line); + bspec_file = as_where (&bspec_line); doing_bspec = 1; } @@ -2236,12 +2272,12 @@ md_estimate_size_before_relax (fragS *fragP, segT segment) emitted is stored in *sizeP . An error message is returned, or NULL on OK. */ -char * +const char * md_atof (int type, char *litP, int *sizeP) { if (type == 'r') type = 'f'; - /* FIXME: Having 'f' in mmix_flt_chars (and here) makes it + /* FIXME: Having 'f' in FLT_CHARS (and here) makes it problematic to also have a forward reference in an expression. The testsuite wants it, and it's customary. We'll deal with the real problems when they come; we share the @@ -2839,7 +2875,7 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixP) } relP = (arelent *) xmalloc (sizeof (arelent)); - assert (relP != 0); + gas_assert (relP != 0); relP->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); *relP->sym_ptr_ptr = baddsy; relP->address = fixP->fx_frag->fr_address + fixP->fx_where; @@ -2903,18 +2939,16 @@ mmix_handle_mmixal (void) caller is about to bump the counters. Adjust the error messages. */ if (is_end_of_line[(unsigned int) *s]) { - char *name; unsigned int line; - as_where (&name, &line); + const char * name = as_where (&line); as_bad_where (name, line + 1, _("[0-9]H labels may not appear alone on a line")); current_fb_label = -1; } if (*s == '.') { - char *name; unsigned int line; - as_where (&name, &line); + const char * name = as_where (&line); as_bad_where (name, line + 1, _("[0-9]H labels do not mix with dot-pseudos")); current_fb_label = -1; @@ -2939,7 +2973,7 @@ mmix_handle_mmixal (void) if (*s == 0 || is_end_of_line[(unsigned int) *s]) /* We avoid handling empty lines here. */ return; - + if (is_name_beginner (*s)) label = s; @@ -2973,7 +3007,7 @@ mmix_handle_mmixal (void) it the same alignment and address as the associated instruction. */ /* Make room for the label including the ending nul. */ - int len_0 = s - label + 1; + size_t len_0 = s - label + 1; /* Save this label on the MMIX symbol obstack. Saving it on an obstack is needless for "IS"-pseudos, but it's harmless and we @@ -3379,7 +3413,7 @@ mmix_md_relax_frag (segT seg, fragS *fragP, long stretch) fragP->fr_subtype = ENCODE_RELAX (STATE_PUSHJSTUB, STATE_ZERO); } /* FALLTHROUGH. */ - + /* See if this PUSHJ is redirectable to a stub. */ case ENCODE_RELAX (STATE_PUSHJSTUB, STATE_ZERO): { @@ -3448,6 +3482,8 @@ mmix_md_end (void) { fragS *fragP; symbolS *mainsym; + asection *regsec; + struct loc_assert_s *loc_assert; int i; /* The first frag of GREG:s going into the register contents section. */ @@ -3505,6 +3541,38 @@ mmix_md_end (void) S_SET_EXTERNAL (mainsym); } + /* Check that we didn't LOC into the unknown, or rather that when it + was unknown, we actually change sections. */ + for (loc_assert = loc_asserts; + loc_assert != NULL; + loc_assert = loc_assert->next) + { + segT actual_seg; + + resolve_symbol_value (loc_assert->loc_sym); + actual_seg = S_GET_SEGMENT (loc_assert->loc_sym); + if (actual_seg != loc_assert->old_seg) + { + const char *fnam; + unsigned int line; + int e_valid = expr_symbol_where (loc_assert->loc_sym, &fnam, &line); + + gas_assert (e_valid == 1); + as_bad_where (fnam, line, + _("LOC to section unknown or indeterminable " + "at first pass")); + + /* Patch up the generic location data to avoid cascading + error messages from later passes. (See original in + write.c:relax_segment.) */ + fragP = loc_assert->frag; + fragP->fr_type = rs_align; + fragP->fr_subtype = 0; + fragP->fr_offset = 0; + fragP->fr_fix = 0; + } + } + if (n_of_raw_gregs != 0) { /* Emit GREGs. They are collected in order of appearance, but must @@ -3512,9 +3580,9 @@ mmix_md_end (void) and the same allocation order (within a file) as mmixal. */ segT this_segment = now_seg; subsegT this_subsegment = now_subseg; - asection *regsec - = bfd_make_section_old_way (stdoutput, - MMIX_REG_CONTENTS_SECTION_NAME); + + regsec = bfd_make_section_old_way (stdoutput, + MMIX_REG_CONTENTS_SECTION_NAME); subseg_set (regsec, 0); /* Finally emit the initialization-value. Emit a variable frag, which @@ -3541,6 +3609,11 @@ mmix_md_end (void) subseg_set (this_segment, this_subsegment); } + regsec = bfd_get_section_by_name (stdoutput, MMIX_REG_CONTENTS_SECTION_NAME); + /* Mark the section symbol as being OK for a reloc. */ + if (regsec != NULL) + regsec->symbol->flags |= BSF_KEEP; + /* Iterate over frags resulting from GREGs and move those that evidently have the same value together and point one to another. @@ -3702,7 +3775,7 @@ mmix_frob_file (void) if (gregs == NULL) { - gregs = xmalloc (sizeof (*gregs)); + gregs = XNEW (struct mmix_symbol_gregs); gregs->n_gregs = 0; symbol_set_tc (sym, &gregs); all_greg_symbols[n_greg_symbols++] = gregs; @@ -3878,13 +3951,30 @@ s_loc (int ignore ATTRIBUTE_UNUSED) if (exp.X_op == O_illegal || exp.X_op == O_absent - || exp.X_op == O_big - || section == undefined_section) + || exp.X_op == O_big) { as_bad (_("invalid LOC expression")); return; } + if (section == undefined_section) + { + /* This is an error or a LOC with an expression involving + forward references. For the expression to be correctly + evaluated, we need to force a proper symbol; gas loses track + of the segment for "local symbols". */ + if (exp.X_op == O_add) + { + symbol_get_value_expression (exp.X_op_symbol); + symbol_get_value_expression (exp.X_add_symbol); + } + else + { + gas_assert (exp.X_op == O_symbol); + symbol_get_value_expression (exp.X_add_symbol); + } + } + if (section == absolute_section) { /* Translate a constant into a suitable section. */ @@ -3956,7 +4046,9 @@ s_loc (int ignore ATTRIBUTE_UNUSED) } } - if (section != now_seg) + /* If we can't deduce the section, it must be the current one. + Below, we arrange to assert this. */ + if (section != now_seg && section != undefined_section) { obj_elf_section_change_hook (); subseg_set (section, 0); @@ -3967,16 +4059,42 @@ s_loc (int ignore ATTRIBUTE_UNUSED) if (exp.X_op != O_absent) { + symbolS *esym = NULL; + if (exp.X_op != O_constant && exp.X_op != O_symbol) { /* Handle complex expressions. */ - sym = make_expr_symbol (&exp); + esym = sym = make_expr_symbol (&exp); off = 0; } else { sym = exp.X_add_symbol; off = exp.X_add_number; + + if (section == undefined_section) + { + /* We need an expr_symbol when tracking sections. In + order to make this an expr_symbol with file and line + tracked, we have to make the exp non-trivial; not an + O_symbol with .X_add_number == 0. The constant part + is unused. */ + exp.X_add_number = 1; + esym = make_expr_symbol (&exp); + } + } + + /* Track the LOC's where we couldn't deduce the section: assert + that we weren't supposed to change section. */ + if (section == undefined_section) + { + struct loc_assert_s *next = loc_asserts; + loc_asserts + = (struct loc_assert_s *) xmalloc (sizeof (*loc_asserts)); + loc_asserts->next = next; + loc_asserts->old_seg = now_seg; + loc_asserts->loc_sym = esym; + loc_asserts->frag = frag_now; } p = frag_var (rs_org, 1, 1, (relax_substateT) 0, sym, off, (char *) 0); @@ -3994,7 +4112,6 @@ static void mmix_byte (void) { unsigned int c; - char *start; if (now_seg == text_section) text_has_contents = 1; @@ -4008,7 +4125,6 @@ mmix_byte (void) { case '\"': ++input_line_pointer; - start = input_line_pointer; while (is_a_char (c = next_char_of_string ())) { FRAG_APPEND_1_CHAR (c); @@ -4084,7 +4200,6 @@ static void mmix_cons (int nbytes) { expressionS exp; - char *start; /* If we don't have any contents, then it's ok to have a specified start address that is not a multiple of the max data size. We will then @@ -4165,7 +4280,6 @@ mmix_cons (int nbytes) bytes. */ case '\"': ++input_line_pointer; - start = input_line_pointer; while (is_a_char (c = next_char_of_string ())) { exp.X_op = O_constant;