X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-mmix.c;h=1514b6d0607d41a4e57afefa20e0d05e37eb2075;hb=508559397632e046a1f734f27d2b1971b1d172d1;hp=acd932196377deca7470c77fd5d74e5e65ee88b0;hpb=7e1792e01868240492e505a95a5e00db00d51f3c;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-mmix.c b/gas/config/tc-mmix.c index acd9321963..1514b6d060 100644 --- a/gas/config/tc-mmix.c +++ b/gas/config/tc-mmix.c @@ -1,11 +1,11 @@ /* tc-mmix.c -- Assembler for Don Knuth's MMIX. - Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation. + Copyright (C) 2001-2019 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. GAS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) + the Free Software Foundation; either version 3, or (at your option) any later version. GAS is distributed in the hope that it will be useful, @@ -15,8 +15,8 @@ You should have received a copy of the GNU General Public License along with GAS; see the file COPYING. If not, write to - the Free Software Foundation, 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ + the Free Software Foundation, 51 Franklin Street - Fifth Floor, + Boston, MA 02110-1301, USA. */ /* Knuth's assembler mmixal does not provide a relocatable format; mmo is to be considered a final link-format. In the final link, we make mmo, @@ -26,11 +26,9 @@ compatible syntax, but the main purpose is to serve GCC. */ -#include -#include #include "as.h" +#include #include "subsegs.h" -#include "bfd.h" #include "elf/mmix.h" #include "opcode/mmix.h" #include "safe-ctype.h" @@ -41,33 +39,31 @@ 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 PARAMS ((char *)); -static int get_operands PARAMS ((int, char *, expressionS[])); -static int get_putget_operands - PARAMS ((struct mmix_opcode *, char *, expressionS[])); -static void s_prefix PARAMS ((int)); -static void s_greg PARAMS ((int)); -static void s_loc PARAMS ((int)); -static void s_bspec PARAMS ((int)); -static void s_espec PARAMS ((int)); -static void mmix_s_local PARAMS ((int)); -static void mmix_greg_internal PARAMS ((char *)); -static void mmix_set_geta_branch_offset PARAMS ((char *, offsetT value)); -static void mmix_set_jmp_offset PARAMS ((char *, offsetT)); -static void mmix_fill_nops PARAMS ((char *, int)); -static int cmp_greg_symbol_fixes PARAMS ((const PTR, const PTR)); -static int cmp_greg_val_greg_symbol_fixes - PARAMS ((const PTR p1, const PTR p2)); -static void mmix_handle_rest_of_empty_line PARAMS ((void)); -static void mmix_discard_rest_of_line PARAMS ((void)); -static void mmix_byte PARAMS ((void)); -static void mmix_cons PARAMS ((int)); +static int get_spec_regno (char *); +static int get_operands (int, char *, expressionS *); +static int get_putget_operands (struct mmix_opcode *, char *, expressionS *); +static void s_prefix (int); +static void s_greg (int); +static void s_loc (int); +static void s_bspec (int); +static void s_espec (int); +static void mmix_s_local (int); +static void mmix_greg_internal (char *); +static void mmix_set_geta_branch_offset (char *, offsetT); +static void mmix_set_jmp_offset (char *, offsetT); +static void mmix_fill_nops (char *, int); +static int cmp_greg_symbol_fixes (const void *, const void *); +static int cmp_greg_val_greg_symbol_fixes (const void *, const void *); +static void mmix_handle_rest_of_empty_line (void); +static void mmix_discard_rest_of_line (void); +static void mmix_byte (void); +static void mmix_cons (int); /* Continue the tradition of symbols.c; use control characters to enforce magic. These are used when replacing e.g. 8F and 8B so we can handle @@ -112,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 @@ -182,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[] = @@ -301,22 +305,9 @@ struct obstack mmix_sym_obstack; #define PUSHJ_4B GETA_3B /* We'll very rarely have sections longer than LONG_MAX, but we'll make a - feeble attempt at getting 64-bit C99 or gcc-specific values (assuming - long long is 64 bits on the host). */ -#ifdef LLONG_MIN -#define PUSHJSTUB_MIN LLONG_MIN -#elif defined (LONG_LONG_MIN) -#define PUSHJSTUB_MIN LONG_LONG_MIN -#else -#define PUSHJSTUB_MIN LONG_MIN -#endif -#ifdef LLONG_MAX -#define PUSHJSTUB_MAX LLONG_MAX -#elif defined (LONG_LONG_MAX) -#define PUSHJSTUB_MAX LONG_LONG_MAX -#else -#define PUSHJSTUB_MAX LONG_MAX -#endif + feeble attempt at getting 64-bit values. */ +#define PUSHJSTUB_MAX ((offsetT) (((addressT) -1) >> 1)) +#define PUSHJSTUB_MIN (-PUSHJSTUB_MAX - 1) #define JMP_0F (65536 * 256 * 4 - 8) #define JMP_0B (-65536 * 256 * 4 - 4) @@ -404,17 +395,15 @@ 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. */ static void -mmix_set_geta_branch_offset (opcodep, value) - char *opcodep; - offsetT value; +mmix_set_geta_branch_offset (char *opcodep, offsetT value) { if (value < 0) { @@ -429,9 +418,7 @@ mmix_set_geta_branch_offset (opcodep, value) /* Fill in the offset-related part of JMP. */ static void -mmix_set_jmp_offset (opcodep, value) - char *opcodep; - offsetT value; +mmix_set_jmp_offset (char *opcodep, offsetT value) { if (value < 0) { @@ -446,9 +433,7 @@ mmix_set_jmp_offset (opcodep, value) /* Fill in NOP:s for the expanded part of GETA/JMP/Bcc/PUSHJ. */ static void -mmix_fill_nops (opcodep, n) - char *opcodep; - int n; +mmix_fill_nops (char *opcodep, int n) { int i; @@ -459,9 +444,7 @@ mmix_fill_nops (opcodep, n) /* See macro md_parse_name in tc-mmix.h. */ int -mmix_current_location (fn, exp) - void (*fn) PARAMS ((expressionS *)); - expressionS *exp; +mmix_current_location (void (*fn) (expressionS *), expressionS *exp) { (*fn) (exp); @@ -472,10 +455,7 @@ mmix_current_location (fn, exp) General idea and code stolen from the tic80 port. */ static int -get_operands (max_operands, s, exp) - int max_operands; - char *s; - expressionS exp[]; +get_operands (int max_operands, char *s, expressionS *exp) { char *p = s; int numexp = 0; @@ -541,8 +521,7 @@ get_operands (max_operands, s, exp) one. NAME is a null-terminated string. */ static int -get_spec_regno (name) - char *name; +get_spec_regno (char *name) { int i; @@ -564,10 +543,8 @@ get_spec_regno (name) /* For GET and PUT, parse the register names "manually", so we don't use user labels. */ static int -get_putget_operands (insn, operands, exp) - struct mmix_opcode *insn; - char *operands; - expressionS exp[]; +get_putget_operands (struct mmix_opcode *insn, char *operands, + expressionS *exp) { expressionS *expp_reg; expressionS *expp_sreg; @@ -610,8 +587,10 @@ get_putget_operands (insn, operands, exp) 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 @@ -619,10 +598,10 @@ get_putget_operands (insn, operands, exp) 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') @@ -661,9 +640,7 @@ get_putget_operands (insn, operands, exp) /* Handle MMIX-specific option. */ int -md_parse_option (c, arg) - int c; - char *arg ATTRIBUTE_UNUSED; +md_parse_option (int c, const char *arg ATTRIBUTE_UNUSED) { switch (c) { @@ -720,8 +697,7 @@ md_parse_option (c, arg) /* Display MMIX-specific help text. */ void -md_show_usage (stream) - FILE * stream; +md_show_usage (FILE * stream) { fprintf (stream, _(" MMIX-specific command line options:\n")); fprintf (stream, _("\ @@ -754,7 +730,7 @@ md_show_usage (stream) /* Step to end of line, but don't step over the end of the line. */ static void -mmix_discard_rest_of_line () +mmix_discard_rest_of_line (void) { while (*input_line_pointer && (! is_end_of_line[(unsigned char) *input_line_pointer] @@ -767,7 +743,7 @@ mmix_discard_rest_of_line () delimiter). */ static void -mmix_handle_rest_of_empty_line () +mmix_handle_rest_of_empty_line (void) { if (mmix_gnu_syntax) demand_empty_rest_of_line (); @@ -781,7 +757,7 @@ mmix_handle_rest_of_empty_line () /* Initialize GAS MMIX specifics. */ void -mmix_md_begin () +mmix_md_begin (void) { int i; const struct mmix_opcode *opcode; @@ -840,8 +816,7 @@ mmix_md_begin () /* Assemble one insn in STR. */ void -md_assemble (str) - char *str; +md_assemble (char *str) { char *operands = str; char modified_char = 0; @@ -1399,6 +1374,9 @@ md_assemble (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. */ @@ -1499,8 +1477,8 @@ md_assemble (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)))) { @@ -1704,7 +1682,10 @@ md_assemble (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 @@ -1715,7 +1696,7 @@ md_assemble (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'"), @@ -1757,7 +1738,7 @@ md_assemble (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'"), @@ -1829,12 +1810,15 @@ md_assemble (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 @@ -1842,49 +1826,48 @@ md_assemble (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: @@ -1922,8 +1905,7 @@ md_assemble (str) tc_unrecognized_line too, through this function. */ int -mmix_assemble_return_nonzero (str) - char *str; +mmix_assemble_return_nonzero (char *str) { int last_error_count = had_errors (); char *s2 = str; @@ -1952,19 +1934,16 @@ mmix_assemble_return_nonzero (str) /* The PREFIX pseudo. */ static void -s_prefix (unused) - int unused ATTRIBUTE_UNUSED; +s_prefix (int unused ATTRIBUTE_UNUSED) { char *p; int c; SKIP_WHITESPACE (); - p = input_line_pointer; - - c = get_symbol_end (); - - /* Reseting prefix? */ + c = get_symbol_name (&p); + + /* Resetting prefix? */ if (*p == ':' && p[1] == 0) mmix_current_prefix = NULL; else @@ -1982,7 +1961,7 @@ s_prefix (unused) mmix_current_prefix = p; } - *input_line_pointer = c; + (void) restore_line_pointer (c); mmix_handle_rest_of_empty_line (); } @@ -1995,8 +1974,7 @@ s_prefix (unused) that. (It might be worth a rewrite for other reasons, though). */ char * -mmix_prefix_name (shortname) - char *shortname; +mmix_prefix_name (char *shortname) { if (*shortname == ':') return shortname + 1; @@ -2020,14 +1998,14 @@ mmix_prefix_name (shortname) be persistent, perhaps allocated on an obstack. */ static void -mmix_greg_internal (label) - char *label; +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. */ @@ -2041,6 +2019,24 @@ mmix_greg_internal (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 @@ -2057,18 +2053,19 @@ mmix_greg_internal (label) /* The ".greg label,expr" worker. */ static void -s_greg (unused) - int unused ATTRIBUTE_UNUSED; +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++; @@ -2087,8 +2084,7 @@ s_greg (unused) /* The "BSPEC expr" worker. */ static void -s_bspec (unused) - int unused ATTRIBUTE_UNUSED; +s_bspec (int unused ATTRIBUTE_UNUSED) { asection *expsec; asection *sec; @@ -2134,9 +2130,8 @@ s_bspec (unused) if (sec == NULL) as_fatal (_("can't create section %s"), newsecname); - if (!bfd_set_section_flags (stdoutput, sec, - bfd_get_section_flags (stdoutput, sec) - | SEC_READONLY)) + if (!bfd_set_section_flags (sec, + bfd_section_flags (sec) | SEC_READONLY)) as_fatal (_("can't set section flags for section %s"), newsecname); } @@ -2145,7 +2140,7 @@ s_bspec (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; } @@ -2153,8 +2148,7 @@ s_bspec (unused) /* The "ESPEC" worker. */ static void -s_espec (unused) - int unused ATTRIBUTE_UNUSED; +s_espec (int unused ATTRIBUTE_UNUSED) { /* First, check that we *do* have a BSPEC in progress. */ if (! doing_bspec) @@ -2177,8 +2171,7 @@ s_espec (unused) Implementing this by means of contents in a section lost. */ static void -mmix_s_local (unused) - int unused ATTRIBUTE_UNUSED; +mmix_s_local (int unused ATTRIBUTE_UNUSED) { expressionS exp; @@ -2208,9 +2201,7 @@ mmix_s_local (unused) function may be called multiple times. */ int -md_estimate_size_before_relax (fragP, segment) - fragS *fragP; - segT segment; +md_estimate_size_before_relax (fragS *fragP, segT segment) { int length; @@ -2280,57 +2271,24 @@ md_estimate_size_before_relax (fragP, segment) emitted is stored in *sizeP . An error message is returned, or NULL on OK. */ -char * -md_atof (type, litP, sizeP) - int type; - char *litP; - int *sizeP; +const char * +md_atof (int type, char *litP, int *sizeP) { - int prec; - LITTLENUM_TYPE words[4]; - char *t; - int i; - - switch (type) - { - /* FIXME: Having 'f' in mmix_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 - problem with most other ports. */ - case 'f': - case 'r': - prec = 2; - break; - case 'd': - prec = 4; - break; - default: - *sizeP = 0; - return _("bad call to md_atof"); - } - - t = atof_ieee (input_line_pointer, type, words); - if (t) - input_line_pointer = t; - - *sizeP = prec * 2; - - for (i = 0; i < prec; i++) - { - md_number_to_chars (litP, (valueT) words[i], 2); - litP += 2; - } - return NULL; + if (type == 'r') + type = 'f'; + /* 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 + problem with most other ports. */ + return ieee_md_atof (type, litP, sizeP, TRUE); } /* Convert variable-sized frags into one or more fixups. */ void -md_convert_frag (abfd, sec, fragP) - bfd *abfd ATTRIBUTE_UNUSED; - segT sec ATTRIBUTE_UNUSED; - fragS *fragP; +md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT sec ATTRIBUTE_UNUSED, + fragS *fragP) { /* Pointer to first byte in variable-sized part of the frag. */ char *var_partp; @@ -2413,7 +2371,7 @@ md_convert_frag (abfd, sec, fragP) if (fragP->tc_frag_data == NULL) { /* We must initialize data that's supposed to be "fixed up" to - avoid emitting garbage, because md_apply_fix3 won't do + avoid emitting garbage, because md_apply_fix won't do anything for undefined symbols. */ md_number_to_chars (var_partp, 0, 8); tmpfixP @@ -2461,10 +2419,7 @@ md_convert_frag (abfd, sec, fragP) Note that this function isn't called when linkrelax != 0. */ void -md_apply_fix3 (fixP, valP, segment) - fixS * fixP; - valueT * valP; - segT segment; +md_apply_fix (fixS *fixP, valueT *valP, segT segment) { char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; /* Note: use offsetT because it is signed, valueT is unsigned. */ @@ -2638,9 +2593,7 @@ md_apply_fix3 (fixP, valP, segment) definitions. */ static int -cmp_greg_val_greg_symbol_fixes (p1, p2) - const PTR p1; - const PTR p2; +cmp_greg_val_greg_symbol_fixes (const void *p1, const void *p2) { offsetT val1 = *(offsetT *) p1; offsetT val2 = ((struct mmix_symbol_greg_fixes *) p2)->offs; @@ -2657,9 +2610,7 @@ cmp_greg_val_greg_symbol_fixes (p1, p2) /* Generate a machine-dependent relocation. */ arelent * -tc_gen_reloc (section, fixP) - asection *section ATTRIBUTE_UNUSED; - fixS *fixP; +tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixP) { bfd_signed_vma val = fixP->fx_offset @@ -2686,7 +2637,7 @@ tc_gen_reloc (section, fixP) than just helping the user around this limitation here; hopefully the code using the local expression is around. Putting the LOCAL semantics in a relocation still seems right; a section didn't do. */ - if (bfd_section_size (section->owner, section) == 0) + if (bfd_section_size (section) == 0) as_bad_where (fixP->fx_file, fixP->fx_line, fixP->fx_r_type == BFD_RELOC_MMIX_LOCAL @@ -2707,7 +2658,7 @@ tc_gen_reloc (section, fixP) if (addsy == NULL || bfd_is_abs_section (addsec)) { - /* Resolve this reloc now, as md_apply_fix3 would have done (not + /* Resolve this reloc now, as md_apply_fix would have done (not called if -linkrelax). There is no point in keeping a reloc to an absolute symbol. No reloc that is subject to relaxation must be to an absolute symbol; difference @@ -2756,7 +2707,7 @@ tc_gen_reloc (section, fixP) resolve the relocation here. */ if (addsy != NULL && (bfd_is_und_section (addsec) - || strcmp (bfd_get_section_name (addsec->owner, addsec), + || strcmp (bfd_section_name (addsec), MMIX_REG_CONTENTS_SECTION_NAME) == 0)) { code = fixP->fx_r_type; @@ -2783,7 +2734,7 @@ tc_gen_reloc (section, fixP) case BFD_RELOC_MMIX_BASE_PLUS_OFFSET: if (addsy != NULL - && strcmp (bfd_get_section_name (addsec->owner, addsec), + && strcmp (bfd_section_name (addsec), MMIX_REG_CONTENTS_SECTION_NAME) == 0) { /* This changed into a register; the relocation is for the @@ -2886,7 +2837,7 @@ tc_gen_reloc (section, fixP) case BFD_RELOC_MMIX_REG: if (addsy != NULL && (bfd_is_und_section (addsec) - || strcmp (bfd_get_section_name (addsec->owner, addsec), + || strcmp (bfd_section_name (addsec), MMIX_REG_CONTENTS_SECTION_NAME) == 0)) { code = fixP->fx_r_type; @@ -2907,9 +2858,9 @@ tc_gen_reloc (section, fixP) } /* FALLTHROUGH. */ - /* The others are supposed to be handled by md_apply_fix3. + /* The others are supposed to be handled by md_apply_fix. FIXME: ... which isn't called when -linkrelax. Move over - md_apply_fix3 code here for everything reasonable. */ + md_apply_fix code here for everything reasonable. */ badop: default: as_bad_where @@ -2922,9 +2873,9 @@ tc_gen_reloc (section, fixP) return NULL; } - relP = (arelent *) xmalloc (sizeof (arelent)); - assert (relP != 0); - relP->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); + relP = XNEW (arelent); + gas_assert (relP != 0); + relP->sym_ptr_ptr = XNEW (asymbol *); *relP->sym_ptr_ptr = baddsy; relP->address = fixP->fx_frag->fr_address + fixP->fx_where; @@ -2953,10 +2904,10 @@ tc_gen_reloc (section, fixP) ugly labels_without_colons etc. */ void -mmix_handle_mmixal () +mmix_handle_mmixal (void) { - char *s0 = input_line_pointer; - char *s; + char *insn; + char *s = input_line_pointer; char *label = NULL; char c; @@ -2966,44 +2917,20 @@ mmix_handle_mmixal () if (mmix_gnu_syntax) return; - /* If the first character is a '.', then it's a pseudodirective, not a - label. Make GAS not handle label-without-colon on this line. We - also don't do mmixal-specific stuff on this line. */ - if (input_line_pointer[0] == '.') - { - label_without_colon_this_line = 0; - return; - } - - /* Don't handle empty lines here. */ - while (1) - { - if (*s0 == 0 || is_end_of_line[(unsigned int) *s0]) - return; - - if (! ISSPACE (*s0)) - break; - - s0++; - } - /* If we're on a line with a label, check if it's a mmixal fb-label. Save an indicator and skip the label; it must be set only after all fb-labels of expressions are evaluated. */ - if (ISDIGIT (input_line_pointer[0]) - && input_line_pointer[1] == 'H' - && ISSPACE (input_line_pointer[2])) + if (ISDIGIT (s[0]) && s[1] == 'H' && ISSPACE (s[2])) { - char *s; - current_fb_label = input_line_pointer[0] - '0'; + current_fb_label = s[0] - '0'; /* We have to skip the label, but also preserve the newlineness of the previous character, since the caller checks that. It's a mess we blame on the caller. */ - input_line_pointer[1] = input_line_pointer[-1]; - input_line_pointer += 2; + s[1] = s[-1]; + s += 2; + input_line_pointer = s; - s = input_line_pointer; while (*s && ISSPACE (*s) && ! is_end_of_line[(unsigned int) *s]) s++; @@ -3011,48 +2938,75 @@ mmix_handle_mmixal () 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; } + + /* Back off to the last space before the opcode so we don't handle + the opcode as a label. */ + s--; } else + current_fb_label = -1; + + if (*s == '.') { - current_fb_label = -1; - if (is_name_beginner (input_line_pointer[0])) - label = input_line_pointer; + /* If the first character is a '.', then it's a pseudodirective, not a + label. Make GAS not handle label-without-colon on this line. We + also don't do mmixal-specific stuff on this line. */ + label_without_colon_this_line = 0; + return; } - s0 = input_line_pointer; - /* Skip over label. */ - while (*s0 && is_part_of_name (*s0)) - s0++; - - /* Remove trailing ":" off labels, as they'd otherwise be considered - part of the name. But don't do it for local labels. */ - if (s0 != input_line_pointer && s0[-1] == ':' - && (s0 - 2 != input_line_pointer - || ! ISDIGIT (s0[-2]))) - s0[-1] = ' '; - else if (label != NULL) + if (*s == 0 || is_end_of_line[(unsigned int) *s]) + /* We avoid handling empty lines here. */ + return; + + if (is_name_beginner (*s)) + label = s; + + /* If there is a label, skip over it. */ + while (*s && is_part_of_name (*s)) + s++; + + /* Find the start of the instruction or pseudo following the label, + if there is one. */ + for (insn = s; + *insn && ISSPACE (*insn) && ! is_end_of_line[(unsigned int) *insn]; + insn++) + /* Empty */ + ; + + /* Remove a trailing ":" off labels, as they'd otherwise be considered + part of the name. But don't do this for local labels. */ + if (s != input_line_pointer && s[-1] == ':' + && (s - 2 != input_line_pointer + || ! ISDIGIT (s[-2]))) + s[-1] = ' '; + else if (label != NULL + /* For a lone label on a line, we don't attach it to the next + instruction or MMIXAL-pseudo (getting its alignment). Thus + is acts like a "normal" :-ended label. Ditto if it's + followed by a non-MMIXAL pseudo. */ + && !is_end_of_line[(unsigned int) *insn] + && *insn != '.') { /* For labels that don't end in ":", we save it so we can later give it the same alignment and address as the associated instruction. */ /* Make room for the label including the ending nul. */ - int len_0 = s0 - 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 @@ -3062,14 +3016,10 @@ mmix_handle_mmixal () pending_label[len_0 - 1] = 0; } - while (*s0 && ISSPACE (*s0) && ! is_end_of_line[(unsigned int) *s0]) - s0++; - - if (pending_label != NULL && is_end_of_line[(unsigned int) *s0]) - /* Whoops, this was actually a lone label on a line. Like :-ended - labels, we don't attach such labels to the next instruction or - pseudo. */ - pending_label = NULL; + /* If we have a non-MMIXAL pseudo, we have not business with the rest of + the line. */ + if (*insn == '.') + return; /* Find local labels of operands. Look for "[0-9][FB]" where the characters before and after are not part of words. Break if a single @@ -3081,7 +3031,6 @@ mmix_handle_mmixal () /* First make sure we don't have any of the magic characters on the line appearing as input. */ - s = s0; while (*s) { c = *s++; @@ -3092,7 +3041,7 @@ mmix_handle_mmixal () } /* Scan again, this time looking for ';' after operands. */ - s = s0; + s = insn; /* Skip the insn. */ while (*s @@ -3132,7 +3081,9 @@ mmix_handle_mmixal () { if ((s[1] != 'B' && s[1] != 'F') || is_part_of_name (s[-1]) - || is_part_of_name (s[2])) + || is_part_of_name (s[2]) + /* Don't treat e.g. #1F as a local-label reference. */ + || (s != input_line_pointer && s[-1] == '#')) s++; else { @@ -3158,7 +3109,7 @@ mmix_handle_mmixal () /* Make IS into an EQU by replacing it with "= ". Only match upper-case though; let lower-case be a syntax error. */ - s = s0; + s = insn; if (s[0] == 'I' && s[1] == 'S' && ISSPACE (s[2])) { *s = '='; @@ -3264,8 +3215,7 @@ mmix_handle_mmixal () We fill in the label as an expression. */ void -mmix_fb_label (expP) - expressionS *expP; +mmix_fb_label (expressionS *expP) { symbolS *sym; char *fb_internal_name; @@ -3314,8 +3264,7 @@ mmix_fb_label (expP) relaxing. */ int -mmix_force_relocation (fixP) - fixS *fixP; +mmix_force_relocation (fixS *fixP) { if (fixP->fx_r_type == BFD_RELOC_MMIX_LOCAL || fixP->fx_r_type == BFD_RELOC_MMIX_BASE_PLUS_OFFSET) @@ -3324,10 +3273,10 @@ mmix_force_relocation (fixP) if (linkrelax) return 1; - /* All our pcrel relocations are must-keep. Note that md_apply_fix3 is + /* All our pcrel relocations are must-keep. Note that md_apply_fix is called *after* this, and will handle getting rid of the presumed reloc; a relocation isn't *forced* other than to be handled by - md_apply_fix3 (or tc_gen_reloc if linkrelax). */ + md_apply_fix (or tc_gen_reloc if linkrelax). */ if (fixP->fx_pcrel) return 1; @@ -3338,9 +3287,7 @@ mmix_force_relocation (fixP) given a PC relative reloc. */ long -md_pcrel_from_section (fixP, sec) - fixS * fixP; - segT sec; +md_pcrel_from_section (fixS *fixP, segT sec) { if (fixP->fx_addsy != (symbolS *) NULL && (! S_IS_DEFINED (fixP->fx_addsy) @@ -3358,7 +3305,7 @@ md_pcrel_from_section (fixP, sec) register section. */ void -mmix_adjust_symtab () +mmix_adjust_symtab (void) { symbolS *sym; symbolS *regsec = section_symbol (reg_section); @@ -3368,7 +3315,7 @@ mmix_adjust_symtab () { if (sym == regsec) { - if (S_IS_EXTERN (sym) || symbol_used_in_reloc_p (sym)) + if (S_IS_EXTERNAL (sym) || symbol_used_in_reloc_p (sym)) abort (); symbol_remove (sym, &symbol_rootP, &symbol_lastP); } @@ -3388,7 +3335,7 @@ mmix_adjust_symtab () thought at the time I first wrote this. */ int -mmix_label_without_colon_this_line () +mmix_label_without_colon_this_line (void) { int retval = label_without_colon_this_line; @@ -3404,10 +3351,7 @@ mmix_label_without_colon_this_line () join with. */ long -mmix_md_relax_frag (seg, fragP, stretch) - segT seg; - fragS *fragP; - long stretch; +mmix_md_relax_frag (segT seg, fragS *fragP, long stretch) { switch (fragP->fr_subtype) { @@ -3468,7 +3412,7 @@ mmix_md_relax_frag (seg, fragP, 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): { @@ -3533,10 +3477,12 @@ mmix_md_relax_frag (seg, fragP, stretch) /* Various things we punt until all input is seen. */ void -mmix_md_end () +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. */ @@ -3594,6 +3540,38 @@ mmix_md_end () 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 @@ -3601,9 +3579,9 @@ mmix_md_end () 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 @@ -3630,6 +3608,11 @@ mmix_md_end () 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. @@ -3708,9 +3691,7 @@ mmix_md_end () /* qsort function for mmix_symbol_gregs. */ static int -cmp_greg_symbol_fixes (parg, qarg) - const PTR parg; - const PTR qarg; +cmp_greg_symbol_fixes (const void *parg, const void *qarg) { const struct mmix_symbol_greg_fixes *p = (const struct mmix_symbol_greg_fixes *) parg; @@ -3727,7 +3708,7 @@ cmp_greg_symbol_fixes (parg, qarg) as an ELF section. */ void -mmix_frob_file () +mmix_frob_file (void) { int i; struct mmix_symbol_gregs *all_greg_symbols[MAX_GREGS]; @@ -3793,7 +3774,7 @@ mmix_frob_file () 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; @@ -3811,18 +3792,11 @@ mmix_frob_file () if (real_reg_section != NULL) { - asection **secpp; - /* FIXME: Pass error state gracefully. */ - if (bfd_get_section_flags (stdoutput, real_reg_section) & SEC_HAS_CONTENTS) + if (bfd_section_flags (real_reg_section) & SEC_HAS_CONTENTS) as_fatal (_("register section has contents\n")); - /* Really remove the section. */ - for (secpp = &stdoutput->sections; - *secpp != real_reg_section; - secpp = &(*secpp)->next) - ; - bfd_section_list_remove (stdoutput, secpp); + bfd_section_list_remove (stdoutput, real_reg_section); --stdoutput->section_count; } @@ -3835,12 +3809,10 @@ mmix_frob_file () If the name isn't a built-in name and parsed into *EXPP, return zero. */ int -mmix_parse_predefined_name (name, expP) - char *name; - expressionS *expP; +mmix_parse_predefined_name (char *name, expressionS *expP) { char *canon_name; - char *handler_charp; + const char *handler_charp; const char handler_chars[] = "DVWIOUZX"; symbolS *symp; @@ -3946,12 +3918,12 @@ mmix_parse_predefined_name (name, expP) section. */ void -mmix_md_elf_section_change_hook () +mmix_md_elf_section_change_hook (void) { if (doing_bspec) as_bad (_("section change from within a BSPEC/ESPEC pair is not supported")); - last_alignment = bfd_get_section_alignment (now_seg->owner, now_seg); + last_alignment = bfd_section_alignment (now_seg); want_unaligned = 0; } @@ -3959,8 +3931,7 @@ mmix_md_elf_section_change_hook () section too. */ static void -s_loc (ignore) - int ignore ATTRIBUTE_UNUSED; +s_loc (int ignore ATTRIBUTE_UNUSED) { segT section; expressionS exp; @@ -3979,20 +3950,39 @@ s_loc (ignore) 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. */ if (exp.X_add_number < ((offsetT) 0x20 << 56)) { - /* Lower than Data_Segment - assume it's .text. */ + /* Lower than Data_Segment or in the reserved area (the + segment number is >= 0x80, appearing negative) - assume + it's .text. */ section = text_section; /* Save the lowest seen location, so we can pass on this @@ -4004,8 +3994,8 @@ s_loc (ignore) this one), we org at (this - lower). There's an implicit "LOC 0" before any entered code. FIXME: handled by spurious settings of text_has_contents. */ - if (exp.X_add_number < 0 - || exp.X_add_number < (offsetT) lowest_text_loc) + if (lowest_text_loc != (bfd_vma) -1 + && (bfd_vma) exp.X_add_number < lowest_text_loc) { as_bad (_("LOC expression stepping backwards is not supported")); exp.X_op = O_absent; @@ -4028,7 +4018,8 @@ s_loc (ignore) } else { - /* Do the same for the .data section. */ + /* Do the same for the .data section, except we don't have + to worry about exp.X_add_number carrying a sign. */ section = data_section; if (exp.X_add_number < (offsetT) lowest_data_loc) @@ -4054,7 +4045,9 @@ s_loc (ignore) } } - 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); @@ -4065,16 +4058,41 @@ s_loc (ignore) 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 = XNEW (struct loc_assert_s); + 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); @@ -4089,10 +4107,9 @@ s_loc (ignore) by comma. */ static void -mmix_byte () +mmix_byte (void) { unsigned int c; - char *start; if (now_seg == text_section) text_has_contents = 1; @@ -4106,7 +4123,6 @@ mmix_byte () { case '\"': ++input_line_pointer; - start = input_line_pointer; while (is_a_char (c = next_char_of_string ())) { FRAG_APPEND_1_CHAR (c); @@ -4179,11 +4195,9 @@ mmix_byte () lenient than mmix_byte but FIXME: they should eventually merge. */ static void -mmix_cons (nbytes) - int nbytes; +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 @@ -4264,7 +4278,6 @@ mmix_cons (nbytes) bytes. */ case '\"': ++input_line_pointer; - start = input_line_pointer; while (is_a_char (c = next_char_of_string ())) { exp.X_op = O_constant; @@ -4309,11 +4322,8 @@ mmix_cons (nbytes) Arguably this is a GCC bug. */ void -mmix_md_do_align (n, fill, len, max) - int n; - char *fill ATTRIBUTE_UNUSED; - int len ATTRIBUTE_UNUSED; - int max ATTRIBUTE_UNUSED; +mmix_md_do_align (int n, char *fill ATTRIBUTE_UNUSED, + int len ATTRIBUTE_UNUSED, int max ATTRIBUTE_UNUSED) { last_alignment = n; want_unaligned = n == 0;