// dynobj.h -- dynamic object support for gold -*- C++ -*- // Copyright 2006, 2007 Free Software Foundation, Inc. // Written by Ian Lance Taylor . // 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 #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 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& 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& dynsyms, unsigned int local_dynsym_count, unsigned char** pphash, unsigned int* phashlen); protected: // 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& hashcodes, bool for_gnu_hash_table); // Sized version of create_elf_hash_table. template static void sized_create_elf_hash_table(const std::vector& bucket, const std::vector& chain, unsigned char* phash, unsigned int hashlen); // Sized version of create_gnu_hash_table. template static void sized_create_gnu_hash_table(const std::vector& hashed_dynsyms, const std::vector& 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 class Sized_dynobj : public Dynobj { public: Sized_dynobj(const std::string& name, Input_file* input_file, off_t offset, const typename elfcpp::Ehdr&); // Set up the object file based on the ELF header. void setup(const typename elfcpp::Ehdr&); // 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*); // 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. Object::Location do_section_contents(unsigned int shndx) { return this->elf_file_.section_contents(shndx); } // Return section flags. uint64_t do_section_flags(unsigned int shndx) { return this->elf_file_.section_flags(shndx); } // 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); } private: // For convenience. typedef Sized_dynobj This; static const int shdr_size = elfcpp::Elf_sizes::shdr_size; static const int sym_size = elfcpp::Elf_sizes::sym_size; static const int dyn_size = elfcpp::Elf_sizes::dyn_size; typedef elfcpp::Shdr Shdr; typedef elfcpp::Dyn Dyn; // Find the dynamic symbol table and the version sections, given the // section headers. void find_dynsym_sections(const unsigned char* pshdrs, unsigned int* pdynshm_shndx, 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 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 elf_file_; }; // 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& deps, bool is_base, bool is_weak, bool is_symbol_created) : name_(name), deps_(deps), is_base_(is_base), is_weak_(is_weak), 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 a version symbol has been created for this // definition. bool is_symbol_created() const { return this->is_symbol_created_; } // Write contents to buffer. template unsigned char* write(const Stringpool*, bool is_last, unsigned char* ACCEPT_SIZE_ENDIAN) 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 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 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 unsigned char* write(const Stringpool*, bool is_last, unsigned char* ACCEPT_SIZE_ENDIAN) 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 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* 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 void symbol_section_contents(const Symbol_table*, const Stringpool*, unsigned int local_symcount, const std::vector& syms, unsigned char**, unsigned int* ACCEPT_SIZE_ENDIAN) const; // Build an allocated buffer holding the contents of the version // definition section (.gnu.version_d). template void def_section_contents(const Stringpool*, unsigned char**, unsigned int* psize, unsigned int* pentries ACCEPT_SIZE_ENDIAN) const; // Build an allocated buffer holding the contents of the version // reference section (.gnu.version_r). template void need_section_contents(const Stringpool*, unsigned char**, unsigned int* psize, unsigned int* pentries ACCEPT_SIZE_ENDIAN) 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 Defs; // The type of the list of version references. typedef std::vector Needs; // Handle a symbol SYM defined with version VERSION. void add_def(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; // We keep a hash table mapping canonicalized name/version pairs to // a version base. typedef std::pair 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 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_; }; } // End namespace gold. #endif // !defined(GOLD_DYNOBJ_H)