This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
[PATCH] More aggressive --gc-sections
- From: Eric Botcazou <ebotcazou at act-europe dot fr>
- To: binutils at sources dot redhat dot com,gcc-patches at gcc dot gnu dot org
- Date: Thu, 18 Mar 2004 00:40:25 +0100
- Subject: [PATCH] More aggressive --gc-sections
Hi,
This is the minimal set of patches needed in order to make --gc-sections
works for dynamically linked Ada programs using DWARF-2 EH on x86/Linux.
For a description of the mechanism, see:
http://gcc.gnu.org/ml/gcc/2004-03/msg00506.html
The GCC part was bootstrapped/regtested on mainline, the binutils part was
tested on mainline, with no new regressions. I ran the ACATS and libstdc++
testsuites with -function-sections -fdata-sections -Wl,--gc-sections too.
I don't expect these patches to be accepted, rather to serve as a starting
point for the discussion. What do you think about the approach? What
criteria should the patches meet to be accepted both in GCC and binutils?
Thanks in advance.
GCC:
* except.h (output_function_exception_table): New prototype.
* output.h (default_exception_section): New prototype.
* target.h (struct gcc_target) <exception_section>: New prototype.
* except.c (PTR_SIZE): New macro.
(default_exception_section): New prototype.
If named sections are supported and flag_function_sections is set,
use a function-specific section.
(output_function_exception_table): New prototype.
Adjust call to targetm.asm_out.exception_section. Keep track of the LDSA
label. If flag_function_sections is set, emit a reference to the LDSA
label in the function section.
* passes.c (rest_of_handle_final): Adjust calls to
output_function_exception_table.
* Makefile.in (LIBGCC2_CFLAGS): Add -ffunction-sections -fdata-sections.
* ada/Makefile.in (GNATLIBCFLAGS): Likewise.
* ada/Make-lang.in (GNATLIBCFLAGS): Likewise.
BFD:
* elflink.h (elf_gc_mark_dynamic_ref_symbol): New function.
(elf_gc_sections): Do not gracefully fail if dynamic sections have
been created. Instead call elf_gc_mark_dynamic_ref_symbol to
mark dynamically referenced symbols. Do not mark the whole graph
rooted at .eh_frame, only the section proper.
LD:
* scripttempl/elf.sc (.text): Add KEEP for .text.*personality*.
(.data): Add KEEP for .gnu.linkonce.d.*personality*.
(.gcc_except_table): Add KEEP for self and accept .gcc_except_table.*.
--
Eric Botcazou
Index: except.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/except.c,v
retrieving revision 1.261
diff -u -p -r1.261 except.c
--- except.c 7 Mar 2004 22:29:28 -0000 1.261
+++ except.c 9 Mar 2004 12:58:43 -0000
@@ -81,6 +81,11 @@ Software Foundation, 59 Temple Place - S
#define EH_RETURN_DATA_REGNO(N) INVALID_REGNUM
#endif
+/* The size of the target's pointer type. */
+#ifndef PTR_SIZE
+#define PTR_SIZE (POINTER_SIZE / BITS_PER_UNIT)
+#endif
+
/* Nonzero means enable synchronous exceptions for non-call instructions. */
int flag_non_call_exceptions;
@@ -3667,7 +3672,7 @@ sjlj_output_call_site_table (void)
table. */
void
-default_exception_section (void)
+default_exception_section (const char *fnname)
{
if (targetm.have_named_sections)
{
@@ -3682,7 +3687,15 @@ default_exception_section (void)
#else
flags = SECTION_WRITE;
#endif
- named_section_flags (".gcc_except_table", flags);
+ if (flag_function_sections)
+ {
+ char *section_name = xmalloc (strlen (fnname) + 32);
+ sprintf (section_name, ".gcc_except_table.%s", fnname);
+ named_section_flags (section_name, flags);
+ free (section_name);
+ }
+ else
+ named_section_flags (".gcc_except_table", flags);
}
else if (flag_pic)
data_section ();
@@ -3691,9 +3704,10 @@ default_exception_section (void)
}
void
-output_function_exception_table (void)
+output_function_exception_table (const char *fnname)
{
int tt_format, cs_format, lp_format, i, n;
+ char llsda_label[32];
#ifdef HAVE_AS_LEB128
char ttype_label[32];
char cs_after_size_label[32];
@@ -3715,7 +3729,7 @@ output_function_exception_table (void)
/* Note that varasm still thinks we're in the function's code section.
The ".endp" directive that will immediately follow will take us back. */
#else
- (*targetm.asm_out.exception_section) ();
+ (*targetm.asm_out.exception_section) (fnname);
#endif
have_tt_data = (VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data) > 0
@@ -3736,8 +3750,9 @@ output_function_exception_table (void)
assemble_align (tt_format_size * BITS_PER_UNIT);
}
- (*targetm.asm_out.internal_label) (asm_out_file, "LLSDA",
- current_function_funcdef_no);
+ ASM_GENERATE_INTERNAL_LABEL (llsda_label, "LLSDA",
+ current_function_funcdef_no);
+ ASM_OUTPUT_LABEL (asm_out_file, llsda_label);
/* The LSDA header. */
@@ -3891,6 +3906,14 @@ output_function_exception_table (void)
(i ? NULL : "Exception specification table"));
function_section (current_function_decl);
+
+ /* Make the function reference its exception table so that the latter
+ cannot be discarded by the linker unless the function itself is
+ discarded. */
+ if (flag_function_sections)
+ dw2_asm_output_addr (PTR_SIZE,
+ llsda_label,
+ "Explicit reference to the table");
}
#include "gt-except.h"
Index: except.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/except.h,v
retrieving revision 1.74
diff -u -p -r1.74 except.h
--- except.h 18 Feb 2004 15:05:03 -0000 1.74
+++ except.h 9 Mar 2004 12:58:43 -0000
@@ -107,7 +107,7 @@ extern void convert_from_eh_region_range
extern void convert_to_eh_region_ranges (void);
extern void find_exception_handler_labels (void);
extern bool current_function_has_exception_handlers (void);
-extern void output_function_exception_table (void);
+extern void output_function_exception_table (const char *);
extern void expand_builtin_unwind_init (void);
extern rtx expand_builtin_eh_return_data_regno (tree);
Index: output.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/output.h,v
retrieving revision 1.137
diff -u -p -r1.137 output.h
--- output.h 27 Feb 2004 08:54:30 -0000 1.137
+++ output.h 9 Mar 2004 12:58:47 -0000
@@ -453,7 +453,7 @@ extern const char *user_label_prefix;
extern void default_function_pro_epilogue (FILE *, HOST_WIDE_INT);
/* Tell assembler to switch to the section for the exception table. */
-extern void default_exception_section (void);
+extern void default_exception_section (const char *);
/* Tell assembler to switch to the section for the EH frames. */
extern void named_section_eh_frame_section (void);
Index: passes.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/passes.c,v
retrieving revision 2.3
diff -u -p -r2.3 passes.c
--- passes.c 3 Mar 2004 16:32:38 -0000 2.3
+++ passes.c 9 Mar 2004 12:58:53 -0000
@@ -451,14 +451,14 @@ rest_of_handle_final (tree decl, rtx ins
#ifdef IA64_UNWIND_INFO
/* ??? The IA-64 ".handlerdata" directive must be issued before
the ".endp" directive that closes the procedure descriptor. */
- output_function_exception_table ();
+ output_function_exception_table (fnname);
#endif
assemble_end_function (decl, fnname);
#ifndef IA64_UNWIND_INFO
/* Otherwise, it feels unclean to switch sections in the middle. */
- output_function_exception_table ();
+ output_function_exception_table (fnname);
#endif
if (! quiet_flag)
Index: target.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/target.h,v
retrieving revision 1.82
diff -u -p -r1.82 target.h
--- target.h 3 Mar 2004 23:55:51 -0000 1.82
+++ target.h 9 Mar 2004 12:58:57 -0000
@@ -98,7 +98,7 @@ struct gcc_target
void (* named_section) (const char *, unsigned int);
/* Switch to the section that holds the exception table. */
- void (* exception_section) (void);
+ void (* exception_section) (const char *);
/* Switch to the section that holds the exception frames. */
void (* eh_frame_section) (void);
Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Makefile.in,v
retrieving revision 1.1261
diff -u -p -r1.1261 Makefile.in
--- Makefile.in 9 Mar 2004 01:53:24 -0000 1.1261
+++ Makefile.in 9 Mar 2004 12:59:17 -0000
@@ -494,7 +494,7 @@ INSTALL_LIBGCC = install-libgcc
# Options to use when compiling libgcc2.a.
#
LIBGCC2_DEBUG_CFLAGS = -g
-LIBGCC2_CFLAGS = -O2 $(LIBGCC2_INCLUDES) $(GCC_CFLAGS) $(TARGET_LIBGCC2_CFLAGS) $(LIBGCC2_DEBUG_CFLAGS) $(GTHREAD_FLAGS) -DIN_LIBGCC2 -D__GCC_FLOAT_NOT_NEEDED @inhibit_libc@
+LIBGCC2_CFLAGS = -O2 -ffunction-sections -fdata-sections $(LIBGCC2_INCLUDES) $(GCC_CFLAGS) $(TARGET_LIBGCC2_CFLAGS) $(LIBGCC2_DEBUG_CFLAGS) $(GTHREAD_FLAGS) -DIN_LIBGCC2 -D__GCC_FLOAT_NOT_NEEDED @inhibit_libc@
# Additional options to use when compiling libgcc2.a.
# Some targets override this to -isystem include
Index: ada/Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/ada/Makefile.in,v
retrieving revision 1.73
diff -u -p -r1.73 Makefile.in
--- ada/Makefile.in 25 Feb 2004 15:59:03 -0000 1.73
+++ ada/Makefile.in 9 Mar 2004 12:59:21 -0000
@@ -123,7 +123,7 @@ ADAFLAGS = -W -Wall -gnatpg -gnata
SOME_ADAFLAGS =-gnata
FORCE_DEBUG_ADAFLAGS = -g
GNATLIBFLAGS = -gnatpg
-GNATLIBCFLAGS = -g -O2
+GNATLIBCFLAGS = -g -O2 -ffunction-sections -fdata-sections
GNATLIBCFLAGS_FOR_C = $(GNATLIBCFLAGS) $(TARGET_LIBGCC2_CFLAGS) -fexceptions \
-DIN_RTS
ALL_ADA_CFLAGS = $(X_ADA_CFLAGS) $(T_ADA_CFLAGS) $(ADA_CFLAGS)
Index: ada/Make-lang.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/ada/Make-lang.in,v
retrieving revision 1.77
diff -u -p -r1.77 Make-lang.in
--- ada/Make-lang.in 5 Mar 2004 10:58:57 -0000 1.77
+++ ada/Make-lang.in 9 Mar 2004 12:59:28 -0000
@@ -57,7 +57,7 @@ ADA_CFLAGS =
ALL_ADA_CFLAGS = $(X_ADA_CFLAGS) $(T_ADA_CFLAGS) $(ADA_CFLAGS)
ADA_INCLUDES = -I- -I. -Iada -I$(srcdir)/ada
GNATLIBFLAGS= -W -Wall -gnatpg
-GNATLIBCFLAGS= -g -O2
+GNATLIBCFLAGS= -g -O2 -ffunction-sections -fdata-sections
ADA_INCLUDE_DIR = $(libsubdir)/adainclude
ADA_RTL_OBJ_DIR = $(libsubdir)/adalib
THREAD_KIND=native
Index: bfd/elflink.h
===================================================================
RCS file: /cvs/src/src/bfd/elflink.h,v
retrieving revision 1.254
diff -u -p -r1.254 elflink.h
--- bfd/elflink.h 29 Feb 2004 06:11:52 -0000 1.254
+++ bfd/elflink.h 17 Mar 2004 09:18:01 -0000
@@ -5535,6 +5538,24 @@ elf_gc_smash_unused_vtentry_relocs (stru
return TRUE;
}
+/* Mark sections containing dynamically referenced symbols. This is called
+ through elf_link_hash_traverse. */
+
+static bfd_boolean
+elf_gc_mark_dynamic_ref_symbol (struct elf_link_hash_entry *h,
+ void *okp ATTRIBUTE_UNUSED)
+{
+ if (h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+ if ((h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC))
+ h->root.u.def.section->flags |= SEC_KEEP;
+
+ return TRUE;
+}
+
/* Do mark and sweep of unused sections. */
bfd_boolean
@@ -5549,8 +5570,7 @@ elf_gc_sections (bfd *abfd, struct bfd_l
if (!get_elf_backend_data (abfd)->can_gc_sections
|| info->relocatable
|| info->emitrelocations
- || !is_elf_hash_table (info->hash)
- || elf_hash_table (info)->dynamic_sections_created)
+ || !is_elf_hash_table (info->hash))
{
(*_bfd_error_handler)(_("Warning: gc-sections option ignored"));
return TRUE;
@@ -5570,8 +5590,15 @@ elf_gc_sections (bfd *abfd, struct bfd_l
if (!ok)
return FALSE;
- /* Grovel through relocs to find out who stays ... */
+ /* Mark dynamically referenced symbols. */
+ if (elf_hash_table (info)->dynamic_sections_created)
+ elf_link_hash_traverse (elf_hash_table (info),
+ elf_gc_mark_dynamic_ref_symbol,
+ &ok);
+ if (!ok)
+ return FALSE;
+ /* Grovel through relocs to find out who stays ... */
gc_mark_hook = get_elf_backend_data (abfd)->gc_mark_hook;
for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
{
@@ -5583,8 +5610,15 @@ elf_gc_sections (bfd *abfd, struct bfd_l
for (o = sub->sections; o != NULL; o = o->next)
{
if (o->flags & SEC_KEEP)
- if (!elf_gc_mark (info, o, gc_mark_hook))
- return FALSE;
+ {
+ /* _bfd_elf_discard_section_eh_frame knows how to discard
+ orphaned FDEs so don't mark sections referenced by the
+ EH frame section. */
+ if (strcmp (o->name, ".eh_frame") == 0)
+ o->gc_mark = 1;
+ else if (!elf_gc_mark (info, o, gc_mark_hook))
+ return FALSE;
+ }
}
}
Index: ld/scripttempl/elf.sc
===================================================================
RCS file: /cvs/src/src/ld/scripttempl/elf.sc,v
retrieving revision 1.41
diff -u -p -r1.41 elf.sc
--- ld/scripttempl/elf.sc 10 Oct 2003 01:36:36 -0000 1.41
+++ ld/scripttempl/elf.sc 17 Mar 2004 09:18:02 -0000
@@ -264,6 +264,7 @@ cat <<EOF
{
${RELOCATING+${TEXT_START_SYMBOLS}}
*(.text .stub${RELOCATING+ .text.* .gnu.linkonce.t.*})
+ KEEP (*(.text.*personality*))
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
${RELOCATING+${OTHER_TEXT_SECTIONS}}
@@ -311,13 +312,14 @@ cat <<EOF
{
${RELOCATING+${DATA_START_SYMBOLS}}
*(.data${RELOCATING+ .data.* .gnu.linkonce.d.*})
+ KEEP (*(.gnu.linkonce.d.*personality*))
${CONSTRUCTING+SORT(CONSTRUCTORS)}
}
.data1 ${RELOCATING-0} : { *(.data1) }
.tdata ${RELOCATING-0} : { *(.tdata${RELOCATING+ .tdata.* .gnu.linkonce.td.*}) }
.tbss ${RELOCATING-0} : { *(.tbss${RELOCATING+ .tbss.* .gnu.linkonce.tb.*})${RELOCATING+ *(.tcommon)} }
.eh_frame ${RELOCATING-0} : { KEEP (*(.eh_frame)) }
- .gcc_except_table ${RELOCATING-0} : { *(.gcc_except_table) }
+ .gcc_except_table ${RELOCATING-0} : { KEEP(*(.gcc_except_table)) *(.gcc_except_table.*) }
${WRITABLE_RODATA+${RODATA}}
${OTHER_READWRITE_SECTIONS}
${TEXT_DYNAMIC-${DYNAMIC}}