X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gold%2Ficf.cc;h=a49ce2e960ffb6ac9764830f11145d045abba216;hb=2571583aed598dd3f9651b53434e5f177a0e3cf7;hp=a132875873ec9ea50fdc06f2a0974107409a11ab;hpb=5f9bcf5825f56b017aacf20aaabce0ed07920454;p=external%2Fbinutils.git diff --git a/gold/icf.cc b/gold/icf.cc index a132875..a49ce2e 100644 --- a/gold/icf.cc +++ b/gold/icf.cc @@ -1,6 +1,6 @@ // icf.cc -- Identical Code Folding. // -// Copyright 2009, 2010 Free Software Foundation, Inc. +// Copyright (C) 2009-2017 Free Software Foundation, Inc. // Written by Sriraman Tallam . // This file is part of gold. @@ -213,6 +213,45 @@ preprocess_for_unique_sections(const std::vector& id_section, } } +// For SHF_MERGE sections that use REL relocations, the addend is stored in +// the text section at the relocation offset. Read the addend value given +// the pointer to the addend in the text section and the addend size. +// Update the addend value if a valid addend is found. +// Parameters: +// RELOC_ADDEND_PTR : Pointer to the addend in the text section. +// ADDEND_SIZE : The size of the addend. +// RELOC_ADDEND_VALUE : Pointer to the addend that is updated. + +inline void +get_rel_addend(const unsigned char* reloc_addend_ptr, + const unsigned int addend_size, + uint64_t* reloc_addend_value) +{ + switch (addend_size) + { + case 0: + break; + case 1: + *reloc_addend_value = + read_from_pointer<8>(reloc_addend_ptr); + break; + case 2: + *reloc_addend_value = + read_from_pointer<16>(reloc_addend_ptr); + break; + case 4: + *reloc_addend_value = + read_from_pointer<32>(reloc_addend_ptr); + break; + case 8: + *reloc_addend_value = + read_from_pointer<64>(reloc_addend_ptr); + break; + default: + gold_unreachable(); + } +} + // This returns the buffer containing the section's contents, both // text and relocs. Relocs are differentiated as those pointing to // sections that could be folded and those that cannot. Only relocs @@ -237,20 +276,16 @@ get_section_contents(bool first_iteration, const std::vector& kept_section_id, std::vector* section_contents) { + // 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(-1); + Task_lock_obj tl(dummy_task, secn.first); + section_size_type plen; const unsigned char* contents = NULL; - if (first_iteration) - { - // 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(-1); - Task_lock_obj tl(dummy_task, secn.first); - contents = secn.first->section_contents(secn.second, - &plen, - false); - } + contents = secn.first->section_contents(secn.second, &plen, false); // The buffer to hold all the contents including relocs. A checksum // is then computed on this buffer. @@ -273,27 +308,46 @@ get_section_contents(bool first_iteration, if (it_reloc_info_list != reloc_info_list.end()) { - Icf::Sections_reachable_info v = + Icf::Sections_reachable_info &v = (it_reloc_info_list->second).section_info; // Stores the information of the symbol pointed to by the reloc. - Icf::Symbol_info s = (it_reloc_info_list->second).symbol_info; + const Icf::Symbol_info &s = (it_reloc_info_list->second).symbol_info; // Stores the addend and the symbol value. - Icf::Addend_info a = (it_reloc_info_list->second).addend_info; + Icf::Addend_info &a = (it_reloc_info_list->second).addend_info; // Stores the offset of the reloc. - Icf::Offset_info o = (it_reloc_info_list->second).offset_info; - Icf::Reloc_addend_size_info reloc_addend_size_info = + const Icf::Offset_info &o = (it_reloc_info_list->second).offset_info; + const Icf::Reloc_addend_size_info &reloc_addend_size_info = (it_reloc_info_list->second).reloc_addend_size_info; Icf::Sections_reachable_info::iterator it_v = v.begin(); - Icf::Symbol_info::iterator it_s = s.begin(); + Icf::Symbol_info::const_iterator it_s = s.begin(); Icf::Addend_info::iterator it_a = a.begin(); - Icf::Offset_info::iterator it_o = o.begin(); - Icf::Reloc_addend_size_info::iterator it_addend_size = + Icf::Offset_info::const_iterator it_o = o.begin(); + Icf::Reloc_addend_size_info::const_iterator it_addend_size = reloc_addend_size_info.begin(); for (; it_v != v.end(); ++it_v, ++it_s, ++it_a, ++it_o, ++it_addend_size) { + if (first_iteration + && it_v->first != NULL) + { + Symbol_location loc; + loc.object = it_v->first; + loc.shndx = it_v->second; + loc.offset = convert_types(it_a->first + + it_a->second); + // Look through function descriptors + parameters->target().function_location(&loc); + if (loc.shndx != it_v->second) + { + it_v->second = loc.shndx; + // Modify symvalue/addend to the code entry. + it_a->first = loc.offset; + it_a->second = 0; + } + } + // ADDEND_STR stores the symbol value and addend and offset, - // each atmost 16 hex digits long. it_a points to a pair + // each at most 16 hex digits long. it_a points to a pair // where first is the symbol value and second is the // addend. char addend_str[50]; @@ -373,73 +427,45 @@ get_section_contents(bool first_iteration, if (!first_iteration) continue; - // 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(-1); - Task_lock_obj tl(dummy_task, it_v->first); - uint64_t secn_flags = (it_v->first)->section_flags(it_v->second); // This reloc points to a merge section. Hash the // contents of this section. if ((secn_flags & elfcpp::SHF_MERGE) != 0 - && parameters->target().can_icf_inline_merge_sections ()) + && parameters->target().can_icf_inline_merge_sections()) { uint64_t entsize = (it_v->first)->section_entsize(it_v->second); long long offset = it_a->first; - - unsigned long long addend = it_a->second; - // Ignoring the addend when it is a negative value. See the - // comments in Merged_symbol_value::Value in object.h. - if (addend < 0xffffff00) - offset = offset + addend; - - // For SHT_REL relocation sections, the addend is stored in the - // text section at the relocation offset. - uint64_t reloc_addend_value = 0; + // 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(*it_o); - switch(*it_addend_size) - { - case 0: - { - break; - } - case 1: - { - reloc_addend_value = - read_from_pointer<8>(reloc_addend_ptr); - break; - } - case 2: - { - reloc_addend_value = - read_from_pointer<16>(reloc_addend_ptr); - break; - } - case 4: - { - reloc_addend_value = - read_from_pointer<32>(reloc_addend_ptr); - break; - } - case 8: - { - reloc_addend_value = - read_from_pointer<64>(reloc_addend_ptr); - break; - } - default: - gold_unreachable(); - } - offset = offset + reloc_addend_value; + + // 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; + const unsigned char* str_contents = (it_v->first)->section_contents(it_v->second, &secn_len, false) + offset; + gold_assert (offset < (long long) secn_len); + if ((secn_flags & elfcpp::SHF_STRINGS) != 0) { // String merge section. @@ -480,10 +506,14 @@ get_section_contents(bool first_iteration, } else { - // Use the entsize to determine the length. - buffer.append(reinterpret_cast secn_len) + bufsize = secn_len - offset; + buffer.append(reinterpret_cast(str_contents), - entsize); + bufsize); } buffer.append("@"); } @@ -515,7 +545,7 @@ get_section_contents(bool first_iteration, { buffer.append("Contents = "); buffer.append(reinterpret_cast(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; } @@ -550,7 +580,7 @@ get_section_contents(bool first_iteration, // KEPT_SECTION_ID : Vector which maps folded sections to kept sections. // ID_SECTION : Vector mapping a section to an unique integer. // IS_SECN_OR_GROUP_UNIQUE : To check if a section or a group of identical -// sectionsis already known to be unique. +// sections is already known to be unique. // SECTION_CONTENTS : Store the section's text and relocs to non-ICF // sections. @@ -560,6 +590,7 @@ match_sections(unsigned int iteration_num, std::vector* num_tracked_relocs, std::vector* kept_section_id, const std::vector& id_section, + const std::vector& section_addraligns, std::vector* is_secn_or_group_unique, std::vector* section_contents) { @@ -600,13 +631,7 @@ match_sections(unsigned int iteration_num, { 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, @@ -641,7 +666,25 @@ match_sections(unsigned int iteration_num, 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; } @@ -658,20 +701,41 @@ match_sections(unsigned int iteration_num, (*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; } // During safe icf (--icf=safe), only fold functions that are ctors or dtors. -// This function returns true if the mangled function name is a ctor or a -// dtor. +// This function returns true if the section name is that of a ctor or a dtor. static bool -is_function_ctor_or_dtor(const char* mangled_func_name) +is_function_ctor_or_dtor(const std::string& section_name) { - if ((is_prefix_of("_ZN", mangled_func_name) - || is_prefix_of("_ZZ", mangled_func_name)) - && (is_gnu_v3_mangled_ctor(mangled_func_name) - || is_gnu_v3_mangled_dtor(mangled_func_name))) + const char* mangled_func_name = strrchr(section_name.c_str(), '.'); + gold_assert(mangled_func_name != NULL); + if ((is_prefix_of("._ZN", mangled_func_name) + || is_prefix_of("._ZZ", mangled_func_name)) + && (is_gnu_v3_mangled_ctor(mangled_func_name + 1) + || is_gnu_v3_mangled_dtor(mangled_func_name + 1))) { return true; } @@ -688,6 +752,7 @@ Icf::find_identical_sections(const Input_objects* input_objects, { unsigned int section_num = 0; std::vector num_tracked_relocs; + std::vector section_addraligns; std::vector is_secn_or_group_unique; std::vector section_contents; const Target& target = parameters->target(); @@ -706,7 +771,7 @@ Icf::find_identical_sections(const Input_objects* input_objects, for (unsigned int i = 0;i < (*p)->shnum(); ++i) { - const char* section_name = (*p)->section_name(i).c_str(); + const std::string section_name = (*p)->section_name(i); if (!is_section_foldable_candidate(section_name)) continue; if (!(*p)->is_section_included(i)) @@ -714,13 +779,11 @@ Icf::find_identical_sections(const Input_objects* input_objects, if (parameters->options().gc_sections() && symtab->gc()->is_section_garbage(*p, i)) continue; - const char* mangled_func_name = strrchr(section_name, '.'); - gold_assert(mangled_func_name != NULL); // With --icf=safe, check if the mangled function name is a ctor // or a dtor. The mangled function name can be obtained from the // section name by stripping the section prefix. if (parameters->options().icf_safe_folding() - && !is_function_ctor_or_dtor(mangled_func_name + 1) + && !is_function_ctor_or_dtor(section_name) && (!target.can_check_for_function_pointers() || section_has_function_pointers(*p, i))) { @@ -730,6 +793,7 @@ Icf::find_identical_sections(const Input_objects* input_objects, 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++; @@ -750,8 +814,8 @@ Icf::find_identical_sections(const Input_objects* input_objects, 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()) @@ -779,7 +843,7 @@ Icf::find_identical_sections(const Input_objects* input_objects, else if (sym->source() == Symbol::FROM_OBJECT && !sym->object()->is_dynamic()) { - Object* obj = sym->object(); + Relobj* obj = static_cast(sym->object()); bool is_ordinary; unsigned int shndx = sym->shndx(&is_ordinary); if (is_ordinary) @@ -796,7 +860,7 @@ Icf::find_identical_sections(const Input_objects* input_objects, // Unfolds the section denoted by OBJ and SHNDX if folded. void -Icf::unfold_section(Object* obj, unsigned int shndx) +Icf::unfold_section(Relobj* obj, unsigned int shndx) { Section_id secn(obj, shndx); Uniq_secn_id_map::iterator it = this->section_id_.find(secn); @@ -813,7 +877,7 @@ Icf::unfold_section(Object* obj, unsigned int shndx) // is different from this section. bool -Icf::is_section_folded(Object* obj, unsigned int shndx) +Icf::is_section_folded(Relobj* obj, unsigned int shndx) { Section_id secn(obj, shndx); Uniq_secn_id_map::iterator it = this->section_id_.find(secn); @@ -827,7 +891,7 @@ Icf::is_section_folded(Object* obj, unsigned int shndx) // This function returns the folded section for the given section. Section_id -Icf::get_folded_section(Object* dup_obj, unsigned int dup_shndx) +Icf::get_folded_section(Relobj* dup_obj, unsigned int dup_shndx) { Section_id dup_secn(dup_obj, dup_shndx); Uniq_secn_id_map::iterator it = this->section_id_.find(dup_secn);