diff --git a/gold/ChangeLog b/gold/ChangeLog index c903192976..854af4bcf9 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,13 @@ +2016-03-20 Cary Coutant + + 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 * mips.cc (Mips_relobj::is_n64_): Remove. diff --git a/gold/ehframe.cc b/gold/ehframe.cc index 57eb031faf..e1a1e741b4 100644 --- a/gold/ehframe.cc +++ b/gold/ehframe.cc @@ -992,13 +992,68 @@ Eh_frame::read_fde(Sized_relobj_file* object, 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) @@ -1031,23 +1086,18 @@ Eh_frame::read_fde(Sized_relobj_file* object, // 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(); } diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am index f5528d12a0..fbaee16c5f 100644 --- a/gold/testsuite/Makefile.am +++ b/gold/testsuite/Makefile.am @@ -388,6 +388,16 @@ eh_test_b.o: eh_test_b.cc 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 diff --git a/gold/testsuite/Makefile.in b/gold/testsuite/Makefile.in index 988d6f7c36..1246504c4b 100644 --- a/gold/testsuite/Makefile.in +++ b/gold/testsuite/Makefile.in @@ -72,7 +72,8 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \ @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 \ @@ -95,6 +96,7 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \ @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 \ @@ -119,6 +121,7 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \ @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 @@ -4496,6 +4499,8 @@ icf_sht_rel_addend_test.sh.log: icf_sht_rel_addend_test.sh @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 @@ -5295,6 +5300,12 @@ uninstall-am: @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 diff --git a/gold/testsuite/eh_test_2.sh b/gold/testsuite/eh_test_2.sh new file mode 100755 index 0000000000..eb26854bf9 --- /dev/null +++ b/gold/testsuite/eh_test_2.sh @@ -0,0 +1,37 @@ +#!/bin/sh + +# eh_test_2.sh -- check that .eh_frame_hdr is valid. + +# Copyright (C) 2016 Free Software Foundation, Inc. +# Written by Cary Coutant . + +# 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 diff --git a/gold/testsuite/eh_test_a.cc b/gold/testsuite/eh_test_a.cc index ad4bcc2e88..e3c8a16a8b 100644 --- a/gold/testsuite/eh_test_a.cc +++ b/gold/testsuite/eh_test_a.cc @@ -1,4 +1,9 @@ +template void -bar() +bar(C*) { } + +template +void +bar(int*); diff --git a/gold/testsuite/eh_test_b.cc b/gold/testsuite/eh_test_b.cc index 50538df4b8..3bf96e9d3c 100644 --- a/gold/testsuite/eh_test_b.cc +++ b/gold/testsuite/eh_test_b.cc @@ -6,6 +6,16 @@ foo() { } +template +void +bar(C*) +{ +} + +template +void +bar(int*); + int main() {