[patch] fix collect2 not to drag every object with eh tables on aix
Olivier Hainque
hainque@adacore.com
Wed Jul 8 20:50:00 GMT 2009
Olivier Hainque wrote:
> This is a recap and resubmission of a patch suggested a while ago
I managed to truncate the attachement in the previous message.
Here it is again.
Thanks in advance,
Olivier
> 2009-07-06 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. 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.
-------------- next part --------------
Index: gcc/collect2.c
===================================================================
*** gcc/collect2.c (revision 148649)
--- gcc/collect2.c (working copy)
*************** int do_collecting = 1;
*** 145,150 ****
--- 145,161 ----
int do_collecting = 0;
#endif
+ /* Cook up an always defined indication of whether we proceed the
+ "EXPORT_LIST" way, much simpler to include in conditional expression
+ and helping readability by preventing the systematic need of #ifdef
+ conditionals. */
+
+ #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;
*************** struct head
*** 165,179 ****
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 */
--- 176,181 ----
*************** static void write_c_file_stat (FILE *, c
*** 288,294 ****
#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
--- 290,295 ----
*************** static void write_aix_file (FILE *, stru
*** 303,308 ****
--- 304,349 ----
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. */
+
+ typedef enum {
+ 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
+ } 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);
+
/* Delete tempfiles and exit function. */
*************** main (int argc, char **argv)
*** 831,836 ****
--- 872,886 ----
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;
*************** main (int argc, char **argv)
*** 1279,1297 ****
}
/* 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);
! }
{
struct id *list = libs.first;
for (; list; list = list->next)
! scan_prog_file (list->name, PASS_FIRST);
}
if (exports.first)
--- 1329,1359 ----
}
/* The AIX linker will discard static constructors in object files if
! 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, this_filter);
!
! ld1_filter = (scanfilter) (ld1_filter & ~this_filter);
}
if (exports.first)
*************** main (int argc, char **argv)
*** 1362,1403 ****
}
/* 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. */
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);
#endif
! 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. */
!
! /* On AIX we already scanned for global constructors/destructors. */
! #ifndef COLLECT_EXPORT_LIST
! scan_prog_file (output_file, PASS_FIRST);
! #endif
#ifdef SCAN_LIBRARIES
scan_libraries (output_file);
--- 1424,1468 ----
}
/* Load the program, searching all libraries and attempting to provide
! 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);
!
! 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;
! }
! }
! /* 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. */
!
! if (ld1_filter != SCAN_NOTHING)
! scan_prog_file (output_file, PASS_FIRST, ld1_filter);
#ifdef SCAN_LIBRARIES
scan_libraries (output_file);
*************** main (int argc, char **argv)
*** 1410,1415 ****
--- 1475,1483 ----
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)
*************** main (int argc, char **argv)
*** 1420,1429 ****
#endif
)
{
! #ifdef COLLECT_EXPORT_LIST
! /* Do tlink without additional code generation. */
! do_tlink (ld1_argv, object_lst);
! #endif
/* Strip now if it was requested on the command line. */
if (strip_flag)
{
--- 1488,1498 ----
#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)
{
*************** main (int argc, char **argv)
*** 1523,1529 ****
/* 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);
#endif
maybe_unlink (c_file);
--- 1592,1598 ----
/* 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_ALL);
#endif
maybe_unlink (c_file);
*************** write_aix_file (FILE *stream, struct id
*** 2097,2112 ****
#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__. */
static void
! scan_prog_file (const char *prog_name, enum pass which_pass)
{
void (*int_handler) (int);
#ifdef SIGQUIT
--- 2166,2176 ----
#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. */
static void
! scan_prog_file (const char *prog_name, scanpass which_pass,
! scanfilter filter)
{
void (*int_handler) (int);
#ifdef SIGQUIT
*************** scan_prog_file (const char *prog_name, e
*** 2185,2191 ****
char *name, *end;
/* If it contains a constructor or destructor name, add the name
! to the appropriate list. */
for (p = buf; (ch = *p) != '\0' && ch != '\n' && ch != '_'; p++)
if (ch == ' ' && p[1] == 'U' && p[2] == ' ')
--- 2249,2256 ----
char *name, *end;
/* If it contains a constructor or destructor name, add the name
! 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] == ' ')
*************** scan_prog_file (const char *prog_name, e
*** 2206,2221 ****
--- 2271,2292 ----
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
*************** scan_prog_file (const char *prog_name, e
*** 2224,2229 ****
--- 2295,2302 ----
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
*************** scan_prog_file (const char *prog_name, e
*** 2232,2237 ****
--- 2305,2312 ----
break;
case SYM_DWEH:
+ if (! (filter & SCAN_DWEH))
+ break;
if (which_pass != PASS_LIB)
add_to_list (&frame_tables, name);
break;
*************** extern char *ldgetname (LDFILE *, GCC_SY
*** 2488,2503 ****
#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__. */
static void
! scan_prog_file (const char *prog_name, enum pass which_pass)
{
LDFILE *ldptr = NULL;
int sym_index, sym_count;
--- 2563,2573 ----
#endif
/* COFF version to scan the name list of the loaded program for
! the symbols g++ uses for static constructors and destructors. */
static void
! scan_prog_file (const char *prog_name, scanpass which_pass,
! scanfilter filter)
{
LDFILE *ldptr = NULL;
int sym_index, sym_count;
*************** scan_prog_file (const char *prog_name, e
*** 2561,2566 ****
--- 2631,2638 ----
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)
*************** scan_prog_file (const char *prog_name, e
*** 2570,2575 ****
--- 2642,2649 ----
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)
*************** scan_prog_file (const char *prog_name, e
*** 2580,2585 ****
--- 2654,2661 ----
#ifdef COLLECT_EXPORT_LIST
case SYM_INIT:
+ if (! (filter & SCAN_INIT))
+ break;
#ifndef LD_INIT_SWITCH
if (is_shared)
add_to_list (&constructors, name);
*************** scan_prog_file (const char *prog_name, e
*** 2587,2592 ****
--- 2663,2670 ----
break;
case SYM_FINI:
+ if (! (filter & SCAN_FINI))
+ break;
#ifndef LD_INIT_SWITCH
if (is_shared)
add_to_list (&destructors, name);
*************** scan_prog_file (const char *prog_name, e
*** 2595,2600 ****
--- 2673,2680 ----
#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: gcc/doc/tm.texi
===================================================================
*** gcc/doc/tm.texi (revision 148541)
--- gcc/doc/tm.texi (working copy)
*************** A C statement to issue assembly directiv
*** 9136,9141 ****
--- 9136,9147 ----
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 given DWARF table identifier @var{label} from the current function
+ section.
+ @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: gcc/dwarf2out.c
===================================================================
*** gcc/dwarf2out.c (revision 148541)
--- gcc/dwarf2out.c (working copy)
*************** dw_cfi_oprnd2_desc (enum dwarf_call_fram
*** 2891,2902 ****
#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. */
static void
! switch_to_eh_frame_section (void)
{
tree label;
--- 2891,2902 ----
#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
! /* 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 (bool back)
{
tree label;
*************** switch_to_eh_frame_section (void)
*** 2939,2949 ****
/* 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));
}
}
--- 2939,2953 ----
/* 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);
!
! 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));
! }
}
}
*************** output_cfi_directive (dw_cfi_ref cfi)
*** 3189,3194 ****
--- 3193,3214 ----
}
}
+ /* 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. */
*************** output_call_frame_info (int for_eh)
*** 3259,3273 ****
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);
! }
ASM_GENERATE_INTERNAL_LABEL (section_start_label, FRAME_BEGIN_LABEL, for_eh);
ASM_OUTPUT_LABEL (asm_out_file, section_start_label);
--- 3279,3286 ----
if (flag_debug_asm)
app_enable ();
! /* 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);
*************** output_call_frame_info (int for_eh)
*** 3542,3547 ****
--- 3555,3574 ----
for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next)
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, which we need do 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)));
Index: gcc/config/rs6000/rs6000-protos.h
===================================================================
*** gcc/config/rs6000/rs6000-protos.h (revision 148541)
--- gcc/config/rs6000/rs6000-protos.h (working copy)
*************** extern bool rs6000_tls_referenced_p (rtx
*** 171,176 ****
--- 171,178 ----
extern int rs6000_hard_regno_nregs (int, enum machine_mode);
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: gcc/config/rs6000/aix.h
===================================================================
*** gcc/config/rs6000/aix.h (revision 148541)
--- gcc/config/rs6000/aix.h (working copy)
***************
*** 43,48 ****
--- 43,54 ----
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: gcc/config/rs6000/rs6000.c
===================================================================
*** gcc/config/rs6000/rs6000.c (revision 148541)
--- gcc/config/rs6000/rs6000.c (working copy)
*************** create_TOC_reference (rtx symbol)
*** 15479,15484 ****
--- 15479,15493 ----
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. */
More information about the Gcc-patches
mailing list