// icf.cc -- Identical Code Folding.
//
-// Copyright (C) 2009-2016 Free Software Foundation, Inc.
+// Copyright (C) 2009-2018 Free Software Foundation, Inc.
// Written by Sriraman Tallam <tmsriram@google.com>.
// This file is part of gold.
for (; it_v != v.end(); ++it_v, ++it_s, ++it_a, ++it_o, ++it_addend_size)
{
+ Symbol* gsym = *it_s;
+ bool is_section_symbol = false;
+
+ // A -1 value in the symbol vector indicates a local section symbol.
+ if (gsym == reinterpret_cast<Symbol*>(-1))
+ {
+ is_section_symbol = true;
+ gsym = NULL;
+ }
+
if (first_iteration
&& it_v->first != NULL)
{
// It would be nice if we could use format macros in inttypes.h
// here but there are not in ISO/IEC C++ 1998.
- snprintf(addend_str, sizeof(addend_str), "%llx %llx %llux",
+ 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));
if (first_iteration)
{
// If the symbol name is available, use it.
- if ((*it_s) != NULL)
- buffer.append((*it_s)->name());
+ if (gsym != NULL)
+ buffer.append(gsym->name());
// Append the addend.
buffer.append(addend_str);
buffer.append("@");
symtab->icf()->section_to_int_map();
Icf::Uniq_secn_id_map::iterator section_id_map_it =
section_id_map.find(reloc_secn);
- bool is_sym_preemptible = (*it_s != NULL
- && !(*it_s)->is_from_dynobj()
- && !(*it_s)->is_undefined()
- && (*it_s)->is_preemptible());
+ bool is_sym_preemptible = (gsym != NULL
+ && !gsym->is_from_dynobj()
+ && !gsym->is_undefined()
+ && gsym->is_preemptible());
if (!is_sym_preemptible
&& section_id_map_it != section_id_map.end())
{
uint64_t entsize =
(it_v->first)->section_entsize(it_v->second);
long long offset = it_a->first;
- // Handle SHT_RELA and SHT_REL addends, only one of these
- // addends exists.
- // Get the SHT_RELA addend. For RELA relocations, we have
- // the addend from the relocation.
- uint64_t reloc_addend_value = it_a->second;
-
- // Handle SHT_REL addends.
- // For REL relocations, we need to fetch the addend from the
- // section contents.
- const unsigned char* reloc_addend_ptr =
- contents + static_cast<unsigned long long>(*it_o);
-
- // Update the addend value with the SHT_REL addend if
- // available.
- get_rel_addend(reloc_addend_ptr, *it_addend_size,
- &reloc_addend_value);
-
- // Ignore the addend when it is a negative value. See the
- // comments in Merged_symbol_value::value in object.h.
- if (reloc_addend_value < 0xffffff00)
- offset = offset + reloc_addend_value;
+
+ // Handle SHT_RELA and SHT_REL addends. Only one of these
+ // addends exists. When pointing to a merge section, the
+ // addend only matters if it's relative to a section
+ // symbol. In order to unambiguously identify the target
+ // of the relocation, the compiler (and assembler) must use
+ // a local non-section symbol unless Symbol+Addend does in
+ // fact point directly to the target. (In other words,
+ // a bias for a pc-relative reference or a non-zero based
+ // access forces the use of a local symbol, and the addend
+ // is used only to provide that bias.)
+ uint64_t reloc_addend_value = 0;
+ if (is_section_symbol)
+ {
+ // Get the SHT_RELA addend. For RELA relocations,
+ // we have the addend from the relocation.
+ reloc_addend_value = it_a->second;
+
+ // Handle SHT_REL addends.
+ // For REL relocations, we need to fetch the addend
+ // from the section contents.
+ const unsigned char* reloc_addend_ptr =
+ contents + static_cast<unsigned long long>(*it_o);
+
+ // Update the addend value with the SHT_REL addend if
+ // available.
+ get_rel_addend(reloc_addend_ptr, *it_addend_size,
+ &reloc_addend_value);
+
+ // Ignore the addend when it is a negative value.
+ // See the comments in Merged_symbol_value::value
+ // in object.h.
+ if (reloc_addend_value < 0xffffff00)
+ offset = offset + reloc_addend_value;
+ }
section_size_type secn_len;
}
buffer.append("@");
}
- else if ((*it_s) != NULL)
+ else if (gsym != NULL)
{
// If symbol name is available use that.
- buffer.append((*it_s)->name());
+ buffer.append(gsym->name());
// Append the addend.
buffer.append(addend_str);
buffer.append("@");
{
buffer.append("Contents = ");
buffer.append(reinterpret_cast<const char*>(contents), plen);
- // Store the section contents that dont change to avoid recomputing
+ // Store the section contents that don't change to avoid recomputing
// during the next call to this function.
(*section_contents)[section_num] = buffer;
}
std::vector<unsigned int>* num_tracked_relocs,
std::vector<unsigned int>* kept_section_id,
const std::vector<Section_id>& id_section,
+ const std::vector<uint64_t>& section_addraligns,
std::vector<bool>* is_secn_or_group_unique,
std::vector<std::string>* section_contents)
{
{
if ((*kept_section_id)[i] != i)
{
- // This section is already folded into something. See
- // if it should point to a different kept section.
- unsigned int kept_section = (*kept_section_id)[i];
- if (kept_section != (*kept_section_id)[kept_section])
- {
- (*kept_section_id)[i] = (*kept_section_id)[kept_section];
- }
+ // This section is already folded into something.
continue;
}
this_secn_contents = get_section_contents(false, secn, i, NULL,
this_secn_contents.c_str(),
this_secn_contents.length()) != 0)
continue;
- (*kept_section_id)[i] = kept_section;
+
+ // Check section alignment here.
+ // The section with the larger alignment requirement
+ // should be kept. We assume alignment can only be
+ // zero or positive integral powers of two.
+ uint64_t align_i = section_addraligns[i];
+ uint64_t align_kept = section_addraligns[kept_section];
+ if (align_i <= align_kept)
+ {
+ (*kept_section_id)[i] = kept_section;
+ }
+ else
+ {
+ (*kept_section_id)[kept_section] = i;
+ it->second = i;
+ full_section_contents[kept_section].swap(
+ full_section_contents[i]);
+ }
+
converged = false;
break;
}
(*is_secn_or_group_unique)[i] = true;
}
+ // If a section was folded into another section that was later folded
+ // again then the former has to be updated.
+ for (unsigned int i = 0; i < id_section.size(); i++)
+ {
+ // Find the end of the folding chain
+ unsigned int kept = i;
+ while ((*kept_section_id)[kept] != kept)
+ {
+ kept = (*kept_section_id)[kept];
+ }
+ // Update every element of the chain
+ unsigned int current = i;
+ while ((*kept_section_id)[current] != kept)
+ {
+ unsigned int next = (*kept_section_id)[current];
+ (*kept_section_id)[current] = kept;
+ current = next;
+ }
+ }
+
return converged;
}
{
unsigned int section_num = 0;
std::vector<unsigned int> num_tracked_relocs;
+ std::vector<uint64_t> section_addraligns;
std::vector<bool> is_secn_or_group_unique;
std::vector<std::string> section_contents;
const Target& target = parameters->target();
this->section_id_[Section_id(*p, i)] = section_num;
this->kept_section_id_.push_back(section_num);
num_tracked_relocs.push_back(0);
+ section_addraligns.push_back((*p)->section_addralign(i));
is_secn_or_group_unique.push_back(false);
section_contents.push_back("");
section_num++;
num_iterations++;
converged = match_sections(num_iterations, symtab,
&num_tracked_relocs, &this->kept_section_id_,
- this->id_section_, &is_secn_or_group_unique,
- §ion_contents);
+ this->id_section_, section_addraligns,
+ &is_secn_or_group_unique, §ion_contents);
}
if (parameters->options().print_icf_sections())