Warning and partial fix for gcc -freorder-blocks-and-partition related problem.
[deliverable/binutils-gdb.git] / gas / config / tc-ia64.c
index f458550e2dd7c19c0da87af060b92fa79d8fc244..cab32cd04737fae2c947838f7d98f7fd680641ae 100644 (file)
@@ -17,8 +17,8 @@
 
    You should have received a copy of the GNU General Public License
    along with GAS; see the file COPYING.  If not, write to
-   the Free Software Foundation, 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   the Free Software Foundation, 51 Franklin Street - Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
 
 /*
   TODO:
@@ -56,6 +56,9 @@
 #endif
 
 #define NELEMS(a)      ((int) (sizeof (a)/sizeof ((a)[0])))
+
+/* Some systems define MIN in, e.g., param.h.  */
+#undef MIN
 #define MIN(a,b)       ((a) < (b) ? (a) : (b))
 
 #define NUM_SLOTS      4
@@ -692,8 +695,6 @@ typedef struct unw_rec_list {
   unwind_record r;
   unsigned long slot_number;
   fragS *slot_frag;
-  unsigned long next_slot_number;
-  fragS *next_slot_frag;
   struct unw_rec_list *next;
 } unw_rec_list;
 
@@ -708,6 +709,12 @@ typedef struct label_prologue_count
   unsigned int prologue_count;
 } label_prologue_count;
 
+typedef struct proc_pending
+{
+  symbolS *sym;
+  struct proc_pending *next;
+} proc_pending;
+
 static struct
 {
   /* Maintain a list of unwind entries for the current function.  */
@@ -719,7 +726,7 @@ static struct
   unw_rec_list *current_entry;
 
   /* These are used to create the unwind table entry for this function.  */
-  symbolS *proc_start;
+  proc_pending proc_pending;
   symbolS *info;               /* pointer to unwind info */
   symbolS *personality_routine;
   segT saved_text_seg;
@@ -1747,8 +1754,6 @@ alloc_record (unw_record_type t)
   ptr->next = NULL;
   ptr->slot_number = SLOT_NUM_NOT_SET;
   ptr->r.type = t;
-  ptr->next_slot_number = 0;
-  ptr->next_slot_frag = 0;
   return ptr;
 }
 
@@ -2703,6 +2708,26 @@ slot_index (slot_addr, slot_frag, first_addr, first_frag, before_relax)
       /* Move to the beginning of the next frag.  */
       first_frag = first_frag->fr_next;
       first_addr = (unsigned long) &first_frag->fr_literal;
+
+      /* This can happen if there is section switching in the middle of a
+        function, causing the frag chain for the function to be broken.  */
+      if (first_frag == NULL)
+       {
+         /* We get six warnings for one problem, because of the loop in
+            fixup_unw_records, and because fixup_unw_records is called 3
+            times: once before creating the variant frag, once to estimate
+            its size, and once to relax it.  This is unreasonable, so we use
+            a static var to make sure we only emit the warning once.  */
+         static int warned = 0;
+
+         if (!warned)
+           {
+             as_warn ("Corrupted unwind info due to unsupported section switching");
+             warned = 1;
+           }
+
+         return index;
+       }
     }
 
   /* Add in the used part of the last frag.  */
@@ -3071,17 +3096,20 @@ static void
 dot_radix (dummy)
      int dummy ATTRIBUTE_UNUSED;
 {
-  int radix;
+  char *radix;
+  int ch;
 
   SKIP_WHITESPACE ();
-  radix = *input_line_pointer++;
 
-  if (radix != 'C' && !is_end_of_line[(unsigned char) radix])
-    {
-      as_bad ("Radix `%c' unsupported", *input_line_pointer);
-      ignore_rest_of_line ();
-      return;
-    }
+  if (is_it_end_of_statement ())
+    return;
+  radix = input_line_pointer;
+  ch = get_symbol_end ();
+  ia64_canonicalize_symbol_name (radix);
+  if (strcasecmp (radix, "C"))
+    as_bad ("Radix `%s' unsupported or invalid", radix);
+  *input_line_pointer = ch;
+  demand_empty_rest_of_line ();
 }
 
 /* Helper function for .loc directives.  If the assembler is not generating
@@ -3129,7 +3157,7 @@ unwind_diagnostic (const char * region, const char *directive)
 static int
 in_procedure (const char *directive)
 {
-  if (unwind.proc_start
+  if (unwind.proc_pending.sym
       && (!unwind.saved_text_seg || strcmp (directive, "endp") == 0))
     return 1;
   return unwind_diagnostic ("procedure", directive);
@@ -3460,7 +3488,7 @@ static char *special_linkonce_name[] =
   };
 
 static void
-start_unwind_section (const segT text_seg, int sec_index, int linkonce_empty)
+start_unwind_section (const segT text_seg, int sec_index)
 {
   /*
     Use a slightly ugly scheme to derive the unwind section names from
@@ -3522,8 +3550,6 @@ start_unwind_section (const segT text_seg, int sec_index, int linkonce_empty)
       prefix = special_linkonce_name [sec_index - SPECIAL_SECTION_UNWIND];
       suffix += sizeof (".gnu.linkonce.t.") - 1;
     }
-  else if (linkonce_empty)
-    return;
 
   prefix_len = strlen (prefix);
   suffix_len = strlen (suffix);
@@ -3534,7 +3560,8 @@ start_unwind_section (const segT text_seg, int sec_index, int linkonce_empty)
   sec_name [sec_name_len] = '\0';
 
   /* Handle COMDAT group.  */
-  if (suffix == text_name && (text_seg->flags & SEC_LINK_ONCE) != 0)
+  if ((text_seg->flags & SEC_LINK_ONCE) != 0
+      && (elf_section_flags (text_seg) & SHF_GROUP) != 0)
     {
       char *section;
       size_t len, group_name_len;
@@ -3611,7 +3638,7 @@ generate_unwind_image (const segT text_seg)
       expressionS exp;
       bfd_reloc_code_real_type reloc;
 
-      start_unwind_section (text_seg, SPECIAL_SECTION_UNWIND_INFO, 0);
+      start_unwind_section (text_seg, SPECIAL_SECTION_UNWIND_INFO);
 
       /* Make sure the section has 4 byte alignment for ILP32 and
         8 byte alignment for LP64.  */
@@ -3652,8 +3679,6 @@ generate_unwind_image (const segT text_seg)
          unwind.personality_routine = 0;
        }
     }
-  else
-    start_unwind_section (text_seg, SPECIAL_SECTION_UNWIND_INFO, 1);
 
   free_saved_prologue_counts ();
   unwind.list = unwind.tail = unwind.current_entry = NULL;
@@ -4269,8 +4294,22 @@ dot_proc (dummy)
 {
   char *name, *p, c;
   symbolS *sym;
+  proc_pending *pending, *last_pending;
+
+  if (unwind.proc_pending.sym)
+    {
+      (md.unwind_check == unwind_check_warning
+       ? as_warn
+       : as_bad) ("Missing .endp after previous .proc");
+      while (unwind.proc_pending.next)
+       {
+         pending = unwind.proc_pending.next;
+         unwind.proc_pending.next = pending->next;
+         free (pending);
+       }
+    }
+  last_pending = NULL;
 
-  unwind.proc_start = 0;
   /* Parse names of main and alternate entry points and mark them as
      function symbols:  */
   while (1)
@@ -4286,9 +4325,16 @@ dot_proc (dummy)
          sym = symbol_find_or_make (name);
          if (S_IS_DEFINED (sym))
            as_bad ("`%s' was already defined", name);
-         else if (unwind.proc_start == 0)
+         else if (!last_pending)
            {
-             unwind.proc_start = sym;
+             unwind.proc_pending.sym = sym;
+             last_pending = &unwind.proc_pending;
+           }
+         else
+           {
+             pending = xmalloc (sizeof (*pending));
+             pending->sym = sym;
+             last_pending = last_pending->next = pending;
            }
          symbol_get_bfdsym (sym)->flags |= BSF_FUNCTION;
        }
@@ -4298,8 +4344,12 @@ dot_proc (dummy)
        break;
       ++input_line_pointer;
     }
-  if (unwind.proc_start == 0)
-    unwind.proc_start = expr_build_dot ();
+  if (!last_pending)
+    {
+      unwind.proc_pending.sym = expr_build_dot ();
+      last_pending = &unwind.proc_pending;
+    }
+  last_pending->next = NULL;
   demand_empty_rest_of_line ();
   ia64_do_align (16);
 
@@ -4387,13 +4437,11 @@ dot_endp (dummy)
      int dummy ATTRIBUTE_UNUSED;
 {
   expressionS e;
-  char *ptr;
   int bytes_per_address;
   long where;
   segT saved_seg;
   subsegT saved_subseg;
-  char *name, *default_name, *p, c;
-  symbolS *sym;
+  proc_pending *pending;
   int unwind_check = md.unwind_check;
 
   md.unwind_check = unwind_check_error;
@@ -4426,7 +4474,7 @@ dot_endp (dummy)
       subseg_set (md.last_text_seg, 0);
       proc_end = expr_build_dot ();
 
-      start_unwind_section (saved_seg, SPECIAL_SECTION_UNWIND, 0);
+      start_unwind_section (saved_seg, SPECIAL_SECTION_UNWIND);
 
       /* Make sure that section has 4 byte alignment for ILP32 and
          8 byte alignment for LP64.  */
@@ -4434,7 +4482,7 @@ dot_endp (dummy)
 
       /* Need space for 3 pointers for procedure start, procedure end,
         and unwind info.  */
-      ptr = frag_more (3 * md.pointer_size);
+      memset (frag_more (3 * md.pointer_size), 0, 3 * md.pointer_size);
       where = frag_now_fix () - (3 * md.pointer_size);
       bytes_per_address = bfd_arch_bits_per_address (stdoutput) / 8;
 
@@ -4442,7 +4490,13 @@ dot_endp (dummy)
       e.X_op = O_pseudo_fixup;
       e.X_op_symbol = pseudo_func[FUNC_SEG_RELATIVE].u.sym;
       e.X_add_number = 0;
-      e.X_add_symbol = unwind.proc_start;
+      if (!S_IS_LOCAL (unwind.proc_pending.sym)
+         && S_IS_DEFINED (unwind.proc_pending.sym))
+       e.X_add_symbol = symbol_temp_new (S_GET_SEGMENT (unwind.proc_pending.sym),
+                                         S_GET_VALUE (unwind.proc_pending.sym),
+                                         symbol_get_frag (unwind.proc_pending.sym));
+      else
+       e.X_add_symbol = unwind.proc_pending.sym;
       ia64_cons_fix_new (frag_now, where, bytes_per_address, &e);
 
       e.X_op = O_pseudo_fixup;
@@ -4461,72 +4515,25 @@ dot_endp (dummy)
          ia64_cons_fix_new (frag_now, where + (bytes_per_address * 2),
                             bytes_per_address, &e);
        }
-      else
-       md_number_to_chars (ptr + (bytes_per_address * 2), 0,
-                           bytes_per_address);
-
     }
-  else
-    start_unwind_section (saved_seg, SPECIAL_SECTION_UNWIND, 1);
-
   subseg_set (saved_seg, saved_subseg);
 
-  if (unwind.proc_start)
-    default_name = (char *) S_GET_NAME (unwind.proc_start);
-  else
-    default_name = NULL;
-
-  /* Parse names of main and alternate entry points and set symbol sizes.  */
-  while (1)
+  /* Set symbol sizes.  */
+  pending = &unwind.proc_pending;
+  if (S_GET_NAME (pending->sym))
     {
-      SKIP_WHITESPACE ();
-      name = input_line_pointer;
-      c = get_symbol_end ();
-      p = input_line_pointer;
-      if (!*name)
-       {
-         if (md.unwind_check == unwind_check_warning)
-           {
-             if (default_name)
-               {
-                 as_warn ("Empty argument of .endp. Use the default name `%s'",
-                          default_name);
-                 name = default_name;
-               }
-             else
-               as_warn ("Empty argument of .endp");
-           }
-         else
-           as_bad ("Empty argument of .endp");
-       }
-      if (*name)
+      do
        {
-         sym = symbol_find (name);
-         if (!sym
-             && md.unwind_check == unwind_check_warning
-             && default_name
-             && default_name != name)
-           {
-             /* We have a bad name. Try the default one if needed.  */
-             as_warn ("`%s' was not defined within procedure. Use the default name `%s'",
-                      name, default_name);
-             name = default_name;
-             sym = symbol_find (name);
-           }
-         if (!sym || !S_IS_DEFINED (sym))
-           as_bad ("`%s' was not defined within procedure", name);
-         else if (unwind.proc_start
-             && (symbol_get_bfdsym (sym)->flags & BSF_FUNCTION)
-             && S_GET_SIZE (sym) == 0 && symbol_get_obj (sym)->size == NULL)
+         symbolS *sym = pending->sym;
+
+         if (!S_IS_DEFINED (sym))
+           as_bad ("`%s' was not defined within procedure", S_GET_NAME (sym));
+         else if (S_GET_SIZE (sym) == 0
+                  && symbol_get_obj (sym)->size == NULL)
            {
-             fragS *fr = symbol_get_frag (unwind.proc_start);
              fragS *frag = symbol_get_frag (sym);
 
-             /* Check whether the function label is at or beyond last
-                .proc directive.  */
-             while (fr && fr != frag)
-               fr = fr->fr_next;
-             if (fr)
+             if (frag)
                {
                  if (frag == frag_now && SEG_NORMAL (now_seg))
                    S_SET_SIZE (sym, frag_now_fix () - S_GET_VALUE (sym));
@@ -4543,6 +4550,36 @@ dot_endp (dummy)
                    }
                }
            }
+       } while ((pending = pending->next) != NULL);
+    }
+
+  /* Parse names of main and alternate entry points.  */
+  while (1)
+    {
+      char *name, *p, c;
+
+      SKIP_WHITESPACE ();
+      name = input_line_pointer;
+      c = get_symbol_end ();
+      p = input_line_pointer;
+      if (!*name)
+       (md.unwind_check == unwind_check_warning
+        ? as_warn
+        : as_bad) ("Empty argument of .endp");
+      else
+       {
+         symbolS *sym = symbol_find (name);
+
+         for (pending = &unwind.proc_pending; pending; pending = pending->next)
+           {
+             if (sym == pending->sym)
+               {
+                 pending->sym = NULL;
+                 break;
+               }
+           }
+         if (!sym || !pending)
+           as_warn ("`%s' was not specified with previous .proc", name);
        }
       *p = c;
       SKIP_WHITESPACE ();
@@ -4551,7 +4588,21 @@ dot_endp (dummy)
       ++input_line_pointer;
     }
   demand_empty_rest_of_line ();
-  unwind.proc_start = unwind.info = 0;
+
+  /* Deliberately only checking for the main entry point here; the
+     language spec even says all arguments to .endp are ignored.  */
+  if (unwind.proc_pending.sym
+      && S_GET_NAME (unwind.proc_pending.sym)
+      && strcmp (S_GET_NAME (unwind.proc_pending.sym), FAKE_LABEL_NAME))
+    as_warn ("`%s' should be an operand to this .endp",
+            S_GET_NAME (unwind.proc_pending.sym));
+  while (unwind.proc_pending.next)
+    {
+      pending = unwind.proc_pending.next;
+      unwind.proc_pending.next = pending->next;
+      free (pending);
+    }
+  unwind.proc_pending.sym = unwind.info = NULL;
 }
 
 static void
@@ -5964,7 +6015,7 @@ operand_match (idesc, index, e)
        case O_symbol:
          fix = CURR_SLOT.fixup + CURR_SLOT.num_fixups;
          /* There are no external relocs for TAG13/TAG13b fields, so we
-            create a dummy reloc.  This will not live past md_apply_fix3.  */
+            create a dummy reloc.  This will not live past md_apply_fix.  */
          fix->code = BFD_RELOC_UNUSED;
          fix->code = ia64_gen_real_reloc_type (e->X_op_symbol, fix->code);
          fix->opnd = idesc->operands[index];
@@ -6482,7 +6533,6 @@ emit_one_bundle ()
   struct ia64_opcode *idesc;
   int end_of_insn_group = 0, user_template = -1;
   int n, i, j, first, curr, last_slot;
-  unw_rec_list *ptr, *last_ptr, *end_ptr;
   bfd_vma t0 = 0, t1 = 0;
   struct label_fix *lfix;
   struct insn_fix *ifix;
@@ -6537,7 +6587,9 @@ emit_one_bundle ()
   for (i = 0; i < 3 && md.num_slots_in_use > 0; ++i)
     {
       /* If we have unwind records, we may need to update some now.  */
-      ptr = md.slot[curr].unwind_record;
+      unw_rec_list *ptr = md.slot[curr].unwind_record;
+      unw_rec_list *end_ptr = NULL;
+
       if (ptr)
        {
          /* Find the last prologue/body record in the list for the current
@@ -6547,9 +6599,11 @@ emit_one_bundle ()
             issued.  This matters because there may have been nops emitted
             meanwhile.  Any non-prologue non-body record followed by a
             prologue/body record must also refer to the current point.  */
-         last_ptr = NULL;
-         end_ptr = md.slot[(curr + 1) % NUM_SLOTS].unwind_record;
-         for (; ptr != end_ptr; ptr = ptr->next)
+         unw_rec_list *last_ptr;
+
+         for (j = 1; end_ptr == NULL && j < md.num_slots_in_use; ++j)
+           end_ptr = md.slot[(curr + j) % NUM_SLOTS].unwind_record;
+         for (last_ptr = NULL; ptr != end_ptr; ptr = ptr->next)
            if (ptr->r.type == prologue || ptr->r.type == prologue_gr
                || ptr->r.type == body)
              last_ptr = ptr;
@@ -6817,7 +6871,6 @@ emit_one_bundle ()
          /* Set slot numbers for all remaining unwind records belonging to the
             current insn.  There can not be any prologue/body unwind records
             here.  */
-         end_ptr = md.slot[(curr + 1) % NUM_SLOTS].unwind_record;
          for (; ptr != end_ptr; ptr = ptr->next)
            {
              ptr->slot_number = (unsigned long) f + i;
@@ -6919,12 +6972,6 @@ emit_one_bundle ()
 
   number_to_chars_littleendian (f + 0, t0, 8);
   number_to_chars_littleendian (f + 8, t1, 8);
-
-  if (unwind.list)
-    {
-      unwind.list->next_slot_number = (unsigned long) f + 16;
-      unwind.list->next_slot_frag = frag_now;
-    }
 }
 
 int
@@ -7150,8 +7197,9 @@ match (int templ, int type, int slot)
   return result;
 }
 
-/* Add a bit of extra goodness if a nop of type F or B would fit
-   in TEMPL at SLOT.  */
+/* For Itanium 1, add a bit of extra goodness if a nop of type F or B would fit
+   in TEMPL at SLOT.  For Itanium 2, add a bit of extra goodness if a nop of
+   type M or I would fit in TEMPL at SLOT.  */
 
 static inline int
 extra_goodness (int templ, int slot)
@@ -7297,7 +7345,7 @@ md_begin ()
                {
                  if (match (t, j, 1))
                    {
-                     if (match (t, k, 2))
+                     if ((t == 2 && j == IA64_TYPE_X) || match (t, k, 2))
                        goodness = 3 + 3 + 3;
                      else
                        goodness = 3 + 3 + extra_goodness (t, 2);
@@ -7313,7 +7361,7 @@ md_begin ()
                }
              else if (match (t, i, 1))
                {
-                 if (match (t, j, 2))
+                 if ((t == 2 && i == IA64_TYPE_X) || match (t, j, 2))
                    goodness = 3 + 3;
                  else
                    goodness = 3 + extra_goodness (t, 2);
@@ -7329,6 +7377,21 @@ md_begin ()
            }
        }
 
+#ifdef DEBUG_TEMPLATES
+  /* For debugging changes to the best_template calculations.  We don't care
+     about combinations with invalid instructions, so start the loops at 1.  */
+  for (i = 0; i < IA64_NUM_TYPES; ++i)
+    for (j = 0; j < IA64_NUM_TYPES; ++j)
+      for (k = 0; k < IA64_NUM_TYPES; ++k)
+       {
+         char type_letter[IA64_NUM_TYPES] = { 'n', 'a', 'i', 'm', 'b', 'f',
+                                              'x', 'd' };
+         fprintf (stderr, "%c%c%c %s\n", type_letter[i], type_letter[j],
+                  type_letter[k],
+                  ia64_templ_desc[best_template[i][j][k]].name);
+       }
+#endif
+
   for (i = 0; i < NUM_SLOTS; ++i)
     md.slot[i].user_template = -1;
 
@@ -8029,8 +8092,6 @@ ia64_canonicalize_symbol_name (name)
     {
       if (full > 0)
        as_bad ("Standalone `#' is illegal");
-      else
-       as_bad ("Zero-length symbol is illegal");
     }
   else if (len < full - 1)
     as_warn ("Redundant `#' suffix operators");
@@ -8180,9 +8241,15 @@ specify_resource (dep, idesc, type, specs, note, path)
   tmpl.qp_regno = CURR_SLOT.qp_regno;
   tmpl.link_to_qp_branch = 1;
   tmpl.mem_offset.hint = 0;
+  tmpl.mem_offset.offset = 0;
+  tmpl.mem_offset.base = 0;
   tmpl.specific = 1;
   tmpl.index = -1;
   tmpl.cmp_type = CMP_NONE;
+  tmpl.depind = 0;
+  tmpl.file = NULL;
+  tmpl.line = 0;
+  tmpl.path = 0;
 
 #define UNHANDLED \
 as_warn (_("Unhandled dependency %s for %s (%s), note %d"), \
@@ -10701,7 +10768,7 @@ md_assemble (str)
          else if (ar_is_only_in_memory_unit (CURR_SLOT.opnd[rop].X_add_number))
            unit = 'm';
          if (unit != 'a' && unit != idesc->name [4])
-           as_bad ("AR %d cannot be accessed by %c-unit",
+           as_bad ("AR %d can only be accessed by %c-unit",
                    (int) (CURR_SLOT.opnd[rop].X_add_number - REG_AR),
                    TOUPPER (unit));
        }
@@ -10771,7 +10838,7 @@ md_assemble (str)
       CURR_SLOT.unwind_record = unwind.current_entry;
       unwind.current_entry = NULL;
     }
-  if (unwind.proc_start && S_IS_DEFINED (unwind.proc_start))
+  if (unwind.proc_pending.sym && S_IS_DEFINED (unwind.proc_pending.sym))
     unwind.insn = 1;
 
   /* Check for dependency violations.  */
@@ -10847,7 +10914,7 @@ ia64_fix_adjustable (fix)
      fixS *fix;
 {
   /* Prevent all adjustments to global symbols */
-  if (S_IS_EXTERN (fix->fx_addsy) || S_IS_WEAK (fix->fx_addsy))
+  if (S_IS_EXTERNAL (fix->fx_addsy) || S_IS_WEAK (fix->fx_addsy))
     return 0;
 
   switch (fix->fx_r_type)
@@ -11008,7 +11075,7 @@ ia64_cons_fix_new (f, where, nbytes, exp)
   fix = fix_new_exp (f, where, nbytes, exp, 0, code);
   /* We need to store the byte order in effect in case we're going
      to fix an 8 or 16 bit relocation (for which there no real
-     relocs available).  See md_apply_fix3().  */
+     relocs available).  See md_apply_fix().  */
   fix->tc_fix_data.bigendian = target_big_endian;
 }
 
@@ -11253,6 +11320,7 @@ ia64_gen_real_reloc_type (sym, r_type)
        case BFD_RELOC_IA64_DIR32LSB: width = 32; suffix = "LSB"; break;
        case BFD_RELOC_IA64_DIR64MSB: width = 64; suffix = "MSB"; break;
        case BFD_RELOC_IA64_DIR64LSB: width = 64; suffix = "LSB"; break;
+       case BFD_RELOC_UNUSED:        width = 13; break;
        case BFD_RELOC_IA64_IMM14:    width = 14; break;
        case BFD_RELOC_IA64_IMM22:    width = 22; break;
        case BFD_RELOC_IA64_IMM64:    width = 64; suffix = "I"; break;
@@ -11354,7 +11422,7 @@ fix_insn (fix, odesc, value)
    (if possible).  */
 
 void
-md_apply_fix3 (fix, valP, seg)
+md_apply_fix (fix, valP, seg)
      fixS *fix;
      valueT *valP;
      segT seg ATTRIBUTE_UNUSED;
This page took 0.032372 seconds and 4 git commands to generate.