+2016-03-20 Cary Coutant <ccoutant@gmail.com>
+
+ PR gold/19002
+ * ehframe.cc (Eh_frame::read_fde): Check for dropped functions.
+ * testsuite/Makefile.am (eh_test_2): New test.
+ * testsuite/Makefile.in: Regenerate.
+ * testsuite/eh_test_2.sh: New test script.
+ * testsuite/eh_test_a.cc (bar): Make it comdat.
+ * testsuite/eh_test_b.cc (bar): Add a duplicate copy.
+
2016-03-18 Vladimir Radosavljevic <vladimir.radosavljevic@imgtec.com>
* mips.cc (Mips_relobj::is_n64_): Remove.
return false;
Cie* cie = pcie->second;
+ int pc_size = 0;
+ switch (cie->fde_encoding() & 7)
+ {
+ case elfcpp::DW_EH_PE_udata2:
+ pc_size = 2;
+ break;
+ case elfcpp::DW_EH_PE_udata4:
+ pc_size = 4;
+ break;
+ case elfcpp::DW_EH_PE_udata8:
+ gold_assert(size == 64);
+ pc_size = 8;
+ break;
+ case elfcpp::DW_EH_PE_absptr:
+ pc_size = size == 32 ? 4 : 8;
+ break;
+ default:
+ // All other cases were rejected in Eh_frame::read_cie.
+ gold_unreachable();
+ }
+
// The FDE should start with a reloc to the start of the code which
// it describes.
if (relocs->advance(pfde - pcontents) > 0)
return false;
-
if (relocs->next_offset() != pfde - pcontents)
- return false;
+ {
+ // In an object produced by a relocatable link, gold may have
+ // discarded a COMDAT group in the previous link, but not the
+ // corresponding FDEs. In that case, gold will have discarded
+ // the relocations, so the FDE will have a non-relocatable zero
+ // (regardless of whether the PC encoding is absolute, pc-relative,
+ // or data-relative) instead of a pointer to the start of the code.
+
+ uint64_t pc_value = 0;
+ switch (pc_size)
+ {
+ case 2:
+ pc_value = elfcpp::Swap<16, big_endian>::readval(pfde);
+ break;
+ case 4:
+ pc_value = elfcpp::Swap<32, big_endian>::readval(pfde);
+ break;
+ case 8:
+ pc_value = elfcpp::Swap_unaligned<64, big_endian>::readval(pfde);
+ break;
+ default:
+ gold_unreachable();
+ }
+
+ if (pc_value == 0)
+ {
+ // This FDE applies to a discarded function. We
+ // can discard this FDE.
+ object->add_merge_mapping(this, shndx, (pfde - 8) - pcontents,
+ pfdeend - (pfde - 8), -1);
+ return true;
+ }
+
+ // Otherwise, reject the FDE.
+ return false;
+ }
unsigned int symndx = relocs->next_symndx();
if (symndx == -1U)
// FDE corresponds to a function that was discarded during optimization
// (too late to discard the corresponding FDE).
uint64_t address_range = 0;
- int pc_size = cie->fde_encoding() & 7;
- if (pc_size == elfcpp::DW_EH_PE_absptr)
- pc_size = size == 32 ? elfcpp::DW_EH_PE_udata4 : elfcpp::DW_EH_PE_udata8;
switch (pc_size)
{
- case elfcpp::DW_EH_PE_udata2:
+ case 2:
address_range = elfcpp::Swap<16, big_endian>::readval(pfde + 2);
break;
- case elfcpp::DW_EH_PE_udata4:
+ case 4:
address_range = elfcpp::Swap<32, big_endian>::readval(pfde + 4);
break;
- case elfcpp::DW_EH_PE_udata8:
- gold_assert(size == 64);
+ case 8:
address_range = elfcpp::Swap_unaligned<64, big_endian>::readval(pfde + 8);
break;
default:
- // All other cases were rejected in Eh_frame::read_cie.
gold_unreachable();
}
eh_test: eh_test_a.o eh_test_b.o gcctestdir/ld
$(CXXLINK_S) -Bgcctestdir/ eh_test_a.o eh_test_b.o
+check_SCRIPTS += eh_test_2.sh
+check_DATA += eh_test_2.sects
+MOSTLYCLEANFILES += eh_test_2.sects
+eh_test_r.o: eh_test_a.o eh_test_b.o gcctestdir/ld
+ gcctestdir/ld -r -o $@ eh_test_a.o eh_test_b.o
+eh_test_2: eh_test_r.o gcctestdir/ld
+ $(CXXLINK_S) -Bgcctestdir/ -Wl,--eh-frame-hdr eh_test_r.o
+eh_test_2.sects: eh_test_2
+ $(TEST_READELF) -SW $< >$@ 2>/dev/null
+
if HAVE_STATIC
check_PROGRAMS += basic_static_test
basic_static_test: basic_test.o gcctestdir/ld
@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_string_merge_test.sh \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_sht_rel_addend_test.sh \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ merge_string_literals.sh \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared.sh weak_plt.sh
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ eh_test_2.sh two_file_shared.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ weak_plt.sh
@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_3 = incremental_test.stdout \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ gc_comdat_test.stdout \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ gc_tls_test.stdout \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_string_merge_test.stdout \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_sht_rel_addend_test.stdout \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ merge_string_literals.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ eh_test_2.sects \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared.dbg \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ weak_plt_shared.so
@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_4 = incremental_test \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_string_merge_test \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_sht_rel_addend_test \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ merge_string_literals \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ eh_test_2.sects \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared.dbg \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ alt/weak_undef_lib.so \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ libweak_undef_2.a
@p='icf_sht_rel_addend_test.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
merge_string_literals.sh.log: merge_string_literals.sh
@p='merge_string_literals.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+eh_test_2.sh.log: eh_test_2.sh
+ @p='eh_test_2.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
two_file_shared.sh.log: two_file_shared.sh
@p='two_file_shared.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
weak_plt.sh.log: weak_plt.sh
@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -o $@ $<
@GCC_TRUE@@NATIVE_LINKER_TRUE@eh_test: eh_test_a.o eh_test_b.o gcctestdir/ld
@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK_S) -Bgcctestdir/ eh_test_a.o eh_test_b.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@eh_test_r.o: eh_test_a.o eh_test_b.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld -r -o $@ eh_test_a.o eh_test_b.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@eh_test_2: eh_test_r.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK_S) -Bgcctestdir/ -Wl,--eh-frame-hdr eh_test_r.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@eh_test_2.sects: eh_test_2
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -SW $< >$@ 2>/dev/null
@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@basic_static_test: basic_test.o gcctestdir/ld
@GCC_TRUE@@HAVE_STATIC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -static basic_test.o
--- /dev/null
+#!/bin/sh
+
+# eh_test_2.sh -- check that .eh_frame_hdr is valid.
+
+# Copyright (C) 2016 Free Software Foundation, Inc.
+# Written by Cary Coutant <ccoutant@gmail.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.
+
+sections="eh_test_2.sects"
+
+hdr_section=`fgrep .eh_frame_hdr $sections`
+size_field=`echo $hdr_section | sed -e 's/\[//' | awk '{print $6;}'`
+size=`printf %d "0x$size_field"`
+
+if test "$size" -le 8; then
+ echo ".eh_frame_hdr section is too small:"
+ echo "$hdr_section"
+ exit 1
+fi
+
+exit 0
+template<typename C>
void
-bar()
+bar(C*)
{
}
+
+template
+void
+bar<int>(int*);
{
}
+template<typename C>
+void
+bar(C*)
+{
+}
+
+template
+void
+bar<int>(int*);
+
int
main()
{