diff options
Diffstat (limited to 'gold/output.h')
-rw-r--r-- | gold/output.h | 365 |
1 files changed, 342 insertions, 23 deletions
diff --git a/gold/output.h b/gold/output.h index 7bd0cf3..6de6e69 100644 --- a/gold/output.h +++ b/gold/output.h @@ -54,7 +54,7 @@ class Output_data explicit Output_data() : address_(0), data_size_(0), offset_(-1), is_address_valid_(false), is_data_size_valid_(false), - is_offset_valid_(false), + is_offset_valid_(false), is_data_size_fixed_(false), dynamic_reloc_count_(0) { } @@ -80,6 +80,11 @@ class Output_data return this->data_size_; } + // Return true if data size is fixed. + bool + is_data_size_fixed() const + { return this->is_data_size_fixed_; } + // Return the file offset. This is only valid after // Layout::finalize is finished. For some non-allocated sections, // it may not be valid until near the end of the link. @@ -97,10 +102,17 @@ class Output_data { this->is_address_valid_ = false; this->is_offset_valid_ = false; - this->is_data_size_valid_ = false; + if (!this->is_data_size_fixed_) + this->is_data_size_valid_ = false; this->do_reset_address_and_file_offset(); } + // Return true if address and file offset already have reset values. In + // other words, calling reset_address_and_file_offset will not change them. + bool + address_and_file_offset_have_reset_values() const + { return this->do_address_and_file_offset_have_reset_values(); } + // Return the required alignment. uint64_t addralign() const @@ -311,6 +323,14 @@ class Output_data do_reset_address_and_file_offset() { } + // Return true if address and file offset already have reset values. In + // other words, calling reset_address_and_file_offset will not change them. + // A child class overriding do_reset_address_and_file_offset may need to + // also override this. + virtual bool + do_address_and_file_offset_have_reset_values() const + { return !this->is_address_valid_ && !this->is_offset_valid_; } + // Set the TLS offset. Called only for SHT_TLS sections. virtual void do_set_tls_offset(uint64_t) @@ -341,11 +361,21 @@ class Output_data void set_data_size(off_t data_size) { - gold_assert(!this->is_data_size_valid_); + gold_assert(!this->is_data_size_valid_ + && !this->is_data_size_fixed_); this->data_size_ = data_size; this->is_data_size_valid_ = true; } + // Fix the data size. Once it is fixed, it cannot be changed + // and the data size remains always valid. + void + fix_data_size() + { + gold_assert(this->is_data_size_valid_); + this->is_data_size_fixed_ = true; + } + // Get the current data size--this is for the convenience of // sections which build up their size over time. off_t @@ -390,6 +420,8 @@ class Output_data bool is_data_size_valid_; // Whether offset_ is valid. bool is_offset_valid_; + // Whether data size is fixed. + bool is_data_size_fixed_; // Count of dynamic relocations applied to this section. unsigned int dynamic_reloc_count_; }; @@ -421,12 +453,21 @@ class Output_section_headers : public Output_data do_print_to_mapfile(Mapfile* mapfile) const { mapfile->print_output_data(this, _("** section headers")); } + // Set final data size. + void + set_final_data_size() + { this->set_data_size(this->do_size()); } + private: // Write the data to the file with the right size and endianness. template<int size, bool big_endian> void do_sized_write(Output_file*); + // Compute data size. + off_t + do_size() const; + const Layout* layout_; const Layout::Segment_list* segment_list_; const Layout::Section_list* section_list_; @@ -457,12 +498,21 @@ class Output_segment_headers : public Output_data do_print_to_mapfile(Mapfile* mapfile) const { mapfile->print_output_data(this, _("** segment headers")); } + // Set final data size. + void + set_final_data_size() + { this->set_data_size(this->do_size()); } + private: // Write the data to the file with the right size and endianness. template<int size, bool big_endian> void do_sized_write(Output_file*); + // Compute the current size. + off_t + do_size() const; + const Layout::Segment_list& segment_list_; }; @@ -496,6 +546,11 @@ class Output_file_header : public Output_data do_print_to_mapfile(Mapfile* mapfile) const { mapfile->print_output_data(this, _("** file header")); } + // Set final data size. + void + set_final_data_size(void) + { this->set_data_size(this->do_size()); } + private: // Write the data to the file with the right size and endianness. template<int size, bool big_endian> @@ -507,6 +562,10 @@ class Output_file_header : public Output_data typename elfcpp::Elf_types<size>::Elf_Addr entry(); + // Compute the current data size. + off_t + do_size() const; + const Target* target_; const Symbol_table* symtab_; const Output_segment_headers* segment_header_; @@ -523,9 +582,14 @@ class Output_file_header : public Output_data class Output_section_data : public Output_data { public: - Output_section_data(off_t data_size, uint64_t addralign) + Output_section_data(off_t data_size, uint64_t addralign, + bool is_data_size_fixed) : Output_data(), output_section_(NULL), addralign_(addralign) - { this->set_data_size(data_size); } + { + this->set_data_size(data_size); + if (is_data_size_fixed) + this->fix_data_size(); + } Output_section_data(uint64_t addralign) : Output_data(), output_section_(NULL), addralign_(addralign) @@ -675,15 +739,15 @@ class Output_data_const : public Output_section_data { public: Output_data_const(const std::string& data, uint64_t addralign) - : Output_section_data(data.size(), addralign), data_(data) + : Output_section_data(data.size(), addralign, true), data_(data) { } Output_data_const(const char* p, off_t len, uint64_t addralign) - : Output_section_data(len, addralign), data_(p, len) + : Output_section_data(len, addralign, true), data_(p, len) { } Output_data_const(const unsigned char* p, off_t len, uint64_t addralign) - : Output_section_data(len, addralign), + : Output_section_data(len, addralign, true), data_(reinterpret_cast<const char*>(p), len) { } @@ -714,7 +778,7 @@ class Output_data_const_buffer : public Output_section_data public: Output_data_const_buffer(const unsigned char* p, off_t len, uint64_t addralign, const char* map_name) - : Output_section_data(len, addralign), + : Output_section_data(len, addralign, true), p_(p), map_name_(map_name) { } @@ -749,7 +813,7 @@ class Output_data_fixed_space : public Output_section_data public: Output_data_fixed_space(off_t data_size, uint64_t addralign, const char* map_name) - : Output_section_data(data_size, addralign), + : Output_section_data(data_size, addralign, true), map_name_(map_name) { } @@ -812,7 +876,7 @@ class Output_data_zero_fill : public Output_section_data { public: Output_data_zero_fill(off_t data_size, uint64_t addralign) - : Output_section_data(data_size, addralign) + : Output_section_data(data_size, addralign, true) { } protected: @@ -1531,6 +1595,11 @@ class Output_data_group : public Output_section_data do_print_to_mapfile(Mapfile* mapfile) const { mapfile->print_output_data(this, _("** group")); } + // Set final data size. + void + set_final_data_size() + { this->set_data_size((this->input_shndxes_.size() + 1) * 4); } + private: // The input object. Sized_relobj<size, big_endian>* relobj_; @@ -1814,6 +1883,11 @@ class Output_data_dynamic : public Output_section_data : tag_(tag), offset_(DYNAMIC_STRING) { this->u_.str = str; } + // Return the tag of this entry. + elfcpp::DT + tag() const + { return this->tag_; } + // Write the dynamic entry to an output view. template<int size, bool big_endian> void @@ -1880,7 +1954,7 @@ class Output_symtab_xindex : public Output_section_data { public: Output_symtab_xindex(size_t symcount) - : Output_section_data(symcount * 4, 4), + : Output_section_data(symcount * 4, 4, true), entries_() { } @@ -1912,6 +1986,33 @@ class Output_symtab_xindex : public Output_section_data Xindex_entries entries_; }; +// A relaxed input section. +class Output_relaxed_input_section : public Output_section_data +{ + public: + // We would like to call relobj->section_addralign(shndx) to get the + // alignment but we do not want the constructor to fail. So callers + // are repsonsible for ensuring that. + Output_relaxed_input_section(Relobj* relobj, unsigned int shndx, + uint64_t addralign) + : Output_section_data(addralign), relobj_(relobj), shndx_(shndx) + { } + + // Return the Relobj of this relaxed input section. + Relobj* + relobj() const + { return this->relobj_; } + + // Return the section index of this relaxed input section. + unsigned int + shndx() const + { return this->shndx_; } + + private: + Relobj* relobj_; + unsigned int shndx_; +}; + // An output section. We don't expect to have too many output // sections, so we don't bother to do a template on the size. @@ -2310,6 +2411,69 @@ class Output_section : public Output_data // The next few calls are for linker script support. + // We need to export the input sections to linker scripts. Previously + // we export a pair of Relobj pointer and section index. We now need to + // handle relaxed input sections as well. So we use this class. + class Simple_input_section + { + private: + static const unsigned int invalid_shndx = static_cast<unsigned int>(-1); + + public: + Simple_input_section(Relobj *relobj, unsigned int shndx) + : shndx_(shndx) + { + gold_assert(shndx != invalid_shndx); + this->u_.relobj = relobj; + } + + Simple_input_section(Output_relaxed_input_section* section) + : shndx_(invalid_shndx) + { this->u_.relaxed_input_section = section; } + + // Whether this is a relaxed section. + bool + is_relaxed_input_section() const + { return this->shndx_ == invalid_shndx; } + + // Return object of an input section. + Relobj* + relobj() const + { + return ((this->shndx_ != invalid_shndx) + ? this->u_.relobj + : this->u_.relaxed_input_section->relobj()); + } + + // Return index of an input section. + unsigned int + shndx() const + { + return ((this->shndx_ != invalid_shndx) + ? this->shndx_ + : this->u_.relaxed_input_section->shndx()); + } + + // Return the Output_relaxed_input_section object of a relaxed section. + Output_relaxed_input_section* + relaxed_input_section() const + { + gold_assert(this->shndx_ == invalid_shndx); + return this->u_.relaxed_input_section; + } + + private: + // Pointer to either an Relobj or an Output_relaxed_input_section. + union + { + Relobj* relobj; + Output_relaxed_input_section* relaxed_input_section; + } u_; + // Section index for an non-relaxed section or invalid_shndx for + // a relaxed section. + unsigned int shndx_; + }; + // Store the list of input sections for this Output_section into the // list passed in. This removes the input sections, leaving only // any Output_section_data elements. This returns the size of those @@ -2318,11 +2482,11 @@ class Output_section : public Output_data // any spaces between the remaining Output_section_data elements. uint64_t get_input_sections(uint64_t address, const std::string& fill, - std::list<std::pair<Relobj*, unsigned int > >*); + std::list<Simple_input_section>*); // Add an input section from a script. void - add_input_section_for_script(Relobj* object, unsigned int shndx, + add_input_section_for_script(const Simple_input_section& input_section, off_t data_size, uint64_t addralign); // Set the current size of the output section. @@ -2337,6 +2501,15 @@ class Output_section : public Output_data // End of linker script support. + // Save states before doing section layout. + // This is used for relaxation. + void + save_states(); + + // Restore states prior to section layout. + void + restore_states(); + // Print merge statistics to stderr. void print_merge_stats(); @@ -2374,6 +2547,11 @@ class Output_section : public Output_data void do_reset_address_and_file_offset(); + // Return true if address and file offset already have reset values. In + // other words, calling reset_address_and_file_offset will not change them. + bool + do_address_and_file_offset_have_reset_values() const; + // Write the data to the file. For a typical Output_section, this // does nothing: the data is written out by calling Object::Relocate // on each input object. But if there are any Output_section_data @@ -2476,7 +2654,8 @@ class Output_section : public Output_data { gold_assert(shndx != OUTPUT_SECTION_CODE && shndx != MERGE_DATA_SECTION_CODE - && shndx != MERGE_STRING_SECTION_CODE); + && shndx != MERGE_STRING_SECTION_CODE + && shndx != RELAXED_INPUT_SECTION_CODE); this->u1_.data_size = data_size; this->u2_.object = object; } @@ -2500,6 +2679,14 @@ class Output_section : public Output_data this->u2_.posd = posd; } + // For a relaxed input section. + Input_section(Output_relaxed_input_section *psection) + : shndx_(RELAXED_INPUT_SECTION_CODE), p2align_(0) + { + this->u1_.data_size = 0; + this->u2_.poris = psection; + } + // The required alignment. uint64_t addralign() const @@ -2521,7 +2708,8 @@ class Output_section : public Output_data { return (this->shndx_ != OUTPUT_SECTION_CODE && this->shndx_ != MERGE_DATA_SECTION_CODE - && this->shndx_ != MERGE_STRING_SECTION_CODE); + && this->shndx_ != MERGE_STRING_SECTION_CODE + && this->shndx_ != RELAXED_INPUT_SECTION_CODE); } // Return whether this is a merge section which matches the @@ -2537,6 +2725,18 @@ class Output_section : public Output_data && this->addralign() == addralign); } + // Return whether this is a relaxed input section. + bool + is_relaxed_input_section() const + { return this->shndx_ == RELAXED_INPUT_SECTION_CODE; } + + // Return whether this is a generic Output_section_data. + bool + is_output_section_data() const + { + return this->shndx_ == OUTPUT_SECTION_CODE; + } + // Return the object for an input section. Relobj* relobj() const @@ -2553,12 +2753,31 @@ class Output_section : public Output_data return this->shndx_; } + // For non-input-sections, return the associated Output_section_data + // object. + Output_section_data* + output_section_data() const + { + gold_assert(!this->is_input_section()); + return this->u2_.posd; + } + + // Return the Output_relaxed_input_section object. + Output_relaxed_input_section* + relaxed_input_section() const + { + gold_assert(this->is_relaxed_input_section()); + return this->u2_.poris; + } + // Set the output section. void set_output_section(Output_section* os) { gold_assert(!this->is_input_section()); - this->u2_.posd->set_output_section(os); + Output_section_data *posd = + this->is_relaxed_input_section() ? this->u2_.poris : this->u2_.posd; + posd->set_output_section(os); } // Set the address and file offset. This is called during @@ -2636,7 +2855,9 @@ class Output_section : public Output_data MERGE_DATA_SECTION_CODE = -2U, // An Output_section_data for an SHF_MERGE section with // SHF_STRINGS set. - MERGE_STRING_SECTION_CODE = -3U + MERGE_STRING_SECTION_CODE = -3U, + // An Output_section_data for a relaxed input section. + RELAXED_INPUT_SECTION_CODE = -4U }; // For an ordinary input section, this is the section index in the @@ -2650,8 +2871,8 @@ class Output_section : public Output_data { // For an ordinary input section, the section size. off_t data_size; - // For OUTPUT_SECTION_CODE, this is not used. For - // MERGE_DATA_SECTION_CODE or MERGE_STRING_SECTION_CODE, the + // For OUTPUT_SECTION_CODE or RELAXED_INPUT_SECTION_CODE, this is not + // used. For MERGE_DATA_SECTION_CODE or MERGE_STRING_SECTION_CODE, the // entity size. uint64_t entsize; } u1_; @@ -2663,11 +2884,97 @@ class Output_section : public Output_data // For OUTPUT_SECTION_CODE or MERGE_DATA_SECTION_CODE or // MERGE_STRING_SECTION_CODE, the data. Output_section_data* posd; + // For RELAXED_INPUT_SECTION_CODE, the data. + Output_relaxed_input_section* poris; } u2_; }; typedef std::vector<Input_section> Input_section_list; + // We only save enough information to undo the effects of section layout. + class Checkpoint_output_section + { + public: + Checkpoint_output_section(uint64_t addralign, elfcpp::Elf_Xword flags, + const Input_section_list& input_sections, + off_t first_input_offset, + bool attached_input_sections_are_sorted) + : addralign_(addralign), flags_(flags), + input_sections_(input_sections), + input_sections_size_(input_sections_.size()), + input_sections_copy_(), first_input_offset_(first_input_offset), + attached_input_sections_are_sorted_(attached_input_sections_are_sorted) + { } + + virtual + ~Checkpoint_output_section() + { } + + // Return the address alignment. + uint64_t + addralign() const + { return this->addralign_; } + + // Return the section flags. + elfcpp::Elf_Xword + flags() const + { return this->flags_; } + + // Return a reference to the input section list copy. + const Input_section_list& + input_sections() const + { return this->input_sections_copy_; } + + // Return the size of input_sections at the time when checkpoint is + // taken. + size_t + input_sections_size() const + { return this->input_sections_size_; } + + // Whether input sections are copied. + bool + input_sections_saved() const + { return this->input_sections_copy_.size() == this->input_sections_size_; } + + off_t + first_input_offset() const + { return this->first_input_offset_; } + + bool + attached_input_sections_are_sorted() const + { return this->attached_input_sections_are_sorted_; } + + // Save input sections. + void + save_input_sections() + { + this->input_sections_copy_.reserve(this->input_sections_size_); + this->input_sections_copy_.clear(); + Input_section_list::const_iterator p = this->input_sections_.begin(); + gold_assert(this->input_sections_size_ >= this->input_sections_.size()); + for(size_t i = 0; i < this->input_sections_size_ ; i++, ++p) + this->input_sections_copy_.push_back(*p); + } + + private: + // The section alignment. + uint64_t addralign_; + // The section flags. + elfcpp::Elf_Xword flags_; + // Reference to the input sections to be checkpointed. + const Input_section_list& input_sections_; + // Size of the checkpointed portion of input_sections_; + size_t input_sections_size_; + // Copy of input sections. + Input_section_list input_sections_copy_; + // The offset of the first entry in input_sections_. + off_t first_input_offset_; + // True if the input sections attached to this output section have + // already been sorted. + bool attached_input_sections_are_sorted_; + }; + + private: // This class is used to sort the input sections. class Input_section_sort_entry; @@ -2729,6 +3036,10 @@ class Output_section : public Output_data add_output_merge_section(Output_section_data* posd, bool is_string, uint64_t entsize); + // Relax an existing input section. + void + relax_input_section(Output_relaxed_input_section*); + // Sort the attached input sections. void sort_attached_input_sections(); @@ -2836,11 +3147,19 @@ class Output_section : public Output_data // For SHT_TLS sections, the offset of this section relative to the base // of the TLS segment. uint64_t tls_offset_; + // Saved checkpoint. + Checkpoint_output_section* checkpoint_; }; // An output segment. PT_LOAD segments are built from collections of // output sections. Other segments typically point within PT_LOAD // segments, and are built directly as needed. +// +// NOTE: We want to use the copy constructor for this class. During +// relaxation, we may try built the segments multiple times. We do +// that by copying the original segment list before lay-out, doing +// a trial lay-out and roll-back to the saved copied if we need to +// to the lay-out again. class Output_segment { @@ -2998,9 +3317,6 @@ class Output_segment print_sections_to_mapfile(Mapfile*) const; private: - Output_segment(const Output_segment&); - Output_segment& operator=(const Output_segment&); - typedef std::list<Output_data*> Output_data_list; // Find the maximum alignment in an Output_data_list. @@ -3043,6 +3359,9 @@ class Output_segment void print_section_list_to_mapfile(Mapfile*, const Output_data_list*) const; + // NOTE: We want to use the copy constructor. Currently, shallow copy + // works for us so we do not need to write our own copy constructor. + // The list of output data with contents attached to this segment. Output_data_list output_data_; // The list of output data without contents attached to this segment. |