bfd/
[deliverable/binutils-gdb.git] / gas / config / tc-ia64.c
index 2082241d93fd75df33fa72f3b2193fb2df43b16e..387a1b7b51ee9f48358a30b071b7c87594f08ddd 100644 (file)
@@ -1,5 +1,6 @@
 /* tc-ia64.c -- Assembler for the HP/Intel IA-64 architecture.
-   Copyright 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004
+   Free Software Foundation, Inc.
    Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
 
    This file is part of GAS, the GNU Assembler.
@@ -153,8 +154,12 @@ struct label_fix
   struct symbol *sym;
 };
 
+/* This is the endianness of the current section.  */
 extern int target_big_endian;
 
+/* This is the default endianness.  */
+static int default_big_endian = TARGET_BYTES_BIG_ENDIAN;
+
 void (*ia64_number_to_chars) PARAMS ((char *, valueT, int));
 
 static void ia64_float_to_chars_bigendian
@@ -169,6 +174,10 @@ static struct hash_control *alias_name_hash;
 static struct hash_control *secalias_hash;
 static struct hash_control *secalias_name_hash;
 
+/* List of chars besides those in app.c:symbol_chars that can start an
+   operand.  Used to prevent the scrubber eating vital white-space.  */
+const char ia64_symbol_chars[] = "@?";
+
 /* Characters which always start a comment.  */
 const char comment_chars[] = "";
 
@@ -226,6 +235,13 @@ static struct
       auto_align : 1,
       keep_pending_output : 1;
 
+    /* What to do when something is wrong with unwind directives.  */
+    enum
+      {
+       unwind_check_warning,
+       unwind_check_error
+      } unwind_check;
+
     /* Each bundle consists of up to three instructions.  We keep
        track of four most recent instructions so we can correctly set
        the end_of_insn_group for the last instruction in a bundle.  */
@@ -236,7 +252,8 @@ static struct
        unsigned int
          end_of_insn_group : 1,
          manual_bundling_on : 1,
-         manual_bundling_off : 1;
+         manual_bundling_off : 1,
+         loc_directive_seen : 1;
        signed char user_template;      /* user-selected template, if any */
        unsigned char qp_regno;         /* qualifying predicate */
        /* This duplicates a good fraction of "struct fix" but we
@@ -286,25 +303,6 @@ static struct
                                       the current DV-checking block.  */
     int maxpaths;                   /* size currently allocated for
                                       entry_labels */
-    /* Support for hardware errata workarounds.  */
-
-    /* Record data about the last three insn groups.  */
-    struct group
-    {
-      /* B-step workaround.
-        For each predicate register, this is set if the corresponding insn
-        group conditionally sets this register with one of the affected
-        instructions.  */
-      int p_reg_set[64];
-      /* B-step workaround.
-        For each general register, this is set if the corresponding insn
-        a) is conditional one one of the predicate registers for which
-           P_REG_SET is 1 in the corresponding entry of the previous group,
-        b) sets this general register with one of the affected
-           instructions.  */
-      int g_reg_set_conditionally[128];
-    } last_groups[3];
-    int group_idx;
 
     int pointer_size;       /* size in bytes of a pointer */
     int pointer_size_shift; /* shift size of a pointer for alignment */
@@ -508,10 +506,10 @@ pseudo_func[] =
     { "segrel",        PSEUDO_FUNC_RELOC, { 0 } },
     { "tprel", PSEUDO_FUNC_RELOC, { 0 } },
     { "ltv",   PSEUDO_FUNC_RELOC, { 0 } },
-    { "", 0, { 0 } },  /* placeholder for FUNC_LT_FPTR_RELATIVE */
-    { "", 0, { 0 } },  /* placeholder for FUNC_LT_DTP_MODULE */
-    { "", 0, { 0 } },  /* placeholder for FUNC_LT_DTP_RELATIVE */
-    { "", 0, { 0 } },  /* placeholder for FUNC_LT_TP_RELATIVE */
+    { NULL, 0, { 0 } },        /* placeholder for FUNC_LT_FPTR_RELATIVE */
+    { NULL, 0, { 0 } },        /* placeholder for FUNC_LT_DTP_MODULE */
+    { NULL, 0, { 0 } },        /* placeholder for FUNC_LT_DTP_RELATIVE */
+    { NULL, 0, { 0 } },        /* placeholder for FUNC_LT_TP_RELATIVE */
     { "iplt",  PSEUDO_FUNC_RELOC, { 0 } },
 
     /* mbtype4 constants:  */
@@ -571,11 +569,6 @@ static char special_section_name[][20] =
     {".init_array"}, {".fini_array"}
   };
 
-static char *special_linkonce_name[] =
-  {
-    ".gnu.linkonce.ia64unw.", ".gnu.linkonce.ia64unwi."
-  };
-
 /* The best template for a particular sequence of up to three
    instructions:  */
 #define N      IA64_NUM_TYPES
@@ -636,6 +629,9 @@ static struct gr {
   valueT value;
 } gr_values[128] = {{ 1, 0, 0 }};
 
+/* Remember the alignment frag.  */
+static fragS *align_frag;
+
 /* These are the routines required to output the various types of
    unwind records.  */
 
@@ -680,7 +676,6 @@ static struct
 
   /* These are used to create the unwind table entry for this function.  */
   symbolS *proc_start;
-  symbolS *proc_end;
   symbolS *info;               /* pointer to unwind info */
   symbolS *personality_routine;
   segT saved_text_seg;
@@ -688,20 +683,28 @@ static struct
   unsigned int force_unwind_entry : 1; /* force generation of unwind entry? */
 
   /* TRUE if processing unwind directives in a prologue region.  */
-  int prologue;
-  int prologue_mask;
+  unsigned int prologue : 1;
+  unsigned int prologue_mask : 4;
+  unsigned int body : 1;
+  unsigned int insn : 1;
   unsigned int prologue_count; /* number of .prologues seen so far */
   /* Prologue counts at previous .label_state directives.  */
   struct label_prologue_count * saved_prologue_counts;
 } unwind;
 
+/* The input value is a negated offset from psp, and specifies an address
+   psp - offset.  The encoded value is psp + 16 - (4 * offset).  Thus we
+   must add 16 and divide by 4 to get the encoded value.  */
+
+#define ENCODED_PSP_OFFSET(OFFSET) (((OFFSET) + 16) / 4)
+
 typedef void (*vbyte_func) PARAMS ((int, char *, char *));
 
 /* Forward declarations:  */
-static int ar_is_in_integer_unit PARAMS ((int regnum));
 static void set_section PARAMS ((char *name));
 static unsigned int set_regstack PARAMS ((unsigned int, unsigned int,
                                          unsigned int, unsigned int));
+static void dot_align (int);
 static void dot_radix PARAMS ((int));
 static void dot_special_section PARAMS ((int));
 static void dot_proc PARAMS ((int));
@@ -751,6 +754,7 @@ static void dot_xfloat_cons_ua PARAMS ((int));
 static void print_prmask PARAMS ((valueT mask));
 static void dot_pred_rel PARAMS ((int));
 static void dot_reg_val PARAMS ((int));
+static void dot_serialize PARAMS ((int));
 static void dot_dv_mode PARAMS ((int));
 static void dot_entry PARAMS ((int));
 static void dot_mem_offset PARAMS ((int));
@@ -763,7 +767,6 @@ static enum operand_match_result operand_match PARAMS ((const struct ia64_opcode
                                                        expressionS *e));
 static int parse_operand PARAMS ((expressionS *e));
 static struct ia64_opcode * parse_operands PARAMS ((struct ia64_opcode *));
-static int errata_nop_necessary_p PARAMS ((struct slot *, enum ia64_unit));
 static void build_insn PARAMS ((struct slot *, bfd_vma *));
 static void emit_one_bundle PARAMS ((void));
 static void fix_insn PARAMS ((fixS *, const struct ia64_operand *, valueT));
@@ -898,54 +901,32 @@ static void process_unw_records PARAMS ((unw_rec_list *, vbyte_func));
 static int calc_record_size PARAMS ((unw_rec_list *));
 static void set_imask PARAMS ((unw_rec_list *, unsigned long, unsigned long, unsigned int));
 static unsigned long slot_index PARAMS ((unsigned long, fragS *,
-                                        unsigned long, fragS *));
+                                        unsigned long, fragS *,
+                                        int));
 static unw_rec_list *optimize_unw_records PARAMS ((unw_rec_list *));
-static void fixup_unw_records PARAMS ((unw_rec_list *));
+static void fixup_unw_records PARAMS ((unw_rec_list *, int));
 static int convert_expr_to_ab_reg PARAMS ((expressionS *, unsigned int *, unsigned int *));
 static int convert_expr_to_xy_reg PARAMS ((expressionS *, unsigned int *, unsigned int *));
-static void generate_unwind_image PARAMS ((const char *));
 static unsigned int get_saved_prologue_count PARAMS ((unsigned long));
 static void save_prologue_count PARAMS ((unsigned long, unsigned int));
 static void free_saved_prologue_counts PARAMS ((void));
 
-/* Build the unwind section name by appending the (possibly stripped)
-   text section NAME to the unwind PREFIX.  The resulting string
-   pointer is assigned to RESULT.  The string is allocated on the
-   stack, so this must be a macro...  */
-#define make_unw_section_name(special, text_name, result)                 \
-  {                                                                       \
-    const char *_prefix = special_section_name[special];                  \
-    const char *_suffix = text_name;                                      \
-    size_t _prefix_len, _suffix_len;                                      \
-    char *_result;                                                        \
-    if (strncmp (text_name, ".gnu.linkonce.t.",                                   \
-                sizeof (".gnu.linkonce.t.") - 1) == 0)                    \
-      {                                                                           \
-       _prefix = special_linkonce_name[special - SPECIAL_SECTION_UNWIND]; \
-       _suffix += sizeof (".gnu.linkonce.t.") - 1;                        \
-      }                                                                           \
-    _prefix_len = strlen (_prefix), _suffix_len = strlen (_suffix);       \
-    _result = alloca (_prefix_len + _suffix_len + 1);                     \
-    memcpy (_result, _prefix, _prefix_len);                               \
-    memcpy (_result + _prefix_len, _suffix, _suffix_len);                 \
-    _result[_prefix_len + _suffix_len] = '\0';                            \
-    result = _result;                                                     \
-  }                                                                       \
-while (0)
-
-/* Determine if application register REGNUM resides in the integer
+/* Determine if application register REGNUM resides only in the integer
    unit (as opposed to the memory unit).  */
 static int
-ar_is_in_integer_unit (reg)
-     int reg;
+ar_is_only_in_integer_unit (int reg)
 {
   reg -= REG_AR;
+  return reg >= 64 && reg <= 111;
+}
 
-  return (reg == 64    /* pfs */
-         || reg == 65  /* lc */
-         || reg == 66  /* ec */
-         /* ??? ias accepts and puts these in the integer unit.  */
-         || (reg >= 112 && reg <= 127));
+/* Determine if application register REGNUM resides only in the memory 
+   unit (as opposed to the integer unit).  */
+static int
+ar_is_only_in_memory_unit (int reg)
+{
+  reg -= REG_AR;
+  return reg >= 0 && reg <= 47;
 }
 
 /* Switch to section NAME and create section if necessary.  It's
@@ -1014,12 +995,6 @@ ia64_elf_section_type (str, len)
   if (STREQ ("unwind"))
     return SHT_IA_64_UNWIND;
 
-  if (STREQ ("init_array"))
-    return SHT_INIT_ARRAY;
-
-  if (STREQ ("fini_array"))
-    return SHT_FINI_ARRAY;
-
   return -1;
 #undef STREQ
 }
@@ -1092,14 +1067,36 @@ ia64_flush_insns ()
      here.  Give an error for others.  */
   for (ptr = unwind.current_entry; ptr; ptr = ptr->next)
     {
-      if (ptr->r.type == prologue || ptr->r.type == prologue_gr
-         || ptr->r.type == body || ptr->r.type == endp)
+      switch (ptr->r.type)
        {
+       case prologue:
+       case prologue_gr:
+       case body:
+       case endp:
          ptr->slot_number = (unsigned long) frag_more (0);
          ptr->slot_frag = frag_now;
+         break;
+
+         /* Allow any record which doesn't have a "t" field (i.e.,
+            doesn't relate to a particular instruction).  */
+       case unwabi:
+       case br_gr:
+       case copy_state:
+       case fr_mem:
+       case frgr_mem:
+       case gr_gr:
+       case gr_mem:
+       case label_state:
+       case rp_br:
+       case spill_base:
+       case spill_mask:
+         /* nothing */
+         break;
+
+       default:
+         as_bad (_("Unwind directive not followed by an instruction."));
+         break;
        }
-      else
-       as_bad (_("Unwind directive not followed by an instruction."));
     }
   unwind.current_entry = NULL;
 
@@ -1109,9 +1106,8 @@ ia64_flush_insns ()
     as_bad ("qualifying predicate not followed by instruction");
 }
 
-void
-ia64_do_align (nbytes)
-     int nbytes;
+static void
+ia64_do_align (int nbytes)
 {
   char *saved_input_line_pointer = input_line_pointer;
 
@@ -1813,7 +1809,7 @@ output_rp_psprel (offset)
      unsigned int offset;
 {
   unw_rec_list *ptr = alloc_record (rp_psprel);
-  ptr->r.record.p.pspoff = offset / 4;
+  ptr->r.record.p.pspoff = ENCODED_PSP_OFFSET (offset);
   return ptr;
 }
 
@@ -1847,7 +1843,7 @@ output_pfs_psprel (offset)
      unsigned int offset;
 {
   unw_rec_list *ptr = alloc_record (pfs_psprel);
-  ptr->r.record.p.pspoff = offset / 4;
+  ptr->r.record.p.pspoff = ENCODED_PSP_OFFSET (offset);
   return ptr;
 }
 
@@ -1881,7 +1877,7 @@ output_preds_psprel (offset)
      unsigned int offset;
 {
   unw_rec_list *ptr = alloc_record (preds_psprel);
-  ptr->r.record.p.pspoff = offset / 4;
+  ptr->r.record.p.pspoff = ENCODED_PSP_OFFSET (offset);
   return ptr;
 }
 
@@ -1958,7 +1954,7 @@ output_spill_base (offset)
      unsigned int offset;
 {
   unw_rec_list *ptr = alloc_record (spill_base);
-  ptr->r.record.p.pspoff = offset / 4;
+  ptr->r.record.p.pspoff = ENCODED_PSP_OFFSET (offset);
   return ptr;
 }
 
@@ -1983,7 +1979,7 @@ output_unat_psprel (offset)
      unsigned int offset;
 {
   unw_rec_list *ptr = alloc_record (unat_psprel);
-  ptr->r.record.p.pspoff = offset / 4;
+  ptr->r.record.p.pspoff = ENCODED_PSP_OFFSET (offset);
   return ptr;
 }
 
@@ -2017,7 +2013,7 @@ output_lc_psprel (offset)
      unsigned int offset;
 {
   unw_rec_list *ptr = alloc_record (lc_psprel);
-  ptr->r.record.p.pspoff = offset / 4;
+  ptr->r.record.p.pspoff = ENCODED_PSP_OFFSET (offset);
   return ptr;
 }
 
@@ -2051,7 +2047,7 @@ output_fpsr_psprel (offset)
      unsigned int offset;
 {
   unw_rec_list *ptr = alloc_record (fpsr_psprel);
-  ptr->r.record.p.pspoff = offset / 4;
+  ptr->r.record.p.pspoff = ENCODED_PSP_OFFSET (offset);
   return ptr;
 }
 
@@ -2092,7 +2088,7 @@ output_priunat_psprel (offset)
      unsigned int offset;
 {
   unw_rec_list *ptr = alloc_record (priunat_psprel);
-  ptr->r.record.p.pspoff = offset / 4;
+  ptr->r.record.p.pspoff = ENCODED_PSP_OFFSET (offset);
   return ptr;
 }
 
@@ -2126,7 +2122,7 @@ output_bsp_psprel (offset)
      unsigned int offset;
 {
   unw_rec_list *ptr = alloc_record (bsp_psprel);
-  ptr->r.record.p.pspoff = offset / 4;
+  ptr->r.record.p.pspoff = ENCODED_PSP_OFFSET (offset);
   return ptr;
 }
 
@@ -2160,7 +2156,7 @@ output_bspstore_psprel (offset)
      unsigned int offset;
 {
   unw_rec_list *ptr = alloc_record (bspstore_psprel);
-  ptr->r.record.p.pspoff = offset / 4;
+  ptr->r.record.p.pspoff = ENCODED_PSP_OFFSET (offset);
   return ptr;
 }
 
@@ -2194,7 +2190,7 @@ output_rnat_psprel (offset)
      unsigned int offset;
 {
   unw_rec_list *ptr = alloc_record (rnat_psprel);
-  ptr->r.record.p.pspoff = offset / 4;
+  ptr->r.record.p.pspoff = ENCODED_PSP_OFFSET (offset);
   return ptr;
 }
 
@@ -2251,7 +2247,7 @@ output_spill_psprel (ab, reg, offset)
   unw_rec_list *ptr = alloc_record (spill_psprel);
   ptr->r.record.x.ab = ab;
   ptr->r.record.x.reg = reg;
-  ptr->r.record.x.pspoff = offset / 4;
+  ptr->r.record.x.pspoff = ENCODED_PSP_OFFSET (offset);
   return ptr;
 }
 
@@ -2278,7 +2274,7 @@ output_spill_psprel_p (ab, reg, offset, predicate)
   unw_rec_list *ptr = alloc_record (spill_psprel_p);
   ptr->r.record.x.ab = ab;
   ptr->r.record.x.reg = reg;
-  ptr->r.record.x.pspoff = offset / 4;
+  ptr->r.record.x.pspoff = ENCODED_PSP_OFFSET (offset);
   ptr->r.record.x.qp = predicate;
   return ptr;
 }
@@ -2590,14 +2586,16 @@ set_imask (region, regmask, t, type)
 
 /* Return the number of instruction slots from FIRST_ADDR to SLOT_ADDR.
    SLOT_FRAG is the frag containing SLOT_ADDR, and FIRST_FRAG is the frag
-   containing FIRST_ADDR.  */
+   containing FIRST_ADDR.  If BEFORE_RELAX, then we use worst-case estimates
+   for frag sizes.  */
 
 unsigned long
-slot_index (slot_addr, slot_frag, first_addr, first_frag)
+slot_index (slot_addr, slot_frag, first_addr, first_frag, before_relax)
      unsigned long slot_addr;
      fragS *slot_frag;
      unsigned long first_addr;
      fragS *first_frag;
+     int before_relax;
 {
   unsigned long index = 0;
 
@@ -2612,10 +2610,10 @@ slot_index (slot_addr, slot_frag, first_addr, first_frag)
     {
       unsigned long start_addr = (unsigned long) &first_frag->fr_literal;
 
-      if (finalize_syms)
+      if (! before_relax)
        {
-         /* We can get the final addresses only after relaxation is
-            done. */
+         /* We can get the final addresses only during and after
+            relaxation.  */
          if (first_frag->fr_next && first_frag->fr_next->fr_address)
            index += 3 * ((first_frag->fr_next->fr_address
                           - first_frag->fr_address
@@ -2694,8 +2692,9 @@ optimize_unw_records (list)
    within each record to generate an image.  */
 
 static void
-fixup_unw_records (list)
+fixup_unw_records (list, before_relax)
      unw_rec_list *list;
+     int before_relax;
 {
   unw_rec_list *ptr, *region = 0;
   unsigned long first_addr = 0, rlen = 0, t;
@@ -2706,7 +2705,7 @@ fixup_unw_records (list)
       if (ptr->slot_number == SLOT_NUM_NOT_SET)
        as_bad (" Insn slot not set in unwind record.");
       t = slot_index (ptr->slot_number, ptr->slot_frag,
-                     first_addr, first_frag);
+                     first_addr, first_frag, before_relax);
       switch (ptr->r.type)
        {
        case prologue:
@@ -2730,7 +2729,8 @@ fixup_unw_records (list)
                  last_frag = last->slot_frag;
                  break;
                }
-           size = slot_index (last_addr, last_frag, first_addr, first_frag);
+           size = slot_index (last_addr, last_frag, first_addr, first_frag,
+                              before_relax);
            rlen = ptr->r.record.r.rlen = size;
            if (ptr->r.type == body)
              /* End of region.  */
@@ -2740,7 +2740,13 @@ fixup_unw_records (list)
            break;
          }
        case epilogue:
-         ptr->r.record.b.t = rlen - 1 - t;
+         if (t < rlen)
+           ptr->r.record.b.t = rlen - 1 - t;
+         else
+           /* This happens when a memory-stack-less procedure uses a
+              ".restore sp" directive at the end of a region to pop
+              the frame state.  */
+           ptr->r.record.b.t = 0;
          break;
 
        case mem_stack_f:
@@ -2771,7 +2777,7 @@ fixup_unw_records (list)
        case frgr_mem:
          if (!region)
            {
-             as_bad ("frgr_mem record before region record!\n");
+             as_bad ("frgr_mem record before region record!");
              return;
            }
          region->r.record.r.mask.fr_mem |= ptr->r.record.p.frmask;
@@ -2782,7 +2788,7 @@ fixup_unw_records (list)
        case fr_mem:
          if (!region)
            {
-             as_bad ("fr_mem record before region record!\n");
+             as_bad ("fr_mem record before region record!");
              return;
            }
          region->r.record.r.mask.fr_mem |= ptr->r.record.p.rmask;
@@ -2791,7 +2797,7 @@ fixup_unw_records (list)
        case gr_mem:
          if (!region)
            {
-             as_bad ("gr_mem record before region record!\n");
+             as_bad ("gr_mem record before region record!");
              return;
            }
          region->r.record.r.mask.gr_mem |= ptr->r.record.p.rmask;
@@ -2800,7 +2806,7 @@ fixup_unw_records (list)
        case br_mem:
          if (!region)
            {
-             as_bad ("br_mem record before region record!\n");
+             as_bad ("br_mem record before region record!");
              return;
            }
          region->r.record.r.mask.br_mem |= ptr->r.record.p.brmask;
@@ -2810,7 +2816,7 @@ fixup_unw_records (list)
        case gr_gr:
          if (!region)
            {
-             as_bad ("gr_gr record before region record!\n");
+             as_bad ("gr_gr record before region record!");
              return;
            }
          set_imask (region, ptr->r.record.p.grmask, t, 2);
@@ -2818,7 +2824,7 @@ fixup_unw_records (list)
        case br_gr:
          if (!region)
            {
-             as_bad ("br_gr record before region record!\n");
+             as_bad ("br_gr record before region record!");
              return;
            }
          set_imask (region, ptr->r.record.p.brmask, t, 3);
@@ -2830,6 +2836,38 @@ fixup_unw_records (list)
     }
 }
 
+/* Estimate the size of a frag before relaxing.  We only have one type of frag
+   to handle here, which is the unwind info frag.  */
+
+int
+ia64_estimate_size_before_relax (fragS *frag,
+                                asection *segtype ATTRIBUTE_UNUSED)
+{
+  unw_rec_list *list;
+  int len, size, pad;
+
+  /* ??? This code is identical to the first part of ia64_convert_frag.  */
+  list = (unw_rec_list *) frag->fr_opcode;
+  fixup_unw_records (list, 0);
+
+  len = calc_record_size (list);
+  /* pad to pointer-size boundary.  */
+  pad = len % md.pointer_size;
+  if (pad != 0)
+    len += md.pointer_size - pad;
+  /* Add 8 for the header.  */
+  size = len + 8;
+  /* Add a pointer for the personality offset.  */
+  if (frag->fr_offset)
+    size += md.pointer_size;
+
+  /* fr_var carries the max_chars that we created the fragment with.
+     We must, of course, have allocated enough memory earlier.  */
+  assert (frag->fr_var >= size);
+
+  return frag->fr_fix + size;
+}
+
 /* This function converts a rs_machine_dependent variant frag into a
   normal fill frag with the unwind image from the the record list.  */
 void
@@ -2839,16 +2877,20 @@ ia64_convert_frag (fragS *frag)
   int len, size, pad;
   valueT flag_value;
 
+  /* ??? This code is identical to ia64_estimate_size_before_relax.  */
   list = (unw_rec_list *) frag->fr_opcode;
-  fixup_unw_records (list);
+  fixup_unw_records (list, 0);
 
   len = calc_record_size (list);
   /* pad to pointer-size boundary.  */
   pad = len % md.pointer_size;
   if (pad != 0)
     len += md.pointer_size - pad;
-  /* Add 8 for the header + a pointer for the personality offset.  */
-  size = len + 8 + md.pointer_size;
+  /* Add 8 for the header.  */
+  size = len + 8;
+  /* Add a pointer for the personality offset.  */
+  if (frag->fr_offset)
+    size += md.pointer_size;
 
   /* fr_var carries the max_chars that we created the fragment with.
      We must, of course, have allocated enough memory earlier.  */
@@ -2973,6 +3015,14 @@ convert_expr_to_xy_reg (e, xy, regp)
   return 1;
 }
 
+static void
+dot_align (int arg)
+{
+  /* The current frag is an alignment frag.  */
+  align_frag = frag_now;
+  s_align_bytes (arg);
+}
+
 static void
 dot_radix (dummy)
      int dummy ATTRIBUTE_UNUSED;
@@ -2990,6 +3040,17 @@ dot_radix (dummy)
     }
 }
 
+/* Helper function for .loc directives.  If the assembler is not generating
+   line number info, then we need to remember which instructions have a .loc
+   directive, and only call dwarf2_gen_line_info for those instructions.  */
+
+static void
+dot_loc (int x)
+{
+  CURR_SLOT.loc_directive_seen = 1;
+  dwarf2_directive_loc (x);
+}
+
 /* .sbss, .bss etc. are macros that expand into ".section SECNAME".  */
 static void
 dot_special_section (which)
@@ -2998,6 +3059,84 @@ dot_special_section (which)
   set_section ((char *) special_section_name[which]);
 }
 
+/* Return -1 for warning and 0 for error.  */
+
+static int
+unwind_diagnostic (const char * region, const char *directive)
+{
+  if (md.unwind_check == unwind_check_warning)
+    {
+      as_warn (".%s outside of %s", directive, region);
+      return -1;
+    }
+  else
+    {
+      as_bad (".%s outside of %s", directive, region);
+      ignore_rest_of_line ();
+      return 0;
+    }
+}
+
+/* Return 1 if a directive is in a procedure, -1 if a directive isn't in
+   a procedure but the unwind directive check is set to warning, 0 if
+   a directive isn't in a procedure and the unwind directive check is set
+   to error.  */
+
+static int
+in_procedure (const char *directive)
+{
+  if (unwind.proc_start
+      && (!unwind.saved_text_seg || strcmp (directive, "endp") == 0))
+    return 1;
+  return unwind_diagnostic ("procedure", directive);
+}
+
+/* Return 1 if a directive is in a prologue, -1 if a directive isn't in
+   a prologue but the unwind directive check is set to warning, 0 if
+   a directive isn't in a prologue and the unwind directive check is set
+   to error.  */
+
+static int
+in_prologue (const char *directive)
+{
+  int in = in_procedure (directive);
+  if (in)
+    {
+      /* We are in a procedure. Check if we are in a prologue.  */
+      if (unwind.prologue)
+       return 1;
+      /* We only want to issue one message.  */
+      if (in == 1)
+       return unwind_diagnostic ("prologue", directive);
+      else
+       return -1;
+    }
+  return 0;
+}
+
+/* Return 1 if a directive is in a body, -1 if a directive isn't in
+   a body but the unwind directive check is set to warning, 0 if
+   a directive isn't in a body and the unwind directive check is set
+   to error.  */
+
+static int
+in_body (const char *directive)
+{
+  int in = in_procedure (directive);
+  if (in)
+    {
+      /* We are in a procedure. Check if we are in a body.  */
+      if (unwind.body)
+       return 1;
+      /* We only want to issue one message.  */
+      if (in == 1)
+       return unwind_diagnostic ("body region", directive);
+      else
+       return -1;
+    }
+  return 0;
+}
+
 static void
 add_unwind_entry (ptr)
      unw_rec_list *ptr;
@@ -3019,6 +3158,9 @@ dot_fframe (dummy)
 {
   expressionS e;
 
+  if (!in_prologue ("fframe"))
+    return;
+
   parse_operand (&e);
 
   if (e.X_op != O_constant)
@@ -3034,6 +3176,9 @@ dot_vframe (dummy)
   expressionS e;
   unsigned reg;
 
+  if (!in_prologue ("vframe"))
+    return;
+
   parse_operand (&e);
   reg = e.X_add_number - REG_GR;
   if (e.X_op == O_register && reg < 128)
@@ -3052,6 +3197,9 @@ dot_vframesp (dummy)
 {
   expressionS e;
 
+  if (!in_prologue ("vframesp"))
+    return;
+
   parse_operand (&e);
   if (e.X_op == O_constant)
     {
@@ -3068,6 +3216,9 @@ dot_vframepsp (dummy)
 {
   expressionS e;
 
+  if (!in_prologue ("vframepsp"))
+    return;
+
   parse_operand (&e);
   if (e.X_op == O_constant)
     {
@@ -3086,6 +3237,9 @@ dot_save (dummy)
   int sep;
   int reg1, reg2;
 
+  if (!in_prologue ("save"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     as_bad ("No second operand to .save");
@@ -3163,6 +3317,9 @@ dot_restore (dummy)
   unsigned long ecount;        /* # of _additional_ regions to pop */
   int sep;
 
+  if (!in_body ("restore"))
+    return;
+
   sep = parse_operand (&e1);
   if (e1.X_op != O_register || e1.X_add_number != REG_GR + 12)
     {
@@ -3205,6 +3362,9 @@ dot_restorereg (dummy)
   unsigned int ab, reg;
   expressionS e;
 
+  if (!in_procedure ("restorereg"))
+    return;
+
   parse_operand (&e);
 
   if (!convert_expr_to_ab_reg (&e, &ab, &reg))
@@ -3223,6 +3383,9 @@ dot_restorereg_p (dummy)
   expressionS e1, e2;
   int sep;
 
+  if (!in_procedure ("restorereg.p"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     {
@@ -3247,20 +3410,141 @@ dot_restorereg_p (dummy)
   add_unwind_entry (output_spill_reg_p (ab, reg, 0, 0, qp));
 }
 
+static char *special_linkonce_name[] =
+  {
+    ".gnu.linkonce.ia64unw.", ".gnu.linkonce.ia64unwi."
+  };
+
+static void
+start_unwind_section (const segT text_seg, int sec_index, int linkonce_empty)
+{
+  /*
+    Use a slightly ugly scheme to derive the unwind section names from
+    the text section name:
+
+    text sect.  unwind table sect.
+    name:       name:                      comments:
+    ----------  -----------------          --------------------------------
+    .text       .IA_64.unwind
+    .text.foo   .IA_64.unwind.text.foo
+    .foo        .IA_64.unwind.foo
+    .gnu.linkonce.t.foo
+               .gnu.linkonce.ia64unw.foo
+    _info       .IA_64.unwind_info         gas issues error message (ditto)
+    _infoFOO    .IA_64.unwind_infoFOO      gas issues error message (ditto)
+
+    This mapping is done so that:
+
+       (a) An object file with unwind info only in .text will use
+           unwind section names .IA_64.unwind and .IA_64.unwind_info.
+           This follows the letter of the ABI and also ensures backwards
+           compatibility with older toolchains.
+
+       (b) An object file with unwind info in multiple text sections
+           will use separate unwind sections for each text section.
+           This allows us to properly set the "sh_info" and "sh_link"
+           fields in SHT_IA_64_UNWIND as required by the ABI and also
+           lets GNU ld support programs with multiple segments
+           containing unwind info (as might be the case for certain
+           embedded applications).
+
+       (c) An error is issued if there would be a name clash.
+  */
+
+  const char *text_name, *sec_text_name;
+  char *sec_name;
+  const char *prefix = special_section_name [sec_index];
+  const char *suffix;
+  size_t prefix_len, suffix_len, sec_name_len;
+
+  sec_text_name = segment_name (text_seg);
+  text_name = sec_text_name;
+  if (strncmp (text_name, "_info", 5) == 0)
+    {
+      as_bad ("Illegal section name `%s' (causes unwind section name clash)",
+             text_name);
+      ignore_rest_of_line ();
+      return;
+    }
+  if (strcmp (text_name, ".text") == 0)
+    text_name = "";
+
+  /* Build the unwind section name by appending the (possibly stripped)
+     text section name to the unwind prefix.  */
+  suffix = text_name;
+  if (strncmp (text_name, ".gnu.linkonce.t.",
+              sizeof (".gnu.linkonce.t.") - 1) == 0)
+    {
+      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);
+  sec_name_len = prefix_len + suffix_len;
+  sec_name = alloca (sec_name_len + 1);
+  memcpy (sec_name, prefix, prefix_len);
+  memcpy (sec_name + prefix_len, suffix, suffix_len);
+  sec_name [sec_name_len] = '\0';
+
+  /* Handle COMDAT group.  */
+  if (suffix == text_name && (text_seg->flags & SEC_LINK_ONCE) != 0)
+    {
+      char *section;
+      size_t len, group_name_len;
+      const char *group_name = elf_group_name (text_seg);
+
+      if (group_name == NULL)
+       {
+         as_bad ("Group section `%s' has no group signature",
+                 sec_text_name);
+         ignore_rest_of_line ();
+         return;
+       }
+      /* We have to construct a fake section directive. */
+      group_name_len = strlen (group_name);
+      len = (sec_name_len
+            + 16                       /* ,"aG",@progbits,  */
+            + group_name_len           /* ,group_name  */
+            + 7);                      /* ,comdat  */
+
+      section = alloca (len + 1);
+      memcpy (section, sec_name, sec_name_len);
+      memcpy (section + sec_name_len, ",\"aG\",@progbits,", 16);
+      memcpy (section + sec_name_len + 16, group_name, group_name_len);
+      memcpy (section + len - 7, ",comdat", 7);
+      section [len] = '\0';
+      set_section (section);
+    }
+  else
+    {
+      set_section (sec_name);
+      bfd_set_section_flags (stdoutput, now_seg,
+                            SEC_LOAD | SEC_ALLOC | SEC_READONLY);
+    }
+
+  elf_linked_to_section (now_seg) = text_seg;
+}
+
 static void
-generate_unwind_image (text_name)
-     const char *text_name;
+generate_unwind_image (const segT text_seg)
 {
   int size, pad;
   unw_rec_list *list;
 
+  /* Mark the end of the unwind info, so that we can compute the size of the
+     last unwind region.  */
+  add_unwind_entry (output_endp ());
+
   /* Force out pending instructions, to make sure all unwind records have
      a valid slot_number field.  */
   ia64_flush_insns ();
 
   /* Generate the unwind record.  */
   list = optimize_unw_records (unwind.list);
-  fixup_unw_records (list);
+  fixup_unw_records (list, 1);
   size = calc_record_size (list);
 
   if (size > 0 || unwind.force_unwind_entry)
@@ -3270,22 +3554,20 @@ generate_unwind_image (text_name)
       pad = size % md.pointer_size;
       if (pad != 0)
        size += md.pointer_size - pad;
-      /* Add 8 for the header + a pointer for the personality
-        offset.  */
-      size += 8 + md.pointer_size;
+      /* Add 8 for the header.  */
+      size += 8;
+      /* Add a pointer for the personality offset.  */
+      if (unwind.personality_routine)
+       size += md.pointer_size;
     }
 
   /* If there are unwind records, switch sections, and output the info.  */
   if (size != 0)
     {
-      char *sec_name;
       expressionS exp;
       bfd_reloc_code_real_type reloc;
 
-      make_unw_section_name (SPECIAL_SECTION_UNWIND_INFO, text_name, sec_name);
-      set_section (sec_name);
-      bfd_set_section_flags (stdoutput, now_seg,
-                            SEC_LOAD | SEC_ALLOC | SEC_READONLY);
+      start_unwind_section (text_seg, SPECIAL_SECTION_UNWIND_INFO, 0);
 
       /* Make sure the section has 4 byte alignment for ILP32 and
         8 byte alignment for LP64.  */
@@ -3296,7 +3578,8 @@ generate_unwind_image (text_name)
       unwind.info = expr_build_dot ();
       
       frag_var (rs_machine_dependent, size, size, 0, 0,
-               (offsetT) unwind.personality_routine, (char *) list);
+               (offsetT) (long) unwind.personality_routine,
+               (char *) list);
 
       /* Add the personality address to the image.  */
       if (unwind.personality_routine != 0)
@@ -3325,6 +3608,8 @@ generate_unwind_image (text_name)
          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;
@@ -3334,13 +3619,8 @@ static void
 dot_handlerdata (dummy)
      int dummy ATTRIBUTE_UNUSED;
 {
-  const char *text_name = segment_name (now_seg);
-
-  /* If text section name starts with ".text" (which it should),
-     strip this prefix off.  */
-  if (strcmp (text_name, ".text") == 0)
-    text_name = "";
-
+  if (!in_procedure ("handlerdata"))
+    return;
   unwind.force_unwind_entry = 1;
 
   /* Remember which segment we're in so we can switch back after .endp */
@@ -3350,7 +3630,7 @@ dot_handlerdata (dummy)
   /* Generate unwind info into unwind-info section and then leave that
      section as the currently active one so dataXX directives go into
      the language specific data area of the unwind info block.  */
-  generate_unwind_image (text_name);
+  generate_unwind_image (now_seg);
   demand_empty_rest_of_line ();
 }
 
@@ -3358,6 +3638,8 @@ static void
 dot_unwentry (dummy)
      int dummy ATTRIBUTE_UNUSED;
 {
+  if (!in_procedure ("unwentry"))
+    return;
   unwind.force_unwind_entry = 1;
   demand_empty_rest_of_line ();
 }
@@ -3369,6 +3651,9 @@ dot_altrp (dummy)
   expressionS e;
   unsigned reg;
 
+  if (!in_prologue ("altrp"))
+    return;
+
   parse_operand (&e);
   reg = e.X_add_number - REG_BR;
   if (e.X_op == O_register && reg < 8)
@@ -3385,6 +3670,9 @@ dot_savemem (psprel)
   int sep;
   int reg1, val;
 
+  if (!in_prologue (psprel ? "savepsp" : "savesp"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     as_bad ("No second operand to .save%ssp", psprel ? "p" : "");
@@ -3477,6 +3765,10 @@ dot_saveg (dummy)
 {
   expressionS e1, e2;
   int sep;
+
+  if (!in_prologue ("save.g"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep == ',')
     parse_operand (&e2);
@@ -3505,6 +3797,10 @@ dot_savef (dummy)
 {
   expressionS e1;
   int sep;
+
+  if (!in_prologue ("save.f"))
+    return;
+
   sep = parse_operand (&e1);
 
   if (e1.X_op != O_constant)
@@ -3522,6 +3818,9 @@ dot_saveb (dummy)
   unsigned char sep;
   int brmask;
 
+  if (!in_prologue ("save.b"))
+    return;
+
   sep = parse_operand (&e1);
   if (e1.X_op != O_constant)
     {
@@ -3545,7 +3844,7 @@ dot_saveb (dummy)
     add_unwind_entry (output_br_mem (brmask));
 
   if (!is_end_of_line[sep] && !is_it_end_of_statement ())
-    ignore_rest_of_line ();
+    demand_empty_rest_of_line ();
 }
 
 static void
@@ -3554,6 +3853,10 @@ dot_savegf (dummy)
 {
   expressionS e1, e2;
   int sep;
+
+  if (!in_prologue ("save.gf"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep == ',')
     parse_operand (&e2);
@@ -3575,9 +3878,12 @@ dot_spill (dummy)
   expressionS e;
   unsigned char sep;
 
+  if (!in_prologue ("spill"))
+    return;
+
   sep = parse_operand (&e);
   if (!is_end_of_line[sep] && !is_it_end_of_statement ())
-    ignore_rest_of_line ();
+    demand_empty_rest_of_line ();
 
   if (e.X_op != O_constant)
     as_bad ("Operand to .spill must be a constant");
@@ -3592,6 +3898,9 @@ dot_spillreg (dummy)
   int sep, ab, xy, reg, treg;
   expressionS e1, e2;
 
+  if (!in_procedure ("spillreg"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     {
@@ -3623,6 +3932,9 @@ dot_spillmem (psprel)
   expressionS e1, e2;
   int sep, ab, reg;
 
+  if (!in_procedure ("spillmem"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     {
@@ -3660,6 +3972,9 @@ dot_spillreg_p (dummy)
   expressionS e1, e2, e3;
   unsigned int qp;
 
+  if (!in_procedure ("spillreg.p"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     {
@@ -3707,6 +4022,9 @@ dot_spillmem_p (psprel)
   int sep, ab, reg;
   unsigned int qp;
 
+  if (!in_procedure ("spillmem.p"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     {
@@ -3812,6 +4130,9 @@ dot_label_state (dummy)
 {
   expressionS e;
 
+  if (!in_body ("label_state"))
+    return;
+
   parse_operand (&e);
   if (e.X_op != O_constant)
     {
@@ -3828,6 +4149,9 @@ dot_copy_state (dummy)
 {
   expressionS e;
 
+  if (!in_body ("copy_state"))
+    return;
+
   parse_operand (&e);
   if (e.X_op != O_constant)
     {
@@ -3845,6 +4169,9 @@ dot_unwabi (dummy)
   expressionS e1, e2;
   unsigned char sep;
 
+  if (!in_procedure ("unwabi"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     {
@@ -3853,7 +4180,7 @@ dot_unwabi (dummy)
     }
   sep = parse_operand (&e2);
   if (!is_end_of_line[sep] && !is_it_end_of_statement ())
-    ignore_rest_of_line ();
+    demand_empty_rest_of_line ();
 
   if (e1.X_op != O_constant)
     {
@@ -3875,6 +4202,8 @@ dot_personality (dummy)
      int dummy ATTRIBUTE_UNUSED;
 {
   char *name, *p, c;
+  if (!in_procedure ("personality"))
+    return;
   SKIP_WHITESPACE ();
   name = input_line_pointer;
   c = get_symbol_end ();
@@ -3893,7 +4222,7 @@ dot_proc (dummy)
   char *name, *p, c;
   symbolS *sym;
 
-  unwind.proc_start = expr_build_dot ();
+  unwind.proc_start = 0;
   /* Parse names of main and alternate entry points and mark them as
      function symbols:  */
   while (1)
@@ -3902,22 +4231,34 @@ dot_proc (dummy)
       name = input_line_pointer;
       c = get_symbol_end ();
       p = input_line_pointer;
-      sym = symbol_find_or_make (name);
-      if (unwind.proc_start == 0)
+      if (!*name)
+       as_bad ("Empty argument of .proc");
+      else
        {
-         unwind.proc_start = sym;
+         sym = symbol_find_or_make (name);
+         if (S_IS_DEFINED (sym))
+           as_bad ("`%s' was already defined", name);
+         else if (unwind.proc_start == 0)
+           {
+             unwind.proc_start = sym;
+           }
+         symbol_get_bfdsym (sym)->flags |= BSF_FUNCTION;
        }
-      symbol_get_bfdsym (sym)->flags |= BSF_FUNCTION;
       *p = c;
       SKIP_WHITESPACE ();
       if (*input_line_pointer != ',')
        break;
       ++input_line_pointer;
     }
+  if (unwind.proc_start == 0)
+    unwind.proc_start = expr_build_dot ();
   demand_empty_rest_of_line ();
   ia64_do_align (16);
 
+  unwind.prologue = 0;
   unwind.prologue_count = 0;
+  unwind.body = 0;
+  unwind.insn = 0;
   unwind.list = unwind.tail = unwind.current_entry = NULL;
   unwind.personality_routine = 0;
 }
@@ -3926,8 +4267,14 @@ static void
 dot_body (dummy)
      int dummy ATTRIBUTE_UNUSED;
 {
+  if (!in_procedure ("body"))
+    return;
+  if (!unwind.prologue && !unwind.body && unwind.insn)
+    as_warn ("Initial .body should precede any instructions");
+
   unwind.prologue = 0;
   unwind.prologue_mask = 0;
+  unwind.body = 1;
 
   add_unwind_entry (output_body ());
   demand_empty_rest_of_line ();
@@ -3940,6 +4287,17 @@ dot_prologue (dummy)
   unsigned char sep;
   int mask = 0, grsave = 0;
 
+  if (!in_procedure ("prologue"))
+    return;
+  if (unwind.prologue)
+    {
+      as_bad (".prologue within prologue");
+      ignore_rest_of_line ();
+      return;
+    }
+  if (!unwind.body && unwind.insn)
+    as_warn ("Initial .prologue should precede any instructions");
+
   if (!is_it_end_of_statement ())
     {
       expressionS e1, e2;
@@ -3948,7 +4306,7 @@ dot_prologue (dummy)
        as_bad ("No second operand to .prologue");
       sep = parse_operand (&e2);
       if (!is_end_of_line[sep] && !is_it_end_of_statement ())
-       ignore_rest_of_line ();
+       demand_empty_rest_of_line ();
 
       if (e1.X_op == O_constant)
        {
@@ -3972,6 +4330,7 @@ dot_prologue (dummy)
 
   unwind.prologue = 1;
   unwind.prologue_mask = mask;
+  unwind.body = 0;
   ++unwind.prologue_count;
 }
 
@@ -3985,9 +4344,14 @@ dot_endp (dummy)
   long where;
   segT saved_seg;
   subsegT saved_subseg;
-  const char *sec_name, *text_name;
-  char *name, *p, c;
+  char *name, *default_name, *p, c;
   symbolS *sym;
+  int unwind_check = md.unwind_check;
+
+  md.unwind_check = unwind_check_error;
+  if (!in_procedure ("endp"))
+    return;
+  md.unwind_check = unwind_check;
 
   if (unwind.saved_text_seg)
     {
@@ -4001,66 +4365,20 @@ dot_endp (dummy)
       saved_subseg = now_subseg;
     }
 
-  /*
-    Use a slightly ugly scheme to derive the unwind section names from
-    the text section name:
-
-    text sect.  unwind table sect.
-    name:       name:                      comments:
-    ----------  -----------------          --------------------------------
-    .text       .IA_64.unwind
-    .text.foo   .IA_64.unwind.text.foo
-    .foo        .IA_64.unwind.foo
-    .gnu.linkonce.t.foo
-               .gnu.linkonce.ia64unw.foo
-    _info       .IA_64.unwind_info         gas issues error message (ditto)
-    _infoFOO    .IA_64.unwind_infoFOO      gas issues error message (ditto)
-
-    This mapping is done so that:
-
-       (a) An object file with unwind info only in .text will use
-           unwind section names .IA_64.unwind and .IA_64.unwind_info.
-           This follows the letter of the ABI and also ensures backwards
-           compatibility with older toolchains.
-
-       (b) An object file with unwind info in multiple text sections
-           will use separate unwind sections for each text section.
-           This allows us to properly set the "sh_info" and "sh_link"
-           fields in SHT_IA_64_UNWIND as required by the ABI and also
-           lets GNU ld support programs with multiple segments
-           containing unwind info (as might be the case for certain
-           embedded applications).
-
-       (c) An error is issued if there would be a name clash.
-  */
-  text_name = segment_name (saved_seg);
-  if (strncmp (text_name, "_info", 5) == 0)
-    {
-      as_bad ("Illegal section name `%s' (causes unwind section name clash)",
-             text_name);
-      ignore_rest_of_line ();
-      return;
-    }
-  if (strcmp (text_name, ".text") == 0)
-    text_name = "";
-
   insn_group_break (1, 0, 0);
 
-  add_unwind_entry (output_endp ());
-
   /* If there wasn't a .handlerdata, we haven't generated an image yet.  */
   if (!unwind.info)
-    generate_unwind_image (text_name);
+    generate_unwind_image (saved_seg);
 
   if (unwind.info || unwind.force_unwind_entry)
     {
+      symbolS *proc_end;
+
       subseg_set (md.last_text_seg, 0);
-      unwind.proc_end = expr_build_dot ();
+      proc_end = expr_build_dot ();
 
-      make_unw_section_name (SPECIAL_SECTION_UNWIND, text_name, sec_name);
-      set_section ((char *) sec_name);
-      bfd_set_section_flags (stdoutput, now_seg,
-                            SEC_LOAD | SEC_ALLOC | SEC_READONLY);
+      start_unwind_section (saved_seg, SPECIAL_SECTION_UNWIND, 0);
 
       /* Make sure that section has 4 byte alignment for ILP32 and
          8 byte alignment for LP64.  */
@@ -4082,7 +4400,7 @@ 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_end;
+      e.X_add_symbol = proc_end;
       ia64_cons_fix_new (frag_now, where + bytes_per_address,
                         bytes_per_address, &e);
 
@@ -4100,8 +4418,16 @@ dot_endp (dummy)
                            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)
     {
@@ -4109,32 +4435,64 @@ dot_endp (dummy)
       name = input_line_pointer;
       c = get_symbol_end ();
       p = input_line_pointer;
-      sym = symbol_find (name);
-      if (sym && unwind.proc_start
-         && (symbol_get_bfdsym (sym)->flags & BSF_FUNCTION)
-         && 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 == frag_now && SEG_NORMAL (now_seg))
-               S_SET_SIZE (sym, frag_now_fix () - S_GET_VALUE (sym));
+      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)
+       {
+         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)
+           {
+             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)
                {
-                 symbol_get_obj (sym)->size =
-                   (expressionS *) xmalloc (sizeof (expressionS));
-                 symbol_get_obj (sym)->size->X_op = O_subtract;
-                 symbol_get_obj (sym)->size->X_add_symbol
-                   = symbol_new (FAKE_LABEL_NAME, now_seg,
-                                 frag_now_fix (), frag_now);
-                 symbol_get_obj (sym)->size->X_op_symbol = sym;
-                 symbol_get_obj (sym)->size->X_add_number = 0;
+                 if (frag == frag_now && SEG_NORMAL (now_seg))
+                   S_SET_SIZE (sym, frag_now_fix () - S_GET_VALUE (sym));
+                 else
+                   {
+                     symbol_get_obj (sym)->size =
+                       (expressionS *) xmalloc (sizeof (expressionS));
+                     symbol_get_obj (sym)->size->X_op = O_subtract;
+                     symbol_get_obj (sym)->size->X_add_symbol
+                       = symbol_new (FAKE_LABEL_NAME, now_seg,
+                                     frag_now_fix (), frag_now);
+                     symbol_get_obj (sym)->size->X_op_symbol = sym;
+                     symbol_get_obj (sym)->size->X_add_number = 0;
+                   }
                }
            }
        }
@@ -4145,7 +4503,7 @@ dot_endp (dummy)
       ++input_line_pointer;
     }
   demand_empty_rest_of_line ();
-  unwind.proc_start = unwind.proc_end = unwind.info = 0;
+  unwind.proc_start = unwind.info = 0;
 }
 
 static void
@@ -4206,6 +4564,7 @@ dot_rot (type)
   for (dr = md.dynreg[type]; dr && dr->num_regs; dr = dr->next)
     {
       hash_delete (md.dynreg_hash, dr->name);
+      /* FIXME: Free dr->name.  */
       dr->num_regs = 0;
     }
 
@@ -4214,8 +4573,8 @@ dot_rot (type)
     {
       start = input_line_pointer;
       ch = get_symbol_end ();
+      len = strlen (ia64_canonicalize_symbol_name (start));
       *input_line_pointer = ch;
-      len = (input_line_pointer - start);
 
       SKIP_WHITESPACE ();
       if (*input_line_pointer != '[')
@@ -4264,16 +4623,16 @@ dot_rot (type)
          break;
        }
 
-      name = obstack_alloc (&notes, len + 1);
-      memcpy (name, start, len);
-      name[len] = '\0';
-
       if (!*drpp)
        {
          *drpp = obstack_alloc (&notes, sizeof (*dr));
          memset (*drpp, 0, sizeof (*dr));
        }
 
+      name = obstack_alloc (&notes, len + 1);
+      memcpy (name, start, len);
+      name[len] = '\0';
+
       dr = *drpp;
       dr->name = name;
       dr->num_regs = num_regs;
@@ -4284,6 +4643,7 @@ dot_rot (type)
       if (hash_insert (md.dynreg_hash, name, dr))
        {
          as_bad ("Attempt to redefine register set `%s'", name);
+         obstack_free (&notes, name);
          goto err;
        }
 
@@ -4308,8 +4668,7 @@ dot_byteorder (byteorder)
   if (byteorder == -1)
     {
       if (seginfo->tc_segment_info_data.endian == 0)
-       seginfo->tc_segment_info_data.endian
-         = TARGET_BYTES_BIG_ENDIAN ? 1 : 2;
+       seginfo->tc_segment_info_data.endian = default_big_endian ? 1 : 2;
       byteorder = seginfo->tc_segment_info_data.endian == 1;
     }
   else
@@ -4379,13 +4738,22 @@ parse_section_name ()
   int len;
 
   SKIP_WHITESPACE ();
-  if (*input_line_pointer != '"')
+  if (*input_line_pointer == '"')
+      name = demand_copy_C_string (&len);
+  else
     {
-      as_bad ("Missing section name");
-      ignore_rest_of_line ();
-      return 0;
+      char *start = input_line_pointer;
+      char c = get_symbol_end ();
+
+      if (input_line_pointer == start)
+       {
+         as_bad ("Missing section name");
+         ignore_rest_of_line ();
+         return 0;
+       }
+      name = obstack_copy (&notes, start, input_line_pointer - start + 1);
+      *input_line_pointer = c;
     }
-  name = demand_copy_C_string (&len);
   if (!name)
     {
       ignore_rest_of_line ();
@@ -4557,6 +4925,23 @@ dot_reg_val (dummy)
   demand_empty_rest_of_line ();
 }
 
+/*
+  .serialize.data
+  .serialize.instruction
+ */
+static void
+dot_serialize (type)
+     int type;
+{
+  insn_group_break (0, 0, 0);
+  if (type)
+    instruction_serialization ();
+  else
+    data_serialization ();
+  insn_group_break (0, 0, 0);
+  demand_empty_rest_of_line ();
+}
+
 /* select dv checking mode
    .auto
    .explicit
@@ -4619,9 +5004,9 @@ print_prmask (mask)
 }
 
 /*
-  .pred.rel.clear [p1 [,p2 [,...]]]     (also .pred.rel "clear")
-  .pred.rel.imply p1, p2                (also .pred.rel "imply")
-  .pred.rel.mutex p1, p2 [,...]         (also .pred.rel "mutex")
+  .pred.rel.clear [p1 [,p2 [,...]]]     (also .pred.rel "clear" or @clear)
+  .pred.rel.imply p1, p2                (also .pred.rel "imply" or @imply)
+  .pred.rel.mutex p1, p2 [,...]         (also .pred.rel "mutex" or @mutex)
   .pred.safe_across_calls p1 [, p2 [,...]]
  */
 
@@ -4635,28 +5020,43 @@ dot_pred_rel (type)
 
   if (type == 0)
     {
-      if (*input_line_pointer != '"')
-       {
-         as_bad (_("Missing predicate relation type"));
-         ignore_rest_of_line ();
-         return;
-       }
-      else
+      if (*input_line_pointer == '"')
        {
          int len;
          char *form = demand_copy_C_string (&len);
+
          if (strcmp (form, "mutex") == 0)
            type = 'm';
          else if (strcmp (form, "clear") == 0)
            type = 'c';
          else if (strcmp (form, "imply") == 0)
            type = 'i';
-         else
-           {
-             as_bad (_("Unrecognized predicate relation type"));
-             ignore_rest_of_line ();
-             return;
-           }
+         obstack_free (&notes, form);
+       }
+      else if (*input_line_pointer == '@')
+       {
+         char *form = ++input_line_pointer;
+         char c = get_symbol_end();
+
+         if (strcmp (form, "mutex") == 0)
+           type = 'm';
+         else if (strcmp (form, "clear") == 0)
+           type = 'c';
+         else if (strcmp (form, "imply") == 0)
+           type = 'i';
+         *input_line_pointer = c;
+       }
+      else
+       {
+         as_bad (_("Missing predicate relation type"));
+         ignore_rest_of_line ();
+         return;
+       }
+      if (type == 0)
+       {
+         as_bad (_("Unrecognized predicate relation type"));
+         ignore_rest_of_line ();
+         return;
        }
       if (*input_line_pointer == ',')
        ++input_line_pointer;
@@ -4666,59 +5066,57 @@ dot_pred_rel (type)
   SKIP_WHITESPACE ();
   while (1)
     {
-      valueT bit = 1;
+      valueT bits = 1;
       int regno;
-
-      if (TOUPPER (*input_line_pointer) != 'P'
-         || (regno = atoi (++input_line_pointer)) < 0
-         || regno > 63)
-       {
-         as_bad (_("Predicate register expected"));
-         ignore_rest_of_line ();
-         return;
-       }
-      while (ISDIGIT (*input_line_pointer))
-       ++input_line_pointer;
-      if (p1 == -1)
-       p1 = regno;
-      else if (p2 == -1)
-       p2 = regno;
-      bit <<= regno;
-      if (mask & bit)
-       as_warn (_("Duplicate predicate register ignored"));
-      mask |= bit;
-      count++;
-      /* See if it's a range.  */
-      if (*input_line_pointer == '-')
-       {
-         valueT stop = 1;
-         ++input_line_pointer;
-
-         if (TOUPPER (*input_line_pointer) != 'P'
-             || (regno = atoi (++input_line_pointer)) < 0
-             || regno > 63)
-           {
-             as_bad (_("Predicate register expected"));
-             ignore_rest_of_line ();
-             return;
-           }
-         while (ISDIGIT (*input_line_pointer))
-           ++input_line_pointer;
-         stop <<= regno;
-         if (bit >= stop)
+      expressionS pr, *pr1, *pr2;
+
+      expression (&pr);
+      if (pr.X_op == O_register
+         && pr.X_add_number >= REG_P
+         && pr.X_add_number <= REG_P + 63)
+       {
+         regno = pr.X_add_number - REG_P;
+         bits <<= regno;
+         count++;
+         if (p1 == -1)
+           p1 = regno;
+         else if (p2 == -1)
+           p2 = regno;
+       }
+      else if (type != 'i'
+         && pr.X_op == O_subtract
+         && (pr1 = symbol_get_value_expression (pr.X_add_symbol))
+         && pr1->X_op == O_register
+         && pr1->X_add_number >= REG_P
+         && pr1->X_add_number <= REG_P + 63
+         && (pr2 = symbol_get_value_expression (pr.X_op_symbol))
+         && pr2->X_op == O_register
+         && pr2->X_add_number >= REG_P
+         && pr2->X_add_number <= REG_P + 63)
+       {
+         /* It's a range.  */
+         int stop;
+
+         regno = pr1->X_add_number - REG_P;
+         stop = pr2->X_add_number - REG_P;
+         if (regno >= stop)
            {
              as_bad (_("Bad register range"));
              ignore_rest_of_line ();
              return;
            }
-         while (bit < stop)
-           {
-             bit <<= 1;
-             mask |= bit;
-             count++;
-           }
-         SKIP_WHITESPACE ();
+         bits = ((bits << stop) << 1) - (bits << regno);
+         count += stop - regno + 1;
+       }
+      else
+       {
+         as_bad (_("Predicate register expected"));
+         ignore_rest_of_line ();
+         return;
        }
+      if (mask & bits)
+       as_warn (_("Duplicate predicate register ignored"));
+      mask |= bits;
       if (*input_line_pointer != ',')
        break;
       ++input_line_pointer;
@@ -4838,6 +5236,7 @@ const pseudo_typeS md_pseudo_table[] =
   {
     { "radix", dot_radix, 0 },
     { "lcomm", s_lcomm_bytes, 1 },
+    { "loc", dot_loc, 0 },
     { "bss", dot_special_section, SPECIAL_SECTION_BSS },
     { "sbss", dot_special_section, SPECIAL_SECTION_SBSS },
     { "sdata", dot_special_section, SPECIAL_SECTION_SDATA },
@@ -4880,9 +5279,6 @@ const pseudo_typeS md_pseudo_table[] =
     { "copy_state", dot_copy_state, 0 },
     { "unwabi", dot_unwabi, 0 },
     { "personality", dot_personality, 0 },
-#if 0
-    { "estate", dot_estate, 0 },
-#endif
     { "mii", dot_template, 0x0 },
     { "mli", dot_template, 0x2 }, /* old format, for compatibility */
     { "mlx", dot_template, 0x2 },
@@ -4894,11 +5290,7 @@ const pseudo_typeS md_pseudo_table[] =
     { "bbb", dot_template, 0xb },
     { "mmb", dot_template, 0xc },
     { "mfb", dot_template, 0xe },
-#if 0
-    { "lb", dot_scope, 0 },
-    { "le", dot_scope, 1 },
-#endif
-    { "align", s_align_bytes, 0 },
+    { "align", dot_align, 0 },
     { "regstk", dot_regstk, 0 },
     { "rotr", dot_rot, DYNREG_GR },
     { "rotf", dot_rot, DYNREG_FR },
@@ -4914,6 +5306,7 @@ const pseudo_typeS md_pseudo_table[] =
     { "xdata2", dot_xdata, 2 },
     { "xdata4", dot_xdata, 4 },
     { "xdata8", dot_xdata, 8 },
+    { "xdata16", dot_xdata, 16 },
     { "xreal4", dot_xfloat_cons, 'f' },
     { "xreal8", dot_xfloat_cons, 'd' },
     { "xreal10", dot_xfloat_cons, 'x' },
@@ -4925,6 +5318,7 @@ const pseudo_typeS md_pseudo_table[] =
     { "xdata2.ua", dot_xdata_ua, 2 },
     { "xdata4.ua", dot_xdata_ua, 4 },
     { "xdata8.ua", dot_xdata_ua, 8 },
+    { "xdata16.ua", dot_xdata_ua, 16 },
     { "xreal4.ua", dot_xfloat_cons_ua, 'f' },
     { "xreal8.ua", dot_xfloat_cons_ua, 'd' },
     { "xreal10.ua", dot_xfloat_cons_ua, 'x' },
@@ -4939,6 +5333,8 @@ const pseudo_typeS md_pseudo_table[] =
     { "pred.rel.mutex", dot_pred_rel, 'm' },
     { "pred.safe_across_calls", dot_pred_rel, 's' },
     { "reg.val", dot_reg_val, 0 },
+    { "serialize.data", dot_serialize, 0 },
+    { "serialize.instruction", dot_serialize, 1 },
     { "auto", dot_dv_mode, 'a' },
     { "explicit", dot_dv_mode, 'e' },
     { "default", dot_dv_mode, 'd' },
@@ -5625,7 +6021,8 @@ parse_operands (idesc)
   assert (strlen (idesc->name) <= 128);
 
   strcpy (mnemonic, idesc->name);
-  if (idesc->operands[2] == IA64_OPND_SOF)
+  if (idesc->operands[2] == IA64_OPND_SOF
+      || idesc->operands[1] == IA64_OPND_SOF)
     {
       /* To make the common idiom "alloc loc?=ar.pfs,0,1,0,0" work, we
         can't parse the first operand until we have parsed the
@@ -5643,11 +6040,22 @@ parse_operands (idesc)
       ++num_outputs;
     }
 
-  for (; i < NELEMS (CURR_SLOT.opnd); ++i)
+  for (; ; ++i)
     {
-      sep = parse_operand (CURR_SLOT.opnd + i);
-      if (CURR_SLOT.opnd[i].X_op == O_absent)
-       break;
+      if (i < NELEMS (CURR_SLOT.opnd)) 
+       {
+         sep = parse_operand (CURR_SLOT.opnd + i);
+         if (CURR_SLOT.opnd[i].X_op == O_absent)
+           break;
+       }
+      else
+       {
+         expressionS dummy;
+
+         sep = parse_operand (&dummy);
+         if (dummy.X_op == O_absent)
+           break;
+       }
 
       ++num_operands;
 
@@ -5668,20 +6076,23 @@ parse_operands (idesc)
       return 0;
     }
 
-  if (idesc->operands[2] == IA64_OPND_SOF)
+  if (idesc->operands[2] == IA64_OPND_SOF
+      || idesc->operands[1] == IA64_OPND_SOF)
     {
       /* map alloc r1=ar.pfs,i,l,o,r to alloc r1=ar.pfs,(i+l+o),(i+l),r */
       know (strcmp (idesc->name, "alloc") == 0);
-      if (num_operands == 5 /* first_arg not included in this count! */
-         && CURR_SLOT.opnd[2].X_op == O_constant
-         && CURR_SLOT.opnd[3].X_op == O_constant
-         && CURR_SLOT.opnd[4].X_op == O_constant
-         && CURR_SLOT.opnd[5].X_op == O_constant)
-       {
-         sof = set_regstack (CURR_SLOT.opnd[2].X_add_number,
-                             CURR_SLOT.opnd[3].X_add_number,
-                             CURR_SLOT.opnd[4].X_add_number,
-                             CURR_SLOT.opnd[5].X_add_number);
+      i = (CURR_SLOT.opnd[1].X_op == O_register
+          && CURR_SLOT.opnd[1].X_add_number == REG_AR + AR_PFS) ? 2 : 1;
+      if (num_operands == i + 3 /* first_arg not included in this count! */
+         && CURR_SLOT.opnd[i].X_op == O_constant
+         && CURR_SLOT.opnd[i + 1].X_op == O_constant
+         && CURR_SLOT.opnd[i + 2].X_op == O_constant
+         && CURR_SLOT.opnd[i + 3].X_op == O_constant)
+       {
+         sof = set_regstack (CURR_SLOT.opnd[i].X_add_number,
+                             CURR_SLOT.opnd[i + 1].X_add_number,
+                             CURR_SLOT.opnd[i + 2].X_add_number,
+                             CURR_SLOT.opnd[i + 3].X_add_number);
 
          /* now we can parse the first arg:  */
          saved_input_pointer = input_line_pointer;
@@ -5691,21 +6102,29 @@ parse_operands (idesc)
            --num_outputs;      /* force error */
          input_line_pointer = saved_input_pointer;
 
-         CURR_SLOT.opnd[2].X_add_number = sof;
-         CURR_SLOT.opnd[3].X_add_number
-           = sof - CURR_SLOT.opnd[4].X_add_number;
-         CURR_SLOT.opnd[4] = CURR_SLOT.opnd[5];
+         CURR_SLOT.opnd[i].X_add_number = sof;
+         CURR_SLOT.opnd[i + 1].X_add_number
+           = sof - CURR_SLOT.opnd[i + 2].X_add_number;
+         CURR_SLOT.opnd[i + 2] = CURR_SLOT.opnd[i + 3];
        }
     }
 
-  highest_unmatched_operand = 0;
+  highest_unmatched_operand = -4;
   curr_out_of_range_pos = -1;
   error_pos = 0;
-  expected_operand = idesc->operands[0];
   for (; idesc; idesc = get_next_opcode (idesc))
     {
       if (num_outputs != idesc->num_outputs)
        continue;               /* mismatch in # of outputs */
+      if (highest_unmatched_operand < 0)
+       highest_unmatched_operand |= 1;
+      if (num_operands > NELEMS (idesc->operands)
+         || (num_operands < NELEMS (idesc->operands)
+          && idesc->operands[num_operands])
+         || (num_operands > 0 && !idesc->operands[num_operands - 1]))
+       continue;               /* mismatch in number of arguments */
+      if (highest_unmatched_operand < 0)
+       highest_unmatched_operand |= 2;
 
       CURR_SLOT.num_fixups = 0;
 
@@ -5758,10 +6177,6 @@ parse_operands (idesc)
          continue;
        }
 
-      if (num_operands < NELEMS (idesc->operands)
-         && idesc->operands[num_operands])
-       continue;               /* mismatch in number of arguments */
-
       break;
     }
   if (!idesc)
@@ -5770,6 +6185,10 @@ parse_operands (idesc)
        as_bad ("Operand %u of `%s' should be %s",
                error_pos + 1, mnemonic,
                elf64_ia64_operands[expected_operand].desc);
+      else if (highest_unmatched_operand < 0 && !(highest_unmatched_operand & 1))
+       as_bad ("Wrong number of output operands");
+      else if (highest_unmatched_operand < 0 && !(highest_unmatched_operand & 2))
+       as_bad ("Wrong number of input operands");
       else
        as_bad ("Operand mismatch");
       return 0;
@@ -5777,98 +6196,6 @@ parse_operands (idesc)
   return idesc;
 }
 
-/* Keep track of state necessary to determine whether a NOP is necessary
-   to avoid an erratum in A and B step Itanium chips, and return 1 if we
-   detect a case where additional NOPs may be necessary.  */
-static int
-errata_nop_necessary_p (slot, insn_unit)
-     struct slot *slot;
-     enum ia64_unit insn_unit;
-{
-  int i;
-  struct group *this_group = md.last_groups + md.group_idx;
-  struct group *prev_group = md.last_groups + (md.group_idx + 2) % 3;
-  struct ia64_opcode *idesc = slot->idesc;
-
-  /* Test whether this could be the first insn in a problematic sequence.  */
-  if (insn_unit == IA64_UNIT_F)
-    {
-      for (i = 0; i < idesc->num_outputs; i++)
-       if (idesc->operands[i] == IA64_OPND_P1
-           || idesc->operands[i] == IA64_OPND_P2)
-         {
-           int regno = slot->opnd[i].X_add_number - REG_P;
-           /* Ignore invalid operands; they generate errors elsewhere.  */
-           if (regno >= 64)
-             return 0;
-           this_group->p_reg_set[regno] = 1;
-         }
-    }
-
-  /* Test whether this could be the second insn in a problematic sequence.  */
-  if (insn_unit == IA64_UNIT_M && slot->qp_regno > 0
-      && prev_group->p_reg_set[slot->qp_regno])
-    {
-      for (i = 0; i < idesc->num_outputs; i++)
-       if (idesc->operands[i] == IA64_OPND_R1
-           || idesc->operands[i] == IA64_OPND_R2
-           || idesc->operands[i] == IA64_OPND_R3)
-         {
-           int regno = slot->opnd[i].X_add_number - REG_GR;
-           /* Ignore invalid operands; they generate errors elsewhere.  */
-           if (regno >= 128)
-             return 0;
-           if (strncmp (idesc->name, "add", 3) != 0
-               && strncmp (idesc->name, "sub", 3) != 0
-               && strncmp (idesc->name, "shladd", 6) != 0
-               && (idesc->flags & IA64_OPCODE_POSTINC) == 0)
-             this_group->g_reg_set_conditionally[regno] = 1;
-         }
-    }
-
-  /* Test whether this could be the third insn in a problematic sequence.  */
-  for (i = 0; i < NELEMS (idesc->operands) && idesc->operands[i]; i++)
-    {
-      if (/* For fc, ptc, ptr, tak, thash, tpa, ttag, probe, ptr, ptc.  */
-         idesc->operands[i] == IA64_OPND_R3
-         /* For mov indirect.  */
-         || idesc->operands[i] == IA64_OPND_RR_R3
-         || idesc->operands[i] == IA64_OPND_DBR_R3
-         || idesc->operands[i] == IA64_OPND_IBR_R3
-         || idesc->operands[i] == IA64_OPND_PKR_R3
-         || idesc->operands[i] == IA64_OPND_PMC_R3
-         || idesc->operands[i] == IA64_OPND_PMD_R3
-         || idesc->operands[i] == IA64_OPND_MSR_R3
-         || idesc->operands[i] == IA64_OPND_CPUID_R3
-         /* For itr.  */
-         || idesc->operands[i] == IA64_OPND_ITR_R3
-         || idesc->operands[i] == IA64_OPND_DTR_R3
-         /* Normal memory addresses (load, store, xchg, cmpxchg, etc.).  */
-         || idesc->operands[i] == IA64_OPND_MR3)
-       {
-         int regno = slot->opnd[i].X_add_number - REG_GR;
-         /* Ignore invalid operands; they generate errors elsewhere.  */
-         if (regno >= 128)
-           return 0;
-         if (idesc->operands[i] == IA64_OPND_R3)
-           {
-             if (strcmp (idesc->name, "fc") != 0
-                 && strcmp (idesc->name, "tak") != 0
-                 && strcmp (idesc->name, "thash") != 0
-                 && strcmp (idesc->name, "tpa") != 0
-                 && strcmp (idesc->name, "ttag") != 0
-                 && strncmp (idesc->name, "ptr", 3) != 0
-                 && strncmp (idesc->name, "ptc", 3) != 0
-                 && strncmp (idesc->name, "probe", 5) != 0)
-               return 0;
-           }
-         if (prev_group->g_reg_set_conditionally[regno])
-           return 1;
-       }
-    }
-  return 0;
-}
-
 static void
 build_insn (slot, insnp)
      struct slot *slot;
@@ -5996,8 +6323,7 @@ build_insn (slot, insnp)
 static void
 emit_one_bundle ()
 {
-  unsigned int manual_bundling_on = 0, manual_bundling_off = 0;
-  unsigned int manual_bundling = 0;
+  int manual_bundling_off = 0, manual_bundling = 0;
   enum ia64_unit required_unit, insn_unit = 0;
   enum ia64_insn_type type[3], insn_type;
   unsigned int template, orig_template;
@@ -6012,6 +6338,7 @@ emit_one_bundle ()
   char mnemonic[16];
   fixS *fix;
   char *f;
+  int addr_mod;
 
   first = (md.curr_slot + NUM_SLOTS - md.num_slots_in_use) % NUM_SLOTS;
   know (first >= 0 & first < NUM_SLOTS);
@@ -6043,6 +6370,14 @@ emit_one_bundle ()
 
   f = frag_more (16);
 
+  /* Check to see if this bundle is at an offset that is a multiple of 16-bytes
+     from the start of the frag.  */
+  addr_mod = frag_now_fix () & 15;
+  if (frag_now->has_code && frag_now->insn_addr != addr_mod)
+    as_bad (_("instruction address is not a multiple of 16"));
+  frag_now->insn_addr = addr_mod;
+  frag_now->has_code = 1;
+
   /* now fill in slots with as many insns as possible:  */
   curr = first;
   idesc = md.slot[curr].idesc;
@@ -6083,13 +6418,25 @@ emit_one_bundle ()
            }
        }
 
+      manual_bundling_off = md.slot[curr].manual_bundling_off;
+      if (md.slot[curr].manual_bundling_on)
+       {
+         if (curr == first)
+           manual_bundling = 1;
+         else
+         break; /* Need to start a new bundle.  */
+       }
+
       if (idesc->flags & IA64_OPCODE_SLOT2)
        {
-         if (manual_bundling && i != 2)
-           as_bad_where (md.slot[curr].src_file, md.slot[curr].src_line,
-                         "`%s' must be last in bundle", idesc->name);
-         else
-           i = 2;
+         if (manual_bundling && !manual_bundling_off)
+           {
+             as_bad_where (md.slot[curr].src_file, md.slot[curr].src_line,
+                           "`%s' must be last in bundle", idesc->name);
+             if (i < 2)
+               manual_bundling = -1; /* Suppress meaningless post-loop errors.  */
+           }
+         i = 2;
        }
       if (idesc->flags & IA64_OPCODE_LAST)
        {
@@ -6122,10 +6469,19 @@ emit_one_bundle ()
              required_slot = i;
              break;
            }
-         if (manual_bundling && i != required_slot)
-           as_bad_where (md.slot[curr].src_file, md.slot[curr].src_line,
-                         "`%s' must be last in instruction group",
-                         idesc->name);
+         if (manual_bundling
+             && (i > required_slot
+                 || (required_slot == 2 && !manual_bundling_off)
+                 || (user_template >= 0
+                     /* Changing from MMI to M;MI is OK.  */
+                     && (template ^ required_template) > 1)))
+           {
+             as_bad_where (md.slot[curr].src_file, md.slot[curr].src_line,
+                           "`%s' must be last in instruction group",
+                           idesc->name);
+             if (i < 2 && required_slot == 2 && !manual_bundling_off)
+               manual_bundling = -1; /* Suppress meaningless post-loop errors.  */
+           }
          if (required_slot < i)
            /* Can't fit this instruction.  */
            break;
@@ -6144,24 +6500,16 @@ emit_one_bundle ()
        }
       if (curr != first && md.slot[curr].label_fixups)
        {
-         if (manual_bundling_on)
-           as_bad_where (md.slot[curr].src_file, md.slot[curr].src_line,
+         if (manual_bundling)
+           {
+             as_bad_where (md.slot[curr].src_file, md.slot[curr].src_line,
                          "Label must be first in a bundle");
+             manual_bundling = -1; /* Suppress meaningless post-loop errors.  */
+           }
          /* This insn must go into the first slot of a bundle.  */
          break;
        }
 
-      manual_bundling_on = md.slot[curr].manual_bundling_on;
-      manual_bundling_off = md.slot[curr].manual_bundling_off;
-
-      if (manual_bundling_on)
-       {
-         if (curr == first)
-           manual_bundling = 1;
-         else
-           break;                      /* need to start a new bundle */
-       }
-
       if (end_of_insn_group && md.num_slots_in_use >= 1)
        {
          /* We need an instruction group boundary in the middle of a
@@ -6189,12 +6537,17 @@ emit_one_bundle ()
                      reason we have to check for this is that otherwise we
                      may end up generating "MI;;I M.." which has the deadly
                      effect that the second M instruction is no longer the
-                     first in the bundle! --davidm 99/12/16  */
+                     first in the group! --davidm 99/12/16  */
                   && (idesc->flags & IA64_OPCODE_FIRST) == 0)
            {
              template = 1;
              end_of_insn_group = 0;
            }
+         else if (i == 1
+                  && user_template == 0
+                  && !(idesc->flags & IA64_OPCODE_FIRST))
+           /* Use the next slot.  */
+           continue;
          else if (curr != first)
            /* can't fit this insn */
            break;
@@ -6212,25 +6565,37 @@ emit_one_bundle ()
       /* resolve dynamic opcodes such as "break", "hint", and "nop":  */
       if (idesc->type == IA64_TYPE_DYN)
        {
+         enum ia64_opnd opnd1, opnd2;
+
          if ((strcmp (idesc->name, "nop") == 0)
              || (strcmp (idesc->name, "hint") == 0)
              || (strcmp (idesc->name, "break") == 0))
            insn_unit = required_unit;
-         else if (strcmp (idesc->name, "chk.s") == 0)
+         else if (strcmp (idesc->name, "chk.s") == 0
+             || strcmp (idesc->name, "mov") == 0)
            {
              insn_unit = IA64_UNIT_M;
-             if (required_unit == IA64_UNIT_I)
+             if (required_unit == IA64_UNIT_I
+                 || (required_unit == IA64_UNIT_F && template == 6))
                insn_unit = IA64_UNIT_I;
            }
          else
            as_fatal ("emit_one_bundle: unexpected dynamic op");
 
-         sprintf (mnemonic, "%s.%c", idesc->name, "?imbf??"[insn_unit]);
+         sprintf (mnemonic, "%s.%c", idesc->name, "?imbfxx"[insn_unit]);
+         opnd1 = idesc->operands[0];
+         opnd2 = idesc->operands[1];
          ia64_free_opcode (idesc);
-         md.slot[curr].idesc = idesc = ia64_find_opcode (mnemonic);
-#if 0
-         know (!idesc->next);  /* no resolved dynamic ops have collisions */
-#endif
+         idesc = ia64_find_opcode (mnemonic);
+         /* moves to/from ARs have collisions */
+         if (opnd1 == IA64_OPND_AR3 || opnd2 == IA64_OPND_AR3)
+           {
+             while (idesc != NULL
+                    && (idesc->operands[0] != opnd1
+                        || idesc->operands[1] != opnd2))
+               idesc = get_next_opcode (idesc);
+           }
+         md.slot[curr].idesc = idesc;
        }
       else
        {
@@ -6274,15 +6639,13 @@ emit_one_bundle ()
          continue;             /* try next slot */
        }
 
-      {
-       bfd_vma addr;
-
-       addr = frag_now->fr_address + frag_now_fix () - 16 + i;
-       dwarf2_gen_line_info (addr, &md.slot[curr].debug_line);
-      }
+      if (debug_type == DEBUG_DWARF2 || md.slot[curr].loc_directive_seen)
+       {
+         bfd_vma addr = frag_now->fr_address + frag_now_fix () - 16 + i;
 
-      if (errata_nop_necessary_p (md.slot + curr, insn_unit))
-       as_warn (_("Additional NOP may be necessary to workaround Itanium processor A/B step errata"));
+         md.slot[curr].loc_directive_seen = 0;
+         dwarf2_gen_line_info (addr, &md.slot[curr].debug_line);
+       }
 
       build_insn (md.slot + curr, insn + i);
 
@@ -6335,12 +6698,6 @@ emit_one_bundle ()
 
       end_of_insn_group = md.slot[curr].end_of_insn_group;
 
-      if (end_of_insn_group)
-       {
-         md.group_idx = (md.group_idx + 1) % 3;
-         memset (md.last_groups + md.group_idx, 0, sizeof md.last_groups[0]);
-       }
-
       /* clear slot:  */
       ia64_free_opcode (md.slot[curr].idesc);
       memset (md.slot + curr, 0, sizeof (md.slot[curr]));
@@ -6354,12 +6711,15 @@ emit_one_bundle ()
       curr = (curr + 1) % NUM_SLOTS;
       idesc = md.slot[curr].idesc;
     }
-  if (manual_bundling)
+  if (manual_bundling > 0)
     {
       if (md.num_slots_in_use > 0)
-       as_bad_where (md.slot[curr].src_file, md.slot[curr].src_line,
-                     "`%s' does not fit into %s template",
-                     idesc->name, ia64_templ_desc[template].name);
+       {
+         as_bad_where (md.slot[curr].src_file, md.slot[curr].src_line,
+                       "`%s' does not fit into %s template",
+                       idesc->name, ia64_templ_desc[template].name);
+         --md.num_slots_in_use;
+       }
       else
        as_bad_where (md.slot[curr].src_file, md.slot[curr].src_line,
                      "Missing '}' at end of file");
@@ -6402,10 +6762,22 @@ md_parse_option (c, arg)
       else if (strcmp (arg, "le") == 0)
        {
          md.flags &= ~EF_IA_64_BE;
+         default_big_endian = 0;
        }
       else if (strcmp (arg, "be") == 0)
        {
          md.flags |= EF_IA_64_BE;
+         default_big_endian = 1;
+       }
+      else if (strncmp (arg, "unwind-check=", 13) == 0)
+       {
+         arg += 13;
+         if (strcmp (arg, "warning") == 0)
+           md.unwind_check = unwind_check_warning;
+         else if (strcmp (arg, "error") == 0)
+           md.unwind_check = unwind_check_error;
+         else
+           return 0;
        }
       else
        return 0;
@@ -6462,6 +6834,10 @@ md_parse_option (c, arg)
        {
          md.default_explicit_mode = 0;
        }
+      else if (strcmp (arg, "none") == 0)
+       {
+         md.detect_dv = 0;
+       }
       else if (strcmp (arg, "debug") == 0)
        {
          md.debug_dv = 1;
@@ -6471,6 +6847,11 @@ md_parse_option (c, arg)
          md.default_explicit_mode = 1;
          md.debug_dv = 1;
        }
+      else if (strcmp (arg, "debugn") == 0)
+       {
+         md.debug_dv = 1;
+         md.detect_dv = 0;
+       }
       else
        {
          as_bad (_("Unrecognized option '-x%s'"), arg);
@@ -6510,9 +6891,16 @@ IA-64 options:\n\
                          EF_IA_64_NOFUNCDESC_CONS_GP)\n\
   -milp32|-milp64|-mlp64|-mp64 select data model (default -mlp64)\n\
   -mle | -mbe            select little- or big-endian byte order (default -mle)\n\
-  -x | -xexplicit        turn on dependency violation checking (default)\n\
-  -xauto                 automagically remove dependency violations\n\
-  -xdebug                debug dependency violation checker\n"),
+  -munwind-check=[warning|error]\n\
+                         unwind directive check (default -munwind-check=warning)\n\
+  -x | -xexplicit        turn on dependency violation checking\n\
+  -xauto                 automagically remove dependency violations (default)\n\
+  -xnone                 turn off dependency violation checking\n\
+  -xdebug                debug dependency violation checker\n\
+  -xdebugn               debug dependency violation checker but turn off\n\
+                         dependency violation checking\n\
+  -xdebugx               debug dependency violation checker and turn on\n\
+                         dependency violation checking\n"),
        stream);
 }
 
@@ -6578,7 +6966,7 @@ md_begin ()
 
   /* Make sure function pointers get initialized.  */
   target_big_endian = -1;
-  dot_byteorder (TARGET_BYTES_BIG_ENDIAN);
+  dot_byteorder (default_big_endian);
 
   alias_hash = hash_new ();
   alias_name_hash = hash_new ();
@@ -6844,10 +7232,9 @@ md_begin ()
   md.entry_labels = NULL;
 }
 
-/* Set the elf type to 64 bit ABI by default.  Cannot do this in md_begin
-   because that is called after md_parse_option which is where we do the
-   dynamic changing of md.flags based on -mlp64 or -milp32.  Also, set the
-   default endianness.  */
+/* Set the default options in md.  Cannot do this in md_begin because
+   that is called after md_parse_option which is where we set the
+   options in md based on command line options.  */
 
 void
 ia64_init (argc, argv)
@@ -6855,6 +7242,9 @@ ia64_init (argc, argv)
      char **argv ATTRIBUTE_UNUSED;
 {
   md.flags = MD_FLAGS_DEFAULT;
+  md.detect_dv = 1;
+  /* FIXME: We should change it to unwind_check_error someday.  */
+  md.unwind_check = unwind_check_warning;
 }
 
 /* Return a string for the target object file format.  */
@@ -6930,7 +7320,15 @@ ia64_start_line ()
   if (input_line_pointer[0] == ';' && input_line_pointer[-1] == ';')
     {
       if (md.detect_dv && !md.explicit_mode)
-       as_warn (_("Explicit stops are ignored in auto mode"));
+       {
+         static int warned;
+
+         if (!warned)
+           {
+             warned = 1;
+             as_warn (_("Explicit stops are ignored in auto mode"));
+           }
+       }
       else
        insn_group_break (1, 0, 0);
     }
@@ -7117,6 +7515,23 @@ ia64_frob_label (sym)
     }
 }
 
+#ifdef TE_HPUX
+/* The HP-UX linker will give unresolved symbol errors for symbols
+   that are declared but unused.  This routine removes declared,
+   unused symbols from an object.  */
+int
+ia64_frob_symbol (sym)
+     struct symbol *sym;
+{
+  if ((S_GET_SEGMENT (sym) == &bfd_und_section && ! symbol_used_p (sym) &&
+       ELF_ST_VISIBILITY (S_GET_OTHER (sym)) == STV_DEFAULT)
+      || (S_GET_SEGMENT (sym) == &bfd_abs_section
+         && ! S_IS_EXTERNAL (sym)))
+    return 1;
+  return 0;
+}
+#endif
+
 void
 ia64_flush_pending_output ()
 {
@@ -7176,16 +7591,101 @@ ia64_optimize_expr (l, op, r)
 }
 
 int
-ia64_parse_name (name, e)
+ia64_parse_name (name, e, nextcharP)
      char *name;
      expressionS *e;
+     char *nextcharP;
 {
   struct const_desc *cdesc;
   struct dynreg *dr = 0;
   unsigned int regnum;
+  unsigned int idx;
   struct symbol *sym;
   char *end;
 
+  if (*name == '@')
+    {
+      enum pseudo_type pseudo_type = PSEUDO_FUNC_NONE;
+
+      /* Find what relocation pseudo-function we're dealing with.  */
+      for (idx = 0; idx < NELEMS (pseudo_func); ++idx)
+       if (pseudo_func[idx].name
+           && pseudo_func[idx].name[0] == name[1]
+           && strcmp (pseudo_func[idx].name + 1, name + 2) == 0)
+         {
+           pseudo_type = pseudo_func[idx].type;
+           break;
+         }
+      switch (pseudo_type)
+       {
+       case PSEUDO_FUNC_RELOC:
+         end = input_line_pointer;
+         if (*nextcharP != '(')
+           {
+             as_bad ("Expected '('");
+             break;
+           }
+         /* Skip '('.  */
+         ++input_line_pointer;
+         expression (e);
+         if (*input_line_pointer != ')')
+           {
+             as_bad ("Missing ')'");
+             goto done;
+           }
+         /* Skip ')'.  */
+         ++input_line_pointer;
+         if (e->X_op != O_symbol)
+           {
+             if (e->X_op != O_pseudo_fixup)
+               {
+                 as_bad ("Not a symbolic expression");
+                 goto done;
+               }
+             if (idx != FUNC_LT_RELATIVE)
+               {
+                 as_bad ("Illegal combination of relocation functions");
+                 goto done;
+               }
+             switch (S_GET_VALUE (e->X_op_symbol))
+               {
+               case FUNC_FPTR_RELATIVE:
+                 idx = FUNC_LT_FPTR_RELATIVE; break;
+               case FUNC_DTP_MODULE:
+                 idx = FUNC_LT_DTP_MODULE; break;
+               case FUNC_DTP_RELATIVE:
+                 idx = FUNC_LT_DTP_RELATIVE; break;
+               case FUNC_TP_RELATIVE:
+                 idx = FUNC_LT_TP_RELATIVE; break;
+               default:
+                 as_bad ("Illegal combination of relocation functions");
+                 goto done;
+               }
+           }
+         /* Make sure gas doesn't get rid of local symbols that are used
+            in relocs.  */
+         e->X_op = O_pseudo_fixup;
+         e->X_op_symbol = pseudo_func[idx].u.sym;
+       done:
+         *nextcharP = *input_line_pointer;
+         break;
+
+       case PSEUDO_FUNC_CONST:
+         e->X_op = O_constant;
+         e->X_add_number = pseudo_func[idx].u.ival;
+         break;
+
+       case PSEUDO_FUNC_REG:
+         e->X_op = O_register;
+         e->X_add_number = pseudo_func[idx].u.ival;
+         break;
+
+       default:
+         return 0;
+       }
+      return 1;
+    }
+
   /* first see if NAME is a known register name:  */
   sym = hash_find (md.reg_hash, name);
   if (sym)
@@ -7255,6 +7755,9 @@ ia64_parse_name (name, e)
        }
     }
 
+  end = alloca (strlen (name) + 1);
+  strcpy (end, name);
+  name = ia64_canonicalize_symbol_name (end);
   if ((dr = hash_find (md.dynreg_hash, name)))
     {
       /* We've got ourselves the name of a rotating register set.
@@ -7274,9 +7777,20 @@ char *
 ia64_canonicalize_symbol_name (name)
      char *name;
 {
-  size_t len = strlen (name);
-  if (len > 1 && name[len - 1] == '#')
-    name[len - 1] = '\0';
+  size_t len = strlen (name), full = len;
+
+  while (len > 0 && name[len - 1] == '#')
+    --len;
+  if (len <= 0)
+    {
+      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");
+  name[len] = '\0';
   return name;
 }
 
@@ -9243,10 +9757,6 @@ resources_match (rs, idesc, note, qp_regno, path)
       else if (specs[count].index == rs->index)
        return 1;
     }
-#if 0
-  if (md.debug_dv)
-    fprintf (stderr, "  No %s conflicts\n", rs->dependency->name);
-#endif
 
   return 0;
 }
@@ -9426,17 +9936,15 @@ remove_marked_resource (rs)
        insn_group_break (1, 0, 0);
       if (rs->insn_srlz < STATE_SRLZ)
        {
-         int oldqp = CURR_SLOT.qp_regno;
-         struct ia64_opcode *oldidesc = CURR_SLOT.idesc;
+         struct slot oldslot = CURR_SLOT;
          /* Manually jam a srlz.i insn into the stream */
-         CURR_SLOT.qp_regno = 0;
+         memset (&CURR_SLOT, 0, sizeof (CURR_SLOT));
          CURR_SLOT.idesc = ia64_find_opcode ("srlz.i");
          instruction_serialization ();
          md.curr_slot = (md.curr_slot + 1) % NUM_SLOTS;
          if (++md.num_slots_in_use >= NUM_SLOTS)
            emit_one_bundle ();
-         CURR_SLOT.qp_regno = oldqp;
-         CURR_SLOT.idesc = oldidesc;
+         CURR_SLOT = oldslot;
        }
       insn_group_break (1, 0, 0);
       break;
@@ -9449,17 +9957,15 @@ remove_marked_resource (rs)
       if (rs->data_srlz < STATE_STOP)
        insn_group_break (1, 0, 0);
       {
-       int oldqp = CURR_SLOT.qp_regno;
-       struct ia64_opcode *oldidesc = CURR_SLOT.idesc;
+       struct slot oldslot = CURR_SLOT;
        /* Manually jam a srlz.d insn into the stream */
-       CURR_SLOT.qp_regno = 0;
+       memset (&CURR_SLOT, 0, sizeof (CURR_SLOT));
        CURR_SLOT.idesc = ia64_find_opcode ("srlz.d");
        data_serialization ();
        md.curr_slot = (md.curr_slot + 1) % NUM_SLOTS;
        if (++md.num_slots_in_use >= NUM_SLOTS)
          emit_one_bundle ();
-       CURR_SLOT.qp_regno = oldqp;
-       CURR_SLOT.idesc = oldidesc;
+       CURR_SLOT = oldslot;
       }
       break;
     case IA64_DVS_IMPLIED:
@@ -9651,12 +10157,6 @@ mark_resources (idesc)
 
       count = specify_resource (dep, idesc, DV_REG, specs, note, md.path);
 
-#if 0
-      if (md.debug_dv && !count)
-       fprintf (stderr, "  No %s %s usage found (path %d)\n",
-                dv_mode[dep->mode], dep->name, md.path);
-#endif
-
       while (count-- > 0)
        {
          mark_resource (idesc, dep, &specs[count],
@@ -9873,9 +10373,6 @@ md_assemble (str)
            mnemonic = "adds";
          ia64_free_opcode (idesc);
          idesc = ia64_find_opcode (mnemonic);
-#if 0
-         know (!idesc->next);
-#endif
        }
       else if (strcmp (idesc->name, "mov") == 0)
        {
@@ -9890,17 +10387,53 @@ md_assemble (str)
            rop = 1;
          else
            abort ();
-         if (CURR_SLOT.opnd[rop].X_op == O_register
-             && ar_is_in_integer_unit (CURR_SLOT.opnd[rop].X_add_number))
-           mnemonic = "mov.i";
+         if (CURR_SLOT.opnd[rop].X_op == O_register)
+           {
+             if (ar_is_only_in_integer_unit (CURR_SLOT.opnd[rop].X_add_number))
+               mnemonic = "mov.i";
+             else if (ar_is_only_in_memory_unit (CURR_SLOT.opnd[rop].X_add_number))
+               mnemonic = "mov.m";
+             else
+               rop = -1;
+           }
          else
-           mnemonic = "mov.m";
-         ia64_free_opcode (idesc);
-         idesc = ia64_find_opcode (mnemonic);
-         while (idesc != NULL
-                && (idesc->operands[0] != opnd1
-                    || idesc->operands[1] != opnd2))
-           idesc = get_next_opcode (idesc);
+           abort ();
+         if (rop >= 0)
+           {
+             ia64_free_opcode (idesc);
+             idesc = ia64_find_opcode (mnemonic);
+             while (idesc != NULL
+                    && (idesc->operands[0] != opnd1
+                        || idesc->operands[1] != opnd2))
+               idesc = get_next_opcode (idesc);
+           }
+       }
+    }
+  else if (strcmp (idesc->name, "mov.i") == 0
+          || strcmp (idesc->name, "mov.m") == 0)
+    {
+      enum ia64_opnd opnd1, opnd2;
+      int rop;
+      
+      opnd1 = idesc->operands[0];
+      opnd2 = idesc->operands[1];
+      if (opnd1 == IA64_OPND_AR3)
+       rop = 0;
+      else if (opnd2 == IA64_OPND_AR3)
+       rop = 1;
+      else
+       abort ();
+      if (CURR_SLOT.opnd[rop].X_op == O_register)
+       {
+         char unit = 'a';
+         if (ar_is_only_in_integer_unit (CURR_SLOT.opnd[rop].X_add_number))
+           unit = 'i';
+         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",
+                   (int) (CURR_SLOT.opnd[rop].X_add_number - REG_AR),
+                   TOUPPER (unit));
        }
     }
 
@@ -9914,7 +10447,27 @@ md_assemble (str)
   flags = idesc->flags;
 
   if ((flags & IA64_OPCODE_FIRST) != 0)
-    insn_group_break (1, 0, 0);
+    {
+      /* The alignment frag has to end with a stop bit only if the
+        next instruction after the alignment directive has to be
+        the first instruction in an instruction group.  */
+      if (align_frag)
+       {
+         while (align_frag->fr_type != rs_align_code)
+           {
+             align_frag = align_frag->fr_next;
+             if (!align_frag)
+               break;
+           }
+         /* align_frag can be NULL if there are directives in
+            between.  */
+         if (align_frag && align_frag->fr_next == frag_now)
+           align_frag->tc_frag_data = 1;
+       }
+
+      insn_group_break (1, 0, 0);
+    }
+  align_frag = NULL;
 
   if ((flags & IA64_OPCODE_NO_PRED) != 0 && qp_regno != 0)
     {
@@ -9934,6 +10487,8 @@ md_assemble (str)
       CURR_SLOT.unwind_record = unwind.current_entry;
       unwind.current_entry = NULL;
     }
+  if (unwind.proc_start && S_IS_DEFINED (unwind.proc_start))
+    unwind.insn = 1;
 
   /* Check for dependency violations.  */
   if (md.detect_dv)
@@ -9970,104 +10525,14 @@ void
 md_operand (e)
      expressionS *e;
 {
-  enum pseudo_type pseudo_type;
-  const char *name;
-  size_t len;
-  int ch, i;
-
   switch (*input_line_pointer)
     {
-    case '@':
-      /* Find what relocation pseudo-function we're dealing with.  */
-      pseudo_type = 0;
-      ch = *++input_line_pointer;
-      for (i = 0; i < NELEMS (pseudo_func); ++i)
-       if (pseudo_func[i].name && pseudo_func[i].name[0] == ch)
-         {
-           len = strlen (pseudo_func[i].name);
-           if (strncmp (pseudo_func[i].name + 1,
-                        input_line_pointer + 1, len - 1) == 0
-               && !is_part_of_name (input_line_pointer[len]))
-             {
-               input_line_pointer += len;
-               pseudo_type = pseudo_func[i].type;
-               break;
-             }
-         }
-      switch (pseudo_type)
-       {
-       case PSEUDO_FUNC_RELOC:
-         SKIP_WHITESPACE ();
-         if (*input_line_pointer != '(')
-           {
-             as_bad ("Expected '('");
-             goto err;
-           }
-         /* Skip '('.  */
-         ++input_line_pointer;
-         expression (e);
-         if (*input_line_pointer++ != ')')
-           {
-             as_bad ("Missing ')'");
-             goto err;
-           }
-         if (e->X_op != O_symbol)
-           {
-             if (e->X_op != O_pseudo_fixup)
-               {
-                 as_bad ("Not a symbolic expression");
-                 goto err;
-               }
-             if (i != FUNC_LT_RELATIVE)
-               {
-                 as_bad ("Illegal combination of relocation functions");
-                 goto err;
-               }
-             switch (S_GET_VALUE (e->X_op_symbol))
-               {
-               case FUNC_FPTR_RELATIVE:
-                 i = FUNC_LT_FPTR_RELATIVE; break;
-               case FUNC_DTP_MODULE:
-                 i = FUNC_LT_DTP_MODULE; break;
-               case FUNC_DTP_RELATIVE:
-                 i = FUNC_LT_DTP_RELATIVE; break;
-               case FUNC_TP_RELATIVE:
-                 i = FUNC_LT_TP_RELATIVE; break;
-               default:
-                 as_bad ("Illegal combination of relocation functions");
-                 goto err;
-               }
-           }
-         /* Make sure gas doesn't get rid of local symbols that are used
-            in relocs.  */
-         e->X_op = O_pseudo_fixup;
-         e->X_op_symbol = pseudo_func[i].u.sym;
-         break;
-
-       case PSEUDO_FUNC_CONST:
-         e->X_op = O_constant;
-         e->X_add_number = pseudo_func[i].u.ival;
-         break;
-
-       case PSEUDO_FUNC_REG:
-         e->X_op = O_register;
-         e->X_add_number = pseudo_func[i].u.ival;
-         break;
-
-       default:
-         name = input_line_pointer - 1;
-         get_symbol_end ();
-         as_bad ("Unknown pseudo function `%s'", name);
-         goto err;
-       }
-      break;
-
     case '[':
       ++input_line_pointer;
       expression (e);
       if (*input_line_pointer != ']')
        {
-         as_bad ("Closing bracket misssing");
+         as_bad ("Closing bracket missing");
          goto err;
        }
       else
@@ -10273,6 +10738,7 @@ ia64_gen_real_reloc_type (sym, r_type)
      bfd_reloc_code_real_type r_type;
 {
   bfd_reloc_code_real_type new = 0;
+  const char *type = NULL, *suffix = "";
 
   if (sym == NULL)
     {
@@ -10289,7 +10755,7 @@ ia64_gen_real_reloc_type (sym, r_type)
        case BFD_RELOC_IA64_DIR32LSB:   new = BFD_RELOC_IA64_FPTR32LSB; break;
        case BFD_RELOC_IA64_DIR64MSB:   new = BFD_RELOC_IA64_FPTR64MSB; break;
        case BFD_RELOC_IA64_DIR64LSB:   new = BFD_RELOC_IA64_FPTR64LSB; break;
-       default:                        break;
+       default:                        type = "FPTR"; break;
        }
       break;
 
@@ -10302,7 +10768,7 @@ ia64_gen_real_reloc_type (sym, r_type)
        case BFD_RELOC_IA64_DIR32LSB:   new = BFD_RELOC_IA64_GPREL32LSB; break;
        case BFD_RELOC_IA64_DIR64MSB:   new = BFD_RELOC_IA64_GPREL64MSB; break;
        case BFD_RELOC_IA64_DIR64LSB:   new = BFD_RELOC_IA64_GPREL64LSB; break;
-       default:                        break;
+       default:                        type = "GPREL"; break;
        }
       break;
 
@@ -10311,7 +10777,7 @@ ia64_gen_real_reloc_type (sym, r_type)
        {
        case BFD_RELOC_IA64_IMM22:      new = BFD_RELOC_IA64_LTOFF22; break;
        case BFD_RELOC_IA64_IMM64:      new = BFD_RELOC_IA64_LTOFF64I; break;
-       default:                        break;
+       default:                        type = "LTOFF"; break;
        }
       break;
 
@@ -10319,7 +10785,7 @@ ia64_gen_real_reloc_type (sym, r_type)
       switch (r_type)
        {
        case BFD_RELOC_IA64_IMM22:      new = BFD_RELOC_IA64_LTOFF22X; break;
-       default:                        break;
+       default:                        type = "LTOFF"; suffix = "X"; break;
        }
       break;
 
@@ -10332,7 +10798,7 @@ ia64_gen_real_reloc_type (sym, r_type)
        case BFD_RELOC_IA64_DIR32LSB:   new = BFD_RELOC_IA64_PCREL32LSB; break;
        case BFD_RELOC_IA64_DIR64MSB:   new = BFD_RELOC_IA64_PCREL64MSB; break;
        case BFD_RELOC_IA64_DIR64LSB:   new = BFD_RELOC_IA64_PCREL64LSB; break;
-       default:                        break;
+       default:                        type = "PCREL"; break;
        }
       break;
 
@@ -10343,7 +10809,7 @@ ia64_gen_real_reloc_type (sym, r_type)
        case BFD_RELOC_IA64_IMM64:      new = BFD_RELOC_IA64_PLTOFF64I; break;
        case BFD_RELOC_IA64_DIR64MSB:   new = BFD_RELOC_IA64_PLTOFF64MSB;break;
        case BFD_RELOC_IA64_DIR64LSB:   new = BFD_RELOC_IA64_PLTOFF64LSB;break;
-       default:                        break;
+       default:                        type = "PLTOFF"; break;
        }
       break;
 
@@ -10354,7 +10820,7 @@ ia64_gen_real_reloc_type (sym, r_type)
        case BFD_RELOC_IA64_DIR32LSB:   new = BFD_RELOC_IA64_SECREL32LSB;break;
        case BFD_RELOC_IA64_DIR64MSB:   new = BFD_RELOC_IA64_SECREL64MSB;break;
        case BFD_RELOC_IA64_DIR64LSB:   new = BFD_RELOC_IA64_SECREL64LSB;break;
-       default:                        break;
+       default:                        type = "SECREL"; break;
        }
       break;
 
@@ -10365,7 +10831,7 @@ ia64_gen_real_reloc_type (sym, r_type)
        case BFD_RELOC_IA64_DIR32LSB:   new = BFD_RELOC_IA64_SEGREL32LSB;break;
        case BFD_RELOC_IA64_DIR64MSB:   new = BFD_RELOC_IA64_SEGREL64MSB;break;
        case BFD_RELOC_IA64_DIR64LSB:   new = BFD_RELOC_IA64_SEGREL64LSB;break;
-       default:                        break;
+       default:                        type = "SEGREL"; break;
        }
       break;
 
@@ -10376,7 +10842,7 @@ ia64_gen_real_reloc_type (sym, r_type)
        case BFD_RELOC_IA64_DIR32LSB:   new = BFD_RELOC_IA64_LTV32LSB; break;
        case BFD_RELOC_IA64_DIR64MSB:   new = BFD_RELOC_IA64_LTV64MSB; break;
        case BFD_RELOC_IA64_DIR64LSB:   new = BFD_RELOC_IA64_LTV64LSB; break;
-       default:                        break;
+       default:                        type = "LTV"; break;
        }
       break;
 
@@ -10387,22 +10853,28 @@ ia64_gen_real_reloc_type (sym, r_type)
          new = BFD_RELOC_IA64_LTOFF_FPTR22; break;
        case BFD_RELOC_IA64_IMM64:
          new = BFD_RELOC_IA64_LTOFF_FPTR64I; break;
+       case BFD_RELOC_IA64_DIR32MSB:
+         new = BFD_RELOC_IA64_LTOFF_FPTR32MSB; break;
+       case BFD_RELOC_IA64_DIR32LSB:
+         new = BFD_RELOC_IA64_LTOFF_FPTR32LSB; break;
+       case BFD_RELOC_IA64_DIR64MSB:
+         new = BFD_RELOC_IA64_LTOFF_FPTR64MSB; break;
+       case BFD_RELOC_IA64_DIR64LSB:
+         new = BFD_RELOC_IA64_LTOFF_FPTR64LSB; break;
        default:
-         break;
+         type = "LTOFF_FPTR"; break;
        }
       break;
 
     case FUNC_TP_RELATIVE:
       switch (r_type)
        {
-       case BFD_RELOC_IA64_IMM14:
-         new = BFD_RELOC_IA64_TPREL14; break;
-       case BFD_RELOC_IA64_IMM22:
-         new = BFD_RELOC_IA64_TPREL22; break;
-       case BFD_RELOC_IA64_IMM64:
-         new = BFD_RELOC_IA64_TPREL64I; break;
-       default:
-         break;
+       case BFD_RELOC_IA64_IMM14:      new = BFD_RELOC_IA64_TPREL14; break;
+       case BFD_RELOC_IA64_IMM22:      new = BFD_RELOC_IA64_TPREL22; break;
+       case BFD_RELOC_IA64_IMM64:      new = BFD_RELOC_IA64_TPREL64I; break;
+       case BFD_RELOC_IA64_DIR64MSB:   new = BFD_RELOC_IA64_TPREL64MSB; break;
+       case BFD_RELOC_IA64_DIR64LSB:   new = BFD_RELOC_IA64_TPREL64LSB; break;
+       default:                        type = "TPREL"; break;
        }
       break;
 
@@ -10412,7 +10884,19 @@ ia64_gen_real_reloc_type (sym, r_type)
        case BFD_RELOC_IA64_IMM22:
          new = BFD_RELOC_IA64_LTOFF_TPREL22; break;
        default:
-         break;
+         type = "LTOFF_TPREL"; break;
+       }
+      break;
+
+    case FUNC_DTP_MODULE:
+      switch (r_type)
+       {
+       case BFD_RELOC_IA64_DIR64MSB:
+         new = BFD_RELOC_IA64_DTPMOD64MSB; break;
+       case BFD_RELOC_IA64_DIR64LSB:
+         new = BFD_RELOC_IA64_DTPMOD64LSB; break;
+       default:
+         type = "DTPMOD"; break;
        }
       break;
 
@@ -10422,13 +10906,17 @@ ia64_gen_real_reloc_type (sym, r_type)
        case BFD_RELOC_IA64_IMM22:
          new = BFD_RELOC_IA64_LTOFF_DTPMOD22; break;
        default:
-         break;
+         type = "LTOFF_DTPMOD"; break;
        }
       break;
 
     case FUNC_DTP_RELATIVE:
       switch (r_type)
        {
+       case BFD_RELOC_IA64_DIR32MSB:
+         new = BFD_RELOC_IA64_DTPREL32MSB; break;
+       case BFD_RELOC_IA64_DIR32LSB:
+         new = BFD_RELOC_IA64_DTPREL32LSB; break;
        case BFD_RELOC_IA64_DIR64MSB:
          new = BFD_RELOC_IA64_DTPREL64MSB; break;
        case BFD_RELOC_IA64_DIR64LSB:
@@ -10440,7 +10928,7 @@ ia64_gen_real_reloc_type (sym, r_type)
        case BFD_RELOC_IA64_IMM64:
          new = BFD_RELOC_IA64_DTPREL64I; break;
        default:
-         break;
+         type = "DTPREL"; break;
        }
       break;
 
@@ -10450,22 +10938,48 @@ ia64_gen_real_reloc_type (sym, r_type)
        case BFD_RELOC_IA64_IMM22:
          new = BFD_RELOC_IA64_LTOFF_DTPREL22; break;
        default:
-         break;
+         type = "LTOFF_DTPREL"; break;
        }
       break;
 
     case FUNC_IPLT_RELOC:
+      switch (r_type)
+       {
+       case BFD_RELOC_IA64_IPLTMSB:    return r_type;
+       case BFD_RELOC_IA64_IPLTLSB:    return r_type;
+       default:                        type = "IPLT"; break;
+       }
       break;
 
     default:
       abort ();
     }
 
-  /* Hmmmm.  Should this ever occur?  */
   if (new)
     return new;
   else
-    return r_type;
+    {
+      int width;
+
+      if (!type)
+       abort ();
+      switch (r_type)
+       {
+       case BFD_RELOC_IA64_DIR32MSB: width = 32; suffix = "MSB"; break;
+       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_IA64_IMM14:    width = 14; break;
+       case BFD_RELOC_IA64_IMM22:    width = 22; break;
+       case BFD_RELOC_IA64_IMM64:    width = 64; suffix = "I"; break;
+       default:                      abort ();
+       }
+
+      /* This should be an error, but since previously there wasn't any
+        diagnostic here, dont't make it fail because of this for now.  */
+      as_warn ("Cannot express %s%d%s relocation", type, width, suffix);
+      return r_type;
+    }
 }
 
 /* Here is where generate the appropriate reloc for pseudo relocation
@@ -10747,16 +11261,43 @@ ia64_handle_align (fragp)
   static const unsigned char le_nop[]
     = { 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
        0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00};
+  static const unsigned char le_nop_stop[]
+    = { 0x0d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+       0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00};
 
   int bytes;
   char *p;
+  const unsigned char *nop;
 
   if (fragp->fr_type != rs_align_code)
     return;
 
+  /* Check if this frag has to end with a stop bit.  */
+  nop = fragp->tc_frag_data ? le_nop_stop : le_nop;
+
   bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix;
   p = fragp->fr_literal + fragp->fr_fix;
 
+  /* If no paddings are needed, we check if we need a stop bit.  */ 
+  if (!bytes && fragp->tc_frag_data)
+    {
+      if (fragp->fr_fix < 16)
+#if 1
+       /* FIXME: It won't work with
+          .align 16
+          alloc r32=ar.pfs,1,2,4,0
+        */
+       ;
+#else
+       as_bad_where (fragp->fr_file, fragp->fr_line,
+                     _("Can't add stop bit to mark end of instruction group"));
+#endif
+      else
+       /* Bundles are always in little-endian byte order. Make sure
+          the previous bundle has the stop bit.  */
+       *(p - 16) |= 1;
+    }
+
   /* Make sure we are on a 16-byte boundary, in case someone has been
      putting data into a text section.  */
   if (bytes & 15)
@@ -10769,7 +11310,7 @@ ia64_handle_align (fragp)
     }
 
   /* Instruction bundles are always little-endian.  */
-  memcpy (p, le_nop, 16);
+  memcpy (p, nop, 16);
   fragp->fr_var = 16;
 }
 
@@ -10800,6 +11341,9 @@ ia64_float_to_chars_littleendian (char *lit, LITTLENUM_TYPE *words,
 void
 ia64_elf_section_change_hook  (void)
 {
+  if (elf_section_type (now_seg) == SHT_IA_64_UNWIND
+      && elf_linked_to_section (now_seg) == NULL)
+    elf_linked_to_section (now_seg) = text_section;
   dot_byteorder (-1);
 }
 
@@ -10864,6 +11408,7 @@ dot_alias (int section)
 
   input_line_pointer++;
   *end_name = 0;
+  ia64_canonicalize_symbol_name (name);
 
   /* We call demand_copy_C_string to check if alias string is valid.
      There should be a closing `"' and no `\0' in the string.  */
This page took 0.060181 seconds and 4 git commands to generate.