Clean up setting address and section offset.
authorIan Lance Taylor <iant@google.com>
Thu, 29 Nov 2007 20:10:17 +0000 (20:10 +0000)
committerIan Lance Taylor <iant@google.com>
Thu, 29 Nov 2007 20:10:17 +0000 (20:10 +0000)
13 files changed:
gold/common.cc
gold/ehframe.cc
gold/ehframe.h
gold/gold.cc
gold/gold.h
gold/i386.cc
gold/layout.cc
gold/layout.h
gold/merge.cc
gold/merge.h
gold/output.cc
gold/output.h
gold/x86_64.cc

index 3b616b154a1a5661e710357bae3b0e076da1a693..652dfa174dba8c6745048cf3a9339374a40cb8cf 100644 (file)
@@ -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();
 }
index 1c7b7141aba7d3884064047436fcb741804fb659..91a977f88c44f133e24c7bba7f5540331bf1c70c 100644 (file)
@@ -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 =
index 6a584f97133b88352f441c0f03a29f7d8d4c109f..12c8c160df8ae85dc2e4f7f91c7fdaff5839722e 100644 (file)
@@ -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
index 0b7c2ecfee38784606a301e7eed6623588f165a7..ca8c9298a50386c4838557aa0f333c4f8cb4e10c 100644 (file)
@@ -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)
 {
index 25f6c0c77120cde54b27e8095f441aa31e65a30b..fcb77ec14bc44b1cad27659c67494a2e10197074 100644 (file)
@@ -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);
 
index e37e41ff13cedf82256cfe82eb00aff9552fef3d..1bfc659fa6d63d67665d28e9b5927629a847f113 100644 (file)
@@ -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);
 
index 8cb945bd6d6b0760794a0d81ee2b095057ea7392..d95aea4f4dc136b6d99673688e6d57550c49140f 100644 (file)
@@ -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.
index 9e0bcf7254345adf05cdc47b0a787bc0d91b7f50..0659d1bb27fd7ab2f9e146fce0f509d6a9aebf3d 100644 (file)
@@ -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_;
index d8648d6f0554c4f1a4446a6fd55b7dc43d7a70bc..726a972a9f3edbc41128fbed9709c33051b10d3c 100644 (file)
@@ -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<unsigned char*>(realloc(this->p_, this->len_));
@@ -502,7 +502,7 @@ Output_merge_string<Char_type>::do_add_input_section(Relobj* object,
 
 template<typename Char_type>
 void
-Output_merge_string<Char_type>::do_set_address(uint64_t, off_t)
+Output_merge_string<Char_type>::set_final_data_size()
 {
   this->stringpool_.set_string_offsets();
 
index ad009973fc717b63101dcb6641fe9fccb666b090..70fe6b7237d4ce017e7e5a355f230e3ba31a756e 100644 (file)
@@ -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
index 97277e0996bbf64e1ad43a23a7b18eaed5958464..d89c72a9723c1a37c86fcc6264cbc98bf67555ca 100644 (file)
@@ -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<size, big_endian>* 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<size, big_endian>* 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));
index 5239b60f7ea165874e15b3ebcd8b85da3faac8d1..05ed1f87a5dec511d81030880566293aa9f6b91a 100644 (file)
@@ -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<int size, bool big_endian>
@@ -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<const char*>(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<elfcpp::SHT_RELA, dynamic, size, big_endian>
 // the reloc type.
 
 template<int sh_type, bool dynamic, int size, bool big_endian>
-class Output_data_reloc_base : public Output_section_data
+class Output_data_reloc_base : public Output_section_data_build
 {
  public:
   typedef Output_reloc<sh_type, dynamic, size, big_endian> 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<elfcpp::SHT_RELA, dynamic, size, big_endian>
 // needed.
 
 template<int size, bool big_endian>
-class Output_data_got : public Output_section_data
+class Output_data_got : public Output_section_data_build
 {
  public:
   typedef typename elfcpp::Elf_types<size>::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<int size, bool big_endian>
+  void
+  write_header(const Layout*, const Stringpool*,
+              elfcpp::Shdr_write<size, big_endian>*) 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<int size, bool big_endian>
-  void
-  write_header(const Layout*, const Stringpool*,
-              elfcpp::Shdr_write<size, big_endian>*) 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.
index 5ccde57f838d297d829960d7e82803a34ee45321..f19fa9bf7c7aac1461d83ee4cc21fc6e91e19f1d 100644 (file)
@@ -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);