| // dynobj.h -- dynamic object support for gold -*- C++ -*- |
| |
| #ifndef GOLD_DYNOBJ_H |
| #define GOLD_DYNOBJ_H |
| |
| #include <vector> |
| |
| #include "stringpool.h" |
| #include "object.h" |
| |
| namespace gold |
| { |
| |
| class General_options; |
| class Stringpool; |
| |
| // 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: |
| Dynobj(const std::string& name, Input_file* input_file, off_t offset = 0) |
| : Object(name, input_file, true, offset), soname_() |
| { } |
| |
| // Return the name to use in a DT_NEEDED entry for this object. |
| const char* |
| soname() const; |
| |
| // 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 Target*, 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 Target*, const std::vector<Symbol*>& 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); } |
| |
| 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); |
| |
| // The DT_SONAME name, if any. |
| std::string soname_; |
| }; |
| |
| // A dynamic object, size and endian specific version. |
| |
| template<int size, bool big_endian> |
| class Sized_dynobj : public Dynobj |
| { |
| public: |
| 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 the ELF header. |
| void |
| setup(const typename elfcpp::Ehdr<size, big_endian>&); |
| |
| // Read the symbols. |
| void |
| do_read_symbols(Read_symbols_data*); |
| |
| // Lay out the input sections. |
| void |
| do_layout(const General_options&, Symbol_table*, Layout*, |
| Read_symbols_data*); |
| |
| // Add the symbols to the symbol table. |
| void |
| do_add_symbols(Symbol_table*, Read_symbols_data*); |
| |
| // 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); } |
| |
| 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; |
| |
| // 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, off_t* view_size, |
| unsigned int* view_info); |
| |
| // Set the SONAME from the SHT_DYNAMIC section at DYNAMIC_SHNDX. |
| // The STRTAB parameters may have the relevant string table. |
| void |
| set_soname(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_; |
| }; |
| |
| // 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, bool is_base, bool is_weak, bool is_symbol_created) |
| : name_(name), 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<int size, bool big_endian> |
| 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<const char*> 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<int size, bool big_endian> |
| 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<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() |
| : defs_(), needs_(), version_table_(), is_finalized_(false) |
| { } |
| |
| ~Versions(); |
| |
| // SYM is going into the dynamic symbol table and has a version. |
| // Record the appropriate version information. |
| void |
| record_version(const General_options*, 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(const Target*, 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 Stringpool*, unsigned int local_symcount, |
| const std::vector<Symbol*>& 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<int size, bool big_endian> |
| 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<int size, bool big_endian> |
| void |
| need_section_contents(const Stringpool*, unsigned char**, |
| unsigned int* psize, unsigned int* pentries |
| ACCEPT_SIZE_ENDIAN) const; |
| |
| private: |
| // 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(const General_options*, 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); |
| |
| // Return the version index to use for SYM. |
| unsigned int |
| version_index(const Stringpool*, const Symbol* sym) const; |
| |
| // 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_; |
| }; |
| |
| } // End namespace gold. |
| |
| #endif // !defined(GOLD_DYNOBJ_H) |