| // dynobj.h -- dynamic object support for gold -*- C++ -*- | |
| // Copyright 2006, 2007, 2008, 2009, 2010, 2011 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; | |
| } | |
| // 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<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) | |
| { 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_; } | |
| 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) |