+2012-08-14 Nick Clifton <nickc@redhat.com>
+
+ PR ld/14265
+ * script-sections.cc (Sections_element::output_section_name): Add
+ keep return parameter.
+ (Output_section_element::match_name): Add keep return parameter.
+ Return the value of the keep_ member.
+ * script-sections.h (class Output_section): Update
+ output_section_name prototype.
+ * layout.cc (Layout::keep_input_section): New public member
+ function.
+ (Layout::choose_output_section): Pass keep parameter to
+ output_section_name.
+ * layout.h (class Layout): Add keep_input_section.
+ * object.cc (Sized_relobj_file::do_layout): Check for kept input
+ sections.
+ * testsuite/Makefile.am: Add a test.
+ * testsuite/Makefile.in: Regenerate.
+ * testsuite/pr14265.c: Source file for the test.
+ * testsuite/pr14265.t: Linker script for the test.
+ * testsuite/pr14265.sh: Shell script for the test.
+
2012-08-14 Alan Modra <amodra@gmail.com>
* target.h (Target::output_section_name): New function.
}
}
+// Returns TRUE iff NAME (an input section from RELOBJ) will
+// be mapped to an output section that should be KEPT.
+
+bool
+Layout::keep_input_section(const Relobj* relobj, const char* name)
+{
+ if (! this->script_options_->saw_sections_clause())
+ return false;
+
+ Script_sections* ss = this->script_options_->script_sections();
+ const char* file_name = relobj == NULL ? NULL : relobj->name().c_str();
+ Output_section** output_section_slot;
+ Script_sections::Section_type script_section_type;
+ bool keep;
+
+ name = ss->output_section_name(file_name, name, &output_section_slot,
+ &script_section_type, &keep);
+ return name != NULL && keep;
+}
+
// Pick the output section to use for section NAME, in input file
// RELOBJ, with type TYPE and flags FLAGS. RELOBJ may be NULL for a
// linker created section. IS_INPUT_SECTION is true if we are
Output_section** output_section_slot;
Script_sections::Section_type script_section_type;
const char* orig_name = name;
+ bool keep;
name = ss->output_section_name(file_name, name, &output_section_slot,
- &script_section_type);
+ &script_section_type, &keep);
+
if (name == NULL)
{
gold_debug(DEBUG_SCRIPT, _("Unable to create output section '%s' "
section_list() const
{ return this->section_list_; }
+ // Returns TRUE iff NAME (an input section from RELOBJ) will
+ // be mapped to an output section that should be KEPT.
+ bool
+ keep_input_section(const Relobj*, const char*);
+
private:
Layout(const Layout&);
Layout& operator=(const Layout&);
if (is_gc_pass_one && parameters->options().gc_sections())
{
if (this->is_section_name_included(name)
+ || layout->keep_input_section (this, name)
|| shdr.get_sh_type() == elfcpp::SHT_INIT_ARRAY
|| shdr.get_sh_type() == elfcpp::SHT_FINI_ARRAY)
{
// Output_section_definition.
virtual const char*
output_section_name(const char*, const char*, Output_section***,
- Script_sections::Section_type*)
+ Script_sections::Section_type*, bool*)
{ return NULL; }
// Initialize OSP with an output section.
// Return whether this element matches FILE_NAME and SECTION_NAME.
// The only real implementation is in Output_section_element_input.
virtual bool
- match_name(const char*, const char*) const
+ match_name(const char*, const char*, bool *) const
{ return false; }
// Set section addresses. This includes applying assignments if the
*dot_section = this->final_dot_section_;
}
- // See whether we match FILE_NAME and SECTION_NAME as an input
- // section.
+ // See whether we match FILE_NAME and SECTION_NAME as an input section.
+ // If we do then also indicate whether the section should be KEPT.
bool
- match_name(const char* file_name, const char* section_name) const;
+ match_name(const char* file_name, const char* section_name, bool* keep) const;
// Set the section address.
void
return true;
}
-// See whether we match FILE_NAME and SECTION_NAME.
+// See whether we match FILE_NAME and SECTION_NAME. If we do then
+// KEEP indicates whether the section should survive garbage collection.
bool
Output_section_element_input::match_name(const char* file_name,
- const char* section_name) const
+ const char* section_name,
+ bool *keep) const
{
if (!this->match_file_name(file_name))
return false;
+ *keep = this->keep_;
+
// If there are no section name patterns, then we match.
if (this->input_section_patterns_.empty())
return true;
// section name.
const char*
output_section_name(const char* file_name, const char* section_name,
- Output_section***, Script_sections::Section_type*);
+ Output_section***, Script_sections::Section_type*,
+ bool*);
// Initialize OSP with an output section.
void
const char* file_name,
const char* section_name,
Output_section*** slot,
- Script_sections::Section_type* psection_type)
+ Script_sections::Section_type* psection_type,
+ bool* keep)
{
// Ask each element whether it matches NAME.
for (Output_section_elements::const_iterator p = this->elements_.begin();
p != this->elements_.end();
++p)
{
- if ((*p)->match_name(file_name, section_name))
+ if ((*p)->match_name(file_name, section_name, keep))
{
// We found a match for NAME, which means that it should go
// into this output section.
const char* file_name,
const char* section_name,
Output_section*** output_section_slot,
- Script_sections::Section_type* psection_type)
+ Script_sections::Section_type* psection_type,
+ bool* keep)
{
for (Sections_elements::const_iterator p = this->sections_elements_->begin();
p != this->sections_elements_->end();
{
const char* ret = (*p)->output_section_name(file_name, section_name,
output_section_slot,
- psection_type);
+ psection_type, keep);
if (ret != NULL)
{
// PSCRIPT_SECTION_TYPE points to a location for returning the section
// type specified in script. This can be SCRIPT_SECTION_TYPE_NONE if
// no type is specified.
+ // *KEEP indicates whether the section should survive garbage collection.
const char*
output_section_name(const char* file_name, const char* section_name,
Output_section*** output_section_slot,
- Section_type* pscript_section_type);
+ Section_type* pscript_section_type,
+ bool* keep);
// Place a marker for an orphan output section into the SECTIONS
// clause.
gc_orphan_section_test.stdout: gc_orphan_section_test
$(TEST_NM) gc_orphan_section_test > gc_orphan_section_test.stdout
+check_SCRIPTS += pr14265.sh
+check_DATA += pr14265.stdout
+MOSTLYCLEANFILES += pr14265
+pr14265.o: pr14265.c
+ $(COMPILE) -O0 -c -o $@ $<
+pr14265: pr14265.o
+ $(LINK) -Bgcctestdir/ -Wl,--gc-sections -T $(srcdir)/pr14265.t -o $@ $<
+pr14265.stdout: pr14265
+ $(TEST_NM) --format=bsd --numeric-sort $< > $@
+
check_SCRIPTS += icf_test.sh
check_DATA += icf_test.stdout
MOSTLYCLEANFILES += icf_test
@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_2 = incremental_test.sh \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ gc_comdat_test.sh gc_tls_test.sh \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ gc_orphan_section_test.sh \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_test.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ pr14265.sh icf_test.sh \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_keep_unique_test.sh \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_safe_test.sh \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_safe_so_test.sh \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ gc_comdat_test.stdout \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ gc_tls_test.stdout \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ gc_orphan_section_test.stdout \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_test.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ pr14265.stdout icf_test.stdout \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_keep_unique_test.stdout \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_safe_test_1.stdout \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_safe_test_2.stdout \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ weak_plt_shared.so debug_msg.err
@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_4 = incremental_test \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ gc_comdat_test gc_tls_test \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ gc_orphan_section_test icf_test \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_keep_unique_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gc_orphan_section_test pr14265 \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_test icf_keep_unique_test \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_safe_test icf_safe_so_test \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ final_layout \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_virtual_function_folding_test \
@p='gc_tls_test.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
gc_orphan_section_test.sh.log: gc_orphan_section_test.sh
@p='gc_orphan_section_test.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+pr14265.sh.log: pr14265.sh
+ @p='pr14265.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
icf_test.sh.log: icf_test.sh
@p='icf_test.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
icf_keep_unique_test.sh.log: icf_keep_unique_test.sh
@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--gc-sections gc_orphan_section_test.o
@GCC_TRUE@@NATIVE_LINKER_TRUE@gc_orphan_section_test.stdout: gc_orphan_section_test
@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_NM) gc_orphan_section_test > gc_orphan_section_test.stdout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@pr14265.o: pr14265.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -O0 -c -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@pr14265: pr14265.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ -Wl,--gc-sections -T $(srcdir)/pr14265.t -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@pr14265.stdout: pr14265
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_NM) --format=bsd --numeric-sort $< > $@
@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_test.o: icf_test.cc
@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -ffunction-sections -g -o $@ $<
@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_test: icf_test.o gcctestdir/ld
--- /dev/null
+int foo0 __attribute__((used,section(".foo0.0")));
+int foo1 __attribute__((used,section(".foo1.0")));
+int foo2 __attribute__((used,section(".foo2.0")));
+
+extern unsigned long __foo0_start;
+extern unsigned long __foo0_end;
+
+extern unsigned long __foo1_start;
+extern unsigned long __foo1_end;
+
+extern unsigned long __foo2_start;
+extern unsigned long __foo2_end;
+
+int
+main (void)
+{
+ return ((__foo0_end - __foo0_start) -
+ (__foo1_end - __foo1_start) -
+ (__foo2_end - __foo2_start));
+}
--- /dev/null
+#!/bin/sh
+
+# pr14265.sh -- test --gc-sections with KEEP
+
+# Copyright 2012 Free Software Foundation, Inc.
+# Written by Nick Clifton <nickc@redhat.com>
+
+# This file is part of gold.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Garbage collection failed to KEEP :"
+ echo " $2"
+ exit 1
+ fi
+}
+
+check pr14265.stdout "foo1_start"
+check pr14265.stdout "foo1_end"
+check pr14265.stdout "foo2_start"
+check pr14265.stdout "foo2_end"
+
--- /dev/null
+SECTIONS
+{
+ .text : { *(.text) }
+
+ __foo0_start = .;
+ .foo0 : { *(.foo0.*) }
+ __foo0_end = .;
+
+ __foo1_start = .;
+ .foo1 : { KEEP(*(.foo1.*)) }
+ __foo1_end = .;
+
+ .foo2 : {
+ __foo2_start = .;
+ KEEP(*(.foo2.*))
+ __foo2_end = .;
+ }
+}
+
+
+ASSERT (__foo1_start < __foo1_end, "foo1 not KEPT");
+ASSERT ((__foo1_end - __foo1_start) == (__foo2_end - __foo2_start),"foo2 not KEPT");
+
+2012-08-14 Nick Clifton <nickc@redhat.com>
+
+ PR ld/14265
+ * ld-gc/gc.exp: Add a new test.
+ * ld-gc/pr14265.c: Source file for the new test.
+ * ld-gc/pr14265.t: Linker script for the new test.
+ * ld-gc/pr14265.d: Expected symbol dump.
+
2012-08-13 Maciej W. Rozycki <macro@codesourcery.com>
* ld-mips-elf/export-class-call16-o32.dd: New test.
ld_compile "$CC $CFLAGS $cflags" $srcdir/$subdir/pr13683.c tmpdir/pr13683.o
run_dump_test "pr13683"
}
+
+if { [is_remote host] || [which $CC] != 0 } {
+ ld_compile "$CC $CFLAGS $cflags" $srcdir/$subdir/pr14265.c tmpdir/pr14265.o
+ run_dump_test "pr14265"
+}
--- /dev/null
+int foo0 __attribute__((used,section(".foo0.0")));
+int foo1 __attribute__((used,section(".foo1.0")));
+int foo2 __attribute__((used,section(".foo2.0")));
+
+extern unsigned long __foo0_start;
+extern unsigned long __foo0_end;
+
+extern unsigned long __foo1_start;
+extern unsigned long __foo1_end;
+
+extern unsigned long __foo2_start;
+extern unsigned long __foo2_end;
+
+int
+main (void)
+{
+ return ((__foo0_end - __foo0_start) -
+ (__foo1_end - __foo1_start) -
+ (__foo2_end - __foo2_start));
+}
--- /dev/null
+#name: --gc-sections with KEEP
+#source: dummy.s
+#ld: --gc-sections -T pr14265.t -e 0 tmpdir/pr14265.o
+#nm: --format=bsd --numeric-sort
+
+#...
+[0-9a-f]+[ ]d[ ]_*foo1_start
+[0-9a-f]+[ ]D[ ]_*foo1
+[0-9a-f]+[ ]d[ ]_*foo1_end
+[0-9a-f]+[ ]d[ ]_*foo2_start
+[0-9a-f]+[ ]D[ ]_*foo2
+[0-9a-f]+[ ]d[ ]_*foo2_end
+#...
--- /dev/null
+SECTIONS
+{
+ .text : { *(.text) }
+
+ __foo0_start = .;
+ .foo0 : { *(.foo0.*) }
+ __foo0_end = .;
+
+ __foo1_start = .;
+ .foo1 : { KEEP(*(.foo1.*)) }
+ __foo1_end = .;
+
+ .foo2 : {
+ __foo2_start = .;
+ KEEP(*(.foo2.*))
+ __foo2_end = .;
+ }
+ /DISCARD/ : { *(*) }
+}
+
+ASSERT (__foo1_start < __foo1_end, "foo1 not KEPT");
+ASSERT ((__foo1_end - __foo1_start) == (__foo2_end - __foo2_start),"foo2 not KEPT");