mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-21 10:34:21 +08:00
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:
@ -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>
|
2016-03-04 Cary Coutant <ccoutant@gmail.com>
|
||||||
|
|
||||||
PR gold/19019
|
PR gold/19019
|
||||||
|
@ -1252,6 +1252,19 @@ Output_data_reloc_base<sh_type, dynamic, size, big_endian>
|
|||||||
os->set_should_link_to_dynsym();
|
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.
|
// Write out relocation data.
|
||||||
|
|
||||||
template<int sh_type, bool dynamic, int size, bool big_endian>
|
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_data_reloc_base<sh_type, dynamic, size, big_endian>::do_write(
|
||||||
Output_file* of)
|
Output_file* of)
|
||||||
{
|
{
|
||||||
const off_t off = this->offset();
|
typedef Output_reloc_writer<sh_type, dynamic, size, big_endian> Writer;
|
||||||
const off_t oview_size = this->data_size();
|
this->do_write_generic<Writer>(of);
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Class Output_relocatable_relocs.
|
// Class Output_relocatable_relocs.
|
||||||
|
296
gold/output.h
296
gold/output.h
@ -23,6 +23,7 @@
|
|||||||
#ifndef GOLD_OUTPUT_H
|
#ifndef GOLD_OUTPUT_H
|
||||||
#define GOLD_OUTPUT_H
|
#define GOLD_OUTPUT_H
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -37,7 +38,6 @@ namespace gold
|
|||||||
class General_options;
|
class General_options;
|
||||||
class Object;
|
class Object;
|
||||||
class Symbol;
|
class Symbol;
|
||||||
class Output_file;
|
|
||||||
class Output_merge_base;
|
class Output_merge_base;
|
||||||
class Output_section;
|
class Output_section;
|
||||||
class Relocatable_relocs;
|
class Relocatable_relocs;
|
||||||
@ -49,6 +49,131 @@ class Sized_relobj;
|
|||||||
template<int size, bool big_endian>
|
template<int size, bool big_endian>
|
||||||
class Sized_relobj_file;
|
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.
|
// An abtract class for data which has to go into the output file.
|
||||||
|
|
||||||
class Output_data
|
class Output_data
|
||||||
@ -1150,11 +1275,6 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
|
|||||||
r2) const
|
r2) const
|
||||||
{ return this->compare(r2) < 0; }
|
{ return this->compare(r2) < 0; }
|
||||||
|
|
||||||
private:
|
|
||||||
// Record that we need a dynamic symbol index.
|
|
||||||
void
|
|
||||||
set_needs_dynsym_index();
|
|
||||||
|
|
||||||
// Return the symbol index.
|
// Return the symbol index.
|
||||||
unsigned int
|
unsigned int
|
||||||
get_symbol_index() const;
|
get_symbol_index() const;
|
||||||
@ -1163,6 +1283,11 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
|
|||||||
Address
|
Address
|
||||||
get_address() const;
|
get_address() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Record that we need a dynamic symbol index.
|
||||||
|
void
|
||||||
|
set_needs_dynsym_index();
|
||||||
|
|
||||||
// Codes for local_sym_index_.
|
// Codes for local_sym_index_.
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
@ -1487,6 +1612,40 @@ class Output_data_reloc_base : public Output_data_reloc_generic
|
|||||||
void
|
void
|
||||||
do_write(Output_file*);
|
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.
|
// Set the entry size and the link.
|
||||||
void
|
void
|
||||||
do_adjust_output_section(Output_section* os);
|
do_adjust_output_section(Output_section* os);
|
||||||
@ -4756,131 +4915,6 @@ class Output_segment
|
|||||||
bool is_unique_segment_ : 1;
|
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.
|
} // End namespace gold.
|
||||||
|
|
||||||
#endif // !defined(GOLD_OUTPUT_H)
|
#endif // !defined(GOLD_OUTPUT_H)
|
||||||
|
Reference in New Issue
Block a user