| // dynobj.h -- dynamic object support for gold -*- C++ -*- |
| |
| // Copyright (C) 2006-2024 Free Software Foundation, Inc. |
| // Written by Ian Lance Taylor <iant@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_DYNOBJ_H |
| #define GOLD_DYNOBJ_H |
| |
| #include <vector> |
| |
| #include "stringpool.h" |
| #include "object.h" |
| |
| namespace gold |
| { |
| |
| class Version_script_info; |
| |
| // A dynamic object (ET_DYN). This is an abstract base class itself. |
| // The implementations is the template class Sized_dynobj. |
| |
| class Dynobj : public Object |
| { |
| public: |
| // We keep a list of all the DT_NEEDED entries we find. |
| typedef std::vector<std::string> Needed; |
| |
| Dynobj(const std::string& name, Input_file* input_file, off_t offset = 0); |
| |
| // Return the name to use in a DT_NEEDED entry for this object. |
| const char* |
| soname() const |
| { return this->soname_.c_str(); } |
| |
| // Return the list of DT_NEEDED strings. |
| const Needed& |
| needed() const |
| { return this->needed_; } |
| |
| // Return whether this dynamic object has any DT_NEEDED entries |
| // which were not seen during the link. |
| bool |
| has_unknown_needed_entries() const |
| { |
| gold_assert(this->unknown_needed_ != UNKNOWN_NEEDED_UNSET); |
| return this->unknown_needed_ == UNKNOWN_NEEDED_TRUE; |
| } |
| |
| // Set whether this dynamic object has any DT_NEEDED entries which |
| // were not seen during the link. |
| void |
| set_has_unknown_needed_entries(bool set) |
| { |
| gold_assert(this->unknown_needed_ == UNKNOWN_NEEDED_UNSET); |
| this->unknown_needed_ = set ? UNKNOWN_NEEDED_TRUE : UNKNOWN_NEEDED_FALSE; |
| } |
| |
| // Return the word size of the object file. |
| int |
| elfsize() const |
| { gold_unreachable(); } |
| |
| // Return TRUE if this is a big-endian object file. |
| bool |
| is_big_endian() const |
| { gold_unreachable(); } |
| |
| // Compute the ELF hash code for a string. |
| static uint32_t |
| elf_hash(const char*); |
| |
| // Create a standard ELF hash table, setting *PPHASH and *PHASHLEN. |
| // DYNSYMS is the global dynamic symbols. LOCAL_DYNSYM_COUNT is the |
| // number of local dynamic symbols, which is the index of the first |
| // dynamic gobal symbol. |
| static void |
| create_elf_hash_table(const std::vector<Symbol*>& dynsyms, |
| unsigned int local_dynsym_count, |
| unsigned char** pphash, |
| unsigned int* phashlen); |
| |
| // Create a GNU hash table, setting *PPHASH and *PHASHLEN. DYNSYMS |
| // is the global dynamic symbols. LOCAL_DYNSYM_COUNT is the number |
| // of local dynamic symbols, which is the index of the first dynamic |
| // gobal symbol. |
| static void |
| create_gnu_hash_table(const std::vector<Symbol*>& dynsyms, |
| unsigned int local_dynsym_count, |
| unsigned char** pphash, unsigned int* phashlen); |
| |
| protected: |
| // Return a pointer to this object. |
| virtual Dynobj* |
| do_dynobj() |
| { return this; } |
| |
| // Set the DT_SONAME string. |
| void |
| set_soname_string(const char* s) |
| { this->soname_.assign(s); } |
| |
| // Add an entry to the list of DT_NEEDED strings. |
| void |
| add_needed(const char* s) |
| { this->needed_.push_back(std::string(s)); } |
| |
| private: |
| // Compute the GNU hash code for a string. |
| static uint32_t |
| gnu_hash(const char*); |
| |
| // Compute the number of hash buckets to use. |
| static unsigned int |
| compute_bucket_count(const std::vector<uint32_t>& hashcodes, |
| bool for_gnu_hash_table); |
| |
| // Sized version of create_elf_hash_table. |
| template<int size, bool big_endian> |
| static void |
| sized_create_elf_hash_table(const std::vector<uint32_t>& bucket, |
| const std::vector<uint32_t>& chain, |
| unsigned char* phash, |
| unsigned int hashlen); |
| |
| // Sized version of create_gnu_hash_table. |
| template<int size, bool big_endian> |
| static void |
| sized_create_gnu_hash_table(const std::vector<Symbol*>& hashed_dynsyms, |
| const std::vector<uint32_t>& dynsym_hashvals, |
| unsigned int unhashed_dynsym_count, |
| unsigned char** pphash, |
| unsigned int* phashlen); |
| |
| // Values for the has_unknown_needed_entries_ field. |
| enum Unknown_needed |
| { |
| UNKNOWN_NEEDED_UNSET, |
| UNKNOWN_NEEDED_TRUE, |
| UNKNOWN_NEEDED_FALSE |
| }; |
| |
| // The DT_SONAME name, if any. |
| std::string soname_; |
| // The list of DT_NEEDED entries. |
| Needed needed_; |
| // Whether this dynamic object has any DT_NEEDED entries not seen |
| // during the link. |
| Unknown_needed unknown_needed_; |
| }; |
| |
| // A dynamic object, size and endian specific version. |
| |
| template<int size, bool big_endian> |
| class Sized_dynobj : public Dynobj |
| { |
| public: |
| typedef typename Sized_relobj_file<size, big_endian>::Symbols Symbols; |
| |
| Sized_dynobj(const std::string& name, Input_file* input_file, off_t offset, |
| const typename elfcpp::Ehdr<size, big_endian>&); |
| |
| // Set up the object file based on TARGET. |
| void |
| setup(); |
| |
| // Read the symbols. |
| void |
| do_read_symbols(Read_symbols_data*); |
| |
| // Lay out the input sections. |
| void |
| do_layout(Symbol_table*, Layout*, Read_symbols_data*); |
| |
| // Add the symbols to the symbol table. |
| void |
| do_add_symbols(Symbol_table*, Read_symbols_data*, Layout*); |
| |
| Archive::Should_include |
| do_should_include_member(Symbol_table* symtab, Layout*, Read_symbols_data*, |
| std::string* why); |
| |
| // Iterate over global symbols, calling a visitor class V for each. |
| void |
| do_for_all_global_symbols(Read_symbols_data* sd, |
| Library_base::Symbol_visitor_base* v); |
| |
| // Iterate over local symbols, calling a visitor class V for each GOT offset |
| // associated with a local symbol. |
| void |
| do_for_all_local_got_entries(Got_offset_list::Visitor* v) const; |
| |
| // Get the size of a section. |
| uint64_t |
| do_section_size(unsigned int shndx) |
| { return this->elf_file_.section_size(shndx); } |
| |
| // Get the name of a section. |
| std::string |
| do_section_name(unsigned int shndx) const |
| { return this->elf_file_.section_name(shndx); } |
| |
| // Return a view of the contents of a section. Set *PLEN to the |
| // size. |
| const unsigned char* |
| do_section_contents(unsigned int shndx, section_size_type* plen, |
| bool cache) |
| { |
| Location loc(this->elf_file_.section_contents(shndx)); |
| *plen = convert_to_section_size_type(loc.data_size); |
| if (*plen == 0) |
| { |
| static const unsigned char empty[1] = { '\0' }; |
| return empty; |
| } |
| return this->get_view(loc.file_offset, *plen, true, cache); |
| } |
| |
| // Return section flags. |
| uint64_t |
| do_section_flags(unsigned int shndx) |
| { return this->elf_file_.section_flags(shndx); } |
| |
| // Not used for dynobj. |
| uint64_t |
| do_section_entsize(unsigned int ) |
| { gold_unreachable(); } |
| |
| // Return section address. |
| uint64_t |
| do_section_address(unsigned int shndx) |
| { return this->elf_file_.section_addr(shndx); } |
| |
| // Return section type. |
| unsigned int |
| do_section_type(unsigned int shndx) |
| { return this->elf_file_.section_type(shndx); } |
| |
| // Return the section link field. |
| unsigned int |
| do_section_link(unsigned int shndx) |
| { return this->elf_file_.section_link(shndx); } |
| |
| // Return the section link field. |
| unsigned int |
| do_section_info(unsigned int shndx) |
| { return this->elf_file_.section_info(shndx); } |
| |
| // Return the section alignment. |
| uint64_t |
| do_section_addralign(unsigned int shndx) |
| { return this->elf_file_.section_addralign(shndx); } |
| |
| // Return the Xindex structure to use. |
| Xindex* |
| do_initialize_xindex(); |
| |
| // Get symbol counts. |
| void |
| do_get_global_symbol_counts(const Symbol_table*, size_t*, size_t*) const; |
| |
| // Get the global symbols. |
| const Symbols* |
| do_get_global_symbols() const |
| { return this->symbols_; } |
| |
| protected: |
| // Read the symbols. This is common code for all target-specific |
| // overrides of do_read_symbols(). |
| void |
| base_read_symbols(Read_symbols_data*); |
| |
| private: |
| // For convenience. |
| typedef Sized_dynobj<size, big_endian> This; |
| static const int shdr_size = elfcpp::Elf_sizes<size>::shdr_size; |
| static const int sym_size = elfcpp::Elf_sizes<size>::sym_size; |
| static const int dyn_size = elfcpp::Elf_sizes<size>::dyn_size; |
| typedef elfcpp::Shdr<size, big_endian> Shdr; |
| typedef elfcpp::Dyn<size, big_endian> Dyn; |
| |
| // Adjust a section index if necessary. |
| unsigned int |
| adjust_shndx(unsigned int shndx) |
| { |
| if (shndx >= elfcpp::SHN_LORESERVE) |
| shndx += this->elf_file_.large_shndx_offset(); |
| return shndx; |
| } |
| |
| // Find the dynamic symbol table and the version sections, given the |
| // section headers. |
| void |
| find_dynsym_sections(const unsigned char* pshdrs, |
| unsigned int* pversym_shndx, |
| unsigned int* pverdef_shndx, |
| unsigned int* pverneed_shndx, |
| unsigned int* pdynamic_shndx); |
| |
| // Read the dynamic symbol section SHNDX. |
| void |
| read_dynsym_section(const unsigned char* pshdrs, unsigned int shndx, |
| elfcpp::SHT type, unsigned int link, |
| File_view** view, section_size_type* view_size, |
| unsigned int* view_info); |
| |
| // Read the dynamic tags. |
| void |
| read_dynamic(const unsigned char* pshdrs, unsigned int dynamic_shndx, |
| unsigned int strtab_shndx, const unsigned char* strtabu, |
| off_t strtab_size); |
| |
| // Mapping from version number to version name. |
| typedef std::vector<const char*> Version_map; |
| |
| // Create the version map. |
| void |
| make_version_map(Read_symbols_data* sd, Version_map*) const; |
| |
| // Add version definitions to the version map. |
| void |
| make_verdef_map(Read_symbols_data* sd, Version_map*) const; |
| |
| // Add version references to the version map. |
| void |
| make_verneed_map(Read_symbols_data* sd, Version_map*) const; |
| |
| // Add an entry to the version map. |
| void |
| set_version_map(Version_map*, unsigned int ndx, const char* name) const; |
| |
| // General access to the ELF file. |
| elfcpp::Elf_file<size, big_endian, Object> elf_file_; |
| // The section index of the dynamic symbol table. |
| unsigned int dynsym_shndx_; |
| // The entries in the symbol table for the symbols. We only keep |
| // this if we need it to print symbol information. |
| Symbols* symbols_; |
| // Number of defined symbols. |
| size_t defined_count_; |
| }; |
| |
| // A base class for Verdef and Verneed_version which just handles the |
| // version index which will be stored in the SHT_GNU_versym section. |
| |
| class Version_base |
| { |
| public: |
| Version_base() |
| : index_(-1U) |
| { } |
| |
| virtual |
| ~Version_base() |
| { } |
| |
| // Return the version index. |
| unsigned int |
| index() const |
| { |
| gold_assert(this->index_ != -1U); |
| return this->index_; |
| } |
| |
| // Set the version index. |
| void |
| set_index(unsigned int index) |
| { |
| gold_assert(this->index_ == -1U); |
| this->index_ = index; |
| } |
| |
| // Clear the weak flag in a version definition. |
| virtual void |
| clear_weak() = 0; |
| |
| private: |
| Version_base(const Version_base&); |
| Version_base& operator=(const Version_base&); |
| |
| // The index of the version definition or reference. |
| unsigned int index_; |
| }; |
| |
| // This class handles a version being defined in the file we are |
| // generating. |
| |
| class Verdef : public Version_base |
| { |
| public: |
| Verdef(const char* name, const std::vector<std::string>& deps, |
| bool is_base, bool is_weak, bool is_info, bool is_symbol_created) |
| : name_(name), deps_(deps), is_base_(is_base), is_weak_(is_weak), |
| is_info_(is_info), is_symbol_created_(is_symbol_created) |
| { } |
| |
| // Return the version name. |
| const char* |
| name() const |
| { return this->name_; } |
| |
| // Return the number of dependencies. |
| unsigned int |
| count_dependencies() const |
| { return this->deps_.size(); } |
| |
| // Add a dependency to this version. The NAME should be |
| // canonicalized in the dynamic Stringpool. |
| void |
| add_dependency(const char* name) |
| { this->deps_.push_back(name); } |
| |
| // Return whether this definition is weak. |
| bool |
| is_weak() const |
| { return this->is_weak_; } |
| |
| // Clear the weak flag. |
| void |
| clear_weak() |
| { this->is_weak_ = false; } |
| |
| // Return whether this definition is informational. |
| bool |
| is_info() const |
| { return this->is_info_; } |
| |
| // Return whether a version symbol has been created for this |
| // definition. |
| bool |
| is_symbol_created() const |
| { return this->is_symbol_created_; } |
| |
| // Write contents to buffer. |
| template<int size, bool big_endian> |
| unsigned char* |
| write(const Stringpool*, bool is_last, unsigned char*) const; |
| |
| private: |
| Verdef(const Verdef&); |
| Verdef& operator=(const Verdef&); |
| |
| // The type of the list of version dependencies. Each dependency |
| // should be canonicalized in the dynamic Stringpool. |
| typedef std::vector<std::string> Deps; |
| |
| // The name of this version. This should be canonicalized in the |
| // dynamic Stringpool. |
| const char* name_; |
| // A list of other versions which this version depends upon. |
| Deps deps_; |
| // Whether this is the base version. |
| bool is_base_; |
| // Whether this version is weak. |
| bool is_weak_; |
| // Whether this version is informational. |
| bool is_info_; |
| // Whether a version symbol has been created. |
| bool is_symbol_created_; |
| }; |
| |
| // A referened version. This will be associated with a filename by |
| // Verneed. |
| |
| class Verneed_version : public Version_base |
| { |
| public: |
| Verneed_version(const char* version) |
| : version_(version) |
| { } |
| |
| // Return the version name. |
| const char* |
| version() const |
| { return this->version_; } |
| |
| // Clear the weak flag. This is invalid for a reference. |
| void |
| clear_weak() |
| { gold_unreachable(); } |
| |
| private: |
| Verneed_version(const Verneed_version&); |
| Verneed_version& operator=(const Verneed_version&); |
| |
| const char* version_; |
| }; |
| |
| // Version references in a single dynamic object. |
| |
| class Verneed |
| { |
| public: |
| Verneed(const char* filename) |
| : filename_(filename), need_versions_() |
| { } |
| |
| ~Verneed(); |
| |
| // Return the file name. |
| const char* |
| filename() const |
| { return this->filename_; } |
| |
| // Return the number of versions. |
| unsigned int |
| count_versions() const |
| { return this->need_versions_.size(); } |
| |
| // Add a version name. The name should be canonicalized in the |
| // dynamic Stringpool. If the name is already present, this does |
| // nothing. |
| Verneed_version* |
| add_name(const char* name); |
| |
| // Set the version indexes, starting at INDEX. Return the updated |
| // INDEX. |
| unsigned int |
| finalize(unsigned int index); |
| |
| // Write contents to buffer. |
| template<int size, bool big_endian> |
| unsigned char* |
| write(const Stringpool*, bool is_last, unsigned char*) const; |
| |
| private: |
| Verneed(const Verneed&); |
| Verneed& operator=(const Verneed&); |
| |
| // The type of the list of version names. Each name should be |
| // canonicalized in the dynamic Stringpool. |
| typedef std::vector<Verneed_version*> Need_versions; |
| |
| // The filename of the dynamic object. This should be |
| // canonicalized in the dynamic Stringpool. |
| const char* filename_; |
| // The list of version names. |
| Need_versions need_versions_; |
| }; |
| |
| // This class handles version definitions and references which go into |
| // the output file. |
| |
| class Versions |
| { |
| public: |
| Versions(const Version_script_info&, Stringpool*); |
| |
| ~Versions(); |
| |
| // SYM is going into the dynamic symbol table and has a version. |
| // Record the appropriate version information. |
| void |
| record_version(const Symbol_table* symtab, Stringpool*, const Symbol* sym); |
| |
| // Set the version indexes. DYNSYM_INDEX is the index we should use |
| // for the next dynamic symbol. We add new dynamic symbols to SYMS |
| // and return an updated DYNSYM_INDEX. |
| unsigned int |
| finalize(Symbol_table* symtab, unsigned int dynsym_index, |
| std::vector<Symbol*>* syms); |
| |
| // Return whether there are any version definitions. |
| bool |
| any_defs() const |
| { return !this->defs_.empty(); } |
| |
| // Return whether there are any version references. |
| bool |
| any_needs() const |
| { return !this->needs_.empty(); } |
| |
| // Build an allocated buffer holding the contents of the symbol |
| // version section (.gnu.version). |
| template<int size, bool big_endian> |
| void |
| symbol_section_contents(const Symbol_table*, const Stringpool*, |
| unsigned int local_symcount, |
| const std::vector<Symbol*>& syms, |
| unsigned char**, unsigned int*) const; |
| |
| // Build an allocated buffer holding the contents of the version |
| // definition section (.gnu.version_d). |
| template<int size, bool big_endian> |
| void |
| def_section_contents(const Stringpool*, unsigned char**, |
| unsigned int* psize, unsigned int* pentries) const; |
| |
| // Build an allocated buffer holding the contents of the version |
| // reference section (.gnu.version_r). |
| template<int size, bool big_endian> |
| void |
| need_section_contents(const Stringpool*, unsigned char**, |
| unsigned int* psize, unsigned int* pentries) const; |
| |
| const Version_script_info& |
| version_script() const |
| { return this->version_script_; } |
| |
| private: |
| Versions(const Versions&); |
| Versions& operator=(const Versions&); |
| |
| // The type of the list of version definitions. |
| typedef std::vector<Verdef*> Defs; |
| |
| // The type of the list of version references. |
| typedef std::vector<Verneed*> Needs; |
| |
| // Handle a symbol SYM defined with version VERSION. |
| void |
| add_def(Stringpool*, const Symbol* sym, const char* version, |
| Stringpool::Key); |
| |
| // Add a reference to version NAME in file FILENAME. |
| void |
| add_need(Stringpool*, const char* filename, const char* name, |
| Stringpool::Key); |
| |
| // Get the dynamic object to use for SYM. |
| Dynobj* |
| get_dynobj_for_sym(const Symbol_table*, const Symbol* sym) const; |
| |
| // Return the version index to use for SYM. |
| unsigned int |
| version_index(const Symbol_table*, const Stringpool*, |
| const Symbol* sym) const; |
| |
| // Define the base version of a shared library. |
| void |
| define_base_version(Stringpool* dynpool); |
| |
| // We keep a hash table mapping canonicalized name/version pairs to |
| // a version base. |
| typedef std::pair<Stringpool::Key, Stringpool::Key> Key; |
| |
| struct Version_table_hash |
| { |
| size_t |
| operator()(const Key& k) const |
| { return k.first + k.second; } |
| }; |
| |
| struct Version_table_eq |
| { |
| bool |
| operator()(const Key& k1, const Key& k2) const |
| { return k1.first == k2.first && k1.second == k2.second; } |
| }; |
| |
| typedef Unordered_map<Key, Version_base*, Version_table_hash, |
| Version_table_eq> Version_table; |
| |
| // The version definitions. |
| Defs defs_; |
| // The version references. |
| Needs needs_; |
| // The mapping from a canonicalized version/filename pair to a |
| // version index. The filename may be NULL. |
| Version_table version_table_; |
| // Whether the version indexes have been set. |
| bool is_finalized_; |
| // Contents of --version-script, if passed, or NULL. |
| const Version_script_info& version_script_; |
| // Whether we need to insert a base version. This is only used for |
| // shared libraries and is cleared when the base version is defined. |
| bool needs_base_version_; |
| }; |
| |
| } // End namespace gold. |
| |
| #endif // !defined(GOLD_DYNOBJ_H) |