* dwarf2.c: Convert to C90, remove unneeded casts and prototypes.
[deliverable/binutils-gdb.git] / gas / config / tc-ia64.c
index 88905b87ed0a273dd34b97a9b9a851fd66f695fc..4e98aa4ffb3e184d28e6243a6c2e07aea7b89b58 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-ia64.c -- Assembler for the HP/Intel IA-64 architecture.
-   Copyright 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   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
@@ -77,15 +76,22 @@ enum special_section
 
 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,
   };
 
@@ -149,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[] = "";
 
@@ -476,15 +496,22 @@ 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:  */
@@ -507,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 } }
@@ -618,6 +652,8 @@ typedef struct unw_rec_list {
   unwind_record r;
   unsigned long slot_number;
   fragS *slot_frag;
+  unsigned long next_slot_number;
+  fragS *next_slot_frag;
   struct unw_rec_list *next;
 } unw_rec_list;
 
@@ -634,9 +670,6 @@ typedef struct label_prologue_count
 
 static struct
 {
-  unsigned long next_slot_number;
-  fragS *next_slot_frag;
-
   /* Maintain a list of unwind entries for the current function.  */
   unw_rec_list *list;
   unw_rec_list *tail;
@@ -664,7 +697,7 @@ static struct
 
 typedef void (*vbyte_func) PARAMS ((int, char *, char *));
 
-/* Forward delarations:  */
+/* Forward declarations:  */
 static int ar_is_in_integer_unit PARAMS ((int regnum));
 static void set_section PARAMS ((char *name));
 static unsigned int set_regstack PARAMS ((unsigned int, unsigned int,
@@ -789,7 +822,6 @@ static void output_X2_format PARAMS ((vbyte_func, int, int, int, int, int, unsig
 static void output_X3_format PARAMS ((vbyte_func, unw_record_type, int, int, int, unsigned long,
                                      unsigned long));
 static void output_X4_format PARAMS ((vbyte_func, int, int, int, int, int, int, unsigned long));
-static void free_list_records PARAMS ((unw_rec_list *));
 static unw_rec_list *output_prologue PARAMS ((void));
 static unw_rec_list *output_prologue_gr PARAMS ((unsigned int, unsigned int));
 static unw_rec_list *output_body PARAMS ((void));
@@ -869,10 +901,9 @@ 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 ((const char *));
+static void generate_unwind_image PARAMS ((const char *));
 static unsigned int get_saved_prologue_count PARAMS ((unsigned long));
 static void save_prologue_count PARAMS ((unsigned long, unsigned int));
 static void free_saved_prologue_counts PARAMS ((void));
@@ -880,7 +911,7 @@ 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... */
+   stack, so this must be a macro...  */
 #define make_unw_section_name(special, text_name, result)                 \
   {                                                                       \
     const char *_prefix = special_section_name[special];                  \
@@ -942,9 +973,11 @@ ia64_elf_section_letter (letter, 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,s,w,x,M,S in string");
-  return 0;
+  *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.  */
@@ -961,11 +994,11 @@ ia64_elf_section_flags (flags, attr, type)
 
 int
 ia64_elf_section_type (str, len)
-       const char *str;
-       size_t 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;
 
@@ -978,12 +1011,15 @@ ia64_elf_section_type (str, len)
   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
 }
@@ -1671,28 +1707,11 @@ alloc_record (unw_record_type t)
   ptr->next = NULL;
   ptr->slot_number = SLOT_NUM_NOT_SET;
   ptr->r.type = t;
+  ptr->next_slot_number = 0;
+  ptr->next_slot_frag = 0;
   return ptr;
 }
 
-/* This function frees an entire list of record structures.  */
-
-void
-free_list_records (unw_rec_list *first)
-{
-  unw_rec_list *ptr;
-  for (ptr = first; ptr != NULL;)
-    {
-      unw_rec_list *tmp = ptr;
-
-      if ((tmp->r.type == prologue || tmp->r.type == prologue_gr)
-         && tmp->r.record.r.mask.i)
-       free (tmp->r.record.r.mask.i);
-
-      ptr = ptr->next;
-      free (tmp);
-    }
-}
-
 static unw_rec_list *
 output_prologue ()
 {
@@ -2592,6 +2611,46 @@ slot_index (slot_addr, slot_frag, first_addr, first_frag)
     {
       unsigned long start_addr = (unsigned long) &first_frag->fr_literal;
 
+      if (finalize_syms)
+       {
+         /* We can get the final addresses only after relaxation is
+            done. */
+         if (first_frag->fr_next && first_frag->fr_next->fr_address)
+           index += 3 * ((first_frag->fr_next->fr_address
+                          - first_frag->fr_address
+                            - first_frag->fr_fix) >> 4);
+       }
+      else
+       /* We don't know what the final addresses will be. We try our
+          best to estimate.  */
+       switch (first_frag->fr_type)
+         {
+         default:
+           break;
+
+         case rs_space:
+           as_fatal ("only constant space allocation is supported");
+           break;
+
+         case rs_align:
+         case rs_align_code:
+         case rs_align_test:
+           /* Take alignment into account.  Assume the worst case
+              before relaxation.  */
+           index += 3 * ((1 << first_frag->fr_offset) >> 4);
+           break;
+
+         case rs_org:
+           if (first_frag->fr_symbol)
+             {
+               as_fatal ("only constant offsets are supported");
+               break;
+             }
+         case rs_fill:
+           index += 3 * (first_frag->fr_offset >> 4);
+           break;
+         }
+
       /* Add in the full size of the frag converted to instruction slots.  */
       index += 3 * (first_frag->fr_fix >> 4);
       /* Subtract away the initial part before first_addr.  */
@@ -2630,7 +2689,7 @@ optimize_unw_records (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
+   this has been run, all necessary information should be available
    within each record to generate an image.  */
 
 static void
@@ -2660,11 +2719,10 @@ fixup_unw_records (list)
 
            first_addr = ptr->slot_number;
            first_frag = ptr->slot_frag;
-           ptr->slot_number = 0;
            /* Find either the next body/prologue start, or the end of
               the list, and determine the size of the region.  */
-           last_addr = unwind.next_slot_number;
-           last_frag = unwind.next_slot_frag;
+           last_addr = list->next_slot_number;
+           last_frag = list->next_slot_frag;
            for (last = ptr->next; last != NULL; last = last->next)
              if (last->r.type == prologue || last->r.type == prologue_gr
                  || last->r.type == body)
@@ -2709,7 +2767,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:
@@ -2803,29 +2865,33 @@ 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)
+/* This function converts a rs_machine_dependent variant frag into a
+  normal fill frag with the unwind image from the the record list.  */
+void
+ia64_convert_frag (fragS *frag)
 {
-  int x, extra = 0;
+  unw_rec_list *list;
+  int len, size, pad;
   valueT flag_value;
 
-  /* pad to pointer-size boundry.  */
-  x = size % md.pointer_size;
-  if (x != 0)
-    extra = md.pointer_size - x;
+  list = (unw_rec_list *) frag->fr_opcode;
+  fixup_unw_records (list);
 
-  /* Add 8 for the header + a pointer for the 
-     personality offset.  */
-  *mem = xmalloc (size + extra + 8 + md.pointer_size);
+  len = calc_record_size (list);
+  /* pad to pointer-size boundary.  */
+  pad = len % md.pointer_size;
+  if (pad != 0)
+    len += md.pointer_size - pad;
+  /* Add 8 for the header + a pointer for the personality offset.  */
+  size = len + 8 + md.pointer_size;
 
-  /* Clear the padding area and personality.  */
-  memset (*mem + 8 + size, 0 , extra + md.pointer_size);
+  /* fr_var carries the max_chars that we created the fragment with.
+     We must, of course, have allocated enough memory earlier.  */
+  assert (frag->fr_var >= size);
 
-  /* Initialize the header area.  */
-  if (unwind.personality_routine)
+  /* Initialize the header area. fr_offset is initialized with
+     unwind.personality_routine.  */
+  if (frag->fr_offset)
     {
       if (md.flags & EF_IA_64_ABI64)
        flag_value = (bfd_vma) 3 << 32;
@@ -2836,44 +2902,19 @@ setup_unwind_header (int size, unsigned char **mem)
   else
     flag_value = 0;
 
-  md_number_to_chars (*mem, (((bfd_vma) 1 << 48)     /* Version.  */
-                            | flag_value            /* U & E handler flags.  */
-                            | ((size + extra) / md.pointer_size)), /* Length.  */
-                     8);
-
-  return extra;
-}
-
-/* Generate an unwind image from a record list.  Returns the number of
-   bytes in the resulting image. The memory image itselof is returned
-   in the 'ptr' parameter.  */
-static int
-output_unw_records (list, ptr)
-     unw_rec_list *list;
-     void **ptr;
-{
-  int size, extra;
-  unsigned char *mem;
-
-  *ptr = NULL;
-
-  list = optimize_unw_records (list);
-  fixup_unw_records (list);
-  size = calc_record_size (list);
-
-  if (size > 0 || unwind.force_unwind_entry)
-    {
-      unwind.force_unwind_entry = 0;
-      extra = setup_unwind_header (size, &mem);
-
-      vbyte_mem_ptr = mem + 8;
-      process_unw_records (list, output_vbyte_mem);
-
-      *ptr = mem;
+ md_number_to_chars (frag->fr_literal,
+                    (((bfd_vma) 1 << 48) /* Version.  */
+                     | flag_value        /* U & E handler flags.  */
+                     | (len / md.pointer_size)), /* Length.  */
+                    8);
 
-      size += extra + 8 + md.pointer_size;
-    }
-  return size;
+  /* Skip the header.  */
+  vbyte_mem_ptr = frag->fr_literal + 8;
+  process_unw_records (list, output_vbyte_mem);
+  frag->fr_fix += size;
+  frag->fr_type = rs_fill;
+  frag->fr_var = 0;
+  frag->fr_offset = 0;
 }
 
 static int
@@ -3047,7 +3088,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
@@ -3063,7 +3104,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
@@ -3235,26 +3276,37 @@ dot_restorereg_p (dummy)
   add_unwind_entry (output_spill_reg_p (ab, reg, 0, 0, qp));
 }
 
-static int
+static void
 generate_unwind_image (text_name)
      const char *text_name;
 {
-  int size;
-  unsigned char *unw_rec;
+  int size, pad;
+  unw_rec_list *list;
 
   /* 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 % md.pointer_size != 0)
-    as_bad ("Unwind record is not a multiple of %d bytes.", md.pointer_size);
+  list = optimize_unw_records (unwind.list);
+  fixup_unw_records (list);
+  size = calc_record_size (list);
+
+  if (size > 0 || unwind.force_unwind_entry)
+    {
+      unwind.force_unwind_entry = 0;
+      /* pad to pointer-size boundary.  */
+      pad = size % md.pointer_size;
+      if (pad != 0)
+       size += md.pointer_size - pad;
+      /* Add 8 for the header + a pointer for the personality
+        offset.  */
+      size += 8 + md.pointer_size;
+    }
 
   /* If there are unwind records, switch sections, and output the info.  */
   if (size != 0)
     {
-      unsigned char *where;
       char *sec_name;
       expressionS exp;
       bfd_reloc_code_real_type reloc;
@@ -3271,20 +3323,14 @@ generate_unwind_image (text_name)
 
       /* Set expression which points to start of unwind descriptor area.  */
       unwind.info = expr_build_dot ();
-
-      where = (unsigned char *) frag_more (size);
-
-      /* Issue a label for this address, and keep track of it to put it
-        in the unwind section.  */
-
-      /* Copy the information from the unwind record into this section. The
-        data is already in the correct byte order.  */
-      memcpy (where, unw_rec, size);
+      
+      frag_var (rs_machine_dependent, size, size, 0, 0,
+               (offsetT) unwind.personality_routine, (char *) list);
 
       /* 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;
 
@@ -3295,7 +3341,7 @@ generate_unwind_image (text_name)
              else
                reloc = BFD_RELOC_IA64_LTOFF_FPTR32MSB;
            }
-          else
+         else
            {
              if (md.flags & EF_IA_64_ABI64)
                reloc = BFD_RELOC_IA64_LTOFF_FPTR64LSB;
@@ -3304,16 +3350,13 @@ generate_unwind_image (text_name)
            }
 
          fix_new_exp (frag_now, frag_now_fix () - md.pointer_size,
-                      md.pointer_size, & exp, 0, reloc);
+                      md.pointer_size, &exp, 0, reloc);
          unwind.personality_routine = 0;
        }
     }
 
-  free_list_records (unwind.list);
   free_saved_prologue_counts ();
   unwind.list = unwind.tail = unwind.current_entry = NULL;
-
-  return size;
 }
 
 static void
@@ -3767,7 +3810,7 @@ save_prologue_count (lbl, count)
     lpc->prologue_count = count;
   else
     {
-      label_prologue_count * new_lpc = xmalloc (sizeof (* new_lpc));
+      label_prologue_count *new_lpc = xmalloc (sizeof (* new_lpc));
 
       new_lpc->next = unwind.saved_prologue_counts;
       new_lpc->label_number = lbl;
@@ -3779,8 +3822,8 @@ save_prologue_count (lbl, count)
 static void
 free_saved_prologue_counts ()
 {
-  label_prologue_count * lpc = unwind.saved_prologue_counts;
-  label_prologue_count * next;
+  label_prologue_count *lpc = unwind.saved_prologue_counts;
+  label_prologue_count *next;
 
   while (lpc != NULL)
     {
@@ -4016,7 +4059,7 @@ dot_endp (dummy)
            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);
@@ -4056,7 +4099,7 @@ dot_endp (dummy)
       where = frag_now_fix () - (3 * md.pointer_size);
       bytes_per_address = bfd_arch_bits_per_address (stdoutput) / 8;
 
-      /* Issue the values of  a) Proc Begin, b) Proc End, c) Unwind Record. */
+      /* 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;
@@ -4287,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
@@ -4323,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;
@@ -4389,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);
 }
 
@@ -4811,8 +4878,6 @@ const pseudo_typeS md_pseudo_table[] =
     { "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 },
@@ -4869,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 },
@@ -4878,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 },
 
@@ -4888,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 },
@@ -4931,6 +4999,7 @@ pseudo_opcode[] =
     { "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 },
 
@@ -4942,6 +5011,7 @@ pseudo_opcode[] =
     { "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
@@ -5016,6 +5086,11 @@ operand_match (idesc, index, e)
        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 OPERAND_MATCH;
@@ -5133,7 +5208,7 @@ operand_match (idesc, index, e)
 
     case IA64_OPND_R3_2:
       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)
@@ -5507,6 +5582,15 @@ operand_match (idesc, index, e)
        }
       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;
     }
@@ -5803,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;
@@ -6131,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)
@@ -6195,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"));
@@ -6288,8 +6373,11 @@ emit_one_bundle ()
   number_to_chars_littleendian (f + 0, t0, 8);
   number_to_chars_littleendian (f + 8, t1, 8);
 
-  unwind.next_slot_number = (unsigned long) f + 16;
-  unwind.next_slot_frag = frag_now;
+  if (unwind.list)
+    {
+  unwind.list->next_slot_number = (unsigned long) f + 16;
+  unwind.list->next_slot_frag = frag_now;
+    }
 }
 
 int
@@ -6489,7 +6577,23 @@ md_begin ()
 
   bfd_set_section_alignment (stdoutput, text_section, 4);
 
-  target_big_endian = TARGET_BYTES_BIG_ENDIAN;
+  /* Make sure function 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);
@@ -6502,6 +6606,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);
@@ -6518,6 +6626,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);
@@ -6526,6 +6638,18 @@ 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);
@@ -7455,7 +7579,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)
                  {
@@ -7977,7 +8101,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;
@@ -8468,13 +8592,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
@@ -8496,8 +8620,8 @@ 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 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;
 
@@ -8505,7 +8629,7 @@ dep->name, idesc->name, (rsrc_write?"write":"read"), note)
                  && (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));
                }
@@ -8513,7 +8637,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));
                }
@@ -8605,6 +8729,77 @@ clear_qp_branch_flag (mask)
     }
 }
 
+/* MASK contains 2 and only 2 PRs which are mutually exclusive.  Remove
+   any mutexes which contain one of the PRs and create new ones when
+   needed.  */
+
+static int
+update_qp_mutex (valueT mask)
+{
+  int i;
+  int add = 0;
+
+  i = 0;
+  while (i < qp_mutexeslen)
+    {
+      if ((qp_mutexes[i].prmask & mask) != 0)
+       {
+         /* If it destroys and creates the same mutex, do nothing.  */
+         if (qp_mutexes[i].prmask == mask
+             && qp_mutexes[i].path == md.path)
+           {
+             i++;
+             add = -1;
+           }
+         else
+           {
+             int keep = 0;
+
+             if (md.debug_dv)
+               {
+                 fprintf (stderr, "  Clearing mutex relation");
+                 print_prmask (qp_mutexes[i].prmask);
+                 fprintf (stderr, "\n");
+               }
+             
+             /* Deal with the old mutex with more than 3+ PRs only if
+                the new mutex on the same execution path with it.
+
+                FIXME: The 3+ mutex support is incomplete.
+                dot_pred_rel () may be a better place to fix it.  */
+             if (qp_mutexes[i].path == md.path)
+               {
+                 /* If it is a proper subset of the mutex, create a
+                    new mutex.  */
+                 if (add == 0
+                     && (qp_mutexes[i].prmask & mask) == mask)
+                   add = 1;
+                 
+                 qp_mutexes[i].prmask &= ~mask;
+                 if (qp_mutexes[i].prmask & (qp_mutexes[i].prmask - 1))
+                   {
+                     /* Modify the mutex if there are more than one
+                        PR left.  */
+                     keep = 1;
+                     i++;
+                   }
+               }
+             
+             if (keep == 0)
+               /* Remove the mutex.  */
+               qp_mutexes[i] = qp_mutexes[--qp_mutexeslen];
+           }
+       }
+      else
+       ++i;
+    }
+
+  if (add == 1)
+    add_qp_mutex (mask);
+
+  return add;
+}
+
 /* Remove any mutexes which contain any of the PRs indicated in the mask.
 
    Any changes to a PR clears the mutex relations which include that PR.  */
@@ -8752,8 +8947,8 @@ add_qp_mutex (mask)
 
 static int
 has_suffix_p (name, suffix)
-      const char *name;
-      const char *suffix;
+     const char *name;
+     const char *suffix;
 {
   size_t namelen = strlen (name);
   size_t sufflen = strlen (suffix);
@@ -8819,7 +9014,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;
@@ -8869,11 +9064,11 @@ note_register_values (idesc)
     {
       int p1 = CURR_SLOT.opnd[0].X_add_number - REG_P;
       int p2 = CURR_SLOT.opnd[1].X_add_number - REG_P;
-      valueT p1mask = (valueT) 1 << p1;
-      valueT p2mask = (valueT) 1 << p2;
+      valueT p1mask = (p1 != 0) ? (valueT) 1 << p1 : 0;
+      valueT p2mask = (p2 != 0) ? (valueT) 1 << p2 : 0;
 
-      /* If one of the PRs is PR0, we can't really do anything.  */
-      if (p1 == 0 || p2 == 0)
+      /* If both PRs are PR0, we can't really do anything.  */
+      if (p1 == 0 && p2 == 0)
        {
          if (md.debug_dv)
            fprintf (stderr, "  Ignoring PRs due to inclusion of p0\n");
@@ -8883,7 +9078,6 @@ note_register_values (idesc)
       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 (has_suffix_p (idesc->name, ".andcm")
@@ -8899,26 +9093,29 @@ note_register_values (idesc)
        }
       else
        {
+         int added = 0;
+
          clear_qp_implies (p1mask | p2mask, p1mask | p2mask);
-         if (has_suffix_p (idesc->name, ".unc"))
+
+         /* If one of the PRs is PR0, we call clear_qp_mutex.  */
+         if (p1 == 0 || p2 == 0)
+           clear_qp_mutex (p1mask | p2mask);
+         else
+           added = update_qp_mutex (p1mask | p2mask);
+
+         if (CURR_SLOT.qp_regno == 0
+             || has_suffix_p (idesc->name, ".unc"))
            {
-             add_qp_mutex (p1mask | p2mask);
+             if (added == 0 && p1 && p2)
+               add_qp_mutex (p1mask | p2mask);
              if (CURR_SLOT.qp_regno != 0)
                {
-                 add_qp_imply (CURR_SLOT.opnd[0].X_add_number - REG_P,
-                               CURR_SLOT.qp_regno);
-                 add_qp_imply (CURR_SLOT.opnd[1].X_add_number - REG_P,
-                               CURR_SLOT.qp_regno);
+                 if (p1)
+                   add_qp_imply (p1, CURR_SLOT.qp_regno);
+                 if (p2)
+                   add_qp_imply (p2, CURR_SLOT.qp_regno);
                }
            }
-         else if (CURR_SLOT.qp_regno == 0)
-           {
-             add_qp_mutex (p1mask | p2mask);
-           }
-         else
-           {
-             clear_qp_mutex (p1mask | p2mask);
-           }
        }
     }
   /* Look for mov imm insns into GRs.  */
@@ -9822,14 +10019,25 @@ 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;
+               }
            }
          /* Make sure gas doesn't get rid of local symbols that are used
             in relocs.  */
@@ -9931,12 +10139,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,
@@ -9954,6 +10166,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.  */
@@ -9982,11 +10208,27 @@ 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
@@ -9997,7 +10239,6 @@ ia64_cons_fix_new (f, where, nbytes, exp)
            code = BFD_RELOC_IA64_IPLTMSB;
          else
            code = BFD_RELOC_IA64_IPLTLSB;
-
          exp->X_op = O_symbol;
          break;
        }
@@ -10008,11 +10249,12 @@ ia64_cons_fix_new (f, where, nbytes, exp)
       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);
@@ -10074,6 +10316,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)
        {
@@ -10143,12 +10393,75 @@ ia64_gen_real_reloc_type (sym, r_type)
        }
       break;
 
-    case  FUNC_IPLT_RELOC:
-        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;
@@ -10176,8 +10489,6 @@ ia64_validate_fix (fix)
     default:
       break;
     }
-
-  return;
 }
 
 static void
@@ -10248,12 +10559,11 @@ fix_insn (fix, odesc, value)
 void
 md_apply_fix3 (fix, valP, seg)
      fixS *fix;
-     valueT * valP;
+     valueT *valP;
      segT seg ATTRIBUTE_UNUSED;
 {
   char *fixpos;
-  valueT value = * valP;
-  int adjust = 0;
+  valueT value = *valP;
 
   fixpos = fix->fx_frag->fr_literal + fix->fx_where;
 
@@ -10263,22 +10573,18 @@ md_apply_fix3 (fix, valP, 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:
@@ -10287,8 +10593,9 @@ md_apply_fix3 (fix, valP, seg)
     }
   if (fix->fx_addsy)
     {
-      if (fix->fx_r_type == (int) BFD_RELOC_UNUSED)
+      switch (fix->fx_r_type)
        {
+       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,
@@ -10296,12 +10603,22 @@ md_apply_fix3 (fix, valP, seg)
                        elf64_ia64_operands[fix->tc_fix_data.opnd].desc);
          fix->fx_done = 1;
          return;
-       }
 
-      /* ??? 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;
+       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;
+       }
     }
   else if (fix->tc_fix_data.opnd == IA64_OPND_NIL)
     {
@@ -10358,7 +10675,6 @@ md_atof (type, lit, size)
      int *size;
 {
   LITTLENUM_TYPE words[MAX_LITTLENUMS];
-  LITTLENUM_TYPE *word;
   char *t;
   int prec;
 
@@ -10393,26 +10709,19 @@ 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.  */
@@ -10436,9 +10745,6 @@ ia64_handle_align (fragp)
      fragS *fragp;
 {
   /* Use mfi bundle of nops with no stop bits.  */
-  static const unsigned char be_nop[]
-    = { 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
-       0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c};
   static const unsigned char le_nop[]
     = { 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
        0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00};
@@ -10463,6 +10769,214 @@ ia64_handle_align (fragp)
       fragp->fr_fix += fix;
     }
 
-  memcpy (p, (target_big_endian ? be_nop : le_nop), 16);
+  /* Instruction bundles are always little-endian.  */
+  memcpy (p, 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.042939 seconds and 4 git commands to generate.