Refactor Output_data_reloc_base::do_write for MIPS-specific relocs.
authorCary Coutant <ccoutant@gmail.com>
Tue, 8 Mar 2016 20:24:39 +0000 (12:24 -0800)
committerCary Coutant <ccoutant@gmail.com>
Tue, 8 Mar 2016 23:06:59 +0000 (15:06 -0800)
This patch is a simple refactoring that will allow the MIPS backend to
replace the Output_data_reloc_base::do_write() method without copying
its entire implementation. I've moved the implementation of do_write()
into a function template, which can be instantiated with a custom
class to write the MIPS-specific relocation format. The custom class
for MIPS needs access to the symbol index and address from
Output_reloc, so I've included the part of Vlad's MIPS-64 patch that
makes those accessor methods public.

2016-03-08  Cary Coutant  <ccoutant@gmail.com>
            Vladimir Radosavljevic  <vladimir.radosavljevic@imgtec.com>

gold/
* output.cc (Output_reloc_writer): New type.
(Output_data_reloc_base::do_write): Move implementation to template
in output.h and replace with invocation of template.
* output.h (Output_file): Move to top of file.
(Output_reloc::get_symbol_index): Move to public interface.
(Output_reloc::get_address): Likewise.
(Output_data_reloc_base::do_write_generic): New function template.

gold/ChangeLog
gold/output.cc
gold/output.h

index 34192907bb9feba8503227b66265fcf61219651f..d3ec5de111e39fa84d5e3f3100fe4320e4f6face 100644 (file)
@@ -1,3 +1,14 @@
+2016-03-08  Cary Coutant  <ccoutant@gmail.com>
+            Vladimir Radosavljevic  <vladimir.radosavljevic@imgtec.com>
+
+       * output.cc (Output_reloc_writer): New type.
+       (Output_data_reloc_base::do_write): Move implementation to template
+       in output.h and replace with invocation of template.
+       * output.h (Output_file): Move to top of file.
+       (Output_reloc::get_symbol_index): Move to public interface.
+       (Output_reloc::get_address): Likewise.
+       (Output_data_reloc_base::do_write_generic): New function template.
+
 2016-03-04  Cary Coutant  <ccoutant@gmail.com>
 
        PR gold/19019
index f9d4f23c119620ee889e8151e9fa04a39c937ad7..077e2c4481ecb8445028c773eba51506846e957e 100644 (file)
@@ -1252,6 +1252,19 @@ Output_data_reloc_base<sh_type, dynamic, size, big_endian>
     os->set_should_link_to_dynsym();
 }
 
+// Standard relocation writer, which just calls Output_reloc::write().
+
+template<int sh_type, bool dynamic, int size, bool big_endian>
+struct Output_reloc_writer
+{
+  typedef Output_reloc<sh_type, dynamic, size, big_endian> Output_reloc_type;
+  typedef std::vector<Output_reloc_type> Relocs;
+
+  static void
+  write(typename Relocs::const_iterator p, unsigned char* pov)
+  { p->write(pov); }
+};
+
 // Write out relocation data.
 
 template<int sh_type, bool dynamic, int size, bool big_endian>
@@ -1259,32 +1272,8 @@ void
 Output_data_reloc_base<sh_type, dynamic, size, big_endian>::do_write(
     Output_file* of)
 {
-  const off_t off = this->offset();
-  const off_t oview_size = this->data_size();
-  unsigned char* const oview = of->get_output_view(off, oview_size);
-
-  if (this->sort_relocs())
-    {
-      gold_assert(dynamic);
-      std::sort(this->relocs_.begin(), this->relocs_.end(),
-               Sort_relocs_comparison());
-    }
-
-  unsigned char* pov = oview;
-  for (typename Relocs::const_iterator p = this->relocs_.begin();
-       p != this->relocs_.end();
-       ++p)
-    {
-      p->write(pov);
-      pov += reloc_size;
-    }
-
-  gold_assert(pov - oview == oview_size);
-
-  of->write_output_view(off, oview_size, oview);
-
-  // We no longer need the relocation entries.
-  this->relocs_.clear();
+  typedef Output_reloc_writer<sh_type, dynamic, size, big_endian> Writer;
+  this->do_write_generic<Writer>(of);
 }
 
 // Class Output_relocatable_relocs.
index 9d05b6711f13913e35739cab735fcd8ed769c9d5..0b96a03dddb8b6defc7ece19d918d04b294a83c1 100644 (file)
@@ -23,6 +23,7 @@
 #ifndef GOLD_OUTPUT_H
 #define GOLD_OUTPUT_H
 
+#include <algorithm>
 #include <list>
 #include <vector>
 
@@ -37,7 +38,6 @@ namespace gold
 class General_options;
 class Object;
 class Symbol;
-class Output_file;
 class Output_merge_base;
 class Output_section;
 class Relocatable_relocs;
@@ -49,6 +49,131 @@ class Sized_relobj;
 template<int size, bool big_endian>
 class Sized_relobj_file;
 
+// This class represents the output file.
+
+class Output_file
+{
+ public:
+  Output_file(const char* name);
+
+  // Indicate that this is a temporary file which should not be
+  // output.
+  void
+  set_is_temporary()
+  { this->is_temporary_ = true; }
+
+  // Try to open an existing file. Returns false if the file doesn't
+  // exist, has a size of 0 or can't be mmaped.  This method is
+  // thread-unsafe.  If BASE_NAME is not NULL, use the contents of
+  // that file as the base for incremental linking.
+  bool
+  open_base_file(const char* base_name, bool writable);
+
+  // Open the output file.  FILE_SIZE is the final size of the file.
+  // If the file already exists, it is deleted/truncated.  This method
+  // is thread-unsafe.
+  void
+  open(off_t file_size);
+
+  // Resize the output file.  This method is thread-unsafe.
+  void
+  resize(off_t file_size);
+
+  // Close the output file (flushing all buffered data) and make sure
+  // there are no errors.  This method is thread-unsafe.
+  void
+  close();
+
+  // Return the size of this file.
+  off_t
+  filesize()
+  { return this->file_size_; }
+
+  // Return the name of this file.
+  const char*
+  filename()
+  { return this->name_; }
+
+  // We currently always use mmap which makes the view handling quite
+  // simple.  In the future we may support other approaches.
+
+  // Write data to the output file.
+  void
+  write(off_t offset, const void* data, size_t len)
+  { memcpy(this->base_ + offset, data, len); }
+
+  // Get a buffer to use to write to the file, given the offset into
+  // the file and the size.
+  unsigned char*
+  get_output_view(off_t start, size_t size)
+  {
+    gold_assert(start >= 0
+               && start + static_cast<off_t>(size) <= this->file_size_);
+    return this->base_ + start;
+  }
+
+  // VIEW must have been returned by get_output_view.  Write the
+  // buffer to the file, passing in the offset and the size.
+  void
+  write_output_view(off_t, size_t, unsigned char*)
+  { }
+
+  // Get a read/write buffer.  This is used when we want to write part
+  // of the file, read it in, and write it again.
+  unsigned char*
+  get_input_output_view(off_t start, size_t size)
+  { return this->get_output_view(start, size); }
+
+  // Write a read/write buffer back to the file.
+  void
+  write_input_output_view(off_t, size_t, unsigned char*)
+  { }
+
+  // Get a read buffer.  This is used when we just want to read part
+  // of the file back it in.
+  const unsigned char*
+  get_input_view(off_t start, size_t size)
+  { return this->get_output_view(start, size); }
+
+  // Release a read bfufer.
+  void
+  free_input_view(off_t, size_t, const unsigned char*)
+  { }
+
+ private:
+  // Map the file into memory or, if that fails, allocate anonymous
+  // memory.
+  void
+  map();
+
+  // Allocate anonymous memory for the file.
+  bool
+  map_anonymous();
+
+  // Map the file into memory.
+  bool
+  map_no_anonymous(bool);
+
+  // Unmap the file from memory (and flush to disk buffers).
+  void
+  unmap();
+
+  // File name.
+  const char* name_;
+  // File descriptor.
+  int o_;
+  // File size.
+  off_t file_size_;
+  // Base of file mapped into memory.
+  unsigned char* base_;
+  // True iff base_ points to a memory buffer rather than an output file.
+  bool map_is_anonymous_;
+  // True if base_ was allocated using new rather than mmap.
+  bool map_is_allocated_;
+  // True if this is a temporary file which should not be output.
+  bool is_temporary_;
+};
+
 // An abtract class for data which has to go into the output file.
 
 class Output_data
@@ -1150,11 +1275,6 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
              r2) const
   { return this->compare(r2) < 0; }
 
- private:
-  // Record that we need a dynamic symbol index.
-  void
-  set_needs_dynsym_index();
-
   // Return the symbol index.
   unsigned int
   get_symbol_index() const;
@@ -1163,6 +1283,11 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   Address
   get_address() const;
 
+ private:
+  // Record that we need a dynamic symbol index.
+  void
+  set_needs_dynsym_index();
+
   // Codes for local_sym_index_.
   enum
   {
@@ -1487,6 +1612,40 @@ class Output_data_reloc_base : public Output_data_reloc_generic
   void
   do_write(Output_file*);
 
+  // Generic implementation of do_write, allowing a customized
+  // class for writing the output relocation (e.g., for MIPS-64).
+  template<class Output_reloc_writer>
+  void
+  do_write_generic(Output_file* of)
+  {
+    const off_t off = this->offset();
+    const off_t oview_size = this->data_size();
+    unsigned char* const oview = of->get_output_view(off, oview_size);
+
+    if (this->sort_relocs())
+      {
+       gold_assert(dynamic);
+       std::sort(this->relocs_.begin(), this->relocs_.end(),
+                 Sort_relocs_comparison());
+      }
+
+    unsigned char* pov = oview;
+    for (typename Relocs::const_iterator p = this->relocs_.begin();
+        p != this->relocs_.end();
+        ++p)
+      {
+       Output_reloc_writer::write(p, pov);
+       pov += reloc_size;
+      }
+
+    gold_assert(pov - oview == oview_size);
+
+    of->write_output_view(off, oview_size, oview);
+
+    // We no longer need the relocation entries.
+    this->relocs_.clear();
+  }
+
   // Set the entry size and the link.
   void
   do_adjust_output_section(Output_section* os);
@@ -4756,131 +4915,6 @@ class Output_segment
   bool is_unique_segment_ : 1;
 };
 
-// This class represents the output file.
-
-class Output_file
-{
- public:
-  Output_file(const char* name);
-
-  // Indicate that this is a temporary file which should not be
-  // output.
-  void
-  set_is_temporary()
-  { this->is_temporary_ = true; }
-
-  // Try to open an existing file. Returns false if the file doesn't
-  // exist, has a size of 0 or can't be mmaped.  This method is
-  // thread-unsafe.  If BASE_NAME is not NULL, use the contents of
-  // that file as the base for incremental linking.
-  bool
-  open_base_file(const char* base_name, bool writable);
-
-  // Open the output file.  FILE_SIZE is the final size of the file.
-  // If the file already exists, it is deleted/truncated.  This method
-  // is thread-unsafe.
-  void
-  open(off_t file_size);
-
-  // Resize the output file.  This method is thread-unsafe.
-  void
-  resize(off_t file_size);
-
-  // Close the output file (flushing all buffered data) and make sure
-  // there are no errors.  This method is thread-unsafe.
-  void
-  close();
-
-  // Return the size of this file.
-  off_t
-  filesize()
-  { return this->file_size_; }
-
-  // Return the name of this file.
-  const char*
-  filename()
-  { return this->name_; }
-
-  // We currently always use mmap which makes the view handling quite
-  // simple.  In the future we may support other approaches.
-
-  // Write data to the output file.
-  void
-  write(off_t offset, const void* data, size_t len)
-  { memcpy(this->base_ + offset, data, len); }
-
-  // Get a buffer to use to write to the file, given the offset into
-  // the file and the size.
-  unsigned char*
-  get_output_view(off_t start, size_t size)
-  {
-    gold_assert(start >= 0
-               && start + static_cast<off_t>(size) <= this->file_size_);
-    return this->base_ + start;
-  }
-
-  // VIEW must have been returned by get_output_view.  Write the
-  // buffer to the file, passing in the offset and the size.
-  void
-  write_output_view(off_t, size_t, unsigned char*)
-  { }
-
-  // Get a read/write buffer.  This is used when we want to write part
-  // of the file, read it in, and write it again.
-  unsigned char*
-  get_input_output_view(off_t start, size_t size)
-  { return this->get_output_view(start, size); }
-
-  // Write a read/write buffer back to the file.
-  void
-  write_input_output_view(off_t, size_t, unsigned char*)
-  { }
-
-  // Get a read buffer.  This is used when we just want to read part
-  // of the file back it in.
-  const unsigned char*
-  get_input_view(off_t start, size_t size)
-  { return this->get_output_view(start, size); }
-
-  // Release a read bfufer.
-  void
-  free_input_view(off_t, size_t, const unsigned char*)
-  { }
-
- private:
-  // Map the file into memory or, if that fails, allocate anonymous
-  // memory.
-  void
-  map();
-
-  // Allocate anonymous memory for the file.
-  bool
-  map_anonymous();
-
-  // Map the file into memory.
-  bool
-  map_no_anonymous(bool);
-
-  // Unmap the file from memory (and flush to disk buffers).
-  void
-  unmap();
-
-  // File name.
-  const char* name_;
-  // File descriptor.
-  int o_;
-  // File size.
-  off_t file_size_;
-  // Base of file mapped into memory.
-  unsigned char* base_;
-  // True iff base_ points to a memory buffer rather than an output file.
-  bool map_is_anonymous_;
-  // True if base_ was allocated using new rather than mmap.
-  bool map_is_allocated_;
-  // True if this is a temporary file which should not be output.
-  bool is_temporary_;
-};
-
 } // End namespace gold.
 
 #endif // !defined(GOLD_OUTPUT_H)