| // icf.h -- Identical Code Folding |
| |
| // Copyright (C) 2009-2024 Free Software Foundation, Inc. |
| // Written by Sriraman Tallam <tmsriram@google.com>. |
| |
| // 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. |
| |
| #ifndef GOLD_ICF_H |
| #define GOLD_ICF_H |
| |
| #include <vector> |
| |
| #include "elfcpp.h" |
| #include "symtab.h" |
| #include "object.h" |
| |
| namespace gold |
| { |
| |
| class Object; |
| class Input_objects; |
| class Symbol_table; |
| |
| class Icf |
| { |
| public: |
| typedef std::vector<Section_id> Sections_reachable_info; |
| typedef std::vector<Symbol*> Symbol_info; |
| typedef std::vector<std::pair<long long, long long> > Addend_info; |
| typedef std::vector<uint64_t> Offset_info; |
| typedef std::vector<unsigned int> Reloc_addend_size_info; |
| typedef Unordered_map<Section_id, |
| unsigned int, |
| Section_id_hash> Uniq_secn_id_map; |
| typedef Unordered_set<Section_id, Section_id_hash> Secn_fptr_taken_set; |
| |
| typedef struct |
| { |
| // This stores the section corresponding to the reloc. |
| Sections_reachable_info section_info; |
| // This stores the symbol corresponding to the reloc. |
| Symbol_info symbol_info; |
| // This stores the symbol value and the addend for a reloc. |
| Addend_info addend_info; |
| Offset_info offset_info; |
| Reloc_addend_size_info reloc_addend_size_info; |
| } Reloc_info; |
| |
| 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_(), |
| icf_ready_(false), |
| reloc_info_list_() |
| { } |
| |
| // Returns the kept folded identical section corresponding to |
| // dup_obj and dup_shndx. |
| Section_id |
| get_folded_section(Relobj* dup_obj, unsigned int dup_shndx); |
| |
| // Forms groups of identical sections where the first member |
| // of each group is the kept section during folding. |
| void |
| find_identical_sections(const Input_objects* input_objects, |
| Symbol_table* symtab); |
| |
| // This is set when ICF has been run and the groups of |
| // identical sections have been formed. |
| void |
| icf_ready() |
| { this->icf_ready_ = true; } |
| |
| // Returns true if ICF has been run. |
| bool |
| is_icf_ready() |
| { return this->icf_ready_; } |
| |
| // Unfolds the section denoted by OBJ and SHNDX if folded. |
| void |
| unfold_section(Relobj* obj, unsigned int shndx); |
| |
| // Returns the kept section corresponding to the |
| // given section. |
| bool |
| is_section_folded(Relobj* obj, unsigned int shndx); |
| |
| // Given an object and a section index, this returns true if the |
| // pointer of the function defined in this section is taken. |
| bool |
| section_has_function_pointers(Relobj* obj, unsigned int shndx) |
| { |
| return (this->fptr_section_id_.find(Section_id(obj, shndx)) |
| != this->fptr_section_id_.end()); |
| } |
| |
| // Records that a pointer of the function defined in this section |
| // is taken. |
| void |
| set_section_has_function_pointers(Relobj* obj, unsigned int shndx) |
| { |
| this->fptr_section_id_.insert(Section_id(obj, shndx)); |
| } |
| |
| // Checks if the section_name should be searched for relocs |
| // corresponding to taken function pointers. Ignores eh_frame |
| // and vtable sections. |
| inline bool |
| check_section_for_function_pointers(const std::string& section_name, |
| Target* target) |
| { |
| return (parameters->options().icf_safe_folding() |
| && target->can_check_for_function_pointers() |
| && target->section_may_have_icf_unsafe_pointers( |
| section_name.c_str())); |
| } |
| |
| // Returns a map of a section to info (Reloc_info) about its relocations. |
| Reloc_info_list& |
| 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() |
| { return this->section_id_; } |
| |
| 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. |
| Uniq_secn_id_map section_id_; |
| // Given a section id, this maps it to the id of the kept |
| // section. If the id's are the same then this section is |
| // not folded. |
| std::vector<unsigned int> kept_section_id_; |
| // Given a section id, this says if the pointer to this |
| // function is taken in which case it is dangerous to fold |
| // this function. |
| Secn_fptr_taken_set fptr_section_id_; |
| // Flag to indicate if ICF has been run. |
| 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)); |
| } |
| |
| } // End of namespace gold. |
| |
| #endif |