From 72b016b4ac0d7532a8f173fe3472e2e88ac49d45 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Tue, 26 Apr 2011 15:28:08 +0000 Subject: [PATCH] * 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. * 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. --- bfd/ChangeLog | 5 + bfd/coffcode.h | 5 +- gas/ChangeLog | 32 ++- gas/dw2gencfi.c | 461 ++++++++++++++++++++++++++++--------- gas/ehopt.c | 7 +- ld/ChangeLog | 5 + ld/scripttempl/pe.sc | 4 +- ld/scripttempl/pep.sc | 4 +- ld/testsuite/ChangeLog | 8 + ld/testsuite/ld-pe/cfi.d | 36 +++ ld/testsuite/ld-pe/cfi32.d | 28 +++ ld/testsuite/ld-pe/cfia.s | 26 +++ ld/testsuite/ld-pe/cfib.s | 16 ++ ld/testsuite/ld-pe/pe.exp | 6 + 14 files changed, 521 insertions(+), 122 deletions(-) create mode 100644 ld/testsuite/ld-pe/cfi.d create mode 100644 ld/testsuite/ld-pe/cfi32.d create mode 100644 ld/testsuite/ld-pe/cfia.s create mode 100644 ld/testsuite/ld-pe/cfib.s diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 7a4b5bd9d2b..93cdda01b4e 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,8 @@ +2011-04-26 Kai Tietz + + * coffcode.h (sec_to_styp_flags): Allow linkonce for + debugging sections. + 2011-04-26 Tristan Gingold * coff64-rs6000.c: Convert to ISO-C. Remove PARAMS and PTR macros. diff --git a/bfd/coffcode.h b/bfd/coffcode.h index 9db86b5be60..b8b856efc94 100644 --- a/bfd/coffcode.h +++ b/bfd/coffcode.h @@ -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 */ diff --git a/gas/ChangeLog b/gas/ChangeLog index 9721288e967..beb3847b0a6 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,33 @@ +2011-04-26 Kai Tietz + + * 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 David Ung @@ -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 * hash.c (set_gas_hash_table_size): Use bfd_hash_set_default_size. diff --git a/gas/dw2gencfi.c b/gas/dw2gencfi.c index 7a051e35c3b..8f6300d2a43 100644 --- a/gas/dw2gencfi.c +++ b/gas/dw2gencfi.c @@ -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 @@ -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 @@ -46,36 +46,188 @@ /* 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; } } diff --git a/gas/ehopt.c b/gas/ehopt.c index c09eb15b498..70e1a00f4e2 100644 --- a/gas/ehopt.c +++ b/gas/ehopt.c @@ -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; diff --git a/ld/ChangeLog b/ld/ChangeLog index b25a87f1478..dfbb58219db 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,8 @@ +2011-04-26 Kai Tietz + + * scripttempl/pe.sc: Handle .eh_frame($|.)* sections. + * scripttempl/pep.sc: Likewise. + 2011-04-24 Alan Modra PR ld/12365 diff --git a/ld/scripttempl/pe.sc b/ld/scripttempl/pe.sc index 7d52cc542cf..a82d08c7b59 100644 --- a/ld/scripttempl/pe.sc +++ b/ld/scripttempl/pe.sc @@ -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)} : diff --git a/ld/scripttempl/pep.sc b/ld/scripttempl/pep.sc index 8fa5f052d6b..b8315c53f9a 100644 --- a/ld/scripttempl/pep.sc +++ b/ld/scripttempl/pep.sc @@ -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)} : diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog index 7a09d41d62b..1fd011e3803 100644 --- a/ld/testsuite/ChangeLog +++ b/ld/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2011-04-26 Kai Tietz + + * 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 PR ld/12694 diff --git a/ld/testsuite/ld-pe/cfi.d b/ld/testsuite/ld-pe/cfi.d new file mode 100644 index 00000000000..6c5042bdd8b --- /dev/null +++ b/ld/testsuite/ld-pe/cfi.d @@ -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 index 00000000000..d13fb1a7535 --- /dev/null +++ b/ld/testsuite/ld-pe/cfi32.d @@ -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 index 00000000000..d1ea51d974d --- /dev/null +++ b/ld/testsuite/ld-pe/cfia.s @@ -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 index 00000000000..9b761cf6690 --- /dev/null +++ b/ld/testsuite/ld-pe/cfib.s @@ -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 diff --git a/ld/testsuite/ld-pe/pe.exp b/ld/testsuite/ld-pe/pe.exp index 183c5c6a4e4..c72c3b1f68f 100644 --- a/ld/testsuite/ld-pe/pe.exp +++ b/ld/testsuite/ld-pe/pe.exp @@ -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"} -- 2.30.2