diff options
-rw-r--r-- | gold/ChangeLog | 23 | ||||
-rw-r--r-- | gold/gc.h | 3 | ||||
-rw-r--r-- | gold/icf.cc | 270 | ||||
-rw-r--r-- | gold/icf.h | 30 | ||||
-rw-r--r-- | gold/options.h | 2 | ||||
-rw-r--r-- | gold/testsuite/Makefile.am | 10 | ||||
-rw-r--r-- | gold/testsuite/Makefile.in | 19 | ||||
-rw-r--r-- | gold/testsuite/icf_test_pr21066.cc | 67 | ||||
-rwxr-xr-x | gold/testsuite/icf_test_pr21066.sh | 48 |
9 files changed, 438 insertions, 34 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog index f74b92e..5d23e71 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,26 @@ +2019-05-10 Joshua Oreman <oremanj@hudson-trading.com> + + PR gold/21066 + * gc.h (gc_process_relocs): Track relocations in .eh_frame sections + when ICF is enabled, even though the .eh_frame sections themselves + are not foldable. + * icf.cc (get_section_contents): Change arguments to permit operation + on just part of a section. Include extra identity regions in the + referring section's contents recursively. + (match_sections): Lock object here instead of in get_section_contents + so that get_section_contents can operate recursively. + (Icf::add_ehframe_links): New method. + (Icf::find_identical_sections): Pass .eh_frame sections to + add_ehframe_links(). Increase default iteration count from 2 to 3 + because handling exception info typically requires one extra iteration. + * icf.h (Icf::extra_identity_list_): New data member with accessor. + (is_section_foldable_candidate): Include .gcc_except_table sections. + * options.h: Update documentation for new default ICF iteration count. + * testsuite/Makefile.am (icf_test_pr21066): New test case. + * testsuite/Makefile.in: Regenerate. + * testsuite/icf_test_pr21066.cc: New source file. + * testsuite/icf_test_pr21066.sh: New test script. + 2019-02-19 Egeyar Bagcioglu <egeyar.bagcioglu@oracle.com> PR gold/23870 @@ -200,7 +200,8 @@ gc_process_relocs( bool check_section_for_function_pointers = false; if (parameters->options().icf_enabled() - && is_section_foldable_candidate(src_section_name.c_str())) + && (is_section_foldable_candidate(src_section_name) + || is_prefix_of(".eh_frame", src_section_name.c_str()))) { is_icf_tracked = true; Section_id src_id(src_obj, src_indx); diff --git a/gold/icf.cc b/gold/icf.cc index 3411306..56b6f29 100644 --- a/gold/icf.cc +++ b/gold/icf.cc @@ -130,6 +130,26 @@ // folded causing unpredictable run-time behaviour if the pointers were used // in comparisons. // +// Notes regarding C++ exception handling : +// -------------------------------------- +// +// It is possible for two sections to have identical text, identical +// relocations, but different exception handling metadata (unwind +// information in the .eh_frame section, and/or handler information in +// a .gcc_except_table section). Thus, if a foldable section is +// referenced from a .eh_frame FDE, we must include in its checksum +// the contents of that FDE as well as of the CIE that the FDE refers +// to. The CIE and FDE in turn probably contain relocations to the +// personality routine and LSDA, which are handled like any other +// relocation for ICF purposes. This logic is helped by the fact that +// gcc with -ffunction-sections puts each function's LSDA in its own +// .gcc_except_table.<functionname> section. Given sections for two +// functions with nontrivial exception handling logic, we will +// determine on the first iteration that their .gcc_except_table +// sections are identical and can be folded, and on the second +// iteration that their .text and .eh_frame contents (including the +// now-merged .gcc_except_table relocations for the LSDA) are +// identical and can be folded. // // // How to run : --icf=[safe|all|none] @@ -148,6 +168,8 @@ #include "elfcpp.h" #include "int_encoding.h" +#include <limits> + namespace gold { @@ -259,29 +281,35 @@ get_rel_addend(const unsigned char* reloc_addend_ptr, // subsequent invocations of this function. // Parameters : // FIRST_ITERATION : true if it is the first invocation. +// FIXED_CACHE : String that stores the portion of the result that +// does not change from iteration to iteration; +// written if first_iteration is true, read if it's false. // SECN : Section for which contents are desired. -// SECTION_NUM : Unique section number of this section. +// SELF_SECN : Relocations that target this section will be +// considered "relocations to self" so that recursive +// functions can be folded. Should normally be the +// same as `secn` except when processing extra identity +// regions. // NUM_TRACKED_RELOCS : Vector reference to store the number of relocs // to ICF sections. // KEPT_SECTION_ID : Vector which maps folded sections to kept sections. -// SECTION_CONTENTS : Store the section's text and relocs to non-ICF -// sections. +// START_OFFSET : Only consider the part of the section at and after +// this offset. +// END_OFFSET : Only consider the part of the section before this +// offset. static std::string get_section_contents(bool first_iteration, + std::string* fixed_cache, const Section_id& secn, - unsigned int section_num, + const Section_id& self_secn, unsigned int* num_tracked_relocs, Symbol_table* symtab, const std::vector<unsigned int>& kept_section_id, - std::vector<std::string>* section_contents) + section_offset_type start_offset = 0, + section_offset_type end_offset = + std::numeric_limits<section_offset_type>::max()) { - // Lock the object so we can read from it. This is only called - // single-threaded from queue_middle_tasks, so it is OK to lock. - // Unfortunately we have no way to pass in a Task token. - const Task* dummy_task = reinterpret_cast<const Task*>(-1); - Task_lock_obj<Object> tl(dummy_task, secn.first); - section_size_type plen; const unsigned char* contents = NULL; if (first_iteration) @@ -292,9 +320,6 @@ get_section_contents(bool first_iteration, std::string buffer; std::string icf_reloc_buffer; - if (num_tracked_relocs) - *num_tracked_relocs = 0; - Icf::Reloc_info_list& reloc_info_list = symtab->icf()->reloc_info_list(); @@ -330,6 +355,11 @@ get_section_contents(bool first_iteration, Symbol* gsym = *it_s; bool is_section_symbol = false; + // Ignore relocations outside the region we were told to look at + if (static_cast<section_offset_type>(*it_o) < start_offset + || static_cast<section_offset_type>(*it_o) >= end_offset) + continue; + // A -1 value in the symbol vector indicates a local section symbol. if (gsym == reinterpret_cast<Symbol*>(-1)) { @@ -367,7 +397,7 @@ get_section_contents(bool first_iteration, snprintf(addend_str, sizeof(addend_str), "%llx %llx %llx", static_cast<long long>((*it_a).first), static_cast<long long>((*it_a).second), - static_cast<unsigned long long>(*it_o)); + static_cast<unsigned long long>(*it_o - start_offset)); // If the symbol pointed to by the reloc is not in an ordinary // section or if the symbol type is not FROM_OBJECT, then the @@ -390,8 +420,8 @@ get_section_contents(bool first_iteration, // If this reloc turns back and points to the same section, // like a recursive call, use a special symbol to mark this. - if (reloc_secn.first == secn.first - && reloc_secn.second == secn.second) + if (reloc_secn.first == self_secn.first + && reloc_secn.second == self_secn.second) { if (first_iteration) { @@ -568,16 +598,48 @@ get_section_contents(bool first_iteration, if (first_iteration) { buffer.append("Contents = "); - buffer.append(reinterpret_cast<const char*>(contents), plen); + + const unsigned char* slice_end = + contents + std::min<section_offset_type>(plen, end_offset); + + if (contents + start_offset < slice_end) + { + buffer.append(reinterpret_cast<const char*>(contents + start_offset), + slice_end - (contents + start_offset)); + } + } + + // Add any extra identity regions. + std::pair<Icf::Extra_identity_list::const_iterator, + Icf::Extra_identity_list::const_iterator> + extra_range = symtab->icf()->extra_identity_list().equal_range(secn); + for (Icf::Extra_identity_list::const_iterator it_ext = extra_range.first; + it_ext != extra_range.second; ++it_ext) + { + std::string external_fixed; + std::string external_all = + get_section_contents(first_iteration, &external_fixed, + it_ext->second.section, self_secn, + num_tracked_relocs, symtab, + kept_section_id, it_ext->second.offset, + it_ext->second.offset + it_ext->second.length); + buffer.append(external_fixed); + icf_reloc_buffer.append(external_all, external_fixed.length(), + std::string::npos); + } + + if (first_iteration) + { // Store the section contents that don't change to avoid recomputing // during the next call to this function. - (*section_contents)[section_num] = buffer; + *fixed_cache = buffer; } else { gold_assert(buffer.empty()); + // Reuse the contents computed in the previous iteration. - buffer.append((*section_contents)[section_num]); + buffer.append(*fixed_cache); } buffer.append(icf_reloc_buffer); @@ -641,14 +703,22 @@ match_sections(unsigned int iteration_num, continue; Section_id secn = id_section[i]; + + // Lock the object so we can read from it. This is only called + // single-threaded from queue_middle_tasks, so it is OK to lock. + // Unfortunately we have no way to pass in a Task token. + const Task* dummy_task = reinterpret_cast<const Task*>(-1); + Task_lock_obj<Object> tl(dummy_task, secn.first); + std::string this_secn_contents; uint32_t cksum; + std::string* this_secn_cache = &((*section_contents)[i]); if (iteration_num == 1) { unsigned int num_relocs = 0; - this_secn_contents = get_section_contents(true, secn, i, &num_relocs, - symtab, (*kept_section_id), - section_contents); + this_secn_contents = get_section_contents(true, this_secn_cache, + secn, secn, &num_relocs, + symtab, (*kept_section_id)); (*num_tracked_relocs)[i] = num_relocs; } else @@ -658,9 +728,9 @@ match_sections(unsigned int iteration_num, // This section is already folded into something. continue; } - this_secn_contents = get_section_contents(false, secn, i, NULL, - symtab, (*kept_section_id), - section_contents); + this_secn_contents = get_section_contents(false, this_secn_cache, + secn, secn, NULL, + symtab, (*kept_section_id)); } const unsigned char* this_secn_contents_array = @@ -766,8 +836,115 @@ is_function_ctor_or_dtor(const std::string& section_name) return false; } +// Iterate through the .eh_frame section that has index +// `ehframe_shndx` in `object`, adding entries to extra_identity_list_ +// that will cause the contents of each FDE and its CIE to be included +// in the logical ICF identity of the function that the FDE refers to. + +bool +Icf::add_ehframe_links(Relobj* object, unsigned int ehframe_shndx, + Reloc_info& relocs) +{ + section_size_type contents_len; + const unsigned char* pcontents = object->section_contents(ehframe_shndx, + &contents_len, + false); + const unsigned char* p = pcontents; + const unsigned char* pend = pcontents + contents_len; + + Sections_reachable_info::iterator it_target = relocs.section_info.begin(); + Sections_reachable_info::iterator it_target_end = relocs.section_info.end(); + Offset_info::iterator it_offset = relocs.offset_info.begin(); + Offset_info::iterator it_offset_end = relocs.offset_info.end(); + + // Maps section offset to the length of the CIE defined at that offset. + typedef Unordered_map<section_offset_type, section_size_type> Cie_map; + Cie_map cies; + + uint32_t (*read_swap_32)(const unsigned char*); + if (object->is_big_endian()) + read_swap_32 = &elfcpp::Swap<32, true>::readval; + else + read_swap_32 = &elfcpp::Swap<32, false>::readval; + + // TODO: The logic for parsing the CIE/FDE framing is copied from + // Eh_frame::do_add_ehframe_input_section() and might want to be + // factored into a shared helper function. + while (p < pend) + { + if (pend - p < 4) + return false; + + unsigned int len = read_swap_32(p); + p += 4; + if (len == 0) + { + // We should only find a zero-length entry at the end of the + // section. + if (p < pend) + return false; + break; + } + // We don't support a 64-bit .eh_frame. + if (len == 0xffffffff) + return false; + if (static_cast<unsigned int>(pend - p) < len) + return false; + + const unsigned char* const pentend = p + len; + + if (pend - p < 4) + return false; + + unsigned int id = read_swap_32(p); + p += 4; + + if (id == 0) + { + // CIE. + cies.insert(std::make_pair(p - pcontents, len - 4)); + } + else + { + // FDE. + Cie_map::const_iterator it; + it = cies.find((p - pcontents) - (id - 4)); + if (it == cies.end()) + return false; + + // Figure out which section this FDE refers into. The word at `p` + // is an address, and we expect to see a relocation there. If not, + // this FDE isn't ICF-relevant. + while (it_offset != it_offset_end + && it_target != it_target_end + && static_cast<ptrdiff_t>(*it_offset) < (p - pcontents)) + { + ++it_offset; + ++it_target; + } + if (it_offset != it_offset_end + && it_target != it_target_end + && static_cast<ptrdiff_t>(*it_offset) == (p - pcontents)) + { + // Found a reloc. Add this FDE and its CIE as extra identity + // info for the section it refers to. + Extra_identity_info rec_fde = {Section_id(object, ehframe_shndx), + p - pcontents, len - 4}; + Extra_identity_info rec_cie = {Section_id(object, ehframe_shndx), + it->first, it->second}; + extra_identity_list_.insert(std::make_pair(*it_target, rec_fde)); + extra_identity_list_.insert(std::make_pair(*it_target, rec_cie)); + } + } + + p = pentend; + } + + return true; +} + // This is the main ICF function called in gold.cc. This does the -// initialization and calls match_sections repeatedly (twice by default) +// initialization and calls match_sections repeatedly (thrice by default) // which computes the crc checksums and detects identical functions. void @@ -792,12 +969,18 @@ Icf::find_identical_sections(const Input_objects* input_objects, // Unfortunately we have no way to pass in a Task token. const Task* dummy_task = reinterpret_cast<const Task*>(-1); Task_lock_obj<Object> tl(dummy_task, *p); + std::vector<unsigned int> eh_frame_ind; - for (unsigned int i = 0;i < (*p)->shnum(); ++i) + for (unsigned int i = 0; i < (*p)->shnum(); ++i) { const std::string section_name = (*p)->section_name(i); if (!is_section_foldable_candidate(section_name)) - continue; + { + if (is_prefix_of(".eh_frame", section_name.c_str())) + eh_frame_ind.push_back(i); + continue; + } + if (!(*p)->is_section_included(i)) continue; if (parameters->options().gc_sections() @@ -822,14 +1005,39 @@ Icf::find_identical_sections(const Input_objects* input_objects, section_contents.push_back(""); section_num++; } + + for (std::vector<unsigned int>::iterator it_eh_ind = eh_frame_ind.begin(); + it_eh_ind != eh_frame_ind.end(); ++it_eh_ind) + { + // gc_process_relocs() recorded relocations for this + // section even though we can't fold it. We need to + // use those relocations to associate other foldable + // sections with the FDEs and CIEs that are relevant + // to them, so we can avoid merging sections that + // don't have identical exception-handling behavior. + + Section_id sect(*p, *it_eh_ind); + Reloc_info_list::iterator it_rel = this->reloc_info_list().find(sect); + if (it_rel != this->reloc_info_list().end()) + { + if (!add_ehframe_links(*p, *it_eh_ind, it_rel->second)) + { + gold_warning(_("could not parse eh_frame section %s(%s); ICF " + "might not preserve exception handling " + "behavior"), + (*p)->name().c_str(), + (*p)->section_name(*it_eh_ind).c_str()); + } + } + } } unsigned int num_iterations = 0; - // Default number of iterations to run ICF is 2. + // Default number of iterations to run ICF is 3. unsigned int max_iterations = (parameters->options().icf_iterations() > 0) ? parameters->options().icf_iterations() - : 2; + : 3; bool converged = false; @@ -64,6 +64,19 @@ class Icf typedef Unordered_map<Section_id, Reloc_info, Section_id_hash> Reloc_info_list; + // A region of some other section that should be considered part of + // a section for ICF purposes. This is used to avoid folding sections + // that have identical text and relocations but different .eh_frame + // information. + typedef struct + { + Section_id section; + section_offset_type offset; + section_size_type length; + } Extra_identity_info; + + typedef std::multimap<Section_id, Extra_identity_info> Extra_identity_list; + Icf() : id_section_(), section_id_(), kept_section_id_(), fptr_section_id_(), @@ -137,6 +150,12 @@ class Icf reloc_info_list() { return this->reloc_info_list_; } + // Returns a map from section to region of a different section that should + // be considered part of the key section for ICF purposes. + Extra_identity_list& + extra_identity_list() + { return this->extra_identity_list_; } + // Returns a mapping of each section to a unique integer. Uniq_secn_id_map& section_to_int_map() @@ -144,6 +163,10 @@ class Icf private: + bool + add_ehframe_links(Relobj* object, unsigned int ehframe_shndx, + Reloc_info& ehframe_relocs); + // Maps integers to sections. std::vector<Section_id> id_section_; // Does the reverse. @@ -160,17 +183,24 @@ class Icf bool icf_ready_; // This list is populated by gc_process_relocs in gc.h. Reloc_info_list reloc_info_list_; + // Regions of other sections that should be considered part of + // each section for ICF purposes. + Extra_identity_list extra_identity_list_; }; // This function returns true if this section corresponds to a function that // should be considered by icf as a possible candidate for folding. Some // earlier gcc versions, like 4.0.3, put constructors and destructors in // .gnu.linkonce.t sections and hence should be included too. +// The mechanism used to safely fold functions referenced by .eh_frame +// requires folding .gcc_except_table sections as well; see "Notes regarding +// C++ exception handling" at the top of icf.cc for an explanation why. inline bool is_section_foldable_candidate(const std::string& section_name) { const char* section_name_cstr = section_name.c_str(); return (is_prefix_of(".text", section_name_cstr) + || is_prefix_of(".gcc_except_table", section_name_cstr) || is_prefix_of(".gnu.linkonce.t", section_name_cstr)); } diff --git a/gold/options.h b/gold/options.h index 5ca89bd..f7c1279 100644 --- a/gold/options.h +++ b/gold/options.h @@ -946,7 +946,7 @@ class General_options {"none", "all", "safe"}); DEFINE_uint(icf_iterations, options::TWO_DASHES , '\0', 0, - N_("Number of iterations of ICF (default 2)"), N_("COUNT")); + N_("Number of iterations of ICF (default 3)"), N_("COUNT")); DEFINE_special(incremental, options::TWO_DASHES, '\0', N_("Do an incremental link if possible; " diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am index e499177..4c26f33 100644 --- a/gold/testsuite/Makefile.am +++ b/gold/testsuite/Makefile.am @@ -278,6 +278,16 @@ icf_test: icf_test.o gcctestdir/ld icf_test.map: icf_test @touch icf_test.map +check_SCRIPTS += icf_test_pr21066.sh +check_DATA += icf_test_pr21066.map +MOSTLYCLEANFILES += icf_test_pr21066 icf_test_pr21066.map +icf_test_pr21066.o: icf_test_pr21066.cc + $(CXXCOMPILE) -O0 -c -ffunction-sections -g -o $@ $< +icf_test_pr21066: icf_test_pr21066.o gcctestdir/ld + $(CXXLINK) -o icf_test_pr21066 -Bgcctestdir/ -Wl,--icf=all,-Map,icf_test_pr21066.map icf_test_pr21066.o +icf_test_pr21066.map: icf_test_pr21066 + @touch icf_test_pr21066.map + check_SCRIPTS += icf_keep_unique_test.sh check_DATA += icf_keep_unique_test.stdout MOSTLYCLEANFILES += icf_keep_unique_test diff --git a/gold/testsuite/Makefile.in b/gold/testsuite/Makefile.in index a5b109b..dac0db2 100644 --- a/gold/testsuite/Makefile.in +++ b/gold/testsuite/Makefile.in @@ -129,7 +129,7 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ gc_orphan_section_test.sh \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ pr14265.sh pr20717.sh \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ gc_dynamic_list_test.sh \ -@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_test.sh \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_test.sh icf_test_pr21066.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_pie_test.sh \ @@ -152,6 +152,7 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ pr14265.stdout pr20717.stdout \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ gc_dynamic_list_test.stdout \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_test.map \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_test_pr21066.map \ @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 \ @@ -182,6 +183,8 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ gc_orphan_section_test pr14265 \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ pr20717 gc_dynamic_list_test \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_test icf_test.map \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_test_pr21066 \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_test_pr21066.map \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_keep_unique_test \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_safe_test icf_safe_test.map \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_safe_pie_test \ @@ -2705,6 +2708,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -5517,6 +5521,13 @@ icf_test.sh.log: icf_test.sh --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) +icf_test_pr21066.sh.log: icf_test_pr21066.sh + @p='icf_test_pr21066.sh'; \ + b='icf_test_pr21066.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) icf_keep_unique_test.sh.log: icf_keep_unique_test.sh @p='icf_keep_unique_test.sh'; \ b='icf_keep_unique_test.sh'; \ @@ -7935,6 +7946,12 @@ uninstall-am: @GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -o icf_test -Wl,--icf=all,-Map,icf_test.map icf_test.o @GCC_TRUE@@NATIVE_LINKER_TRUE@icf_test.map: icf_test @GCC_TRUE@@NATIVE_LINKER_TRUE@ @touch icf_test.map +@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_test_pr21066.o: icf_test_pr21066.cc +@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -ffunction-sections -g -o $@ $< +@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_test_pr21066: icf_test_pr21066.o gcctestdir/ld +@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -o icf_test_pr21066 -Bgcctestdir/ -Wl,--icf=all,-Map,icf_test_pr21066.map icf_test_pr21066.o +@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_test_pr21066.map: icf_test_pr21066 +@GCC_TRUE@@NATIVE_LINKER_TRUE@ @touch icf_test_pr21066.map @GCC_TRUE@@NATIVE_LINKER_TRUE@icf_keep_unique_test.o: icf_keep_unique_test.cc @GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -ffunction-sections -g -o $@ $< @GCC_TRUE@@NATIVE_LINKER_TRUE@icf_keep_unique_test: icf_keep_unique_test.o gcctestdir/ld diff --git a/gold/testsuite/icf_test_pr21066.cc b/gold/testsuite/icf_test_pr21066.cc new file mode 100644 index 0000000..568873d --- /dev/null +++ b/gold/testsuite/icf_test_pr21066.cc @@ -0,0 +1,67 @@ +// icf_test.cc -- a test case for gold + +// Copyright (C) 2009-2018 Free Software Foundation, Inc. +// Test case from PR 21066 submitted by Gandhi Shaheen + +// 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. + +// The goal of this program is to verify if identical code folding +// correctly identifies and folds functions. folded_func must be +// folded into kept_func. + +// Written by Sriraman Tallam <tmsriram@google.com>. + +#include <stdio.h> + +struct first_exception { +}; + +struct second_exception { +}; + +typedef void (*callback_fn_t)(); + +void raise_first_exception() +{ + throw first_exception(); +} + +void raise_second_exception() +{ + throw second_exception(); +} + +template<typename E> +void capture_exception_of_type(volatile callback_fn_t f) +{ + try { + f(); + } catch (E& e) { + puts("caught expected exception"); + } catch (...) { + puts("ERROR: caught unexpected exception"); + throw; + } +} + +int main() +{ + capture_exception_of_type<first_exception>(raise_first_exception); + capture_exception_of_type<second_exception>(raise_second_exception); + return 0; +} diff --git a/gold/testsuite/icf_test_pr21066.sh b/gold/testsuite/icf_test_pr21066.sh new file mode 100755 index 0000000..2f3e85d --- /dev/null +++ b/gold/testsuite/icf_test_pr21066.sh @@ -0,0 +1,48 @@ +#!/bin/sh + +# icf_test_pr21066.sh -- regression test for ICF tracking exception handling +# metadata differences + +# Copyright (C) 2009-2018 Free Software Foundation, Inc. +# Written by Joshua Oreman <oremanj@hudson-trading.com>, based on icf_test.sh + +# 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. + +set -e + +check() +{ + awk " +BEGIN { discard = 0; } +/^Discarded input/ { discard = 1; } +/^Memory map/ { discard = 0; } +/.*\\.text\\..*capture_exception_of_type.*($2|$3).*/ { + act[discard] = act[discard] \" \" \$0; +} +END { + # printf \"kept\" act[0] \"\\nfolded\" act[1] \"\\n\"; + if (length(act[0]) != 0 && length(act[1]) != 0) + { + printf \"Identical Code Folding improperly folded functions\\n\" + printf \"with same code but different .gcc_except_table\\n\" + exit 1; + } + }" $1 +} + +check icf_test_pr21066.map "first_exception" "second_exception" |