From patchwork Fri Aug 13 19:50:29 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Iain Sandoe X-Patchwork-Id: 61707 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 35208B70A8 for ; Sat, 14 Aug 2010 05:50:46 +1000 (EST) Received: (qmail 2695 invoked by alias); 13 Aug 2010 19:50:44 -0000 Received: (qmail 2669 invoked by uid 22791); 13 Aug 2010 19:50:41 -0000 X-SWARE-Spam-Status: No, hits=-2.0 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_NONE, TW_XF X-Spam-Check-By: sourceware.org Received: from c2bthomr13.btconnect.com (HELO c2bthomr13.btconnect.com) (213.123.20.131) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 13 Aug 2010 19:50:35 +0000 Received: from thor.office (host81-138-1-83.in-addr.btopenworld.com [81.138.1.83]) by c2bthomr13.btconnect.com with ESMTP id FTR11916; Fri, 13 Aug 2010 20:50:30 +0100 (BST) X-Mirapoint-IP-Reputation: reputation=Fair-1, source=Queried, refid=0001.0A0B0301.4C65A206.00C1, actions=tag Message-Id: <89584BF2-10CD-45DE-A4A5-4C2EE43396B3@sandoe-acoustics.co.uk> From: IainS To: GCC Patches Mime-Version: 1.0 (Apple Message framework v936) Subject: [Patch, _eh, dawin] Allow targets to suppress epilogues in _eh frames. Date: Fri, 13 Aug 2010 20:50:29 +0100 Cc: Richard Henderson , mrs@gcc.gnu.org X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org As discussed off list and in IRC with Richard, =----= Some (if not most) targets do not require the function epilogue in their _eh unwind frames. In fact, it breaks the darwin unwinder (PR41991) my original motivation for looking at this. However, as we went through the discussion it became apparent that this might have wider application than fixing a darwin bug, in saving some space in the eh. What this does is to use the existing DW_CFA_save/restore_state and a new DW_CFA_GNU_start_epilogue marker to suppress the emitting of function epilogues - when (a) we're emitting _eh and (b) the target requests suppression via a hook. The hook is a bool function to permit targets to choose whether to emit this data or not at run time rather than config time (the default hook does nothing). ---- The DW_CFA_GNU_start_epilogue marker is inserted under the circumstance that an epilogue is detected at the end of a function. The save/restore markers are not touched and deal with the case that we are mid-function. There is a debug print of # DW_CFA_GNU_start_epilogue to show where we are intercepting in the eh frames and not curtailing the debug_frames. I'd particularly welcome someone's eye over what's happening in the case of section switches (it seems to me that the skipping of mid- function save/restore is handled OK, but I'm not familiar with that code - and my main target(s) don't use that facility). ==== This has only been lightly tested on i686/powerpc-darwin9 (regtested on i686) - but it appears to restore Unwind functionality to the platform :) [gcj works again, Yay!] ==== so we get this in the _eh frame: LECIE1: .globl _main.eh _main.eh: LSFDE1: .set L$set$1,LEFDE1-LASFDE1 .long L$set$1 # FDE Length LASFDE1: .long LASFDE1-EH_frame1 # FDE CIE offset .long LFB1-. # FDE initial location .set L$set$2,LFE1-LFB1 .set L$set$5,LCFI4-LCFI1 .long L$set$5 .byte 0x83 # DW_CFA_offset, column 0x3 .byte 0x3 # uleb128 0x3 .byte 0x4 # DW_CFA_advance_loc4 .set L$set$6,LCFI6-LCFI4 .long L$set$6 # # DW_CFA_GNU_start_epilogue .align 2 and this in the _debug_frame: .section __DWARF,__debug_frame,regular,debug Lsection__debug_frame: Lframe0: .set L$set$7,LECIE0-LSCIE0 .long L$set$7 # Length of Common Information Entry LSCIE0: .byte 0x83 # DW_CFA_offset, column 0x3 .byte 0x3 # uleb128 0x3 .byte 0x4 # DW_CFA_advance_loc4 .set L$set$14,LCFI6-LCFI4 .long L$set$14 # # DW_CFA_GNU_start_epilogue .byte 0xc3 # DW_CFA_restore, column 0x3 .byte 0x4 # DW_CFA_advance_loc4 .set L$set$15,LCFI7-LCFI6 .long L$set$15 .byte 0xc # DW_CFA_def_cfa .byte 0x4 # uleb128 0x4 .byte 0x4 # uleb128 0x4 .byte 0xc5 # DW_CFA_restore, column 0x5 .align 2 LEFDE2: ===== thoughts? Iain Change notes (not a proper changelog, at this juncture) include/dwarf2.h : DW_CFA_GNU_start_epilogue new enum. dwarf2out.c: dwarf_cfi_name() recognize DW_CFA_GNU_start_epilogue static scope emit_cfa_start_epilogue new var. add_fde_cfi() : emit a marker for the epilogue start; dwarf2out_cfi_begin_epilogue (): note that we need to emit the epilogue start marker when the epilogue is at the end. dw_cfi_oprnd1_desc (): recognize DW_CFA_GNU_start_epilogue as a no-op. output_cfi(): print debug message for DW_CFA_GNU_start_epilogue emit_cfi_or_skip_epilogue (): New. output_fde () : use emit_cfi_or_skip_epilogue (); target.def: suppress_eh_epilogue_p (): New ASM Hook. === the remainder are the implementation on the darwin side: gcc/config/darwin.h (TARGET_ASM_SUPPRESS_EH_EPILOGUE_P): New gcc/config/darwin.c (darwin_asm_suppress_eh_epilogue_p): New. gcc/config/darwin-protos.h: Declare darwin_asm_suppress_eh_epilogue_p. ========== - =========== Index: include/dwarf2.h =================================================================== --- include/dwarf2.h (revision 163221) +++ include/dwarf2.h (working copy) @@ -854,7 +854,8 @@ enum dwarf_call_frame_info /* GNU extensions. */ DW_CFA_GNU_window_save = 0x2d, DW_CFA_GNU_args_size = 0x2e, - DW_CFA_GNU_negative_offset_extended = 0x2f + DW_CFA_GNU_negative_offset_extended = 0x2f, + DW_CFA_GNU_start_epilogue = 0x30 }; #define DW_CIE_ID 0xffffffff Index: gcc/dwarf2out.c =================================================================== --- gcc/dwarf2out.c (revision 163221) +++ gcc/dwarf2out.c (working copy) @@ -720,7 +724,9 @@ dwarf_cfi_name (unsigned int cfi_opc) return "DW_CFA_GNU_args_size"; case DW_CFA_GNU_negative_offset_extended: return "DW_CFA_GNU_negative_offset_extended"; - + case DW_CFA_GNU_start_epilogue: + return "DW_CFA_GNU_start_epilogue"; + default: return "DW_CFA_"; } @@ -801,6 +807,9 @@ dwarf2out_cfi_label (bool force) /* True if remember_state should be emitted before following CFI directive. */ static bool emit_cfa_remember; +/* True if start_epilogue should be emitted before following CFI directive. */ +static bool emit_cfa_start_epilogue; + /* Add CFI to the current fde at the PC value indicated by LABEL if specified, or to the CIE if LABEL is NULL. */ @@ -809,6 +818,17 @@ add_fde_cfi (const char *label, dw_cfi_ref cfi) { dw_cfi_ref *list_head; + if (emit_cfa_start_epilogue) + { + dw_cfi_ref cfi_epi_start; + + /* Emit the state save. */ + emit_cfa_start_epilogue = false; + cfi_epi_start = new_cfi (); + cfi_epi_start->dw_cfi_opc = DW_CFA_GNU_start_epilogue; + add_fde_cfi (label, cfi_epi_start); + } + if (emit_cfa_remember) { dw_cfi_ref cfi_remember; @@ -2898,7 +2918,12 @@ dwarf2out_cfi_begin_epilogue (rtx insn) gcc_assert (i != NULL); i = next_real_insn (i); if (i == NULL) - return; + { + /* But we do mark the start of the epilogue to allow it to be skipped + in _eh frames. */ + emit_cfa_start_epilogue = true; + return; + } /* Insert the restore before that next real insn in the stream, and before a potential NOTE_INSN_EPILOGUE_BEG -- we do need these notes to be @@ -2953,6 +2978,7 @@ dw_cfi_oprnd1_desc (enum dwarf_call_frame_info cfi case DW_CFA_GNU_window_save: case DW_CFA_remember_state: case DW_CFA_restore_state: + case DW_CFA_GNU_start_epilogue: return dw_cfi_oprnd_unused; case DW_CFA_set_loc: @@ -3121,6 +3148,10 @@ output_cfi (dw_cfi_ref cfi, dw_fde_ref fde, int fo dw2_asm_output_data (1, (cfi->dw_cfi_opc | (r & 0x3f)), "DW_CFA_restore, column %#lx", r); } + else if (cfi->dw_cfi_opc == DW_CFA_GNU_start_epilogue) +/* DEBUG */ + fputs (ASM_COMMENT_START"\t\t\t"ASM_COMMENT_START + " DW_CFA_GNU_start_epilogue\n",asm_out_file); else { dw2_asm_output_data (1, cfi->dw_cfi_opc, @@ -3303,6 +3334,12 @@ output_cfi_directive (dw_cfi_ref cfi) cfi->dw_cfi_oprnd1.dw_cfi_offset); break; + case DW_CFA_GNU_start_epilogue: +/*DEBUG */ + fputs (ASM_COMMENT_START"\t\t\t"ASM_COMMENT_START + " DW_CFA_GNU_start_epilogue\n",asm_out_file); + break; + case DW_CFA_remember_state: fprintf (asm_out_file, "\t.cfi_remember_state\n"); break; @@ -3498,6 +3535,41 @@ output_cfis (dw_cfi_ref cfi, bool do_cfi_asm, dw_f } } +/* Output cfi skipping save/restore and epilogues in _eh frames + for targets that do not want them. */ + +static dw_cfi_ref +emit_cfi_or_skip_epilogue (dw_cfi_ref cfi, dw_fde_ref fde, bool for_eh) +{ + if (for_eh + && targetm.asm_out.suppress_eh_epilogue_p()) + { + if (cfi->dw_cfi_opc == DW_CFA_remember_state) + { + /* Skip to the restore, unless there's an error and we fall off + the end. */ + while (cfi->dw_cfi_next + && cfi->dw_cfi_opc != DW_CFA_restore_state) + cfi = cfi->dw_cfi_next; + return cfi; + } + if (cfi->dw_cfi_opc == DW_CFA_GNU_start_epilogue) + { +/*DEBUG */ + fputs (ASM_COMMENT_START"\t\t\t"ASM_COMMENT_START + " DW_CFA_GNU_start_epilogue\n",asm_out_file); + while (cfi->dw_cfi_next) + /* Skip to the end. */ + cfi = cfi->dw_cfi_next; + return cfi; + } + } + + /* if it's not a special case, then just emit it. */ + output_cfi (cfi, fde, for_eh); + return cfi; +} + /* Output one FDE. */ static void @@ -3613,13 +3685,13 @@ output_fde (dw_fde_ref fde, bool for_eh, bool seco fde->dw_fde_current_label = begin; if (!fde->dw_fde_switched_sections) for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next) - output_cfi (cfi, fde, for_eh); + cfi = emit_cfi_or_skip_epilogue (cfi, fde, for_eh); else if (!second) { if (fde->dw_fde_switch_cfi) for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next) { - output_cfi (cfi, fde, for_eh); + cfi = emit_cfi_or_skip_epilogue (cfi, fde, for_eh); if (cfi == fde->dw_fde_switch_cfi) break; } @@ -3636,7 +3707,7 @@ output_fde (dw_fde_ref fde, bool for_eh, bool seco fde->dw_fde_switch_cfi->dw_cfi_next = cfi_next; } for (cfi = cfi_next; cfi != NULL; cfi = cfi->dw_cfi_next) - output_cfi (cfi, fde, for_eh); + cfi = emit_cfi_or_skip_epilogue (cfi, fde, for_eh); } /* If we are to emit a ref/link from function bodies to their frame tables, Index: gcc/target.def =================================================================== --- gcc/target.def (revision 163221) +++ gcc/target.def (working copy) @@ -390,6 +406,15 @@ DEFHOOK void, (FILE *file, int size, rtx x), NULL) +/* Targets might not need epilogue information in dwarf2 _eh frames. This + hook should return true if the epilogue should be suppressed in such frames. + Epilogues will still be emitted in _debug_frames. */ +DEFHOOK_UNDOC +(suppress_eh_epilogue_p, + "", + bool, (void), + hook_bool_void_false) + /* Some target machines need to postscan each insn after it is output. */ DEFHOOK (final_postscan_insn, Index: gcc/config/darwin-protos.h =================================================================== --- gcc/config/darwin-protos.h (revision 163221) +++ gcc/config/darwin-protos.h (working copy) @@ -83,10 +84,15 @@ extern tree darwin_handle_weak_import_attribute (t extern void machopic_output_stub (FILE *, const char *, const char *); extern void darwin_globalize_label (FILE *, const char *); extern void darwin_assemble_visibility (tree, int); + +extern bool darwin_asm_suppress_eh_epilogue_p (void); +extern void darwin_asm_output_dwarf_section_start_label (FILE *file, + section *sect); extern void darwin_asm_output_dwarf_delta (FILE *, int, const char *, const char *); extern void darwin_asm_output_dwarf_offset (FILE *, int, const char *, section *); + extern void darwin_asm_declare_constant_name (FILE *, const char *, const_tree, HOST_WIDE_INT); extern bool darwin_binds_local_p (const_tree); Index: gcc/config/darwin.h =================================================================== --- gcc/config/darwin.h (revision 163221) +++ gcc/config/darwin.h (working copy) @@ -669,7 +675,6 @@ extern GTY(()) int darwin_ms_struct; Make Objective-C internal symbols local and in doing this, we need to accommodate the name mangling done by c++ on file scope locals. */ - int darwin_label_is_anonymous_local_objc_name (const char *name); #undef ASM_OUTPUT_LABELREF @@ -927,6 +932,16 @@ enum machopic_addr_class { ? (DW_EH_PE_pcrel | DW_EH_PE_indirect | DW_EH_PE_sdata4) : \ ((CODE) == 1 || (GLOBAL) == 0) ? DW_EH_PE_pcrel : DW_EH_PE_absptr) +/* Mark the start of each dwarf debug section to allow us to compute local + offsets within the sections. We do this in darwin, rather than emitting + relocs. */ +#define TARGET_ASM_OUTPUT_DWARF_SECTION_START_LABEL \ + darwin_asm_output_dwarf_section_start_label + +/* For OSX compatibility we do not want to emit epilogues in _eh frames. */ +#define TARGET_ASM_SUPPRESS_EH_EPILOGUE_P \ + darwin_asm_suppress_eh_epilogue_p + #define ASM_OUTPUT_DWARF_DELTA(FILE,SIZE,LABEL1,LABEL2) \ darwin_asm_output_dwarf_delta (FILE, SIZE, LABEL1, LABEL2) Index: gcc/config/darwin.c =================================================================== --- gcc/config/darwin.c (revision 163221) +++ gcc/config/darwin.c (working copy) @@ -1666,6 +1666,36 @@ darwin_assemble_visibility (tree decl, int vis) "not supported in this configuration; ignored"); } +/* For compatibility with OSX versions that do not emit epilogues in _eh + frames we suppress them. This is made a predicate function to permit + us to add an OSX/FSF compatibility switch should that be required. */ + +bool +darwin_asm_suppress_eh_epilogue_p (void) +{ + return true; +} + +/* So that we can compute dwarf offsets within sections, we emit a known + section marker at the begining of the section. This is distinct from + the ones emitted by dwarf2out. The label is constructed by extracting + sectname from __DWARF,__sectname,etc,etc. The hook should be invoked + once, after the first switch to the section. */ + +void +darwin_asm_output_dwarf_section_start_label (FILE *file, section *sect) +{ + const char *dnam; + int namelen; + gcc_assert (sect && (sect->common.flags & (SECTION_NAMED|SECTION_DEBUG))); + dnam = ((struct named_section *)sect)->name; + gcc_assert (strncmp (dnam, "__DWARF,", 8) == 0); + gcc_assert (strchr (dnam + 8, ',')); + + namelen = strchr (dnam + 8, ',') - (dnam + 8); + fprintf (file, "Lsection%.*s:\n", namelen, dnam + 8); +} + /* Output a difference of two labels that will be an assembly time constant if the two labels are local. (.long lab1-lab2 will be very different if lab1 is at the boundary between two sections; it