* config/tc-mips.c (mips_validate_fix): New function.
[deliverable/binutils-gdb.git] / gas / config / tc-mmix.c
index b76980789c4c43a08c3c884fb26e708a84c96c09..c6ce34f8ebc46098774336dec772585859949087 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-mmix.c -- Assembler for Don Knuth's MMIX.
-   Copyright (C) 2001 Free Software Foundation.
+   Copyright (C) 2001, 2002, 2003 Free Software Foundation.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -67,7 +67,6 @@ 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 void mmix_frob_local_reloc PARAMS ((bfd *, asection *, PTR));
 
 /* 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
@@ -154,11 +153,15 @@ static int warn_on_expansion = 1;
 /* Should we merge non-zero GREG register definitions?  */
 static int merge_gregs = 1;
 
+/* Should we pass on undefined BFD_RELOC_MMIX_BASE_PLUS_OFFSET relocs
+   (missing suitable GREG definitions) to the linker?  */
+static int allocate_undefined_gregs_in_linker = 0;
+
 /* Should we emit built-in symbols?  */
 static int predefined_syms = 1;
 
-/* Should we anything but the listed special register name (e.g. equated
-   symbols)?  */
+/* Should we allow anything but the listed special register name
+   (e.g. equated symbols)?  */
 static int equated_spec_regs = 1;
 
 /* Do we require standard GNU syntax?  */
@@ -185,6 +188,7 @@ struct option md_longopts[] =
 #define OPTION_GNU_SYNTAX  (OPTION_NOSYMS + 1)
 #define OPTION_GLOBALIZE_SYMBOLS  (OPTION_GNU_SYNTAX + 1)
 #define OPTION_FIXED_SPEC_REGS  (OPTION_GLOBALIZE_SYMBOLS + 1)
+#define OPTION_LINKER_ALLOCATED_GREGS  (OPTION_FIXED_SPEC_REGS + 1)
    {"linkrelax", no_argument, NULL, OPTION_RELAX},
    {"no-expand", no_argument, NULL, OPTION_NOEXPAND},
    {"no-merge-gregs", no_argument, NULL, OPTION_NOMERGEGREG},
@@ -193,6 +197,8 @@ struct option md_longopts[] =
    {"globalize-symbols", no_argument, NULL, OPTION_GLOBALIZE_SYMBOLS},
    {"fixed-special-register-names", no_argument, NULL,
     OPTION_FIXED_SPEC_REGS},
+   {"linker-allocated-gregs", no_argument, NULL,
+    OPTION_LINKER_ALLOCATED_GREGS},
    {NULL, no_argument, NULL, 0}
  };
 
@@ -255,28 +261,28 @@ struct obstack mmix_sym_obstack;
 #define GETA_0F (65536 * 4 - 8)
 #define GETA_0B (-65536 * 4 - 4)
 
-#define GETA_MAX_LEN 4*4
+#define GETA_MAX_LEN 4 * 4
 #define GETA_3F 0
 #define GETA_3B 0
 
 #define BCC_0F GETA_0F
 #define BCC_0B GETA_0B
 
-#define BCC_MAX_LEN 6*4
+#define BCC_MAX_LEN 6 * 4
 #define BCC_5F GETA_3F
 #define BCC_5B GETA_3B
 
 #define PUSHJ_0F GETA_0F
 #define PUSHJ_0B GETA_0B
 
-#define PUSHJ_MAX_LEN 5*4
+#define PUSHJ_MAX_LEN 5 * 4
 #define PUSHJ_4F GETA_3F
 #define PUSHJ_4B GETA_3B
 
 #define JMP_0F (65536 * 256 * 4 - 8)
 #define JMP_0B (-65536 * 256 * 4 - 4)
 
-#define JMP_MAX_LEN 5*4
+#define JMP_MAX_LEN 5 * 4
 #define JMP_4F 0
 #define JMP_4B 0
 
@@ -338,7 +344,7 @@ const pseudo_typeS md_pseudo_table[] =
    {"local", mmix_s_local, 1},
 
    /* Support DWARF2 debugging info.  */
-   {"file", dwarf2_directive_file, 0},
+   {"file", (void (*) PARAMS ((int))) dwarf2_directive_file, 0},
    {"loc", dwarf2_directive_loc, 0},
 
    {NULL, 0, 0}
@@ -406,7 +412,7 @@ mmix_fill_nops (opcodep, n)
   int i;
 
   for (i = 0; i < n; i++)
-    md_number_to_chars (opcodep + i*4, SWYM_INSN_BYTE << 24, 4);
+    md_number_to_chars (opcodep + i * 4, SWYM_INSN_BYTE << 24, 4);
 }
 
 /* See macro md_parse_name in tc-mmix.h.  */
@@ -454,7 +460,7 @@ get_operands (max_operands, s, exp)
          return 0;
        }
 
-      /* Begin operand parsing at the current scan point. */
+      /* Begin operand parsing at the current scan point.  */
 
       input_line_pointer = p;
       expression (&exp[numexp]);
@@ -484,7 +490,7 @@ get_operands (max_operands, s, exp)
       input_line_pointer--;
     }
 
-  /* Mark the end of the valid operands with an illegal expression. */
+  /* Mark the end of the valid operands with an illegal expression.  */
   exp[numexp].X_op = O_illegal;
 
   return (numexp);
@@ -536,6 +542,11 @@ get_putget_operands (insn, operands, exp)
 
   input_line_pointer = p;
 
+  /* Initialize both possible operands to error state, in case we never
+     get further.  */
+  exp[0].X_op = O_illegal;
+  exp[1].X_op = O_illegal;
+
   if (insn->operands == mmix_operands_get)
     {
       expp_reg = &exp[0];
@@ -567,10 +578,6 @@ get_putget_operands (insn, operands, exp)
       expp_sreg = &exp[0];
       expp_reg = &exp[1];
 
-      /* Initialize to error state in case we'll never call expression on
-         this operand.  */
-      expp_reg->X_op = O_illegal;
-
       sregp = p;
       c = get_symbol_end ();
       sregend = p = input_line_pointer;
@@ -621,6 +628,7 @@ md_parse_option (c, arg)
     {
     case 'x':
       warn_on_expansion = 0;
+      allocate_undefined_gregs_in_linker = 1;
       break;
 
     case OPTION_RELAX:
@@ -653,6 +661,10 @@ md_parse_option (c, arg)
       equated_spec_regs = 0;
       break;
 
+    case OPTION_LINKER_ALLOCATED_GREGS:
+      allocate_undefined_gregs_in_linker = 1;
+      break;
+
     default:
       return 0;
     }
@@ -685,9 +697,13 @@ md_show_usage (stream)
   fprintf (stream, _("\
   -no-merge-gregs         Do not merge GREG definitions with nearby values.\n"));
   fprintf (stream, _("\
+  -linker-allocated-gregs If there's no suitable GREG definition for the\
+                          operands of an instruction, let the linker resolve.\n"));
+  fprintf (stream, _("\
   -x                      Do not warn when an operand to GETA, a branch,\n\
                           PUSHJ or JUMP is not known to be within range.\n\
-                          The linker will catch any errors.\n"));
+                          The linker will catch any errors.  Implies\n\
+                          -linker-allocated-gregs."));
 }
 
 /* Step to end of line, but don't step over the end of the line.  */
@@ -696,7 +712,7 @@ static void
 mmix_discard_rest_of_line ()
 {
   while (*input_line_pointer
-        && (! is_end_of_line [(unsigned char) *input_line_pointer]
+        && (! is_end_of_line[(unsigned char) *input_line_pointer]
             || TC_EOL_IN_INSN (input_line_pointer)))
     input_line_pointer++;
 }
@@ -730,7 +746,7 @@ mmix_md_begin ()
 
   /* This will break the day the "lex" thingy changes.  For now, it's the
      only way to make ':' part of a name, and a name beginner.  */
-  lex_type [':'] = (LEX_NAME | LEX_BEGIN_NAME);
+  lex_type[':'] = (LEX_NAME | LEX_BEGIN_NAME);
 
   mmix_opcode_hash = hash_new ();
 
@@ -1031,10 +1047,10 @@ md_assemble (str)
       current_fb_label = -1;
     }
 
-  /* We also assume that the length of the instruction is determinable
-     from the first format character.  Currently *all* the information is
-     in the first character.  We need a self-contained frag since we want
-     the relocation to point to the instruction, not the variant part.  */
+  /* We also assume that the length of the instruction is at least 4, the
+     size of an unexpanded instruction.  We need a self-contained frag
+     since we want the relocation to point to the instruction, not the
+     variant part.  */
 
   opcodep = frag_more (4);
   mmix_opcode_frag = opc_fragP = frag_now;
@@ -1065,7 +1081,7 @@ md_assemble (str)
        }
 
       if (expand_op)
-       frag_var (rs_machine_dependent, 4*4, 0,
+       frag_var (rs_machine_dependent, 4 * 4, 0,
                  ENCODE_RELAX (STATE_JMP, STATE_UNDF),
                  exp[0].X_add_symbol,
                  exp[0].X_add_number,
@@ -1265,7 +1281,7 @@ md_assemble (str)
       /* SYNCD: "X,$Y,$Z|Z".  */
       /* FALLTHROUGH.  */
     case mmix_operands_regs:
-      /* Three registers, $X,$Y,$Z. */
+      /* Three registers, $X,$Y,$Z.  */
       /* FALLTHROUGH.  */
     case mmix_operands_regs_z:
       /* Operands "$X,$Y,$Z|Z", number of arguments checked above.  */
@@ -1470,27 +1486,27 @@ md_assemble (str)
 
     case mmix_operands_sync:
     a_single_24_bit_number_operand:
-    if (n_operands != 1
-       || exp[0].X_op == O_register
-       || (exp[0].X_op == O_constant
-           && (exp[0].X_add_number > 0xffffff || exp[0].X_add_number < 0)))
-      {
-       as_bad (_("invalid operands to opcode %s: `%s'"),
-               instruction->name, operands);
-       return;
-      }
+      if (n_operands != 1
+         || exp[0].X_op == O_register
+         || (exp[0].X_op == O_constant
+             && (exp[0].X_add_number > 0xffffff || exp[0].X_add_number < 0)))
+       {
+         as_bad (_("invalid operands to opcode %s: `%s'"),
+                 instruction->name, operands);
+         return;
+       }
 
-    if (exp[0].X_op == O_constant)
-      {
-       opcodep[1] = (exp[0].X_add_number >> 16) & 255;
-       opcodep[2] = (exp[0].X_add_number >> 8) & 255;
-       opcodep[3] = exp[0].X_add_number & 255;
-      }
-    else
-      /* FIXME: This doesn't bring us unsignedness checking.  */
-      fix_new_exp (opc_fragP, opcodep - opc_fragP->fr_literal + 1,
-                  3, exp + 0, 0, BFD_RELOC_24);
-    break;
+      if (exp[0].X_op == O_constant)
+       {
+         opcodep[1] = (exp[0].X_add_number >> 16) & 255;
+         opcodep[2] = (exp[0].X_add_number >> 8) & 255;
+         opcodep[3] = exp[0].X_add_number & 255;
+       }
+      else
+       /* FIXME: This doesn't bring us unsignedness checking.  */
+       fix_new_exp (opc_fragP, opcodep - opc_fragP->fr_literal + 1,
+                    3, exp + 0, 0, BFD_RELOC_24);
+      break;
 
     case mmix_operands_neg:
       /* Operands "$X,Y,$Z|Z"; NEG or NEGU.  Y is optional, 0 is default.  */
@@ -1544,7 +1560,7 @@ md_assemble (str)
       break;
 
     case mmix_operands_regaddr:
-      /* A GETA/branch-type. */
+      /* A GETA/branch-type.  */
       break;
 
     case mmix_operands_get:
@@ -1622,7 +1638,7 @@ md_assemble (str)
          break;
        }
 
-      /* "0,$Z"; UNSAVE. */
+      /* "0,$Z"; UNSAVE.  */
       if (n_operands != 2
          || exp[0].X_op != O_constant
          || exp[0].X_add_number != 0
@@ -1862,7 +1878,7 @@ md_assemble (str)
 
 int
 mmix_assemble_return_nonzero (str)
-     char  *str;
+     char *str;
 {
   int last_error_count = had_errors ();
   char *s2 = str;
@@ -2009,7 +2025,7 @@ s_greg (unused)
      register.  */
   c = get_symbol_end ();
 
-  if (! is_end_of_line [(unsigned char) c])
+  if (! is_end_of_line[(unsigned char) c])
     input_line_pointer++;
 
   if (*p)
@@ -2156,7 +2172,8 @@ md_estimate_size_before_relax (fragP, segment)
 #define HANDLE_RELAXABLE(state)                                                \
  case ENCODE_RELAX (state, STATE_UNDF):                                        \
    if (fragP->fr_symbol != NULL                                                \
-       && S_GET_SEGMENT (fragP->fr_symbol) == segment)                 \
+       && S_GET_SEGMENT (fragP->fr_symbol) == segment                  \
+       && !S_IS_WEAK (fragP->fr_symbol))                               \
      {                                                                 \
        /* The symbol lies in the same segment - a relaxable case.  */  \
        fragP->fr_subtype                                               \
@@ -2242,7 +2259,7 @@ md_atof (type, litP, sizeP)
   for (i = 0; i < prec; i++)
     {
       md_number_to_chars (litP, (valueT) words[i], 2);
-         litP += 2;
+      litP += 2;
     }
   return NULL;
 }
@@ -2255,7 +2272,7 @@ md_convert_frag (abfd, sec, fragP)
      segT sec ATTRIBUTE_UNUSED;
      fragS *fragP;
 {
-  /* Pointer to first byte in variable-sized part of the frag. */
+  /* Pointer to first byte in variable-sized part of the frag.  */
   char *var_partp;
 
   /* Pointer to first opcode byte in frag.  */
@@ -2293,48 +2310,52 @@ md_convert_frag (abfd, sec, fragP)
   opcode_address = fragP->fr_address + fragP->fr_fix - 4;
 
   switch (fragP->fr_subtype)
-  {
-  case ENCODE_RELAX (STATE_GETA, STATE_ZERO):
-  case ENCODE_RELAX (STATE_BCC, STATE_ZERO):
-  case ENCODE_RELAX (STATE_PUSHJ, STATE_ZERO):
-    mmix_set_geta_branch_offset (opcodep, target_address - opcode_address);
-    if (linkrelax)
-      {
-       tmpfixP
-         = fix_new (opc_fragP, opcodep - opc_fragP->fr_literal, 4,
-                    fragP->fr_symbol, fragP->fr_offset, 1,
-                    BFD_RELOC_MMIX_ADDR19);
-       COPY_FR_WHERE_TO_FX (fragP, tmpfixP);
-      }
-    var_part_size = 0;
-    break;
-
-  case ENCODE_RELAX (STATE_JMP, STATE_ZERO):
-    mmix_set_jmp_offset (opcodep, target_address - opcode_address);
-    if (linkrelax)
-      {
-       tmpfixP
-         = fix_new (opc_fragP, opcodep - opc_fragP->fr_literal, 4,
-                    fragP->fr_symbol, fragP->fr_offset, 1,
-                    BFD_RELOC_MMIX_ADDR27);
-       COPY_FR_WHERE_TO_FX (fragP, tmpfixP);
-      }
-    var_part_size = 0;
-    break;
+    {
+    case ENCODE_RELAX (STATE_GETA, STATE_ZERO):
+    case ENCODE_RELAX (STATE_BCC, STATE_ZERO):
+    case ENCODE_RELAX (STATE_PUSHJ, STATE_ZERO):
+      mmix_set_geta_branch_offset (opcodep, target_address - opcode_address);
+      if (linkrelax)
+       {
+         tmpfixP
+           = fix_new (opc_fragP, opcodep - opc_fragP->fr_literal, 4,
+                      fragP->fr_symbol, fragP->fr_offset, 1,
+                      BFD_RELOC_MMIX_ADDR19);
+         COPY_FR_WHERE_TO_FX (fragP, tmpfixP);
+       }
+      var_part_size = 0;
+      break;
 
-  case STATE_GREG_DEF:
-    if (fragP->tc_frag_data == NULL)
-      {
-       tmpfixP
-         = fix_new (fragP, var_partp - fragP->fr_literal, 8,
-                    fragP->fr_symbol, fragP->fr_offset, 0, BFD_RELOC_64);
-       COPY_FR_WHERE_TO_FX (fragP, tmpfixP);
-       mmix_gregs[n_of_cooked_gregs++] = tmpfixP;
-       var_part_size = 8;
-      }
-    else
+    case ENCODE_RELAX (STATE_JMP, STATE_ZERO):
+      mmix_set_jmp_offset (opcodep, target_address - opcode_address);
+      if (linkrelax)
+       {
+         tmpfixP
+           = fix_new (opc_fragP, opcodep - opc_fragP->fr_literal, 4,
+                      fragP->fr_symbol, fragP->fr_offset, 1,
+                      BFD_RELOC_MMIX_ADDR27);
+         COPY_FR_WHERE_TO_FX (fragP, tmpfixP);
+       }
       var_part_size = 0;
-    break;
+      break;
+
+    case STATE_GREG_DEF:
+      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
+            anything for undefined symbols.  */
+         md_number_to_chars (var_partp, 0, 8);
+         tmpfixP
+           = fix_new (fragP, var_partp - fragP->fr_literal, 8,
+                      fragP->fr_symbol, fragP->fr_offset, 0, BFD_RELOC_64);
+         COPY_FR_WHERE_TO_FX (fragP, tmpfixP);
+         mmix_gregs[n_of_cooked_gregs++] = tmpfixP;
+         var_part_size = 8;
+       }
+      else
+       var_part_size = 0;
+      break;
 
 #define HANDLE_MAX_RELOC(state, reloc)                                 \
   case ENCODE_RELAX (state, STATE_MAX):                                        \
@@ -2349,15 +2370,15 @@ md_convert_frag (abfd, sec, fragP)
     COPY_FR_WHERE_TO_FX (fragP, tmpfixP);                              \
     break
 
-  HANDLE_MAX_RELOC (STATE_GETA, BFD_RELOC_MMIX_GETA);
-  HANDLE_MAX_RELOC (STATE_BCC, BFD_RELOC_MMIX_CBRANCH);
-  HANDLE_MAX_RELOC (STATE_PUSHJ, BFD_RELOC_MMIX_PUSHJ);
-  HANDLE_MAX_RELOC (STATE_JMP, BFD_RELOC_MMIX_JMP);
+      HANDLE_MAX_RELOC (STATE_GETA, BFD_RELOC_MMIX_GETA);
+      HANDLE_MAX_RELOC (STATE_BCC, BFD_RELOC_MMIX_CBRANCH);
+      HANDLE_MAX_RELOC (STATE_PUSHJ, BFD_RELOC_MMIX_PUSHJ);
+      HANDLE_MAX_RELOC (STATE_JMP, BFD_RELOC_MMIX_JMP);
 
-  default:
-    BAD_CASE (fragP->fr_subtype);
-    break;
-  }
+    default:
+      BAD_CASE (fragP->fr_subtype);
+      break;
+    }
 
   fragP->fr_fix += var_part_size;
   fragP->fr_var = 0;
@@ -2369,15 +2390,15 @@ md_convert_frag (abfd, sec, fragP)
 
    Note that this function isn't called when linkrelax != 0.  */
 
-int
-md_apply_fix3 (fixP, valp, segment)
+void
+md_apply_fix3 (fixP, valP, segment)
      fixS *   fixP;
-     valueT * valp;
+     valueT * valP;
      segT     segment;
 {
   char *buf  = fixP->fx_where + fixP->fx_frag->fr_literal;
   /* Note: use offsetT because it is signed, valueT is unsigned.  */
-  offsetT val  = (offsetT) * valp;
+  offsetT val  = (offsetT) * valP;
   segT symsec
     = (fixP->fx_addsy == NULL
        ? absolute_section : S_GET_SEGMENT (fixP->fx_addsy));
@@ -2393,11 +2414,10 @@ md_apply_fix3 (fixP, valp, segment)
              && symsec != absolute_section
              && ((fixP->fx_r_type != BFD_RELOC_MMIX_REG
                   && fixP->fx_r_type != BFD_RELOC_MMIX_REG_OR_BYTE)
-                 || (symsec != reg_section
-                     && symsec != real_reg_section)))))
+                 || symsec != reg_section))))
     {
       fixP->fx_done = 0;
-      return 0;
+      return;
     }
   else if (fixP->fx_r_type == BFD_RELOC_MMIX_LOCAL
           || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
@@ -2405,7 +2425,7 @@ md_apply_fix3 (fixP, valp, segment)
     {
       /* These are never "fixed".  */
       fixP->fx_done = 0;
-      return 0;
+      return;
     }
   else
     /* We assume every other relocation is "fixed".  */
@@ -2478,11 +2498,17 @@ md_apply_fix3 (fixP, valp, segment)
 
     case BFD_RELOC_MMIX_REG_OR_BYTE:
       if (fixP->fx_addsy != NULL
-         && (S_GET_SEGMENT (fixP->fx_addsy) != real_reg_section
+         && (S_GET_SEGMENT (fixP->fx_addsy) != reg_section
              || S_GET_VALUE (fixP->fx_addsy) > 255)
          && S_GET_SEGMENT (fixP->fx_addsy) != absolute_section)
-       as_bad_where (fixP->fx_file, fixP->fx_line,
-                     _("invalid operands"));
+       {
+         as_bad_where (fixP->fx_file, fixP->fx_line,
+                       _("invalid operands"));
+         /* We don't want this "symbol" appearing in output, because
+            that will fail.  */
+         fixP->fx_done = 1;
+       }
+
       buf[0] = val;
 
       /* If this reloc is for a Z field, we need to adjust
@@ -2493,31 +2519,25 @@ md_apply_fix3 (fixP, valp, segment)
          && (fixP->fx_addsy == NULL
              || S_GET_SEGMENT (fixP->fx_addsy) == absolute_section))
        buf[-3] |= IMM_OFFSET_BIT;
-
-      /* We don't want this "symbol" appearing in output, because that
-        will fail.  */
-      if (fixP->fx_addsy
-         && S_GET_SEGMENT (fixP->fx_addsy) == real_reg_section)
-       symbol_clear_used_in_reloc (fixP->fx_addsy);
       break;
 
     case BFD_RELOC_MMIX_REG:
       if (fixP->fx_addsy == NULL
-         || S_GET_SEGMENT (fixP->fx_addsy) != real_reg_section
+         || S_GET_SEGMENT (fixP->fx_addsy) != reg_section
          || S_GET_VALUE (fixP->fx_addsy) > 255)
-       as_bad_where (fixP->fx_file, fixP->fx_line,
-                     _("invalid operands"));
-      *buf = val;
+       {
+         as_bad_where (fixP->fx_file, fixP->fx_line,
+                       _("invalid operands"));
+         fixP->fx_done = 1;
+       }
 
-      if (fixP->fx_addsy
-         && S_GET_SEGMENT (fixP->fx_addsy) == real_reg_section)
-       symbol_clear_used_in_reloc (fixP->fx_addsy);
+      *buf = val;
       break;
 
     case BFD_RELOC_MMIX_BASE_PLUS_OFFSET:
       /* These are never "fixed".  */
       fixP->fx_done = 0;
-      return 0;
+      return;
 
     case BFD_RELOC_MMIX_PUSHJ_1:
     case BFD_RELOC_MMIX_PUSHJ_2:
@@ -2541,8 +2561,6 @@ md_apply_fix3 (fixP, valp, segment)
     /* Make sure that for completed fixups we have the value around for
        use by e.g. mmix_frob_file.  */
     fixP->fx_offset = val;
-
-  return 0; /* Return value is ignored.  */
 }
 
 /* A bsearch function for looking up a value against offsets for GREG
@@ -2573,14 +2591,20 @@ tc_gen_reloc (section, fixP)
      fixS *fixP;
 {
   bfd_signed_vma val
-    = fixP->fx_offset + (fixP->fx_addsy ? S_GET_VALUE (fixP->fx_addsy) : 0);
+    = fixP->fx_offset
+    + (fixP->fx_addsy != NULL
+       && !S_IS_WEAK (fixP->fx_addsy)
+       && !S_IS_COMMON (fixP->fx_addsy)
+       ? S_GET_VALUE (fixP->fx_addsy) : 0);
   arelent *relP;
   bfd_reloc_code_real_type code = BFD_RELOC_NONE;
   char *buf  = fixP->fx_where + fixP->fx_frag->fr_literal;
   symbolS *addsy = fixP->fx_addsy;
   asection *addsec = addsy == NULL ? NULL : S_GET_SEGMENT (addsy);
-  bfd_vma addend = fixP->fx_offset;
   asymbol *baddsy = addsy != NULL ? symbol_get_bfdsym (addsy) : NULL;
+  bfd_vma addend
+    = val - (baddsy == NULL || S_IS_COMMON (addsy) || S_IS_WEAK (addsy)
+            ? 0 : bfd_asymbol_value (baddsy));
 
   /* A single " LOCAL expression" in the wrong section will not work when
      linking to MMO; relocations for zero-content sections are then
@@ -2610,8 +2634,7 @@ tc_gen_reloc (section, fixP)
     case BFD_RELOC_8:
       code = fixP->fx_r_type;
 
-      if (addsy == NULL
-         || bfd_is_abs_section (S_GET_SEGMENT (addsy)))
+      if (addsy == NULL || bfd_is_abs_section (addsec))
        {
          /* Resolve this reloc now, as md_apply_fix3 would have done (not
             called if -linkrelax).  There is no point in keeping a reloc
@@ -2660,7 +2683,7 @@ tc_gen_reloc (section, fixP)
         register contents section (that is, to a register), then we can't
         resolve the relocation here.  */
       if (addsy != NULL
-         && (bfd_is_und_section (S_GET_SEGMENT (addsy))
+         && (bfd_is_und_section (addsec)
              || strcmp (bfd_get_section_name (addsec->owner, addsec),
                         MMIX_REG_CONTENTS_SECTION_NAME) == 0))
        {
@@ -2674,14 +2697,13 @@ tc_gen_reloc (section, fixP)
          && (S_GET_SEGMENT (addsy) != real_reg_section
              || val > 255
              || val < 0)
-         && ! bfd_is_abs_section (S_GET_SEGMENT (addsy)))
+         && ! bfd_is_abs_section (addsec))
        goto badop;
 
       /* Set the "immediate" bit of the insn if this relocation is to Z
         field when the value is a numeric value, i.e. not a register.  */
       if ((fixP->fx_where & 3) == 3
-         && (addsy == NULL
-             || S_GET_SEGMENT (addsy) == absolute_section))
+         && (addsy == NULL || bfd_is_abs_section (addsec)))
        buf[-3] |= IMM_OFFSET_BIT;
 
       buf[0] = val;
@@ -2689,8 +2711,8 @@ tc_gen_reloc (section, fixP)
 
     case BFD_RELOC_MMIX_BASE_PLUS_OFFSET:
       if (addsy != NULL
-         &&  strcmp (bfd_get_section_name (addsec->owner, addsec),
-                     MMIX_REG_CONTENTS_SECTION_NAME) == 0)
+         && strcmp (bfd_get_section_name (addsec->owner, addsec),
+                    MMIX_REG_CONTENTS_SECTION_NAME) == 0)
        {
          /* This changed into a register; the relocation is for the
             register-contents section.  The constant part remains zero.  */
@@ -2703,16 +2725,16 @@ tc_gen_reloc (section, fixP)
 
         If we encounter any other defined symbol, then we must find a
         suitable register and emit a reloc.  */
-      if (addsy == NULL
-         || S_GET_SEGMENT (addsy) != real_reg_section)
+      if (addsy == NULL || addsec != real_reg_section)
        {
          struct mmix_symbol_gregs *gregs;
          struct mmix_symbol_greg_fixes *fix;
 
-         if (S_IS_DEFINED (addsy))
+         if (S_IS_DEFINED (addsy)
+             && !bfd_is_com_section (addsec)
+             && !S_IS_WEAK (addsy))
            {
-             if (! symbol_section_p (addsy)
-                 && ! bfd_is_abs_section (S_GET_SEGMENT (addsy)))
+             if (! symbol_section_p (addsy) && ! bfd_is_abs_section (addsec))
                as_fatal (_("internal: BFD_RELOC_MMIX_BASE_PLUS_OFFSET not resolved to section"));
 
              /* If this is an absolute symbol sufficiently near
@@ -2722,7 +2744,7 @@ tc_gen_reloc (section, fixP)
                 comparisons.  */
              if (lowest_data_loc != (bfd_vma) -1
                  && (bfd_vma) val + 256 > lowest_data_loc
-                 && bfd_is_abs_section (S_GET_SEGMENT (addsy)))
+                 && bfd_is_abs_section (addsec))
                {
                  val -= (offsetT) lowest_data_loc;
                  addsy = section_symbol (data_section);
@@ -2730,7 +2752,7 @@ tc_gen_reloc (section, fixP)
              /* Likewise text section.  */
              else if (lowest_text_loc != (bfd_vma) -1
                       && (bfd_vma) val + 256 > lowest_text_loc
-                      && bfd_is_abs_section (S_GET_SEGMENT (addsy)))
+                      && bfd_is_abs_section (addsec))
                {
                  val -= (offsetT) lowest_text_loc;
                  addsy = section_symbol (text_section);
@@ -2740,8 +2762,7 @@ tc_gen_reloc (section, fixP)
          gregs = *symbol_get_tc (addsy);
 
          /* If that symbol does not have any associated GREG definitions,
-            we can't do anything.  FIXME: implement allocate-on-demand in
-            the linker.  */
+            we can't do anything.  */
          if (gregs == NULL
              || (fix = bsearch (&val, gregs->greg_fixes, gregs->n_gregs,
                                 sizeof (gregs->greg_fixes[0]),
@@ -2752,8 +2773,17 @@ tc_gen_reloc (section, fixP)
                 before the address we want.  */
              || fix->offs + 255 < val)
            {
-             as_bad_where (fixP->fx_file, fixP->fx_line,
-                           _("no suitable GREG definition for operands"));
+             /* We can either let the linker allocate GREGs
+                automatically, or emit an error.  */
+             if (allocate_undefined_gregs_in_linker)
+               {
+                 /* The values in baddsy and addend are right.  */
+                 code = fixP->fx_r_type;
+                 break;
+               }
+             else
+               as_bad_where (fixP->fx_file, fixP->fx_line,
+                             _("no suitable GREG definition for operands"));
              return NULL;
            }
          else
@@ -2783,7 +2813,7 @@ tc_gen_reloc (section, fixP)
 
     case BFD_RELOC_MMIX_REG:
       if (addsy != NULL
-         && (bfd_is_und_section (S_GET_SEGMENT (addsy))
+         && (bfd_is_und_section (addsec)
              || strcmp (bfd_get_section_name (addsec->owner, addsec),
                         MMIX_REG_CONTENTS_SECTION_NAME) == 0))
        {
@@ -2792,10 +2822,10 @@ tc_gen_reloc (section, fixP)
        }
 
       if (addsy != NULL
-         && (S_GET_SEGMENT (addsy) != real_reg_section
+         && (addsec != real_reg_section
              || val > 255
              || val < 0)
-         && ! bfd_is_und_section (S_GET_SEGMENT (addsy)))
+         && ! bfd_is_und_section (addsec))
        /* Drop through to error message.  */
        ;
       else
@@ -2803,7 +2833,7 @@ tc_gen_reloc (section, fixP)
          buf[0] = val;
          return NULL;
        }
-      /* FALLTHROUGH. */
+      /* FALLTHROUGH.  */
 
       /* The others are supposed to be handled by md_apply_fix3.
         FIXME: ... which isn't called when -linkrelax.  Move over
@@ -2816,8 +2846,7 @@ tc_gen_reloc (section, fixP)
 
       /* Unmark this symbol as used in a reloc, so we don't bump into a BFD
         assert when trying to output reg_section.  FIXME: A gas bug.  */
-      if (addsy)
-       symbol_clear_used_in_reloc (addsy);
+      fixP->fx_addsy = NULL;
       return NULL;
     }
 
@@ -2877,7 +2906,7 @@ mmix_handle_mmixal ()
   /* Don't handle empty lines here.  */
   while (1)
     {
-      if (*s0 == 0 || is_end_of_line [(unsigned int) *s0])
+      if (*s0 == 0 || is_end_of_line[(unsigned int) *s0])
        return;
 
       if (! ISSPACE (*s0))
@@ -2908,7 +2937,7 @@ mmix_handle_mmixal ()
 
       /* For errors emitted here, the book-keeping is off by one; the
         caller is about to bump the counters.  Adjust the error messages.  */
-      if (is_end_of_line [(unsigned int) *s])
+      if (is_end_of_line[(unsigned int) *s])
        {
          char *name;
          unsigned int line;
@@ -2935,7 +2964,7 @@ mmix_handle_mmixal ()
     }
 
   s0 = input_line_pointer;
-  /* Skip over label. */
+  /* Skip over label.  */
   while (*s0 && is_part_of_name (*s0))
     s0++;
 
@@ -2961,10 +2990,10 @@ mmix_handle_mmixal ()
       pending_label[len_0 - 1] = 0;
     }
 
-  while (*s0 && ISSPACE (*s0) && ! is_end_of_line [(unsigned int) *s0])
+  while (*s0 && ISSPACE (*s0) && ! is_end_of_line[(unsigned int) *s0])
     s0++;
 
-  if (pending_label != NULL && is_end_of_line [(unsigned int) *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.  */
@@ -2984,7 +3013,7 @@ mmix_handle_mmixal ()
   while (*s)
     {
       c = *s++;
-      if (is_end_of_line [(unsigned int) c])
+      if (is_end_of_line[(unsigned int) c])
        break;
       if (c == MAGIC_FB_BACKWARD_CHAR || c == MAGIC_FB_FORWARD_CHAR)
        as_bad (_("invalid characters in input"));
@@ -3021,7 +3050,7 @@ mmix_handle_mmixal ()
          /* FIXME: Test-case for semi-colon in string.  */
          while (*s
                 && *s != '"'
-                && (! is_end_of_line [(unsigned int) *s] || *s == ';'))
+                && (! is_end_of_line[(unsigned int) *s] || *s == ';'))
            s++;
 
          if (*s == '"')
@@ -3214,19 +3243,12 @@ mmix_fb_label (expP)
 
 int
 mmix_force_relocation (fixP)
-     fixS * fixP;
+     fixS *fixP;
 {
   if (fixP->fx_r_type == BFD_RELOC_MMIX_LOCAL
-      || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
-      || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY
       || fixP->fx_r_type == BFD_RELOC_MMIX_BASE_PLUS_OFFSET)
     return 1;
 
-  /* FIXME: This is dubious.  Handling of weak symbols should have been
-     caught before we get here.  */
-  if ((fixP->fx_addsy && S_IS_WEAK (fixP->fx_addsy)))
-    return 1;
-
   if (linkrelax)
     return 1;
 
@@ -3237,7 +3259,7 @@ mmix_force_relocation (fixP)
   if (fixP->fx_pcrel)
     return 1;
 
-  return 0;
+  return generic_force_reloc (fixP);
 }
 
 /* The location from which a PC relative jump should be calculated,
@@ -3261,47 +3283,29 @@ md_pcrel_from_section (fixP, sec)
 }
 
 /* Adjust the symbol table.  We make reg_section relative to the real
-   register section.
-
-   FIXME: There's a gas bug; should be fixed when the reg_section symbol
-   is "accidentally" saved for relocs which are really fixups that will be
-   fixed up.  */
+   register section.  */
 
 void
 mmix_adjust_symtab ()
 {
   symbolS *sym;
-  symbolS *prevsym;
   symbolS *regsec = section_symbol (reg_section);
-  segT realregsec = NULL;
 
-  for (prevsym = sym = symbol_rootP;
-       sym != NULL;
-       prevsym = sym, sym = symbol_next (sym))
+  for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym))
     if (S_GET_SEGMENT (sym) == reg_section)
       {
-       if (sym == regsec
-           || (!S_IS_EXTERN (sym) && !symbol_used_in_reloc_p (sym)))
+       if (sym == regsec)
          {
+           if (S_IS_EXTERN (sym) || symbol_used_in_reloc_p (sym))
+             abort ();
            symbol_remove (sym, &symbol_rootP, &symbol_lastP);
-
-           /* We make one extra turn, or we'll lose the next symbol.  We
-              assume that the symbol we remove is not the symbol root
-              (.text normally is).  */
-           sym = prevsym;
          }
        else
-         {
-           /* Change section to the *real* register section, so it gets
-              proper treatment when writing it out.  Only do this for
-              global symbols.  This also means we don't have to check for
-              $0..$255.  */
-           if (realregsec == NULL)
-             realregsec
-               = bfd_make_section_old_way (stdoutput, MMIX_REG_SECTION_NAME);
-
-           S_SET_SEGMENT (sym, realregsec);
-         }
+         /* Change section to the *real* register section, so it gets
+            proper treatment when writing it out.  Only do this for
+            global symbols.  This also means we don't have to check for
+            $0..$255.  */
+         S_SET_SEGMENT (sym, real_reg_section);
       }
 }
 
@@ -3387,8 +3391,8 @@ mmix_md_end ()
     {
       symbolS *symbolP;
       char locsymbol[sizeof (":") - 1
-                   + sizeof (MMIX_LOC_SECTION_START_SYMBOL_PREFIX) - 1
-                   + sizeof (".data")];
+                    + sizeof (MMIX_LOC_SECTION_START_SYMBOL_PREFIX) - 1
+                    + sizeof (".data")];
 
       sprintf (locsymbol, ":%s%s", MMIX_LOC_SECTION_START_SYMBOL_PREFIX,
               ".data");
@@ -3574,7 +3578,9 @@ mmix_frob_file ()
 
       /* If the symbol is defined, then it must be resolved to a section
         symbol at this time, or else we don't know how to handle it.  */
-      if (S_IS_DEFINED (sym))
+      if (S_IS_DEFINED (sym)
+         && !bfd_is_com_section (S_GET_SEGMENT (sym))
+         && !S_IS_WEAK (sym))
        {
          if (! symbol_section_p (sym)
              && ! bfd_is_abs_section (S_GET_SEGMENT (sym)))
@@ -3631,14 +3637,12 @@ mmix_frob_file ()
       if (bfd_get_section_flags (stdoutput, real_reg_section) & SEC_HAS_CONTENTS)
        as_fatal (_("register section has contents\n"));
 
-      /* FIXME: This does not seem like the proper way to kill a section,
-        but it's the way it's done elsewhere, like elf64-alpha.c.  */
       /* Really remove the section.  */
       for (secpp = &stdoutput->sections;
           *secpp != real_reg_section;
           secpp = &(*secpp)->next)
        ;
-      *secpp = (*secpp)->next;
+      bfd_section_list_remove (stdoutput, secpp);
       --stdoutput->section_count;
     }
 
@@ -3731,7 +3735,7 @@ mmix_parse_predefined_name (name, expP)
        return 0;
 
       for (i = 0;
-          i < sizeof (predefined_abs_syms)/sizeof (predefined_abs_syms[0]);
+          i < sizeof (predefined_abs_syms) / sizeof (predefined_abs_syms[0]);
           i++)
        if (strcmp (canon_name, predefined_abs_syms[i].name) == 0)
          {
@@ -3757,50 +3761,6 @@ mmix_parse_predefined_name (name, expP)
   return 1;
 }
 
-/* Worker for mmix_frob_file_before_adjust.  */
-
-static void
-mmix_frob_local_reloc (abfd, sec, xxx)
-     bfd *abfd ATTRIBUTE_UNUSED;
-     asection *sec;
-     PTR xxx ATTRIBUTE_UNUSED;
-{
-  segment_info_type *seginfo = seg_info (sec);
-  fixS *fixp;
-
-  if (seginfo == NULL)
-    return;
-
-  for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next)
-    if (! fixp->fx_done && fixp->fx_addsy != NULL)
-      {
-       symbolS *sym = fixp->fx_addsy;
-       asection *section = S_GET_SEGMENT (sym);
-
-       if (section == reg_section
-           && fixp->fx_r_type == BFD_RELOC_MMIX_LOCAL)
-         {
-           /* If the register is marked global, we don't need to replace
-              with the *real* register section since that will be done
-              when the symbol is changed.  */
-           if (! S_IS_EXTERNAL (sym))
-             /* If it's a local symbol, we replace it with an anonymous
-                one with the same constant value.  */
-             fixp->fx_addsy = expr_build_uconstant (S_GET_VALUE (sym));
-         }
-      }
-}
-
-/* Change fixups for register symbols for BFD_MMIX_LOCAL to be for an
-   absolute symbol.  */
-
-void
-mmix_frob_file_before_adjust ()
-{
-  return;
-  bfd_map_over_sections (stdoutput, mmix_frob_local_reloc, (char *) 0);
-}
-
 /* Just check that we don't have a BSPEC/ESPEC pair active when changing
    sections "normally", and get knowledge about alignment from the new
    section.  */
@@ -3828,7 +3788,7 @@ s_loc (ignore)
   symbolS *sym;
   offsetT off;
 
-  /* Must not have a BSPEC in progress. */
+  /* Must not have a BSPEC in progress.  */
   if (doing_bspec)
     {
       as_bad (_("directive LOC from within a BSPEC/ESPEC pair is not supported"));
@@ -4102,7 +4062,7 @@ mmix_cons (nbytes)
 
   SKIP_WHITESPACE ();
 
-  if (is_end_of_line [(unsigned int) *input_line_pointer])
+  if (is_end_of_line[(unsigned int) *input_line_pointer])
     {
       /* Default to zero if the expression was absent.  */
 
This page took 0.037088 seconds and 4 git commands to generate.