Compress all debug sections.
authorIan Lance Taylor <iant@google.com>
Sat, 1 Dec 2007 06:34:12 +0000 (06:34 +0000)
committerIan Lance Taylor <iant@google.com>
Sat, 1 Dec 2007 06:34:12 +0000 (06:34 +0000)
15 files changed:
gold/compressed_output.cc
gold/compressed_output.h
gold/layout.cc
gold/layout.h
gold/merge.cc
gold/merge.h
gold/object.cc
gold/object.h
gold/output.cc
gold/output.h
gold/parameters.cc
gold/parameters.h
gold/reloc.cc
gold/stringpool.cc
gold/stringpool.h

index bf5f6407d3b7cefd2ffae5432e8e6f799fa1528e..d12bfda03c271595c44d40e9a9d377599acffd20 100644 (file)
@@ -26,8 +26,8 @@
 #include <zlib.h>
 #endif
 
-#include "compressed_output.h"
 #include "parameters.h"
+#include "compressed_output.h"
 
 namespace gold
 {
@@ -89,187 +89,60 @@ zlib_compressed_suffix(unsigned long uncompressed_size)
   return std::string(".zlib.") + size_string;
 }
 
-// Class Output_compressed_section_data.
-
-// Add an input section.  In this case, we just keep track of the sections.
-
-bool
-Output_compressed_section_data::do_add_input_section(Relobj* obj,
-                                                     unsigned int shndx)
-{
-  this->objects_.push_back(Object_entry(obj, shndx));
-  return true;
-}
+// Class Output_compressed_section.
 
 // Set the final data size of a compressed section.  This is where
 // we actually compress the section data.
 
 void
-Output_compressed_section_data::set_final_data_size()
+Output_compressed_section::set_final_data_size()
 {
-  // FIXME: assert that relocations have already been applied.
-
-  off_t uncompressed_size = 0;
-  for (std::vector<Object_entry>::iterator it = this->objects_.begin();
-       it != this->objects_.end();
-       ++it)
-    {
-      it->contents
-        = it->object->section_contents(it->shndx, &it->length, false);
-      uncompressed_size += it->length;
-    }
+  off_t uncompressed_size = this->postprocessing_buffer_size();
 
   // (Try to) compress the data.
   unsigned long compressed_size;
-  char* uncompressed_data = new char[uncompressed_size];
-  off_t pos = 0;
-  for (std::vector<Object_entry>::const_iterator it = this->objects_.begin();
-       it != this->objects_.end();
-       ++it)
-    {
-      memcpy(uncompressed_data + pos,
-             reinterpret_cast<const char*>(it->contents),
-             it->length);
-      pos += it->length;
-    }
+  unsigned char* u_uncompressed_data = this->postprocessing_buffer();
+  char* uncompressed_data = reinterpret_cast<char*>(u_uncompressed_data);
+
+  // At this point the contents of all regular input sections will
+  // have been copied into the postprocessing buffer, and relocations
+  // will have been applied.  Now we need to copy in the contents of
+  // anything other than a regular input section.
+  this->write_to_postprocessing_buffer();
 
   bool success = false;
-  if (options_.zlib_compress_debug_sections())
+  if (this->options_->zlib_compress_debug_sections())
     success = zlib_compress(uncompressed_data, uncompressed_size,
                             &this->data_, &compressed_size);
   if (success)
     {
-      delete[] uncompressed_data;
+      std::string suffix(zlib_compressed_suffix(uncompressed_size));
+      this->new_section_name_ = std::string(this->name()) + suffix;
+      this->set_name(this->new_section_name_.c_str());
       this->set_data_size(compressed_size);
-      this->new_section_name_ = zlib_compressed_suffix(uncompressed_size);
     }
   else
     {
-      gold_warning(_("Not compressing section data: zlib error"));
+      gold_warning(_("not compressing section data: zlib error"));
       gold_assert(this->data_ == NULL);
-      this->data_ = uncompressed_data;
       this->set_data_size(uncompressed_size);
     }
 }
 
-// Change the name of the output section to reflect it's compressed.
-// The layout routines call into this right before finalizing the
-// shstrtab.
-
-const char*
-Output_compressed_section_data::do_modified_output_section_name(
-  const char* name)
-{
-  // This mean we never compressed the data.
-  if (this->new_section_name_.empty())
-    return NULL;
-  this->new_section_name_ = std::string(name) + this->new_section_name_;
-  return this->new_section_name_.c_str();
-}
-
 // Write out a compressed section.  If we couldn't compress, we just
 // write it out as normal, uncompressed data.
 
 void
-Output_compressed_section_data::do_write(Output_file* of)
-{
-  unsigned char* uview = of->get_output_view(this->offset(),
-                                             this->data_size());
-  char* view = reinterpret_cast<char*>(uview);
-  memcpy(view, this->data_, this->data_size());
-  of->write_output_view(this->offset(), this->data_size(), uview);
-}
-
-// Class Output_compressed_string.
-
-// Add an input section.  We don't do anything special here.
-
-template<typename Char_type>
-bool
-Output_compressed_string<Char_type>::do_add_input_section(Relobj* object,
-                                                          unsigned int shndx)
-{
-  return Output_merge_string<Char_type>::do_add_input_section(object, shndx);
-}
-
-// Set the final data size of a compressed section.  This is where
-// we actually compress the section data.
-
-template<typename Char_type>
-void
-Output_compressed_string<Char_type>::set_final_data_size()
+Output_compressed_section::do_write(Output_file* of)
 {
-  // First let the superclass finalize all its data, then write it to
-  // a buffer.
-  unsigned long uncompressed_size = this->finalize_merged_data();
-  char* uncompressed_data = new char[uncompressed_size];
-  this->stringpool_to_buffer(uncompressed_data, uncompressed_size);
-
-  // (Try to) compress the data.
-  unsigned long compressed_size;
-  if (options_.zlib_compress_debug_sections()
-      && zlib_compress(uncompressed_data, uncompressed_size,
-                       &this->compressed_data_, &compressed_size))
-    {
-      this->set_data_size(compressed_size);
-      // Save some memory.
-      this->clear_stringpool();
-      // We will be renaming the section to name.zlib.uncompressed_size.
-      this->new_section_name_ = zlib_compressed_suffix(uncompressed_size);
-    }
+  off_t offset = this->offset();
+  off_t data_size = this->data_size();
+  unsigned char* view = of->get_output_view(offset, data_size);
+  if (this->data_ == NULL)
+    memcpy(view, this->postprocessing_buffer(), data_size);
   else
-    {
-      this->compressed_data_ = NULL;
-      this->set_data_size(uncompressed_size);
-    }
-
-  delete[] uncompressed_data;
+    memcpy(view, this->data_, data_size);
+  of->write_output_view(offset, data_size, view);
 }
 
-// Change the name of the output section to reflect it's compressed.
-// The layout routines call into this right before finalizing the
-// shstrtab.
-
-template<typename Char_type>
-const char*
-Output_compressed_string<Char_type>::do_modified_output_section_name(
-  const char* name)
-{
-  // This mean we never compressed the data
-  if (this->new_section_name_.empty())
-    return NULL;
-  this->new_section_name_ = std::string(name) + this->new_section_name_;
-  return this->new_section_name_.c_str();
-}
-
-// Write out a compressed string section.  If we couldn't compress,
-// we just write out the normal string section.
-
-template<typename Char_type>
-void
-Output_compressed_string<Char_type>::do_write(Output_file* of)
-{
-  if (this->compressed_data_ == NULL)
-    Output_merge_string<Char_type>::do_write(of);
-  else
-    {
-      unsigned char* uview = of->get_output_view(this->offset(),
-                                                 this->data_size());
-      char* view = reinterpret_cast<char*>(uview);
-      memcpy(view, this->compressed_data_, this->data_size());
-      of->write_output_view(this->offset(), this->data_size(), uview);
-    }
-}
-
-// Instantiate the templates we need.
-
-template
-class Output_compressed_string<char>;
-
-template
-class Output_compressed_string<uint16_t>;
-
-template
-class Output_compressed_string<uint32_t>;
-
 } // End namespace gold.
index 589dacc372dcb94e49520bda358ed7db79895ff8..d9bb0c4c46063d874cd23a78858d29071dc90b54 100644 (file)
 #define GOLD_COMPRESSED_OUTPUT_H
 
 #include <string>
-#include <vector>
 
 #include "output.h"
-#include "merge.h"
 
 namespace gold
 {
 
 class General_options;
 
-// This is used for compressing a section before emitting it in the
-// output file.  This only works for unloaded sections, since it
-// assumes the final section contents are available at
-// set_final_data_size() time.  For loaded sections (those that end up
-// in segments), this is not true; relocations are applied after
-// set_final_data_size() is called.  However, for unloaded sections,
-// we can -- and do -- postpone calling finalize_data_size() until
-// after relocations are applies.
+// This is used for a section whose data should be compressed.  It is
+// a regular Output_section which computes its contents into a buffer
+// and then postprocesses it.
 
-class Output_compressed_section_data : public Output_section_data
+class Output_compressed_section : public Output_section
 {
  public:
-  Output_compressed_section_data(uint64_t addralign,
-                                 const General_options& options)
-    : Output_section_data(addralign), options_(options), data_(NULL)
-  { }
+  Output_compressed_section(const General_options* options,
+                           const char* name, elfcpp::Elf_Word flags,
+                           elfcpp::Elf_Xword type)
+    : Output_section(name, flags, type),
+      options_(options)
+  { this->set_requires_postprocessing(); }
 
  protected:
-  // Add an input section.
-  bool
-  do_add_input_section(Relobj* object, unsigned int shndx);
-
   // Set the final data size.
   void
   set_final_data_size();
 
-  // Change the name of the output section to reflect it's compressed.
-  const char*
-  do_modified_output_section_name(const char* name);
-
-  // Write the data to the file.
+  // Write out the compressed contents.
   void
   do_write(Output_file*);
 
  private:
-  struct Object_entry
-  {
-    Relobj* object;
-    unsigned int shndx;
-    const unsigned char* contents;
-    off_t length;
-
-    Object_entry(Relobj* o, unsigned int s)
-      : object(o), shndx(s), contents(NULL), length(0)
-    { }
-  };
-
-  const General_options& options_;
-  std::vector<Object_entry> objects_;
+  // The options--this includes the compression type.
+  const General_options* options_;
+  // The compressed data.
   char* data_;
-  std::string new_section_name_;
-};
-
-// This is a special case for when the output section is a string
-// section and does not have any relocations to apply to it.
-
-template<typename Char_type>
-class Output_compressed_string : public Output_merge_string<Char_type>
-{
- public:
-  Output_compressed_string(uint64_t addralign,
-                           const General_options& options)
-    : Output_merge_string<Char_type>(addralign),
-      options_(options), compressed_data_(NULL)
-  { }
-
-  ~Output_compressed_string()
-  { delete[] compressed_data_; }
-
- protected:
-  // Add an input section.
-  bool
-  do_add_input_section(Relobj* object, unsigned int shndx);
-
-  // Set the final data size.  Also compresses the buffer.
-  void
-  set_final_data_size();
-
-  // Change the name of the output section to reflect it's compressed.
-  const char*
-  do_modified_output_section_name(const char* name);
-
-  // Write the data to the file.
-  void
-  do_write(Output_file*);
-
- private:
-  const General_options& options_;
-  char* compressed_data_;
-  // This is just a buffer to store the section name in "permanent" storage.
+  // The new section name if we do compress.
   std::string new_section_name_;
 };
 
index f7c1e40be3989946d90b48e825b881a7230bd45e..39008cd46fe2cfc42560fa31b8006dc522537eab 100644 (file)
@@ -32,6 +32,7 @@
 #include "symtab.h"
 #include "dynobj.h"
 #include "ehframe.h"
+#include "compressed_output.h"
 #include "layout.h"
 
 namespace gold
@@ -386,6 +387,22 @@ Layout::section_flags_to_segment(elfcpp::Elf_Xword flags)
   return ret;
 }
 
+// Sometimes we compress sections.  This is typically done for
+// sections that are not part of normal program execution (such as
+// .debug_* sections), and where the readers of these sections know
+// how to deal with compressed sections.  (To make it easier for them,
+// we will rename the ouput section in such cases from .foo to
+// .foo.zlib.nnnn, where nnnn is the uncompressed size.)  This routine
+// doesn't say for certain whether we'll compress -- it depends on
+// commandline options as well -- just whether this section is a
+// candidate for compression.
+
+static bool
+is_compressible_debug_section(const char* secname)
+{
+  return (strncmp(secname, ".debug", sizeof(".debug") - 1) == 0);
+}
+
 // Make a new Output_section, and attach it to segments as
 // appropriate.
 
@@ -393,7 +410,14 @@ Output_section*
 Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
                            elfcpp::Elf_Xword flags)
 {
-  Output_section* os = new Output_section(this->options_, name, type, flags);
+  Output_section* os;
+  if ((flags & elfcpp::SHF_ALLOC) == 0
+      && this->options_.compress_debug_sections()
+      && is_compressible_debug_section(name))
+    os = new Output_compressed_section(&this->options_, name, type, flags);
+  else
+    os = new Output_section(name, type, flags);
+
   this->section_list_.push_back(os);
 
   if ((flags & elfcpp::SHF_ALLOC) == 0)
@@ -1069,6 +1093,10 @@ Layout::set_section_offsets(off_t off, Layout::Section_offset_pass pass)
       if (*p == this->symtab_section_)
        continue;
 
+      if (pass == BEFORE_INPUT_SECTIONS_PASS
+         && (*p)->requires_postprocessing())
+       (*p)->create_postprocessing_buffer();
+
       if (pass == BEFORE_INPUT_SECTIONS_PASS
           && (*p)->after_input_sections())
         continue;
@@ -1085,23 +1113,14 @@ Layout::set_section_offsets(off_t off, Layout::Section_offset_pass pass)
       (*p)->set_file_offset(off);
       (*p)->finalize_data_size();
       off += (*p)->data_size();
+
+      // At this point the name must be set.
+      if (pass != STRTAB_AFTER_INPUT_SECTIONS_PASS)
+       this->namepool_.add((*p)->name(), false, NULL);
     }
   return off;
 }
 
-// Allow any section not associated with a segment to change its
-// output section name at the last minute.
-
-void
-Layout::modify_section_names()
-{
-  for (Section_list::iterator p = this->unattached_section_list_.begin();
-       p != this->unattached_section_list_.end();
-       ++p)
-    if ((*p)->maybe_modify_output_section_name())
-      this->namepool_.add((*p)->name(), true, NULL);
-}
-
 // Set the section indexes of all the sections not associated with a
 // segment.
 
@@ -1911,10 +1930,6 @@ Layout::write_sections_after_input_sections(Output_file* of)
   off_t off = this->output_file_size_;
   off = this->set_section_offsets(off, AFTER_INPUT_SECTIONS_PASS);
 
-  // Determine the final section names as well (at least, for sections
-  // that we haven't written yet).
-  this->modify_section_names();
-
   // Now that we've finalized the names, we can finalize the shstrab.
   off = this->set_section_offsets(off, STRTAB_AFTER_INPUT_SECTIONS_PASS);
 
index cff29ed22a5ef4fe26f807e2f3fd465ec98fd4aa..d909acec94baf9125b93775ba599dbb92c30808b 100644 (file)
@@ -356,12 +356,6 @@ class Layout
   off_t
   set_section_offsets(off_t, Section_offset_pass pass);
 
-  // We also allow any section not associated with a segment to change
-  // its output section name at the last minute.  Compressed sections
-  // use this to embed compression info in their name.
-  void
-  modify_section_names();
-
   // Set the final section indexes of all the sections not associated
   // with a segment.  Returns the next unused index.
   unsigned int
index 215bc341c030c5a38500c4b202b7fef79d966b64..98ea89e13400782cdb912b006adc3ea3af991b54 100644 (file)
@@ -445,6 +445,14 @@ Output_merge_data::do_write(Output_file* of)
   of->write(this->offset(), this->p_, this->len_);
 }
 
+// Write the data to a buffer.
+
+void
+Output_merge_data::do_write_to_buffer(unsigned char* buffer)
+{
+  memcpy(buffer, this->p_, this->len_);
+}
+
 // Class Output_merge_string.
 
 // Add an input section to a merged string section.
@@ -535,6 +543,15 @@ Output_merge_string<Char_type>::do_write(Output_file* of)
   this->stringpool_.write(of, this->offset());
 }
 
+// Write a merged string section to a buffer.
+
+template<typename Char_type>
+void
+Output_merge_string<Char_type>::do_write_to_buffer(unsigned char* buffer)
+{
+  this->stringpool_.write_to_buffer(buffer, this->data_size());
+}
+
 // Instantiate the templates we need.
 
 template
index a28ff425cf9d71aa71aac6fc5931773b4a397438..adafb0bc389f5e38a82c5ea7b4c42ea66e3fbe5b 100644 (file)
@@ -120,6 +120,10 @@ class Output_merge_data : public Output_merge_base
   void
   do_write(Output_file*);
 
+  // Write the data to a buffer.
+  void
+  do_write_to_buffer(unsigned char*);
+
  private:
   // We build a hash table of the fixed-size constants.  Each constant
   // is stored as a pointer into the section data we are accumulating.
@@ -227,9 +231,13 @@ class Output_merge_string : public Output_merge_base
   void
   do_write(Output_file*);
 
+  // Write the data to a buffer.
+  void
+  do_write_to_buffer(unsigned char*);
+
   // Writes the stringpool to a buffer.
   void
-  stringpool_to_buffer(char* buffer, size_t buffer_size)
+  stringpool_to_buffer(unsigned char* buffer, size_t buffer_size)
   { this->stringpool_.write_to_buffer(buffer, buffer_size); }
 
   // Clears all the data in the stringpool, to save on memory.
index ecefa8bf393c11aa673aea36a666aa00a5677bd0..fee249fbc552314f6f87ca6830b460b5eb568b34 100644 (file)
@@ -1103,8 +1103,7 @@ Input_objects::add_object(Object* obj)
        }
     }
 
-  set_parameters_size_and_endianness(target->get_size(),
-                                    target->is_big_endian());
+  set_parameters_target(target);
 
   return true;
 }
index 6991d2647007115d0c75b5181c3922365d9b28bc..40839bc7f4185bd10b8670a92e7c1ab6da5127ee 100644 (file)
@@ -960,6 +960,7 @@ class Sized_relobj : public Relobj
     off_t offset;
     off_t view_size;
     bool is_input_output_view;
+    bool is_postprocessing_view;
   };
 
   typedef std::vector<View_size> Views;
index 351c21dee3f5f4509170280eb85965041cebc133..59658c79942e3aba0f8108221d03174712b59836 100644 (file)
@@ -32,7 +32,6 @@
 #include "libiberty.h"   // for unlink_if_ordinary()
 
 #include "parameters.h"
-#include "compressed_output.h"
 #include "object.h"
 #include "symtab.h"
 #include "reloc.h"
@@ -987,13 +986,25 @@ Output_section::Input_section::data_size() const
 // Set the address and file offset.
 
 void
-Output_section::Input_section::set_address(uint64_t addr, off_t off,
-                                          off_t secoff)
+Output_section::Input_section::set_address_and_file_offset(
+    uint64_t address,
+    off_t file_offset,
+    off_t section_file_offset)
 {
   if (this->is_input_section())
-    this->u2_.object->set_section_offset(this->shndx_, off - secoff);
+    this->u2_.object->set_section_offset(this->shndx_,
+                                        file_offset - section_file_offset);
   else
-    this->u2_.posd->set_address_and_file_offset(addr, off);
+    this->u2_.posd->set_address_and_file_offset(address, file_offset);
+}
+
+// Finalize the data size.
+
+void
+Output_section::Input_section::finalize_data_size()
+{
+  if (!this->is_input_section())
+    this->u2_.posd->finalize_data_size();
 }
 
 // Try to turn an input offset into an output offset.
@@ -1030,15 +1041,23 @@ Output_section::Input_section::write(Output_file* of)
     this->u2_.posd->write(of);
 }
 
+// Write the data to a buffer.  As for write(), we don't have to do
+// anything for an input section.
+
+void
+Output_section::Input_section::write_to_buffer(unsigned char* buffer)
+{
+  if (!this->is_input_section())
+    this->u2_.posd->write_to_buffer(buffer);
+}
+
 // Output_section methods.
 
 // Construct an Output_section.  NAME will point into a Stringpool.
 
-Output_section::Output_section(const General_options& options,
-                               const char* name, elfcpp::Elf_Word type,
+Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
                               elfcpp::Elf_Xword flags)
-  : options_(options),
-    name_(name),
+  : name_(name),
     addralign_(0),
     entsize_(0),
     link_section_(NULL),
@@ -1053,6 +1072,7 @@ Output_section::Output_section(const General_options& options,
     input_sections_(),
     first_input_offset_(0),
     fills_(),
+    postprocessing_buffer_(NULL),
     needs_symtab_index_(false),
     needs_dynsym_index_(false),
     should_link_to_symtab_(false),
@@ -1082,22 +1102,6 @@ Output_section::set_entsize(uint64_t v)
     gold_assert(this->entsize_ == v);
 }
 
-// Sometimes we compress sections.  This is typically done for
-// sections that are not part of normal program execution (such as
-// .debug_* sections), and where the readers of these sections know
-// how to deal with compressed sections.  (To make it easier for them,
-// we will rename the ouput section in such cases from .foo to
-// .foo.zlib.nnnn, where nnnn is the uncompressed size.)  This routine
-// doesn't say for certain whether we'll compress -- it depends on
-// commandline options as well -- just whether this section is a
-// candidate for compression.
-
-static bool
-is_compressible_section(const char* secname)
-{
-  return (strncmp(secname, ".debug", sizeof(".debug") - 1) == 0);
-}
-
 // Add the input section SHNDX, with header SHDR, named SECNAME, in
 // OBJECT, to the Output_section.  RELOC_SHNDX is the index of a
 // relocation section which applies to this section, or 0 if none, or
@@ -1145,8 +1149,7 @@ Output_section::add_input_section(Sized_relobj<size, big_endian>* object,
       && reloc_shndx == 0)
     {
       if (this->add_merge_input_section(object, shndx, sh_flags,
-                                       entsize, addralign,
-                                        is_compressible_section(secname)))
+                                       entsize, addralign))
        {
          // Tell the relocation routines that they need to call the
          // output_offset method to determine the final address.
@@ -1233,8 +1236,7 @@ Output_section::add_output_merge_section(Output_section_data* posd,
 bool
 Output_section::add_merge_input_section(Relobj* object, unsigned int shndx,
                                        uint64_t flags, uint64_t entsize,
-                                       uint64_t addralign,
-                                        bool is_compressible_section)
+                                       uint64_t addralign)
 {
   bool is_string = (flags & elfcpp::SHF_STRINGS) != 0;
 
@@ -1258,25 +1260,6 @@ Output_section::add_merge_input_section(Relobj* object, unsigned int shndx,
   Output_section_data* posd;
   if (!is_string)
     posd = new Output_merge_data(entsize, addralign);
-  else if (is_compressible_section && options_.compress_debug_sections())
-    {
-      switch (entsize)
-       {
-        case 1:
-         posd = new Output_compressed_string<char>(addralign, this->options_);
-         break;
-        case 2:
-         posd = new Output_compressed_string<uint16_t>(addralign,
-                                                       this->options_);
-         break;
-        case 4:
-         posd = new Output_compressed_string<uint32_t>(addralign,
-                                                       this->options_);
-         break;
-        default:
-         return false;
-       }
-    }
   else
     {
       switch (entsize)
@@ -1407,36 +1390,14 @@ Output_section::set_final_data_size()
        ++p)
     {
       off = align_address(off, p->addralign());
-      p->set_address(address + (off - startoff), off, startoff);
+      p->set_address_and_file_offset(address + (off - startoff), off,
+                                    startoff);
       off += p->data_size();
     }
 
   this->set_data_size(off - startoff);
 }
 
-// Ask each output_section_data member if it wants to change the name
-// of the output section.  If any of them says yes, use this to set
-// the new name.  This should be called after all processing of this
-// output section is done, but before the name is finally committed to
-// the output-section's header.
-
-bool
-Output_section::maybe_modify_output_section_name()
-{
-  for (Input_section_list::const_iterator it = input_sections_.begin();
-       it != input_sections_.end();
-       ++it)
-    {
-      const char* newname = it->modified_output_section_name(this->name());
-      if (newname != NULL)
-        {
-          this->set_name(newname);
-          return true;
-        }
-    }
-  return false;
-}
-
 // Write the section header to *OSHDR.
 
 template<int size, bool big_endian>
@@ -1474,6 +1435,8 @@ Output_section::write_header(const Layout* layout,
 void
 Output_section::do_write(Output_file* of)
 {
+  gold_assert(!this->requires_postprocessing());
+
   off_t output_section_file_offset = this->offset();
   for (Fill_list::iterator p = this->fills_.begin();
        p != this->fills_.end();
@@ -1490,6 +1453,63 @@ Output_section::do_write(Output_file* of)
     p->write(of);
 }
 
+// If a section requires postprocessing, create the buffer to use.
+
+void
+Output_section::create_postprocessing_buffer()
+{
+  gold_assert(this->requires_postprocessing());
+  gold_assert(this->postprocessing_buffer_ == NULL);
+
+  if (!this->input_sections_.empty())
+    {
+      off_t off = this->first_input_offset_;
+      for (Input_section_list::iterator p = this->input_sections_.begin();
+          p != this->input_sections_.end();
+          ++p)
+       {
+         off = align_address(off, p->addralign());
+         p->finalize_data_size();
+         off += p->data_size();
+       }
+      this->set_current_data_size_for_child(off);
+    }
+
+  off_t buffer_size = this->current_data_size_for_child();
+  this->postprocessing_buffer_ = new unsigned char[buffer_size];
+}
+
+// Write all the data of an Output_section into the postprocessing
+// buffer.  This is used for sections which require postprocessing,
+// such as compression.  Input sections are handled by
+// Object::Relocate.
+
+void
+Output_section::write_to_postprocessing_buffer()
+{
+  gold_assert(this->requires_postprocessing());
+
+  Target* target = parameters->target();
+  unsigned char* buffer = this->postprocessing_buffer();
+  for (Fill_list::iterator p = this->fills_.begin();
+       p != this->fills_.end();
+       ++p)
+    {
+      std::string fill_data(target->code_fill(p->length()));
+      memcpy(buffer + p->section_offset(), fill_data.data(), fill_data.size());
+    }
+
+  off_t off = this->first_input_offset_;
+  for (Input_section_list::iterator p = this->input_sections_.begin();
+       p != this->input_sections_.end();
+       ++p)
+    {
+      off = align_address(off, p->addralign());
+      p->write_to_buffer(buffer + off);
+      off += p->data_size();
+    }
+}
+
 // Output segment methods.
 
 Output_segment::Output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags)
index 95d95f65582b1641320cda3411cd8418e35f124f..fafd62b1faa0ecc11b38f6dd8538b1d28fee7ed9 100644 (file)
@@ -432,15 +432,6 @@ class Output_section_data : public Output_data
   add_input_section(Relobj* object, unsigned int shndx)
   { return this->do_add_input_section(object, shndx); }
 
-  // This class may change the output section name.  This is called
-  // right before shstrtab is written, so after all input-section
-  // layout processing is done.  The input is the old name, and the
-  // output should be a new name (which will be copied into permanent
-  // storage) to change the name, or NULL to keep the name as-is.
-  virtual const char*
-  do_modified_output_section_name(const char*)
-  { return NULL; }
-
   // Given an input OBJECT, an input section index SHNDX within that
   // object, and an OFFSET relative to the start of that input
   // section, return whether or not the corresponding offset within
@@ -452,6 +443,12 @@ class Output_section_data : public Output_data
                off_t *poutput) const
   { return this->do_output_offset(object, shndx, offset, poutput); }
 
+  // Write the contents to a buffer.  This is used for sections which
+  // require postprocessing, such as compression.
+  void
+  write_to_buffer(unsigned char* buffer)
+  { this->do_write_to_buffer(buffer); }
+
  protected:
   // The child class must implement do_write.
 
@@ -472,6 +469,13 @@ class Output_section_data : public Output_data
   do_output_offset(const Relobj*, unsigned int, off_t, off_t*) const
   { return false; }
 
+  // The child class may implement write_to_buffer.  Most child
+  // classes can not appear in a compressed section, and they do not
+  // implement this.
+  virtual void
+  do_write_to_buffer(unsigned char*)
+  { gold_unreachable(); }
+
   // Return the required alignment.
   uint64_t
   do_addralign() const
@@ -545,6 +549,11 @@ class Output_data_const : public Output_section_data
   void
   do_write(Output_file*);
 
+  // Write the data to a buffer.
+  void
+  do_write_to_buffer(unsigned char* buffer)
+  { memcpy(buffer, this->data_.data(), this->data_.size()); }
+
  private:
   std::string data_;
 };
@@ -565,6 +574,11 @@ class Output_data_const_buffer : public Output_section_data
   void
   do_write(Output_file*);
 
+  // Write the data to a buffer.
+  void
+  do_write_to_buffer(unsigned char* buffer)
+  { memcpy(buffer, this->p_, this->data_size()); }
+
  private:
   const unsigned char* p_;
 };
@@ -629,6 +643,11 @@ class Output_data_strtab : public Output_section_data
   void
   do_write(Output_file*);
 
+  // Write the data to a buffer.
+  void
+  do_write_to_buffer(unsigned char* buffer)
+  { this->strtab_->write_to_buffer(buffer, this->data_size()); }
+
  private:
   Stringpool* strtab_;
 };
@@ -1317,8 +1336,7 @@ class Output_section : public Output_data
 {
  public:
   // Create an output section, giving the name, type, and flags.
-  Output_section(const General_options& options,
-                 const char* name, elfcpp::Elf_Word, elfcpp::Elf_Xword);
+  Output_section(const char* name, elfcpp::Elf_Word, elfcpp::Elf_Xword);
   virtual ~Output_section();
 
   // Add a new input section SHNDX, named NAME, with header SHDR, from
@@ -1341,13 +1359,6 @@ class Output_section : public Output_data
   name() const
   { return this->name_; }
 
-  // Modify the section name.  This should be called only after this
-  // section is done being constructed.  The input should be a pointer
-  // into layout's namepool_.
-  void
-  set_name(const char* newname)
-  { this->name_ = newname; }
-
   // Return the section type.
   elfcpp::Elf_Word
   type() const
@@ -1506,11 +1517,23 @@ class Output_section : public Output_data
   requires_postprocessing() const
   { return this->requires_postprocessing_; }
 
-  // Record that this section requires postprocessing after all
-  // relocations have been applied.
+  // If a section requires postprocessing, return the buffer to use.
+  unsigned char*
+  postprocessing_buffer() const
+  {
+    gold_assert(this->postprocessing_buffer_ != NULL);
+    return this->postprocessing_buffer_;
+  }
+
+  // If a section requires postprocessing, create the buffer to use.
   void
-  set_requires_postprocessing()
-  { this->requires_postprocessing_ = true; }
+  create_postprocessing_buffer();
+
+  // If a section requires postprocessing, this is the size of the
+  // buffer to which relocations should be applied.
+  off_t
+  postprocessing_buffer_size() const
+  { return this->current_data_size_for_child(); }
 
   // Return whether the offset OFFSET in the input section SHNDX in
   // object OBJECT is being included in the link.
@@ -1535,16 +1558,6 @@ class Output_section : public Output_data
   write_header(const Layout*, const Stringpool*,
               elfcpp::Shdr_write<size, big_endian>*) const;
 
-  // This class may change the output section name.  This is called
-  // right before shstrtab is written, so after all input-section
-  // layout processing is done.  This calls
-  // do_modified_output_section_name() on all its output_section_data
-  // members, and changes the name if any member so suggests.  If
-  // several members would suggest, this takes the first, arbitrarily.
-  // Return true if the name was modified, false else.
-  bool
-  maybe_modify_output_section_name();
-
  protected:
   // Return the section index in the output file.
   unsigned int
@@ -1566,14 +1579,14 @@ class Output_section : public Output_data
   // Output_section, there is nothing to do, but if there are any
   // Output_section_data objects we need to set their final addresses
   // here.
-  void
+  virtual void
   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
   // on each input object.  But if there are any Output_section_data
   // objects we do need to write them out here.
-  void
+  virtual void
   do_write(Output_file*);
 
   // Return the address alignment--function required by parent class.
@@ -1596,6 +1609,36 @@ class Output_section : public Output_data
   do_is_section_flag_set(elfcpp::Elf_Xword flag) const
   { return (this->flags_ & flag) != 0; }
 
+  // Modify the section name.  This is only permitted for an
+  // unallocated section, and only before the size has been finalized.
+  // Otherwise the name will not get into Layout::namepool_.
+  void
+  set_name(const char* newname)
+  {
+    gold_assert((this->flags_ & elfcpp::SHF_ALLOC) == 0);
+    gold_assert(!this->is_data_size_valid());
+    this->name_ = newname;
+  }
+
+  // This may be implemented by a child class.
+  virtual void
+  do_finalize_name(Layout*)
+  { }
+
+  // Record that this section requires postprocessing after all
+  // relocations have been applied.  This is called by a child class.
+  void
+  set_requires_postprocessing()
+  {
+    this->requires_postprocessing_ = true;
+    this->after_input_sections_ = true;
+  }
+
+  // Write all the data of an Output_section into the postprocessing
+  // buffer.
+  void
+  write_to_postprocessing_buffer();
+
  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
@@ -1685,19 +1728,15 @@ class Output_section : public Output_data
     }
 
     // Set the address and file offset.  This is called during
-    // Layout::finalize.  SECOFF is the file offset of the enclosing
-    // section.
+    // Layout::finalize.  SECTION_FILE_OFFSET is the file offset of
+    // the enclosing section.
     void
-    set_address(uint64_t addr, off_t off, off_t secoff);
+    set_address_and_file_offset(uint64_t address, off_t file_offset,
+                               off_t section_file_offset);
 
-    // Call modified_output_section_name on the output-section-data object.
-    const char*
-    modified_output_section_name(const char* name) const
-    {
-      if (this->is_input_section())
-        return NULL;
-      return this->u2_.posd->do_modified_output_section_name(name);
-    }
+    // Finalize the data size.
+    void
+    finalize_data_size();
 
     // Add an input section, for SHF_MERGE sections.
     bool
@@ -1721,6 +1760,11 @@ class Output_section : public Output_data
     void
     write(Output_file*);
 
+    // Write the data to a buffer.  This does nothing for an input
+    // section.
+    void
+    write_to_buffer(unsigned char*);
+
    private:
     // Code values which appear in shndx_.  If the value is not one of
     // these codes, it is the input section index in the object file.
@@ -1813,8 +1857,7 @@ class Output_section : public Output_data
   // handled.
   bool
   add_merge_input_section(Relobj* object, unsigned int shndx, uint64_t flags,
-                         uint64_t entsize, uint64_t addralign,
-                          bool can_compress_section);
+                         uint64_t entsize, uint64_t addralign);
 
   // Add an output SHF_MERGE section POSD to this output section.
   // IS_STRING indicates whether it is a SHF_STRINGS section, and
@@ -1826,8 +1869,6 @@ class Output_section : public Output_data
 
   // Most of these fields are only valid after layout.
 
-  // General options.
-  const General_options& options_;
   // The name of the section.  This will point into a Stringpool.
   const char* name_;
   // The section address is in the parent class.
@@ -1869,6 +1910,9 @@ class Output_section : public Output_data
   // often will need fill sections without needing to keep track of
   // input sections.
   Fill_list fills_;
+  // If the section requires postprocessing, this buffer holds the
+  // section contents during relocation.
+  unsigned char* postprocessing_buffer_;
   // Whether this output section needs a STT_SECTION symbol in the
   // normal symbol table.  This will be true if there is a relocation
   // which needs it.
index cd05ffee8ddfda4c1a3fc440b32cffdcb30d8645..e6b96825353c4a443bc72f858b760a4af08673f7 100644 (file)
@@ -23,6 +23,7 @@
 #include "gold.h"
 
 #include "options.h"
+#include "target.h"
 #include "parameters.h"
 
 namespace gold
@@ -37,7 +38,7 @@ Parameters::Parameters(Errors* errors)
     symbolic_(false), demangle_(false), detect_odr_violations_(false),
     optimization_level_(0), export_dynamic_(false), debug_(0),
     is_doing_static_link_valid_(false), doing_static_link_(false),
-    is_size_and_endian_valid_(false), size_(0), is_big_endian_(false)
+    is_target_valid_(false), target_(NULL)
 {
 }
 
@@ -85,22 +86,20 @@ Parameters::set_doing_static_link(bool doing_static_link)
   this->is_doing_static_link_valid_ = true;
 }
 
-// Set the size and endianness.
+// Set the target.
 
 void
-Parameters::set_size_and_endianness(int size, bool is_big_endian)
+Parameters::set_target(Target* target)
 {
-  if (!this->is_size_and_endian_valid_)
+  if (!this->is_target_valid_)
     {
-      this->size_ = size;
-      this->is_big_endian_ = is_big_endian;
-      this->is_size_and_endian_valid_ = true;
+      this->target_ = target;
+      this->size_ = target->get_size();
+      this->is_big_endian_ = target->is_big_endian();
+      this->is_target_valid_ = true;
     }
   else
-    {
-      gold_assert(size == this->size_);
-      gold_assert(is_big_endian == this->is_big_endian_);
-    }
+    gold_assert(target == this->target_);
 }
 
 // Our local version of the variable, which is not const.
@@ -135,12 +134,12 @@ set_parameters_doing_static_link(bool doing_static_link)
   static_parameters->set_doing_static_link(doing_static_link);
 }
 
-// Set the size and endianness.
+// Set the target.
 
 void
-set_parameters_size_and_endianness(int size, bool is_big_endian)
+set_parameters_target(Target* target)
 {
-  static_parameters->set_size_and_endianness(size, is_big_endian);
+  static_parameters->set_target(target);
 }
 
 } // End namespace gold.
index 4b764e3214908c795b53e36f07241417f7ff86a9..2467295c857f634dcc4f0f2bf0f067095f7eda6a 100644 (file)
@@ -28,6 +28,7 @@ namespace gold
 
 class General_options;
 class Errors;
+class Target;
 
 // Here we define the Parameters class which simply holds simple
 // general parameters which apply to the entire link.  We use a global
@@ -199,12 +200,20 @@ class Parameters
     return this->doing_static_link_;
   }
 
+  // The target of the output file we are generating.
+  Target*
+  target() const
+  {
+    gold_assert(this->is_target_valid_);
+    return this->target_;
+  }
+
   // The size of the output file we are generating.  This should
   // return 32 or 64.
   int
   get_size() const
   {
-    gold_assert(this->is_size_and_endian_valid_);
+    gold_assert(this->is_target_valid_);
     return this->size_;
   }
 
@@ -212,7 +221,7 @@ class Parameters
   bool
   is_big_endian() const
   {
-    gold_assert(this->is_size_and_endian_valid_);
+    gold_assert(this->is_target_valid_);
     return this->is_big_endian_;
   }
 
@@ -224,9 +233,9 @@ class Parameters
   void
   set_doing_static_link(bool doing_static_link);
 
-  // Set the size and endianness.
+  // Set the target.
   void
-  set_size_and_endianness(int size, bool is_big_endian);
+  set_target(Target* target);
 
  private:
   // The types of output files.
@@ -291,8 +300,10 @@ class Parameters
   bool is_doing_static_link_valid_;
   // Whether we are doing a static link.
   bool doing_static_link_;
-  // Whether the size_ and is_big_endian_ fields are valid.
-  bool is_size_and_endian_valid_;
+  // Whether the target_ field is valid.
+  bool is_target_valid_;
+  // The target.
+  Target* target_;
   // The size of the output file--32 or 64.
   int size_;
   // Whether the output file is big endian.
@@ -308,8 +319,8 @@ extern void initialize_parameters(Errors*);
 // Set the options.
 extern void set_parameters_from_options(const General_options*);
 
-// Set the size and endianness of the global parameters variable.
-extern void set_parameters_size_and_endianness(int size, bool is_big_endian);
+// Set the target recorded in the global parameters variable.
+extern void set_parameters_target(Target* target);
 
 // Set whether we are doing a static link.
 extern void set_parameters_doing_static_link(bool doing_static_link);
index d50674f6d77159349b2f6c23038d80cd137802f8..2763be5ba4b64eca4e811318bce653f4aef66a6a 100644 (file)
@@ -376,12 +376,16 @@ Sized_relobj<size, big_endian>::do_relocate(const General_options& options,
     {
       if (views[i].view != NULL)
        {
-         if (views[i].is_input_output_view)
-           of->write_input_output_view(views[i].offset, views[i].view_size,
-                                       views[i].view);
-         else
-           of->write_output_view(views[i].offset, views[i].view_size,
-                                 views[i].view);
+         if (!views[i].is_postprocessing_view)
+           {
+             if (views[i].is_input_output_view)
+               of->write_input_output_view(views[i].offset,
+                                           views[i].view_size,
+                                           views[i].view);
+             else
+               of->write_output_view(views[i].offset, views[i].view_size,
+                                     views[i].view);
+           }
        }
     }
 
@@ -419,17 +423,50 @@ Sized_relobj<size, big_endian>::write_sections(const unsigned char* pshdrs,
       if (shdr.get_sh_type() == elfcpp::SHT_NOBITS)
        continue;
 
+      // In the normal case, this input section is simply mapped to
+      // the output section at offset OUTPUT_OFFSET.
+
+      // However, if OUTPUT_OFFSET == -1, then input data is handled
+      // specially--e.g., a .eh_frame section.  The relocation
+      // routines need to check for each reloc where it should be
+      // applied.  For this case, we need an input/output view for the
+      // entire contents of the section in the output file.  We don't
+      // want to copy the contents of the input section to the output
+      // section; the output section contents were already written,
+      // and we waited for them in Relocate_task::is_runnable because
+      // relocs_must_follow_section_writes is set for the object.
+
+      // Regardless of which of the above cases is true, we have to
+      // check requires_postprocessing of the output section.  If that
+      // is false, then we work with views of the output file
+      // directly.  If it is true, then we work with a separate
+      // buffer, and the output section is responsible for writing the
+      // final data to the output file.
+
+      off_t output_section_offset;
+      off_t output_section_size;
+      if (!os->requires_postprocessing())
+       {
+         output_section_offset = os->offset();
+         output_section_size = os->data_size();
+       }
+      else
+       {
+         output_section_offset = 0;
+         output_section_size = os->postprocessing_buffer_size();
+       }
+
       off_t view_start;
       off_t view_size;
       if (output_offset != -1)
        {
-         view_start = os->offset() + output_offset;
+         view_start = output_section_offset + output_offset;
          view_size = shdr.get_sh_size();
        }
       else
        {
-         view_start = os->offset();
-         view_size = os->data_size();
+         view_start = output_section_offset;
+         view_size = output_section_size;
        }
 
       if (view_size == 0)
@@ -437,15 +474,25 @@ Sized_relobj<size, big_endian>::write_sections(const unsigned char* pshdrs,
 
       gold_assert(output_offset == -1
                  || (output_offset >= 0
-                     && output_offset + view_size <= os->data_size()));
+                     && output_offset + view_size <= output_section_size));
 
       unsigned char* view;
-      if (output_offset == -1)
-       view = of->get_input_output_view(view_start, view_size);
+      if (os->requires_postprocessing())
+       {
+         unsigned char* buffer = os->postprocessing_buffer();
+         view = buffer + view_start;
+         if (output_offset != -1)
+           this->read(shdr.get_sh_offset(), view_size, view);
+       }
       else
        {
-         view = of->get_output_view(view_start, view_size);
-         this->read(shdr.get_sh_offset(), view_size, view);
+         if (output_offset == -1)
+           view = of->get_input_output_view(view_start, view_size);
+         else
+           {
+             view = of->get_output_view(view_start, view_size);
+             this->read(shdr.get_sh_offset(), view_size, view);
+           }
        }
 
       pvs->view = view;
@@ -455,6 +502,7 @@ Sized_relobj<size, big_endian>::write_sections(const unsigned char* pshdrs,
       pvs->offset = view_start;
       pvs->view_size = view_size;
       pvs->is_input_output_view = output_offset == -1;
+      pvs->is_postprocessing_view = os->requires_postprocessing();
     }
 }
 
@@ -543,6 +591,9 @@ Sized_relobj<size, big_endian>::relocate_sections(
          continue;
        }
 
+      gold_assert(output_offset != -1
+                 || this->relocs_must_follow_section_writes());
+
       relinfo.reloc_shndx = i;
       relinfo.data_shndx = index;
       target->relocate_section(&relinfo,
index 42a2fdabfdb96515daee2031987a5f025e392959..6d3ecfa0e175962b0e25e0bef2e9b5bb39538513 100644 (file)
@@ -426,7 +426,7 @@ Stringpool_template<Stringpool_char>::get_offset(const Stringpool_char* s)
 
 template<typename Stringpool_char>
 void
-Stringpool_template<Stringpool_char>::write_to_buffer(char* buffer,
+Stringpool_template<Stringpool_char>::write_to_buffer(unsigned char* buffer,
                                                       size_t bufsize)
 {
   gold_assert(this->strtab_size_ != 0);
@@ -452,7 +452,7 @@ Stringpool_template<Stringpool_char>::write(Output_file* of, off_t offset)
 {
   gold_assert(this->strtab_size_ != 0);
   unsigned char* view = of->get_output_view(offset, this->strtab_size_);
-  this->write_to_buffer(reinterpret_cast<char*>(view), this->strtab_size_);
+  this->write_to_buffer(view, this->strtab_size_);
   of->write_output_view(offset, this->strtab_size_, view);
 }
 
index 57725a5c5990654aabbf7b952fe2218f51009670..e902b8e4aae5757c77668e59db16f3c70fe71bb3 100644 (file)
@@ -147,7 +147,7 @@ class Stringpool_template
   // specified size.  buffer_size should be at least
   // get_strtab_size().
   void
-  write_to_buffer(char* buffer, size_t buffer_size);
+  write_to_buffer(unsigned char* buffer, size_t buffer_size);
 
  private:
   Stringpool_template(const Stringpool_template&);