* dw2gencfi.c (dwcfi_seg_list): New struct.
authorNick Clifton <nickc@redhat.com>
Tue, 26 Apr 2011 15:28:08 +0000 (15:28 +0000)
committerNick Clifton <nickc@redhat.com>
Tue, 26 Apr 2011 15:28:08 +0000 (15:28 +0000)
(dwcfi_hash): New static hash variable.
(get_debugseg_name): New.
(alloc_debugseg_item): New.
(make_debug_seg): New.
(dwcfi_hash_insert): New.
(dwcfi_hash_find): New.
(dwcfi_hash_find_or_make): New.
(cfi_insn_data): New member cur_seg.
(cie_entry): Likewise.
(fde_entry): New cseg and handled members.
(alloc_fde_entry): Initialize cseg member.
(alloc_cfi_insn_data): Initialize cur_seg member.
(dot_cfi_sections): Compare for beginning of
section names via strncmp.
(get_cfi_seg): New.
(cfi_finish): Treat link-once sections.
(is_now_linkonce_segment): New local helper.
(output_cie): Ignore cie entries not member of current
segment.
(output_fde): Likewise.
(select_cie_for_fde): Likewise.
(cfi_change_reg_numbers): Add new argument for current segment
and ignore insn elements, if not part of current segment.
* ehopt.c (get_cie_info): Use strncmp for
section name matching.
(heck_eh_frame): Likewise.

* coffcode.h (sec_to_styp_flags): Allow linkonce for
debugging sections.

* scripttempl/pe.sc: Handle .eh_frame($|.)* sections.
* scripttempl/pep.sc: Likewise.

* ld-pe/pe.exp: Add cfi/cfi32 tests.
* ld-pe/cfi.d: New.
* ld-pe/cfi32.d: New.
* ld-pe/cfia.s: New.
* ld-pe/cfib.s: New.

14 files changed:
bfd/ChangeLog
bfd/coffcode.h
gas/ChangeLog
gas/dw2gencfi.c
gas/ehopt.c
ld/ChangeLog
ld/scripttempl/pe.sc
ld/scripttempl/pep.sc
ld/testsuite/ChangeLog
ld/testsuite/ld-pe/cfi.d [new file with mode: 0644]
ld/testsuite/ld-pe/cfi32.d [new file with mode: 0644]
ld/testsuite/ld-pe/cfia.s [new file with mode: 0644]
ld/testsuite/ld-pe/cfib.s [new file with mode: 0644]
ld/testsuite/ld-pe/pe.exp

index 7a4b5bd9d2bbab4ec5b3f5bd56b5ab5778f90af7..93cdda01b4ea23f41d0cb35235bf052b43df4a99 100644 (file)
@@ -1,3 +1,8 @@
+2011-04-26  Kai Tietz  <ktietz@redhat.com>
+
+       * coffcode.h (sec_to_styp_flags): Allow linkonce for
+       debugging sections.
+
 2011-04-26  Tristan Gingold  <gingold@adacore.com>
 
        * coff64-rs6000.c: Convert to ISO-C.  Remove PARAMS and PTR macros.
index 9db86b5be6097b84f3aafa0436e45a0f28069c5d..b8b856efc94f83a72d6db52faf3e42799407ab7c 100644 (file)
@@ -658,7 +658,10 @@ sec_to_styp_flags (const char *sec_name, flagword sec_flags)
 
   /* FIXME: There is no gas syntax to specify the debug section flag.  */
   if (is_dbg)
-      sec_flags = SEC_DEBUGGING | SEC_READONLY;
+    {
+      sec_flags &= (SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD);
+      sec_flags |= SEC_DEBUGGING | SEC_READONLY;
+    }
 
   /* skip LOAD */
   /* READONLY later */
index 9721288e967ea5b3143c99c1a97bb78fe608b200..beb3847b0a684f81dc4f813a1c1da2a7238961b3 100644 (file)
@@ -1,3 +1,33 @@
+2011-04-26  Kai Tietz  <ktietz@redhat.com>
+
+       * dw2gencfi.c (dwcfi_seg_list): New struct.
+       (dwcfi_hash): New static hash variable.
+       (get_debugseg_name): New.
+       (alloc_debugseg_item): New.
+       (make_debug_seg): New.
+       (dwcfi_hash_insert): New.
+       (dwcfi_hash_find): New.
+       (dwcfi_hash_find_or_make): New.
+       (cfi_insn_data): New member cur_seg.
+       (cie_entry): Likewise.
+       (fde_entry): New cseg and handled members.
+       (alloc_fde_entry): Initialize cseg member.
+       (alloc_cfi_insn_data): Initialize cur_seg member.
+       (dot_cfi_sections): Compare for beginning of
+       section names via strncmp.
+       (get_cfi_seg): New.
+       (cfi_finish): Treat link-once sections.
+       (is_now_linkonce_segment): New local helper.
+       (output_cie): Ignore cie entries not member of current
+       segment.
+       (output_fde): Likewise.
+       (select_cie_for_fde): Likewise.
+       (cfi_change_reg_numbers): Add new argument for current segment
+       and ignore insn elements, if not part of current segment.
+       * ehopt.c (get_cie_info): Use strncmp for
+       section name matching.
+       (heck_eh_frame): Likewise.
+
 2011-04-20  Catherine Moore  <clm@codesourcery.com>
             David Ung <davidu@mips.com>
 
@@ -11,7 +41,7 @@
        (nops_for_24k): New.
        (nops_for_insn): Call nops_for_24k.
        (append_insn): Move O_constant expression handling.
-       
+
 2011-04-20  Alan Modra  <amodra@gmail.com>
 
        * hash.c (set_gas_hash_table_size): Use bfd_hash_set_default_size.
index 7a051e35c3b31e76254205475b6305e8c8235445..8f6300d2a43fd7b9e66cf41c38808702aa1fba40 100644 (file)
@@ -1,5 +1,5 @@
 /* dw2gencfi.c - Support for generating Dwarf2 CFI information.
-   Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
    Contributed by Michal Ludvig <mludvig@suse.cz>
 
@@ -37,7 +37,7 @@
 #endif
 
 #ifndef CFI_DIFF_LSDA_OK
-# define CFI_DIFF_LSDA_OK CFI_DIFF_EXPR_OK
+#define CFI_DIFF_LSDA_OK CFI_DIFF_EXPR_OK
 #endif
 
 #if CFI_DIFF_EXPR_OK == 1 && CFI_DIFF_LSDA_OK == 0
 
 /* We re-use DWARF2_LINE_MIN_INSN_LENGTH for the code alignment field
    of the CIE.  Default to 1 if not otherwise specified.  */
-#ifndef  DWARF2_LINE_MIN_INSN_LENGTH
-# define DWARF2_LINE_MIN_INSN_LENGTH 1
+#ifndef DWARF2_LINE_MIN_INSN_LENGTH
+#define DWARF2_LINE_MIN_INSN_LENGTH 1
 #endif
 
 /* By default, use 32-bit relocations from .eh_frame into .text.  */
 #ifndef DWARF2_FDE_RELOC_SIZE
-# define DWARF2_FDE_RELOC_SIZE 4
+#define DWARF2_FDE_RELOC_SIZE 4
 #endif
 
 /* By default, use a read-only .eh_frame section.  */
 #ifndef DWARF2_EH_FRAME_READ_ONLY
-# define DWARF2_EH_FRAME_READ_ONLY SEC_READONLY
+#define DWARF2_EH_FRAME_READ_ONLY SEC_READONLY
 #endif
 
 #ifndef EH_FRAME_ALIGNMENT
-# define EH_FRAME_ALIGNMENT (bfd_get_arch_size (stdoutput) == 64 ? 3 : 2)
+#define EH_FRAME_ALIGNMENT (bfd_get_arch_size (stdoutput) == 64 ? 3 : 2)
 #endif
 
 #ifndef tc_cfi_frame_initial_instructions
-# define tc_cfi_frame_initial_instructions() ((void)0)
+#define tc_cfi_frame_initial_instructions() ((void)0)
 #endif
 
 #ifndef DWARF2_FORMAT
-# define DWARF2_FORMAT(SEC) dwarf2_format_32bit
+#define DWARF2_FORMAT(SEC) dwarf2_format_32bit
 #endif
 
 #ifndef DWARF2_ADDR_SIZE
-# define DWARF2_ADDR_SIZE(bfd) (bfd_arch_bits_per_address (bfd) / 8)
+#define DWARF2_ADDR_SIZE(bfd) (bfd_arch_bits_per_address (bfd) / 8)
 #endif
 
+/* Private segment collection list.  */
+struct dwcfi_seg_list
+{
+  segT   seg;
+  int    subseg;
+  char * seg_name;
+};
+
+#define FRAME_NAME ".eh_frame"
+
+static struct hash_control *dwcfi_hash;
+
+/* Build based on segment the derived .debug_...
+   segment name containing origin segment's postfix name part.  */
+
+static char *
+get_debugseg_name (segT seg, const char *base_name)
+{
+  const char *name;
+
+  if (!seg)
+    name = "";
+  else
+    {
+      const char * dollar;
+      const char * dot;
+
+      name = bfd_get_section_name (stdoutput, seg);
+
+      dollar = strchr (name, '$');
+      dot = strchr (name + 1, '.');
+
+      if (!dollar && !dot)
+       name = "";
+      else if (!dollar)
+       name = dot;
+      else if (!dot)
+       name = dollar;
+      else if (dot < dollar)
+       name = dot;
+      else
+       name = dollar;
+    }
+
+  return concat (base_name, name, NULL);
+}
+
+/* Allocate a dwcfi_seg_list structure.  */
+
+static struct dwcfi_seg_list *
+alloc_debugseg_item (segT seg, int subseg, char *name)
+{
+  struct dwcfi_seg_list *r;
+
+  r = (struct dwcfi_seg_list *)
+    xmalloc (sizeof (struct dwcfi_seg_list) + strlen (name));
+  r->seg = seg;
+  r->subseg = subseg;
+  r->seg_name = name;
+  return r;
+}
+
+static segT
+is_now_linkonce_segment (void)
+{
+#if defined (TE_PE) || defined (TE_PEP)
+  if ((bfd_get_section_flags (stdoutput, now_seg)
+       & (SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD
+         | SEC_LINK_DUPLICATES_ONE_ONLY | SEC_LINK_DUPLICATES_SAME_SIZE
+         | SEC_LINK_DUPLICATES_SAME_CONTENTS)) != 0)
+    return now_seg;
+#endif
+  return NULL;
+}
+
+/* Generate debug... segment with same linkonce properties
+   of based segment.  */
+
+static segT
+make_debug_seg (segT cseg, char *name, int sflags)
+{
+  segT save_seg = now_seg;
+  int save_subseg = now_subseg;
+  segT r;
+  flagword flags;
+
+  r = subseg_new (name, 0);
+
+  /* Check if code segment is marked as linked once.  */
+  if (!cseg)
+    flags = 0;
+  else
+    flags = bfd_get_section_flags (stdoutput, cseg)
+      & (SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD
+         | SEC_LINK_DUPLICATES_ONE_ONLY | SEC_LINK_DUPLICATES_SAME_SIZE
+         | SEC_LINK_DUPLICATES_SAME_CONTENTS);
+
+  /* Add standard section flags.  */
+  flags |= sflags;
+
+  /* Apply possibly linked once flags to new generated segment, too.  */
+  if (!bfd_set_section_flags (stdoutput, r, flags))
+    as_bad (_("bfd_set_section_flags: %s"),
+           bfd_errmsg (bfd_get_error ()));
+
+  /* Restore to previous segment.  */
+  if (save_seg != NULL)
+    subseg_set (save_seg, save_subseg);
+  return r;
+}
+
+static void
+dwcfi_hash_insert (const char *name, struct dwcfi_seg_list *item)
+{
+  const char *error_string;
+
+  if ((error_string = hash_jam (dwcfi_hash, name, (char *) item)))
+    as_fatal (_("Inserting \"%s\" into structure table failed: %s"),
+             name, error_string);
+}
+
+static struct dwcfi_seg_list *
+dwcfi_hash_find (char *name)
+{
+  return (struct dwcfi_seg_list *) hash_find (dwcfi_hash, name);
+}
+
+static struct dwcfi_seg_list *
+dwcfi_hash_find_or_make (segT cseg, const char *base_name, int flags)
+{
+  struct dwcfi_seg_list *item;
+  char *name;
+
+  /* Initialize dwcfi_hash once.  */
+  if (!dwcfi_hash)
+    dwcfi_hash = hash_new ();
+
+  name = get_debugseg_name (cseg, base_name);
+
+  item = dwcfi_hash_find (name);
+  if (!item)
+    {
+      item = alloc_debugseg_item (make_debug_seg (cseg, name, flags), 0, name);
+
+      dwcfi_hash_insert (item->seg_name, item);
+    }
+  else
+    free (name);
+
+  return item;
+}
+
 /* ??? Share this with dwarf2cfg.c.  */
 #ifndef TC_DWARF2_EMIT_OFFSET
 #define TC_DWARF2_EMIT_OFFSET  generic_dwarf2_emit_offset
@@ -94,7 +246,8 @@ generic_dwarf2_emit_offset (symbolS *symbol, unsigned int size)
 }
 #endif
 
-struct cfi_escape_data {
+struct cfi_escape_data
+{
   struct cfi_escape_data *next;
   expressionS exp;
 };
@@ -102,14 +255,18 @@ struct cfi_escape_data {
 struct cfi_insn_data
 {
   struct cfi_insn_data *next;
+  segT cur_seg;
   int insn;
-  union {
-    struct {
+  union
+  {
+    struct
+    {
       unsigned reg;
       offsetT offset;
     } ri;
 
-    struct {
+    struct
+    {
       unsigned reg1;
       unsigned reg2;
     } rr;
@@ -117,14 +274,16 @@ struct cfi_insn_data
     unsigned r;
     offsetT i;
 
-    struct {
+    struct
+    {
       symbolS *lab1;
       symbolS *lab2;
     } ll;
 
     struct cfi_escape_data *esc;
 
-    struct {
+    struct
+    {
       unsigned reg, encoding;
       expressionS exp;
     } ea;
@@ -134,6 +293,7 @@ struct cfi_insn_data
 struct fde_entry
 {
   struct fde_entry *next;
+  segT cseg;
   symbolS *start_address;
   symbolS *end_address;
   struct cfi_insn_data *data;
@@ -144,11 +304,13 @@ struct fde_entry
   expressionS lsda;
   unsigned int return_column;
   unsigned int signal_frame;
+  int handled;
 };
 
 struct cie_entry
 {
   struct cie_entry *next;
+  segT cur_seg;
   symbolS *start_address;
   unsigned int return_column;
   unsigned int signal_frame;
@@ -158,8 +320,8 @@ struct cie_entry
   struct cfi_insn_data *first, *last;
 };
 
-
 /* List of FDE entries.  */
+
 static struct fde_entry *all_fde_data;
 static struct fde_entry **last_fde_data = &all_fde_data;
 
@@ -195,7 +357,8 @@ alloc_fde_entry (void)
   frchain_now->frch_cfi_data->cur_fde_data = fde;
   *last_fde_data = fde;
   last_fde_data = &fde->next;
-
+  fde->cseg = is_now_linkonce_segment ();
+  fde->handled = 0;
   fde->last = &fde->data;
   fde->return_column = DWARF2_DEFAULT_RETURN_COLUMN;
   fde->per_encoding = DW_EH_PE_omit;
@@ -219,13 +382,14 @@ alloc_cfi_insn_data (void)
 
   *cur_fde_data->last = insn;
   cur_fde_data->last = &insn->next;
+  insn->cur_seg = is_now_linkonce_segment ();
 
   return insn;
 }
 
 /* Construct a new FDE structure that begins at LABEL.  */
 
-void 
+void
 cfi_new_fde (symbolS *label)
 {
   struct fde_entry *fde = alloc_fde_entry ();
@@ -235,7 +399,7 @@ cfi_new_fde (symbolS *label)
 
 /* End the currently open FDE.  */
 
-void 
+void
 cfi_end_fde (symbolS *label)
 {
   frchain_now->frch_cfi_data->cur_fde_data->end_address = label;
@@ -254,7 +418,7 @@ cfi_set_return_column (unsigned regno)
 /* Universal functions to store new instructions.  */
 
 static void
-cfi_add_CFA_insn(int insn)
+cfi_add_CFA_insn (int insn)
 {
   struct cfi_insn_data *insn_ptr = alloc_cfi_insn_data ();
 
@@ -471,7 +635,7 @@ cfi_parse_separator (void)
 
 #ifndef tc_parse_to_dw2regnum
 static void
-tc_parse_to_dw2regnum(expressionS *exp)
+tc_parse_to_dw2regnum (expressionS *exp)
 {
 # ifdef tc_regname_to_dw2regnum
   SKIP_WHITESPACE ();
@@ -853,7 +1017,7 @@ dot_cfi_val_encoded_addr (int ignored ATTRIBUTE_UNUSED)
 
   insn_ptr = alloc_cfi_insn_data ();
   insn_ptr->insn = CFI_val_encoded_addr;
-  
+
   insn_ptr->u.ea.reg = cfi_parse_reg ();
 
   cfi_parse_separator ();
@@ -916,9 +1080,10 @@ dot_cfi_sections (int ignored ATTRIBUTE_UNUSED)
        name = input_line_pointer;
        c = get_symbol_end ();
 
-       if (strcmp (name, ".eh_frame") == 0)
+       if (strncmp (name, ".eh_frame", sizeof ".eh_frame") == 0
+           && name[9] != '_')
          sections |= CFI_EMIT_eh_frame;
-       else if (strcmp (name, ".debug_frame") == 0)
+       else if (strncmp (name, ".debug_frame", sizeof ".debug_frame") == 0)
          sections |= CFI_EMIT_debug_frame;
        else
          {
@@ -1250,7 +1415,7 @@ output_cfi_insn (struct cfi_insn_data *insn)
        emit_expr (&insn->u.ea.exp, encoding_size);
       }
       break;
-      
+
     default:
       abort ();
     }
@@ -1384,8 +1549,14 @@ output_cie (struct cie_entry *cie, bfd_boolean eh_frame, int align)
     out_one (enc);
 
   if (cie->first)
-    for (i = cie->first; i != cie->last; i = i->next)
-      output_cfi_insn (i);
+    {
+      for (i = cie->first; i != cie->last; i = i->next)
+        {
+         if (i->cur_seg != cie->cur_seg)
+           continue;
+         output_cfi_insn (i);
+       }
+    }
 
   frag_align (align, DW_CFA_nop, 0);
   symbol_set_value_now (end_address);
@@ -1492,7 +1663,10 @@ output_fde (struct fde_entry *fde, struct cie_entry *cie,
     }
 
   for (; first; first = first->next)
-    output_cfi_insn (first);
+    {
+      if (first->cur_seg == fde->cseg)
+        output_cfi_insn (first);
+    }
 
   frag_align (align, DW_CFA_nop, 0);
   symbol_set_value_now (end_address);
@@ -1507,7 +1681,8 @@ select_cie_for_fde (struct fde_entry *fde, bfd_boolean eh_frame,
 
   for (cie = cie_root; cie; cie = cie->next)
     {
-      if (cie->return_column != fde->return_column
+      if (cie->cur_seg != fde->cseg
+          || cie->return_column != fde->return_column
          || cie->signal_frame != fde->signal_frame
          || cie->per_encoding != fde->per_encoding
          || cie->lsda_encoding != fde->lsda_encoding)
@@ -1605,6 +1780,7 @@ select_cie_for_fde (struct fde_entry *fde, bfd_boolean eh_frame,
   cie = (struct cie_entry *) xmalloc (sizeof (struct cie_entry));
   cie->next = cie_root;
   cie_root = cie;
+  cie->cur_seg = fde->cseg;
   cie->return_column = fde->return_column;
   cie->signal_frame = fde->signal_frame;
   cie->per_encoding = fde->per_encoding;
@@ -1629,130 +1805,189 @@ select_cie_for_fde (struct fde_entry *fde, bfd_boolean eh_frame,
 
 #ifdef md_reg_eh_frame_to_debug_frame
 static void
-cfi_change_reg_numbers (struct cfi_insn_data *insn)
+cfi_change_reg_numbers (struct cfi_insn_data *insn, segT ccseg)
 {
   for (; insn; insn = insn->next)
-    switch (insn->insn)
-      {
-      case DW_CFA_advance_loc:
-      case DW_CFA_def_cfa_offset:
-      case DW_CFA_remember_state:
-      case DW_CFA_restore_state:
-      case DW_CFA_GNU_window_save:
-      case CFI_escape:
-       break;
+    {
+      if (insn->cur_seg != ccseg)
+        continue;
+      switch (insn->insn)
+       {
+       case DW_CFA_advance_loc:
+       case DW_CFA_def_cfa_offset:
+       case DW_CFA_remember_state:
+       case DW_CFA_restore_state:
+       case DW_CFA_GNU_window_save:
+       case CFI_escape:
+         break;
 
-      case DW_CFA_def_cfa:
-      case DW_CFA_offset:
-       insn->u.ri.reg = md_reg_eh_frame_to_debug_frame (insn->u.ri.reg);
-       break;
+       case DW_CFA_def_cfa:
+       case DW_CFA_offset:
+         insn->u.ri.reg = md_reg_eh_frame_to_debug_frame (insn->u.ri.reg);
+         break;
 
-      case DW_CFA_def_cfa_register:
-      case DW_CFA_undefined:
-      case DW_CFA_same_value:
-      case DW_CFA_restore:
-       insn->u.r = md_reg_eh_frame_to_debug_frame (insn->u.r);
-       break;
+       case DW_CFA_def_cfa_register:
+       case DW_CFA_undefined:
+       case DW_CFA_same_value:
+       case DW_CFA_restore:
+         insn->u.r = md_reg_eh_frame_to_debug_frame (insn->u.r);
+         break;
 
-      case DW_CFA_register:
-       insn->u.rr.reg1 = md_reg_eh_frame_to_debug_frame (insn->u.rr.reg1);
-       insn->u.rr.reg2 = md_reg_eh_frame_to_debug_frame (insn->u.rr.reg2);
-       break;
+       case DW_CFA_register:
+         insn->u.rr.reg1 = md_reg_eh_frame_to_debug_frame (insn->u.rr.reg1);
+         insn->u.rr.reg2 = md_reg_eh_frame_to_debug_frame (insn->u.rr.reg2);
+         break;
 
-      case CFI_val_encoded_addr:
-       insn->u.ea.reg = md_reg_eh_frame_to_debug_frame (insn->u.ea.reg);
-       break;
+       case CFI_val_encoded_addr:
+         insn->u.ea.reg = md_reg_eh_frame_to_debug_frame (insn->u.ea.reg);
+         break;
 
-      default:
-       abort ();
-      }
+       default:
+         abort ();
+       }
+    }
 }
 #else
-#define cfi_change_reg_numbers(insn) do { } while (0)
+#define cfi_change_reg_numbers(insn, cseg) do { } while (0)
 #endif
 
+static segT
+get_cfi_seg (segT cseg, const char *base, flagword flags, int align)
+{
+  struct dwcfi_seg_list *l;
+
+  l = dwcfi_hash_find_or_make (cseg, base, flags);
+
+  subseg_set (l->seg, l->subseg);
+  record_alignment (l->seg, align);
+  return l->seg;
+}
+
 void
 cfi_finish (void)
 {
-  segT cfi_seg;
+  struct cie_entry *cie, *cie_next;
+  segT cfi_seg, ccseg;
   struct fde_entry *fde;
-  int save_flag_traditional_format;
+  struct cfi_insn_data *first;
+  int save_flag_traditional_format, seek_next_seg;
 
   if (all_fde_data == 0)
     return;
 
   if ((cfi_sections & CFI_EMIT_eh_frame) != 0)
     {
-      /* Open .eh_frame section.  */
-      cfi_seg = subseg_new (".eh_frame", 0);
-      bfd_set_section_flags (stdoutput, cfi_seg,
-                            SEC_ALLOC | SEC_LOAD | SEC_DATA
-                            | DWARF2_EH_FRAME_READ_ONLY);
-      subseg_set (cfi_seg, 0);
-      record_alignment (cfi_seg, EH_FRAME_ALIGNMENT);
-
-#ifdef md_fix_up_eh_frame
-      md_fix_up_eh_frame (cfi_seg);
-#endif
-
       /* Make sure check_eh_frame doesn't do anything with our output.  */
       save_flag_traditional_format = flag_traditional_format;
       flag_traditional_format = 1;
 
-      for (fde = all_fde_data; fde ; fde = fde->next)
-       {
-         struct cfi_insn_data *first;
-         struct cie_entry *cie;
-
-         if (fde->end_address == NULL)
+      do
+        {
+         ccseg = NULL;
+         cfi_seg = NULL;
+         seek_next_seg = 0;
+         for (cie = cie_root; cie; cie = cie_next)
            {
-             as_bad (_("open CFI at the end of file; missing .cfi_endproc directive"));
-             fde->end_address = fde->start_address;
+             cie_next = cie->next;
+             free ((void *) cie);
            }
+         cie_root = NULL;
 
-         cie = select_cie_for_fde (fde, TRUE, &first, 2);
-         output_fde (fde, cie, TRUE, first,
-                     fde->next == NULL ? EH_FRAME_ALIGNMENT : 2);
+         for (fde = all_fde_data; fde ; fde = fde->next)
+           {
+             if (fde->handled != 0)
+               continue;
+             if (seek_next_seg && fde->cseg != ccseg)
+               {
+                 seek_next_seg = 2;
+                 continue;
+               }
+             if (!seek_next_seg)
+               {
+                 ccseg = fde->cseg;
+                 /* Open .eh_frame section.  */
+                 cfi_seg = get_cfi_seg (ccseg, ".eh_frame",
+                                        SEC_ALLOC | SEC_LOAD | SEC_DATA
+                                        | DWARF2_EH_FRAME_READ_ONLY,
+                                        EH_FRAME_ALIGNMENT);
+#ifdef md_fix_up_eh_frame
+                 md_fix_up_eh_frame (cfi_seg);
+#endif
+                 seek_next_seg = 1;
+               }
+             fde->handled = 1;
+
+             if (fde->end_address == NULL)
+               {
+                 as_bad (_("open CFI at the end of file; missing .cfi_endproc directive"));
+                 fde->end_address = fde->start_address;
+               }
+
+             cie = select_cie_for_fde (fde, TRUE, &first, 2);
+             output_fde (fde, cie, TRUE, first,
+                         fde->next == NULL ? EH_FRAME_ALIGNMENT : 2);
+           }
        }
+      while (seek_next_seg == 2);
+
+      for (fde = all_fde_data; fde ; fde = fde->next)
+        fde->handled = 0;
 
       flag_traditional_format = save_flag_traditional_format;
     }
 
   if ((cfi_sections & CFI_EMIT_debug_frame) != 0)
     {
-      struct cie_entry *cie, *cie_next;
       int alignment = ffs (DWARF2_ADDR_SIZE (stdoutput)) - 1;
 
-      for (cie = cie_root; cie; cie = cie_next)
-       {
-         cie_next = cie->next;
-         free ((void *) cie);
-       }
-      cie_root = NULL;
-
-      /* Open .debug_frame section.  */
-      cfi_seg = subseg_new (".debug_frame", 0);
-      bfd_set_section_flags (stdoutput, cfi_seg,
-                            SEC_READONLY | SEC_DEBUGGING);
-      subseg_set (cfi_seg, 0);
-      record_alignment (cfi_seg, alignment);
-
-      for (fde = all_fde_data; fde ; fde = fde->next)
-       {
-         struct cfi_insn_data *first;
-
-         if (fde->end_address == NULL)
+      do
+        {
+         ccseg = NULL;
+         cfi_seg = NULL;
+         seek_next_seg = 0;
+         for (cie = cie_root; cie; cie = cie_next)
            {
-             as_bad (_("open CFI at the end of file; missing .cfi_endproc directive"));
-             fde->end_address = fde->start_address;
+             cie_next = cie->next;
+             free ((void *) cie);
            }
+         cie_root = NULL;
 
-         fde->per_encoding = DW_EH_PE_omit;
-         fde->lsda_encoding = DW_EH_PE_omit;
-         cfi_change_reg_numbers (fde->data);
-         cie = select_cie_for_fde (fde, FALSE, &first, alignment);
-         output_fde (fde, cie, FALSE, first, alignment);
+         for (fde = all_fde_data; fde ; fde = fde->next)
+           {
+             if (fde->handled != 0)
+               continue;
+             if (seek_next_seg && fde->cseg != ccseg)
+               {
+                 seek_next_seg = 2;
+                 continue;
+               }
+             if (!seek_next_seg)
+               {
+                 ccseg = fde->cseg;
+                 /* Open .debug_frame section.  */
+                 cfi_seg = get_cfi_seg (ccseg, ".debug_frame",
+                                        SEC_READONLY | SEC_DEBUGGING,
+                                        alignment);
+                 seek_next_seg = 1;
+               }
+             fde->handled = 1;
+             if (fde->end_address == NULL)
+               {
+                 as_bad (_("open CFI at the end of file; missing .cfi_endproc directive"));
+                 fde->end_address = fde->start_address;
+               }
+
+             fde->per_encoding = DW_EH_PE_omit;
+             fde->lsda_encoding = DW_EH_PE_omit;
+             cfi_change_reg_numbers (fde->data, ccseg);
+             cie = select_cie_for_fde (fde, FALSE, &first, alignment);
+             output_fde (fde, cie, FALSE, first, alignment);
+           }
        }
+      while (seek_next_seg == 2);
+
+      for (fde = all_fde_data; fde ; fde = fde->next)
+        fde->handled = 0;
     }
 }
 
index c09eb15b4983f86f9884b5590dfafabbf1c2c1ec..70e1a00f4e29622372198bd57e684f20d999fdfc 100644 (file)
@@ -120,7 +120,7 @@ get_cie_info (struct cie_info *info)
 
   /* First make sure that the CIE Identifier Tag is 0/-1.  */
 
-  if (strcmp (segment_name (now_seg), ".debug_frame") == 0)
+  if (strncmp (segment_name (now_seg), ".debug_frame", 12) == 0)
     CIE_id = (char)0xff;
   else
     CIE_id = 0;
@@ -285,9 +285,10 @@ check_eh_frame (expressionS *exp, unsigned int *pnbytes)
 #endif
 
   /* Select the proper section data.  */
-  if (strcmp (segment_name (now_seg), ".eh_frame") == 0)
+  if (strncmp (segment_name (now_seg), ".eh_frame", 9) == 0
+      && segment_name (now_seg)[9] != '_')
     d = &eh_frame_data;
-  else if (strcmp (segment_name (now_seg), ".debug_frame") == 0)
+  else if (strncmp (segment_name (now_seg), ".debug_frame", 12) == 0)
     d = &debug_frame_data;
   else
     return 0;
index b25a87f14780662e35e038fd025409a284fbb3b0..dfbb58219dbbdcd90b6a9889255911e06d0a5012 100644 (file)
@@ -1,3 +1,8 @@
+2011-04-26  Kai Tietz  <ktietz@redhat.com>
+
+       * scripttempl/pe.sc: Handle .eh_frame($|.)* sections.
+       * scripttempl/pep.sc: Likewise.
+
 2011-04-24  Alan Modra  <amodra@gmail.com>
 
        PR ld/12365
index 7d52cc542cf121f5803af764dc0137c17ed8a89a..a82d08c7b599c40a906531f3ec229d3d3ea266dd 100644 (file)
@@ -115,7 +115,7 @@ SECTIONS
 
   .eh_frame ${RELOCATING+BLOCK(__section_alignment__)} :
   {
-    *(.eh_frame)
+    *(.eh_frame*)
   }
 
   .pdata ${RELOCATING+BLOCK(__section_alignment__)} :
@@ -250,7 +250,7 @@ SECTIONS
 
   .debug_frame ${RELOCATING+BLOCK(__section_alignment__)} ${RELOCATING+(NOLOAD)} :
   {
-    *(.debug_frame)
+    *(.debug_frame*)
   }
 
   .debug_str ${RELOCATING+BLOCK(__section_alignment__)} ${RELOCATING+(NOLOAD)} :
index 8fa5f052d6beca135fb95a2e785f06596b43ac98..b8315c53f9ac4f709c20a17d6ebd498821b56b9c 100644 (file)
@@ -116,7 +116,7 @@ SECTIONS
 
   .eh_frame ${RELOCATING+BLOCK(__section_alignment__)} :
   {
-    *(.eh_frame)
+    *(.eh_frame*)
   }
 
   .pdata ${RELOCATING+BLOCK(__section_alignment__)} :
@@ -256,7 +256,7 @@ SECTIONS
 
   .debug_frame ${RELOCATING+BLOCK(__section_alignment__)} ${RELOCATING+(NOLOAD)} :
   {
-    *(.debug_frame)
+    *(.debug_frame*)
   }
 
   .debug_str ${RELOCATING+BLOCK(__section_alignment__)} ${RELOCATING+(NOLOAD)} :
index 7a09d41d62b0c901d0f7290577e2b68a06316f13..1fd011e380332f0ab7624b34ac1ddf989f16e838 100644 (file)
@@ -1,3 +1,11 @@
+2011-04-26  Kai Tietz  <ktietz@redhat.com>
+
+       * ld-pe/pe.exp: Add cfi/cfi32 tests.
+       * ld-pe/cfi.d: New.
+       * ld-pe/cfi32.d: New.
+       * ld-pe/cfia.s: New.
+       * ld-pe/cfib.s: New.
+
 2011-04-21  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR ld/12694
diff --git a/ld/testsuite/ld-pe/cfi.d b/ld/testsuite/ld-pe/cfi.d
new file mode 100644 (file)
index 0000000..6c5042b
--- /dev/null
@@ -0,0 +1,36 @@
+#source: cfia.s
+#source: cfib.s
+#ld: --file-align 1 --section-align 1
+#objdump: -Wf
+
+#...
+00000004 00000014 ffffffff CIE
+  Version:               1
+  Augmentation:          ""
+  Code alignment factor: 1
+  Data alignment factor: \-8
+  Return address column: 32
+
+  DW_CFA_def_cfa: r7 \(rsp\) ofs 8
+  DW_CFA_offset: r32 \(xmm15\) at cfa\-8
+  DW_CFA_nop
+  DW_CFA_nop
+  DW_CFA_nop
+  DW_CFA_nop
+  DW_CFA_nop
+  DW_CFA_nop
+
+0000001c 00000024 00000004 FDE cie=00000004 pc=.*
+  DW_CFA_advance_loc: 4 to .*
+  DW_CFA_def_cfa_offset: 16
+  DW_CFA_offset: r6 \(rbp\) at cfa\-16
+  DW_CFA_advance_loc: 4 to .*
+^  DW_CFA_def_cfa: r7 \(rsp\) ofs 8
+  DW_CFA_restore: r6 \(rbp\)
+  DW_CFA_nop
+  DW_CFA_nop
+  DW_CFA_nop
+  DW_CFA_nop
+  DW_CFA_nop
+  DW_CFA_nop
+#pass
diff --git a/ld/testsuite/ld-pe/cfi32.d b/ld/testsuite/ld-pe/cfi32.d
new file mode 100644 (file)
index 0000000..d13fb1a
--- /dev/null
@@ -0,0 +1,28 @@
+#source: cfia.s
+#source: cfib.s
+#ld: --file-align 1 --section-align 1
+#objdump: -Wf
+
+#...
+00000000 00000010 ffffffff CIE
+  Version:               1
+  Augmentation:          ""
+  Code alignment factor: 1
+  Data alignment factor: \-4
+  Return address column: 8
+
+  DW_CFA_def_cfa: r4 \(esp\) ofs 4
+  DW_CFA_offset: r8 \(eip\) at cfa\-4
+  DW_CFA_nop
+  DW_CFA_nop
+
+00000014 00000018 00000000 FDE cie=00000000 pc=.*
+  DW_CFA_advance_loc: 4 to .*
+  DW_CFA_def_cfa_offset: 16
+  DW_CFA_offset: r6 \(esi\) at cfa\-16
+  DW_CFA_advance_loc: 4 to .*
+  DW_CFA_def_cfa: r7 \(edi\) ofs 8
+  DW_CFA_restore: r6 \(esi\)
+  DW_CFA_nop
+  DW_CFA_nop
+#pass
diff --git a/ld/testsuite/ld-pe/cfia.s b/ld/testsuite/ld-pe/cfia.s
new file mode 100644 (file)
index 0000000..d1ea51d
--- /dev/null
@@ -0,0 +1,26 @@
+ .globl _mainCRTStartup
+ .globl _start
+ .text
+_mainCRTStartup:
+mainCRTStartup:
+_start:
+start:
+ .long -1
+
+ .cfi_sections .debug_frame
+ .section .text$abc,"x"
+ .linkonce discard
+ .align 2
+ .globl _tst
+ .def _tst; .scl 2; .type 32; .endef
+_tst:
+ .cfi_startproc
+ .long 0
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ .long 1
+ .cfi_def_cfa 7, 8
+ .cfi_restore 6
+ .long 2
+ .cfi_endproc
+
diff --git a/ld/testsuite/ld-pe/cfib.s b/ld/testsuite/ld-pe/cfib.s
new file mode 100644 (file)
index 0000000..9b761cf
--- /dev/null
@@ -0,0 +1,16 @@
+ .cfi_sections .debug_frame
+ .section .text$abc,"x"
+ .linkonce discard
+ .align 2
+ .globl _tst
+ .def _tst; .scl 2; .type 32; .endef
+_tst:
+ .cfi_startproc
+ .long 0
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ .long 1
+ .cfi_def_cfa 7, 8
+ .cfi_restore 6
+ .long 2
+ .cfi_endproc
index 183c5c6a4e43a88a9c3ae936ab6543e8d11ba484..c72c3b1f68ffcebf84695107264648c5eb697033 100644 (file)
@@ -77,6 +77,12 @@ run_dump_test "longsecn-5"
 run_dump_test "orphan"
 run_dump_test "orphan_nu"
 
+if {[istarget x86_64-*-mingw*] } {
+       run_dump_test "cfi"
+} elseif {[istarget i*86-*-cygwin*] || [istarget i*86-*-mingw*] } {
+       run_dump_test "cfi32"
+}
+
 set foreign_sym_test {
   {"non-C aligned common" "" "" {non-c-lang-syms.s}
    {{nm -C non-c-lang-syms.d}} "non-c-lang-syms.x"}