diff options
Diffstat (limited to 'gold/layout.h')
-rw-r--r-- | gold/layout.h | 430 |
1 files changed, 430 insertions, 0 deletions
diff --git a/gold/layout.h b/gold/layout.h new file mode 100644 index 000000000000..8b349cc0a4bd --- /dev/null +++ b/gold/layout.h @@ -0,0 +1,430 @@ +// layout.h -- lay out output file sections for gold -*- C++ -*- + +#ifndef GOLD_LAYOUT_H +#define GOLD_LAYOUT_H + +#include <list> +#include <string> +#include <utility> +#include <vector> + +#include "workqueue.h" +#include "object.h" +#include "dynobj.h" +#include "stringpool.h" + +namespace gold +{ + +class General_options; +class Input_objects; +class Symbol_table; +class Output_section_data; +class Output_section; +class Output_section_headers; +class Output_segment; +class Output_data; +class Output_data_dynamic; +class Target; + +// This task function handles mapping the input sections to output +// sections and laying them out in memory. + +class Layout_task_runner : public Task_function_runner +{ + public: + // OPTIONS is the command line options, INPUT_OBJECTS is the list of + // input objects, SYMTAB is the symbol table, LAYOUT is the layout + // object. + Layout_task_runner(const General_options& options, + const Input_objects* input_objects, + Symbol_table* symtab, + Layout* layout) + : options_(options), input_objects_(input_objects), symtab_(symtab), + layout_(layout) + { } + + // Run the operation. + void + run(Workqueue*); + + private: + Layout_task_runner(const Layout_task_runner&); + Layout_task_runner& operator=(const Layout_task_runner&); + + const General_options& options_; + const Input_objects* input_objects_; + Symbol_table* symtab_; + Layout* layout_; +}; + +// This class handles the details of laying out input sections. + +class Layout +{ + public: + Layout(const General_options& options); + + // Given an input section SHNDX, named NAME, with data in SHDR, from + // the object file OBJECT, return the output section where this + // input section should go. Set *OFFSET to the offset within the + // output section. + template<int size, bool big_endian> + Output_section* + layout(Relobj *object, unsigned int shndx, const char* name, + const elfcpp::Shdr<size, big_endian>& shdr, off_t* offset); + + // Add an Output_section_data to the layout. This is used for + // special sections like the GOT section. + void + add_output_section_data(const char* name, elfcpp::Elf_Word type, + elfcpp::Elf_Xword flags, + Output_section_data*); + + // Create dynamic sections if necessary. + void + create_initial_dynamic_sections(const Input_objects*, Symbol_table*); + + // Return the Stringpool used for symbol names. + const Stringpool* + sympool() const + { return &this->sympool_; } + + // Return the Stringpool used for dynamic symbol names and dynamic + // tags. + const Stringpool* + dynpool() const + { return &this->dynpool_; } + + // Return whether a section is a .gnu.linkonce section, given the + // section name. + static inline bool + is_linkonce(const char* name) + { return strncmp(name, ".gnu.linkonce", sizeof(".gnu.linkonce") - 1) == 0; } + + // Record the signature of a comdat section, and return whether to + // include it in the link. The GROUP parameter is true for a + // section group signature, false for a signature derived from a + // .gnu.linkonce section. + bool + add_comdat(const char*, bool group); + + // Finalize the layout after all the input sections have been added. + off_t + finalize(const Input_objects*, Symbol_table*); + + // Return the TLS segment. This will return NULL if there isn't + // one. + Output_segment* + tls_segment() const + { return this->tls_segment_; } + + // Return the normal symbol table. + Output_section* + symtab_section() const + { + gold_assert(this->symtab_section_ != NULL); + return this->symtab_section_; + } + + // Return the dynamic symbol table. + Output_section* + dynsym_section() const + { + gold_assert(this->dynsym_section_ != NULL); + return this->dynsym_section_; + } + + // Return the dynamic tags. + Output_data_dynamic* + dynamic_data() const + { return this->dynamic_data_; } + + // Write out data not associated with an input file or the symbol + // table. + void + write_data(const Symbol_table*, const Target*, Output_file*) const; + + // Return an output section named NAME, or NULL if there is none. + Output_section* + find_output_section(const char* name) const; + + // Return an output segment of type TYPE, with segment flags SET set + // and segment flags CLEAR clear. Return NULL if there is none. + Output_segment* + find_output_segment(elfcpp::PT type, elfcpp::Elf_Word set, + elfcpp::Elf_Word clear) const; + + // The list of segments. + + typedef std::vector<Output_segment*> Segment_list; + + // The list of sections not attached to a segment. + + typedef std::vector<Output_section*> Section_list; + + // The list of information to write out which is not attached to + // either a section or a segment. + typedef std::vector<Output_data*> Data_list; + + private: + Layout(const Layout&); + Layout& operator=(const Layout&); + + // Mapping from .gnu.linkonce section names to output section names. + struct Linkonce_mapping + { + const char* from; + int fromlen; + const char* to; + int tolen; + }; + static const Linkonce_mapping linkonce_mapping[]; + static const int linkonce_mapping_count; + + // Find the first read-only PT_LOAD segment, creating one if + // necessary. + Output_segment* + find_first_load_seg(); + + // Create the output sections for the symbol table. + void + create_symtab_sections(int size, const Input_objects*, Symbol_table*, + off_t*); + + // Create the .shstrtab section. + Output_section* + create_shstrtab(); + + // Create the section header table. + Output_section_headers* + create_shdrs(int size, bool big_endian, off_t*); + + // Create the dynamic symbol table. + void + create_dynamic_symtab(const Target*, Symbol_table*, Output_section** pdynstr, + unsigned int* plocal_dynamic_count, + std::vector<Symbol*>* pdynamic_symbols, + Versions* versions); + + // Finish the .dynamic section and PT_DYNAMIC segment. + void + finish_dynamic_section(const Input_objects*, const Symbol_table*); + + // Create the .interp section and PT_INTERP segment. + void + create_interp(const Target* target); + + // Create the version sections. + void + create_version_sections(const Target*, const Versions*, + unsigned int local_symcount, + const std::vector<Symbol*>& dynamic_symbols, + const Output_section* dynstr); + + template<int size, bool big_endian> + void + sized_create_version_sections(const Versions* versions, + unsigned int local_symcount, + const std::vector<Symbol*>& dynamic_symbols, + const Output_section* dynstr + ACCEPT_SIZE_ENDIAN); + + // Return whether to include this section in the link. + template<int size, bool big_endian> + bool + include_section(Object* object, const char* name, + const elfcpp::Shdr<size, big_endian>&); + + // Return the output section name to use given an input section + // name. Set *PLEN to the length of the name. *PLEN must be + // initialized to the length of NAME. + static const char* + output_section_name(const char* name, size_t* plen); + + // Return the output section name to use for a linkonce section + // name. PLEN is as for output_section_name. + static const char* + linkonce_output_name(const char* name, size_t* plen); + + // Return the output section for NAME, TYPE and FLAGS. + Output_section* + get_output_section(const char* name, Stringpool::Key name_key, + elfcpp::Elf_Word type, elfcpp::Elf_Xword flags); + + // Create a new Output_section. + Output_section* + make_output_section(const char* name, elfcpp::Elf_Word type, + elfcpp::Elf_Xword flags); + + // Set the final file offsets of all the segments. + off_t + set_segment_offsets(const Target*, Output_segment*, unsigned int* pshndx); + + // Set the final file offsets and section indexes of all the + // sections not associated with a segment. + off_t + set_section_offsets(off_t, unsigned int *pshndx); + + // Return whether SEG1 comes before SEG2 in the output file. + static bool + segment_precedes(const Output_segment* seg1, const Output_segment* seg2); + + // Map from section flags to segment flags. + static elfcpp::Elf_Word + section_flags_to_segment(elfcpp::Elf_Xword flags); + + // A mapping used for group signatures. + typedef Unordered_map<std::string, bool> Signatures; + + // Mapping from input section name/type/flags to output section. We + // use canonicalized strings here. + + typedef std::pair<Stringpool::Key, + std::pair<elfcpp::Elf_Word, elfcpp::Elf_Xword> > Key; + + struct Hash_key + { + size_t + operator()(const Key& k) const; + }; + + typedef Unordered_map<Key, Output_section*, Hash_key> Section_name_map; + + // A comparison class for segments. + + struct Compare_segments + { + bool + operator()(const Output_segment* seg1, const Output_segment* seg2) + { return Layout::segment_precedes(seg1, seg2); } + }; + + // A reference to the options on the command line. + const General_options& options_; + // The output section names. + Stringpool namepool_; + // The output symbol names. + Stringpool sympool_; + // The dynamic strings, if needed. + Stringpool dynpool_; + // The list of group sections and linkonce sections which we have seen. + Signatures signatures_; + // The mapping from input section name/type/flags to output sections. + Section_name_map section_name_map_; + // The list of output segments. + Segment_list segment_list_; + // The list of output sections. + Section_list section_list_; + // The list of output sections which are not attached to any output + // segment. + Section_list unattached_section_list_; + // The list of unattached Output_data objects which require special + // handling because they are not Output_sections. + Data_list special_output_list_; + // A pointer to the PT_TLS segment if there is one. + Output_segment* tls_segment_; + // The SHT_SYMTAB output section. + Output_section* symtab_section_; + // The SHT_DYNSYM output section if there is one. + Output_section* dynsym_section_; + // The SHT_DYNAMIC output section if there is one. + Output_section* dynamic_section_; + // The dynamic data which goes into dynamic_section_. + Output_data_dynamic* dynamic_data_; +}; + +// This task handles writing out data which is not part of a section +// or segment. + +class Write_data_task : public Task +{ + public: + Write_data_task(const Layout* layout, const Symbol_table* symtab, + const Target* target, Output_file* of, + Task_token* final_blocker) + : layout_(layout), symtab_(symtab), target_(target), of_(of), + final_blocker_(final_blocker) + { } + + // The standard Task methods. + + Is_runnable_type + is_runnable(Workqueue*); + + Task_locker* + locks(Workqueue*); + + void + run(Workqueue*); + + private: + const Layout* layout_; + const Symbol_table* symtab_; + const Target* target_; + Output_file* of_; + Task_token* final_blocker_; +}; + +// This task handles writing out the global symbols. + +class Write_symbols_task : public Task +{ + public: + Write_symbols_task(const Symbol_table* symtab, const Target* target, + const Stringpool* sympool, const Stringpool* dynpool, + Output_file* of, Task_token* final_blocker) + : symtab_(symtab), target_(target), sympool_(sympool), dynpool_(dynpool), + of_(of), final_blocker_(final_blocker) + { } + + // The standard Task methods. + + Is_runnable_type + is_runnable(Workqueue*); + + Task_locker* + locks(Workqueue*); + + void + run(Workqueue*); + + private: + const Symbol_table* symtab_; + const Target* target_; + const Stringpool* sympool_; + const Stringpool* dynpool_; + Output_file* of_; + Task_token* final_blocker_; +}; + +// This task function handles closing the file. + +class Close_task_runner : public Task_function_runner +{ + public: + Close_task_runner(Output_file* of) + : of_(of) + { } + + // Run the operation. + void + run(Workqueue*); + + private: + Output_file* of_; +}; + +// A small helper function to align an address. + +inline uint64_t +align_address(uint64_t address, uint64_t addralign) +{ + if (addralign != 0) + address = (address + addralign - 1) &~ (addralign - 1); + return address; +} + +} // End namespace gold. + +#endif // !defined(GOLD_LAYOUT_H) |