This commit was generated by cvs2svn to track changes on a CVS vendor
[deliverable/binutils-gdb.git] / gas / config / tc-mips.c
index f98a332790f67d6fc94817d1eae739dba7a3a80b..2836d845a501672a9a46732358df2337b20b5ebf 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-mips.c -- assemble code for a MIPS chip.
-   Copyright (C) 1993, 94, 95, 96, 97, 98, 1999 Free Software Foundation, Inc.
+   Copyright (C) 1993, 94, 95, 96, 97, 98, 1999, 2000 Free Software Foundation, Inc.
    Contributed by the OSF and Ralph Campbell.
    Written by Keith Knowles and Ralph Campbell, working independently.
    Modified for ECOFF and R4000 support by Ian Lance Taylor of Cygnus
@@ -118,10 +118,18 @@ mips_target_format ()
       return target_big_endian ? "a.out-mips-big" : "a.out-mips-little";
     case bfd_target_ecoff_flavour:
       return target_big_endian ? "ecoff-bigmips" : ECOFF_LITTLE_FORMAT;
+    case bfd_target_coff_flavour:
+      return "pe-mips";
     case bfd_target_elf_flavour:
+#ifdef TE_TMIPS
+      /* This is traditional mips */
+      return (target_big_endian
+              ? "elf32-tradbigmips" : "elf32-tradlittlemips");
+#else
       return (target_big_endian
              ? (mips_64 ? "elf64-bigmips" : "elf32-bigmips")
              : (mips_64 ? "elf64-littlemips" : "elf32-littlemips"));
+#endif
     default:
       abort ();
       return NULL;
@@ -133,6 +141,8 @@ mips_target_format ()
                            ? ".data" \
                            : OUTPUT_FLAVOR == bfd_target_ecoff_flavour \
                            ? ".rdata" \
+                           : OUTPUT_FLAVOR == bfd_target_coff_flavour \
+                           ? ".rdata" \
                            : OUTPUT_FLAVOR == bfd_target_elf_flavour \
                            ? ".rodata" \
                            : (abort (), ""))
@@ -179,7 +189,7 @@ struct mips_set_options
    that we must set the isa and mips16 fields to -1 to indicate that
    they have not been initialized.  */
 
-static struct mips_set_options mips_opts = { -1, -1 };
+static struct mips_set_options mips_opts = { -1, -1, 0, 0, 0, 0, 0, 0 };
 
 /* These variables are filled in with the masks of registers used.
    The object format code reads them and puts them in the appropriate
@@ -203,6 +213,9 @@ static int mips_eabi64 = 0;
    mips3 or greater, then mark the object file 32BITMODE. */
 static int mips_32bitmode = 0;
 
+/* True if -mgp32 was passed. */
+static int mips_gp32 = 0;
+
 /* Some ISA's have delay slots for instructions which read or write
    from a coprocessor (eg. mips1-mips3); some don't (eg mips4).
    Return true if instructions marked INSN_LOAD_COPROC_DELAY, 
@@ -265,6 +278,10 @@ static int mips_32bitmode = 0;
 #define cop_interlocks (mips_cpu == 4300                            \
                        )
 
+/* Is this a mfhi or mflo instruction?  */
+#define MF_HILO_INSN(PINFO) \
+          ((PINFO & INSN_READ_HI) || (PINFO & INSN_READ_LO))
+
 /* MIPS PIC level.  */
 
 enum mips_pic_level
@@ -300,6 +317,10 @@ static int mips_trap;
 
 static int mips_any_noreorder;
 
+/* Non-zero if nops should be inserted when the register referenced in
+   an mfhi/mflo instruction is read in the next two instructions.  */
+static int mips_7000_hilo_fix;
+
 /* The size of the small data section.  */
 static int g_switch_value = 8;
 /* Whether the -G option was used.  */
@@ -342,7 +363,7 @@ const char comment_chars[] = "#";
 const char line_comment_chars[] = "#";
 
 /* This array holds machine specific line separator characters. */
-const char line_separator_chars[] = "";
+const char line_separator_chars[] = ";";
 
 /* Chars that can be used to separate mant from exp in floating point nums */
 const char EXP_CHARS[] = "eE";
@@ -392,7 +413,7 @@ static struct mips_cl_insn prev_prev_insn;
 
 /* If we don't want information for prev_insn or prev_prev_insn, we
    point the insn_mo field at this dummy integer.  */
-static const struct mips_opcode dummy_opcode = { 0 };
+static const struct mips_opcode dummy_opcode = { NULL, NULL, 0, 0, 0, 0 };
 
 /* Non-zero if prev_insn is valid.  */
 static int prev_insn_valid;
@@ -741,7 +762,7 @@ static const pseudo_typeS mips_pseudo_table[] =
   {"stabn", s_mips_stab, 'n'},
   {"text", s_change_sec, 't'},
   {"word", s_cons, 2},
-  { 0 },
+  { NULL, NULL, 0 },
 };
 
 static const pseudo_typeS mips_nonecoff_pseudo_table[] = {
@@ -758,7 +779,7 @@ static const pseudo_typeS mips_nonecoff_pseudo_table[] = {
   {"loc", s_ignore, 0},
   {"mask", s_mips_mask, 'R'},
   {"verstamp", s_ignore, 0},
-  { 0 },
+  { NULL, NULL, 0 },
 };
 
 extern void pop_insert PARAMS ((const pseudo_typeS *));
@@ -837,6 +858,15 @@ md_begin ()
   int broken = 0;
   int mips_isa_from_cpu;
 
+  /* GP relative stuff not working for PE */
+  if (strncmp (TARGET_OS, "pe", 2) == 0
+      && g_switch_value != 0)
+    {
+      if (g_switch_seen)
+       as_bad (_("-G not supported in this configuration."));
+      g_switch_value = 0;
+    }
+
   cpu = TARGET_CPU;
   if (strcmp (cpu + (sizeof TARGET_CPU) - 3, "el") == 0)
     {
@@ -1551,6 +1581,37 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
              || (pinfo & INSN_READ_COND_CODE))
            ++nops;
        }
+
+      /* If we're fixing up mfhi/mflo for the r7000 and the
+        previous insn was an mfhi/mflo and the current insn
+        reads the register that the mfhi/mflo wrote to, then
+        insert two nops.  */
+
+      else if (mips_7000_hilo_fix
+              && MF_HILO_INSN (prev_pinfo)
+              && insn_uses_reg (ip, ((prev_insn.insn_opcode >> OP_SH_RD)
+                                       & OP_MASK_RD),
+                                    MIPS_GR_REG))
+
+       {
+         nops += 2;
+       }
+
+      /* If we're fixing up mfhi/mflo for the r7000 and the
+        2nd previous insn was an mfhi/mflo and the current insn
+        reads the register that the mfhi/mflo wrote to, then
+        insert one nop.  */
+
+      else if (mips_7000_hilo_fix
+              && MF_HILO_INSN (prev_prev_insn.insn_opcode)
+              && insn_uses_reg (ip, ((prev_prev_insn.insn_opcode >> OP_SH_RD)
+                                       & OP_MASK_RD),
+                                    MIPS_GR_REG))
+     
+       {
+         nops += 1;
+       }
       else if (prev_pinfo & INSN_READ_LO)
        {
          /* The previous instruction reads the LO register; if the
@@ -2424,7 +2485,6 @@ macro_build (place, counter, ep, name, fmt, va_alist)
   struct mips_cl_insn insn;
   bfd_reloc_code_real_type r;
   va_list args;
-  int insn_isa;
 
 #ifdef USE_STDARG
   va_start (args, fmt);
@@ -2458,31 +2518,10 @@ macro_build (place, counter, ep, name, fmt, va_alist)
   /* Search until we get a match for NAME.  */
   while (1)
     {
-      insn_isa = 0;
-
-      if ((insn.insn_mo->membership & INSN_ISA) == INSN_ISA1)
-       insn_isa = 1;
-      else if ((insn.insn_mo->membership & INSN_ISA) == INSN_ISA2)
-       insn_isa = 2;
-      else if ((insn.insn_mo->membership & INSN_ISA) == INSN_ISA3)
-       insn_isa = 3;
-      else if ((insn.insn_mo->membership & INSN_ISA) == INSN_ISA4)
-       insn_isa = 4;
-
       if (strcmp (fmt, insn.insn_mo->args) == 0
          && insn.insn_mo->pinfo != INSN_MACRO
-         && ((insn_isa != 0
-              && insn_isa <= mips_opts.isa)
-             || (mips_cpu == 4650
-                 && (insn.insn_mo->membership & INSN_4650) != 0)
-             || (mips_cpu == 4010
-                 && (insn.insn_mo->membership & INSN_4010) != 0)
-             || ((mips_cpu == 4100
-                  || mips_cpu == 4111
-                  )
-                 && (insn.insn_mo->membership & INSN_4100) != 0)
-             || (mips_cpu == 3900
-                 && (insn.insn_mo->membership & INSN_3900) != 0))
+         && OPCODE_IS_MEMBER (insn.insn_mo, mips_opts.isa, mips_cpu, 
+                              mips_gp32)
          && (mips_cpu != 4650 || (insn.insn_mo->pinfo & FP_D) == 0))
        break;
 
@@ -2564,7 +2603,6 @@ macro_build (place, counter, ep, name, fmt, va_alist)
                  || r == BFD_RELOC_MIPS_GOT_LO16
                  || r == BFD_RELOC_MIPS_CALL_LO16
                  || (ep->X_op == O_subtract
-                     && now_seg == text_section
                      && r == BFD_RELOC_PCREL_LO16));
          continue;
 
@@ -2578,7 +2616,6 @@ macro_build (place, counter, ep, name, fmt, va_alist)
                              || r == BFD_RELOC_MIPS_GOT_HI16
                              || r == BFD_RELOC_MIPS_CALL_HI16))
                      || (ep->X_op == O_subtract
-                         && now_seg == text_section
                          && r == BFD_RELOC_PCREL_HI16_S)));
          if (ep->X_op == O_constant)
            {
@@ -2629,7 +2666,7 @@ macro_build (place, counter, ep, name, fmt, va_alist)
 static void
 mips16_macro_build (place, counter, ep, name, fmt, args)
      char *place;
-     int *counter;
+     int *counter ATTRIBUTE_UNUSED;
      expressionS *ep;
      const char *name;
      const char *fmt;
@@ -3412,7 +3449,7 @@ macro (ip)
   int tempreg;
   int mask;
   int icnt = 0;
-  int used_at;
+  int used_at = 0;
   expressionS expr1;
   const char *s;
   const char *s2;
@@ -4117,23 +4154,23 @@ macro (ip)
       /* When generating embedded PIC code, we permit expressions of
         the form
           la   $4,foo-bar
-        where bar is an address in the .text section.  These are used
+        where bar is an address in the current section.  These are used
         when getting the addresses of functions.  We don't permit
         X_add_number to be non-zero, because if the symbol is
         external the relaxing code needs to know that any addend is
         purely the offset to X_op_symbol.  */
       if (mips_pic == EMBEDDED_PIC
          && offset_expr.X_op == O_subtract
-         && now_seg == text_section
          && (symbol_constant_p (offset_expr.X_op_symbol)
-             ? S_GET_SEGMENT (offset_expr.X_op_symbol) == text_section
+             ? S_GET_SEGMENT (offset_expr.X_op_symbol) == now_seg
              : (symbol_equated_p (offset_expr.X_op_symbol)
                 && (S_GET_SEGMENT
                     (symbol_get_value_expression (offset_expr.X_op_symbol)
                      ->X_add_symbol)
-                    == text_section)))
+                    == now_seg)))
          && breg == 0
-         && offset_expr.X_add_number == 0)
+         && (offset_expr.X_add_number == 0
+             || OUTPUT_FLAVOR == bfd_target_elf_flavour))
        {
          macro_build ((char *) NULL, &icnt, &offset_expr, "lui", "t,u",
                       treg, (int) BFD_RELOC_PCREL_HI16_S);
@@ -6377,8 +6414,8 @@ macro2 (ip)
       macro_build ((char *) NULL, &icnt, NULL, s, "s,t", sreg, AT);
       break;
 
-    case M_TRUNCWD:
     case M_TRUNCWS:
+    case M_TRUNCWD:
       assert (mips_opts.isa == 1);
       sreg = (ip->insn_opcode >> 11) & 0x1f;   /* floating reg */
       dreg = (ip->insn_opcode >> 06) & 0x1f;   /* floating reg */
@@ -6966,7 +7003,7 @@ mips_ip (str, ip)
 {
   char *s;
   const char *args;
-  char c;
+  char c = 0;
   struct mips_opcode *insn;
   char *argsStart;
   unsigned int regno;
@@ -7028,37 +7065,15 @@ mips_ip (str, ip)
   argsStart = s;
   for (;;)
     {
-      int insn_isa;
       boolean ok;
 
       assert (strcmp (insn->name, str) == 0);
 
-      insn_isa = 0;
-      if ((insn->membership & INSN_ISA) == INSN_ISA1)
-       insn_isa = 1;
-      else if ((insn->membership & INSN_ISA) == INSN_ISA2)
-       insn_isa = 2;
-      else if ((insn->membership & INSN_ISA) == INSN_ISA3)
-       insn_isa = 3;
-      else if ((insn->membership & INSN_ISA) == INSN_ISA4)
-       insn_isa = 4;
-
-      if (insn_isa != 0 
-         && insn_isa <= mips_opts.isa)
+      if (OPCODE_IS_MEMBER (insn, mips_opts.isa, mips_cpu, mips_gp32))
        ok = true;
-      else if (insn->pinfo == INSN_MACRO)
+      else 
        ok = false;
-      else if ((mips_cpu == 4650 && (insn->membership & INSN_4650) != 0)
-              || (mips_cpu == 4010 && (insn->membership & INSN_4010) != 0)
-              || ((mips_cpu == 4100
-                   || mips_cpu == 4111
-                   )
-                  && (insn->membership & INSN_4100) != 0)
-              || (mips_cpu == 3900 && (insn->membership & INSN_3900) != 0))
-       ok = true;
-      else
-       ok = false;
-
+      
       if (insn->pinfo != INSN_MACRO)
        {
          if (mips_cpu == 4650 && (insn->pinfo & FP_D) != 0)
@@ -7073,18 +7088,16 @@ mips_ip (str, ip)
              ++insn;
              continue;
            }
-
-         if (insn_isa == 0
-              || insn_isa <= mips_opts.isa)
-           insn_error = _("opcode not supported on this processor");
          else
-           {
+           {
              static char buf[100];
-
-             sprintf (buf, _("opcode requires -mips%d or greater"), insn_isa);
+             sprintf (buf, 
+                      _("opcode not supported on this processor: %d (MIPS%d)"),
+                      mips_cpu, mips_opts.isa);
+                      
              insn_error = buf;
+             return;
            }
-         return;
        }
 
       ip->insn_mo = insn;
@@ -7657,11 +7670,15 @@ mips_ip (str, ip)
                      default: /* unused default case avoids warnings.  */
                      case 'L':
                        newname = RDATA_SECTION_NAME;
-                       if (USE_GLOBAL_POINTER_OPT && g_switch_value >= 8)
+                       if ((USE_GLOBAL_POINTER_OPT && g_switch_value >= 8)
+                           || mips_pic == EMBEDDED_PIC)
                          newname = ".lit8";
                        break;
                      case 'F':
-                       newname = RDATA_SECTION_NAME;
+                       if (mips_pic == EMBEDDED_PIC)
+                         newname = ".lit8";
+                       else
+                         newname = RDATA_SECTION_NAME;
                        break;
                      case 'l':
                        assert (!USE_GLOBAL_POINTER_OPT
@@ -7735,10 +7752,8 @@ mips_ip (str, ip)
                      if (insn + 1 < &mips_opcodes[NUMOPCODES] &&
                          !strcmp (insn->name, insn[1].name))
                        break;
-                     if (imm_expr.X_op != O_constant
-                         && imm_expr.X_op != O_big)
-                       insn_error = _("absolute expression required");
-                     else
+                     if (imm_expr.X_op == O_constant
+                         || imm_expr.X_op == O_big)
                        as_bad (_("16 bit expression not in range 0..65535"));
                    }
                }
@@ -7774,10 +7789,8 @@ mips_ip (str, ip)
                    {
                      if (more)
                        break;
-                     if (imm_expr.X_op != O_constant
-                         && imm_expr.X_op != O_big)
-                       insn_error = _("absolute expression required");
-                     else
+                     if (imm_expr.X_op == O_constant
+                         || imm_expr.X_op == O_big)
                        as_bad (_("16 bit expression not in range -32768..32767"));
                    }
                }
@@ -7804,9 +7817,8 @@ mips_ip (str, ip)
                      || offset_expr.X_add_number < -0x8000)
                  && (mips_pic != EMBEDDED_PIC
                      || offset_expr.X_op != O_subtract
-                     || now_seg != text_section
                      || (S_GET_SEGMENT (offset_expr.X_op_symbol)
-                         != text_section)))
+                         != now_seg)))
                break;
 
              if (c == 'h' || c == 'H')
@@ -8730,8 +8742,8 @@ my_getExpression (ep, str)
 }
 
 /* Turn a string in input_line_pointer into a floating point constant
-   of type type, and store the appropriate bytes in *litP.  The number
-   of LITTLENUMS emitted is stored in *sizeP .  An error message is
+   of type TYPE, and store the appropriate bytes in *LITP.  The number
+   of LITTLENUMS emitted is stored in *SIZEP.  An error message is
    returned, or NULL on OK.  */
 
 char *
@@ -8849,6 +8861,11 @@ struct option md_longopts[] = {
 #define OPTION_MABI (OPTION_MD_BASE + 38)
   {"mabi", required_argument, NULL, OPTION_MABI},
 
+#define OPTION_M7000_HILO_FIX (OPTION_MD_BASE + 39)
+  {"mfix7000", no_argument, NULL, OPTION_M7000_HILO_FIX},
+#define OPTION_NO_M7000_HILO_FIX (OPTION_MD_BASE + 40)
+  {"no-fix-7000", no_argument, NULL, OPTION_NO_M7000_HILO_FIX},
+
 #define OPTION_CALL_SHARED (OPTION_MD_BASE + 7)
 #define OPTION_NON_SHARED (OPTION_MD_BASE + 8)
 #define OPTION_XGOT (OPTION_MD_BASE + 19)
@@ -8863,6 +8880,11 @@ struct option md_longopts[] = {
   {"64", no_argument, NULL, OPTION_64},
 #endif
 
+#define OPTION_GP32 (OPTION_MD_BASE + 41)
+#define OPTION_GP64 (OPTION_MD_BASE + 42)
+  {"mgp32", no_argument, NULL, OPTION_GP32},
+  {"mgp64", no_argument, NULL, OPTION_GP64},
+
   {NULL, no_argument, NULL, 0}
 };
 size_t md_longopts_size = sizeof(md_longopts);
@@ -9021,8 +9043,24 @@ md_parse_option (c, arg)
                if (strcmp (p, "orion") == 0)
                  mips_cpu = 4600;
                break;
-             }
 
+             case 'm':
+             case 'M':
+               switch (atoi (p + 1))
+                 {
+                 case 5200:
+                 case 5230:
+                 case 5231:
+                 case 5261:
+                 case 5721:
+                 case 7000:
+                   mips_cpu = 5000;
+                   break;
+                 default:
+                   break;
+                 }
+             }
+           
            if (sv
                && (mips_cpu != 4300
                    && mips_cpu != 4100
@@ -9163,6 +9201,27 @@ md_parse_option (c, arg)
       }
       break;
 
+    case OPTION_GP32:
+      mips_gp32 = 1;
+      mips_64 = 0;
+
+      /* We deliberately don't allow "-gp32" to set the MIPS_32BITMODE
+        flag in object files because to do so would make it
+        impossible to link with libraries compiled without "-gp32".
+        This is unnecessarily restrictive.  
+
+        We could solve this problem by adding "-gp32" multilibs to
+        gcc, but to set this flag before gcc is built with such
+        multilibs will break too many systems. */
+
+/*    mips_32bitmode = 1; */
+      break;
+
+    case OPTION_GP64:
+      mips_gp32 = 0;
+      mips_64 = 1;
+/*    mips_32bitmode = 0; */
+      break;
 
     case OPTION_MABI:
       if (strcmp (arg,"32") == 0
@@ -9173,6 +9232,14 @@ md_parse_option (c, arg)
        mips_abi_string = arg;
       break;
 
+    case OPTION_M7000_HILO_FIX:
+      mips_7000_hilo_fix = true;
+      break;
+
+    case OPTION_NO_M7000_HILO_FIX:
+      mips_7000_hilo_fix = false;
+      break;
+
     default:
       return 0;
     }
@@ -9314,7 +9381,7 @@ md_pcrel_from (fixP)
 
 void
 cons_fix_new_mips (frag, where, nbytes, exp)
-     fragS *frag;
+     fragS *frag ATTRIBUTE_UNUSED;
      int where;
      unsigned int nbytes;
      expressionS *exp;
@@ -9447,6 +9514,7 @@ mips_frob_file ()
    fixup requires the special reloc.  */
 #define SWITCH_TABLE(fixp) \
   ((fixp)->fx_r_type == BFD_RELOC_32 \
+   && OUTPUT_FLAVOR != bfd_target_elf_flavour \
    && (fixp)->fx_addsy != NULL \
    && (fixp)->fx_subsy != NULL \
    && S_GET_SEGMENT ((fixp)->fx_addsy) == text_section \
@@ -9494,15 +9562,16 @@ md_apply_fix (fixP, valueP)
      symbol, we need to adjust the value.  */
 #ifdef OBJ_ELF
   if (fixP->fx_addsy != NULL && OUTPUT_FLAVOR == bfd_target_elf_flavour)
+    {
     if (S_GET_OTHER (fixP->fx_addsy) == STO_MIPS16 
         || S_IS_WEAK (fixP->fx_addsy)
         || (symbol_used_in_reloc_p (fixP->fx_addsy)
             && (((bfd_get_section_flags (stdoutput,
-                                        S_GET_SEGMENT (fixP->fx_addsy))
-                 & SEC_LINK_ONCE) != 0)
-               || !strncmp (segment_name (S_GET_SEGMENT (fixP->fx_addsy)),
-                            ".gnu.linkonce",
-                            sizeof (".gnu.linkonce") - 1))))
+                                         S_GET_SEGMENT (fixP->fx_addsy))
+                  & SEC_LINK_ONCE) != 0)
+                || !strncmp (segment_name (S_GET_SEGMENT (fixP->fx_addsy)),
+                             ".gnu.linkonce",
+                             sizeof (".gnu.linkonce") - 1))))
 
       {
         value -= S_GET_VALUE (fixP->fx_addsy);
@@ -9510,12 +9579,29 @@ md_apply_fix (fixP, valueP)
           {
             /* In this case, the bfd_install_relocation routine will
                incorrectly add the symbol value back in.  We just want
-               the addend to appear in the object file.  */
+               the addend to appear in the object file.  
+              FIXME: If this makes VALUE zero, we're toast.  */
             value -= S_GET_VALUE (fixP->fx_addsy);
           }
       }
-#endif
 
+      /* This code was generated using trial and error and so is
+        fragile and not trustworthy.  If you change it, you should
+        rerun the elf-rel, elf-rel2, and empic testcases and ensure
+        they still pass.  */
+      if (fixP->fx_pcrel || fixP->fx_subsy != NULL)
+       {
+         value += fixP->fx_frag->fr_address + fixP->fx_where;
+
+         /* BFD's REL handling, for MIPS, is _very_ weird.
+            This gives the right results, but it can't possibly
+            be the way things are supposed to work.  */
+         if (fixP->fx_r_type != BFD_RELOC_16_PCREL_S2
+             || S_GET_SEGMENT (fixP->fx_addsy) != undefined_section)
+           value += fixP->fx_frag->fr_address + fixP->fx_where;
+       }
+    }
+#endif
 
   fixP->fx_addnumber = value;  /* Remember value for tc_gen_reloc */
 
@@ -9553,7 +9639,12 @@ md_apply_fix (fixP, valueP)
     case BFD_RELOC_PCREL_HI16_S:
       /* The addend for this is tricky if it is internal, so we just
         do everything here rather than in bfd_install_relocation.  */
-      if ((symbol_get_bfdsym (fixP->fx_addsy)->flags & BSF_SECTION_SYM) == 0)
+      if (OUTPUT_FLAVOR == bfd_target_elf_flavour 
+         && !fixP->fx_done
+         && value != 0)
+       break;
+      if (fixP->fx_addsy
+         && (symbol_get_bfdsym (fixP->fx_addsy)->flags & BSF_SECTION_SYM) == 0)
        {
          /* For an external symbol adjust by the address to make it
             pcrel_offset.  We use the address of the RELLO reloc
@@ -9573,7 +9664,12 @@ md_apply_fix (fixP, valueP)
     case BFD_RELOC_PCREL_LO16:
       /* The addend for this is tricky if it is internal, so we just
         do everything here rather than in bfd_install_relocation.  */
-      if ((symbol_get_bfdsym (fixP->fx_addsy)->flags & BSF_SECTION_SYM) == 0)
+      if (OUTPUT_FLAVOR == bfd_target_elf_flavour 
+         && !fixP->fx_done
+         && value != 0)
+       break;
+      if (fixP->fx_addsy
+         && (symbol_get_bfdsym (fixP->fx_addsy)->flags & BSF_SECTION_SYM) == 0)
        value += fixP->fx_frag->fr_address + fixP->fx_where;
       buf = (unsigned char *) fixP->fx_frag->fr_literal + fixP->fx_where;
       if (target_big_endian)
@@ -9610,6 +9706,7 @@ md_apply_fix (fixP, valueP)
        }
       break;
 
+    case BFD_RELOC_RVA:
     case BFD_RELOC_32:
       /* If we are deleting this reloc entry, we must fill in the
         value now.  This can happen if we have a .word which is not
@@ -9655,6 +9752,15 @@ md_apply_fix (fixP, valueP)
       if ((value & 0x3) != 0)
        as_bad_where (fixP->fx_file, fixP->fx_line,
                      _("Branch to odd address (%lx)"), value);
+
+      if (!fixP->fx_done && value != 0)
+       break;
+      /* If 'value' is zero, the remaining reloc code won't actually
+        do the store, so it must be done here.  This is probably
+        a bug somewhere.  */
+      if (!fixP->fx_done)
+       value -= fixP->fx_frag->fr_address + fixP->fx_where;
+      
       value >>= 2;
 
       /* update old instruction data */
@@ -9852,7 +9958,7 @@ mips_align (to, fill, label)
 
 static void
 s_align (x)
-     int x;
+     int x ATTRIBUTE_UNUSED;
 {
   register int temp;
   register long temp_fill;
@@ -9957,7 +10063,7 @@ s_change_sec (sec)
                                      | SEC_RELOC
                                      | SEC_DATA));
              if (strcmp (TARGET_OS, "elf") != 0)
-               bfd_set_section_alignment (stdoutput, seg, 4);
+               record_alignment (seg, 4);
            }
          demand_empty_rest_of_line ();
        }
@@ -9979,7 +10085,7 @@ s_change_sec (sec)
                                     SEC_ALLOC | SEC_LOAD | SEC_RELOC
                                     | SEC_DATA);
              if (strcmp (TARGET_OS, "elf") != 0)
-               bfd_set_section_alignment (stdoutput, seg, 4);
+               record_alignment (seg, 4);
            }
          demand_empty_rest_of_line ();
          break;
@@ -10046,7 +10152,7 @@ s_float_cons (type)
 
 static void
 s_mips_globl (x)
-     int x;
+     int x ATTRIBUTE_UNUSED;
 {
   char *name;
   int c;
@@ -10087,7 +10193,7 @@ s_mips_globl (x)
 
 static void
 s_option (x)
-     int x;
+     int x ATTRIBUTE_UNUSED;
 {
   char *opt;
   char c;
@@ -10140,7 +10246,7 @@ static struct mips_option_stack *mips_opts_stack;
 
 static void
 s_mipsset (x)
-     int x;
+     int x ATTRIBUTE_UNUSED;
 {
   char *name = input_line_pointer, ch;
 
@@ -10276,7 +10382,7 @@ s_mipsset (x)
 
 static void
 s_abicalls (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   mips_pic = SVR4_PIC;
   if (USE_GLOBAL_POINTER_OPT)
@@ -10301,7 +10407,7 @@ s_abicalls (ignore)
 
 static void
 s_cpload (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   expressionS ex;
   int icnt = 0;
@@ -10341,7 +10447,7 @@ s_cpload (ignore)
 
 static void
 s_cprestore (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   expressionS ex;
   int icnt = 0;
@@ -10374,7 +10480,7 @@ s_cprestore (ignore)
 
 static void
 s_gpword (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   symbolS *label;
   expressionS ex;
@@ -10414,7 +10520,7 @@ s_gpword (ignore)
 
 static void
 s_cpadd (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   int icnt = 0;
   int reg;
@@ -10448,7 +10554,7 @@ s_cpadd (ignore)
 
 static void
 s_insn (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   if (mips_opts.mips16)
     mips16_mark_labels ();
@@ -10477,7 +10583,7 @@ s_mips_stab (type)
 
 static void
 s_mips_weakext (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   char *name;
   int c;
@@ -10887,7 +10993,8 @@ md_estimate_size_before_relax (fragp, segtype)
      fragS *fragp;
      asection *segtype;
 {
-  int change;
+  int change = 0;
+  boolean linkonce = false;
 
   if (RELAX_MIPS16_P (fragp->fr_subtype))
     {
@@ -10930,10 +11037,31 @@ md_estimate_size_before_relax (fragp, segtype)
 
       symsec = S_GET_SEGMENT (sym);
 
+      /* duplicate the test for LINK_ONCE sections as in adjust_reloc_syms */
+      if (symsec != segtype && ! S_IS_LOCAL (sym))
+        {
+          if ((bfd_get_section_flags (stdoutput, symsec) & SEC_LINK_ONCE)
+              != 0)
+            linkonce = true;
+
+          /* The GNU toolchain uses an extension for ELF: a section
+             beginning with the magic string .gnu.linkonce is a linkonce
+             section.  */
+          if (strncmp (segment_name (symsec), ".gnu.linkonce",
+                       sizeof ".gnu.linkonce" - 1) == 0)
+            linkonce = true;
+        }
+
       /* This must duplicate the test in adjust_reloc_syms.  */
       change = (symsec != &bfd_und_section
                && symsec != &bfd_abs_section
-               && ! bfd_is_com_section (symsec));
+               && ! bfd_is_com_section (symsec)
+               && !linkonce
+#ifdef OBJ_ELF
+               /* A weak symbol is treated as external.  */
+               && ! S_IS_WEAK (sym)
+#endif
+               );
     }
   else
     abort ();
@@ -10990,7 +11118,7 @@ mips_fix_adjustable (fixp)
 
 arelent **
 tc_gen_reloc (section, fixp)
-     asection *section;
+     asection *section ATTRIBUTE_UNUSED;
      fixS *fixp;
 {
   static arelent *retval[4];
@@ -11015,6 +11143,8 @@ tc_gen_reloc (section, fixp)
        as_fatal (_("Double check fx_r_type in tc-mips.c:tc_gen_reloc"));
       fixp->fx_r_type = BFD_RELOC_GPREL32;
     }
+  else if (fixp->fx_pcrel == 0 || OUTPUT_FLAVOR == bfd_target_elf_flavour)
+    reloc->addend = fixp->fx_addnumber;
   else if (fixp->fx_r_type == BFD_RELOC_PCREL_LO16)
     {
       /* We use a special addend for an internal RELLO reloc.  */
@@ -11039,8 +11169,6 @@ tc_gen_reloc (section, fixp)
                         + fixp->fx_next->fx_frag->fr_address
                         + fixp->fx_next->fx_where);
     }
-  else if (fixp->fx_pcrel == 0)
-    reloc->addend = fixp->fx_addnumber;
   else
     {
       if (OUTPUT_FLAVOR != bfd_target_aout_flavour)
@@ -11179,7 +11307,8 @@ tc_gen_reloc (section, fixp)
   /* To support a PC relative reloc when generating embedded PIC code
      for ECOFF, we use a Cygnus extension.  We check for that here to
      make sure that we don't let such a reloc escape normally.  */
-  if (OUTPUT_FLAVOR == bfd_target_ecoff_flavour
+  if ((OUTPUT_FLAVOR == bfd_target_ecoff_flavour
+       || OUTPUT_FLAVOR == bfd_target_elf_flavour)
       && code == BFD_RELOC_16_PCREL_S2
       && mips_pic != EMBEDDED_PIC)
     reloc->howto = NULL;
@@ -11230,7 +11359,7 @@ mips_relax_frag (fragp, stretch)
 
 void
 md_convert_frag (abfd, asec, fragp)
-     bfd *abfd;
+     bfd *abfd ATTRIBUTE_UNUSED;
      segT asec;
      fragS *fragp;
 {
@@ -11483,6 +11612,36 @@ static procS cur_proc;
 static procS *cur_proc_ptr;
 static int numprocs;
 
+/* When we align code in the .text section of mips16, use the correct two
+   byte nop pattern of 0x6500 (move $0,$0) */
+
+int
+mips_do_align (n, fill, len, max)
+     int n;
+     const char *fill;
+     int len ATTRIBUTE_UNUSED;
+     int max;
+{
+  if (fill == NULL
+      && subseg_text_p (now_seg)
+      && n > 1
+      && mips_opts.mips16)
+    {
+      static const unsigned char be_nop[] = { 0x65, 0x00 };
+      static const unsigned char le_nop[] = { 0x00, 0x65 };
+
+      frag_align (1, 0, 0);
+
+      if (target_big_endian)
+       frag_align_pattern (n, be_nop, 2, max);      
+      else
+       frag_align_pattern (n, le_nop, 2, max);      
+      return 1;
+    }
+
+  return 0;
+}
+
 static void
 md_obj_begin ()
 {
@@ -11552,7 +11711,7 @@ get_number ()
 
 static void
 s_file (x)
-     int x;
+     int x ATTRIBUTE_UNUSED;
 {
   int line;
 
@@ -11565,7 +11724,7 @@ s_file (x)
 
 static void
 s_mips_end (x)
-     int x;
+     int x ATTRIBUTE_UNUSED;
 {
   symbolS *p;
   int maybe_text;
@@ -11814,6 +11973,3 @@ s_loc (x)
   symbolP->sy_segment = now_seg;
 }
 #endif
-
-
-  
This page took 0.038209 seconds and 4 git commands to generate.