mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2025-03-25 14:01:00 +08:00
Fix problem with ICF where diffs in EH frame info is ignored.
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.
This commit is contained in:
parent
1367480341
commit
e173ea00c2
@ -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);
|
||||
|
270
gold/icf.cc
270
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;
|
||||
|
||||
|
30
gold/icf.h
30
gold/icf.h
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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; "
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
67
gold/testsuite/icf_test_pr21066.cc
Normal file
67
gold/testsuite/icf_test_pr21066.cc
Normal file
@ -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;
|
||||
}
|
48
gold/testsuite/icf_test_pr21066.sh
Executable file
48
gold/testsuite/icf_test_pr21066.sh
Executable file
@ -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"
|
Loading…
x
Reference in New Issue
Block a user