Constify more
[deliverable/binutils-gdb.git] / gas / config / tc-mn10300.c
index 671c0089f7fd0dbfba498f034fed1bb7e324f3d7..9a5d3bed5dcb6f78185b4b7b23286f79a1eb5966 100644 (file)
@@ -1,6 +1,5 @@
 /* tc-mn10300.c -- Assembler code for the Matsushita 10300
-   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
-   2006, 2007 Free Software Foundation, Inc.
+   Copyright (C) 1996-2016 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -281,6 +280,8 @@ static const struct reg_name other_registers[] =
   { "pc", AM33 },
   { "psw", 0 },
   { "sp", 0 },
+  { "ssp", 0 },
+  { "usp", 0 },
 };
 
 #define OTHER_REG_NAME_CNT     ARRAY_SIZE (other_registers)
@@ -336,13 +337,13 @@ get_register_name (expressionS *           expressionP,
   char c;
 
   /* Find the spelling of the operand.  */
-  start = name = input_line_pointer;
+  start = input_line_pointer;
 
-  c = get_symbol_end ();
+  c = get_symbol_name (&name);
   reg_number = reg_name_search (table, table_length, name);
 
   /* Put back the delimiting char.  */
-  *input_line_pointer = c;
+  (void) restore_line_pointer (c);
 
   /* Look to see if it's in the register table.  */
   if (reg_number >= 0)
@@ -408,13 +409,13 @@ other_register_name (expressionS *expressionP)
   char c;
 
   /* Find the spelling of the operand.  */
-  start = name = input_line_pointer;
+  start = input_line_pointer;
 
-  c = get_symbol_end ();
+  c = get_symbol_name (&name);
   reg_number = reg_name_search (other_registers, ARRAY_SIZE (other_registers), name);
 
   /* Put back the delimiting char.  */
-  *input_line_pointer = c;
+  (void) restore_line_pointer (c);
 
   /* Look to see if it's in the register table.  */
   if (reg_number == 0
@@ -443,7 +444,7 @@ none yet\n"));
 }
 
 int
-md_parse_option (int c ATTRIBUTE_UNUSED, char *arg ATTRIBUTE_UNUSED)
+md_parse_option (int c ATTRIBUTE_UNUSED, const char *arg ATTRIBUTE_UNUSED)
 {
   return 0;
 }
@@ -454,7 +455,7 @@ md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
   return 0;
 }
 
-char *
+const char *
 md_atof (int type, char *litp, int *sizep)
 {
   return ieee_md_atof (type, litp, sizep, FALSE);
@@ -675,6 +676,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
   else if (fragP->fr_subtype == 6)
     {
       int offset = fragP->fr_fix;
+
       fragP->fr_literal[offset] = 0xcd;
       fix_new (fragP, fragP->fr_fix + 1, 2, fragP->fr_symbol,
               fragP->fr_offset + 1, 1, BFD_RELOC_16_PCREL);
@@ -684,9 +686,12 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
   else if (fragP->fr_subtype == 7)
     {
       int offset = fragP->fr_fix;
+
       fragP->fr_literal[offset] = 0xdd;
       fragP->fr_literal[offset + 5] = fragP->fr_literal[offset + 3];
       fragP->fr_literal[offset + 6] = fragP->fr_literal[offset + 4];
+      fragP->fr_literal[offset + 3] = 0;
+      fragP->fr_literal[offset + 4] = 0;
 
       fix_new (fragP, fragP->fr_fix + 1, 4, fragP->fr_symbol,
               fragP->fr_offset + 1, 1, BFD_RELOC_32_PCREL);
@@ -696,6 +701,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
   else if (fragP->fr_subtype == 8)
     {
       int offset = fragP->fr_fix;
+
       fragP->fr_literal[offset] = 0xfa;
       fragP->fr_literal[offset + 1] = 0xff;
       fix_new (fragP, fragP->fr_fix + 2, 2, fragP->fr_symbol,
@@ -706,6 +712,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
   else if (fragP->fr_subtype == 9)
     {
       int offset = fragP->fr_fix;
+
       fragP->fr_literal[offset] = 0xfc;
       fragP->fr_literal[offset + 1] = 0xff;
 
@@ -725,6 +732,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
   else if (fragP->fr_subtype == 11)
     {
       int offset = fragP->fr_fix;
+
       fragP->fr_literal[offset] = 0xcc;
 
       fix_new (fragP, fragP->fr_fix + 1, 2, fragP->fr_symbol,
@@ -735,6 +743,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
   else if (fragP->fr_subtype == 12)
     {
       int offset = fragP->fr_fix;
+
       fragP->fr_literal[offset] = 0xdc;
 
       fix_new (fragP, fragP->fr_fix + 1, 4, fragP->fr_symbol,
@@ -896,13 +905,13 @@ md_section_align (asection *seg, valueT addr)
 {
   int align = bfd_get_section_alignment (stdoutput, seg);
 
-  return ((addr + (1 << align) - 1) & (-1 << align));
+  return ((addr + (1 << align) - 1) & -(1 << align));
 }
 
 void
 md_begin (void)
 {
-  char *prev_name = "";
+  const char *prev_name = "";
   const struct mn10300_opcode *op;
 
   mn10300_hash = hash_new ();
@@ -929,7 +938,7 @@ md_begin (void)
     as_warn (_("could not set architecture and machine"));
 
   current_machine = AM33_2;
-#else  
+#else
   if (!bfd_set_arch_mach (stdoutput, bfd_arch_mn10300, MN103))
     as_warn (_("could not set architecture and machine"));
 
@@ -1004,7 +1013,8 @@ mn10300_check_fixup (struct mn10300_fixup *fixup)
 }
 
 void
-mn10300_cons_fix_new (fragS *frag, int off, int size, expressionS *exp)
+mn10300_cons_fix_new (fragS *frag, int off, int size, expressionS *exp,
+                     bfd_reloc_code_real_type r ATTRIBUTE_UNUSED)
 {
   struct mn10300_fixup fixup;
 
@@ -1059,7 +1069,7 @@ mn10300_cons_fix_new (fragS *frag, int off, int size, expressionS *exp)
       as_bad (_("unsupported BFD relocation size %u"), size);
       fixup.reloc = BFD_RELOC_UNUSED;
     }
-    
+
   fix_new_exp (frag, off, size, &fixup.exp, 0, fixup.reloc);
 }
 
@@ -1336,17 +1346,17 @@ md_assemble (char *str)
            }
          else if (operand->flags & MN10300_OPERAND_SP)
            {
-             char *start = input_line_pointer;
-             char c = get_symbol_end ();
+             char *start;
+             char c = get_symbol_name (&start);
 
              if (strcasecmp (start, "sp") != 0)
                {
-                 *input_line_pointer = c;
+                 (void) restore_line_pointer (c);
                  input_line_pointer = hold;
                  str = hold;
                  goto error;
                }
-             *input_line_pointer = c;
+             (void) restore_line_pointer (c);
              goto keep_going;
            }
          else if (operand->flags & MN10300_OPERAND_RREG)
@@ -1387,92 +1397,92 @@ md_assemble (char *str)
            }
          else if (operand->flags & MN10300_OPERAND_FPCR)
            {
-             char *start = input_line_pointer;
-             char c = get_symbol_end ();
+             char *start;
+             char c = get_symbol_name (&start);
 
              if (strcasecmp (start, "fpcr") != 0)
                {
-                 *input_line_pointer = c;
+                 (void) restore_line_pointer (c);
                  input_line_pointer = hold;
                  str = hold;
                  goto error;
                }
-             *input_line_pointer = c;
+             (void) restore_line_pointer (c);
              goto keep_going;
            }
          else if (operand->flags & MN10300_OPERAND_USP)
            {
-             char *start = input_line_pointer;
-             char c = get_symbol_end ();
+             char *start;
+             char c = get_symbol_name (&start);
 
              if (strcasecmp (start, "usp") != 0)
                {
-                 *input_line_pointer = c;
+                 (void) restore_line_pointer (c);
                  input_line_pointer = hold;
                  str = hold;
                  goto error;
                }
-             *input_line_pointer = c;
+             (void) restore_line_pointer (c);
              goto keep_going;
            }
          else if (operand->flags & MN10300_OPERAND_SSP)
            {
-             char *start = input_line_pointer;
-             char c = get_symbol_end ();
+             char *start;
+             char c = get_symbol_name (&start);
 
              if (strcasecmp (start, "ssp") != 0)
                {
-                 *input_line_pointer = c;
+                 (void) restore_line_pointer (c);
                  input_line_pointer = hold;
                  str = hold;
                  goto error;
                }
-             *input_line_pointer = c;
+             (void) restore_line_pointer (c);
              goto keep_going;
            }
          else if (operand->flags & MN10300_OPERAND_MSP)
            {
-             char *start = input_line_pointer;
-             char c = get_symbol_end ();
+             char *start;
+             char c = get_symbol_name (&start);
 
              if (strcasecmp (start, "msp") != 0)
                {
-                 *input_line_pointer = c;
+                 (void) restore_line_pointer (c);
                  input_line_pointer = hold;
                  str = hold;
                  goto error;
                }
-             *input_line_pointer = c;
+             (void) restore_line_pointer (c);
              goto keep_going;
            }
          else if (operand->flags & MN10300_OPERAND_PC)
            {
-             char *start = input_line_pointer;
-             char c = get_symbol_end ();
+             char *start;
+             char c = get_symbol_name (&start);
 
              if (strcasecmp (start, "pc") != 0)
                {
-                 *input_line_pointer = c;
+                 (void) restore_line_pointer (c);
                  input_line_pointer = hold;
                  str = hold;
                  goto error;
                }
-             *input_line_pointer = c;
+             (void) restore_line_pointer (c);
              goto keep_going;
            }
          else if (operand->flags & MN10300_OPERAND_EPSW)
            {
-             char *start = input_line_pointer;
-             char c = get_symbol_end ();
+             char *start;
+             char c = get_symbol_name (&start);
 
              if (strcasecmp (start, "epsw") != 0)
                {
-                 *input_line_pointer = c;
+                 (void) restore_line_pointer (c);
                  input_line_pointer = hold;
                  str = hold;
                  goto error;
                }
-             *input_line_pointer = c;
+             (void) restore_line_pointer (c);
              goto keep_going;
            }
          else if (operand->flags & MN10300_OPERAND_PLUS)
@@ -1488,32 +1498,32 @@ md_assemble (char *str)
            }
          else if (operand->flags & MN10300_OPERAND_PSW)
            {
-             char *start = input_line_pointer;
-             char c = get_symbol_end ();
+             char *start;
+             char c = get_symbol_name (&start);
 
              if (strcasecmp (start, "psw") != 0)
                {
-                 *input_line_pointer = c;
+                 (void) restore_line_pointer (c);
                  input_line_pointer = hold;
                  str = hold;
                  goto error;
                }
-             *input_line_pointer = c;
+             (void) restore_line_pointer (c);
              goto keep_going;
            }
          else if (operand->flags & MN10300_OPERAND_MDR)
            {
-             char *start = input_line_pointer;
-             char c = get_symbol_end ();
+             char *start;
+             char c = get_symbol_name (&start);
 
              if (strcasecmp (start, "mdr") != 0)
                {
-                 *input_line_pointer = c;
+                 (void) restore_line_pointer (c);
                  input_line_pointer = hold;
                  str = hold;
                  goto error;
                }
-             *input_line_pointer = c;
+             (void) restore_line_pointer (c);
              goto keep_going;
            }
          else if (operand->flags & MN10300_OPERAND_REG_LIST)
@@ -1544,57 +1554,56 @@ md_assemble (char *str)
                  if (*input_line_pointer == ',')
                    input_line_pointer++;
 
-                 start = input_line_pointer;
-                 c = get_symbol_end ();
+                 c = get_symbol_name (&start);
 
                  if (strcasecmp (start, "d2") == 0)
                    {
                      value |= 0x80;
-                     *input_line_pointer = c;
+                     (void) restore_line_pointer (c);
                    }
                  else if (strcasecmp (start, "d3") == 0)
                    {
                      value |= 0x40;
-                     *input_line_pointer = c;
+                     (void) restore_line_pointer (c);
                    }
                  else if (strcasecmp (start, "a2") == 0)
                    {
                      value |= 0x20;
-                     *input_line_pointer = c;
+                     (void) restore_line_pointer (c);
                    }
                  else if (strcasecmp (start, "a3") == 0)
                    {
                      value |= 0x10;
-                     *input_line_pointer = c;
+                     (void) restore_line_pointer (c);
                    }
                  else if (strcasecmp (start, "other") == 0)
                    {
                      value |= 0x08;
-                     *input_line_pointer = c;
+                     (void) restore_line_pointer (c);
                    }
                  else if (HAVE_AM33
                           && strcasecmp (start, "exreg0") == 0)
                    {
                      value |= 0x04;
-                     *input_line_pointer = c;
+                     (void) restore_line_pointer (c);
                    }
                  else if (HAVE_AM33
                           && strcasecmp (start, "exreg1") == 0)
                    {
                      value |= 0x02;
-                     *input_line_pointer = c;
+                     (void) restore_line_pointer (c);
                    }
                  else if (HAVE_AM33
                           && strcasecmp (start, "exother") == 0)
                    {
                      value |= 0x01;
-                     *input_line_pointer = c;
+                     (void) restore_line_pointer (c);
                    }
                  else if (HAVE_AM33
                           && strcasecmp (start, "all") == 0)
                    {
                      value |= 0xff;
-                     *input_line_pointer = c;
+                     (void) restore_line_pointer (c);
                    }
                  else
                    {
@@ -1766,8 +1775,6 @@ keep_going:
         that they do indeed not match.  */
       if (opcode->no_match_operands)
        {
-         int i;
-
          /* Look at each operand to see if it's marked.  */
          for (i = 0; i < MN10300_MAX_OPERANDS; i++)
            {
@@ -2050,18 +2057,23 @@ keep_going:
       for (i = 0; i < fc; i++)
        {
          const struct mn10300_operand *operand;
+         int reloc_size;
 
          operand = &mn10300_operands[fixups[i].opindex];
          if (fixups[i].reloc != BFD_RELOC_UNUSED
              && fixups[i].reloc != BFD_RELOC_32_GOT_PCREL
              && fixups[i].reloc != BFD_RELOC_32_GOTOFF
              && fixups[i].reloc != BFD_RELOC_32_PLT_PCREL
+             && fixups[i].reloc != BFD_RELOC_MN10300_TLS_GD
+             && fixups[i].reloc != BFD_RELOC_MN10300_TLS_LD
+             && fixups[i].reloc != BFD_RELOC_MN10300_TLS_LDO
+             && fixups[i].reloc != BFD_RELOC_MN10300_TLS_GOTIE
+             && fixups[i].reloc != BFD_RELOC_MN10300_TLS_IE
+             && fixups[i].reloc != BFD_RELOC_MN10300_TLS_LE
              && fixups[i].reloc != BFD_RELOC_MN10300_GOT32)
            {
              reloc_howto_type *reloc_howto;
-             int size;
              int offset;
-             fixS *fixP;
 
              reloc_howto = bfd_reloc_type_lookup (stdoutput,
                                                   fixups[i].reloc);
@@ -2069,20 +2081,20 @@ keep_going:
              if (!reloc_howto)
                abort ();
 
-             size = bfd_get_reloc_size (reloc_howto);
+             reloc_size = bfd_get_reloc_size (reloc_howto);
 
-             if (size < 1 || size > 4)
+             if (reloc_size < 1 || reloc_size > 4)
                abort ();
 
              offset = 4 - size;
-             fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset,
-                                 size, &fixups[i].exp,
-                                 reloc_howto->pc_relative,
-                                 fixups[i].reloc);
+             fix_new_exp (frag_now, f - frag_now->fr_literal + offset,
+                          reloc_size, &fixups[i].exp,
+                          reloc_howto->pc_relative,
+                          fixups[i].reloc);
            }
          else
            {
-             int reloc, pcrel, reloc_size, offset;
+             int reloc, pcrel, offset;
              fixS *fixP;
 
              reloc = BFD_RELOC_NONE;
@@ -2141,15 +2153,21 @@ keep_going:
 
       dwarf2_emit_insn (size);
     }
+
+  /* Label this frag as one that contains instructions.  */
+  frag_now->tc_frag_data = TRUE;
 }
 
 /* If while processing a fixup, a reloc really needs to be created
    then it is done here.  */
 
-arelent *
+arelent **
 tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp)
 {
+  static arelent * no_relocs = NULL;
+  static arelent * relocs[MAX_RELOC_EXPANSION + 1];
   arelent *reloc;
+
   reloc = xmalloc (sizeof (arelent));
 
   reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
@@ -2158,9 +2176,13 @@ tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp)
       as_bad_where (fixp->fx_file, fixp->fx_line,
                    _("reloc %d not supported by object file format"),
                    (int) fixp->fx_r_type);
-      return NULL;
+      free (reloc);
+      return & no_relocs;
     }
+
   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
+  relocs[0] = reloc;
+  relocs[1] = NULL;
 
   if (fixp->fx_subsy
       && S_GET_SEGMENT (fixp->fx_subsy) == absolute_section)
@@ -2171,53 +2193,43 @@ tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp)
 
   if (fixp->fx_addsy && fixp->fx_subsy)
     {
-      reloc->sym_ptr_ptr = NULL;
-
-      /* If we got a difference between two symbols, and the
-        subtracted symbol is in the current section, use a
-        PC-relative relocation.  If both symbols are in the same
-        section, the difference would have already been simplified
-        to a constant.  */
-      if (S_GET_SEGMENT (fixp->fx_subsy) == seg)
-       {
-         reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
-         *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
-         reloc->addend = (reloc->address - S_GET_VALUE (fixp->fx_subsy)
-                          + fixp->fx_offset);
+      asection *asec, *ssec;
 
-         switch (fixp->fx_r_type)
-           {
-           case BFD_RELOC_8:
-             reloc->howto = bfd_reloc_type_lookup (stdoutput,
-                                                   BFD_RELOC_8_PCREL);
-             return reloc;
+      asec = S_GET_SEGMENT (fixp->fx_addsy);
+      ssec = S_GET_SEGMENT (fixp->fx_subsy);
 
-           case BFD_RELOC_16:
-             reloc->howto = bfd_reloc_type_lookup (stdoutput,
-                                                   BFD_RELOC_16_PCREL);
-             return reloc;
+      /* If we have a difference between two (non-absolute) symbols we must
+        generate two relocs (one for each symbol) and allow the linker to
+        resolve them - relaxation may change the distances between symbols,
+        even local symbols defined in the same section.  */
+      if (ssec != absolute_section || asec != absolute_section)
+       {
+         arelent * reloc2 = xmalloc (sizeof * reloc);
 
-           case BFD_RELOC_24:
-             reloc->howto = bfd_reloc_type_lookup (stdoutput,
-                                                   BFD_RELOC_24_PCREL);
-             return reloc;
+         relocs[0] = reloc2;
+         relocs[1] = reloc;
 
-           case BFD_RELOC_32:
-             reloc->howto = bfd_reloc_type_lookup (stdoutput,
-                                                   BFD_RELOC_32_PCREL);
-             return reloc;
+         reloc2->address = reloc->address;
+         reloc2->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_MN10300_SYM_DIFF);
+         reloc2->addend = - S_GET_VALUE (fixp->fx_subsy);
+         reloc2->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
+         *reloc2->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_subsy);
 
-           default:
-             /* Try to compute the absolute value below.  */
-             break;
+         reloc->addend = fixp->fx_offset;
+         if (asec == absolute_section)
+           {
+             reloc->addend += S_GET_VALUE (fixp->fx_addsy);
+             reloc->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
+           }
+         else
+           {
+             reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
+             *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
            }
-       }
 
-      if ((S_GET_SEGMENT (fixp->fx_addsy) != S_GET_SEGMENT (fixp->fx_subsy))
-         || S_GET_SEGMENT (fixp->fx_addsy) == undefined_section)
-       {
-         as_bad_where (fixp->fx_file, fixp->fx_line,
-                       "Difference of symbols in different sections is not supported");
+         fixp->fx_pcrel = 0;
+         fixp->fx_done = 1;
+         return relocs;
        }
       else
        {
@@ -2247,14 +2259,12 @@ tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp)
            default:
              reloc->sym_ptr_ptr
                = (asymbol **) bfd_abs_section_ptr->symbol_ptr_ptr;
-             return reloc;
+             return relocs;
            }
-       }
 
-      if (reloc->sym_ptr_ptr)
-       free (reloc->sym_ptr_ptr);
-      free (reloc);
-      return NULL;
+         free (reloc);
+         return & no_relocs;
+       }
     }
   else
     {
@@ -2262,27 +2272,39 @@ tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp)
       *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
       reloc->addend = fixp->fx_offset;
     }
-  return reloc;
+  return relocs;
+}
+
+/* Returns true iff the symbol attached to the frag is at a known location
+   in the given section, (and hence the relocation to it can be relaxed by
+   the assembler).  */
+static inline bfd_boolean
+has_known_symbol_location (fragS * fragp, asection * sec)
+{
+  symbolS * sym = fragp->fr_symbol;
+
+  return sym != NULL
+    && S_IS_DEFINED (sym)
+    && ! S_IS_WEAK (sym)
+    && S_GET_SEGMENT (sym) == sec;
 }
 
 int
 md_estimate_size_before_relax (fragS *fragp, asection *seg)
 {
   if (fragp->fr_subtype == 6
-      && (!S_IS_DEFINED (fragp->fr_symbol)
-         || seg != S_GET_SEGMENT (fragp->fr_symbol)))
+      && ! has_known_symbol_location (fragp, seg))
     fragp->fr_subtype = 7;
   else if (fragp->fr_subtype == 8
-          && (!S_IS_DEFINED (fragp->fr_symbol)
-              || seg != S_GET_SEGMENT (fragp->fr_symbol)))
+          && ! has_known_symbol_location (fragp, seg))
     fragp->fr_subtype = 9;
   else if (fragp->fr_subtype == 10
-          &&  (!S_IS_DEFINED (fragp->fr_symbol)
-               || seg != S_GET_SEGMENT (fragp->fr_symbol)))
+          && ! has_known_symbol_location (fragp, seg))
     fragp->fr_subtype = 12;
 
   if (fragp->fr_subtype == 13)
     return 3;
+
   if (fragp->fr_subtype >= sizeof (md_relax_table) / sizeof (md_relax_table[0]))
     abort ();
 
@@ -2292,11 +2314,11 @@ md_estimate_size_before_relax (fragS *fragp, asection *seg)
 long
 md_pcrel_from (fixS *fixp)
 {
-  if (fixp->fx_addsy != NULL && !S_IS_DEFINED (fixp->fx_addsy))
-    {
-      /* The symbol is undefined.  Let the linker figure it out.  */
-      return 0;
-    }
+  if (fixp->fx_addsy != (symbolS *) NULL
+      && (!S_IS_DEFINED (fixp->fx_addsy) || S_IS_WEAK (fixp->fx_addsy)))
+    /* The symbol is undefined or weak.  Let the linker figure it out.  */
+    return 0;
+
   return fixp->fx_frag->fr_address + fixp->fx_where;
 }
 
@@ -2307,7 +2329,7 @@ md_apply_fix (fixS * fixP, valueT * valP, segT seg)
   int size = 0;
   int value = (int) * valP;
 
-  assert (fixP->fx_r_type < BFD_RELOC_UNUSED);
+  gas_assert (fixP->fx_r_type < BFD_RELOC_UNUSED);
 
   /* This should never happen.  */
   if (seg->flags & SEC_ALLOC)
@@ -2358,6 +2380,10 @@ md_apply_fix (fixS * fixP, valueT * valP, segT seg)
       fixP->fx_done = 0;
       return;
 
+    case BFD_RELOC_MN10300_ALIGN:
+      fixP->fx_done = 1;
+      return;
+
     case BFD_RELOC_NONE:
     default:
       as_bad_where (fixP->fx_file, fixP->fx_line,
@@ -2377,11 +2403,14 @@ md_apply_fix (fixS * fixP, valueT * valP, segT seg)
 bfd_boolean
 mn10300_fix_adjustable (struct fix *fixp)
 {
-  if (TC_FORCE_RELOCATION_LOCAL (fixp))
-    return FALSE;
-
-  if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
-      || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+  if (fixp->fx_pcrel)
+    {
+      if (TC_FORCE_RELOCATION_LOCAL (fixp))
+       return FALSE;
+    }
+  /* Non-relative relocs can (and must) be adjusted if they do
+     not meet the criteria below, or the generic criteria.  */
+  else if (TC_FORCE_RELOCATION (fixp))
     return FALSE;
 
   /* Do not adjust relocations involving symbols in code sections,
@@ -2395,8 +2424,9 @@ mn10300_fix_adjustable (struct fix *fixp)
      symbols, because they too break relaxation.  We do want to adjust
      other mergable symbols, like .rodata, because code relaxations
      need section-relative symbols to properly relax them.  */
-  if (! (S_GET_SEGMENT(fixp->fx_addsy)->flags & SEC_MERGE))
+  if (! (S_GET_SEGMENT (fixp->fx_addsy)->flags & SEC_MERGE))
     return FALSE;
+
   if (strncmp (S_GET_SEGMENT (fixp->fx_addsy)->name, ".debug", 6) == 0)
     return FALSE;
 
@@ -2413,7 +2443,7 @@ set_arch_mach (int mach)
 }
 
 static inline char *
-mn10300_end_of_match (char *cont, char *what)
+mn10300_end_of_match (char *cont, const char *what)
 {
   int len = strlen (what);
 
@@ -2422,7 +2452,7 @@ mn10300_end_of_match (char *cont, char *what)
     return cont + len;
 
   return NULL;
-}  
+}
 
 int
 mn10300_parse_name (char const *name,
@@ -2469,7 +2499,7 @@ mn10300_parse_name (char const *name,
     }
 
   exprP->X_add_symbol = symbol_find_or_make (name);
-  
+
   if (*nextcharP != '@')
     goto no_suffix;
   else if ((next_end = mn10300_end_of_match (next + 1, "GOTOFF")))
@@ -2478,6 +2508,18 @@ mn10300_parse_name (char const *name,
     reloc_type = BFD_RELOC_MN10300_GOT32;
   else if ((next_end = mn10300_end_of_match (next + 1, "PLT")))
     reloc_type = BFD_RELOC_32_PLT_PCREL;
+  else if ((next_end = mn10300_end_of_match (next + 1, "tlsgd")))
+    reloc_type = BFD_RELOC_MN10300_TLS_GD;
+  else if ((next_end = mn10300_end_of_match (next + 1, "tlsldm")))
+    reloc_type = BFD_RELOC_MN10300_TLS_LD;
+  else if ((next_end = mn10300_end_of_match (next + 1, "dtpoff")))
+    reloc_type = BFD_RELOC_MN10300_TLS_LDO;
+  else if ((next_end = mn10300_end_of_match (next + 1, "gotntpoff")))
+    reloc_type = BFD_RELOC_MN10300_TLS_GOTIE;
+  else if ((next_end = mn10300_end_of_match (next + 1, "indntpoff")))
+    reloc_type = BFD_RELOC_MN10300_TLS_IE;
+  else if ((next_end = mn10300_end_of_match (next + 1, "tpoff")))
+    reloc_type = BFD_RELOC_MN10300_TLS_LE;
   else
     goto no_suffix;
 
@@ -2502,3 +2544,95 @@ const pseudo_typeS md_pseudo_table[] =
   { "mn10300", set_arch_mach,  MN103 },
   {NULL, 0, 0}
 };
+
+/* Returns FALSE if there is some mn10300 specific reason why the
+   subtraction of two same-section symbols cannot be computed by
+   the assembler.  */
+
+bfd_boolean
+mn10300_allow_local_subtract (expressionS * left, expressionS * right, segT section)
+{
+  bfd_boolean result;
+  fragS * left_frag;
+  fragS * right_frag;
+  fragS * frag;
+
+  /* If we are not performing linker relaxation then we have nothing
+     to worry about.  */
+  if (linkrelax == 0)
+    return TRUE;
+
+  /* If the symbols are not in a code section then they are OK.  */
+  if ((section->flags & SEC_CODE) == 0)
+    return TRUE;
+
+  /* Otherwise we have to scan the fragments between the two symbols.
+     If any instructions are found then we have to assume that linker
+     relaxation may change their size and so we must delay resolving
+     the subtraction until the final link.  */
+  left_frag = symbol_get_frag (left->X_add_symbol);
+  right_frag = symbol_get_frag (right->X_add_symbol);
+
+  if (left_frag == right_frag)
+    return ! left_frag->tc_frag_data;
+
+  result = TRUE;
+  for (frag = left_frag; frag != NULL; frag = frag->fr_next)
+    {
+      if (frag->tc_frag_data)
+       result = FALSE;
+      if (frag == right_frag)
+       break;
+    }
+
+  if (frag == NULL)
+    for (frag = right_frag; frag != NULL; frag = frag->fr_next)
+      {
+       if (frag->tc_frag_data)
+         result = FALSE;
+       if (frag == left_frag)
+         break;
+      }
+
+  if (frag == NULL)
+    /* The two symbols are on disjoint fragment chains
+       - we cannot possibly compute their difference.  */
+    return FALSE;
+
+  return result;
+}
+
+/* When relaxing, we need to output a reloc for any .align directive
+   that requests alignment to a two byte boundary or larger.  */
+
+void
+mn10300_handle_align (fragS *frag)
+{
+  if (linkrelax
+      && (frag->fr_type == rs_align
+         || frag->fr_type == rs_align_code)
+      && frag->fr_address + frag->fr_fix > 0
+      && frag->fr_offset > 1
+      && now_seg != bss_section
+      /* Do not create relocs for the merging sections - such
+        relocs will prevent the contents from being merged.  */
+      && (bfd_get_section_flags (now_seg->owner, now_seg) & SEC_MERGE) == 0)
+    /* Create a new fixup to record the alignment request.  The symbol is
+       irrelevent but must be present so we use the absolute section symbol.
+       The offset from the symbol is used to record the power-of-two alignment
+       value.  The size is set to 0 because the frag may already be aligned,
+       thus causing cvt_frag_to_fill to reduce the size of the frag to zero.  */
+    fix_new (frag, frag->fr_fix, 0, & abs_symbol, frag->fr_offset, FALSE,
+            BFD_RELOC_MN10300_ALIGN);
+}
+
+bfd_boolean
+mn10300_force_relocation (struct fix * fixp)
+{
+  if (linkrelax
+      && (fixp->fx_pcrel
+         || fixp->fx_r_type == BFD_RELOC_MN10300_ALIGN))
+    return TRUE;
+
+  return generic_force_reloc (fixp);
+}
This page took 0.038421 seconds and 4 git commands to generate.