From c32482d65c43f40572a0722b48c20b3f571666a3 Mon Sep 17 00:00:00 2001 From: Cary Coutant Date: Tue, 8 Mar 2016 12:24:39 -0800 Subject: [PATCH] Refactor Output_data_reloc_base::do_write for MIPS-specific relocs. 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 Vladimir Radosavljevic 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 | 11 +++ gold/output.cc | 41 +++----- gold/output.h | 296 ++++++++++++++++++++++++++++++++------------------------- 3 files changed, 191 insertions(+), 157 deletions(-) diff --git a/gold/ChangeLog b/gold/ChangeLog index 3419290..d3ec5de 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,14 @@ +2016-03-08 Cary Coutant + Vladimir Radosavljevic + + * 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 PR gold/19019 diff --git a/gold/output.cc b/gold/output.cc index f9d4f23..077e2c4 100644 --- a/gold/output.cc +++ b/gold/output.cc @@ -1252,6 +1252,19 @@ Output_data_reloc_base os->set_should_link_to_dynsym(); } +// Standard relocation writer, which just calls Output_reloc::write(). + +template +struct Output_reloc_writer +{ + typedef Output_reloc Output_reloc_type; + typedef std::vector Relocs; + + static void + write(typename Relocs::const_iterator p, unsigned char* pov) + { p->write(pov); } +}; + // Write out relocation data. template @@ -1259,32 +1272,8 @@ void Output_data_reloc_base::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 Writer; + this->do_write_generic(of); } // Class Output_relocatable_relocs. diff --git a/gold/output.h b/gold/output.h index 9d05b67..0b96a03 100644 --- a/gold/output.h +++ b/gold/output.h @@ -23,6 +23,7 @@ #ifndef GOLD_OUTPUT_H #define GOLD_OUTPUT_H +#include #include #include @@ -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 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(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 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 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 + 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(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) -- 2.7.4