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 <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.
This commit is contained in:
parent
d1ed1c7d69
commit
c32482d65c
3 changed files with 191 additions and 157 deletions
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
296
gold/output.h
296
gold/output.h
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue