This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [Patch, _eh, dawin] Allow targets to suppress epilogues in _eh frames.


On Fri, Aug 13, 2010 at 08:50:29PM +0100, IainS wrote:
> 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
>
> <SNIP>
>
> 	.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:
>
> <SNIP>
>
> 	.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
>

Iain,
   So far the only failure I see with your patch under darwin10.4.0, using the
compact unwinder (by eliminating the addition of -no_compact_unwind
in darwin10.h), is...

FAIL: g++.dg/eh/async-unwind2.C execution test

at -m32. Interestingly, if I pass -Wl,-warn_compact_unwind when building
that testcase, I get...

[MacPro:~/async_unwind] howarth% /sw/src/fink.build/gcc46-4.6.0-1000/darwin_objdir/gcc/testsuite/g++/../../g++ -B/sw/src/fink.build/gcc46-4.6.0-1000/darwin_objdir/gcc/testsuite/g++/../../ /sw/src/fink.build/gcc46-4.6.0-1000/gcc-4.6-20100813/gcc/testsuite/g++.dg/eh/async-unwind2.C -nostdinc++ -I/sw/src/fink.build/gcc46-4.6.0-1000/darwin_objdir/x86_64-apple-darwin10.4.0/i386/libstdc++-v3/include/x86_64-apple-darwin10.4.0 -I/sw/src/fink.build/gcc46-4.6.0-1000/darwin_objdir/x86_64-apple-darwin10.4.0/i386/libstdc++-v3/include -I/sw/src/fink.build/gcc46-4.6.0-1000/gcc-4.6-20100813/libstdc++-v3/libsupc++ -I/sw/src/fink.build/gcc46-4.6.0-1000/gcc-4.6-20100813/libstdc++-v3/include/backward -I/sw/src/fink.build/gcc46-4.6.0-1000/gcc-4.6-20100813/libstdc++-v3/testsuite/util -fmessage-length=0 -Os -fasynchronous-unwind-tables -fpic -fno-inline -L/sw/src/fink.build/gcc46-4.6.0-1000/darwin_objdir/x86_64-apple-darwin10.4.0/i386/libstdc++-v3/src/.libs -B/sw/src/fink.build/gcc46-4.6.0-1000/darwin_objdir/x86_64-apple-darwin10.4.0/i386/libstdc++-v3/src/.libs -L/sw/src/fink.build/gcc46-4.6.0-1000/darwin_objdir/x86_64-apple-darwin10.4.0/i386/libstdc++-v3/src/.libs -L/sw/src/fink.build/gcc46-4.6.0-1000/darwin_objdir/x86_64-apple-darwin10.4.0/i386/libiberty -multiply_defined suppress -lm -m32 -g -Wl,-warn_compact_unwind -o ./async-unwind2.exe
ld: warning: can't make compact unwind encoding from dwarf for S::sfn2(int)  in /var/folders/1C/1CdoNxmNFHyOIjNBLNuJh++++TM/-Tmp-//ccw4LTKt.o because dwarf uses DW_CFA_GNU_args_size
ld: warning: can't make compact unwind encoding from dwarf for S::sfn3(char const*) in /var/folders/1C/1CdoNxmNFHyOIjNBLNuJh++++TM/-Tmp-//ccw4LTKt.o because dwarf uses DW_CFA_GNU_args_size
ld: warning: can't make compact unwind encoding from dwarf for baz1(S const&) in /var/folders/1C/1CdoNxmNFHyOIjNBLNuJh++++TM/-Tmp-//ccw4LTKt.o because dwarf uses DW_CFA_GNU_args_size

These errors don't appear when I do the same to build the non-failing async-unwind1.exe testcase. Can we inhibit the emission of
DW_CFA_GNU_args_size on darwin as well?
                Jack


>
> 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_<unknown>";
>      }
> @@ -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

>
>
>
>
>


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]