daily update
[external/binutils.git] / gas / config / tc-mn10300.c
index 5ec58bb..1ddb110 100644 (file)
@@ -1,6 +1,6 @@
 /* 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.
+   2006, 2007, 2008, 2009 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -675,6 +675,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,6 +685,7 @@ 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];
@@ -696,6 +698,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 +709,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 +729,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 +740,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,
@@ -1766,8 +1772,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,6 +2054,7 @@ 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
@@ -2059,7 +2064,6 @@ keep_going:
              && fixups[i].reloc != BFD_RELOC_MN10300_GOT32)
            {
              reloc_howto_type *reloc_howto;
-             int size;
              int offset;
              fixS *fixP;
 
@@ -2069,20 +2073,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_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;
@@ -2181,13 +2185,18 @@ tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp)
 
   if (fixp->fx_addsy && fixp->fx_subsy)
     {
+      asection *asec, *ssec;
+
+      asec = S_GET_SEGMENT (fixp->fx_addsy);
+      ssec = S_GET_SEGMENT (fixp->fx_subsy);
+
       reloc->sym_ptr_ptr = NULL;
 
       /* 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 segment.  */
-      if (S_GET_SEGMENT (fixp->fx_subsy) == seg)
+        even local symbols defined in the same section.  */
+      if (ssec != absolute_section || asec != absolute_section)
        {
          arelent * reloc2 = xmalloc (sizeof * reloc);
 
@@ -2201,7 +2210,7 @@ tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp)
          *reloc2->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_subsy);
 
          reloc->addend = fixp->fx_offset; 
-         if (S_GET_SEGMENT (fixp->fx_addsy) == absolute_section)
+         if (asec == absolute_section)
            reloc->addend += S_GET_VALUE (fixp->fx_addsy);
 
          reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
@@ -2211,13 +2220,6 @@ tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp)
          fixp->fx_done = 1;
          return relocs;
        }
-
-      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");
-       }
       else
        {
          char *fixpos = fixp->fx_where + fixp->fx_frag->fr_literal;
@@ -2248,12 +2250,12 @@ tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp)
                = (asymbol **) bfd_abs_section_ptr->symbol_ptr_ptr;
              return relocs;
            }
-       }
 
-      if (reloc->sym_ptr_ptr)
-       free (reloc->sym_ptr_ptr);
-      free (reloc);
-      return & no_relocs;
+         if (reloc->sym_ptr_ptr)
+           free (reloc->sym_ptr_ptr);
+         free (reloc);
+         return & no_relocs;
+       }
     }
   else
     {
@@ -2264,24 +2266,36 @@ tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp)
   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 ();
 
@@ -2291,11 +2305,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;
 }
 
@@ -2306,7 +2320,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)
@@ -2357,6 +2371,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,
@@ -2562,3 +2580,38 @@ mn10300_allow_local_subtract (expressionS * left, expressionS * right, segT sect
 
   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);
+}