* collect2.c (DO_COLLECT_EXPORT_LIST): New internal macro,
authorhainque <hainque@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 28 Aug 2009 09:04:52 +0000 (09:04 +0000)
committerhainque <hainque@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 28 Aug 2009 09:04:52 +0000 (09:04 +0000)
        always defined.  Reflect definition or absence of such for
        COLLECT_EXPORT_LIST.  Readability helper.
        (scanfilter): New enum, to help control what symbols
        are to be considered or ignored by scan_prog_file.
        (enum pass): Rename as "scanpass", moved together with scanfilter
        prior to scan_prog_file's prototype.
        (scan_prog_file): Accept and honor scanpass and scanfilter arguments.
        Group prototype with the scanpass/scanfilter definitions, factorize
        head comments for the several implementations at the prototype.
        (main): Reorganize the first pass link control to let AIX
        drag only the needed frame tables in executables.  Prevent
        frame tables collection during the scan aimed at static ctors.
        Pre-link and scan for frame tables later to compensate.
        * doc/tm.texi (ASM_OUTPUT_DWARF_TABLE_REF): New macro.
        A C statement to issue assembly directives that create a reference
        to the given DWARF table identifier label from the current function
        section.
        * dwarf2out.c (switch_to_eh_frame_section): Add a BACK argument
        to differentiate first time section entry.  Only emit a .data
        tables start identifier label the first time around.
        (switch_to_frame_table_section): New function.  Helper for
        output_call_frame_info to switch possibly BACK into the eh_frame
        or the debug_frame section depending on FOR_EH.
        (output_call_frame_info): Use helper to first enter the proper
        frame section.
        (output_fde): Use ASM_OUTPUT_DWARF_TABLE_REF when defined to
        emit a link to the frame table start label from each function
        section.
        * config/rs6000/rs6000.c (rs6000_aix_asm_output_dwarf_table_ref):
        New function.  Implementation of ASM_OUTPUT_DWARF_TABLE_REF.
        * config/rs6000/rs6000-protos.h: Declare it.
        * config/rs6000/aix.h (ASM_OUTPUT_DWARF_TABLE_REF): Define.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@151157 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/collect2.c
gcc/config/rs6000/aix.h
gcc/config/rs6000/rs6000-protos.h
gcc/config/rs6000/rs6000.c
gcc/doc/tm.texi
gcc/dwarf2out.c

index de1e1c5..c53d9c8 100644 (file)
@@ -1,3 +1,39 @@
+2009-08-28  Olivier Hainque  <hainque@adacore.com>
+
+       * collect2.c (DO_COLLECT_EXPORT_LIST): New internal macro,
+       always defined.  Reflect definition or absence of such for
+       COLLECT_EXPORT_LIST.  Readability helper.
+       (scanfilter): New enum, to help control what symbols
+       are to be considered or ignored by scan_prog_file.
+       (enum pass): Rename as "scanpass", moved together with scanfilter
+       prior to scan_prog_file's prototype.
+       (scan_prog_file): Accept and honor scanpass and scanfilter arguments.
+       Group prototype with the scanpass/scanfilter definitions, factorize
+       head comments for the several implementations at the prototype.
+       (main): Reorganize the first pass link control to let AIX
+       drag only the needed frame tables in executables.  Prevent
+       frame tables collection during the scan aimed at static ctors.
+       Pre-link and scan for frame tables later to compensate.
+       * doc/tm.texi (ASM_OUTPUT_DWARF_TABLE_REF): New macro.
+       A C statement to issue assembly directives that create a reference
+       to the given DWARF table identifier label from the current function
+       section.
+       * dwarf2out.c (switch_to_eh_frame_section): Add a BACK argument
+       to differentiate first time section entry.  Only emit a .data
+       tables start identifier label the first time around.
+       (switch_to_frame_table_section): New function.  Helper for
+       output_call_frame_info to switch possibly BACK into the eh_frame
+       or the debug_frame section depending on FOR_EH.
+       (output_call_frame_info): Use helper to first enter the proper
+       frame section.
+       (output_fde): Use ASM_OUTPUT_DWARF_TABLE_REF when defined to
+       emit a link to the frame table start label from each function
+       section.
+       * config/rs6000/rs6000.c (rs6000_aix_asm_output_dwarf_table_ref):
+       New function.  Implementation of ASM_OUTPUT_DWARF_TABLE_REF.
+       * config/rs6000/rs6000-protos.h: Declare it.
+       * config/rs6000/aix.h (ASM_OUTPUT_DWARF_TABLE_REF): Define.
+
 2009-08-27  Kaz Kojima  <kkojima@gcc.gnu.org>
 
        * config/sh/sh.c (split_branches): Check the result of
index aed4c67..b235f2b 100644 (file)
@@ -145,6 +145,15 @@ int do_collecting = 1;
 int do_collecting = 0;
 #endif
 
+/* Cook up an always defined indication of whether we proceed the
+   "EXPORT_LIST" way.  */
+
+#ifdef COLLECT_EXPORT_LIST
+#define DO_COLLECT_EXPORT_LIST 1
+#else
+#define DO_COLLECT_EXPORT_LIST 0
+#endif
+
 /* Nonzero if we should suppress the automatic demangling of identifiers
    in linker error messages.  Set from COLLECT_NO_DEMANGLE.  */
 int no_demangle;
@@ -165,15 +174,6 @@ struct head
   int number;
 };
 
-/* Enumeration giving which pass this is for scanning the program file.  */
-
-enum pass {
-  PASS_FIRST,                          /* without constructors */
-  PASS_OBJ,                            /* individual objects */
-  PASS_LIB,                            /* looking for shared libraries */
-  PASS_SECOND                          /* with constructors linked in */
-};
-
 int vflag;                             /* true if -v */
 static int rflag;                      /* true if -r */
 static int strip_flag;                 /* true if -s */
@@ -288,7 +288,6 @@ static void write_c_file_stat (FILE *, const char *);
 #ifndef LD_INIT_SWITCH
 static void write_c_file_glob (FILE *, const char *);
 #endif
-static void scan_prog_file (const char *, enum pass);
 #ifdef SCAN_LIBRARIES
 static void scan_libraries (const char *);
 #endif
@@ -303,6 +302,50 @@ static void write_aix_file (FILE *, struct id *);
 static char *resolve_lib_name (const char *);
 #endif
 static char *extract_string (const char **);
+
+/* Enumerations describing which pass this is for scanning the
+   program file ...  */
+
+typedef enum {
+  PASS_FIRST,                          /* without constructors */
+  PASS_OBJ,                            /* individual objects */
+  PASS_LIB,                            /* looking for shared libraries */
+  PASS_SECOND                          /* with constructors linked in */
+} scanpass;
+
+/* ... and which kinds of symbols are to be considered.  */
+
+enum scanfilter_masks {
+  SCAN_NOTHING = 0,
+
+  SCAN_CTOR = 1 << SYM_CTOR, 
+  SCAN_DTOR = 1 << SYM_DTOR,
+  SCAN_INIT = 1 << SYM_INIT,
+  SCAN_FINI = 1 << SYM_FINI,
+  SCAN_DWEH = 1 << SYM_DWEH,
+  SCAN_ALL  = ~0
+};
+
+/* This type is used for parameters and variables which hold
+   combinations of the flags in enum scanfilter_masks.  */
+typedef int scanfilter;
+
+/* Scan the name list of the loaded program for the symbols g++ uses for
+   static constructors and destructors.
+
+   The SCANPASS argument tells which collect processing pass this is for and
+   the SCANFILTER argument tells which kinds of symbols to consider in this
+   pass.  Symbols of a special kind not in the filter mask are considered as
+   regular ones.
+
+   The constructor table begins at __CTOR_LIST__ and contains a count of the
+   number of pointers (or -1 if the constructors are built in a separate
+   section by the linker), followed by the pointers to the constructor
+   functions, terminated with a null pointer.  The destructor table has the
+   same format, and begins at __DTOR_LIST__.  */
+
+static void scan_prog_file (const char *, scanpass, scanfilter);
+
 \f
 /* Delete tempfiles and exit function.  */
 
@@ -831,6 +874,15 @@ main (int argc, char **argv)
   const char **c_ptr;
   char **ld1_argv;
   const char **ld1;
+  
+  /* The kinds of symbols we will have to consider when scanning the
+     outcome of a first pass link.  This is ALL to start with, then might
+     be adjusted before getting to the first pass link per se, typically on
+     AIX where we perform an early scan of objects and libraries to fetch
+     the list of global ctors/dtors and make sure they are not garbage
+     collected.  */
+  scanfilter ld1_filter = SCAN_ALL;
+
   char **ld2_argv;
   const char **ld2;
   char **object_lst;
@@ -1279,19 +1331,31 @@ main (int argc, char **argv)
     }
 
   /* The AIX linker will discard static constructors in object files if
-     nothing else in the file is referenced, so look at them first.  */
-  {
-      const char **export_object_lst 
-       = CONST_CAST2 (const char **, char **, object_lst);
-
-      while (export_object_lst < object)
-       scan_prog_file (*export_object_lst++, PASS_OBJ);
-  }
+     nothing else in the file is referenced, so look at them first.  Unless
+     we are building a shared object, ignore the eh frame tables, as we
+     would otherwise reference them all, hence drag all the corresponding
+     objects even if nothing else is referenced.  */
   {
+    const char **export_object_lst 
+      = CONST_CAST2 (const char **, char **, object_lst);
+    
     struct id *list = libs.first;
 
+    /* Compute the filter to use from the current one, do scan, then adjust
+       the "current" filter to remove what we just included here.  This will
+       control whether we need a first pass link later on or not, and what
+       will remain to be scanned there.  */
+    
+    scanfilter this_filter
+      = shared_obj ? ld1_filter : (ld1_filter & ~SCAN_DWEH);
+    
+    while (export_object_lst < object)
+      scan_prog_file (*export_object_lst++, PASS_OBJ, this_filter);
+    
     for (; list; list = list->next)
-      scan_prog_file (list->name, PASS_FIRST);
+      scan_prog_file (list->name, PASS_FIRST, this_filter);
+    
+    ld1_filter = ld1_filter & ~this_filter;
   }
 
   if (exports.first)
@@ -1362,42 +1426,45 @@ main (int argc, char **argv)
     }
 
   /* Load the program, searching all libraries and attempting to provide
-     undefined symbols from repository information.  */
-
-  /* On AIX we do this later.  */
-#ifndef COLLECT_EXPORT_LIST
-  do_tlink (ld1_argv, object_lst);
-#endif
-
-  /* If -r or they will be run via some other method, do not build the
-     constructor or destructor list, just return now.  */
-  if (rflag
-#ifndef COLLECT_EXPORT_LIST
-      || ! do_collecting
-#endif
-      )
-    {
-#ifdef COLLECT_EXPORT_LIST
-      /* Do the link we avoided above if we are exiting.  */
+     undefined symbols from repository information.
+     
+     If -r or they will be run via some other method, do not build the
+     constructor or destructor list, just return now.  */  
+  {
+    bool early_exit
+      = rflag || (! DO_COLLECT_EXPORT_LIST && ! do_collecting);
+
+    /* Perform the first pass link now, if we're about to exit or if we need
+       to scan for things we haven't collected yet before pursuing further.
+
+       On AIX, the latter typically includes nothing for shared objects or
+       frame tables for an executable, out of what the required early scan on
+       objects and libraries has performed above.  In the !shared_obj case, we
+       expect the relevant tables to be dragged together with their associated
+       functions from precise cross reference insertions by the compiler.  */
+       
+    if (early_exit || ld1_filter != SCAN_NOTHING)
       do_tlink (ld1_argv, object_lst);
-
-      /* But make sure we delete the export file we may have created.  */
-      if (export_file != 0 && export_file[0])
-       maybe_unlink (export_file);
+    
+    if (early_exit)
+      {
+#ifdef COLLECT_EXPORT_LIST
+       /* Make sure we delete the export file we may have created.  */
+       if (export_file != 0 && export_file[0])
+         maybe_unlink (export_file);
 #endif
-      maybe_unlink (c_file);
-      maybe_unlink (o_file);
-      return 0;
-    }
+       maybe_unlink (c_file);
+       maybe_unlink (o_file);
+       return 0;
+      }
+  }
 
-  /* Examine the namelist with nm and search it for static constructors
-     and destructors to call.
-     Write the constructor and destructor tables to a .s file and reload.  */
+  /* Unless we have done it all already, examine the namelist and search for
+     static constructors and destructors to call.  Write the constructor and
+     destructor tables to a .s file and reload.  */
 
-  /* On AIX we already scanned for global constructors/destructors.  */
-#ifndef COLLECT_EXPORT_LIST
-  scan_prog_file (output_file, PASS_FIRST);
-#endif
+  if (ld1_filter != SCAN_NOTHING)
+    scan_prog_file (output_file, PASS_FIRST, ld1_filter);
 
 #ifdef SCAN_LIBRARIES
   scan_libraries (output_file);
@@ -1410,6 +1477,9 @@ main (int argc, char **argv)
       notice ("%d frame table(s) found\n", frame_tables.number);
     }
 
+  /* If the scan exposed nothing of special interest, there's no need to
+     generate the glue code and relink so return now.  */
+
   if (constructors.number == 0 && destructors.number == 0
       && frame_tables.number == 0
 #if defined (SCAN_LIBRARIES) || defined (COLLECT_EXPORT_LIST)
@@ -1420,10 +1490,11 @@ main (int argc, char **argv)
 #endif
       )
     {
-#ifdef COLLECT_EXPORT_LIST
-      /* Do tlink without additional code generation.  */
-      do_tlink (ld1_argv, object_lst);
-#endif
+      /* Do tlink without additional code generation now if we didn't
+        do it earlier for scanning purposes.  */
+      if (ld1_filter == SCAN_NOTHING)
+       do_tlink (ld1_argv, object_lst);
+
       /* Strip now if it was requested on the command line.  */
       if (strip_flag)
        {
@@ -1523,7 +1594,7 @@ main (int argc, char **argv)
 
   /* Let scan_prog_file do any final mods (OSF/rose needs this for
      constructors/destructors in shared libraries.  */
-  scan_prog_file (output_file, PASS_SECOND);
+  scan_prog_file (output_file, PASS_SECOND, SCAN_ALL);
 #endif
 
   maybe_unlink (c_file);
@@ -2097,16 +2168,11 @@ write_aix_file (FILE *stream, struct id *list)
 #ifdef OBJECT_FORMAT_NONE
 
 /* Generic version to scan the name list of the loaded program for
-   the symbols g++ uses for static constructors and destructors.
-
-   The constructor table begins at __CTOR_LIST__ and contains a count
-   of the number of pointers (or -1 if the constructors are built in a
-   separate section by the linker), followed by the pointers to the
-   constructor functions, terminated with a null pointer.  The
-   destructor table has the same format, and begins at __DTOR_LIST__.  */
+   the symbols g++ uses for static constructors and destructors.  */
 
 static void
-scan_prog_file (const char *prog_name, enum pass which_pass)
+scan_prog_file (const char *prog_name, scanpass which_pass,
+               scanfilter filter)
 {
   void (*int_handler) (int);
 #ifdef SIGQUIT
@@ -2185,7 +2251,8 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
       char *name, *end;
 
       /* If it contains a constructor or destructor name, add the name
-        to the appropriate list.  */
+        to the appropriate list unless this is a kind of symbol we're
+        not supposed to even consider.  */
 
       for (p = buf; (ch = *p) != '\0' && ch != '\n' && ch != '_'; p++)
        if (ch == ' ' && p[1] == 'U' && p[2] == ' ')
@@ -2206,16 +2273,22 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
       switch (is_ctor_dtor (name))
        {
        case SYM_CTOR:
+         if (! (filter & SCAN_CTOR))
+           break;
          if (which_pass != PASS_LIB)
            add_to_list (&constructors, name);
          break;
 
        case SYM_DTOR:
+         if (! (filter & SCAN_DTOR))
+           break;
          if (which_pass != PASS_LIB)
            add_to_list (&destructors, name);
          break;
 
        case SYM_INIT:
+         if (! (filter & SCAN_INIT))
+           break;
          if (which_pass != PASS_LIB)
            fatal ("init function found in object %s", prog_name);
 #ifndef LD_INIT_SWITCH
@@ -2224,6 +2297,8 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
          break;
 
        case SYM_FINI:
+         if (! (filter & SCAN_FINI))
+           break;
          if (which_pass != PASS_LIB)
            fatal ("fini function found in object %s", prog_name);
 #ifndef LD_FINI_SWITCH
@@ -2232,6 +2307,8 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
          break;
 
        case SYM_DWEH:
+         if (! (filter & SCAN_DWEH))
+           break;
          if (which_pass != PASS_LIB)
            add_to_list (&frame_tables, name);
          break;
@@ -2488,16 +2565,11 @@ extern char *ldgetname (LDFILE *, GCC_SYMENT *);
 #endif
 
 /* COFF version to scan the name list of the loaded program for
-   the symbols g++ uses for static constructors and destructors.
-
-   The constructor table begins at __CTOR_LIST__ and contains a count
-   of the number of pointers (or -1 if the constructors are built in a
-   separate section by the linker), followed by the pointers to the
-   constructor functions, terminated with a null pointer.  The
-   destructor table has the same format, and begins at __DTOR_LIST__.  */
+   the symbols g++ uses for static constructors and destructors.  */
 
 static void
-scan_prog_file (const char *prog_name, enum pass which_pass)
+scan_prog_file (const char *prog_name, scanpass which_pass,
+               scanfilter filter)
 {
   LDFILE *ldptr = NULL;
   int sym_index, sym_count;
@@ -2561,6 +2633,8 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
                      switch (is_ctor_dtor (name))
                        {
                        case SYM_CTOR:
+                         if (! (filter & SCAN_CTOR))
+                           break;
                          if (! is_shared)
                            add_to_list (&constructors, name);
 #if defined (COLLECT_EXPORT_LIST) && !defined (LD_INIT_SWITCH)
@@ -2570,6 +2644,8 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
                          break;
 
                        case SYM_DTOR:
+                         if (! (filter & SCAN_DTOR))
+                           break;
                          if (! is_shared)
                            add_to_list (&destructors, name);
 #if defined (COLLECT_EXPORT_LIST) && !defined (LD_INIT_SWITCH)
@@ -2580,6 +2656,8 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
 
 #ifdef COLLECT_EXPORT_LIST
                        case SYM_INIT:
+                         if (! (filter & SCAN_INIT))
+                           break;
 #ifndef LD_INIT_SWITCH
                          if (is_shared)
                            add_to_list (&constructors, name);
@@ -2587,6 +2665,8 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
                          break;
 
                        case SYM_FINI:
+                         if (! (filter & SCAN_FINI))
+                           break;
 #ifndef LD_INIT_SWITCH
                          if (is_shared)
                            add_to_list (&destructors, name);
@@ -2595,6 +2675,8 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
 #endif
 
                        case SYM_DWEH:
+                         if (! (filter & SCAN_DWEH))
+                           break;
                          if (! is_shared)
                            add_to_list (&frame_tables, name);
 #if defined (COLLECT_EXPORT_LIST) && !defined (LD_INIT_SWITCH)
index 44015a3..4676110 100644 (file)
    collect has a chance to see them, so scan the object files directly.  */
 #define COLLECT_EXPORT_LIST
 
+/* Issue assembly directives that create a reference to the given DWARF table
+   identifier label from the current function section.  This is defined to
+   ensure we drag frame frame tables associated with needed function bodies in
+   a link with garbage collection activated.  */
+#define ASM_OUTPUT_DWARF_TABLE_REF rs6000_aix_asm_output_dwarf_table_ref
+
 /* Handle #pragma weak and #pragma pack.  */
 #define HANDLE_SYSV_PRAGMA 1
 
index 96f215b..6e6bb9e 100644 (file)
@@ -179,6 +179,8 @@ extern int rs6000_memory_move_cost (enum machine_mode, enum reg_class, int);
 extern bool rs6000_tls_referenced_p (rtx);
 extern void rs6000_conditional_register_usage (void);
 
+extern void rs6000_aix_asm_output_dwarf_table_ref (char *);
+
 /* Declare functions in rs6000-c.c */
 
 extern void rs6000_pragma_longcall (struct cpp_reader *);
index cb64d28..8e31cbb 100644 (file)
@@ -17612,6 +17612,15 @@ create_TOC_reference (rtx symbol)
               gen_rtx_UNSPEC (Pmode, gen_rtvec (1, symbol), UNSPEC_TOCREL)));
 }
 
+/* Issue assembly directives that create a reference to the given DWARF
+   FRAME_TABLE_LABEL from the current function section.  */
+void
+rs6000_aix_asm_output_dwarf_table_ref (char * frame_table_label)
+{
+  fprintf (asm_out_file, "\t.ref %s\n",
+          TARGET_STRIP_NAME_ENCODING (frame_table_label));
+}
+
 /* If _Unwind_* has been called from within the same module,
    toc register is not guaranteed to be saved to 40(1) on function
    entry.  Save it there in that case.  */
index 818df81..f236a7d 100644 (file)
@@ -9159,6 +9159,13 @@ A C statement to issue assembly directives that create a self-relative
 reference to the given @var{label}, using an integer of the given @var{size}.
 @end defmac
 
+@defmac ASM_OUTPUT_DWARF_TABLE_REF (@var{label})
+A C statement to issue assembly directives that create a reference to
+the DWARF table identifier @var{label} from the current section.  This
+is used on some systems to avoid garbage collecting a DWARF table which
+is referenced by a function.
+@end defmac
+
 @deftypefn {Target Hook} void TARGET_ASM_OUTPUT_DWARF_DTPREL (FILE *@var{FILE}, int @var{size}, rtx @var{x})
 If defined, this target hook is a function which outputs a DTP-relative
 reference to the given TLS symbol of the specified size.
index ad956f8..04f8758 100644 (file)
@@ -2932,12 +2932,12 @@ dw_cfi_oprnd2_desc (enum dwarf_call_frame_info cfi)
 
 #if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
 
-/* Switch to eh_frame_section.  If we don't have an eh_frame_section,
-   switch to the data section instead, and write out a synthetic label
-   for collect2.  */
+/* Switch [BACK] to eh_frame_section.  If we don't have an eh_frame_section,
+   switch to the data section instead, and write out a synthetic start label
+   for collect2 the first time around.  */
 
 static void
-switch_to_eh_frame_section (void)
+switch_to_eh_frame_section (bool back)
 {
   tree label;
 
@@ -2980,11 +2980,15 @@ switch_to_eh_frame_section (void)
       /* We have no special eh_frame section.  Put the information in
         the data section and emit special labels to guide collect2.  */
       switch_to_section (data_section);
-      label = get_file_function_name ("F");
-      ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
-      targetm.asm_out.globalize_label (asm_out_file,
-                                      IDENTIFIER_POINTER (label));
-      ASM_OUTPUT_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
+
+      if (!back)
+       {
+         label = get_file_function_name ("F");
+         ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
+         targetm.asm_out.globalize_label (asm_out_file,
+                                          IDENTIFIER_POINTER (label));
+         ASM_OUTPUT_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
+       }
     }
 }
 
@@ -3534,6 +3538,20 @@ output_fde (dw_fde_ref fde, bool for_eh, bool second,
        output_cfi (cfi, fde, for_eh);
     }
 
+  /* If we are to emit a ref/link from function bodies to their frame tables,
+     do it now.  This is typically performed to make sure that tables
+     associated with functions are dragged with them and not discarded in
+     garbage collecting links. We need to do this on a per function basis to
+     cope with -ffunction-sections.  */
+
+#ifdef ASM_OUTPUT_DWARF_TABLE_REF
+  /* Switch to the function section, emit the ref to the tables, and
+     switch *back* into the table section.  */
+  switch_to_section (function_section (fde->decl));
+  ASM_OUTPUT_DWARF_TABLE_REF (section_start_label);
+  switch_to_frame_table_section (for_eh, true);
+#endif
+
   /* Pad the FDE out to an address sized boundary.  */
   ASM_OUTPUT_ALIGN (asm_out_file,
                    floor_log2 ((for_eh ? PTR_SIZE : DWARF2_ADDR_SIZE)));
@@ -3543,6 +3561,22 @@ output_fde (dw_fde_ref fde, bool for_eh, bool second,
 }
 
 
+/* Switch [BACK] to the eh or debug frame table section, depending on
+   FOR_EH.  */
+static void
+switch_to_frame_table_section (int for_eh, bool back)
+{
+  if (for_eh)
+    switch_to_eh_frame_section (back);
+  else
+    {
+      if (!debug_frame_section)
+       debug_frame_section = get_section (DEBUG_FRAME_SECTION,
+                                          SECTION_DEBUG, NULL);
+      switch_to_section (debug_frame_section);
+    }
+}
+
 /* Output the call frame information used to record information
    that relates to calculating the frame pointer, and records the
    location of saved registers.  */
@@ -3613,15 +3647,8 @@ output_call_frame_info (int for_eh)
   if (flag_debug_asm)
     app_enable ();
 
-  if (for_eh)
-    switch_to_eh_frame_section ();
-  else
-    {
-      if (!debug_frame_section)
-       debug_frame_section = get_section (DEBUG_FRAME_SECTION,
-                                          SECTION_DEBUG, NULL);
-      switch_to_section (debug_frame_section);
-    }
+  /* Switch to the proper frame section, first time.  */
+  switch_to_frame_table_section (for_eh, false);
 
   ASM_GENERATE_INTERNAL_LABEL (section_start_label, FRAME_BEGIN_LABEL, for_eh);
   ASM_OUTPUT_LABEL (asm_out_file, section_start_label);