Line number bug fix patch from David Mosberger.
[deliverable/binutils-gdb.git] / gas / config / tc-ia64.c
index 2a3f15fa16972c1ec845bd1533a64a5457230641..75a84344bd0b328d4063c7e004ceb58ef82f47c9 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
@@ -236,7 +241,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
@@ -571,11 +577,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 +637,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.  */
 
@@ -652,6 +656,8 @@ typedef struct unw_rec_list {
   unwind_record r;
   unsigned long slot_number;
   fragS *slot_frag;
+  unsigned long next_slot_number;
+  fragS *next_slot_frag;
   struct unw_rec_list *next;
 } unw_rec_list;
 
@@ -668,9 +674,6 @@ typedef struct label_prologue_count
 
 static struct
 {
-  unsigned long next_slot_number;
-  fragS *next_slot_frag;
-
   /* Maintain a list of unwind entries for the current function.  */
   unw_rec_list *list;
   unw_rec_list *tail;
@@ -696,13 +699,19 @@ static struct
   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));
@@ -752,6 +761,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));
@@ -823,7 +833,7 @@ static void output_X2_format PARAMS ((vbyte_func, int, int, int, int, int, unsig
 static void output_X3_format PARAMS ((vbyte_func, unw_record_type, int, int, int, unsigned long,
                                      unsigned long));
 static void output_X4_format PARAMS ((vbyte_func, int, int, int, int, int, int, unsigned long));
-static void free_list_records PARAMS ((unw_rec_list *));
+static unw_rec_list *output_endp PARAMS ((void));
 static unw_rec_list *output_prologue PARAMS ((void));
 static unw_rec_list *output_prologue_gr PARAMS ((unsigned int, unsigned int));
 static unw_rec_list *output_body PARAMS ((void));
@@ -898,57 +908,33 @@ static void process_one_record PARAMS ((unw_rec_list *, vbyte_func));
 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 int count_bits PARAMS ((unsigned long));
 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 int output_unw_records PARAMS ((unw_rec_list *, void **));
+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 int 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
@@ -1017,12 +1003,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
 }
@@ -1091,18 +1071,40 @@ ia64_flush_insns ()
   CURR_SLOT.tag_fixups = 0;
 
   /* In case there are unwind directives following the last instruction,
-     resolve those now.  We only handle body and prologue directives here.
-     Give an error for others.  */
+     resolve those now.  We only handle prologue, body, and endp directives
+     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)
+      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;
 
@@ -1112,9 +1114,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;
 
@@ -1710,26 +1711,19 @@ alloc_record (unw_record_type t)
   ptr->next = NULL;
   ptr->slot_number = SLOT_NUM_NOT_SET;
   ptr->r.type = t;
+  ptr->next_slot_number = 0;
+  ptr->next_slot_frag = 0;
   return ptr;
 }
 
-/* This function frees an entire list of record structures.  */
+/* Dummy unwind record used for calculating the length of the last prologue or
+   body region.  */
 
-void
-free_list_records (unw_rec_list *first)
+static unw_rec_list *
+output_endp ()
 {
-  unw_rec_list *ptr;
-  for (ptr = first; ptr != NULL;)
-    {
-      unw_rec_list *tmp = ptr;
-
-      if ((tmp->r.type == prologue || tmp->r.type == prologue_gr)
-         && tmp->r.record.r.mask.i)
-       free (tmp->r.record.r.mask.i);
-
-      ptr = ptr->next;
-      free (tmp);
-    }
+  unw_rec_list *ptr = alloc_record (endp);
+  return ptr;
 }
 
 static unw_rec_list *
@@ -1823,7 +1817,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;
 }
 
@@ -1857,7 +1851,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;
 }
 
@@ -1891,7 +1885,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;
 }
 
@@ -1968,7 +1962,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;
 }
 
@@ -1993,7 +1987,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;
 }
 
@@ -2027,7 +2021,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;
 }
 
@@ -2061,7 +2055,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;
 }
 
@@ -2102,7 +2096,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;
 }
 
@@ -2136,7 +2130,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;
 }
 
@@ -2170,7 +2164,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;
 }
 
@@ -2204,7 +2198,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;
 }
 
@@ -2261,7 +2255,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;
 }
 
@@ -2288,7 +2282,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;
 }
@@ -2352,6 +2346,10 @@ process_one_record (ptr, f)
 
   switch (ptr->r.type)
     {
+      /* This is a dummy record that takes up no space in the output.  */
+    case endp:
+      break;
+
     case gr_mem:
     case fr_mem:
     case br_mem:
@@ -2594,29 +2592,18 @@ set_imask (region, regmask, t, type)
     }
 }
 
-static int
-count_bits (unsigned long mask)
-{
-  int n = 0;
-
-  while (mask)
-    {
-      mask &= mask - 1;
-      ++n;
-    }
-  return n;
-}
-
 /* 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;
 
@@ -2631,6 +2618,46 @@ slot_index (slot_addr, slot_frag, first_addr, first_frag)
     {
       unsigned long start_addr = (unsigned long) &first_frag->fr_literal;
 
+      if (! before_relax)
+       {
+         /* 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
+                            - first_frag->fr_fix) >> 4);
+       }
+      else
+       /* We don't know what the final addresses will be. We try our
+          best to estimate.  */
+       switch (first_frag->fr_type)
+         {
+         default:
+           break;
+
+         case rs_space:
+           as_fatal ("only constant space allocation is supported");
+           break;
+
+         case rs_align:
+         case rs_align_code:
+         case rs_align_test:
+           /* Take alignment into account.  Assume the worst case
+              before relaxation.  */
+           index += 3 * ((1 << first_frag->fr_offset) >> 4);
+           break;
+
+         case rs_org:
+           if (first_frag->fr_symbol)
+             {
+               as_fatal ("only constant offsets are supported");
+               break;
+             }
+         case rs_fill:
+           index += 3 * (first_frag->fr_offset >> 4);
+           break;
+         }
+
       /* Add in the full size of the frag converted to instruction slots.  */
       index += 3 * (first_frag->fr_fix >> 4);
       /* Subtract away the initial part before first_addr.  */
@@ -2660,8 +2687,8 @@ optimize_unw_records (list)
   /* If the only unwind record is ".prologue" or ".prologue" followed
      by ".body", then we can optimize the unwind directives away.  */
   if (list->r.type == prologue
-      && (list->next == NULL
-         || (list->next->r.type == body && list->next->next == NULL)))
+      && (list->next->r.type == endp
+         || (list->next->r.type == body && list->next->next->r.type == endp)))
     return NULL;
 
   return list;
@@ -2673,8 +2700,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;
@@ -2685,7 +2713,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:
@@ -2693,60 +2721,24 @@ fixup_unw_records (list)
        case body:
          {
            unw_rec_list *last;
-           int size, dir_len = 0;
-           unsigned long last_addr;
-           fragS *last_frag;
+           int size;
+           unsigned long last_addr = 0;
+           fragS *last_frag = NULL;
 
            first_addr = ptr->slot_number;
            first_frag = ptr->slot_frag;
-           ptr->slot_number = 0;
            /* Find either the next body/prologue start, or the end of
-              the list, and determine the size of the region.  */
-           last_addr = unwind.next_slot_number;
-           last_frag = unwind.next_slot_frag;
+              the function, and determine the size of the region.  */
            for (last = ptr->next; last != NULL; last = last->next)
              if (last->r.type == prologue || last->r.type == prologue_gr
-                 || last->r.type == body)
+                 || last->r.type == body || last->r.type == endp)
                {
                  last_addr = last->slot_number;
                  last_frag = last->slot_frag;
                  break;
                }
-             else if (!last->next)
-               {
-                 /* In the absence of an explicit .body directive,
-                    the prologue ends after the last instruction
-                    covered by an unwind directive.  */
-                 if (ptr->r.type != body)
-                   {
-                     last_addr = last->slot_number;
-                     last_frag = last->slot_frag;
-                     switch (last->r.type)
-                       {
-                       case frgr_mem:
-                         dir_len = (count_bits (last->r.record.p.frmask)
-                                    + count_bits (last->r.record.p.grmask));
-                         break;
-                       case fr_mem:
-                       case gr_mem:
-                         dir_len += count_bits (last->r.record.p.rmask);
-                         break;
-                       case br_mem:
-                       case br_gr:
-                         dir_len += count_bits (last->r.record.p.brmask);
-                         break;
-                       case gr_gr:
-                         dir_len += count_bits (last->r.record.p.grmask);
-                         break;
-                       default:
-                         dir_len = 1;
-                         break;
-                       }
-                   }
-                 break;
-               }
-           size = (slot_index (last_addr, last_frag, first_addr, first_frag)
-                   + dir_len);
+           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.  */
@@ -2756,7 +2748,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:
@@ -2846,29 +2844,63 @@ fixup_unw_records (list)
     }
 }
 
-/* Helper routine for output_unw_records.  Emits the header for the unwind
-   info.  */
+/* Estimate the size of a frag before relaxing.  We only have one type of frag
+   to handle here, which is the unwind info frag.  */
 
-static int
-setup_unwind_header (int size, unsigned char **mem)
+int
+ia64_estimate_size_before_relax (fragS *frag,
+                                asection *segtype ATTRIBUTE_UNUSED)
 {
-  int x, extra = 0;
-  valueT flag_value;
+  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.  */
-  x = size % md.pointer_size;
-  if (x != 0)
-    extra = md.pointer_size - x;
+  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;
+
+  /* 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);
 
-  /* Add 8 for the header + a pointer for the
-     personality offset.  */
-  *mem = xmalloc (size + extra + 8 + md.pointer_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
+ia64_convert_frag (fragS *frag)
+{
+  unw_rec_list *list;
+  int len, size, pad;
+  valueT flag_value;
 
-  /* Clear the padding area and personality.  */
-  memset (*mem + 8 + size, 0, extra + md.pointer_size);
+  /* ??? This code is identical to ia64_estimate_size_before_relax.  */
+  list = (unw_rec_list *) frag->fr_opcode;
+  fixup_unw_records (list, 0);
 
-  /* Initialize the header area.  */
-  if (unwind.personality_routine)
+  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;
+
+  /* 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);
+
+  /* Initialize the header area. fr_offset is initialized with
+     unwind.personality_routine.  */
+  if (frag->fr_offset)
     {
       if (md.flags & EF_IA_64_ABI64)
        flag_value = (bfd_vma) 3 << 32;
@@ -2879,44 +2911,25 @@ setup_unwind_header (int size, unsigned char **mem)
   else
     flag_value = 0;
 
-  md_number_to_chars (*mem, (((bfd_vma) 1 << 48)     /* Version.  */
-                            | flag_value            /* U & E handler flags.  */
-                            | ((size + extra) / md.pointer_size)), /* Length.  */
-                     8);
-
-  return extra;
-}
-
-/* Generate an unwind image from a record list.  Returns the number of
-   bytes in the resulting image. The memory image itselof is returned
-   in the 'ptr' parameter.  */
-static int
-output_unw_records (list, ptr)
-     unw_rec_list *list;
-     void **ptr;
-{
-  int size, extra;
-  unsigned char *mem;
+ md_number_to_chars (frag->fr_literal,
+                    (((bfd_vma) 1 << 48) /* Version.  */
+                     | flag_value        /* U & E handler flags.  */
+                     | (len / md.pointer_size)), /* Length.  */
+                    8);
 
-  *ptr = NULL;
+  /* Skip the header.  */
+  vbyte_mem_ptr = frag->fr_literal + 8;
+  process_unw_records (list, output_vbyte_mem);
 
-  list = optimize_unw_records (list);
-  fixup_unw_records (list);
-  size = calc_record_size (list);
+  /* Fill the padding bytes with zeros.  */
+  if (pad != 0)
+    md_number_to_chars (frag->fr_literal + len + 8 - md.pointer_size + pad, 0,
+                       md.pointer_size - pad);
 
-  if (size > 0 || unwind.force_unwind_entry)
-    {
-      unwind.force_unwind_entry = 0;
-      extra = setup_unwind_header (size, &mem);
-
-      vbyte_mem_ptr = mem + 8;
-      process_unw_records (list, output_vbyte_mem);
-
-      *ptr = mem;
-
-      size += extra + 8 + md.pointer_size;
-    }
-  return size;
+  frag->fr_fix += size;
+  frag->fr_type = rs_fill;
+  frag->fr_var = 0;
+  frag->fr_offset = 0;
 }
 
 static int
@@ -3004,6 +3017,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;
@@ -3021,6 +3042,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)
@@ -3278,34 +3310,162 @@ dot_restorereg_p (dummy)
   add_unwind_entry (output_spill_reg_p (ab, reg, 0, 0, qp));
 }
 
-static int
-generate_unwind_image (text_name)
-     const char *text_name;
+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)
 {
-  int size;
-  void *unw_rec;
+  /*
+    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 (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.  */
-  size = output_unw_records (unwind.list, &unw_rec);
-  if (size % md.pointer_size != 0)
-    as_bad ("Unwind record is not a multiple of %d bytes.", md.pointer_size);
+  list = optimize_unw_records (unwind.list);
+  fixup_unw_records (list, 1);
+  size = calc_record_size (list);
+
+  if (size > 0 || unwind.force_unwind_entry)
+    {
+      unwind.force_unwind_entry = 0;
+      /* pad to pointer-size boundary.  */
+      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;
+    }
 
   /* If there are unwind records, switch sections, and output the info.  */
   if (size != 0)
     {
-      unsigned char *where;
-      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.  */
@@ -3314,15 +3474,10 @@ generate_unwind_image (text_name)
 
       /* Set expression which points to start of unwind descriptor area.  */
       unwind.info = expr_build_dot ();
-
-      where = (unsigned char *) frag_more (size);
-
-      /* Issue a label for this address, and keep track of it to put it
-        in the unwind section.  */
-
-      /* Copy the information from the unwind record into this section. The
-        data is already in the correct byte order.  */
-      memcpy (where, unw_rec, size);
+      
+      frag_var (rs_machine_dependent, size, size, 0, 0,
+               (offsetT) (long) unwind.personality_routine,
+               (char *) list);
 
       /* Add the personality address to the image.  */
       if (unwind.personality_routine != 0)
@@ -3351,25 +3506,17 @@ generate_unwind_image (text_name)
          unwind.personality_routine = 0;
        }
     }
+  else
+    start_unwind_section (text_seg, SPECIAL_SECTION_UNWIND_INFO, 1);
 
-  free_list_records (unwind.list);
   free_saved_prologue_counts ();
   unwind.list = unwind.tail = unwind.current_entry = NULL;
-
-  return size;
 }
 
 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 = "";
-
   unwind.force_unwind_entry = 1;
 
   /* Remember which segment we're in so we can switch back after .endp */
@@ -3379,7 +3526,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 ();
 }
 
@@ -3574,7 +3721,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
@@ -3606,7 +3753,7 @@ dot_spill (dummy)
 
   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");
@@ -3882,7 +4029,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)
     {
@@ -3977,7 +4124,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)
        {
@@ -4014,7 +4161,6 @@ dot_endp (dummy)
   long where;
   segT saved_seg;
   subsegT saved_subseg;
-  const char *sec_name, *text_name;
   char *name, *p, c;
   symbolS *sym;
 
@@ -4030,64 +4176,18 @@ 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);
 
   /* 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)
     {
       subseg_set (md.last_text_seg, 0);
       unwind.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.  */
@@ -4127,6 +4227,9 @@ dot_endp (dummy)
                            bytes_per_address);
 
     }
+  else
+    start_unwind_section (saved_seg, SPECIAL_SECTION_UNWIND, 1);
+
   subseg_set (saved_seg, saved_subseg);
 
   /* Parse names of main and alternate entry points and set symbol sizes.  */
@@ -4335,8 +4438,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
@@ -4584,6 +4686,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
@@ -4865,6 +4984,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 },
@@ -4925,7 +5045,7 @@ const pseudo_typeS md_pseudo_table[] =
     { "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 },
@@ -4966,6 +5086,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' },
@@ -6032,13 +6154,14 @@ emit_one_bundle ()
   struct ia64_opcode *idesc;
   int end_of_insn_group = 0, user_template = -1;
   int n, i, j, first, curr;
-  unw_rec_list *ptr;
+  unw_rec_list *ptr, *last_ptr, *end_ptr;
   bfd_vma t0 = 0, t1 = 0;
   struct label_fix *lfix;
   struct insn_fix *ifix;
   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);
@@ -6070,24 +6193,53 @@ 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;
   end_of_insn_group = 0;
   for (i = 0; i < 3 && md.num_slots_in_use > 0; ++i)
     {
-      /* Set the slot number for prologue/body records now as those
-        refer to the current point, not the point after the
-        instruction has been issued:  */
-      /* Don't try to delete prologue/body records here, as that will cause
-        them to also be deleted from the master list of unwind records.  */
-      for (ptr = md.slot[curr].unwind_record; ptr; ptr = ptr->next)
-       if (ptr->r.type == prologue || ptr->r.type == prologue_gr
-           || ptr->r.type == body)
-         {
-           ptr->slot_number = (unsigned long) f + i;
-           ptr->slot_frag = frag_now;
-         }
+      /* If we have unwind records, we may need to update some now.  */
+      ptr = md.slot[curr].unwind_record;
+      if (ptr)
+       {
+         /* Find the last prologue/body record in the list for the current
+            insn, and set the slot number for all records up to that point.
+            This needs to be done now, because prologue/body records refer to
+            the current point, not the point after the instruction has been
+            issued.  This matters because there may have been nops emitted
+            meanwhile.  Any non-prologue non-body record followed by a
+            prologue/body record must also refer to the current point.  */
+         last_ptr = NULL;
+         end_ptr = md.slot[(curr + 1) % NUM_SLOTS].unwind_record;
+         for (; ptr != end_ptr; ptr = ptr->next)
+           if (ptr->r.type == prologue || ptr->r.type == prologue_gr
+               || ptr->r.type == body)
+             last_ptr = ptr;
+         if (last_ptr)
+           {
+             /* Make last_ptr point one after the last prologue/body
+                record.  */
+             last_ptr = last_ptr->next;
+             for (ptr = md.slot[curr].unwind_record; ptr != last_ptr;
+                  ptr = ptr->next)
+               {
+                 ptr->slot_number = (unsigned long) f + i;
+                 ptr->slot_frag = frag_now;
+               }
+             /* Remove the initialized records, so that we won't accidentally
+                update them again if we insert a nop and continue.  */
+             md.slot[curr].unwind_record = last_ptr;
+           }
+       }
 
       if (idesc->flags & IA64_OPCODE_SLOT2)
        {
@@ -6280,27 +6432,33 @@ emit_one_bundle ()
          continue;             /* try next slot */
        }
 
-      {
-       bfd_vma addr;
+      if (debug_type == DEBUG_DWARF2 || md.slot[curr].loc_directive_seen)
+       {
+         bfd_vma addr = frag_now->fr_address + frag_now_fix () - 16 + i;
 
-       addr = frag_now->fr_address + frag_now_fix () - 16 + i;
-       dwarf2_gen_line_info (addr, &md.slot[curr].debug_line);
-      }
+         md.slot[curr].loc_directive_seen = 0;
+         dwarf2_gen_line_info (addr, &md.slot[curr].debug_line);
+       }
 
       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"));
 
       build_insn (md.slot + curr, insn + i);
 
-      /* Set slot counts for non prologue/body unwind records.  */
-      for (ptr = md.slot[curr].unwind_record; ptr; ptr = ptr->next)
-       if (ptr->r.type != prologue && ptr->r.type != prologue_gr
-           && ptr->r.type != body)
-         {
-           ptr->slot_number = (unsigned long) f + i;
-           ptr->slot_frag = frag_now;
-         }
-      md.slot[curr].unwind_record = NULL;
+      ptr = md.slot[curr].unwind_record;
+      if (ptr)
+       {
+         /* Set slot numbers for all remaining unwind records belonging to the
+            current insn.  There can not be any prologue/body unwind records
+            here.  */
+         end_ptr = md.slot[(curr + 1) % NUM_SLOTS].unwind_record;
+         for (; ptr != end_ptr; ptr = ptr->next)
+           {
+             ptr->slot_number = (unsigned long) f + i;
+             ptr->slot_frag = frag_now;
+           }
+         md.slot[curr].unwind_record = NULL;
+       }
 
       if (required_unit == IA64_UNIT_L)
        {
@@ -6358,9 +6516,12 @@ emit_one_bundle ()
   if (manual_bundling)
     {
       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");
@@ -6373,8 +6534,11 @@ emit_one_bundle ()
   number_to_chars_littleendian (f + 0, t0, 8);
   number_to_chars_littleendian (f + 8, t1, 8);
 
-  unwind.next_slot_number = (unsigned long) f + 16;
-  unwind.next_slot_frag = frag_now;
+  if (unwind.list)
+    {
+      unwind.list->next_slot_number = (unsigned long) f + 16;
+      unwind.list->next_slot_frag = frag_now;
+    }
 }
 
 int
@@ -6400,10 +6564,12 @@ 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
        return 0;
@@ -6576,7 +6742,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 ();
@@ -7115,6 +7281,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 ()
 {
@@ -9424,17 +9607,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;
@@ -9447,17 +9628,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:
@@ -9888,11 +10067,15 @@ 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
+               mnemonic = "mov.m";
+           }
          else
-           mnemonic = "mov.m";
+           abort ();
          ia64_free_opcode (idesc);
          idesc = ia64_find_opcode (mnemonic);
          while (idesc != NULL
@@ -9901,6 +10084,33 @@ md_assemble (str)
            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));
+       }
+    }
 
   qp_regno = 0;
   if (md.qp.X_op == O_register)
@@ -9912,7 +10122,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)
     {
@@ -10745,16 +10975,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)
@@ -10767,7 +11024,7 @@ ia64_handle_align (fragp)
     }
 
   /* Instruction bundles are always little-endian.  */
-  memcpy (p, le_nop, 16);
+  memcpy (p, nop, 16);
   fragp->fr_var = 16;
 }
 
@@ -10798,6 +11055,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);
 }
 
This page took 0.053412 seconds and 4 git commands to generate.