From: Ian Lance Taylor Date: Thu, 29 Nov 2007 20:10:17 +0000 (+0000) Subject: Clean up setting address and section offset. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=27bc2bce094e3a3ef536c5b8c2a38470bd7f3217;p=binutils-gdb.git Clean up setting address and section offset. --- diff --git a/gold/common.cc b/gold/common.cc index 3b616b154a1..652dfa174db 100644 --- a/gold/common.cc +++ b/gold/common.cc @@ -231,7 +231,7 @@ Symbol_table::do_allocate_commons(const General_options&, off += ssym->symsize(); } - poc->set_space_size(off); + poc->set_current_data_size(off); this->commons_.clear(); } diff --git a/gold/ehframe.cc b/gold/ehframe.cc index 1c7b7141aba..91a977f88c4 100644 --- a/gold/ehframe.cc +++ b/gold/ehframe.cc @@ -88,10 +88,10 @@ Eh_frame_hdr::Eh_frame_hdr(Output_section* eh_frame_section, { } -// Set the final address and size of the exception frame header. +// Set the size of the exception frame header. void -Eh_frame_hdr::do_set_address(uint64_t, off_t) +Eh_frame_hdr::set_final_data_size() { unsigned int data_size = eh_frame_hdr_size + 4; if (!this->any_unrecognized_eh_frame_sections_) @@ -976,8 +976,9 @@ Eh_frame::fde_count() const // Set the final data size. void -Eh_frame::do_set_address(uint64_t, off_t start_file_offset) +Eh_frame::set_final_data_size() { + off_t start_file_offset = this->offset(); off_t output_offset = 0; for (Unmergeable_cie_offsets::iterator p = diff --git a/gold/ehframe.h b/gold/ehframe.h index 6a584f97133..12c8c160df8 100644 --- a/gold/ehframe.h +++ b/gold/ehframe.h @@ -65,7 +65,7 @@ class Eh_frame_hdr : public Output_section_data // Set the final data size. void - do_set_address(uint64_t address, off_t offset); + set_final_data_size(); // Write the data to the file. void @@ -314,7 +314,7 @@ class Eh_frame : public Output_section_data // Set the final data size. void - do_set_address(uint64_t, off_t); + set_final_data_size(); // Return the output address for an input address. bool diff --git a/gold/gold.cc b/gold/gold.cc index 0b7c2ecfee3..ca8c9298a50 100644 --- a/gold/gold.cc +++ b/gold/gold.cc @@ -251,7 +251,7 @@ void queue_final_tasks(const General_options& options, const Input_objects* input_objects, const Symbol_table* symtab, - const Layout* layout, + Layout* layout, Workqueue* workqueue, Output_file* of) { diff --git a/gold/gold.h b/gold/gold.h index 25f6c0c7712..fcb77ec14bc 100644 --- a/gold/gold.h +++ b/gold/gold.h @@ -272,7 +272,7 @@ extern void queue_final_tasks(const General_options&, const Input_objects*, const Symbol_table*, - const Layout*, + Layout*, Workqueue*, Output_file* of); diff --git a/gold/i386.cc b/gold/i386.cc index e37e41ff13c..1bfc659fa6d 100644 --- a/gold/i386.cc +++ b/gold/i386.cc @@ -348,7 +348,7 @@ Target_i386::got_section(Symbol_table* symtab, Layout* layout) this->got_plt_); // The first three entries are reserved. - this->got_plt_->set_space_size(3 * 4); + this->got_plt_->set_current_data_size(3 * 4); // Define _GLOBAL_OFFSET_TABLE_ at the start of the PLT. symtab->define_in_output_data(this, "_GLOBAL_OFFSET_TABLE_", NULL, @@ -417,7 +417,7 @@ class Output_data_plt_i386 : public Output_section_data // Set the final size. void - do_set_address(uint64_t, off_t) + set_final_data_size() { this->set_data_size((this->count_ + 1) * plt_entry_size); } // Write out the PLT data. @@ -466,12 +466,12 @@ Output_data_plt_i386::add_entry(Symbol* gsym) ++this->count_; - off_t got_offset = this->got_plt_->data_size(); + off_t got_offset = this->got_plt_->current_data_size(); // Every PLT entry needs a GOT entry which points back to the PLT // entry (this will be changed by the dynamic linker, normally // lazily when the function is called). - this->got_plt_->set_space_size(got_offset + 4); + this->got_plt_->set_current_data_size(got_offset + 4); // Every PLT entry needs a reloc. gsym->set_needs_dynsym_entry(); @@ -700,10 +700,10 @@ Target_i386::copy_reloc(const General_options* options, if (align > dynbss->addralign()) dynbss->set_space_alignment(align); - off_t dynbss_size = dynbss->data_size(); + off_t dynbss_size = dynbss->current_data_size(); dynbss_size = align_address(dynbss_size, align); off_t offset = dynbss_size; - dynbss->set_space_size(dynbss_size + symsize); + dynbss->set_current_data_size(dynbss_size + symsize); symtab->define_with_copy_reloc(this, ssym, dynbss, offset); diff --git a/gold/layout.cc b/gold/layout.cc index 8cb945bd6d6..d95aea4f4dc 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -65,7 +65,7 @@ Layout::Layout(const General_options& options) : options_(options), namepool_(), sympool_(), dynpool_(), signatures_(), section_name_map_(), segment_list_(), section_list_(), unattached_section_list_(), special_output_list_(), - tls_segment_(NULL), symtab_section_(NULL), + section_headers_(NULL), tls_segment_(NULL), symtab_section_(NULL), dynsym_section_(NULL), dynamic_section_(NULL), dynamic_data_(NULL), eh_frame_section_(NULL), output_file_size_(-1), input_requires_executable_stack_(false), @@ -76,9 +76,9 @@ Layout::Layout(const General_options& options) // This is just for efficiency--it's OK if we wind up needing more. this->segment_list_.reserve(12); - // We expect three unattached Output_data objects: the file header, - // the segment headers, and the section headers. - this->special_output_list_.reserve(3); + // We expect two unattached Output_data objects: the file header and + // the segment headers. + this->special_output_list_.reserve(2); } // Hash a key we use to look up an output section mapping. @@ -695,37 +695,33 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab) this->special_output_list_.push_back(file_header); // We set the output section indexes in set_segment_offsets and - // set_section_offsets. + // set_section_indexes. unsigned int shndx = 1; // Set the file offsets of all the segments, and all the sections // they contain. off_t off = this->set_segment_offsets(target, load_seg, &shndx); - // Set the file offsets of all the data sections not associated with - // segments. This makes sure that debug sections have their offsets - // before symbols are finalized. - off = this->set_section_offsets(off, true); - // Create the symbol table sections. this->create_symtab_sections(input_objects, symtab, &off); // Create the .shstrtab section. Output_section* shstrtab_section = this->create_shstrtab(); - // Set the file offsets of all the non-data sections not associated with - // segments. + // Set the file offsets of all the non-data sections which don't + // have to wait for the input sections. off = this->set_section_offsets(off, false); // Now that all sections have been created, set the section indexes. shndx = this->set_section_indexes(shndx); // Create the section table header. - Output_section_headers* oshdrs = this->create_shdrs(&off); + this->create_shdrs(&off); - file_header->set_section_info(oshdrs, shstrtab_section); + file_header->set_section_info(this->section_headers_, shstrtab_section); - // Now we know exactly where everything goes in the output file. + // Now we know exactly where everything goes in the output file + // (except for non-allocated sections which require postprocessing). Output_data::layout_complete(); this->output_file_size_ = off; @@ -1063,21 +1059,22 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg, // segment. off_t -Layout::set_section_offsets(off_t off, - bool do_bits_sections) +Layout::set_section_offsets(off_t off, bool after_input_sections) { for (Section_list::iterator p = this->unattached_section_list_.begin(); p != this->unattached_section_list_.end(); ++p) { - bool is_bits_section = ((*p)->type() == elfcpp::SHT_PROGBITS - || (*p)->type() == elfcpp::SHT_NOBITS); - if (is_bits_section != do_bits_sections) - continue; - if ((*p)->offset() != -1) + // The symtab section is handled in create_symtab_sections. + if (*p == this->symtab_section_) continue; + + if ((*p)->after_input_sections() != after_input_sections) + continue; + off = align_address(off, (*p)->addralign()); - (*p)->set_address(0, off); + (*p)->set_file_offset(off); + (*p)->finalize_data_size(); off += (*p)->data_size(); } return off; @@ -1194,8 +1191,8 @@ Layout::create_symtab_sections(const Input_objects* input_objects, 0); this->symtab_section_ = osymtab; - Output_section_data* pos = new Output_data_space(off - startoff, - align); + Output_section_data* pos = new Output_data_fixed_space(off - startoff, + align); osymtab->add_output_section_data(pos); const char* strtab_name = this->namepool_.add(".strtab", false, NULL); @@ -1206,7 +1203,8 @@ Layout::create_symtab_sections(const Input_objects* input_objects, Output_section_data* pstr = new Output_data_strtab(&this->sympool_); ostrtab->add_output_section_data(pstr); - osymtab->set_address(0, startoff); + osymtab->set_file_offset(startoff); + osymtab->finalize_data_size(); osymtab->set_link_section(ostrtab); osymtab->set_info(local_symcount); osymtab->set_entsize(symsize); @@ -1227,10 +1225,13 @@ Layout::create_shstrtab() const char* name = this->namepool_.add(".shstrtab", false, NULL); - this->namepool_.set_string_offsets(); - Output_section* os = this->make_output_section(name, elfcpp::SHT_STRTAB, 0); + // We can't write out this section until we've set all the section + // names, and we don't set the names of compressed output sections + // until relocations are complete. + os->set_after_input_sections(); + Output_section_data* posd = new Output_data_strtab(&this->namepool_); os->add_output_section_data(posd); @@ -1240,7 +1241,7 @@ Layout::create_shstrtab() // Create the section headers. SIZE is 32 or 64. OFF is the file // offset. -Output_section_headers* +void Layout::create_shdrs(off_t* poff) { Output_section_headers* oshdrs; @@ -1249,11 +1250,10 @@ Layout::create_shdrs(off_t* poff) &this->unattached_section_list_, &this->namepool_); off_t off = align_address(*poff, oshdrs->addralign()); - oshdrs->set_address(0, off); + oshdrs->set_address_and_file_offset(0, off); off += oshdrs->data_size(); *poff = off; - this->special_output_list_.push_back(oshdrs); - return oshdrs; + this->section_headers_ = oshdrs; } // Create the dynamic symbol table. @@ -1321,8 +1321,8 @@ Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab, elfcpp::SHT_DYNSYM, elfcpp::SHF_ALLOC); - Output_section_data* odata = new Output_data_space(index * symsize, - align); + Output_section_data* odata = new Output_data_fixed_space(index * symsize, + align); dynsym->add_output_section_data(odata); dynsym->set_info(local_symcount); @@ -1880,8 +1880,18 @@ Layout::write_data(const Symbol_table* symtab, Output_file* of) const // input sections are complete. void -Layout::write_sections_after_input_sections(Output_file* of) const +Layout::write_sections_after_input_sections(Output_file* of) { + // Determine the final section offsets, and thus the final output + // file size. + off_t off = this->output_file_size_; + off = this->set_section_offsets(off, true); + if (off > this->output_file_size_) + { + of->resize(off); + this->output_file_size_ = off; + } + for (Section_list::const_iterator p = this->section_list_.begin(); p != this->section_list_.end(); ++p) @@ -1889,6 +1899,16 @@ Layout::write_sections_after_input_sections(Output_file* of) const if ((*p)->after_input_sections()) (*p)->write(of); } + + for (Section_list::const_iterator p = this->unattached_section_list_.begin(); + p != this->unattached_section_list_.end(); + ++p) + { + if ((*p)->after_input_sections()) + (*p)->write(of); + } + + this->section_headers_->write(of); } // Write_sections_task methods. diff --git a/gold/layout.h b/gold/layout.h index 9e0bcf72543..0659d1bb27f 100644 --- a/gold/layout.h +++ b/gold/layout.h @@ -214,7 +214,7 @@ class Layout // Write out output sections which can not be written until all the // input sections are complete. void - write_sections_after_input_sections(Output_file* of) const; + write_sections_after_input_sections(Output_file* of); // Return an output section named NAME, or NULL if there is none. Output_section* @@ -275,7 +275,7 @@ class Layout create_shstrtab(); // Create the section header table. - Output_section_headers* + void create_shdrs(off_t*); // Create the dynamic symbol table. @@ -344,7 +344,7 @@ class Layout // Set the final file offsets of all the sections not associated // with a segment. off_t - set_section_offsets(off_t, bool do_bits_sections); + set_section_offsets(off_t, bool after_input_sections); // Set the final section indexes of all the sections not associated // with a segment. Returns the next unused index. @@ -407,6 +407,8 @@ class Layout // The list of unattached Output_data objects which require special // handling because they are not Output_sections. Data_list special_output_list_; + // The section headers. + Output_section_headers* section_headers_; // A pointer to the PT_TLS segment if there is one. Output_segment* tls_segment_; // The SHT_SYMTAB output section. @@ -554,7 +556,7 @@ class Write_symbols_task : public Task class Write_after_input_sections_task : public Task { public: - Write_after_input_sections_task(const Layout* layout, Output_file* of, + Write_after_input_sections_task(Layout* layout, Output_file* of, Task_token* input_sections_blocker, Task_token* final_blocker) : layout_(layout), of_(of), @@ -580,7 +582,7 @@ class Write_after_input_sections_task : public Task private: class Write_sections_locker; - const Layout* layout_; + Layout* layout_; Output_file* of_; Task_token* input_sections_blocker_; Task_token* final_blocker_; diff --git a/gold/merge.cc b/gold/merge.cc index d8648d6f055..726a972a9f3 100644 --- a/gold/merge.cc +++ b/gold/merge.cc @@ -428,7 +428,7 @@ Output_merge_data::do_add_input_section(Relobj* object, unsigned int shndx) // constants. void -Output_merge_data::do_set_address(uint64_t, off_t) +Output_merge_data::set_final_data_size() { // Release the memory we don't need. this->p_ = static_cast(realloc(this->p_, this->len_)); @@ -502,7 +502,7 @@ Output_merge_string::do_add_input_section(Relobj* object, template void -Output_merge_string::do_set_address(uint64_t, off_t) +Output_merge_string::set_final_data_size() { this->stringpool_.set_string_offsets(); diff --git a/gold/merge.h b/gold/merge.h index ad009973fc7..70fe6b7237d 100644 --- a/gold/merge.h +++ b/gold/merge.h @@ -114,7 +114,7 @@ class Output_merge_data : public Output_merge_base // Set the final data size. void - do_set_address(uint64_t, off_t); + set_final_data_size(); // Write the data to the file. void @@ -215,7 +215,7 @@ class Output_merge_string : public Output_merge_base // Set the final data size. void - do_set_address(uint64_t, off_t); + set_final_data_size(); // Write the data to the file. void diff --git a/gold/output.cc b/gold/output.cc index 97277e0996b..d89c72a9723 100644 --- a/gold/output.cc +++ b/gold/output.cc @@ -43,7 +43,7 @@ namespace gold // Output_data variables. -bool Output_data::sizes_are_fixed; +bool Output_data::allocated_sizes_are_fixed; // Output_data methods. @@ -51,18 +51,6 @@ Output_data::~Output_data() { } -// Set the address and offset. - -void -Output_data::set_address(uint64_t addr, off_t off) -{ - this->address_ = addr; - this->offset_ = off; - - // Let the child class know. - this->do_set_address(addr, off); -} - // Return the default alignment for the target size. uint64_t @@ -335,6 +323,8 @@ Output_file_header::set_section_info(const Output_section_headers* shdrs, void Output_file_header::do_write(Output_file* of) { + gold_assert(this->offset() == 0); + if (parameters->get_size() == 32) { if (parameters->is_big_endian()) @@ -491,11 +481,10 @@ Output_section_data::do_out_shndx() const // Output_data_strtab methods. -// Set the address. We don't actually care about the address, but we -// do set our final size. +// Set the final data size. void -Output_data_strtab::do_set_address(uint64_t, off_t) +Output_data_strtab::set_final_data_size() { this->strtab_->set_string_offsets(); this->set_data_size(this->strtab_->get_strtab_size()); @@ -890,7 +879,7 @@ Output_data_dynamic::do_adjust_output_section(Output_section* os) // Set the final data size. void -Output_data_dynamic::do_set_address(uint64_t, off_t) +Output_data_dynamic::set_final_data_size() { // Add the terminating entry. this->add_constant(elfcpp::DT_NULL, 0); @@ -1003,7 +992,7 @@ Output_section::Input_section::set_address(uint64_t addr, off_t off, if (this->is_input_section()) this->u2_.object->set_section_offset(this->shndx_, off - secoff); else - this->u2_.posd->set_address(addr, off); + this->u2_.posd->set_address_and_file_offset(addr, off); } // Try to turn an input offset into an output offset. @@ -1065,8 +1054,14 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type, needs_dynsym_index_(false), should_link_to_symtab_(false), should_link_to_dynsym_(false), - after_input_sections_(false) + after_input_sections_(false), + requires_postprocessing_(false) { + // An unallocated section has no address. Forcing this means that + // we don't need special treatment for symbols defined in debug + // sections. + if ((flags & elfcpp::SHF_ALLOC) == 0) + this->set_address(0); } Output_section::~Output_section() @@ -1139,7 +1134,7 @@ Output_section::add_input_section(Sized_relobj* object, } } - off_t offset_in_section = this->data_size(); + off_t offset_in_section = this->current_data_size_for_child(); off_t aligned_offset_in_section = align_address(offset_in_section, addralign); @@ -1163,7 +1158,8 @@ Output_section::add_input_section(Sized_relobj* object, } } - this->set_data_size(aligned_offset_in_section + shdr.get_sh_size()); + this->set_current_data_size_for_child(aligned_offset_in_section + + shdr.get_sh_size()); // We need to keep track of this section if we are already keeping // track of sections, or if we are relaxing. FIXME: Add test for @@ -1191,7 +1187,7 @@ void Output_section::add_output_section_data(Input_section* inp) { if (this->input_sections_.empty()) - this->first_input_offset_ = this->data_size(); + this->first_input_offset_ = this->current_data_size_for_child(); this->input_sections_.push_back(*inp); @@ -1344,15 +1340,20 @@ Output_section::output_address(const Relobj* object, unsigned int shndx, gold_unreachable(); } -// Set the address of an Output_section. This is where we handle +// Set the data size of an Output_section. This is where we handle // setting the addresses of any Output_section_data objects. void -Output_section::do_set_address(uint64_t address, off_t startoff) +Output_section::set_final_data_size() { if (this->input_sections_.empty()) - return; + { + this->set_data_size(this->current_data_size_for_child()); + return; + } + uint64_t address = this->address(); + off_t startoff = this->offset(); off_t off = startoff + this->first_input_offset_; for (Input_section_list::iterator p = this->input_sections_.begin(); p != this->input_sections_.end(); @@ -1664,7 +1665,7 @@ Output_segment::set_section_list_addresses(Output_data_list* pdl, ++p) { off = align_address(off, (*p)->addralign()); - (*p)->set_address(addr + (off - startoff), off); + (*p)->set_address_and_file_offset(addr + (off - startoff), off); // Unless this is a PT_TLS segment, we want to ignore the size // of a SHF_TLS/SHT_NOBITS section. Such a section does not @@ -1870,15 +1871,36 @@ Output_file::open(off_t file_size) gold_fatal(_("%s: open: %s"), this->name_, strerror(errno)); this->o_ = o; + this->map(); +} + +// Resize the output file. + +void +Output_file::resize(off_t file_size) +{ + if (::munmap(this->base_, this->file_size_) < 0) + gold_error(_("%s: munmap: %s"), this->name_, strerror(errno)); + this->file_size_ = file_size; + this->map(); +} + +// Map the file into memory. + +void +Output_file::map() +{ + int o = this->o_; + // Write out one byte to make the file the right size. - if (::lseek(o, file_size - 1, SEEK_SET) < 0) + if (::lseek(o, this->file_size_ - 1, SEEK_SET) < 0) gold_fatal(_("%s: lseek: %s"), this->name_, strerror(errno)); char b = 0; if (::write(o, &b, 1) != 1) gold_fatal(_("%s: write: %s"), this->name_, strerror(errno)); // Map the file into memory. - void* base = ::mmap(NULL, file_size, PROT_READ | PROT_WRITE, + void* base = ::mmap(NULL, this->file_size_, PROT_READ | PROT_WRITE, MAP_SHARED, o, 0); if (base == MAP_FAILED) gold_fatal(_("%s: mmap: %s"), this->name_, strerror(errno)); diff --git a/gold/output.h b/gold/output.h index 5239b60f7ea..05ed1f87a5d 100644 --- a/gold/output.h +++ b/gold/output.h @@ -49,32 +49,44 @@ class Sized_relobj; class Output_data { public: - explicit Output_data(off_t data_size = 0) - : address_(0), data_size_(data_size), offset_(-1), + explicit Output_data() + : address_(0), data_size_(0), offset_(-1), + is_address_valid_(false), is_data_size_valid_(false), + is_offset_valid_(false), dynamic_reloc_count_(0) { } virtual ~Output_data(); - // Return the address. This is only valid after Layout::finalize is - // finished. + // Return the address. For allocated sections, this is only valid + // after Layout::finalize is finished. uint64_t address() const - { return this->address_; } + { + gold_assert(this->is_address_valid_); + return this->address_; + } - // Return the size of the data. This must be valid after - // Layout::finalize calls set_address, but need not be valid before - // then. + // Return the size of the data. For allocated sections, this must + // be valid after Layout::finalize calls set_address, but need not + // be valid before then. off_t data_size() const - { return this->data_size_; } + { + gold_assert(this->is_data_size_valid_); + return this->data_size_; + } // Return the file offset. This is only valid after - // Layout::finalize is finished. + // Layout::finalize is finished. For some non-allocated sections, + // it may not be valid until near the end of the link. off_t offset() const - { return this->offset_; } + { + gold_assert(this->is_offset_valid_); + return this->offset_; + } // Return the required alignment. uint64_t @@ -107,10 +119,46 @@ class Output_data set_out_shndx(unsigned int shndx) { this->do_set_out_shndx(shndx); } - // Set the address and file offset of this data. This is called - // during Layout::finalize. + // Set the address and file offset of this data, and finalize the + // size of the data. This is called during Layout::finalize for + // allocated sections. void - set_address(uint64_t addr, off_t off); + set_address_and_file_offset(uint64_t addr, off_t off) + { + this->set_address(addr); + this->set_file_offset(off); + this->finalize_data_size(); + } + + // Set the address. + void + set_address(uint64_t addr) + { + gold_assert(!this->is_address_valid_); + this->address_ = addr; + this->is_address_valid_ = true; + } + + // Set the file offset. + void + set_file_offset(off_t off) + { + gold_assert(!this->is_offset_valid_); + this->offset_ = off; + this->is_offset_valid_ = true; + } + + // Finalize the data size. + void + finalize_data_size() + { + if (!this->is_data_size_valid_) + { + // Tell the child class to set the data size. + this->set_final_data_size(); + gold_assert(this->is_data_size_valid_); + } + } // Write the data to the output file. This is called after // Layout::finalize is complete. @@ -118,16 +166,16 @@ class Output_data write(Output_file* file) { this->do_write(file); } - // This is called by Layout::finalize to note that all sizes must - // now be fixed. + // This is called by Layout::finalize to note that the sizes of + // allocated sections must now be fixed. static void layout_complete() - { Output_data::sizes_are_fixed = true; } + { Output_data::allocated_sizes_are_fixed = true; } // Used to check that layout has been done. static bool is_layout_complete() - { return Output_data::sizes_are_fixed; } + { return Output_data::allocated_sizes_are_fixed; } // Count the number of dynamic relocations applied to this section. void @@ -177,20 +225,51 @@ class Output_data do_set_out_shndx(unsigned int) { gold_unreachable(); } - // Set the address and file offset of the data. This only needs to - // be implemented if the child needs to know. The child class can - // set its size in this call. + // This is a hook for derived classes to set the data size. This is + // called by finalize_data_size, normally called during + // Layout::finalize, when the section address is set. virtual void - do_set_address(uint64_t, off_t) - { } + set_final_data_size() + { gold_unreachable(); } // Functions that child classes may call. + // Whether the address is valid. + bool + is_address_valid() const + { return this->is_address_valid_; } + + // Whether the file offset is valid. + bool + is_offset_valid() const + { return this->is_offset_valid_; } + + // Whether the data size is valid. + bool + is_data_size_valid() const + { return this->is_data_size_valid_; } + // Set the size of the data. void set_data_size(off_t data_size) { - gold_assert(!Output_data::sizes_are_fixed); + gold_assert(!this->is_data_size_valid_); + this->data_size_ = data_size; + this->is_data_size_valid_ = true; + } + + // Get the current data size--this is for the convenience of + // sections which build up their size over time. + off_t + current_data_size_for_child() const + { return this->data_size_; } + + // Set the current data size--this is for the convenience of + // sections which build up their size over time. + void + set_current_data_size_for_child(off_t data_size) + { + gold_assert(!this->is_data_size_valid_); this->data_size_ = data_size; } @@ -207,15 +286,22 @@ class Output_data Output_data& operator=(const Output_data&); // This is used for verification, to make sure that we don't try to - // change any sizes after we set the section addresses. - static bool sizes_are_fixed; + // change any sizes of allocated sections after we set the section + // addresses. + static bool allocated_sizes_are_fixed; - // Memory address in file (not always meaningful). + // Memory address in output file. uint64_t address_; - // Size of data in file. + // Size of data in output file. off_t data_size_; - // Offset within file. + // File offset of contents in output file. off_t offset_; + // Whether address_ is valid. + bool is_address_valid_; + // Whether data_size_ is valid. + bool is_data_size_valid_; + // Whether offset_ is valid. + bool is_offset_valid_; // Count of dynamic relocations applied to this section. unsigned int dynamic_reloc_count_; }; @@ -230,6 +316,7 @@ class Output_section_headers : public Output_data const Layout::Section_list*, const Stringpool*); + protected: // Write the data to the file. void do_write(Output_file*); @@ -258,6 +345,7 @@ class Output_segment_headers : public Output_data public: Output_segment_headers(const Layout::Segment_list& segment_list); + protected: // Write the data to the file. void do_write(Output_file*); @@ -290,6 +378,7 @@ class Output_file_header : public Output_data void set_section_info(const Output_section_headers*, const Output_section* shstrtab); + protected: // Write the data to the file. void do_write(Output_file*); @@ -299,12 +388,6 @@ class Output_file_header : public Output_data do_addralign() const { return Output_data::default_alignment(); } - // Set the address and offset--we only implement this for error - // checking. - void - do_set_address(uint64_t, off_t off) const - { gold_assert(off == 0); } - private: // Write the data to the file with the right size and endianness. template @@ -327,11 +410,11 @@ class Output_section_data : public Output_data { public: Output_section_data(off_t data_size, uint64_t addralign) - : Output_data(data_size), output_section_(NULL), addralign_(addralign) - { } + : Output_data(), output_section_(NULL), addralign_(addralign) + { this->set_data_size(data_size); } Output_section_data(uint64_t addralign) - : Output_data(0), output_section_(NULL), addralign_(addralign) + : Output_data(), output_section_(NULL), addralign_(addralign) { } // Return the output section. @@ -401,6 +484,34 @@ class Output_section_data : public Output_data uint64_t addralign_; }; +// Some Output_section_data classes build up their data step by step, +// rather than all at once. This class provides an interface for +// them. + +class Output_section_data_build : public Output_section_data +{ + public: + Output_section_data_build(uint64_t addralign) + : Output_section_data(addralign) + { } + + // Get the current data size. + off_t + current_data_size() const + { return this->current_data_size_for_child(); } + + // Set the current data size. + void + set_current_data_size(off_t data_size) + { this->set_current_data_size_for_child(data_size); } + + protected: + // Set the final data size. + virtual void + set_final_data_size() + { this->set_data_size(this->current_data_size_for_child()); } +}; + // A simple case of Output_data in which we have constant data to // output. @@ -420,14 +531,7 @@ class Output_data_const : public Output_section_data data_(reinterpret_cast(p), len) { } - // Add more data. - void - add_data(const std::string& add) - { - this->data_.append(add); - this->set_data_size(this->data_.size()); - } - + protected: // Write the data to the output file. void do_write(Output_file*); @@ -447,6 +551,7 @@ class Output_data_const_buffer : public Output_section_data : Output_section_data(len, addralign), p_(p) { } + protected: // Write the data the output file. void do_write(Output_file*); @@ -455,30 +560,42 @@ class Output_data_const_buffer : public Output_section_data const unsigned char* p_; }; -// A place holder for data written out via some other mechanism. +// A place holder for a fixed amount of data written out via some +// other mechanism. -class Output_data_space : public Output_section_data +class Output_data_fixed_space : public Output_section_data { public: - Output_data_space(off_t data_size, uint64_t addralign) + Output_data_fixed_space(off_t data_size, uint64_t addralign) : Output_section_data(data_size, addralign) { } - explicit Output_data_space(uint64_t addralign) - : Output_section_data(addralign) + protected: + // Write out the data--the actual data must be written out + // elsewhere. + void + do_write(Output_file*) { } +}; - // Set the size. - void - set_space_size(off_t space_size) - { this->set_data_size(space_size); } +// A place holder for variable sized data written out via some other +// mechanism. + +class Output_data_space : public Output_section_data_build +{ + public: + explicit Output_data_space(uint64_t addralign) + : Output_section_data_build(addralign) + { } // Set the alignment. void set_space_alignment(uint64_t align) { this->set_addralign(align); } - // Write out the data--this must be handled elsewhere. + protected: + // Write out the data--the actual data must be written out + // elsewhere. void do_write(Output_file*) { } @@ -493,10 +610,11 @@ class Output_data_strtab : public Output_section_data : Output_section_data(1), strtab_(strtab) { } + protected: // This is called to set the address and file offset. Here we make // sure that the Stringpool is finalized. void - do_set_address(uint64_t, off_t); + set_final_data_size(); // Write out the data. void @@ -743,7 +861,7 @@ class Output_reloc // the reloc type. template -class Output_data_reloc_base : public Output_section_data +class Output_data_reloc_base : public Output_section_data_build { public: typedef Output_reloc Output_reloc_type; @@ -753,14 +871,14 @@ class Output_data_reloc_base : public Output_section_data // Construct the section. Output_data_reloc_base() - : Output_section_data(Output_data::default_alignment_for_size(size)) + : Output_section_data_build(Output_data::default_alignment_for_size(size)) { } + protected: // Write out the data. void do_write(Output_file*); - protected: // Set the entry size and the link. void do_adjust_output_section(Output_section *os); @@ -770,7 +888,7 @@ class Output_data_reloc_base : public Output_section_data add(Output_data *od, const Output_reloc_type& reloc) { this->relocs_.push_back(reloc); - this->set_data_size(this->relocs_.size() * reloc_size); + this->set_current_data_size(this->relocs_.size() * reloc_size); od->add_dynamic_reloc(); } @@ -920,13 +1038,13 @@ class Output_data_reloc // needed. template -class Output_data_got : public Output_section_data +class Output_data_got : public Output_section_data_build { public: typedef typename elfcpp::Elf_types::Elf_Addr Valtype; Output_data_got() - : Output_section_data(Output_data::default_alignment_for_size(size)), + : Output_section_data_build(Output_data::default_alignment_for_size(size)), entries_() { } @@ -964,6 +1082,7 @@ class Output_data_got : public Output_section_data return this->last_got_offset(); } + protected: // Write out the GOT table. void do_write(Output_file*); @@ -1039,7 +1158,7 @@ class Output_data_got : public Output_section_data // Set the size of the section. void set_got_size() - { this->set_data_size(this->got_offset(this->entries_.size())); } + { this->set_current_data_size(this->got_offset(this->entries_.size())); } // The list of GOT entries. Got_entries entries_; @@ -1085,19 +1204,19 @@ class Output_data_dynamic : public Output_section_data add_string(elfcpp::DT tag, const std::string& str) { this->add_string(tag, str.c_str()); } + protected: + // Adjust the output section to set the entry size. + void + do_adjust_output_section(Output_section*); + // Set the final data size. void - do_set_address(uint64_t, off_t); + set_final_data_size(); // Write out the dynamic entries. void do_write(Output_file*); - protected: - // Adjust the output section to set the entry size. - void - do_adjust_output_section(Output_section*); - private: // This POD class holds a single dynamic entry. class Dynamic_entry @@ -1222,22 +1341,6 @@ class Output_section : public Output_data flags() const { return this->flags_; } - // Return the section index in the output file. - unsigned int - do_out_shndx() const - { - gold_assert(this->out_shndx_ != -1U); - return this->out_shndx_; - } - - // Set the output section index. - void - do_set_out_shndx(unsigned int shndx) - { - gold_assert(this->out_shndx_ == -1U); - this->out_shndx_ = shndx; - } - // Return the entsize field. uint64_t entsize() const @@ -1380,6 +1483,18 @@ class Output_section : public Output_data set_after_input_sections() { this->after_input_sections_ = true; } + // Return whether this section requires postprocessing after all + // relocations have been applied. + bool + requires_postprocessing() const + { return this->requires_postprocessing_; } + + // Record that this section requires postprocessing after all + // relocations have been applied. + void + set_requires_postprocessing() + { this->requires_postprocessing_ = true; } + // Return whether the offset OFFSET in the input section SHNDX in // object OBJECT is being included in the link. bool @@ -1397,12 +1512,35 @@ class Output_section : public Output_data output_address(const Relobj* object, unsigned int shndx, off_t offset) const; - // Set the address of the Output_section. For a typical + // Write the section header into *OPHDR. + template + void + write_header(const Layout*, const Stringpool*, + elfcpp::Shdr_write*) const; + + protected: + // Return the section index in the output file. + unsigned int + do_out_shndx() const + { + gold_assert(this->out_shndx_ != -1U); + return this->out_shndx_; + } + + // Set the output section index. + void + do_set_out_shndx(unsigned int shndx) + { + gold_assert(this->out_shndx_ == -1U); + this->out_shndx_ = shndx; + } + + // Set the final data size of the Output_section. For a typical // Output_section, there is nothing to do, but if there are any - // Output_section_data objects we need to set the final addresses + // Output_section_data objects we need to set their final addresses // here. void - do_set_address(uint64_t, off_t); + set_final_data_size(); // Write the data to the file. For a typical Output_section, this // does nothing: the data is written out by calling Object::Relocate @@ -1431,12 +1569,6 @@ class Output_section : public Output_data do_is_section_flag_set(elfcpp::Elf_Xword flag) const { return (this->flags_ & flag) != 0; } - // Write the section header into *OPHDR. - template - void - write_header(const Layout*, const Stringpool*, - elfcpp::Shdr_write*) const; - private: // In some cases we need to keep a list of the input sections // associated with this output section. We only need the list if we @@ -1658,7 +1790,7 @@ class Output_section : public Output_data // Most of these fields are only valid after layout. // The name of the section. This will point into a Stringpool. - const char* name_; + const char* const name_; // The section address is in the parent class. // The section alignment. uint64_t addralign_; @@ -1674,9 +1806,9 @@ class Output_section : public Output_data // If info_section_ is NULL, this is the section info field. unsigned int info_; // The section type. - elfcpp::Elf_Word type_; + const elfcpp::Elf_Word type_; // The section flags. - elfcpp::Elf_Xword flags_; + const elfcpp::Elf_Xword flags_; // The section index. unsigned int out_shndx_; // If there is a STT_SECTION for this output section in the normal @@ -1715,6 +1847,9 @@ class Output_section : public Output_data // Whether this section should be written after all the input // sections are complete. bool after_input_sections_ : 1; + // Whether this section requires post processing after all + // relocations have been applied. + bool requires_postprocessing_ : 1; }; // An output segment. PT_LOAD segments are built from collections of @@ -1895,6 +2030,10 @@ class Output_file void open(off_t file_size); + // Resize the output file. + void + resize(off_t file_size); + // Close the output file and make sure there are no error. void close(); @@ -1945,6 +2084,10 @@ class Output_file { } private: + // Map the file into memory. + void + map(); + // General options. const General_options& options_; // Target. diff --git a/gold/x86_64.cc b/gold/x86_64.cc index 5ccde57f838..f19fa9bf7c7 100644 --- a/gold/x86_64.cc +++ b/gold/x86_64.cc @@ -332,7 +332,7 @@ Target_x86_64::got_section(Symbol_table* symtab, Layout* layout) this->got_plt_); // The first three entries are reserved. - this->got_plt_->set_space_size(3 * 8); + this->got_plt_->set_current_data_size(3 * 8); // Define _GLOBAL_OFFSET_TABLE_ at the start of the PLT. symtab->define_in_output_data(this, "_GLOBAL_OFFSET_TABLE_", NULL, @@ -397,7 +397,7 @@ class Output_data_plt_x86_64 : public Output_section_data // Set the final size. void - do_set_address(uint64_t, off_t) + set_final_data_size() { this->set_data_size((this->count_ + 1) * plt_entry_size); } // Write out the PLT data. @@ -446,12 +446,12 @@ Output_data_plt_x86_64::add_entry(Symbol* gsym) ++this->count_; - off_t got_offset = this->got_plt_->data_size(); + off_t got_offset = this->got_plt_->current_data_size(); // Every PLT entry needs a GOT entry which points back to the PLT // entry (this will be changed by the dynamic linker, normally // lazily when the function is called). - this->got_plt_->set_space_size(got_offset + 8); + this->got_plt_->set_current_data_size(got_offset + 8); // Every PLT entry needs a reloc. gsym->set_needs_dynsym_entry(); @@ -654,10 +654,10 @@ Target_x86_64::copy_reloc(const General_options* options, if (align > dynbss->addralign()) dynbss->set_space_alignment(align); - off_t dynbss_size = dynbss->data_size(); + off_t dynbss_size = dynbss->current_data_size(); dynbss_size = align_address(dynbss_size, align); off_t offset = dynbss_size; - dynbss->set_space_size(dynbss_size + symsize); + dynbss->set_current_data_size(dynbss_size + symsize); symtab->define_with_copy_reloc(this, ssym, dynbss, offset);