2004-10-25 H.J. Lu <hongjiu.lu@intel.com>
[binutils-gdb.git] / gas / config / tc-ia64.c
index 8c3756778f391ed9ae0f721f330eea86d0127add..b18b0ea0c856410e69afb163787383126e3e3c50 100644 (file)
@@ -1,5 +1,6 @@
 /* tc-ia64.c -- Assembler for the HP/Intel IA-64 architecture.
-   Copyright 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004
+   Free Software Foundation, Inc.
    Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
 
    This file is part of GAS, the GNU Assembler.
@@ -153,8 +154,12 @@ struct label_fix
   struct symbol *sym;
 };
 
+/* This is the endianness of the current section.  */
 extern int target_big_endian;
 
+/* This is the default endianness.  */
+static int default_big_endian = TARGET_BYTES_BIG_ENDIAN;
+
 void (*ia64_number_to_chars) PARAMS ((char *, valueT, int));
 
 static void ia64_float_to_chars_bigendian
@@ -693,6 +698,12 @@ static struct
   struct label_prologue_count * saved_prologue_counts;
 } unwind;
 
+/* The input value is a negated offset from psp, and specifies an address
+   psp - offset.  The encoded value is psp + 16 - (4 * offset).  Thus we
+   must add 16 and divide by 4 to get the encoded value.  */
+
+#define ENCODED_PSP_OFFSET(OFFSET) (((OFFSET) + 16) / 4)
+
 typedef void (*vbyte_func) PARAMS ((int, char *, char *));
 
 /* Forward declarations:  */
@@ -991,12 +1002,6 @@ ia64_elf_section_type (str, len)
   if (STREQ ("unwind"))
     return SHT_IA_64_UNWIND;
 
-  if (STREQ ("init_array"))
-    return SHT_INIT_ARRAY;
-
-  if (STREQ ("fini_array"))
-    return SHT_FINI_ARRAY;
-
   return -1;
 #undef STREQ
 }
@@ -1811,7 +1816,7 @@ output_rp_psprel (offset)
      unsigned int offset;
 {
   unw_rec_list *ptr = alloc_record (rp_psprel);
-  ptr->r.record.p.pspoff = offset / 4;
+  ptr->r.record.p.pspoff = ENCODED_PSP_OFFSET (offset);
   return ptr;
 }
 
@@ -1845,7 +1850,7 @@ output_pfs_psprel (offset)
      unsigned int offset;
 {
   unw_rec_list *ptr = alloc_record (pfs_psprel);
-  ptr->r.record.p.pspoff = offset / 4;
+  ptr->r.record.p.pspoff = ENCODED_PSP_OFFSET (offset);
   return ptr;
 }
 
@@ -1879,7 +1884,7 @@ output_preds_psprel (offset)
      unsigned int offset;
 {
   unw_rec_list *ptr = alloc_record (preds_psprel);
-  ptr->r.record.p.pspoff = offset / 4;
+  ptr->r.record.p.pspoff = ENCODED_PSP_OFFSET (offset);
   return ptr;
 }
 
@@ -1956,7 +1961,7 @@ output_spill_base (offset)
      unsigned int offset;
 {
   unw_rec_list *ptr = alloc_record (spill_base);
-  ptr->r.record.p.pspoff = offset / 4;
+  ptr->r.record.p.pspoff = ENCODED_PSP_OFFSET (offset);
   return ptr;
 }
 
@@ -1981,7 +1986,7 @@ output_unat_psprel (offset)
      unsigned int offset;
 {
   unw_rec_list *ptr = alloc_record (unat_psprel);
-  ptr->r.record.p.pspoff = offset / 4;
+  ptr->r.record.p.pspoff = ENCODED_PSP_OFFSET (offset);
   return ptr;
 }
 
@@ -2015,7 +2020,7 @@ output_lc_psprel (offset)
      unsigned int offset;
 {
   unw_rec_list *ptr = alloc_record (lc_psprel);
-  ptr->r.record.p.pspoff = offset / 4;
+  ptr->r.record.p.pspoff = ENCODED_PSP_OFFSET (offset);
   return ptr;
 }
 
@@ -2049,7 +2054,7 @@ output_fpsr_psprel (offset)
      unsigned int offset;
 {
   unw_rec_list *ptr = alloc_record (fpsr_psprel);
-  ptr->r.record.p.pspoff = offset / 4;
+  ptr->r.record.p.pspoff = ENCODED_PSP_OFFSET (offset);
   return ptr;
 }
 
@@ -2090,7 +2095,7 @@ output_priunat_psprel (offset)
      unsigned int offset;
 {
   unw_rec_list *ptr = alloc_record (priunat_psprel);
-  ptr->r.record.p.pspoff = offset / 4;
+  ptr->r.record.p.pspoff = ENCODED_PSP_OFFSET (offset);
   return ptr;
 }
 
@@ -2124,7 +2129,7 @@ output_bsp_psprel (offset)
      unsigned int offset;
 {
   unw_rec_list *ptr = alloc_record (bsp_psprel);
-  ptr->r.record.p.pspoff = offset / 4;
+  ptr->r.record.p.pspoff = ENCODED_PSP_OFFSET (offset);
   return ptr;
 }
 
@@ -2158,7 +2163,7 @@ output_bspstore_psprel (offset)
      unsigned int offset;
 {
   unw_rec_list *ptr = alloc_record (bspstore_psprel);
-  ptr->r.record.p.pspoff = offset / 4;
+  ptr->r.record.p.pspoff = ENCODED_PSP_OFFSET (offset);
   return ptr;
 }
 
@@ -2192,7 +2197,7 @@ output_rnat_psprel (offset)
      unsigned int offset;
 {
   unw_rec_list *ptr = alloc_record (rnat_psprel);
-  ptr->r.record.p.pspoff = offset / 4;
+  ptr->r.record.p.pspoff = ENCODED_PSP_OFFSET (offset);
   return ptr;
 }
 
@@ -2249,7 +2254,7 @@ output_spill_psprel (ab, reg, offset)
   unw_rec_list *ptr = alloc_record (spill_psprel);
   ptr->r.record.x.ab = ab;
   ptr->r.record.x.reg = reg;
-  ptr->r.record.x.pspoff = offset / 4;
+  ptr->r.record.x.pspoff = ENCODED_PSP_OFFSET (offset);
   return ptr;
 }
 
@@ -2276,7 +2281,7 @@ output_spill_psprel_p (ab, reg, offset, predicate)
   unw_rec_list *ptr = alloc_record (spill_psprel_p);
   ptr->r.record.x.ab = ab;
   ptr->r.record.x.reg = reg;
-  ptr->r.record.x.pspoff = offset / 4;
+  ptr->r.record.x.pspoff = ENCODED_PSP_OFFSET (offset);
   ptr->r.record.x.qp = predicate;
   return ptr;
 }
@@ -3293,7 +3298,7 @@ static char *special_linkonce_name[] =
   };
 
 static void
-start_unwind_section (const segT text_seg, int sec_index)
+start_unwind_section (const segT text_seg, int sec_index, int linkonce_empty)
 {
   /*
     Use a slightly ugly scheme to derive the unwind section names from
@@ -3355,6 +3360,8 @@ start_unwind_section (const segT text_seg, int sec_index)
       prefix = special_linkonce_name [sec_index - SPECIAL_SECTION_UNWIND];
       suffix += sizeof (".gnu.linkonce.t.") - 1;
     }
+  else if (linkonce_empty)
+    return;
 
   prefix_len = strlen (prefix);
   suffix_len = strlen (suffix);
@@ -3399,6 +3406,8 @@ start_unwind_section (const segT text_seg, int sec_index)
       bfd_set_section_flags (stdoutput, now_seg,
                             SEC_LOAD | SEC_ALLOC | SEC_READONLY);
     }
+
+  elf_linked_to_section (now_seg) = text_seg;
 }
 
 static void
@@ -3438,7 +3447,7 @@ generate_unwind_image (const segT text_seg)
       expressionS exp;
       bfd_reloc_code_real_type reloc;
 
-      start_unwind_section (text_seg, SPECIAL_SECTION_UNWIND_INFO);
+      start_unwind_section (text_seg, SPECIAL_SECTION_UNWIND_INFO, 0);
 
       /* Make sure the section has 4 byte alignment for ILP32 and
         8 byte alignment for LP64.  */
@@ -3479,6 +3488,8 @@ generate_unwind_image (const segT text_seg)
          unwind.personality_routine = 0;
        }
     }
+  else
+    start_unwind_section (text_seg, SPECIAL_SECTION_UNWIND_INFO, 1);
 
   free_saved_prologue_counts ();
   unwind.list = unwind.tail = unwind.current_entry = NULL;
@@ -4158,7 +4169,7 @@ dot_endp (dummy)
       subseg_set (md.last_text_seg, 0);
       unwind.proc_end = expr_build_dot ();
 
-      start_unwind_section (saved_seg, SPECIAL_SECTION_UNWIND);
+      start_unwind_section (saved_seg, SPECIAL_SECTION_UNWIND, 0);
 
       /* Make sure that section has 4 byte alignment for ILP32 and
          8 byte alignment for LP64.  */
@@ -4198,6 +4209,9 @@ dot_endp (dummy)
                            bytes_per_address);
 
     }
+  else
+    start_unwind_section (saved_seg, SPECIAL_SECTION_UNWIND, 1);
+
   subseg_set (saved_seg, saved_subseg);
 
   /* Parse names of main and alternate entry points and set symbol sizes.  */
@@ -4406,8 +4420,7 @@ dot_byteorder (byteorder)
   if (byteorder == -1)
     {
       if (seginfo->tc_segment_info_data.endian == 0)
-       seginfo->tc_segment_info_data.endian
-         = TARGET_BYTES_BIG_ENDIAN ? 1 : 2;
+       seginfo->tc_segment_info_data.endian = default_big_endian ? 1 : 2;
       byteorder = seginfo->tc_segment_info_data.endian == 1;
     }
   else
@@ -6129,6 +6142,7 @@ emit_one_bundle ()
   char mnemonic[16];
   fixS *fix;
   char *f;
+  int addr_mod;
 
   first = (md.curr_slot + NUM_SLOTS - md.num_slots_in_use) % NUM_SLOTS;
   know (first >= 0 & first < NUM_SLOTS);
@@ -6160,6 +6174,14 @@ emit_one_bundle ()
 
   f = frag_more (16);
 
+  /* Check to see if this bundle is at an offset that is a multiple of 16-bytes
+     from the start of the frag.  */
+  addr_mod = frag_now_fix () & 15;
+  if (frag_now->has_code && frag_now->insn_addr != addr_mod)
+    as_bad (_("instruction address is not a multiple of 16"));
+  frag_now->insn_addr = addr_mod;
+  frag_now->has_code = 1;
+
   /* now fill in slots with as many insns as possible:  */
   curr = first;
   idesc = md.slot[curr].idesc;
@@ -6474,9 +6496,12 @@ emit_one_bundle ()
   if (manual_bundling)
     {
       if (md.num_slots_in_use > 0)
-       as_bad_where (md.slot[curr].src_file, md.slot[curr].src_line,
-                     "`%s' does not fit into %s template",
-                     idesc->name, ia64_templ_desc[template].name);
+       {
+         as_bad_where (md.slot[curr].src_file, md.slot[curr].src_line,
+                       "`%s' does not fit into %s template",
+                       idesc->name, ia64_templ_desc[template].name);
+         --md.num_slots_in_use;
+       }
       else
        as_bad_where (md.slot[curr].src_file, md.slot[curr].src_line,
                      "Missing '}' at end of file");
@@ -6519,10 +6544,12 @@ md_parse_option (c, arg)
       else if (strcmp (arg, "le") == 0)
        {
          md.flags &= ~EF_IA_64_BE;
+         default_big_endian = 0;
        }
       else if (strcmp (arg, "be") == 0)
        {
          md.flags |= EF_IA_64_BE;
+         default_big_endian = 1;
        }
       else
        return 0;
@@ -6695,7 +6722,7 @@ md_begin ()
 
   /* Make sure function pointers get initialized.  */
   target_big_endian = -1;
-  dot_byteorder (TARGET_BYTES_BIG_ENDIAN);
+  dot_byteorder (default_big_endian);
 
   alias_hash = hash_new ();
   alias_name_hash = hash_new ();
@@ -9560,17 +9587,15 @@ remove_marked_resource (rs)
        insn_group_break (1, 0, 0);
       if (rs->insn_srlz < STATE_SRLZ)
        {
-         int oldqp = CURR_SLOT.qp_regno;
-         struct ia64_opcode *oldidesc = CURR_SLOT.idesc;
+         struct slot oldslot = CURR_SLOT;
          /* Manually jam a srlz.i insn into the stream */
-         CURR_SLOT.qp_regno = 0;
+         memset (&CURR_SLOT, 0, sizeof (CURR_SLOT));
          CURR_SLOT.idesc = ia64_find_opcode ("srlz.i");
          instruction_serialization ();
          md.curr_slot = (md.curr_slot + 1) % NUM_SLOTS;
          if (++md.num_slots_in_use >= NUM_SLOTS)
            emit_one_bundle ();
-         CURR_SLOT.qp_regno = oldqp;
-         CURR_SLOT.idesc = oldidesc;
+         CURR_SLOT = oldslot;
        }
       insn_group_break (1, 0, 0);
       break;
@@ -9583,17 +9608,15 @@ remove_marked_resource (rs)
       if (rs->data_srlz < STATE_STOP)
        insn_group_break (1, 0, 0);
       {
-       int oldqp = CURR_SLOT.qp_regno;
-       struct ia64_opcode *oldidesc = CURR_SLOT.idesc;
+       struct slot oldslot = CURR_SLOT;
        /* Manually jam a srlz.d insn into the stream */
-       CURR_SLOT.qp_regno = 0;
+       memset (&CURR_SLOT, 0, sizeof (CURR_SLOT));
        CURR_SLOT.idesc = ia64_find_opcode ("srlz.d");
        data_serialization ();
        md.curr_slot = (md.curr_slot + 1) % NUM_SLOTS;
        if (++md.num_slots_in_use >= NUM_SLOTS)
          emit_one_bundle ();
-       CURR_SLOT.qp_regno = oldqp;
-       CURR_SLOT.idesc = oldidesc;
+       CURR_SLOT = oldslot;
       }
       break;
     case IA64_DVS_IMPLIED:
@@ -11012,6 +11035,9 @@ ia64_float_to_chars_littleendian (char *lit, LITTLENUM_TYPE *words,
 void
 ia64_elf_section_change_hook  (void)
 {
+  if (elf_section_type (now_seg) == SHT_IA_64_UNWIND
+      && elf_linked_to_section (now_seg) == NULL)
+    elf_linked_to_section (now_seg) = text_section;
   dot_byteorder (-1);
 }