* config/tc-ia64.h (md_elf_section_type): New macro.
authorRichard Henderson <rth@redhat.com>
Sat, 10 Feb 2001 01:42:04 +0000 (01:42 +0000)
committerRichard Henderson <rth@redhat.com>
Sat, 10 Feb 2001 01:42:04 +0000 (01:42 +0000)
        (ELF_TC_SPECIAL_SECTIONS): Drop .IA_64.unwind and .IA_64.unwind_info
        (they're now handled via ia64_elf_section_type.

        * config/tc-ia64.c (unwind): New members saved_text_seg,
        saved_text_subseg, and force_unwind_entry.
        (optimize_unw_records): New function to optimize away unnecessary
        unwind directives.
        (ia64_elf_section_type): New function.
        (output_unw_records): Generate unwind info only if the size is
        non-zero or if it's forced for some other reason (e.g.,
        handlerdata or a personality routine).
        (generate_unwind_image): Don't switch back to previous
        section---stay inside the unwind info section instead so that
        handlerdata that may follow goes into the right place.
        (dot_handlerdata): Force generation of unwind entry and save the
        current active text segment before generating unwind image.
        (dot_unwentry): Force generation of unwind entry.
        (dot_personality): Ditto.
        (dot_endp): Generate unwind table entry only if there is
        some unwind info or the unwind entry was forced.

        * config/tc-ia64.c (make_unw_section_name): New macro to form
        unwind section name.
        (generate_unwind_image): Add "text_name" argument.  Use it to
        form unwind section name.
        (dot_handlerdata): Determine current segment (section) name and
        pass it to generate_unwind_image().
        (dot_endp): Determine current segment (section) name and use
        it to determine the appropriate unwind section name.
        (ia64_md_do_align): Add missing ATTRIBUTE_UNUSED declarations to
        n, fill, and max arguments.

gas/ChangeLog
gas/config/tc-ia64.c
gas/config/tc-ia64.h

index f3f3800..6fbf67c 100644 (file)
@@ -1,3 +1,38 @@
+2001-02-08  David Mosberger  <davidm@hpl.hp.com>
+
+       * config/tc-ia64.h (md_elf_section_type): New macro.
+       (ELF_TC_SPECIAL_SECTIONS): Drop .IA_64.unwind and .IA_64.unwind_info
+       (they're now handled via ia64_elf_section_type.
+
+       * config/tc-ia64.c (unwind): New members saved_text_seg,
+       saved_text_subseg, and force_unwind_entry.
+       (optimize_unw_records): New function to optimize away unnecessary
+       unwind directives.
+       (ia64_elf_section_type): New function.
+       (output_unw_records): Generate unwind info only if the size is
+       non-zero or if it's forced for some other reason (e.g.,
+       handlerdata or a personality routine).
+       (generate_unwind_image): Don't switch back to previous
+       section---stay inside the unwind info section instead so that
+       handlerdata that may follow goes into the right place.
+       (dot_handlerdata): Force generation of unwind entry and save the
+       current active text segment before generating unwind image.
+       (dot_unwentry): Force generation of unwind entry.
+       (dot_personality): Ditto.
+       (dot_endp): Generate unwind table entry only if there is
+       some unwind info or the unwind entry was forced.
+
+       * config/tc-ia64.c (make_unw_section_name): New macro to form
+       unwind section name.
+       (generate_unwind_image): Add "text_name" argument.  Use it to
+       form unwind section name.
+       (dot_handlerdata): Determine current segment (section) name and
+       pass it to generate_unwind_image().
+       (dot_endp): Determine current segment (section) name and use
+       it to determine the appropriate unwind section name.
+       (ia64_md_do_align): Add missing ATTRIBUTE_UNUSED declarations to
+       n, fill, and max arguments.
+
 2001-02-09  Schwidefsky  <schwidefsky@de.ibm.com>
 
        * Makefile.am: Add linux target for S/390.
index 0b31a55..8f82739 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 (C) 1998, 1999, 2000, 2001 Free Software Foundation.
    Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
 
    This file is part of GAS, the GNU Assembler.
@@ -617,6 +617,9 @@ 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;
@@ -825,11 +828,28 @@ 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 *));
+
+/* 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)                 \
+  {                                                                       \
+    char *_prefix = special_section_name[special];                        \
+    size_t _prefix_len = strlen (_prefix), _text_len = strlen (text_name); \
+    char *_result = alloca (_prefix_len + _text_len + 1);                 \
+    memcpy(_result, _prefix, _prefix_len);                                \
+    memcpy(_result + _prefix_len, text_name, _text_len);                  \
+    _result[_prefix_len + _text_len] = '\0';                              \
+    result = _result;                                                     \
+  }                                                                       \
+while (0)
 
 /* Determine if application register REGNUM resides in the integer
    unit (as opposed to the memory unit).  */
@@ -874,6 +894,22 @@ ia64_elf_section_flags (flags, attr, type)
   return flags;
 }
 
+int
+ia64_elf_section_type (str, len)
+       const char *str;
+       size_t len;
+{
+  len = sizeof (ELF_STRING_ia64_unwind_info) - 1;
+  if (strncmp (str, ELF_STRING_ia64_unwind_info, len) == 0)
+    return SHT_PROGBITS;
+
+  len = sizeof (ELF_STRING_ia64_unwind) - 1;
+  if (strncmp (str, ELF_STRING_ia64_unwind, len) == 0)
+    return SHT_IA_64_UNWIND;
+
+  return -1;
+}
+
 static unsigned int
 set_regstack (ins, locs, outs, rots)
      unsigned int ins, locs, outs, rots;
@@ -2495,6 +2531,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
@@ -2681,6 +2736,9 @@ output_unw_records (list, ptr)
   int size, x, extra = 0;
   unsigned char *mem;
 
+  *ptr = NULL;
+
+  list = optimize_unw_records (list);
   fixup_unw_records (list);
   size = calc_record_size (list);
 
@@ -2688,24 +2746,33 @@ output_unw_records (list, ptr)
   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);
 
-  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);
+  if (size > 0 || unwind.force_unwind_entry)
+    {
+      unwind.force_unwind_entry = 0;
+
+      /* Add 8 for the header + 8 more bytes for the personality offset.  */
+      mem = xmalloc (size + extra + 16);
 
-  process_unw_records (list, output_vbyte_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);
 
-  *ptr = mem;
-  return size + extra + 16;
+      process_unw_records (list, output_vbyte_mem);
+
+      *ptr = mem;
+
+      size += extra + 16;
+    }
+  return size;
 }
 
 static int
@@ -3053,7 +3120,8 @@ dot_restorereg_p (dummy)
 }
 
 static int
-generate_unwind_image ()
+generate_unwind_image (text_name)
+     const char *text_name;
 {
   int size;
   unsigned char *unw_rec;
@@ -3071,8 +3139,13 @@ generate_unwind_image ()
   if (size != 0)
     {
       unsigned char *where;
+      char *sec_name;
       expressionS exp;
-      set_section ((char *) special_section_name[SPECIAL_SECTION_UNWIND_INFO]);
+
+      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 8 byte alignment.  */
       record_alignment (now_seg, 3);
@@ -3088,6 +3161,7 @@ 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)
        {
@@ -3098,7 +3172,6 @@ generate_unwind_image ()
                             &exp, 0, BFD_RELOC_IA64_LTOFF_FPTR64LSB);
          unwind.personality_routine = 0;
        }
-      obj_elf_previous (0);
     }
 
   free_list_records (unwind.list);
@@ -3111,7 +3184,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 +3208,7 @@ static void
 dot_unwentry (dummy)
      int dummy ATTRIBUTE_UNUSED;
 {
+  unwind.force_unwind_entry = 1;
   demand_empty_rest_of_line ();
 }
 
@@ -3583,6 +3673,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 ();
@@ -3685,57 +3776,115 @@ dot_endp (dummy)
   long where;
   segT saved_seg;
   subsegT saved_subseg;
+  const char *sec_name, *text_name;
 
-  saved_seg = now_seg;
-  saved_subseg = now_subseg;
+  if (unwind.saved_text_seg)
+    {
+      saved_seg = unwind.saved_text_seg;
+      saved_subseg = unwind.saved_text_subseg;
+      unwind.saved_text_seg = NULL;
+    }
+  else
+    {
+      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
+    _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 = "";
 
   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)
-    {
-      generate_unwind_image ();
-    }
+  /* If there wasn't a .handlerdata, we haven't generated an image yet.  */
+  if (!unwind.info)
+    generate_unwind_image (text_name);
 
-  subseg_set (md.last_text_seg, 0);
-  unwind.proc_end = expr_build_dot ();
-
-  set_section ((char *) special_section_name[SPECIAL_SECTION_UNWIND]);
+  if (unwind.info || unwind.force_unwind_entry)
+    {
+      subseg_set (md.last_text_seg, 0);
+      unwind.proc_end = expr_build_dot ();
 
-  /* Make sure the section has 8 byte alignment.  */
-  record_alignment (now_seg, 3);
+      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);
 
-  ptr = frag_more (24);
-  where = frag_now_fix () - 24;
-  bytes_per_address = bfd_arch_bits_per_address (stdoutput) / 8;
+      /* Make sure the section has 8 byte alignment.  */
+      record_alignment (now_seg, 3);
 
-  /* 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);
+      ptr = frag_more (24);
+      where = frag_now_fix () - 24;
+      bytes_per_address = bfd_arch_bits_per_address (stdoutput) / 8;
 
-  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);
+      /* 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);
 
-  if (unwind.info != 0)
-    {
       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_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);
   unwind.proc_start = unwind.proc_end = unwind.info = 0;
 }
@@ -9791,10 +9940,10 @@ md_section_align (seg, size)
 
 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 ();
index 05e30c6..f2b9fe4 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-ia64.h -- Header file for tc-ia64.c.
-   Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
    Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
 
    This file is part of GAS, the GNU Assembler.
@@ -82,6 +82,7 @@ extern void ia64_cons_fix_new PARAMS ((fragS *f, int where, int nbytes,
 extern void ia64_validate_fix PARAMS ((struct fix *fix));
 extern char * ia64_canonicalize_symbol_name PARAMS ((char *));
 extern flagword ia64_elf_section_flags PARAMS ((flagword, int, int));
+extern int ia64_elf_section_type PARAMS ((const char *, size_t len));
 extern long ia64_pcrel_from_section PARAMS ((struct fix *fix, segT sec));
 extern void ia64_md_do_align PARAMS ((int, const char *, int, int));
 extern void ia64_handle_align PARAMS ((fragS *f));
@@ -111,6 +112,7 @@ extern void ia64_handle_align PARAMS ((fragS *f));
 #define MD_PCREL_FROM_SECTION(fix,sec) ia64_pcrel_from_section (fix, sec)
 #define md_do_align(n,f,l,m,j)         ia64_md_do_align (n,f,l,m)
 #define HANDLE_ALIGN(f)                        ia64_handle_align (f)
+#define md_elf_section_type(str,len)   ia64_elf_section_type (str, len)
 
 #define MAX_MEM_FOR_RS_ALIGN_CODE  (15 + 16)
 
@@ -121,9 +123,7 @@ extern void ia64_handle_align PARAMS ((fragS *f));
 
 #define ELF_TC_SPECIAL_SECTIONS                                                   \
 { ".sbss",     SHT_NOBITS,     SHF_ALLOC + SHF_WRITE + SHF_IA_64_SHORT }, \
-{ ".sdata",    SHT_PROGBITS,   SHF_ALLOC + SHF_WRITE + SHF_IA_64_SHORT }, \
-{ ".IA_64.unwind",     SHT_IA_64_UNWIND,       SHF_ALLOC }, \
-{ ".IA_64.unwind_info",        SHT_PROGBITS,           SHF_ALLOC },
+{ ".sdata",    SHT_PROGBITS,   SHF_ALLOC + SHF_WRITE + SHF_IA_64_SHORT },
 
 #define DWARF2_LINE_MIN_INSN_LENGTH 1  /* so slot-multipliers can be 1 */