2003-08-24 Jason Eckhardt <jle@rice.edu>
[deliverable/binutils-gdb.git] / gas / config / tc-ia64.c
index b9050951f969102055f0fb60ea561b39deb415e6..24e33c0662648347dae5c46e5274cfb78ee2a4c9 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-ia64.c -- Assembler for the HP/Intel IA-64 architecture.
-   Copyright (C) 1998, 1999, 2000 Free Software Foundation.
+   Copyright 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
    Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
 
    This file is part of GAS, the GNU Assembler.
@@ -24,7 +24,6 @@
 
   - optional operands
   - directives:
-       .alias
        .eb
        .estate
        .lb
@@ -43,6 +42,7 @@
  */
 
 #include "as.h"
+#include "safe-ctype.h"
 #include "dwarf2dbg.h"
 #include "subsegs.h"
 
 
 enum special_section
   {
+    /* IA-64 ABI section pseudo-ops.  */
     SPECIAL_SECTION_BSS = 0,
     SPECIAL_SECTION_SBSS,
     SPECIAL_SECTION_SDATA,
     SPECIAL_SECTION_RODATA,
     SPECIAL_SECTION_COMMENT,
     SPECIAL_SECTION_UNWIND,
-    SPECIAL_SECTION_UNWIND_INFO
+    SPECIAL_SECTION_UNWIND_INFO,
+    /* HPUX specific section pseudo-ops.  */
+    SPECIAL_SECTION_INIT_ARRAY,
+    SPECIAL_SECTION_FINI_ARRAY,
   };
 
 enum reloc_func
   {
+    FUNC_DTP_MODULE,
+    FUNC_DTP_RELATIVE,
     FUNC_FPTR_RELATIVE,
     FUNC_GP_RELATIVE,
     FUNC_LT_RELATIVE,
+    FUNC_LT_RELATIVE_X,
     FUNC_PC_RELATIVE,
     FUNC_PLT_RELATIVE,
     FUNC_SEC_RELATIVE,
     FUNC_SEG_RELATIVE,
+    FUNC_TP_RELATIVE,
     FUNC_LTV_RELATIVE,
     FUNC_LT_FPTR_RELATIVE,
+    FUNC_LT_DTP_MODULE,
+    FUNC_LT_DTP_RELATIVE,
+    FUNC_LT_TP_RELATIVE,
+    FUNC_IPLT_RELOC,
   };
 
 enum reg_symbol
@@ -124,6 +136,13 @@ enum dynreg_type
     DYNREG_NUM_TYPES
   };
 
+enum operand_match_result
+  {
+    OPERAND_MATCH,
+    OPERAND_OUT_OF_RANGE,
+    OPERAND_MISMATCH
+  };
+
 /* On the ia64, we can't know the address of a text label until the
    instructions are packed into a bundle.  To handle this, we keep
    track of the list of labels that appear in front of each
@@ -136,6 +155,20 @@ struct label_fix
 
 extern int target_big_endian;
 
+void (*ia64_number_to_chars) PARAMS ((char *, valueT, int));
+
+static void ia64_float_to_chars_bigendian
+  PARAMS ((char *, LITTLENUM_TYPE *, int));
+static void ia64_float_to_chars_littleendian
+  PARAMS ((char *, LITTLENUM_TYPE *, int));
+static void (*ia64_float_to_chars)
+  PARAMS ((char *, LITTLENUM_TYPE *, int));
+
+static struct hash_control *alias_hash;
+static struct hash_control *alias_name_hash;
+static struct hash_control *secalias_hash;
+static struct hash_control *secalias_name_hash;
+
 /* Characters which always start a comment.  */
 const char comment_chars[] = "";
 
@@ -190,7 +223,8 @@ static struct
       explicit_mode : 1,            /* which mode we're in */
       default_explicit_mode : 1,    /* which mode is the default */
       mode_explicitly_set : 1,      /* was the current mode explicitly set? */
-      auto_align : 1;
+      auto_align : 1,
+      keep_pending_output : 1;
 
     /* Each bundle consists of up to three instructions.  We keep
        track of four most recent instructions so we can correctly set
@@ -271,6 +305,9 @@ static struct
       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 */
   }
 md;
 
@@ -459,15 +496,23 @@ static struct
 pseudo_func[] =
   {
     /* reloc pseudo functions (these must come first!):  */
+    { "dtpmod",        PSEUDO_FUNC_RELOC, { 0 } },
+    { "dtprel",        PSEUDO_FUNC_RELOC, { 0 } },
     { "fptr",  PSEUDO_FUNC_RELOC, { 0 } },
     { "gprel", PSEUDO_FUNC_RELOC, { 0 } },
     { "ltoff", PSEUDO_FUNC_RELOC, { 0 } },
+    { "ltoffx",        PSEUDO_FUNC_RELOC, { 0 } },
     { "pcrel", PSEUDO_FUNC_RELOC, { 0 } },
     { "pltoff",        PSEUDO_FUNC_RELOC, { 0 } },
     { "secrel",        PSEUDO_FUNC_RELOC, { 0 } },
     { "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 */
+    { "iplt",  PSEUDO_FUNC_RELOC, { 0 } },
 
     /* mbtype4 constants:  */
     { "alt",   PSEUDO_FUNC_CONST, { 0xa } },
@@ -489,10 +534,17 @@ pseudo_func[] =
 
     { "natval",        PSEUDO_FUNC_CONST, { 0x100 } }, /* old usage */
 
+    /* hint constants: */
+    { "pause", PSEUDO_FUNC_CONST, { 0x0 } },
+
     /* unwind-related constants:  */
-    { "svr4",  PSEUDO_FUNC_CONST, { 0 } },
-    { "hpux",  PSEUDO_FUNC_CONST, { 1 } },
-    { "nt",    PSEUDO_FUNC_CONST, { 2 } },
+    { "svr4",  PSEUDO_FUNC_CONST,      { ELFOSABI_NONE } },
+    { "hpux",  PSEUDO_FUNC_CONST,      { ELFOSABI_HPUX } },
+    { "nt",    PSEUDO_FUNC_CONST,      { 2 } },                /* conflicts w/ELFOSABI_NETBSD */
+    { "linux", PSEUDO_FUNC_CONST,      { ELFOSABI_LINUX } },
+    { "freebsd", PSEUDO_FUNC_CONST,    { ELFOSABI_FREEBSD } },
+    { "openvms", PSEUDO_FUNC_CONST,    { ELFOSABI_OPENVMS } },
+    { "nsk",   PSEUDO_FUNC_CONST,      { ELFOSABI_NSK } },
 
     /* unwind-related registers:  */
     { "priunat",PSEUDO_FUNC_REG, { REG_PRIUNAT } }
@@ -515,7 +567,13 @@ static const bfd_vma nop[IA64_NUM_UNITS] =
 static char special_section_name[][20] =
   {
     {".bss"}, {".sbss"}, {".sdata"}, {".rodata"}, {".comment"},
-    {".IA_64.unwind"}, {".IA_64.unwind_info"}
+    {".IA_64.unwind"}, {".IA_64.unwind_info"},
+    {".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
@@ -599,6 +657,15 @@ typedef struct unw_rec_list {
 
 #define SLOT_NUM_NOT_SET        (unsigned)-1
 
+/* Linked list of saved prologue counts.  A very poor
+   implementation of a map from label numbers to prologue counts.  */
+typedef struct label_prologue_count
+{
+  struct label_prologue_count *next;
+  unsigned long label_number;
+  unsigned int prologue_count;
+} label_prologue_count;
+
 static struct
 {
   unsigned long next_slot_number;
@@ -617,10 +684,16 @@ static struct
   symbolS *proc_end;
   symbolS *info;               /* pointer to unwind info */
   symbolS *personality_routine;
+  segT saved_text_seg;
+  subsegT saved_text_subseg;
+  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_count; /* number of .prologues seen so far */
+  /* Prologue counts at previous .label_state directives.  */
+  struct label_prologue_count * saved_prologue_counts;
 } unwind;
 
 typedef void (*vbyte_func) PARAMS ((int, char *, char *));
@@ -686,10 +759,12 @@ static void add_unwind_entry PARAMS((unw_rec_list *ptr));
 static symbolS *declare_register PARAMS ((const char *name, int regnum));
 static void declare_register_set PARAMS ((const char *, int, int));
 static unsigned int operand_width PARAMS ((enum ia64_opnd));
-static int operand_match PARAMS ((const struct ia64_opcode *idesc,
-                                 int index, expressionS *e));
+static enum operand_match_result operand_match PARAMS ((const struct ia64_opcode *idesc,
+                                                       int index,
+                                                       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));
@@ -703,6 +778,7 @@ static void add_qp_imply PARAMS((int p1, int p2));
 static void clear_qp_branch_flag PARAMS((valueT mask));
 static void clear_qp_mutex PARAMS((valueT mask));
 static void clear_qp_implies PARAMS((valueT p1_mask, valueT p2_mask));
+static int has_suffix_p PARAMS((const char *, const char *));
 static void clear_register_values PARAMS ((void));
 static void print_dependency PARAMS ((const char *action, int depind));
 static void instruction_serialization PARAMS ((void));
@@ -825,11 +901,40 @@ static void set_imask PARAMS ((unw_rec_list *, unsigned long, unsigned long, uns
 static int count_bits PARAMS ((unsigned long));
 static unsigned long slot_index PARAMS ((unsigned long, fragS *,
                                         unsigned long, fragS *));
+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 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 ((void));
+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
    unit (as opposed to the memory unit).  */
@@ -862,6 +967,22 @@ set_section (name)
   input_line_pointer = saved_input_line_pointer;
 }
 
+/* Map 's' to SHF_IA_64_SHORT.  */
+
+int
+ia64_elf_section_letter (letter, ptr_msg)
+     int letter;
+     char **ptr_msg;
+{
+  if (letter == 's')
+    return SHF_IA_64_SHORT;
+  else if (letter == 'o')
+    return SHF_LINK_ORDER;
+
+  *ptr_msg = _("Bad .section directive: want a,o,s,w,x,M,S,G,T in string");
+  return -1;
+}
+
 /* Map SHF_IA_64_SHORT to SEC_SMALL_DATA.  */
 
 flagword
@@ -874,6 +995,38 @@ ia64_elf_section_flags (flags, attr, type)
   return flags;
 }
 
+int
+ia64_elf_section_type (str, len)
+     const char *str;
+     size_t len;
+{
+#define STREQ(s) ((len == sizeof (s) - 1) && (strncmp (str, s, sizeof (s) - 1) == 0))
+
+  if (STREQ (ELF_STRING_ia64_unwind_info))
+    return SHT_PROGBITS;
+
+  if (STREQ (ELF_STRING_ia64_unwind_info_once))
+    return SHT_PROGBITS;
+
+  if (STREQ (ELF_STRING_ia64_unwind))
+    return SHT_IA_64_UNWIND;
+
+  if (STREQ (ELF_STRING_ia64_unwind_once))
+    return SHT_IA_64_UNWIND;
+
+  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
+}
+
 static unsigned int
 set_regstack (ins, locs, outs, rots)
      unsigned int ins, locs, outs, rots;
@@ -2495,6 +2648,25 @@ slot_index (slot_addr, slot_frag, first_addr, first_frag)
   return index;
 }
 
+/* Optimize unwind record directives.  */
+
+static unw_rec_list *
+optimize_unw_records (list)
+     unw_rec_list *list;
+{
+  if (!list)
+    return NULL;
+
+  /* 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)))
+    return NULL;
+
+  return list;
+}
+
 /* Given a complete record list, process any records which have
    unresolved fields, (ie length counts for a prologue).  After
    this has been run, all neccessary information should be available
@@ -2576,7 +2748,11 @@ fixup_unw_records (list)
            size = (slot_index (last_addr, last_frag, first_addr, first_frag)
                    + dir_len);
            rlen = ptr->r.record.r.rlen = size;
-           region = ptr;
+           if (ptr->r.type == body)
+             /* End of region.  */
+             region = 0;
+           else
+             region = ptr;
            break;
          }
        case epilogue:
@@ -2670,6 +2846,47 @@ fixup_unw_records (list)
     }
 }
 
+/* Helper routine for output_unw_records.  Emits the header for the unwind
+   info.  */
+
+static int
+setup_unwind_header (int size, unsigned char **mem)
+{
+  int x, extra = 0;
+  valueT flag_value;
+
+  /* pad to pointer-size boundry.  */
+  x = size % md.pointer_size;
+  if (x != 0)
+    extra = md.pointer_size - x;
+
+  /* Add 8 for the header + a pointer for the
+     personality offset.  */
+  *mem = xmalloc (size + extra + 8 + md.pointer_size);
+
+  /* Clear the padding area and personality.  */
+  memset (*mem + 8 + size, 0, extra + md.pointer_size);
+
+  /* Initialize the header area.  */
+  if (unwind.personality_routine)
+    {
+      if (md.flags & EF_IA_64_ABI64)
+       flag_value = (bfd_vma) 3 << 32;
+      else
+       /* 32-bit unwind info block.  */
+       flag_value = (bfd_vma) 0x1003 << 32;
+    }
+  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.  */
@@ -2678,34 +2895,28 @@ output_unw_records (list, ptr)
      unw_rec_list *list;
      void **ptr;
 {
-  int size, x, extra = 0;
+  int size, extra;
   unsigned char *mem;
 
+  *ptr = NULL;
+
+  list = optimize_unw_records (list);
   fixup_unw_records (list);
   size = calc_record_size (list);
 
-  /* pad to 8 byte boundry.  */
-  x = size % 8;
-  if (x != 0)
-    extra = 8 - x;
-  /* Add 8 for the header + 8 more bytes for the personality offset.  */
-  mem = xmalloc (size + extra + 16);
+  if (size > 0 || unwind.force_unwind_entry)
+    {
+      unwind.force_unwind_entry = 0;
+      extra = setup_unwind_header (size, &mem);
 
-  vbyte_mem_ptr = mem + 8;
-  /* Clear the padding area and personality.  */
-  memset (mem + 8 + size, 0 , extra + 8);
-  /* Initialize the header area.  */
-  md_number_to_chars (mem, (((bfd_vma) 1 << 48)     /* version */
-                           | (unwind.personality_routine
-                              ? ((bfd_vma) 3 << 32) /* U & E handler flags */
-                              : 0)
-                           | ((size + extra) / 8)),  /* length (dwords) */
-                     8);
+      vbyte_mem_ptr = mem + 8;
+      process_unw_records (list, output_vbyte_mem);
 
-  process_unw_records (list, output_vbyte_mem);
+      *ptr = mem;
 
-  *ptr = mem;
-  return size + extra + 16;
+      size += extra + 8 + md.pointer_size;
+    }
+  return size;
 }
 
 static int
@@ -2879,7 +3090,7 @@ dot_vframesp (dummy)
       add_unwind_entry (output_psp_sprel (e.X_add_number));
     }
   else
-    as_bad ("First operand to .vframesp must be a general register");
+    as_bad ("Operand to .vframesp must be a constant (sp-relative offset)");
 }
 
 static void
@@ -2895,7 +3106,7 @@ dot_vframepsp (dummy)
       add_unwind_entry (output_psp_sprel (e.X_add_number));
     }
   else
-    as_bad ("First operand to .vframepsp must be a general register");
+    as_bad ("Operand to .vframepsp must be a constant (psp-relative offset)");
 }
 
 static void
@@ -2980,7 +3191,7 @@ dot_restore (dummy)
      int dummy ATTRIBUTE_UNUSED;
 {
   expressionS e1, e2;
-  unsigned long ecount = 0;
+  unsigned long ecount;        /* # of _additional_ regions to pop */
   int sep;
 
   sep = parse_operand (&e1);
@@ -2993,14 +3204,29 @@ dot_restore (dummy)
   if (sep == ',')
     {
       parse_operand (&e2);
-      if (e1.X_op != O_constant)
+      if (e2.X_op != O_constant || e2.X_add_number < 0)
        {
-         as_bad ("Second operand to .restore must be constant");
+         as_bad ("Second operand to .restore must be a constant >= 0");
          return;
        }
-      ecount = e1.X_op;
+      ecount = e2.X_add_number;
+    }
+  else
+    ecount = unwind.prologue_count - 1;
+
+  if (ecount >= unwind.prologue_count)
+    {
+      as_bad ("Epilogue count of %lu exceeds number of nested prologues (%u)",
+             ecount + 1, unwind.prologue_count);
+      return;
     }
+
   add_unwind_entry (output_epilogue (ecount));
+
+  if (ecount < unwind.prologue_count)
+    unwind.prologue_count -= ecount + 1;
+  else
+    unwind.prologue_count = 0;
 }
 
 static void
@@ -3053,29 +3279,38 @@ dot_restorereg_p (dummy)
 }
 
 static int
-generate_unwind_image ()
+generate_unwind_image (text_name)
+     const char *text_name;
 {
   int size;
-  unsigned char *unw_rec;
+  void *unw_rec;
 
   /* 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, (void **) &unw_rec);
-  if (size % 8 != 0)
-    as_bad ("Unwind record is not a multiple of 8 bytes.");
+  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);
 
   /* If there are unwind records, switch sections, and output the info.  */
   if (size != 0)
     {
       unsigned char *where;
+      char *sec_name;
       expressionS exp;
-      set_section ((char *) special_section_name[SPECIAL_SECTION_UNWIND_INFO]);
+      bfd_reloc_code_real_type reloc;
 
-      /* Make sure the section has 8 byte alignment.  */
-      record_alignment (now_seg, 3);
+      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);
+
+      /* Make sure the section has 4 byte alignment for ILP32 and
+        8 byte alignment for LP64.  */
+      frag_align (md.pointer_size_shift, 0, 0);
+      record_alignment (now_seg, md.pointer_size_shift);
 
       /* Set expression which points to start of unwind descriptor area.  */
       unwind.info = expr_build_dot ();
@@ -3088,20 +3323,37 @@ generate_unwind_image ()
       /* Copy the information from the unwind record into this section. The
         data is already in the correct byte order.  */
       memcpy (where, unw_rec, size);
+
       /* Add the personality address to the image.  */
       if (unwind.personality_routine != 0)
        {
-         exp.X_op  = O_symbol;
+         exp.X_op = O_symbol;
          exp.X_add_symbol = unwind.personality_routine;
          exp.X_add_number = 0;
-         fix_new_exp (frag_now, frag_now_fix () - 8, 8,
-                            &exp, 0, BFD_RELOC_IA64_LTOFF_FPTR64LSB);
+
+         if (md.flags & EF_IA_64_BE)
+           {
+             if (md.flags & EF_IA_64_ABI64)
+               reloc = BFD_RELOC_IA64_LTOFF_FPTR64MSB;
+             else
+               reloc = BFD_RELOC_IA64_LTOFF_FPTR32MSB;
+           }
+         else
+           {
+             if (md.flags & EF_IA_64_ABI64)
+               reloc = BFD_RELOC_IA64_LTOFF_FPTR64LSB;
+             else
+               reloc = BFD_RELOC_IA64_LTOFF_FPTR32LSB;
+           }
+
+         fix_new_exp (frag_now, frag_now_fix () - md.pointer_size,
+                      md.pointer_size, &exp, 0, reloc);
          unwind.personality_routine = 0;
        }
-      obj_elf_previous (0);
     }
 
   free_list_records (unwind.list);
+  free_saved_prologue_counts ();
   unwind.list = unwind.tail = unwind.current_entry = NULL;
 
   return size;
@@ -3111,7 +3363,23 @@ static void
 dot_handlerdata (dummy)
      int dummy ATTRIBUTE_UNUSED;
 {
-  generate_unwind_image ();
+  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 */
+  unwind.saved_text_seg = now_seg;
+  unwind.saved_text_subseg = now_subseg;
+
+  /* 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);
   demand_empty_rest_of_line ();
 }
 
@@ -3119,6 +3387,7 @@ static void
 dot_unwentry (dummy)
      int dummy ATTRIBUTE_UNUSED;
 {
+  unwind.force_unwind_entry = 1;
   demand_empty_rest_of_line ();
 }
 
@@ -3506,9 +3775,64 @@ dot_spillmem_p (psprel)
     }
 
   if (psprel)
-    add_unwind_entry (output_spill_psprel_p (qp, ab, reg, e3.X_add_number));
+    add_unwind_entry (output_spill_psprel_p (ab, reg, e3.X_add_number, qp));
+  else
+    add_unwind_entry (output_spill_sprel_p (ab, reg, e3.X_add_number, qp));
+}
+
+static unsigned int
+get_saved_prologue_count (lbl)
+     unsigned long lbl;
+{
+  label_prologue_count *lpc = unwind.saved_prologue_counts;
+
+  while (lpc != NULL && lpc->label_number != lbl)
+    lpc = lpc->next;
+
+  if (lpc != NULL)
+    return lpc->prologue_count;
+
+  as_bad ("Missing .label_state %ld", lbl);
+  return 1;
+}
+
+static void
+save_prologue_count (lbl, count)
+     unsigned long lbl;
+     unsigned int count;
+{
+  label_prologue_count *lpc = unwind.saved_prologue_counts;
+
+  while (lpc != NULL && lpc->label_number != lbl)
+    lpc = lpc->next;
+
+  if (lpc != NULL)
+    lpc->prologue_count = count;
   else
-    add_unwind_entry (output_spill_sprel_p (qp, ab, reg, e3.X_add_number));
+    {
+      label_prologue_count *new_lpc = xmalloc (sizeof (* new_lpc));
+
+      new_lpc->next = unwind.saved_prologue_counts;
+      new_lpc->label_number = lbl;
+      new_lpc->prologue_count = count;
+      unwind.saved_prologue_counts = new_lpc;
+    }
+}
+
+static void
+free_saved_prologue_counts ()
+{
+  label_prologue_count *lpc = unwind.saved_prologue_counts;
+  label_prologue_count *next;
+
+  while (lpc != NULL)
+    {
+      next = lpc->next;
+      free (lpc);
+      lpc = next;
+    }
+
+  unwind.saved_prologue_counts = NULL;
 }
 
 static void
@@ -3524,6 +3848,7 @@ dot_label_state (dummy)
       return;
     }
   add_unwind_entry (output_label_state (e.X_add_number));
+  save_prologue_count (e.X_add_number, unwind.prologue_count);
 }
 
 static void
@@ -3539,6 +3864,7 @@ dot_copy_state (dummy)
       return;
     }
   add_unwind_entry (output_copy_state (e.X_add_number));
+  unwind.prologue_count = get_saved_prologue_count (e.X_add_number);
 }
 
 static void
@@ -3583,6 +3909,7 @@ dot_personality (dummy)
   c = get_symbol_end ();
   p = input_line_pointer;
   unwind.personality_routine = symbol_find_or_make (name);
+  unwind.force_unwind_entry = 1;
   *p = c;
   SKIP_WHITESPACE ();
   demand_empty_rest_of_line ();
@@ -3619,6 +3946,7 @@ dot_proc (dummy)
   demand_empty_rest_of_line ();
   ia64_do_align (16);
 
+  unwind.prologue_count = 0;
   unwind.list = unwind.tail = unwind.current_entry = NULL;
   unwind.personality_routine = 0;
 }
@@ -3673,6 +4001,7 @@ dot_prologue (dummy)
 
   unwind.prologue = 1;
   unwind.prologue_mask = mask;
+  ++unwind.prologue_count;
 }
 
 static void
@@ -3685,58 +4014,164 @@ dot_endp (dummy)
   long where;
   segT saved_seg;
   subsegT saved_subseg;
+  const char *sec_name, *text_name;
+  char *name, *p, c;
+  symbolS *sym;
 
-  saved_seg = now_seg;
-  saved_subseg = now_subseg;
-
-  expression (&e);
-  demand_empty_rest_of_line ();
-
-  insn_group_break (1, 0, 0);
-
-  /* If there was a .handlerdata, we haven't generated an image yet.  */
-  if (unwind.info == 0)
+  if (unwind.saved_text_seg)
+    {
+      saved_seg = unwind.saved_text_seg;
+      saved_subseg = unwind.saved_text_subseg;
+      unwind.saved_text_seg = NULL;
+    }
+  else
     {
-      generate_unwind_image ();
+      saved_seg = now_seg;
+      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 = "";
 
-  subseg_set (md.last_text_seg, 0);
-  unwind.proc_end = expr_build_dot ();
+  insn_group_break (1, 0, 0);
 
-  set_section ((char *) special_section_name[SPECIAL_SECTION_UNWIND]);
+  /* If there wasn't a .handlerdata, we haven't generated an image yet.  */
+  if (!unwind.info)
+    generate_unwind_image (text_name);
 
-  /* Make sure the section has 8 byte alignment.  */
-  record_alignment (now_seg, 3);
+  if (unwind.info || unwind.force_unwind_entry)
+    {
+      subseg_set (md.last_text_seg, 0);
+      unwind.proc_end = expr_build_dot ();
 
-  ptr = frag_more (24);
-  where = frag_now_fix () - 24;
-  bytes_per_address = bfd_arch_bits_per_address (stdoutput) / 8;
+      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);
 
-  /* Issue the values of  a) Proc Begin,  b) Proc End,  c) Unwind Record.  */
-  e.X_op = O_pseudo_fixup;
-  e.X_op_symbol = pseudo_func[FUNC_SEG_RELATIVE].u.sym;
-  e.X_add_number = 0;
-  e.X_add_symbol = unwind.proc_start;
-  ia64_cons_fix_new (frag_now, where, bytes_per_address, &e);
+      /* Make sure that section has 4 byte alignment for ILP32 and
+         8 byte alignment for LP64.  */
+      record_alignment (now_seg, md.pointer_size_shift);
 
-  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;
-  ia64_cons_fix_new (frag_now, where + bytes_per_address, bytes_per_address, &e);
+      /* Need space for 3 pointers for procedure start, procedure end,
+        and unwind info.  */
+      ptr = frag_more (3 * md.pointer_size);
+      where = frag_now_fix () - (3 * md.pointer_size);
+      bytes_per_address = bfd_arch_bits_per_address (stdoutput) / 8;
 
-  if (unwind.info != 0)
-    {
+      /* Issue the values of  a) Proc Begin, b) Proc End, c) Unwind Record.  */
       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.info;
-      ia64_cons_fix_new (frag_now, where + (bytes_per_address * 2), bytes_per_address, &e);
-    }
-  else
-    md_number_to_chars (ptr + (bytes_per_address * 2), 0, bytes_per_address);
+      e.X_add_symbol = unwind.proc_start;
+      ia64_cons_fix_new (frag_now, where, bytes_per_address, &e);
+
+      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;
+      ia64_cons_fix_new (frag_now, where + bytes_per_address,
+                        bytes_per_address, &e);
+
+      if (unwind.info)
+       {
+         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.info;
+         ia64_cons_fix_new (frag_now, where + (bytes_per_address * 2),
+                            bytes_per_address, &e);
+       }
+      else
+       md_number_to_chars (ptr + (bytes_per_address * 2), 0,
+                           bytes_per_address);
 
+    }
   subseg_set (saved_seg, saved_subseg);
+
+  /* Parse names of main and alternate entry points and set symbol sizes.  */
+  while (1)
+    {
+      SKIP_WHITESPACE ();
+      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));
+             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;
+               }
+           }
+       }
+      *p = c;
+      SKIP_WHITESPACE ();
+      if (*input_line_pointer != ',')
+       break;
+      ++input_line_pointer;
+    }
+  demand_empty_rest_of_line ();
   unwind.proc_start = unwind.proc_end = unwind.info = 0;
 }
 
@@ -3895,7 +4330,32 @@ static void
 dot_byteorder (byteorder)
      int byteorder;
 {
-  target_big_endian = byteorder;
+  segment_info_type *seginfo = seg_info (now_seg);
+
+  if (byteorder == -1)
+    {
+      if (seginfo->tc_segment_info_data.endian == 0)
+       seginfo->tc_segment_info_data.endian
+         = TARGET_BYTES_BIG_ENDIAN ? 1 : 2;
+      byteorder = seginfo->tc_segment_info_data.endian == 1;
+    }
+  else
+    seginfo->tc_segment_info_data.endian = byteorder ? 1 : 2;
+
+  if (target_big_endian != byteorder)
+    {
+      target_big_endian = byteorder;
+      if (target_big_endian)
+       {
+         ia64_number_to_chars = number_to_chars_bigendian;
+         ia64_float_to_chars = ia64_float_to_chars_bigendian;
+       }
+      else
+       {
+         ia64_number_to_chars = number_to_chars_littleendian;
+         ia64_float_to_chars = ia64_float_to_chars_littleendian;
+       }
+    }
 }
 
 static void
@@ -3931,13 +4391,6 @@ dot_psr (dummy)
   demand_empty_rest_of_line ();
 }
 
-static void
-dot_alias (dummy)
-     int dummy ATTRIBUTE_UNUSED;
-{
-  as_bad (".alias not implemented yet");
-}
-
 static void
 dot_ln (dummy)
      int dummy ATTRIBUTE_UNUSED;
@@ -3984,9 +4437,11 @@ dot_xdata (size)
   if (!name)
     return;
 
+  md.keep_pending_output = 1;
   set_section (name);
   cons (size);
   obj_elf_previous (0);
+  md.keep_pending_output = 0;
 }
 
 /* Why doesn't float_cons() call md_cons_align() the way cons() does?  */
@@ -3995,19 +4450,25 @@ static void
 stmt_float_cons (kind)
      int kind;
 {
-  size_t size;
+  size_t alignment;
 
   switch (kind)
     {
-    case 'd': size = 8; break;
-    case 'x': size = 10; break;
+    case 'd':
+      alignment = 8;
+      break;
+
+    case 'x':
+    case 'X':
+      alignment = 16;
+      break;
 
     case 'f':
     default:
-      size = 4;
+      alignment = 4;
       break;
     }
-  ia64_do_align (size);
+  ia64_do_align (alignment);
   float_cons (kind);
 }
 
@@ -4030,9 +4491,11 @@ dot_xfloat_cons (kind)
   if (!name)
     return;
 
+  md.keep_pending_output = 1;
   set_section (name);
   stmt_float_cons (kind);
   obj_elf_previous (0);
+  md.keep_pending_output = 0;
 }
 
 static void
@@ -4043,9 +4506,11 @@ dot_xstringer (zero)
   if (!name)
     return;
 
+  md.keep_pending_output = 1;
   set_section (name);
   stringer (zero);
   obj_elf_previous (0);
+  md.keep_pending_output = 0;
 }
 
 static void
@@ -4057,11 +4522,13 @@ dot_xdata_ua (size)
   if (!name)
     return;
 
+  md.keep_pending_output = 1;
   set_section (name);
   md.auto_align = 0;
   cons (size);
   md.auto_align = saved_auto_align;
   obj_elf_previous (0);
+  md.keep_pending_output = 0;
 }
 
 static void
@@ -4073,11 +4540,13 @@ dot_xfloat_cons_ua (kind)
   if (!name)
     return;
 
+  md.keep_pending_output = 1;
   set_section (name);
   md.auto_align = 0;
   stmt_float_cons (kind);
   md.auto_align = saved_auto_align;
   obj_elf_previous (0);
+  md.keep_pending_output = 0;
 }
 
 /* .reg.val <regname>,value */
@@ -4227,7 +4696,7 @@ dot_pred_rel (type)
       valueT bit = 1;
       int regno;
 
-      if (toupper (*input_line_pointer) != 'P'
+      if (TOUPPER (*input_line_pointer) != 'P'
          || (regno = atoi (++input_line_pointer)) < 0
          || regno > 63)
        {
@@ -4235,7 +4704,7 @@ dot_pred_rel (type)
          ignore_rest_of_line ();
          return;
        }
-      while (isdigit (*input_line_pointer))
+      while (ISDIGIT (*input_line_pointer))
        ++input_line_pointer;
       if (p1 == -1)
        p1 = regno;
@@ -4252,7 +4721,7 @@ dot_pred_rel (type)
          valueT stop = 1;
          ++input_line_pointer;
 
-         if (toupper (*input_line_pointer) != 'P'
+         if (TOUPPER (*input_line_pointer) != 'P'
              || (regno = atoi (++input_line_pointer)) < 0
              || regno > 63)
            {
@@ -4260,7 +4729,7 @@ dot_pred_rel (type)
              ignore_rest_of_line ();
              return;
            }
-         while (isdigit (*input_line_pointer))
+         while (ISDIGIT (*input_line_pointer))
            ++input_line_pointer;
          stop <<= regno;
          if (bit >= stop)
@@ -4403,12 +4872,12 @@ const pseudo_typeS md_pseudo_table[] =
     { "comment", dot_special_section, SPECIAL_SECTION_COMMENT },
     { "ia_64.unwind", dot_special_section, SPECIAL_SECTION_UNWIND },
     { "ia_64.unwind_info", dot_special_section, SPECIAL_SECTION_UNWIND_INFO },
+    { "init_array", dot_special_section, SPECIAL_SECTION_INIT_ARRAY },
+    { "fini_array", dot_special_section, SPECIAL_SECTION_FINI_ARRAY },
     { "proc", dot_proc, 0 },
     { "body", dot_body, 0 },
     { "prologue", dot_prologue, 0 },
     { "endp", dot_endp, 0 },
-    { "file", dwarf2_directive_file, 0 },
-    { "loc", dwarf2_directive_loc, 0 },
 
     { "fframe", dot_fframe, 0 },
     { "vframe", dot_vframe, 0 },
@@ -4465,6 +4934,7 @@ const pseudo_typeS md_pseudo_table[] =
     { "msb", dot_byteorder, 1 },
     { "psr", dot_psr, 0 },
     { "alias", dot_alias, 0 },
+    { "secalias", dot_alias, 1 },
     { "ln", dot_ln, 0 },               /* source line info (for debugging) */
 
     { "xdata1", dot_xdata, 1 },
@@ -4474,6 +4944,7 @@ const pseudo_typeS md_pseudo_table[] =
     { "xreal4", dot_xfloat_cons, 'f' },
     { "xreal8", dot_xfloat_cons, 'd' },
     { "xreal10", dot_xfloat_cons, 'x' },
+    { "xreal16", dot_xfloat_cons, 'X' },
     { "xstring", dot_xstringer, 0 },
     { "xstringz", dot_xstringer, 1 },
 
@@ -4484,6 +4955,7 @@ const pseudo_typeS md_pseudo_table[] =
     { "xreal4.ua", dot_xfloat_cons_ua, 'f' },
     { "xreal8.ua", dot_xfloat_cons_ua, 'd' },
     { "xreal10.ua", dot_xfloat_cons_ua, 'x' },
+    { "xreal16.ua", dot_xfloat_cons_ua, 'X' },
 
     /* annotations/DV checking support */
     { "entry", dot_entry, 0 },
@@ -4498,6 +4970,15 @@ const pseudo_typeS md_pseudo_table[] =
     { "explicit", dot_dv_mode, 'e' },
     { "default", dot_dv_mode, 'd' },
 
+    /* ??? These are needed to make gas/testsuite/gas/elf/ehopt.s work.
+       IA-64 aligns data allocation pseudo-ops by default, so we have to
+       tell it that these ones are supposed to be unaligned.  Long term,
+       should rewrite so that only IA-64 specific data allocation pseudo-ops
+       are aligned by default.  */
+    {"2byte", stmt_cons_ua, 2},
+    {"4byte", stmt_cons_ua, 4},
+    {"8byte", stmt_cons_ua, 8},
+
     { NULL, 0, 0 }
   };
 
@@ -4514,9 +4995,11 @@ pseudo_opcode[] =
     { "data2", cons, 2 },
     { "data4", cons, 4 },
     { "data8", cons, 8 },
+    { "data16", cons, 16 },
     { "real4", stmt_float_cons, 'f' },
     { "real8", stmt_float_cons, 'd' },
     { "real10", stmt_float_cons, 'x' },
+    { "real16", stmt_float_cons, 'X' },
     { "string", stringer, 0 },
     { "stringz", stringer, 1 },
 
@@ -4524,9 +5007,11 @@ pseudo_opcode[] =
     { "data2.ua", stmt_cons_ua, 2 },
     { "data4.ua", stmt_cons_ua, 4 },
     { "data8.ua", stmt_cons_ua, 8 },
+    { "data16.ua", stmt_cons_ua, 16 },
     { "real4.ua", float_cons, 'f' },
     { "real8.ua", float_cons, 'd' },
     { "real10.ua", float_cons, 'x' },
+    { "real16.ua", float_cons, 'X' },
   };
 
 /* Declare a register by creating a symbol for it and entering it in
@@ -4581,7 +5066,7 @@ operand_width (opnd)
   return bits;
 }
 
-static int
+static enum operand_match_result
 operand_match (idesc, index, e)
      const struct ia64_opcode *idesc;
      int index;
@@ -4598,62 +5083,82 @@ operand_match (idesc, index, e)
 
     case IA64_OPND_AR_CCV:
       if (e->X_op == O_register && e->X_add_number == REG_AR + 32)
-       return 1;
+       return OPERAND_MATCH;
+      break;
+
+    case IA64_OPND_AR_CSD:
+      if (e->X_op == O_register && e->X_add_number == REG_AR + 25)
+       return OPERAND_MATCH;
       break;
 
     case IA64_OPND_AR_PFS:
       if (e->X_op == O_register && e->X_add_number == REG_AR + 64)
-       return 1;
+       return OPERAND_MATCH;
       break;
 
     case IA64_OPND_GR0:
       if (e->X_op == O_register && e->X_add_number == REG_GR + 0)
-       return 1;
+       return OPERAND_MATCH;
       break;
 
     case IA64_OPND_IP:
       if (e->X_op == O_register && e->X_add_number == REG_IP)
-       return 1;
+       return OPERAND_MATCH;
       break;
 
     case IA64_OPND_PR:
       if (e->X_op == O_register && e->X_add_number == REG_PR)
-       return 1;
+       return OPERAND_MATCH;
       break;
 
     case IA64_OPND_PR_ROT:
       if (e->X_op == O_register && e->X_add_number == REG_PR_ROT)
-       return 1;
+       return OPERAND_MATCH;
       break;
 
     case IA64_OPND_PSR:
       if (e->X_op == O_register && e->X_add_number == REG_PSR)
-       return 1;
+       return OPERAND_MATCH;
       break;
 
     case IA64_OPND_PSR_L:
       if (e->X_op == O_register && e->X_add_number == REG_PSR_L)
-       return 1;
+       return OPERAND_MATCH;
       break;
 
     case IA64_OPND_PSR_UM:
       if (e->X_op == O_register && e->X_add_number == REG_PSR_UM)
-       return 1;
+       return OPERAND_MATCH;
       break;
 
     case IA64_OPND_C1:
-      if (e->X_op == O_constant && e->X_add_number == 1)
-       return 1;
+      if (e->X_op == O_constant)
+       {
+         if (e->X_add_number == 1)
+           return OPERAND_MATCH;
+         else
+           return OPERAND_OUT_OF_RANGE;
+       }
       break;
 
     case IA64_OPND_C8:
-      if (e->X_op == O_constant && e->X_add_number == 8)
-       return 1;
+      if (e->X_op == O_constant)
+       {
+         if (e->X_add_number == 8)
+           return OPERAND_MATCH;
+         else
+           return OPERAND_OUT_OF_RANGE;
+       }
       break;
 
     case IA64_OPND_C16:
-      if (e->X_op == O_constant && e->X_add_number == 16)
-       return 1;
+      if (e->X_op == O_constant)
+       {
+         if (e->X_add_number == 16)
+           return OPERAND_MATCH;
+         else
+           return OPERAND_OUT_OF_RANGE;
+       }
       break;
 
       /* register operands:  */
@@ -4661,20 +5166,20 @@ operand_match (idesc, index, e)
     case IA64_OPND_AR3:
       if (e->X_op == O_register && e->X_add_number >= REG_AR
          && e->X_add_number < REG_AR + 128)
-       return 1;
+       return OPERAND_MATCH;
       break;
 
     case IA64_OPND_B1:
     case IA64_OPND_B2:
       if (e->X_op == O_register && e->X_add_number >= REG_BR
          && e->X_add_number < REG_BR + 8)
-       return 1;
+       return OPERAND_MATCH;
       break;
 
     case IA64_OPND_CR3:
       if (e->X_op == O_register && e->X_add_number >= REG_CR
          && e->X_add_number < REG_CR + 128)
-       return 1;
+       return OPERAND_MATCH;
       break;
 
     case IA64_OPND_F1:
@@ -4683,14 +5188,14 @@ operand_match (idesc, index, e)
     case IA64_OPND_F4:
       if (e->X_op == O_register && e->X_add_number >= REG_FR
          && e->X_add_number < REG_FR + 128)
-       return 1;
+       return OPERAND_MATCH;
       break;
 
     case IA64_OPND_P1:
     case IA64_OPND_P2:
       if (e->X_op == O_register && e->X_add_number >= REG_P
          && e->X_add_number < REG_P + 64)
-       return 1;
+       return OPERAND_MATCH;
       break;
 
     case IA64_OPND_R1:
@@ -4698,13 +5203,17 @@ operand_match (idesc, index, e)
     case IA64_OPND_R3:
       if (e->X_op == O_register && e->X_add_number >= REG_GR
          && e->X_add_number < REG_GR + 128)
-       return 1;
+       return OPERAND_MATCH;
       break;
 
     case IA64_OPND_R3_2:
-      if (e->X_op == O_register && e->X_add_number >= REG_GR
-         && e->X_add_number < REG_GR + 4)
-       return 1;
+      if (e->X_op == O_register && e->X_add_number >= REG_GR)
+       {
+         if (e->X_add_number < REG_GR + 4)
+           return OPERAND_MATCH;
+         else if (e->X_add_number < REG_GR + 128)
+           return OPERAND_OUT_OF_RANGE;
+       }
       break;
 
       /* indirect operands:  */
@@ -4721,12 +5230,12 @@ operand_match (idesc, index, e)
       if (e->X_op == O_index && e->X_op_symbol
          && (S_GET_VALUE (e->X_op_symbol) - IND_CPUID
              == opnd - IA64_OPND_CPUID_R3))
-       return 1;
+       return OPERAND_MATCH;
       break;
 
     case IA64_OPND_MR3:
       if (e->X_op == O_index && !e->X_op_symbol)
-       return 1;
+       return OPERAND_MATCH;
       break;
 
       /* immediate operands:  */
@@ -4734,40 +5243,58 @@ operand_match (idesc, index, e)
     case IA64_OPND_LEN4:
     case IA64_OPND_LEN6:
       bits = operand_width (idesc->operands[index]);
-      if (e->X_op == O_constant
-         && (bfd_vma) (e->X_add_number - 1) < ((bfd_vma) 1 << bits))
-       return 1;
+      if (e->X_op == O_constant)
+       {
+         if ((bfd_vma) (e->X_add_number - 1) < ((bfd_vma) 1 << bits))
+           return OPERAND_MATCH;
+         else
+           return OPERAND_OUT_OF_RANGE;
+       }
       break;
 
     case IA64_OPND_CNT2b:
-      if (e->X_op == O_constant
-         && (bfd_vma) (e->X_add_number - 1) < 3)
-       return 1;
+      if (e->X_op == O_constant)
+       {
+         if ((bfd_vma) (e->X_add_number - 1) < 3)
+           return OPERAND_MATCH;
+         else
+           return OPERAND_OUT_OF_RANGE;
+       }
       break;
 
     case IA64_OPND_CNT2c:
       val = e->X_add_number;
-      if (e->X_op == O_constant
-         && (val == 0 || val == 7 || val == 15 || val == 16))
-       return 1;
+      if (e->X_op == O_constant)
+       {
+         if ((val == 0 || val == 7 || val == 15 || val == 16))
+           return OPERAND_MATCH;
+         else
+           return OPERAND_OUT_OF_RANGE;
+       }
       break;
 
     case IA64_OPND_SOR:
       /* SOR must be an integer multiple of 8 */
-      if (e->X_add_number & 0x7)
-       break;
+      if (e->X_op == O_constant && e->X_add_number & 0x7)
+       return OPERAND_OUT_OF_RANGE;
     case IA64_OPND_SOF:
     case IA64_OPND_SOL:
-      if (e->X_op == O_constant &&
-         (bfd_vma) e->X_add_number <= 96)
-       return 1;
+      if (e->X_op == O_constant)
+       {
+         if ((bfd_vma) e->X_add_number <= 96)
+           return OPERAND_MATCH;
+         else
+           return OPERAND_OUT_OF_RANGE;
+       }
       break;
 
     case IA64_OPND_IMMU62:
       if (e->X_op == O_constant)
        {
          if ((bfd_vma) e->X_add_number < ((bfd_vma) 1 << 62))
-           return 1;
+           return OPERAND_MATCH;
+         else
+           return OPERAND_OUT_OF_RANGE;
        }
       else
        {
@@ -4793,10 +5320,10 @@ operand_match (idesc, index, e)
          fix->expr = *e;
          fix->is_pcrel = 0;
          ++CURR_SLOT.num_fixups;
-         return 1;
+         return OPERAND_MATCH;
        }
       else if (e->X_op == O_constant)
-       return 1;
+       return OPERAND_MATCH;
       break;
 
     case IA64_OPND_CCNT5:
@@ -4814,59 +5341,78 @@ operand_match (idesc, index, e)
     case IA64_OPND_MHTYPE8:
     case IA64_OPND_POS6:
       bits = operand_width (idesc->operands[index]);
-      if (e->X_op == O_constant
-         && (bfd_vma) e->X_add_number < ((bfd_vma) 1 << bits))
-       return 1;
+      if (e->X_op == O_constant)
+       {
+         if ((bfd_vma) e->X_add_number < ((bfd_vma) 1 << bits))
+           return OPERAND_MATCH;
+         else
+           return OPERAND_OUT_OF_RANGE;
+       }
       break;
 
     case IA64_OPND_IMMU9:
       bits = operand_width (idesc->operands[index]);
-      if (e->X_op == O_constant
-         && (bfd_vma) e->X_add_number < ((bfd_vma) 1 << bits))
+      if (e->X_op == O_constant)
        {
-         int lobits = e->X_add_number & 0x3;
-         if (((bfd_vma) e->X_add_number & 0x3C) != 0 && lobits == 0)
-           e->X_add_number |= (bfd_vma) 0x3;
-         return 1;
+         if ((bfd_vma) e->X_add_number < ((bfd_vma) 1 << bits))
+           {
+             int lobits = e->X_add_number & 0x3;
+             if (((bfd_vma) e->X_add_number & 0x3C) != 0 && lobits == 0)
+               e->X_add_number |= (bfd_vma) 0x3;
+             return OPERAND_MATCH;
+           }
+         else
+           return OPERAND_OUT_OF_RANGE;
        }
       break;
 
     case IA64_OPND_IMM44:
       /* least 16 bits must be zero */
       if ((e->X_add_number & 0xffff) != 0)
+       /* XXX technically, this is wrong: we should not be issuing warning
+          messages until we're sure this instruction pattern is going to
+          be used! */
        as_warn (_("lower 16 bits of mask ignored"));
 
-      if (e->X_op == O_constant
-         && ((e->X_add_number >= 0
-              && (bfd_vma) e->X_add_number < ((bfd_vma) 1 << 44))
-             || (e->X_add_number < 0
-                 && (bfd_vma) -e->X_add_number <= ((bfd_vma) 1 << 44))))
+      if (e->X_op == O_constant)
        {
-         /* sign-extend */
-         if (e->X_add_number >= 0
-             && (e->X_add_number & ((bfd_vma) 1 << 43)) != 0)
+         if (((e->X_add_number >= 0
+               && (bfd_vma) e->X_add_number < ((bfd_vma) 1 << 44))
+              || (e->X_add_number < 0
+                  && (bfd_vma) -e->X_add_number <= ((bfd_vma) 1 << 44))))
            {
-             e->X_add_number |= ~(((bfd_vma) 1 << 44) - 1);
+             /* sign-extend */
+             if (e->X_add_number >= 0
+                 && (e->X_add_number & ((bfd_vma) 1 << 43)) != 0)
+               {
+                 e->X_add_number |= ~(((bfd_vma) 1 << 44) - 1);
+               }
+             return OPERAND_MATCH;
            }
-         return 1;
+         else
+           return OPERAND_OUT_OF_RANGE;
        }
       break;
 
     case IA64_OPND_IMM17:
       /* bit 0 is a don't care (pr0 is hardwired to 1) */
-      if (e->X_op == O_constant
-         && ((e->X_add_number >= 0
-              && (bfd_vma) e->X_add_number < ((bfd_vma) 1 << 17))
-             || (e->X_add_number < 0
-                 && (bfd_vma) -e->X_add_number <= ((bfd_vma) 1 << 17))))
-       {
-         /* sign-extend */
-         if (e->X_add_number >= 0
-             && (e->X_add_number & ((bfd_vma) 1 << 16)) != 0)
+      if (e->X_op == O_constant)
+       {
+         if (((e->X_add_number >= 0
+               && (bfd_vma) e->X_add_number < ((bfd_vma) 1 << 17))
+              || (e->X_add_number < 0
+                  && (bfd_vma) -e->X_add_number <= ((bfd_vma) 1 << 17))))
            {
-             e->X_add_number |= ~(((bfd_vma) 1 << 17) - 1);
+             /* sign-extend */
+             if (e->X_add_number >= 0
+                 && (e->X_add_number & ((bfd_vma) 1 << 16)) != 0)
+               {
+                 e->X_add_number |= ~(((bfd_vma) 1 << 17) - 1);
+               }
+             return OPERAND_MATCH;
            }
-         return 1;
+         else
+           return OPERAND_OUT_OF_RANGE;
        }
       break;
 
@@ -4904,18 +5450,18 @@ operand_match (idesc, index, e)
          fix->expr = *e;
          fix->is_pcrel = 0;
          ++CURR_SLOT.num_fixups;
-         return 1;
+         return OPERAND_MATCH;
        }
       else if (e->X_op != O_constant
               && ! (e->X_op == O_big && opnd == IA64_OPND_IMM8M1U8))
-       return 0;
+       return OPERAND_MISMATCH;
 
       if (opnd == IA64_OPND_IMM8M1U4)
        {
          /* Zero is not valid for unsigned compares that take an adjusted
             constant immediate range.  */
          if (e->X_add_number == 0)
-           return 0;
+           return OPERAND_OUT_OF_RANGE;
 
          /* Sign-extend 32-bit unsigned numbers, so that the following range
             checks will work.  */
@@ -4927,7 +5473,7 @@ operand_match (idesc, index, e)
          /* Check for 0x100000000.  This is valid because
             0x100000000-1 is the same as ((uint32_t) -1).  */
          if (val == ((bfd_signed_vma) 1 << 32))
-           return 1;
+           return OPERAND_MATCH;
 
          val = val - 1;
        }
@@ -4936,7 +5482,7 @@ operand_match (idesc, index, e)
          /* Zero is not valid for unsigned compares that take an adjusted
             constant immediate range.  */
          if (e->X_add_number == 0)
-           return 0;
+           return OPERAND_OUT_OF_RANGE;
 
          /* Check for 0x10000000000000000.  */
          if (e->X_op == O_big)
@@ -4946,9 +5492,9 @@ operand_match (idesc, index, e)
                  && generic_bignum[2] == 0
                  && generic_bignum[3] == 0
                  && generic_bignum[4] == 1)
-               return 1;
+               return OPERAND_MATCH;
              else
-               return 0;
+               return OPERAND_OUT_OF_RANGE;
            }
          else
            val = e->X_add_number - 1;
@@ -4969,17 +5515,22 @@ operand_match (idesc, index, e)
 
       if ((val >= 0 && (bfd_vma) val < ((bfd_vma) 1 << (bits - 1)))
          || (val < 0 && (bfd_vma) -val <= ((bfd_vma) 1 << (bits - 1))))
-       return 1;
-      break;
+       return OPERAND_MATCH;
+      else
+       return OPERAND_OUT_OF_RANGE;
 
     case IA64_OPND_INC3:
       /* +/- 1, 4, 8, 16 */
       val = e->X_add_number;
       if (val < 0)
        val = -val;
-      if (e->X_op == O_constant
-         && (val == 1 || val == 4 || val == 8 || val == 16))
-       return 1;
+      if (e->X_op == O_constant)
+       {
+         if ((val == 1 || val == 4 || val == 8 || val == 16))
+           return OPERAND_MATCH;
+         else
+           return OPERAND_OUT_OF_RANGE;
+       }
       break;
 
     case IA64_OPND_TGT25:
@@ -5005,33 +5556,45 @@ operand_match (idesc, index, e)
          fix->expr = *e;
          fix->is_pcrel = 1;
          ++CURR_SLOT.num_fixups;
-         return 1;
+         return OPERAND_MATCH;
        }
     case IA64_OPND_TAG13:
     case IA64_OPND_TAG13b:
       switch (e->X_op)
        {
        case O_constant:
-         return 1;
+         return OPERAND_MATCH;
 
        case O_symbol:
          fix = CURR_SLOT.fixup + CURR_SLOT.num_fixups;
-         fix->code = ia64_gen_real_reloc_type (e->X_op_symbol, 0);
+         /* There are no external relocs for TAG13/TAG13b fields, so we
+            create a dummy reloc.  This will not live past md_apply_fix3.  */
+         fix->code = BFD_RELOC_UNUSED;
+         fix->code = ia64_gen_real_reloc_type (e->X_op_symbol, fix->code);
          fix->opnd = idesc->operands[index];
          fix->expr = *e;
          fix->is_pcrel = 1;
          ++CURR_SLOT.num_fixups;
-         return 1;
+         return OPERAND_MATCH;
 
        default:
          break;
        }
       break;
 
+    case IA64_OPND_LDXMOV:
+      fix = CURR_SLOT.fixup + CURR_SLOT.num_fixups;
+      fix->code = BFD_RELOC_IA64_LDXMOV;
+      fix->opnd = idesc->operands[index];
+      fix->expr = *e;
+      fix->is_pcrel = 0;
+      ++CURR_SLOT.num_fixups;
+      return OPERAND_MATCH;
+
     default:
       break;
     }
-  return 0;
+  return OPERAND_MISMATCH;
 }
 
 static int
@@ -5079,8 +5642,9 @@ parse_operands (idesc)
      struct ia64_opcode *idesc;
 {
   int i = 0, highest_unmatched_operand, num_operands = 0, num_outputs = 0;
-  int sep = 0;
+  int error_pos, out_of_range_pos, curr_out_of_range_pos, sep = 0;
   enum ia64_opnd expected_operand = IA64_OPND_NIL;
+  enum operand_match_result result;
   char mnemonic[129];
   char *first_arg = 0, *end, *saved_input_pointer;
   unsigned int sof;
@@ -5162,6 +5726,8 @@ parse_operands (idesc)
     }
 
   highest_unmatched_operand = 0;
+  curr_out_of_range_pos = -1;
+  error_pos = 0;
   expected_operand = idesc->operands[0];
   for (; idesc; idesc = get_next_opcode (idesc))
     {
@@ -5169,16 +5735,52 @@ parse_operands (idesc)
        continue;               /* mismatch in # of outputs */
 
       CURR_SLOT.num_fixups = 0;
+
+      /* Try to match all operands.  If we see an out-of-range operand,
+        then continue trying to match the rest of the operands, since if
+        the rest match, then this idesc will give the best error message.  */
+
+      out_of_range_pos = -1;
       for (i = 0; i < num_operands && idesc->operands[i]; ++i)
-       if (!operand_match (idesc, i, CURR_SLOT.opnd + i))
-         break;
+       {
+         result = operand_match (idesc, i, CURR_SLOT.opnd + i);
+         if (result != OPERAND_MATCH)
+           {
+             if (result != OPERAND_OUT_OF_RANGE)
+               break;
+             if (out_of_range_pos < 0)
+               /* remember position of the first out-of-range operand: */
+               out_of_range_pos = i;
+           }
+       }
+
+      /* If we did not match all operands, or if at least one operand was
+        out-of-range, then this idesc does not match.  Keep track of which
+        idesc matched the most operands before failing.  If we have two
+        idescs that failed at the same position, and one had an out-of-range
+        operand, then prefer the out-of-range operand.  Thus if we have
+        "add r0=0x1000000,r1" we get an error saying the constant is out
+        of range instead of an error saying that the constant should have been
+        a register.  */
 
-      if (i != num_operands)
+      if (i != num_operands || out_of_range_pos >= 0)
        {
-         if (i > highest_unmatched_operand)
+         if (i > highest_unmatched_operand
+             || (i == highest_unmatched_operand
+                 && out_of_range_pos > curr_out_of_range_pos))
            {
              highest_unmatched_operand = i;
-             expected_operand = idesc->operands[i];
+             if (out_of_range_pos >= 0)
+               {
+                 expected_operand = idesc->operands[out_of_range_pos];
+                 error_pos = out_of_range_pos;
+               }
+             else
+               {
+                 expected_operand = idesc->operands[i];
+                 error_pos = i;
+               }
+             curr_out_of_range_pos = out_of_range_pos;
            }
          continue;
        }
@@ -5193,7 +5795,7 @@ parse_operands (idesc)
     {
       if (expected_operand)
        as_bad ("Operand %u of `%s' should be %s",
-               highest_unmatched_operand + 1, mnemonic,
+               error_pos + 1, mnemonic,
                elf64_ia64_operands[expected_operand].desc);
       else
        as_bad ("Operand mismatch");
@@ -5285,7 +5887,7 @@ errata_nop_necessary_p (slot, insn_unit)
                  && strncmp (idesc->name, "ptr", 3) != 0
                  && strncmp (idesc->name, "ptc", 3) != 0
                  && strncmp (idesc->name, "probe", 5) != 0)
-             return 0;
+               return 0;
            }
          if (prev_group->g_reg_set_conditionally[regno])
            return 1;
@@ -5613,10 +6215,11 @@ emit_one_bundle ()
        }
       required_unit = ia64_templ_desc[template].exec_unit[i];
 
-      /* resolve dynamic opcodes such as "break" and "nop":  */
+      /* resolve dynamic opcodes such as "break", "hint", and "nop":  */
       if (idesc->type == IA64_TYPE_DYN)
        {
          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)
@@ -5677,12 +6280,12 @@ emit_one_bundle ()
          continue;             /* try next slot */
        }
 
-       {
-         bfd_vma addr;
+      {
+       bfd_vma addr;
 
-         addr = frag_now->fr_address + frag_now_fix () - 16 + i;
-         dwarf2_gen_line_info (addr, &md.slot[curr].debug_line);
-       }
+       addr = frag_now->fr_address + frag_now_fix () - 16 + i;
+       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"));
@@ -5779,6 +6382,7 @@ md_parse_option (c, arg)
      int c;
      char *arg;
 {
+
   switch (c)
     {
     /* Switches from the Intel assembler.  */
@@ -5834,12 +6438,13 @@ md_parse_option (c, arg)
       break;
 
     case 'a':
-      /* ??? Conflicts with gas' listing option.  */
       /* indirect=<tgt>        Assume unannotated indirect branches behavior
                        according to <tgt> --
                        exit:   branch out from the current context (default)
                        labels: all labels in context may be branch targets
        */
+      if (strncmp (arg, "indirect=", 9) != 0)
+        return 0;
       break;
 
     case 'x':
@@ -5896,6 +6501,11 @@ md_show_usage (stream)
 {
   fputs (_("\
 IA-64 options:\n\
+  --mconstant-gp         mark output file as using the constant-GP model\n\
+                         (sets ELF header flag EF_IA_64_CONS_GP)\n\
+  --mauto-pic            mark output file as using the constant-GP model\n\
+                         without function descriptors (sets ELF header flag\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\
@@ -5904,6 +6514,13 @@ IA-64 options:\n\
        stream);
 }
 
+void
+ia64_after_parse_args ()
+{
+  if (debug_type == DEBUG_STABS)
+    as_fatal (_("--gstabs is not supported for ia64"));
+}
+
 /* Return true if TYPE fits in TEMPL at SLOT.  */
 
 static int
@@ -5957,7 +6574,23 @@ md_begin ()
 
   bfd_set_section_alignment (stdoutput, text_section, 4);
 
-  target_big_endian = TARGET_BYTES_BIG_ENDIAN;
+  /* Make sure fucntion pointers get initialized.  */
+  target_big_endian = -1;
+  dot_byteorder (TARGET_BYTES_BIG_ENDIAN);
+
+  alias_hash = hash_new ();
+  alias_name_hash = hash_new ();
+  secalias_hash = hash_new ();
+  secalias_name_hash = hash_new ();
+
+  pseudo_func[FUNC_DTP_MODULE].u.sym =
+    symbol_new (".<dtpmod>", undefined_section, FUNC_DTP_MODULE,
+               &zero_address_frag);
+
+  pseudo_func[FUNC_DTP_RELATIVE].u.sym =
+    symbol_new (".<dtprel>", undefined_section, FUNC_DTP_RELATIVE,
+               &zero_address_frag);
+
   pseudo_func[FUNC_FPTR_RELATIVE].u.sym =
     symbol_new (".<fptr>", undefined_section, FUNC_FPTR_RELATIVE,
                &zero_address_frag);
@@ -5970,6 +6603,10 @@ md_begin ()
     symbol_new (".<ltoff>", undefined_section, FUNC_LT_RELATIVE,
                &zero_address_frag);
 
+  pseudo_func[FUNC_LT_RELATIVE_X].u.sym =
+    symbol_new (".<ltoffx>", undefined_section, FUNC_LT_RELATIVE_X,
+               &zero_address_frag);
+
   pseudo_func[FUNC_PC_RELATIVE].u.sym =
     symbol_new (".<pcrel>", undefined_section, FUNC_PC_RELATIVE,
                &zero_address_frag);
@@ -5986,6 +6623,10 @@ md_begin ()
     symbol_new (".<segrel>", undefined_section, FUNC_SEG_RELATIVE,
                &zero_address_frag);
 
+  pseudo_func[FUNC_TP_RELATIVE].u.sym =
+    symbol_new (".<tprel>", undefined_section, FUNC_TP_RELATIVE,
+               &zero_address_frag);
+
   pseudo_func[FUNC_LTV_RELATIVE].u.sym =
     symbol_new (".<ltv>", undefined_section, FUNC_LTV_RELATIVE,
                &zero_address_frag);
@@ -5994,6 +6635,22 @@ md_begin ()
     symbol_new (".<ltoff.fptr>", undefined_section, FUNC_LT_FPTR_RELATIVE,
                &zero_address_frag);
 
+  pseudo_func[FUNC_LT_DTP_MODULE].u.sym =
+    symbol_new (".<ltoff.dtpmod>", undefined_section, FUNC_LT_DTP_MODULE,
+               &zero_address_frag);
+
+  pseudo_func[FUNC_LT_DTP_RELATIVE].u.sym =
+    symbol_new (".<ltoff.dptrel>", undefined_section, FUNC_LT_DTP_RELATIVE,
+               &zero_address_frag);
+
+  pseudo_func[FUNC_LT_TP_RELATIVE].u.sym =
+    symbol_new (".<ltoff.tprel>", undefined_section, FUNC_LT_TP_RELATIVE,
+               &zero_address_frag);
+
+  pseudo_func[FUNC_IPLT_RELOC].u.sym =
+    symbol_new (".<iplt>", undefined_section, FUNC_IPLT_RELOC,
+               &zero_address_frag);
+
   /* Compute the table of best templates.  We compute goodness as a
      base 4 value, in which each match counts for 3, each F counts
      for 2, each B counts for 1.  This should maximize the number of
@@ -6166,6 +6823,19 @@ md_begin ()
   if (! ok)
      as_warn (_("Could not set architecture and machine"));
 
+  /* Set the pointer size and pointer shift size depending on md.flags */
+
+  if (md.flags & EF_IA_64_ABI64)
+    {
+      md.pointer_size = 8;         /* pointers are 8 bytes */
+      md.pointer_size_shift = 3;   /* alignment is 8 bytes = 2^2 */
+    }
+  else
+    {
+      md.pointer_size = 4;         /* pointers are 4 bytes */
+      md.pointer_size_shift = 2;   /* alignment is 4 bytes = 2^2 */
+    }
+
   md.mem_offset.hint = 0;
   md.path = 0;
   md.maxpaths = 0;
@@ -6182,9 +6852,7 @@ ia64_init (argc, argv)
      int argc ATTRIBUTE_UNUSED;
      char **argv ATTRIBUTE_UNUSED;
 {
-  md.flags = EF_IA_64_ABI64;
-  if (TARGET_BYTES_BIG_ENDIAN)
-    md.flags |= EF_IA_64_BE;
+  md.flags = MD_FLAGS_DEFAULT;
 }
 
 /* Return a string for the target object file format.  */
@@ -6197,16 +6865,36 @@ ia64_target_format ()
       if (md.flags & EF_IA_64_BE)
        {
          if (md.flags & EF_IA_64_ABI64)
+#if defined(TE_AIX50)
+           return "elf64-ia64-aix-big";
+#elif defined(TE_HPUX)
+           return "elf64-ia64-hpux-big";
+#else
            return "elf64-ia64-big";
+#endif
          else
+#if defined(TE_AIX50)
+           return "elf32-ia64-aix-big";
+#elif defined(TE_HPUX)
+           return "elf32-ia64-hpux-big";
+#else
            return "elf32-ia64-big";
+#endif
        }
       else
        {
          if (md.flags & EF_IA_64_ABI64)
+#ifdef TE_AIX50
+           return "elf64-ia64-aix-little";
+#else
            return "elf64-ia64-little";
+#endif
          else
+#ifdef TE_AIX50
+           return "elf32-ia64-aix-little";
+#else
            return "elf32-ia64-little";
+#endif
        }
     }
   else
@@ -6325,14 +7013,36 @@ ia64_unrecognized_line (ch)
        char *s;
        char c;
        symbolS *tag;
+       int temp;
 
        if (md.qp.X_op == O_register)
          {
            as_bad ("Tag must come before qualifying predicate.");
            return 0;
          }
-       s = input_line_pointer;
-       c = get_symbol_end ();
+
+       /* This implements just enough of read_a_source_file in read.c to
+          recognize labels.  */
+       if (is_name_beginner (*input_line_pointer))
+         {
+           s = input_line_pointer;
+           c = get_symbol_end ();
+         }
+       else if (LOCAL_LABELS_FB
+                && ISDIGIT (*input_line_pointer))
+         {
+           temp = 0;
+           while (ISDIGIT (*input_line_pointer))
+             temp = (temp * 10) + *input_line_pointer++ - '0';
+           fb_label_instance_inc (temp);
+           s = fb_label_name (temp, 0);
+           c = *input_line_pointer;
+         }
+       else
+         {
+           s = NULL;
+           c = '\0';
+         }
        if (c != ':')
          {
            /* Put ':' back for error messages' sake.  */
@@ -6340,6 +7050,7 @@ ia64_unrecognized_line (ch)
            as_bad ("Expected ':'");
            return 0;
          }
+
        defining_tag = 1;
        tag = colon (s);
        defining_tag = 0;
@@ -6407,7 +7118,8 @@ ia64_frob_label (sym)
 void
 ia64_flush_pending_output ()
 {
-  if (bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE)
+  if (!md.keep_pending_output
+      && bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE)
     {
       /* ??? This causes many unnecessary stop bits to be emitted.
         Unfortunately, it isn't clear if it is safe to remove this.  */
@@ -6493,7 +7205,7 @@ ia64_parse_name (name, e)
   switch (name[0])
     {
     case 'i':
-      if (name[1] == 'n' && isdigit (name[2]))
+      if (name[1] == 'n' && ISDIGIT (name[2]))
        {
          dr = &md.in;
          name += 2;
@@ -6501,7 +7213,7 @@ ia64_parse_name (name, e)
       break;
 
     case 'l':
-      if (name[1] == 'o' && name[2] == 'c' && isdigit (name[3]))
+      if (name[1] == 'o' && name[2] == 'c' && ISDIGIT (name[3]))
        {
          dr = &md.loc;
          name += 3;
@@ -6509,7 +7221,7 @@ ia64_parse_name (name, e)
       break;
 
     case 'o':
-      if (name[1] == 'u' && name[2] == 't' && isdigit (name[3]))
+      if (name[1] == 'u' && name[2] == 't' && ISDIGIT (name[3]))
        {
          dr = &md.out;
          name += 3;
@@ -6566,19 +7278,29 @@ ia64_canonicalize_symbol_name (name)
   return name;
 }
 
+/* Return true if idesc is a conditional branch instruction.  This excludes
+   the modulo scheduled branches, and br.ia.  Mod-sched branches are excluded
+   because they always read/write resources regardless of the value of the
+   qualifying predicate.  br.ia must always use p0, and hence is always
+   taken.  Thus this function returns true for branches which can fall
+   through, and which use no resources if they do fall through.  */
+
 static int
 is_conditional_branch (idesc)
      struct ia64_opcode *idesc;
 {
-  return (strncmp (idesc->name, "br", 2) == 0
-         && (strcmp (idesc->name, "br") == 0
-             || strncmp (idesc->name, "br.cond", 7) == 0
-             || strncmp (idesc->name, "br.call", 7) == 0
-             || strncmp (idesc->name, "br.ret", 6) == 0
-             || strcmp (idesc->name, "brl") == 0
-             || strncmp (idesc->name, "brl.cond", 7) == 0
-             || strncmp (idesc->name, "brl.call", 7) == 0
-             || strncmp (idesc->name, "brl.ret", 6) == 0));
+  /* br is a conditional branch.  Everything that starts with br. except
+     br.ia, br.c{loop,top,exit}, and br.w{top,exit} is a conditional branch.
+     Everything that starts with brl is a conditional branch.  */
+  return (idesc->name[0] == 'b' && idesc->name[1] == 'r'
+         && (idesc->name[2] == '\0'
+             || (idesc->name[2] == '.' && idesc->name[3] != 'i'
+                 && idesc->name[3] != 'c' && idesc->name[3] != 'w')
+             || idesc->name[2] == 'l'
+             /* br.cond, br.call, br.clr  */
+             || (idesc->name[2] == '.' && idesc->name[3] == 'c'
+                 && (idesc->name[4] == 'a' || idesc->name[4] == 'o'
+                     || (idesc->name[4] == 'l' && idesc->name[5] == 'r')))));
 }
 
 /* Return whether the given opcode is a taken branch.  If there's any doubt,
@@ -6854,7 +7576,7 @@ dep->name, idesc->name, (rsrc_write?"write":"read"), note)
            }
          else
            {
-             for (i = idesc->num_outputs;i < NELEMS (idesc->operands); i++)
+             for (i = idesc->num_outputs; i < NELEMS (idesc->operands); i++)
                if (idesc->operands[i] == IA64_OPND_B1
                    || idesc->operands[i] == IA64_OPND_B2)
                  {
@@ -7312,8 +8034,8 @@ dep->name, idesc->name, (rsrc_write?"write":"read"), note)
            {
              int p1 = CURR_SLOT.opnd[0].X_add_number - REG_P;
              int p2 = CURR_SLOT.opnd[1].X_add_number - REG_P;
-             int or_andcm = strstr(idesc->name, "or.andcm") != NULL;
-             int and_orcm = strstr(idesc->name, "and.orcm") != NULL;
+             int or_andcm = strstr (idesc->name, "or.andcm") != NULL;
+             int and_orcm = strstr (idesc->name, "and.orcm") != NULL;
 
              if ((idesc->operands[0] == IA64_OPND_P1
                   || idesc->operands[0] == IA64_OPND_P2)
@@ -7376,7 +8098,7 @@ dep->name, idesc->name, (rsrc_write?"write":"read"), note)
              && idesc->operands[0] == IA64_OPND_PR)
            {
              mask = CURR_SLOT.opnd[2].X_add_number;
-             if (mask & ((valueT) 1<<16))
+             if (mask & ((valueT) 1 << 16))
                for (i = 16; i < 63; i++)
                  {
                    specs[count] = tmpl;
@@ -7434,8 +8156,8 @@ dep->name, idesc->name, (rsrc_write?"write":"read"), note)
            {
              int p1 = CURR_SLOT.opnd[0].X_add_number - REG_P;
              int p2 = CURR_SLOT.opnd[1].X_add_number - REG_P;
-             int or_andcm = strstr(idesc->name, "or.andcm") != NULL;
-             int and_orcm = strstr(idesc->name, "and.orcm") != NULL;
+             int or_andcm = strstr (idesc->name, "or.andcm") != NULL;
+             int and_orcm = strstr (idesc->name, "and.orcm") != NULL;
 
              if ((idesc->operands[0] == IA64_OPND_P1
                   || idesc->operands[0] == IA64_OPND_P2)
@@ -7867,13 +8589,13 @@ dep->name, idesc->name, (rsrc_write?"write":"read"), note)
          specs[count++] = tmpl;
        }
       else if (note == 7)
-        {
-          valueT mask = 0;
-          if (idesc->operands[2] == IA64_OPND_IMM17)
-            mask = CURR_SLOT.opnd[2].X_add_number;
-          if (mask & ((valueT) 1 << 63))
+       {
+         valueT mask = 0;
+         if (idesc->operands[2] == IA64_OPND_IMM17)
+           mask = CURR_SLOT.opnd[2].X_add_number;
+         if (mask & ((valueT) 1 << 63))
            specs[count++] = tmpl;
-        }
+       }
       else if (note == 11)
        {
          if ((idesc->operands[0] == IA64_OPND_P1
@@ -7895,16 +8617,16 @@ dep->name, idesc->name, (rsrc_write?"write":"read"), note)
        {
          if (rsrc_write)
            {
-              int p1 = CURR_SLOT.opnd[0].X_add_number - REG_P;
-              int p2 = CURR_SLOT.opnd[1].X_add_number - REG_P;
-             int or_andcm = strstr(idesc->name, "or.andcm") != NULL;
-             int and_orcm = strstr(idesc->name, "and.orcm") != NULL;
+             int p1 = CURR_SLOT.opnd[0].X_add_number - REG_P;
+             int p2 = CURR_SLOT.opnd[1].X_add_number - REG_P;
+             int or_andcm = strstr (idesc->name, "or.andcm") != NULL;
+             int and_orcm = strstr (idesc->name, "and.orcm") != NULL;
 
              if (p1 == 63
                  && (idesc->operands[0] == IA64_OPND_P1
                      || idesc->operands[0] == IA64_OPND_P2))
                {
-                  specs[count] = tmpl;
+                 specs[count] = tmpl;
                  specs[count++].cmp_type =
                    (or_andcm ? CMP_OR : (and_orcm ? CMP_AND : CMP_NONE));
                }
@@ -7912,7 +8634,7 @@ dep->name, idesc->name, (rsrc_write?"write":"read"), note)
                  && (idesc->operands[1] == IA64_OPND_P1
                      || idesc->operands[1] == IA64_OPND_P2))
                {
-                  specs[count] = tmpl;
+                 specs[count] = tmpl;
                  specs[count++].cmp_type =
                    (or_andcm ? CMP_AND : (and_orcm ? CMP_OR : CMP_NONE));
                }
@@ -8149,6 +8871,19 @@ add_qp_mutex (mask)
   qp_mutexes[qp_mutexeslen++].prmask = mask;
 }
 
+static int
+has_suffix_p (name, suffix)
+     const char *name;
+     const char *suffix;
+{
+  size_t namelen = strlen (name);
+  size_t sufflen = strlen (suffix);
+
+  if (namelen <= sufflen)
+    return 0;
+  return strcmp (name + namelen - sufflen, suffix) == 0;
+}
+
 static void
 clear_register_values ()
 {
@@ -8205,7 +8940,7 @@ note_register_values (idesc)
       else if (idesc->operands[i] == IA64_OPND_PR_ROT)
        {
          if (idesc->operands[1] & ((valueT) 1 << 43))
-           qp_changemask = ~(valueT) 0xFFFFFFFFFFF | idesc->operands[1];
+           qp_changemask = -((valueT) 1 << 44) | idesc->operands[1];
          else
            qp_changemask = idesc->operands[1];
          qp_changemask &= ~(valueT) 0xFFFF;
@@ -8266,21 +9001,19 @@ note_register_values (idesc)
        }
       /* In general, clear mutexes and implies which include P1 or P2,
         with the following exceptions.  */
-      else if (strstr (idesc->name, ".or.andcm") != NULL)
+      else if (has_suffix_p (idesc->name, ".or.andcm")
+              || has_suffix_p (idesc->name, ".and.orcm"))
        {
          add_qp_mutex (p1mask | p2mask);
          clear_qp_implies (p2mask, p1mask);
        }
-      else if (strstr (idesc->name, ".and.orcm") != NULL)
-       {
-         add_qp_mutex (p1mask | p2mask);
-         clear_qp_implies (p1mask, p2mask);
-       }
-      else if (strstr (idesc->name, ".and") != NULL)
+      else if (has_suffix_p (idesc->name, ".andcm")
+              || has_suffix_p (idesc->name, ".and"))
        {
          clear_qp_implies (0, p1mask | p2mask);
        }
-      else if (strstr (idesc->name, ".or") != NULL)
+      else if (has_suffix_p (idesc->name, ".orcm")
+              || has_suffix_p (idesc->name, ".or"))
        {
          clear_qp_mutex (p1mask | p2mask);
          clear_qp_implies (p1mask | p2mask, 0);
@@ -8288,7 +9021,7 @@ note_register_values (idesc)
       else
        {
          clear_qp_implies (p1mask | p2mask, p1mask | p2mask);
-         if (strstr (idesc->name, ".unc") != NULL)
+         if (has_suffix_p (idesc->name, ".unc"))
            {
              add_qp_mutex (p1mask | p2mask);
              if (CURR_SLOT.qp_regno != 0)
@@ -9210,11 +9943,22 @@ md_operand (e)
                  as_bad ("Not a symbolic expression");
                  goto err;
                }
-             if (S_GET_VALUE (e->X_op_symbol) == FUNC_FPTR_RELATIVE
-                 && i == FUNC_LT_RELATIVE)
-               i = FUNC_LT_FPTR_RELATIVE;
-             else
+             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;
                }
@@ -9319,12 +10063,16 @@ ia64_force_relocation (fix)
     case BFD_RELOC_IA64_PLTOFF64I:
     case BFD_RELOC_IA64_PLTOFF64MSB:
     case BFD_RELOC_IA64_PLTOFF64LSB:
+
+    case BFD_RELOC_IA64_LTOFF22X:
+    case BFD_RELOC_IA64_LDXMOV:
       return 1;
 
     default:
-      return 0;
+      break;
     }
-  return 0;
+
+  return generic_force_reloc (fix);
 }
 
 /* Decide from what point a pc-relative relocation is relative to,
@@ -9342,6 +10090,20 @@ ia64_pcrel_from_section (fix, sec)
   return off;
 }
 
+
+/* Used to emit section-relative relocs for the dwarf2 debug data.  */
+void
+ia64_dwarf2_emit_offset (symbolS *symbol, unsigned int size)
+{
+  expressionS expr;
+
+  expr.X_op = O_pseudo_fixup;
+  expr.X_op_symbol = pseudo_func[FUNC_SEC_RELATIVE].u.sym;
+  expr.X_add_number = 0;
+  expr.X_add_symbol = symbol;
+  emit_expr (&expr, size);
+}
+
 /* This is called whenever some data item (not an instruction) needs a
    fixup.  We pick the right reloc code depending on the byteorder
    currently in effect.  */
@@ -9370,27 +10132,59 @@ ia64_cons_fix_new (f, where, nbytes, exp)
       break;
 
     case 8:
-      if (target_big_endian)
-       code = BFD_RELOC_IA64_DIR64MSB;
+      /* In 32-bit mode, data8 could mean function descriptors too.  */
+      if (exp->X_op == O_pseudo_fixup
+         && exp->X_op_symbol
+         && S_GET_VALUE (exp->X_op_symbol) == FUNC_IPLT_RELOC
+         && !(md.flags & EF_IA_64_ABI64))
+       {
+         if (target_big_endian)
+           code = BFD_RELOC_IA64_IPLTMSB;
+         else
+           code = BFD_RELOC_IA64_IPLTLSB;
+         exp->X_op = O_symbol;
+         break;
+       }
       else
-       code = BFD_RELOC_IA64_DIR64LSB;
-      break;
+       {
+         if (target_big_endian)
+           code = BFD_RELOC_IA64_DIR64MSB;
+         else
+           code = BFD_RELOC_IA64_DIR64LSB;
+         break;
+       }
+
+    case 16:
+      if (exp->X_op == O_pseudo_fixup
+         && exp->X_op_symbol
+         && S_GET_VALUE (exp->X_op_symbol) == FUNC_IPLT_RELOC)
+       {
+         if (target_big_endian)
+           code = BFD_RELOC_IA64_IPLTMSB;
+         else
+           code = BFD_RELOC_IA64_IPLTLSB;
+         exp->X_op = O_symbol;
+         break;
+       }
+      /* FALLTHRU */
 
     default:
       as_bad ("Unsupported fixup size %d", nbytes);
       ignore_rest_of_line ();
       return;
     }
+
   if (exp->X_op == O_pseudo_fixup)
     {
-      /* ??? */
       exp->X_op = O_symbol;
       code = ia64_gen_real_reloc_type (exp->X_op_symbol, code);
+      /* ??? If code unchanged, unsupported.  */
     }
+
   fix = fix_new_exp (f, where, nbytes, exp, 0, code);
   /* We need to store the byte order in effect in case we're going
      to fix an 8 or 16 bit relocation (for which there no real
-     relocs available).  See md_apply_fix().  */
+     relocs available).  See md_apply_fix3().  */
   fix->tc_fix_data.bigendian = target_big_endian;
 }
 
@@ -9446,6 +10240,14 @@ ia64_gen_real_reloc_type (sym, r_type)
        }
       break;
 
+    case FUNC_LT_RELATIVE_X:
+      switch (r_type)
+       {
+       case BFD_RELOC_IA64_IMM22:      new = BFD_RELOC_IA64_LTOFF22X; break;
+       default:                        break;
+       }
+      break;
+
     case FUNC_PC_RELATIVE:
       switch (r_type)
        {
@@ -9514,9 +10316,76 @@ ia64_gen_real_reloc_type (sym, r_type)
          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;
+       }
+      break;
+
+    case FUNC_LT_TP_RELATIVE:
+      switch (r_type)
+       {
+       case BFD_RELOC_IA64_IMM22:
+         new = BFD_RELOC_IA64_LTOFF_TPREL22; break;
+       default:
+         break;
+       }
+      break;
+
+    case FUNC_LT_DTP_MODULE:
+      switch (r_type)
+       {
+       case BFD_RELOC_IA64_IMM22:
+         new = BFD_RELOC_IA64_LTOFF_DTPMOD22; break;
+       default:
+         break;
+       }
+      break;
+
+    case FUNC_DTP_RELATIVE:
+      switch (r_type)
+       {
+       case BFD_RELOC_IA64_DIR64MSB:
+         new = BFD_RELOC_IA64_DTPREL64MSB; break;
+       case BFD_RELOC_IA64_DIR64LSB:
+         new = BFD_RELOC_IA64_DTPREL64LSB; break;
+       case BFD_RELOC_IA64_IMM14:
+         new = BFD_RELOC_IA64_DTPREL14; break;
+       case BFD_RELOC_IA64_IMM22:
+         new = BFD_RELOC_IA64_DTPREL22; break;
+       case BFD_RELOC_IA64_IMM64:
+         new = BFD_RELOC_IA64_DTPREL64I; break;
+       default:
+         break;
+       }
+      break;
+
+    case FUNC_LT_DTP_RELATIVE:
+      switch (r_type)
+       {
+       case BFD_RELOC_IA64_IMM22:
+         new = BFD_RELOC_IA64_LTOFF_DTPREL22; break;
+       default:
+         break;
+       }
+      break;
+
+    case FUNC_IPLT_RELOC:
+      break;
+
     default:
       abort ();
     }
+
   /* Hmmmm.  Should this ever occur?  */
   if (new)
     return new;
@@ -9612,15 +10481,15 @@ fix_insn (fix, odesc, value)
 
    If fixp->fx_addsy is non-NULL, we'll have to generate a reloc entry
    (if possible).  */
-int
-md_apply_fix3 (fix, valuep, seg)
+
+void
+md_apply_fix3 (fix, valP, seg)
      fixS *fix;
-     valueT *valuep;
+     valueT *valP;
      segT seg ATTRIBUTE_UNUSED;
 {
   char *fixpos;
-  valueT value = *valuep;
-  int adjust = 0;
+  valueT value = *valP;
 
   fixpos = fix->fx_frag->fr_literal + fix->fx_where;
 
@@ -9630,22 +10499,18 @@ md_apply_fix3 (fix, valuep, seg)
        {
        case BFD_RELOC_IA64_DIR32MSB:
          fix->fx_r_type = BFD_RELOC_IA64_PCREL32MSB;
-         adjust = 1;
          break;
 
        case BFD_RELOC_IA64_DIR32LSB:
          fix->fx_r_type = BFD_RELOC_IA64_PCREL32LSB;
-         adjust = 1;
          break;
 
        case BFD_RELOC_IA64_DIR64MSB:
          fix->fx_r_type = BFD_RELOC_IA64_PCREL64MSB;
-         adjust = 1;
          break;
 
        case BFD_RELOC_IA64_DIR64LSB:
          fix->fx_r_type = BFD_RELOC_IA64_PCREL64LSB;
-         adjust = 1;
          break;
 
        default:
@@ -9656,20 +10521,30 @@ md_apply_fix3 (fix, valuep, seg)
     {
       switch (fix->fx_r_type)
        {
-       case 0:
+       case BFD_RELOC_UNUSED:
+         /* This must be a TAG13 or TAG13b operand.  There are no external
+            relocs defined for them, so we must give an error.  */
          as_bad_where (fix->fx_file, fix->fx_line,
                        "%s must have a constant value",
                        elf64_ia64_operands[fix->tc_fix_data.opnd].desc);
+         fix->fx_done = 1;
+         return;
+
+       case BFD_RELOC_IA64_TPREL14:
+       case BFD_RELOC_IA64_TPREL22:
+       case BFD_RELOC_IA64_TPREL64I:
+       case BFD_RELOC_IA64_LTOFF_TPREL22:
+       case BFD_RELOC_IA64_LTOFF_DTPMOD22:
+       case BFD_RELOC_IA64_DTPREL14:
+       case BFD_RELOC_IA64_DTPREL22:
+       case BFD_RELOC_IA64_DTPREL64I:
+       case BFD_RELOC_IA64_LTOFF_DTPREL22:
+         S_SET_THREAD_LOCAL (fix->fx_addsy);
          break;
 
        default:
          break;
        }
-
-      /* ??? This is a hack copied from tc-i386.c to make PCREL relocs
-        work.  There should be a better way to handle this.  */
-      if (adjust)
-       fix->fx_offset += fix->fx_where + fix->fx_frag->fr_address;
     }
   else if (fix->tc_fix_data.opnd == IA64_OPND_NIL)
     {
@@ -9678,15 +10553,12 @@ md_apply_fix3 (fix, valuep, seg)
       else
        number_to_chars_littleendian (fixpos, value, fix->fx_size);
       fix->fx_done = 1;
-      return 1;
     }
   else
     {
       fix_insn (fix, elf64_ia64_operands + fix->tc_fix_data.opnd, value);
       fix->fx_done = 1;
-      return 1;
     }
-  return 1;
 }
 
 /* Generate the BFD reloc to be stuck in the object file from the
@@ -9729,7 +10601,6 @@ md_atof (type, lit, size)
      int *size;
 {
   LITTLENUM_TYPE words[MAX_LITTLENUMS];
-  LITTLENUM_TYPE *word;
   char *t;
   int prec;
 
@@ -9764,36 +10635,29 @@ md_atof (type, lit, size)
   t = atof_ieee (input_line_pointer, type, words);
   if (t)
     input_line_pointer = t;
-  *size = prec * sizeof (LITTLENUM_TYPE);
 
-  for (word = words + prec - 1; prec--;)
+  (*ia64_float_to_chars) (lit, words, prec);
+
+  if (type == 'X')
     {
-      md_number_to_chars (lit, (long) (*word--), sizeof (LITTLENUM_TYPE));
-      lit += sizeof (LITTLENUM_TYPE);
+      /* It is 10 byte floating point with 6 byte padding.  */
+      memset (&lit [10], 0, 6);
+      *size = 8 * sizeof (LITTLENUM_TYPE);
     }
-  return 0;
-}
-
-/* Round up a section's size to the appropriate boundary.  */
-valueT
-md_section_align (seg, size)
-     segT seg;
-     valueT size;
-{
-  int align = bfd_get_section_alignment (stdoutput, seg);
-  valueT mask = ((valueT) 1 << align) - 1;
+  else
+    *size = prec * sizeof (LITTLENUM_TYPE);
 
-  return (size + mask) & ~mask;
+  return 0;
 }
 
 /* Handle ia64 specific semantics of the align directive.  */
 
 void
 ia64_md_do_align (n, fill, len, max)
-     int n;
-     const char *fill;
+     int n ATTRIBUTE_UNUSED;
+     const char *fill ATTRIBUTE_UNUSED;
      int len ATTRIBUTE_UNUSED;
-     int max;
+     int max ATTRIBUTE_UNUSED;
 {
   if (subseg_text_p (now_seg))
     ia64_flush_insns ();
@@ -9837,3 +10701,210 @@ ia64_handle_align (fragp)
   memcpy (p, (target_big_endian ? be_nop : le_nop), 16);
   fragp->fr_var = 16;
 }
+
+static void
+ia64_float_to_chars_bigendian (char *lit, LITTLENUM_TYPE *words,
+                              int prec)
+{
+  while (prec--)
+    {
+      number_to_chars_bigendian (lit, (long) (*words++),
+                                sizeof (LITTLENUM_TYPE));
+      lit += sizeof (LITTLENUM_TYPE);
+    }
+}
+
+static void
+ia64_float_to_chars_littleendian (char *lit, LITTLENUM_TYPE *words,
+                                 int prec)
+{
+  while (prec--)
+    {
+      number_to_chars_littleendian (lit, (long) (words[prec]),
+                                   sizeof (LITTLENUM_TYPE));
+      lit += sizeof (LITTLENUM_TYPE);
+    }
+}
+
+void
+ia64_elf_section_change_hook  (void)
+{
+  dot_byteorder (-1);
+}
+
+/* Check if a label should be made global.  */
+void
+ia64_check_label (symbolS *label)
+{
+  if (*input_line_pointer == ':')
+    {
+      S_SET_EXTERNAL (label);
+      input_line_pointer++;
+    }
+}
+
+/* Used to remember where .alias and .secalias directives are seen. We
+   will rename symbol and section names when we are about to output
+   the relocatable file.  */
+struct alias
+{
+  char *file;          /* The file where the directive is seen.  */
+  unsigned int line;   /* The line number the directive is at.  */
+  const char *name;    /* The orignale name of the symbol.  */
+};
+
+/* Called for .alias and .secalias directives. If SECTION is 1, it is
+   .secalias. Otherwise, it is .alias.  */
+static void
+dot_alias (int section)
+{
+  char *name, *alias;
+  char delim;
+  char *end_name;
+  int len;
+  const char *error_string;
+  struct alias *h;
+  const char *a;
+  struct hash_control *ahash, *nhash;
+  const char *kind;
+
+  name = input_line_pointer;
+  delim = get_symbol_end ();
+  end_name = input_line_pointer;
+  *end_name = delim;
+
+  if (name == end_name)
+    {
+      as_bad (_("expected symbol name"));
+      discard_rest_of_line ();
+      return;
+    }
+
+  SKIP_WHITESPACE ();
+
+  if (*input_line_pointer != ',')
+    {
+      *end_name = 0;
+      as_bad (_("expected comma after \"%s\""), name);
+      *end_name = delim;
+      ignore_rest_of_line ();
+      return;
+    }
+
+  input_line_pointer++;
+  *end_name = 0;
+
+  /* We call demand_copy_C_string to check if alias string is valid.
+     There should be a closing `"' and no `\0' in the string.  */
+  alias = demand_copy_C_string (&len);
+  if (alias == NULL)
+    {
+      ignore_rest_of_line ();
+      return;
+    }
+
+  /* Make a copy of name string.  */
+  len = strlen (name) + 1;
+  obstack_grow (&notes, name, len);
+  name = obstack_finish (&notes);
+
+  if (section)
+    {
+      kind = "section";
+      ahash = secalias_hash;
+      nhash = secalias_name_hash;
+    }
+  else
+    {
+      kind = "symbol";
+      ahash = alias_hash;
+      nhash = alias_name_hash;
+    }
+
+  /* Check if alias has been used before.  */
+  h = (struct alias *) hash_find (ahash, alias);
+  if (h)
+    {
+      if (strcmp (h->name, name))
+       as_bad (_("`%s' is already the alias of %s `%s'"),
+               alias, kind, h->name);
+      goto out;
+    }
+
+  /* Check if name already has an alias.  */
+  a = (const char *) hash_find (nhash, name);
+  if (a)
+    {
+      if (strcmp (a, alias))
+       as_bad (_("%s `%s' already has an alias `%s'"), kind, name, a);
+      goto out;
+    }
+
+  h = (struct alias *) xmalloc (sizeof (struct alias));
+  as_where (&h->file, &h->line);
+  h->name = name;
+  
+  error_string = hash_jam (ahash, alias, (PTR) h);
+  if (error_string)
+    {
+      as_fatal (_("inserting \"%s\" into %s alias hash table failed: %s"),
+               alias, kind, error_string);
+      goto out;
+    }
+
+  error_string = hash_jam (nhash, name, (PTR) alias);
+  if (error_string)
+    {
+      as_fatal (_("inserting \"%s\" into %s name hash table failed: %s"),
+               alias, kind, error_string);
+out:
+      obstack_free (&notes, name);
+      obstack_free (&notes, alias);
+    }
+
+  demand_empty_rest_of_line ();
+}
+
+/* It renames the original symbol name to its alias.  */
+static void
+do_alias (const char *alias, PTR value)
+{
+  struct alias *h = (struct alias *) value;
+  symbolS *sym = symbol_find (h->name);
+
+  if (sym == NULL)
+    as_warn_where (h->file, h->line,
+                  _("symbol `%s' aliased to `%s' is not used"),
+                  h->name, alias);
+    else
+      S_SET_NAME (sym, (char *) alias);
+}
+
+/* Called from write_object_file.  */
+void
+ia64_adjust_symtab (void)
+{
+  hash_traverse (alias_hash, do_alias);
+}
+
+/* It renames the original section name to its alias.  */
+static void
+do_secalias (const char *alias, PTR value)
+{
+  struct alias *h = (struct alias *) value;
+  segT sec = bfd_get_section_by_name (stdoutput, h->name);
+
+  if (sec == NULL)
+    as_warn_where (h->file, h->line,
+                  _("section `%s' aliased to `%s' is not used"),
+                  h->name, alias);
+  else
+    sec->name = alias;
+}
+
+/* Called from write_object_file.  */
+void
+ia64_frob_file (void)
+{
+  hash_traverse (secalias_hash, do_secalias);
+}
This page took 0.057277 seconds and 4 git commands to generate.