Generate a complete exception frame header. Discard duplicate

exception frame information.
This commit is contained in:
Ian Lance Taylor 2007-11-09 07:00:15 +00:00
parent 0abe36f50d
commit 730cdc88f7
24 changed files with 2831 additions and 368 deletions

View File

@ -288,6 +288,7 @@ Sized_dynobj<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
sd->symbols = NULL;
sd->symbols_size = 0;
sd->external_symbols_offset = 0;
sd->symbol_names = NULL;
sd->symbol_names_size = 0;
@ -606,6 +607,7 @@ Sized_dynobj<size, big_endian>::do_add_symbols(Symbol_table* symtab,
const int sym_size = This::sym_size;
const size_t symcount = sd->symbols_size / sym_size;
gold_assert(sd->external_symbols_offset == 0);
if (static_cast<off_t>(symcount * sym_size) != sd->symbols_size)
{
this->error(_("size of dynamic symbols is not multiple of symbol size"));

View File

@ -146,6 +146,11 @@ class Sized_dynobj : public Dynobj
do_section_flags(unsigned int shndx)
{ return this->elf_file_.section_flags(shndx); }
// Return section type.
unsigned int
do_section_type(unsigned int shndx)
{ return this->elf_file_.section_type(shndx); }
// Return the section link field.
unsigned int
do_section_link(unsigned int shndx)

File diff suppressed because it is too large Load Diff

View File

@ -24,10 +24,16 @@
#define GOLD_EHFRAME_H
#include "output.h"
#include "merge.h"
namespace gold
{
template<int size, bool big_endian>
class Track_relocs;
class Eh_frame;
// This class manages the .eh_frame_hdr section, which holds the data
// for the PT_GNU_EH_FRAME segment. gcc's unwind support code uses
// the PT_GNU_EH_FRAME segment to find the list of FDEs. This saves
@ -42,7 +48,20 @@ namespace gold
class Eh_frame_hdr : public Output_section_data
{
public:
Eh_frame_hdr(Output_section* eh_frame_section);
Eh_frame_hdr(Output_section* eh_frame_section, const Eh_frame*);
// Record that we found an unrecognized .eh_frame section.
void
found_unrecognized_eh_frame_section()
{ this->any_unrecognized_eh_frame_sections_ = true; }
// Record an FDE.
void
record_fde(off_t fde_offset, unsigned char fde_encoding)
{
if (!this->any_unrecognized_eh_frame_sections_)
this->fde_offsets_.push_back(std::make_pair(fde_offset, fde_encoding));
}
// Set the final data size.
void
@ -53,8 +72,346 @@ class Eh_frame_hdr : public Output_section_data
do_write(Output_file*);
private:
// Write the data to the file with the right endianness.
template<int size, bool big_endian>
void
do_sized_write(Output_file*);
// The data we record for one FDE: the offset of the FDE within the
// .eh_frame section, and the FDE encoding.
typedef std::pair<off_t, unsigned char> Fde_offset;
// The list of information we record for an FDE.
typedef std::vector<Fde_offset> Fde_offsets;
// When writing out the header, we convert the FDE offsets into FDE
// addresses. This is a list of pairs of the offset from the header
// to the FDE PC and to the FDE itself.
template<int size>
class Fde_addresses
{
public:
typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
typedef typename std::pair<Address, Address> Fde_address;
typedef typename std::vector<Fde_address> Fde_address_list;
typedef typename Fde_address_list::iterator iterator;
Fde_addresses(unsigned int reserve)
: fde_addresses_()
{ this->fde_addresses_.reserve(reserve); }
void
push_back(Address pc_address, Address fde_address)
{
this->fde_addresses_.push_back(std::make_pair(pc_address, fde_address));
}
iterator
begin()
{ return this->fde_addresses_.begin(); }
iterator
end()
{ return this->fde_addresses_.end(); }
private:
Fde_address_list fde_addresses_;
};
// Compare Fde_address objects.
template<int size>
struct Fde_address_compare
{
bool
operator()(const typename Fde_addresses<size>::Fde_address& f1,
const typename Fde_addresses<size>::Fde_address& f2) const
{ return f1.first < f2.first; }
};
// Return the PC to which an FDE refers.
template<int size, bool big_endian>
typename elfcpp::Elf_types<size>::Elf_Addr
get_fde_pc(const unsigned char* eh_frame_contents,
off_t fde_offset, unsigned char fde_encoding);
// Convert Fde_offsets to Fde_addresses.
template<int size, bool big_endian>
void
get_fde_addresses(Output_file* of,
const Fde_offsets* fde_offsets,
Fde_addresses<size>* fde_addresses);
// The .eh_frame section.
Output_section* eh_frame_section_;
// The .eh_frame section data.
const Eh_frame* eh_frame_data_;
// Data from the FDEs in the .eh_frame sections.
Fde_offsets fde_offsets_;
// Whether we found any .eh_frame sections which we could not
// process.
bool any_unrecognized_eh_frame_sections_;
};
// This class holds an FDE.
class Fde
{
public:
Fde(Relobj* object, unsigned int shndx, off_t input_offset,
const unsigned char* contents, size_t length)
: object_(object), shndx_(shndx), input_offset_(input_offset),
contents_(reinterpret_cast<const char*>(contents), length)
{ }
// Return the length of this FDE. Add 4 for the length and 4 for
// the offset to the CIE.
size_t
length() const
{ return this->contents_.length() + 8; }
// Add a mapping for this FDE to MERGE_MAP.
void
add_mapping(off_t output_offset, Merge_map* merge_map) const
{
merge_map->add_mapping(this->object_, this->shndx_,
this->input_offset_, this->length(),
output_offset);
}
// Write the FDE to OVIEW starting at OFFSET. FDE_ENCODING is the
// encoding, from the CIE. Record the FDE in EH_FRAME_HDR. Return
// the new offset.
template<int size, bool big_endian>
off_t
write(unsigned char* oview, off_t offset, off_t cie_offset,
unsigned char fde_encoding, Eh_frame_hdr* eh_frame_hdr);
private:
// The object in which this FDE was seen.
Relobj* object_;
// Input section index for this FDE.
unsigned int shndx_;
// Offset within the input section for this FDE.
off_t input_offset_;
// FDE data.
std::string contents_;
};
// This class holds a CIE.
class Cie
{
public:
Cie(Relobj* object, unsigned int shndx, off_t input_offset,
unsigned char fde_encoding, const char* personality_name,
const unsigned char* contents, size_t length)
: object_(object),
shndx_(shndx),
input_offset_(input_offset),
fde_encoding_(fde_encoding),
personality_name_(personality_name),
fdes_(),
contents_(reinterpret_cast<const char*>(contents), length)
{ }
~Cie();
// We permit copying a CIE when there are no FDEs. This is
// convenient in the code which creates them.
Cie(const Cie& cie)
: object_(cie.object_),
shndx_(cie.shndx_),
input_offset_(cie.input_offset_),
fde_encoding_(cie.fde_encoding_),
personality_name_(cie.personality_name_),
fdes_(),
contents_(cie.contents_)
{ gold_assert(cie.fdes_.empty()); }
// Add an FDE associated with this CIE.
void
add_fde(Fde* fde)
{ this->fdes_.push_back(fde); }
// Return the number of FDEs.
unsigned int
fde_count() const
{ return this->fdes_.size(); }
// Set the output offset of this CIE to OUTPUT_OFFSET. It will be
// followed by all its FDEs. ADDRALIGN is the required address
// alignment, typically 4 or 8. This updates MERGE_MAP with the
// mapping. It returns the new output offset.
off_t
set_output_offset(off_t output_offset, unsigned int addralign, Merge_map*);
// Write the CIE to OVIEW starting at OFFSET. EH_FRAME_HDR is the
// exception frame header for FDE recording. Return the new offset.
template<int size, bool big_endian>
off_t
write(unsigned char* oview, off_t offset, Eh_frame_hdr* eh_frame_hdr);
friend bool operator<(const Cie&, const Cie&);
friend bool operator==(const Cie&, const Cie&);
private:
// The class is not assignable.
Cie& operator=(const Cie&);
// The object in which this CIE was first seen.
Relobj* object_;
// Input section index for this CIE.
unsigned int shndx_;
// Offset within the input section for this CIE.
off_t input_offset_;
// The encoding of the FDE. This is a DW_EH_PE code.
unsigned char fde_encoding_;
// The name of the personality routine. This will be the name of a
// global symbol, or will be the empty string.
std::string personality_name_;
// List of FDEs.
std::vector<Fde*> fdes_;
// CIE data.
std::string contents_;
};
extern bool operator<(const Cie&, const Cie&);
extern bool operator==(const Cie&, const Cie&);
// This class manages .eh_frame sections. It discards duplicate
// exception information.
class Eh_frame : public Output_section_data
{
public:
Eh_frame();
// Record the associated Eh_frame_hdr, if any.
void
set_eh_frame_hdr(Eh_frame_hdr* hdr)
{ this->eh_frame_hdr_ = hdr; }
// Add the input section SHNDX in OBJECT. SYMBOLS is the contents
// of the symbol table section (size SYMBOLS_SIZE), SYMBOL_NAMES is
// the symbol names section (size SYMBOL_NAMES_SIZE). RELOC_SHNDX
// is the relocation section if any (0 for none, -1U for multiple).
// RELOC_TYPE is the type of the relocation section if any. This
// returns whether the section was incorporated into the .eh_frame
// data.
template<int size, bool big_endian>
bool
add_ehframe_input_section(Sized_relobj<size, big_endian>* object,
const unsigned char* symbols,
off_t symbols_size,
const unsigned char* symbol_names,
off_t symbol_names_size,
unsigned int shndx, unsigned int reloc_shndx,
unsigned int reloc_type);
// Return the number of FDEs.
unsigned int
fde_count() const;
// Set the final data size.
void
do_set_address(uint64_t, off_t);
// Return the output address for an input address.
bool
do_output_offset(const Relobj*, unsigned int shndx, off_t offset,
off_t* poutput) const;
// Write the data to the file.
void
do_write(Output_file*);
private:
// The comparison routine for the CIE map.
struct Cie_less
{
bool
operator()(const Cie* cie1, const Cie* cie2) const
{ return *cie1 < *cie2; }
};
// A mapping from unique CIEs to their offset in the output file.
typedef std::map<Cie*, uint64_t, Cie_less> Cie_offsets;
// A list of unmergeable CIEs with their offsets.
typedef std::vector<std::pair<Cie*, uint64_t> > Unmergeable_cie_offsets;
// A mapping from offsets to CIEs. This is used while reading an
// input section.
typedef std::map<uint64_t, Cie*> Offsets_to_cie;
// A list of CIEs, and a bool indicating whether the CIE is
// mergeable.
typedef std::vector<std::pair<Cie*, bool> > New_cies;
// Skip an LEB128.
static bool
skip_leb128(const unsigned char**, const unsigned char*);
// The implementation of add_ehframe_input_section.
template<int size, bool big_endian>
bool
do_add_ehframe_input_section(Sized_relobj<size, big_endian>* object,
const unsigned char* symbols,
off_t symbols_size,
const unsigned char* symbol_names,
off_t symbol_names_size,
unsigned int shndx,
unsigned int reloc_shndx,
unsigned int reloc_type,
const unsigned char* pcontents,
off_t contents_len,
New_cies*);
// Read a CIE.
template<int size, bool big_endian>
bool
read_cie(Sized_relobj<size, big_endian>* object,
unsigned int shndx,
const unsigned char* symbols,
off_t symbols_size,
const unsigned char* symbol_names,
off_t symbol_names_size,
const unsigned char* pcontents,
const unsigned char* pcie,
const unsigned char *pcieend,
Track_relocs<size, big_endian>* relocs,
Offsets_to_cie* cies,
New_cies* new_cies);
// Read an FDE.
template<int size, bool big_endian>
bool
read_fde(Sized_relobj<size, big_endian>* object,
unsigned int shndx,
const unsigned char* symbols,
off_t symbols_size,
const unsigned char* pcontents,
unsigned int offset,
const unsigned char* pfde,
const unsigned char *pfdeend,
Track_relocs<size, big_endian>* relocs,
Offsets_to_cie* cies);
// Template version of write function.
template<int size, bool big_endian>
void
do_sized_write(unsigned char* oview);
// The exception frame header, if any.
Eh_frame_hdr* eh_frame_hdr_;
// A mapping from all unique CIEs to their offset in the output
// file.
Cie_offsets cie_offsets_;
// A mapping from unmergeable CIEs to their offset in the output
// file.
Unmergeable_cie_offsets unmergeable_cie_offsets_;
// A mapping from input sections to the output section.
Merge_map merge_map_;
};
} // End namespace gold.

View File

@ -250,6 +250,14 @@ queue_final_tasks(const General_options& options,
thread_count = input_objects->number_of_input_objects();
workqueue->set_thread_count(thread_count);
// Use a blocker to wait until all the input sections have been
// written out.
Task_token* input_sections_blocker = new Task_token();
// Use a blocker to block any objects which have to wait for the
// output sections to complete before they can apply relocations.
Task_token* output_sections_blocker = new Task_token();
// Use a blocker to block the final cleanup task.
Task_token* final_blocker = new Task_token();
@ -259,8 +267,11 @@ queue_final_tasks(const General_options& options,
p != input_objects->relobj_end();
++p)
{
input_sections_blocker->add_blocker();
final_blocker->add_blocker();
workqueue->queue(new Relocate_task(options, symtab, layout, *p, of,
input_sections_blocker,
output_sections_blocker,
final_blocker));
}
@ -273,10 +284,23 @@ queue_final_tasks(const General_options& options,
of,
final_blocker));
// Queue a task to write out the output sections.
output_sections_blocker->add_blocker();
final_blocker->add_blocker();
workqueue->queue(new Write_sections_task(layout, of, output_sections_blocker,
final_blocker));
// Queue a task to write out everything else.
final_blocker->add_blocker();
workqueue->queue(new Write_data_task(layout, symtab, of, final_blocker));
// Queue a task to write out the output sections which depend on
// input sections.
final_blocker->add_blocker();
workqueue->queue(new Write_after_input_sections_task(layout, of,
input_sections_blocker,
final_blocker));
// Queue a task to close the output file. This will be blocked by
// FINAL_BLOCKER.
workqueue->queue(new Task_function(new Close_task_runner(of),

View File

@ -70,9 +70,10 @@ class Target_i386 : public Sized_target<32, false>
unsigned int sh_type,
const unsigned char* prelocs,
size_t reloc_count,
Output_section* output_section,
bool needs_special_offset_handling,
size_t local_symbol_count,
const unsigned char* plocal_symbols,
Symbol** global_symbols);
const unsigned char* plocal_symbols);
// Finalize the sections.
void
@ -89,6 +90,8 @@ class Target_i386 : public Sized_target<32, false>
unsigned int sh_type,
const unsigned char* prelocs,
size_t reloc_count,
Output_section* output_section,
bool needs_special_offset_handling,
unsigned char* view,
elfcpp::Elf_types<32>::Elf_Addr view_address,
off_t view_size);
@ -1157,9 +1160,10 @@ Target_i386::scan_relocs(const General_options& options,
unsigned int sh_type,
const unsigned char* prelocs,
size_t reloc_count,
Output_section* output_section,
bool needs_special_offset_handling,
size_t local_symbol_count,
const unsigned char* plocal_symbols,
Symbol** global_symbols)
const unsigned char* plocal_symbols)
{
if (sh_type == elfcpp::SHT_RELA)
{
@ -1178,9 +1182,10 @@ Target_i386::scan_relocs(const General_options& options,
data_shndx,
prelocs,
reloc_count,
output_section,
needs_special_offset_handling,
local_symbol_count,
plocal_symbols,
global_symbols);
plocal_symbols);
}
// Finalize the sections.
@ -1770,6 +1775,8 @@ Target_i386::relocate_section(const Relocate_info<32, false>* relinfo,
unsigned int sh_type,
const unsigned char* prelocs,
size_t reloc_count,
Output_section* output_section,
bool needs_special_offset_handling,
unsigned char* view,
elfcpp::Elf_types<32>::Elf_Addr address,
off_t view_size)
@ -1782,6 +1789,8 @@ Target_i386::relocate_section(const Relocate_info<32, false>* relinfo,
this,
prelocs,
reloc_count,
output_section,
needs_special_offset_handling,
view,
address,
view_size);

View File

@ -101,7 +101,7 @@ is_prefix_of(const char* prefix, const char* str)
template<int size, bool big_endian>
bool
Layout::include_section(Object*, const char* name,
Layout::include_section(Sized_relobj<size, big_endian>*, const char* name,
const elfcpp::Shdr<size, big_endian>& shdr)
{
// Some section types are never linked. Some are only linked when
@ -202,13 +202,20 @@ Layout::get_output_section(const char* name, Stringpool::Key name_key,
}
// Return the output section to use for input section SHNDX, with name
// NAME, with header HEADER, from object OBJECT. Set *OFF to the
// offset of this input section without the output section.
// NAME, with header HEADER, from object OBJECT. RELOC_SHNDX is the
// index of a relocation section which applies to this section, or 0
// if none, or -1U if more than one. RELOC_TYPE is the type of the
// relocation section if there is one. Set *OFF to the offset of this
// input section without the output section. Return NULL if the
// section should be discarded. Set *OFF to -1 if the section
// contents should not be written directly to the output file, but
// will instead receive special handling.
template<int size, bool big_endian>
Output_section*
Layout::layout(Relobj* object, unsigned int shndx, const char* name,
const elfcpp::Shdr<size, big_endian>& shdr, off_t* off)
Layout::layout(Sized_relobj<size, big_endian>* object, unsigned int shndx,
const char* name, const elfcpp::Shdr<size, big_endian>& shdr,
unsigned int reloc_shndx, unsigned int, off_t* off)
{
if (!this->include_section(object, name, shdr))
return NULL;
@ -231,38 +238,44 @@ Layout::layout(Relobj* object, unsigned int shndx, const char* name,
shdr.get_sh_type(),
shdr.get_sh_flags());
// Special GNU handling of sections named .eh_frame.
if (!parameters->output_is_object()
&& strcmp(name, ".eh_frame") == 0
&& shdr.get_sh_size() > 0
&& shdr.get_sh_type() == elfcpp::SHT_PROGBITS
&& shdr.get_sh_flags() == elfcpp::SHF_ALLOC)
{
this->layout_eh_frame(object, shndx, name, shdr, os, off);
return os;
}
// FIXME: Handle SHF_LINK_ORDER somewhere.
*off = os->add_input_section(object, shndx, name, shdr);
*off = os->add_input_section(object, shndx, name, shdr, reloc_shndx);
return os;
}
// Special GNU handling of sections named .eh_frame. They will
// normally hold exception frame data.
// Special GNU handling of sections name .eh_frame. They will
// normally hold exception frame data as defined by the C++ ABI
// (http://codesourcery.com/cxx-abi/).
template<int size, bool big_endian>
void
Layout::layout_eh_frame(Relobj* object,
Output_section*
Layout::layout_eh_frame(Sized_relobj<size, big_endian>* object,
const unsigned char* symbols,
off_t symbols_size,
const unsigned char* symbol_names,
off_t symbol_names_size,
unsigned int shndx,
const char* name,
const elfcpp::Shdr<size, big_endian>& shdr,
Output_section* os, off_t* off)
unsigned int reloc_shndx, unsigned int reloc_type,
off_t* off)
{
gold_assert(shdr.get_sh_type() == elfcpp::SHT_PROGBITS);
gold_assert(shdr.get_sh_flags() == elfcpp::SHF_ALLOC);
Stringpool::Key name_key;
const char* name = this->namepool_.add(".eh_frame", false, &name_key);
Output_section* os = this->get_output_section(name, name_key,
elfcpp::SHT_PROGBITS,
elfcpp::SHF_ALLOC);
if (this->eh_frame_section_ == NULL)
{
this->eh_frame_section_ = os;
this->eh_frame_data_ = new Eh_frame();
os->add_output_section_data(this->eh_frame_data_);
if (this->options_.create_eh_frame_hdr())
{
@ -275,19 +288,39 @@ Layout::layout_eh_frame(Relobj* object,
elfcpp::SHT_PROGBITS,
elfcpp::SHF_ALLOC);
Eh_frame_hdr* hdr_posd = new Eh_frame_hdr(os);
Eh_frame_hdr* hdr_posd = new Eh_frame_hdr(os, this->eh_frame_data_);
hdr_os->add_output_section_data(hdr_posd);
hdr_os->set_after_input_sections();
Output_segment* hdr_oseg =
new Output_segment(elfcpp::PT_GNU_EH_FRAME, elfcpp::PF_R);
this->segment_list_.push_back(hdr_oseg);
hdr_oseg->add_output_section(hdr_os, elfcpp::PF_R);
this->eh_frame_data_->set_eh_frame_hdr(hdr_posd);
}
}
gold_assert(this->eh_frame_section_ == os);
*off = os->add_input_section(object, shndx, name, shdr);
if (this->eh_frame_data_->add_ehframe_input_section(object,
symbols,
symbols_size,
symbol_names,
symbol_names_size,
shndx,
reloc_shndx,
reloc_type))
*off = -1;
else
{
// We couldn't handle this .eh_frame section for some reason.
// Add it as a normal section.
*off = os->add_input_section(object, shndx, name, shdr, reloc_shndx);
}
return os;
}
// Add POSD to an output section using NAME, TYPE, and FLAGS.
@ -1724,6 +1757,22 @@ Layout::add_comdat(const char* signature, bool group)
}
}
// Write out the Output_sections. Most won't have anything to write,
// since most of the data will come from input sections which are
// handled elsewhere. But some Output_sections do have Output_data.
void
Layout::write_output_sections(Output_file* of) const
{
for (Section_list::const_iterator p = this->section_list_.begin();
p != this->section_list_.end();
++p)
{
if (!(*p)->after_input_sections())
(*p)->write(of);
}
}
// Write out data not associated with a section or the symbol table.
void
@ -1764,15 +1813,6 @@ Layout::write_data(const Symbol_table* symtab, Output_file* of) const
}
}
// Write out the Output_sections. Most won't have anything to
// write, since most of the data will come from input sections which
// are handled elsewhere. But some Output_sections do have
// Output_data.
for (Section_list::const_iterator p = this->section_list_.begin();
p != this->section_list_.end();
++p)
(*p)->write(of);
// Write out the Output_data which are not in an Output_section.
for (Data_list::const_iterator p = this->special_output_list_.begin();
p != this->special_output_list_.end();
@ -1780,6 +1820,65 @@ Layout::write_data(const Symbol_table* symtab, Output_file* of) const
(*p)->write(of);
}
// Write out the Output_sections which can only be written after the
// input sections are complete.
void
Layout::write_sections_after_input_sections(Output_file* of) const
{
for (Section_list::const_iterator p = this->section_list_.begin();
p != this->section_list_.end();
++p)
{
if ((*p)->after_input_sections())
(*p)->write(of);
}
}
// Write_sections_task methods.
// We can always run this task.
Task::Is_runnable_type
Write_sections_task::is_runnable(Workqueue*)
{
return IS_RUNNABLE;
}
// We need to unlock both OUTPUT_SECTIONS_BLOCKER and FINAL_BLOCKER
// when finished.
class Write_sections_task::Write_sections_locker : public Task_locker
{
public:
Write_sections_locker(Task_token& output_sections_blocker,
Task_token& final_blocker,
Workqueue* workqueue)
: output_sections_block_(output_sections_blocker, workqueue),
final_block_(final_blocker, workqueue)
{ }
private:
Task_block_token output_sections_block_;
Task_block_token final_block_;
};
Task_locker*
Write_sections_task::locks(Workqueue* workqueue)
{
return new Write_sections_locker(*this->output_sections_blocker_,
*this->final_blocker_,
workqueue);
}
// Run the task--write out the data.
void
Write_sections_task::run(Workqueue*)
{
this->layout_->write_output_sections(this->of_);
}
// Write_data_task methods.
// We can always run this task.
@ -1833,6 +1932,34 @@ Write_symbols_task::run(Workqueue*)
this->of_);
}
// Write_after_input_sections_task methods.
// We can only run this task after the input sections have completed.
Task::Is_runnable_type
Write_after_input_sections_task::is_runnable(Workqueue*)
{
if (this->input_sections_blocker_->is_blocked())
return IS_BLOCKED;
return IS_RUNNABLE;
}
// We need to unlock FINAL_BLOCKER when finished.
Task_locker*
Write_after_input_sections_task::locks(Workqueue* workqueue)
{
return new Task_locker_block(*this->final_blocker_, workqueue);
}
// Run the task.
void
Write_after_input_sections_task::run(Workqueue*)
{
this->layout_->write_sections_after_input_sections(this->of_);
}
// Close_task_runner methods.
// Run the task--close the file.
@ -1849,30 +1976,97 @@ Close_task_runner::run(Workqueue*)
#ifdef HAVE_TARGET_32_LITTLE
template
Output_section*
Layout::layout<32, false>(Relobj* object, unsigned int shndx, const char* name,
const elfcpp::Shdr<32, false>& shdr, off_t*);
Layout::layout<32, false>(Sized_relobj<32, false>* object, unsigned int shndx,
const char* name,
const elfcpp::Shdr<32, false>& shdr,
unsigned int, unsigned int, off_t*);
#endif
#ifdef HAVE_TARGET_32_BIG
template
Output_section*
Layout::layout<32, true>(Relobj* object, unsigned int shndx, const char* name,
const elfcpp::Shdr<32, true>& shdr, off_t*);
Layout::layout<32, true>(Sized_relobj<32, true>* object, unsigned int shndx,
const char* name,
const elfcpp::Shdr<32, true>& shdr,
unsigned int, unsigned int, off_t*);
#endif
#ifdef HAVE_TARGET_64_LITTLE
template
Output_section*
Layout::layout<64, false>(Relobj* object, unsigned int shndx, const char* name,
const elfcpp::Shdr<64, false>& shdr, off_t*);
Layout::layout<64, false>(Sized_relobj<64, false>* object, unsigned int shndx,
const char* name,
const elfcpp::Shdr<64, false>& shdr,
unsigned int, unsigned int, off_t*);
#endif
#ifdef HAVE_TARGET_64_BIG
template
Output_section*
Layout::layout<64, true>(Relobj* object, unsigned int shndx, const char* name,
const elfcpp::Shdr<64, true>& shdr, off_t*);
Layout::layout<64, true>(Sized_relobj<64, true>* object, unsigned int shndx,
const char* name,
const elfcpp::Shdr<64, true>& shdr,
unsigned int, unsigned int, off_t*);
#endif
#ifdef HAVE_TARGET_32_LITTLE
template
Output_section*
Layout::layout_eh_frame<32, false>(Sized_relobj<32, false>* object,
const unsigned char* symbols,
off_t symbols_size,
const unsigned char* symbol_names,
off_t symbol_names_size,
unsigned int shndx,
const elfcpp::Shdr<32, false>& shdr,
unsigned int reloc_shndx,
unsigned int reloc_type,
off_t* off);
#endif
#ifdef HAVE_TARGET_32_BIG
template
Output_section*
Layout::layout_eh_frame<32, true>(Sized_relobj<32, true>* object,
const unsigned char* symbols,
off_t symbols_size,
const unsigned char* symbol_names,
off_t symbol_names_size,
unsigned int shndx,
const elfcpp::Shdr<32, true>& shdr,
unsigned int reloc_shndx,
unsigned int reloc_type,
off_t* off);
#endif
#ifdef HAVE_TARGET_64_LITTLE
template
Output_section*
Layout::layout_eh_frame<64, false>(Sized_relobj<64, false>* object,
const unsigned char* symbols,
off_t symbols_size,
const unsigned char* symbol_names,
off_t symbol_names_size,
unsigned int shndx,
const elfcpp::Shdr<64, false>& shdr,
unsigned int reloc_shndx,
unsigned int reloc_type,
off_t* off);
#endif
#ifdef HAVE_TARGET_64_BIG
template
Output_section*
Layout::layout_eh_frame<64, true>(Sized_relobj<64, true>* object,
const unsigned char* symbols,
off_t symbols_size,
const unsigned char* symbol_names,
off_t symbol_names_size,
unsigned int shndx,
const elfcpp::Shdr<64, true>& shdr,
unsigned int reloc_shndx,
unsigned int reloc_type,
off_t* off);
#endif
} // End namespace gold.

View File

@ -45,6 +45,7 @@ class Output_section_headers;
class Output_segment;
class Output_data;
class Output_data_dynamic;
class Eh_frame;
class Target;
// This task function handles mapping the input sections to output
@ -87,12 +88,37 @@ class Layout
// Given an input section SHNDX, named NAME, with data in SHDR, from
// the object file OBJECT, return the output section where this
// input section should go. Set *OFFSET to the offset within the
// output section.
// input section should go. RELOC_SHNDX is the index of a
// relocation section which applies to this section, or 0 if none,
// or -1U if more than one. RELOC_TYPE is the type of the
// relocation section if there is one. Set *OFFSET to the offset
// within the output section.
template<int size, bool big_endian>
Output_section*
layout(Relobj *object, unsigned int shndx, const char* name,
const elfcpp::Shdr<size, big_endian>& shdr, off_t* offset);
layout(Sized_relobj<size, big_endian> *object, unsigned int shndx,
const char* name, const elfcpp::Shdr<size, big_endian>& shdr,
unsigned int reloc_shndx, unsigned int reloc_type, off_t* offset);
// Like layout, only for exception frame sections. OBJECT is an
// object file. SYMBOLS is the contents of the symbol table
// section, with size SYMBOLS_SIZE. SYMBOL_NAMES is the contents of
// the symbol name section, with size SYMBOL_NAMES_SIZE. SHNDX is a
// .eh_frame section in OBJECT. SHDR is the section header.
// RELOC_SHNDX is the index of a relocation section which applies to
// this section, or 0 if none, or -1U if more than one. RELOC_TYPE
// is the type of the relocation section if there is one. This
// returns the output section, and sets *OFFSET to the offset.
template<int size, bool big_endian>
Output_section*
layout_eh_frame(Sized_relobj<size, big_endian>* object,
const unsigned char* symbols,
off_t symbols_size,
const unsigned char* symbol_names,
off_t symbol_names_size,
unsigned int shndx,
const elfcpp::Shdr<size, big_endian>& shdr,
unsigned int reloc_shndx, unsigned int reloc_type,
off_t* offset);
// Handle a GNU stack note. This is called once per input object
// file. SEEN_GNU_STACK is true if the object file has a
@ -176,11 +202,20 @@ class Layout
dynamic_data() const
{ return this->dynamic_data_; }
// Write out the output sections.
void
write_output_sections(Output_file* of) const;
// Write out data not associated with an input file or the symbol
// table.
void
write_data(const Symbol_table*, Output_file*) const;
// Write out output sections which can not be written until all the
// input sections are complete.
void
write_sections_after_input_sections(Output_file* of) const;
// Return an output section named NAME, or NULL if there is none.
Output_section*
find_output_section(const char* name) const;
@ -218,13 +253,6 @@ class Layout
static const Linkonce_mapping linkonce_mapping[];
static const int linkonce_mapping_count;
// Handle an exception frame section.
template<int size, bool big_endian>
void
layout_eh_frame(Relobj*, unsigned int, const char*,
const elfcpp::Shdr<size, big_endian>&,
Output_section*, off_t*);
// Create a .note section for gold.
void
create_gold_note();
@ -285,7 +313,7 @@ class Layout
// Return whether to include this section in the link.
template<int size, bool big_endian>
bool
include_section(Object* object, const char* name,
include_section(Sized_relobj<size, big_endian>* object, const char* name,
const elfcpp::Shdr<size, big_endian>&);
// Return the output section name to use given an input section
@ -389,8 +417,12 @@ class Layout
Output_section* dynamic_section_;
// The dynamic data which goes into dynamic_section_.
Output_data_dynamic* dynamic_data_;
// The exception frame section.
// The exception frame output section if there is one.
Output_section* eh_frame_section_;
// The exception frame data for eh_frame_section_.
Eh_frame* eh_frame_data_;
// The exception frame header output section if there is one.
Output_section* eh_frame_hdr_section_;
// The size of the output file.
off_t output_file_size_;
// Whether we have seen an object file marked to require an
@ -404,6 +436,42 @@ class Layout
bool input_without_gnu_stack_note_;
};
// This task handles writing out data in output sections which is not
// part of an input section, or which requires special handling. When
// this is done, it unblocks both output_sections_blocker and
// final_blocker.
class Write_sections_task : public Task
{
public:
Write_sections_task(const Layout* layout, Output_file* of,
Task_token* output_sections_blocker,
Task_token* final_blocker)
: layout_(layout), of_(of),
output_sections_blocker_(output_sections_blocker),
final_blocker_(final_blocker)
{ }
// The standard Task methods.
Is_runnable_type
is_runnable(Workqueue*);
Task_locker*
locks(Workqueue*);
void
run(Workqueue*);
private:
class Write_sections_locker;
const Layout* layout_;
Output_file* of_;
Task_token* output_sections_blocker_;
Task_token* final_blocker_;
};
// This task handles writing out data which is not part of a section
// or segment.
@ -465,6 +533,42 @@ class Write_symbols_task : public Task
Task_token* final_blocker_;
};
// This task handles writing out data in output sections which can't
// be written out until all the input sections have been handled.
// This is for sections whose contents is based on the contents of
// other output sections.
class Write_after_input_sections_task : public Task
{
public:
Write_after_input_sections_task(const Layout* layout, Output_file* of,
Task_token* input_sections_blocker,
Task_token* final_blocker)
: layout_(layout), of_(of),
input_sections_blocker_(input_sections_blocker),
final_blocker_(final_blocker)
{ }
// The standard Task methods.
Is_runnable_type
is_runnable(Workqueue*);
Task_locker*
locks(Workqueue*);
void
run(Workqueue*);
private:
class Write_sections_locker;
const Layout* layout_;
Output_file* of_;
Task_token* input_sections_blocker_;
Task_token* final_blocker_;
};
// This task function handles closing the file.
class Close_task_runner : public Task_function_runner

View File

@ -30,12 +30,14 @@
namespace gold
{
// Class Merge_map::Merge_key_less.
// Sort the entries in a merge mapping. The key is an input object, a
// section index in that object, and an offset in that section.
bool
Output_merge_base::Merge_key_less::operator()(const Merge_key& mk1,
const Merge_key& mk2) const
Merge_map::Merge_key_less::operator()(const Merge_key& mk1,
const Merge_key& mk2) const
{
// The order of different objects and different sections doesn't
// matter. We want to get consistent results across links so we
@ -55,43 +57,44 @@ Output_merge_base::Merge_key_less::operator()(const Merge_key& mk1,
return mk1.offset < mk2.offset;
}
// Add a mapping from an OFFSET in input section SHNDX in object
// OBJECT to an OUTPUT_OFFSET in a merged output section. This
// manages the mapping used to resolve relocations against merged
// sections.
// Class Merge_map.
// Add a mapping for the bytes from OFFSET to OFFSET + LENGTH in input
// section SHNDX in object OBJECT to an OUTPUT_OFFSET in a merged
// output section.
void
Output_merge_base::add_mapping(Relobj* object, unsigned int shndx,
off_t offset, off_t output_offset)
Merge_map::add_mapping(Relobj* object, unsigned int shndx,
off_t offset, off_t length, off_t output_offset)
{
Merge_key mk;
mk.object = object;
mk.shndx = shndx;
mk.offset = offset;
std::pair<Merge_map::iterator, bool> ins =
this->merge_map_.insert(std::make_pair(mk, output_offset));
Merge_value mv;
mv.length = length;
mv.output_offset = output_offset;
std::pair<Merge_mapping::iterator, bool> ins =
this->merge_map_.insert(std::make_pair(mk, mv));
gold_assert(ins.second);
}
// Return the output address for an input address. The input address
// is at offset OFFSET in section SHNDX in OBJECT.
// OUTPUT_SECTION_ADDRESS is the address of the output section. If we
// know the address, set *POUTPUT and return true. Otherwise return
// false.
// Return the output offset for an input address. The input address
// is at offset OFFSET in section SHNDX in OBJECT. This sets
// *OUTPUT_OFFSET to the offset in the output section. This returns
// true if the mapping is known, false otherwise.
bool
Output_merge_base::do_output_address(const Relobj* object, unsigned int shndx,
off_t offset,
uint64_t output_section_address,
uint64_t* poutput) const
Merge_map::get_output_offset(const Relobj* object, unsigned int shndx,
off_t offset, off_t* output_offset) const
{
gold_assert(output_section_address == this->address());
Merge_key mk;
mk.object = object;
mk.shndx = shndx;
mk.offset = offset;
Merge_map::const_iterator p = this->merge_map_.lower_bound(mk);
Merge_mapping::const_iterator p = this->merge_map_.lower_bound(mk);
// If MK is not in the map, lower_bound returns the next iterator
// larger than it.
@ -108,12 +111,32 @@ Output_merge_base::do_output_address(const Relobj* object, unsigned int shndx,
if (p->first.object != object || p->first.shndx != shndx)
return false;
// Any input section is fully mapped: we don't need to know the size
// of the range starting at P->FIRST.OFFSET.
*poutput = output_section_address + p->second + (offset - p->first.offset);
if (offset - p->first.offset >= p->second.length)
return false;
*output_offset = p->second.output_offset;
if (*output_offset != -1)
*output_offset += (offset - p->first.offset);
return true;
}
// Class Output_merge_base.
// Return the output offset for an input offset. The input address is
// at offset OFFSET in section SHNDX in OBJECT. If we know the
// offset, set *POUTPUT and return true. Otherwise return false.
bool
Output_merge_base::do_output_offset(const Relobj* object,
unsigned int shndx,
off_t offset,
off_t* poutput) const
{
return this->merge_map_.get_output_offset(object, shndx, offset, poutput);
}
// Class Output_merge_data.
// Compute the hash code for a fixed-size constant.
size_t
@ -214,7 +237,7 @@ Output_merge_data::do_add_input_section(Relobj* object, unsigned int shndx)
}
// Record the offset of this constant in the output section.
this->add_mapping(object, shndx, i, k);
this->add_mapping(object, shndx, i, entsize, k);
}
return true;
@ -241,6 +264,8 @@ Output_merge_data::do_write(Output_file* of)
of->write(this->offset(), this->p_, this->len_);
}
// Class Output_merge_string.
// Add an input section to a merged string section.
template<typename Char_type>
@ -279,10 +304,12 @@ Output_merge_string<Char_type>::do_add_input_section(Relobj* object,
const Char_type* str = this->stringpool_.add(p, true, NULL);
this->merged_strings_.push_back(Merged_string(object, shndx, i, str));
off_t bytelen_with_null = (plen + 1) * sizeof(Char_type);
this->merged_strings_.push_back(Merged_string(object, shndx, i, str,
bytelen_with_null));
p += plen + 1;
i += (plen + 1) * sizeof(Char_type);
i += bytelen_with_null;
}
return true;
@ -302,7 +329,7 @@ Output_merge_string<Char_type>::do_set_address(uint64_t, off_t)
this->merged_strings_.begin();
p != this->merged_strings_.end();
++p)
this->add_mapping(p->object, p->shndx, p->offset,
this->add_mapping(p->object, p->shndx, p->offset, p->length,
this->stringpool_.get_offset(p->string));
this->set_data_size(this->stringpool_.get_strtab_size());

View File

@ -31,36 +31,36 @@
namespace gold
{
// A general class for SHF_MERGE data, to hold functions shared by
// fixed-size constant data and string data.
// This class manages mappings from input sections to offsets in an
// output section. This is used where input sections are merged.
class Output_merge_base : public Output_section_data
class Merge_map
{
public:
Output_merge_base(uint64_t entsize, uint64_t addralign)
: Output_section_data(addralign), merge_map_(), entsize_(entsize)
Merge_map()
: merge_map_()
{ }
// Return the output address for an input address.
bool
do_output_address(const Relobj* object, unsigned int shndx, off_t offset,
uint64_t output_section_address, uint64_t* poutput) const;
protected:
// Return the entry size.
uint64_t
entsize() const
{ return this->entsize_; }
// Add a mapping from an OFFSET in input section SHNDX in object
// OBJECT to an OUTPUT_OFFSET in the output section.
// Add a mapping for the bytes from OFFSET to OFFSET + LENGTH in the
// input section SHNDX in object OBJECT to OUTPUT_OFFSET in the
// output section. An OUTPUT_OFFSET of -1 means that the bytes are
// discarded.
void
add_mapping(Relobj* object, unsigned int shndx, off_t offset,
add_mapping(Relobj* object, unsigned int shndx, off_t offset, off_t length,
off_t output_offset);
// Return the output offset for an input address. The input address
// is at offset OFFSET in section SHNDX in OBJECT. This sets
// *OUTPUT_OFFSET to the offset in the output section; this will be
// -1 if the bytes are not being copied to the output. This returns
// true if the mapping is known, false otherwise.
bool
get_output_offset(const Relobj* object, unsigned int shndx, off_t offset,
off_t *output_offset) const;
private:
// We build a mapping from OBJECT/SHNDX/OFFSET to an offset in the
// output section.
// We build a mapping from OBJECT/SHNDX/OFFSET to an offset and
// length in the output section.
struct Merge_key
{
const Relobj* object;
@ -74,12 +74,53 @@ class Output_merge_base : public Output_section_data
operator()(const Merge_key&, const Merge_key&) const;
};
typedef std::map<Merge_key, off_t, Merge_key_less> Merge_map;
struct Merge_value
{
off_t length;
off_t output_offset;
};
typedef std::map<Merge_key, Merge_value, Merge_key_less> Merge_mapping;
// A mapping from input object/section/offset to offset in output
// section.
Merge_map merge_map_;
Merge_mapping merge_map_;
};
// A general class for SHF_MERGE data, to hold functions shared by
// fixed-size constant data and string data.
class Output_merge_base : public Output_section_data
{
public:
Output_merge_base(uint64_t entsize, uint64_t addralign)
: Output_section_data(addralign), merge_map_(), entsize_(entsize)
{ }
// Return the output offset for an input offset.
bool
do_output_offset(const Relobj* object, unsigned int shndx, off_t offset,
off_t* poutput) const;
protected:
// Return the entry size.
uint64_t
entsize() const
{ return this->entsize_; }
// Add a mapping from an OFFSET in input section SHNDX in object
// OBJECT to an OUTPUT_OFFSET in the output section.
void
add_mapping(Relobj* object, unsigned int shndx, off_t offset,
off_t length, off_t output_offset)
{
this->merge_map_.add_mapping(object, shndx, offset, length, output_offset);
}
private:
// A mapping from input object/section/offset to offset in output
// section.
Merge_map merge_map_;
// The entry size. For fixed-size constants, this is the size of
// the constants. For strings, this is the size of a character.
uint64_t entsize_;
@ -221,10 +262,13 @@ class Output_merge_string : public Output_merge_base
off_t offset;
// The string itself, a pointer into a Stringpool.
const Char_type* string;
// The length of the string in bytes, including the null terminator.
size_t length;
Merged_string(Relobj *objecta, unsigned int shndxa, off_t offseta,
const Char_type* stringa)
: object(objecta), shndx(shndxa), offset(offseta), string(stringa)
const Char_type* stringa, size_t lengtha)
: object(objecta), shndx(shndxa), offset(offseta), string(stringa),
length(lengtha)
{ }
};

View File

@ -139,10 +139,11 @@ Sized_relobj<size, big_endian>::Sized_relobj(
symtab_shndx_(-1U),
local_symbol_count_(0),
output_local_symbol_count_(0),
symbols_(NULL),
symbols_(),
local_symbol_offset_(0),
local_values_(),
local_got_offsets_()
local_got_offsets_(),
has_eh_frame_(false)
{
}
@ -198,6 +199,50 @@ Sized_relobj<size, big_endian>::find_symtab(const unsigned char* pshdrs)
}
}
// Return whether SHDR has the right type and flags to be a GNU
// .eh_frame section.
template<int size, bool big_endian>
bool
Sized_relobj<size, big_endian>::check_eh_frame_flags(
const elfcpp::Shdr<size, big_endian>* shdr) const
{
return (shdr->get_sh_size() > 0
&& shdr->get_sh_type() == elfcpp::SHT_PROGBITS
&& shdr->get_sh_flags() == elfcpp::SHF_ALLOC);
}
// Return whether there is a GNU .eh_frame section, given the section
// headers and the section names.
template<int size, bool big_endian>
bool
Sized_relobj<size, big_endian>::find_eh_frame(const unsigned char* pshdrs,
const char* names,
off_t names_size) const
{
const unsigned int shnum = this->shnum();
const unsigned char* p = pshdrs + This::shdr_size;
for (unsigned int i = 1; i < shnum; ++i, p += This::shdr_size)
{
typename This::Shdr shdr(p);
if (this->check_eh_frame_flags(&shdr))
{
if (shdr.get_sh_name() >= names_size)
{
this->error(_("bad section name offset for section %u: %lu"),
i, static_cast<unsigned long>(shdr.get_sh_name()));
continue;
}
const char* name = names + shdr.get_sh_name();
if (strcmp(name, ".eh_frame") == 0)
return true;
}
}
return false;
}
// Read the sections and symbols from an object file.
template<int size, bool big_endian>
@ -210,8 +255,14 @@ Sized_relobj<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
this->find_symtab(pshdrs);
const unsigned char* namesu = sd->section_names->data();
const char* names = reinterpret_cast<const char*>(namesu);
if (this->find_eh_frame(pshdrs, names, sd->section_names_size))
this->has_eh_frame_ = true;
sd->symbols = NULL;
sd->symbols_size = 0;
sd->external_symbols_offset = 0;
sd->symbol_names = NULL;
sd->symbol_names_size = 0;
@ -226,16 +277,26 @@ Sized_relobj<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
+ this->symtab_shndx_ * This::shdr_size);
gold_assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
// We only need the external symbols.
// If this object has a .eh_frame section, we need all the symbols.
// Otherwise we only need the external symbols. While it would be
// simpler to just always read all the symbols, I've seen object
// files with well over 2000 local symbols, which for a 64-bit
// object file format is over 5 pages that we don't need to read
// now.
const int sym_size = This::sym_size;
const unsigned int loccount = symtabshdr.get_sh_info();
this->local_symbol_count_ = loccount;
off_t locsize = loccount * sym_size;
off_t extoff = symtabshdr.get_sh_offset() + locsize;
off_t extsize = symtabshdr.get_sh_size() - locsize;
off_t dataoff = symtabshdr.get_sh_offset();
off_t datasize = symtabshdr.get_sh_size();
off_t extoff = dataoff + locsize;
off_t extsize = datasize - locsize;
// Read the symbol table.
File_view* fvsymtab = this->get_lasting_view(extoff, extsize, false);
off_t readoff = this->has_eh_frame_ ? dataoff : extoff;
off_t readsize = this->has_eh_frame_ ? datasize : extsize;
File_view* fvsymtab = this->get_lasting_view(readoff, readsize, false);
// Read the section header for the symbol names.
unsigned int strtab_shndx = symtabshdr.get_sh_link();
@ -257,11 +318,36 @@ Sized_relobj<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
strtabshdr.get_sh_size(), true);
sd->symbols = fvsymtab;
sd->symbols_size = extsize;
sd->symbols_size = readsize;
sd->external_symbols_offset = this->has_eh_frame_ ? locsize : 0;
sd->symbol_names = fvstrtab;
sd->symbol_names_size = strtabshdr.get_sh_size();
}
// Return the section index of symbol SYM. Set *VALUE to its value in
// the object file. Note that for a symbol which is not defined in
// this object file, this will set *VALUE to 0 and return SHN_UNDEF;
// it will not return the final value of the symbol in the link.
template<int size, bool big_endian>
unsigned int
Sized_relobj<size, big_endian>::symbol_section_and_value(unsigned int sym,
Address* value)
{
off_t symbols_size;
const unsigned char* symbols = this->section_contents(this->symtab_shndx_,
&symbols_size,
false);
const size_t count = symbols_size / This::sym_size;
gold_assert(sym < count);
elfcpp::Sym<size, big_endian> elfsym(symbols + sym * This::sym_size);
*value = elfsym.get_st_value();
// FIXME: Handle SHN_XINDEX.
return elfsym.get_st_shndx();
}
// Return whether to include a section group in the link. LAYOUT is
// used to keep track of which section groups we have already seen.
// INDEX is the index of the section group and SHDR is the section
@ -425,6 +511,38 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
const unsigned char* pnamesu = sd->section_names->data();
const char* pnames = reinterpret_cast<const char*>(pnamesu);
// For each section, record the index of the reloc section if any.
// Use 0 to mean that there is no reloc section, -1U to mean that
// there is more than one.
std::vector<unsigned int> reloc_shndx(shnum, 0);
std::vector<unsigned int> reloc_type(shnum, elfcpp::SHT_NULL);
// Skip the first, dummy, section.
pshdrs += This::shdr_size;
for (unsigned int i = 1; i < shnum; ++i, pshdrs += This::shdr_size)
{
typename This::Shdr shdr(pshdrs);
unsigned int sh_type = shdr.get_sh_type();
if (sh_type == elfcpp::SHT_REL || sh_type == elfcpp::SHT_RELA)
{
unsigned int target_shndx = shdr.get_sh_info();
if (target_shndx == 0 || target_shndx >= shnum)
{
this->error(_("relocation section %u has bad info %u"),
i, target_shndx);
continue;
}
if (reloc_shndx[target_shndx] != 0)
reloc_shndx[target_shndx] = -1U;
else
{
reloc_shndx[target_shndx] = i;
reloc_type[target_shndx] = sh_type;
}
}
}
std::vector<Map_to_output>& map_sections(this->map_to_output());
map_sections.resize(shnum);
@ -436,8 +554,11 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
// Keep track of which sections to omit.
std::vector<bool> omit(shnum, false);
// Keep track of .eh_frame sections.
std::vector<unsigned int> eh_frame_sections;
// Skip the first, dummy, section.
pshdrs += This::shdr_size;
pshdrs = sd->section_headers->data() + This::shdr_size;
for (unsigned int i = 1; i < shnum; ++i, pshdrs += This::shdr_size)
{
typename This::Shdr shdr(pshdrs);
@ -490,15 +611,70 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
continue;
}
// The .eh_frame section is special. It holds exception frame
// information that we need to read in order to generate the
// exception frame header. We process these after all the other
// sections so that the exception frame reader can reliably
// determine which sections are being discarded, and discard the
// corresponding information.
if (!parameters->output_is_object()
&& strcmp(name, ".eh_frame") == 0
&& this->check_eh_frame_flags(&shdr))
{
eh_frame_sections.push_back(i);
continue;
}
off_t offset;
Output_section* os = layout->layout(this, i, name, shdr, &offset);
Output_section* os = layout->layout(this, i, name, shdr,
reloc_shndx[i], reloc_type[i],
&offset);
map_sections[i].output_section = os;
map_sections[i].offset = offset;
// If this section requires special handling, and if there are
// relocs that apply to it, then we must do the special handling
// before we apply the relocs.
if (offset == -1 && reloc_shndx[i] != 0)
this->set_relocs_must_follow_section_writes();
}
layout->layout_gnu_stack(seen_gnu_stack, gnu_stack_flags);
// Handle the .eh_frame sections at the end.
for (std::vector<unsigned int>::const_iterator p = eh_frame_sections.begin();
p != eh_frame_sections.end();
++p)
{
gold_assert(this->has_eh_frame_);
gold_assert(sd->external_symbols_offset != 0);
unsigned int i = *p;
const unsigned char *pshdr;
pshdr = sd->section_headers->data() + i * This::shdr_size;
typename This::Shdr shdr(pshdr);
off_t offset;
Output_section* os = layout->layout_eh_frame(this,
sd->symbols->data(),
sd->symbols_size,
sd->symbol_names->data(),
sd->symbol_names_size,
i, shdr,
reloc_shndx[i],
reloc_type[i],
&offset);
map_sections[i].output_section = os;
map_sections[i].offset = offset;
// If this section requires special handling, and if there are
// relocs that apply to it, then we must do the special handling
// before we apply the relocs.
if (offset == -1 && reloc_shndx[i] != 0)
this->set_relocs_must_follow_section_writes();
}
delete sd->section_headers;
sd->section_headers = NULL;
delete sd->section_names;
@ -519,19 +695,23 @@ Sized_relobj<size, big_endian>::do_add_symbols(Symbol_table* symtab,
}
const int sym_size = This::sym_size;
size_t symcount = sd->symbols_size / sym_size;
if (static_cast<off_t>(symcount * sym_size) != sd->symbols_size)
size_t symcount = ((sd->symbols_size - sd->external_symbols_offset)
/ sym_size);
if (static_cast<off_t>(symcount * sym_size)
!= sd->symbols_size - sd->external_symbols_offset)
{
this->error(_("size of symbols is not multiple of symbol size"));
return;
}
this->symbols_ = new Symbol*[symcount];
this->symbols_.resize(symcount);
const char* sym_names =
reinterpret_cast<const char*>(sd->symbol_names->data());
symtab->add_from_relobj(this, sd->symbols->data(), symcount, sym_names,
sd->symbol_names_size, this->symbols_);
symtab->add_from_relobj(this,
sd->symbols->data() + sd->external_symbols_offset,
symcount, sym_names, sd->symbol_names_size,
&this->symbols_);
delete sd->symbols;
sd->symbols = NULL;

View File

@ -57,6 +57,10 @@ struct Read_symbols_data
File_view* symbols;
// Size of symbol data in bytes.
off_t symbols_size;
// Offset of external symbols within symbol data. This structure
// sometimes contains only external symbols, in which case this will
// be zero. Sometimes it contains all symbols.
off_t external_symbols_offset;
// Symbol names.
File_view* symbol_names;
// Size of symbol name data in bytes.
@ -100,6 +104,10 @@ struct Section_relocs
unsigned int sh_type;
// Number of reloc entries.
size_t reloc_count;
// Output section.
Output_section* output_section;
// Whether this section has special handling for offsets.
bool needs_special_offset_handling;
};
// Relocations in an object file. This is read in read_relocs and
@ -197,6 +205,11 @@ class Object
section_flags(unsigned int shndx)
{ return this->do_section_flags(shndx); }
// Return the section type given a section index.
unsigned int
section_type(unsigned int shndx)
{ return this->do_section_type(shndx); }
// Return the section link field given a section index.
unsigned int
section_link(unsigned int shndx)
@ -291,6 +304,10 @@ class Object
virtual uint64_t
do_section_flags(unsigned int shndx) = 0;
// Get section type--implemented by child class.
virtual unsigned int
do_section_type(unsigned int shndx) = 0;
// Get section link field--implemented by child class.
virtual unsigned int
do_section_link(unsigned int shndx) = 0;
@ -421,9 +438,21 @@ class Relobj : public Object
return this->map_to_output_[shndx].output_section != NULL;
}
// Return whether an input section requires special
// handling--whether it is not simply mapped from the input file to
// the output file.
bool
is_section_specially_mapped(unsigned int shndx) const
{
gold_assert(shndx < this->map_to_output_.size());
return (this->map_to_output_[shndx].output_section != NULL
&& this->map_to_output_[shndx].offset == -1);
}
// Given a section index, return the corresponding Output_section
// (which will be NULL if the section is not included in the link)
// and set *POFF to the offset within that section.
// and set *POFF to the offset within that section. *POFF will be
// set to -1 if the section requires special handling.
inline Output_section*
output_section(unsigned int shndx, off_t* poff) const;
@ -435,6 +464,14 @@ class Relobj : public Object
this->map_to_output_[shndx].offset = off;
}
// Return true if we need to wait for output sections to be written
// before we can apply relocations. This is true if the object has
// any relocations for sections which require special handling, such
// as the exception frame section.
bool
relocs_must_follow_section_writes()
{ return this->relocs_must_follow_section_writes_; }
protected:
// What we need to know to map an input section to an output
// section. We keep an array of these, one for each input section,
@ -478,9 +515,18 @@ class Relobj : public Object
map_to_output() const
{ return this->map_to_output_; }
// Record that we must wait for the output sections to be written
// before applying relocations.
void
set_relocs_must_follow_section_writes()
{ this->relocs_must_follow_section_writes_ = true; }
private:
// Mapping from input sections to output section.
std::vector<Map_to_output> map_to_output_;
// Whether we need to wait for output sections to be written before
// we can apply relocations.
bool relocs_must_follow_section_writes_;
};
// Implement Object::output_section inline for efficiency.
@ -495,8 +541,8 @@ Relobj::output_section(unsigned int shndx, off_t* poff) const
// This POD class is holds the value of a symbol. This is used for
// local symbols, and for all symbols during relocation processing.
// In order to process relocs we need to be able to handle SHF_MERGE
// sections correctly.
// For special sections, such as SHF_MERGE sections, this calls a
// function to get the final symbol value.
template<int size>
class Symbol_value
@ -577,7 +623,10 @@ class Symbol_value
// Set the index of the input section in the input file.
void
set_input_shndx(unsigned int i)
{ this->input_shndx_ = i; }
{
this->input_shndx_ = i;
gold_assert(this->input_shndx_ == i);
}
// Record that this is a section symbol.
void
@ -610,6 +659,7 @@ class Sized_relobj : public Relobj
{
public:
typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
typedef std::vector<Symbol*> Symbols;
typedef std::vector<Symbol_value<size> > Local_values;
Sized_relobj(const std::string& name, Input_file* input_file, off_t offset,
@ -621,6 +671,41 @@ class Sized_relobj : public Relobj
void
setup(const typename elfcpp::Ehdr<size, big_endian>&);
// Return the number of local symbols.
unsigned int
local_symbol_count() const
{ return this->local_symbol_count_; }
// If SYM is the index of a global symbol in the object file's
// symbol table, return the Symbol object. Otherwise, return NULL.
Symbol*
global_symbol(unsigned int sym) const
{
if (sym >= this->local_symbol_count_)
{
gold_assert(sym - this->local_symbol_count_ < this->symbols_.size());
return this->symbols_[sym - this->local_symbol_count_];
}
return NULL;
}
// Return the section index of symbol SYM. Set *VALUE to its value
// in the object file. Note that for a symbol which is not defined
// in this object file, this will set *VALUE to 0 and return
// SHN_UNDEF; it will not return the final value of the symbol in
// the link.
unsigned int
symbol_section_and_value(unsigned int sym, Address* value);
// Return a pointer to the Symbol_value structure which holds the
// value of a local symbol.
const Symbol_value<size>*
local_symbol(unsigned int sym) const
{
gold_assert(sym < this->local_values_.size());
return &this->local_values_[sym];
}
// Return the index of local symbol SYM in the ordinary symbol
// table. A value of -1U means that the symbol is not being output.
unsigned int
@ -731,6 +816,11 @@ class Sized_relobj : public Relobj
do_section_flags(unsigned int shndx)
{ return this->elf_file_.section_flags(shndx); }
// Return section type.
unsigned int
do_section_type(unsigned int shndx)
{ return this->elf_file_.section_type(shndx); }
// Return the section link field.
unsigned int
do_section_link(unsigned int shndx)
@ -748,6 +838,17 @@ class Sized_relobj : public Relobj
void
find_symtab(const unsigned char* pshdrs);
// Return whether SHDR has the right flags for a GNU style exception
// frame section.
bool
check_eh_frame_flags(const elfcpp::Shdr<size, big_endian>* shdr) const;
// Return whether there is a section named .eh_frame which might be
// a GNU style exception frame section.
bool
find_eh_frame(const unsigned char* pshdrs, const char* names,
off_t names_size) const;
// Whether to include a section group in the link.
bool
include_section_group(Layout*, unsigned int,
@ -766,6 +867,7 @@ class Sized_relobj : public Relobj
typename elfcpp::Elf_types<size>::Elf_Addr address;
off_t offset;
off_t view_size;
bool is_input_output_view;
};
typedef std::vector<View_size> Views;
@ -797,13 +899,15 @@ class Sized_relobj : public Relobj
// The number of local symbols which go into the output file.
unsigned int output_local_symbol_count_;
// The entries in the symbol table for the external symbols.
Symbol** symbols_;
Symbols symbols_;
// File offset for local symbols.
off_t local_symbol_offset_;
// Values of local symbols.
Local_values local_values_;
// GOT offsets for local symbols, indexed by symbol number.
Local_got_offsets local_got_offsets_;
// Whether this object has a GNU style .eh_frame section.
bool has_eh_frame_;
};
// A class to manage the list of all objects.
@ -891,12 +995,6 @@ struct Relocate_info
const Layout* layout;
// Object being relocated.
Sized_relobj<size, big_endian>* object;
// Number of local symbols.
unsigned int local_symbol_count;
// Values of local symbols.
const typename Sized_relobj<size, big_endian>::Local_values* local_values;
// Global symbols.
const Symbol* const * symbols;
// Section index of relocation section.
unsigned int reloc_shndx;
// Section index of section being relocated.

View File

@ -63,10 +63,18 @@ Output_data::set_address(uint64_t addr, off_t off)
this->do_set_address(addr, off);
}
// Return the default alignment for the target size.
uint64_t
Output_data::default_alignment()
{
return Output_data::default_alignment_for_size(parameters->get_size());
}
// Return the default alignment for a size--32 or 64.
uint64_t
Output_data::default_alignment(int size)
Output_data::default_alignment_for_size(int size)
{
if (size == 32)
return 4;
@ -569,7 +577,14 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::write_rel(
Output_section* os = this->u2_.relobj->output_section(this->shndx_,
&off);
gold_assert(os != NULL);
address += os->address() + off;
if (off != -1)
address += os->address() + off;
else
{
address = os->output_address(this->u2_.relobj, this->shndx_,
address);
gold_assert(address != -1U);
}
}
else if (this->u2_.od != NULL)
address += this->u2_.od->address();
@ -941,27 +956,25 @@ Output_section::Input_section::set_address(uint64_t addr, off_t off,
this->u2_.posd->set_address(addr, off);
}
// Try to turn an input address into an output address.
// Try to turn an input offset into an output offset.
bool
Output_section::Input_section::output_address(const Relobj* object,
unsigned int shndx,
off_t offset,
uint64_t output_section_address,
uint64_t *poutput) const
Output_section::Input_section::output_offset(const Relobj* object,
unsigned int shndx,
off_t offset,
off_t *poutput) const
{
if (!this->is_input_section())
return this->u2_.posd->output_address(object, shndx, offset,
output_section_address, poutput);
return this->u2_.posd->output_offset(object, shndx, offset, poutput);
else
{
if (this->shndx_ != shndx
|| this->u2_.object != object)
if (this->shndx_ != shndx || this->u2_.object != object)
return false;
off_t output_offset;
Output_section* os = object->output_section(shndx, &output_offset);
gold_assert(os != NULL);
*poutput = output_section_address + output_offset + offset;
gold_assert(output_offset != -1);
*poutput = output_offset + offset;
return true;
}
}
@ -1001,7 +1014,8 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
needs_symtab_index_(false),
needs_dynsym_index_(false),
should_link_to_symtab_(false),
should_link_to_dynsym_(false)
should_link_to_dynsym_(false),
after_input_sections_(false)
{
}
@ -1021,16 +1035,22 @@ Output_section::set_entsize(uint64_t v)
}
// Add the input section SHNDX, with header SHDR, named SECNAME, in
// OBJECT, to the Output_section. Return the offset of the input
// section within the output section. We don't always keep track of
// input sections for an Output_section. Instead, each Object keeps
// track of the Output_section for each of its input sections.
// OBJECT, to the Output_section. RELOC_SHNDX is the index of a
// relocation section which applies to this section, or 0 if none, or
// -1U if more than one. Return the offset of the input section
// within the output section. Return -1 if the input section will
// receive special handling. In the normal case we don't always keep
// track of input sections for an Output_section. Instead, each
// Object keeps track of the Output_section for each of its input
// sections.
template<int size, bool big_endian>
off_t
Output_section::add_input_section(Relobj* object, unsigned int shndx,
Output_section::add_input_section(Sized_relobj<size, big_endian>* object,
unsigned int shndx,
const char* secname,
const elfcpp::Shdr<size, big_endian>& shdr)
const elfcpp::Shdr<size, big_endian>& shdr,
unsigned int reloc_shndx)
{
elfcpp::Elf_Xword addralign = shdr.get_sh_addralign();
if ((addralign & (addralign - 1)) != 0)
@ -1044,15 +1064,17 @@ Output_section::add_input_section(Relobj* object, unsigned int shndx,
this->addralign_ = addralign;
// If this is a SHF_MERGE section, we pass all the input sections to
// a Output_data_merge.
if ((shdr.get_sh_flags() & elfcpp::SHF_MERGE) != 0)
// a Output_data_merge. We don't try to handle relocations for such
// a section.
if ((shdr.get_sh_flags() & elfcpp::SHF_MERGE) != 0
&& reloc_shndx == 0)
{
if (this->add_merge_input_section(object, shndx, shdr.get_sh_flags(),
shdr.get_sh_entsize(),
addralign))
{
// Tell the relocation routines that they need to call the
// output_address method to determine the final address.
// output_offset method to determine the final address.
return -1;
}
}
@ -1176,6 +1198,57 @@ Output_section::add_merge_input_section(Relobj* object, unsigned int shndx,
return true;
}
// Given an address OFFSET relative to the start of input section
// SHNDX in OBJECT, return whether this address is being included in
// the final link. This should only be called if SHNDX in OBJECT has
// a special mapping.
bool
Output_section::is_input_address_mapped(const Relobj* object,
unsigned int shndx,
off_t offset) const
{
gold_assert(object->is_section_specially_mapped(shndx));
for (Input_section_list::const_iterator p = this->input_sections_.begin();
p != this->input_sections_.end();
++p)
{
off_t output_offset;
if (p->output_offset(object, shndx, offset, &output_offset))
return output_offset != -1;
}
// By default we assume that the address is mapped. This should
// only be called after we have passed all sections to Layout. At
// that point we should know what we are discarding.
return true;
}
// Given an address OFFSET relative to the start of input section
// SHNDX in object OBJECT, return the output offset relative to the
// start of the section. This should only be called if SHNDX in
// OBJECT has a special mapping.
off_t
Output_section::output_offset(const Relobj* object, unsigned int shndx,
off_t offset) const
{
gold_assert(object->is_section_specially_mapped(shndx));
// This can only be called meaningfully when layout is complete.
gold_assert(Output_data::is_layout_complete());
for (Input_section_list::const_iterator p = this->input_sections_.begin();
p != this->input_sections_.end();
++p)
{
off_t output_offset;
if (p->output_offset(object, shndx, offset, &output_offset))
return output_offset;
}
gold_unreachable();
}
// Return the output virtual address of OFFSET relative to the start
// of input section SHNDX in object OBJECT.
@ -1183,15 +1256,23 @@ uint64_t
Output_section::output_address(const Relobj* object, unsigned int shndx,
off_t offset) const
{
gold_assert(object->is_section_specially_mapped(shndx));
// This can only be called meaningfully when layout is complete.
gold_assert(Output_data::is_layout_complete());
uint64_t addr = this->address() + this->first_input_offset_;
for (Input_section_list::const_iterator p = this->input_sections_.begin();
p != this->input_sections_.end();
++p)
{
addr = align_address(addr, p->addralign());
uint64_t output;
if (p->output_address(object, shndx, offset, addr, &output))
return output;
off_t output_offset;
if (p->output_offset(object, shndx, offset, &output_offset))
{
if (output_offset == -1)
return -1U;
return addr + output_offset;
}
addr += p->data_size();
}
@ -1739,40 +1820,44 @@ Output_file::close()
template
off_t
Output_section::add_input_section<32, false>(
Relobj* object,
Sized_relobj<32, false>* object,
unsigned int shndx,
const char* secname,
const elfcpp::Shdr<32, false>& shdr);
const elfcpp::Shdr<32, false>& shdr,
unsigned int reloc_shndx);
#endif
#ifdef HAVE_TARGET_32_BIG
template
off_t
Output_section::add_input_section<32, true>(
Relobj* object,
Sized_relobj<32, true>* object,
unsigned int shndx,
const char* secname,
const elfcpp::Shdr<32, true>& shdr);
const elfcpp::Shdr<32, true>& shdr,
unsigned int reloc_shndx);
#endif
#ifdef HAVE_TARGET_64_LITTLE
template
off_t
Output_section::add_input_section<64, false>(
Relobj* object,
Sized_relobj<64, false>* object,
unsigned int shndx,
const char* secname,
const elfcpp::Shdr<64, false>& shdr);
const elfcpp::Shdr<64, false>& shdr,
unsigned int reloc_shndx);
#endif
#ifdef HAVE_TARGET_64_BIG
template
off_t
Output_section::add_input_section<64, true>(
Relobj* object,
Sized_relobj<64, true>* object,
unsigned int shndx,
const char* secname,
const elfcpp::Shdr<64, true>& shdr);
const elfcpp::Shdr<64, true>& shdr,
unsigned int reloc_shndx);
#endif
#ifdef HAVE_TARGET_32_LITTLE

View File

@ -29,7 +29,6 @@
#include "elfcpp.h"
#include "layout.h"
#include "reloc-types.h"
#include "parameters.h"
namespace gold
{
@ -124,6 +123,11 @@ class Output_data
layout_complete()
{ Output_data::sizes_are_fixed = true; }
// Used to check that layout has been done.
static bool
is_layout_complete()
{ return Output_data::sizes_are_fixed; }
protected:
// Functions that child classes may or in some cases must implement.
@ -179,9 +183,13 @@ class Output_data
this->data_size_ = data_size;
}
// Return default alignment for a size--32 or 64.
// Return default alignment for the target size.
static uint64_t
default_alignment(int size);
default_alignment();
// Return default alignment for a specified size--32 or 64.
static uint64_t
default_alignment_for_size(int size);
private:
Output_data(const Output_data&);
@ -216,7 +224,7 @@ class Output_section_headers : public Output_data
// Return the required alignment.
uint64_t
do_addralign() const
{ return Output_data::default_alignment(parameters->get_size()); }
{ return Output_data::default_alignment(); }
private:
// Write the data to the file with the right size and endianness.
@ -244,7 +252,7 @@ class Output_segment_headers : public Output_data
// Return the required alignment.
uint64_t
do_addralign() const
{ return Output_data::default_alignment(parameters->get_size()); }
{ return Output_data::default_alignment(); }
private:
// Write the data to the file with the right size and endianness.
@ -276,7 +284,7 @@ class Output_file_header : public Output_data
// Return the required alignment.
uint64_t
do_addralign() const
{ return Output_data::default_alignment(parameters->get_size()); }
{ return Output_data::default_alignment(); }
// Set the address and offset--we only implement this for error
// checking.
@ -330,17 +338,14 @@ class Output_section_data : public Output_data
// 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 output address is known.
// OUTPUT_SECTION_ADDRESS is the address of the output section which
// this is a part of. If this function returns true, it sets
// *POUTPUT to the output address.
// section, return whether or not the corresponding offset within
// the output section is known. If this function returns true, it
// sets *POUTPUT to the output offset. The value -1 indicates that
// this input offset is being discarded.
virtual bool
output_address(const Relobj* object, unsigned int shndx, off_t offset,
uint64_t output_section_address, uint64_t *poutput) const
{
return this->do_output_address(object, shndx, offset,
output_section_address, poutput);
}
output_offset(const Relobj* object, unsigned int shndx, off_t offset,
off_t *poutput) const
{ return this->do_output_offset(object, shndx, offset, poutput); }
protected:
// The child class must implement do_write.
@ -357,10 +362,9 @@ class Output_section_data : public Output_data
do_add_input_section(Relobj*, unsigned int)
{ gold_unreachable(); }
// The child class may implement output_address.
// The child class may implement output_offset.
virtual bool
do_output_address(const Relobj*, unsigned int, off_t, uint64_t,
uint64_t*) const
do_output_offset(const Relobj*, unsigned int, off_t, off_t*) const
{ return false; }
// Return the required alignment.
@ -736,7 +740,7 @@ class Output_data_reloc_base : public Output_section_data
// Construct the section.
Output_data_reloc_base()
: Output_section_data(Output_data::default_alignment(size))
: Output_section_data(Output_data::default_alignment_for_size(size))
{ }
// Write out the data.
@ -901,7 +905,8 @@ class Output_data_got : public Output_section_data
typedef typename elfcpp::Elf_types<size>::Elf_Addr Valtype;
Output_data_got()
: Output_section_data(Output_data::default_alignment(size)), entries_()
: Output_section_data(Output_data::default_alignment_for_size(size)),
entries_()
{ }
// Add an entry for a global symbol to the GOT. Return true if this
@ -1013,8 +1018,7 @@ class Output_data_dynamic : public Output_section_data
{
public:
Output_data_dynamic(Stringpool* pool)
: Output_section_data(Output_data::default_alignment(
parameters->get_size())),
: Output_section_data(Output_data::default_alignment()),
entries_(), pool_(pool)
{ }
@ -1155,11 +1159,15 @@ class Output_section : public Output_data
virtual ~Output_section();
// Add a new input section SHNDX, named NAME, with header SHDR, from
// object OBJECT. Return the offset within the output section.
// object OBJECT. RELOC_SHNDX is the index of a relocation section
// which applies to this section, or 0 if none, or -1U if more than
// one. Return the offset within the output section.
template<int size, bool big_endian>
off_t
add_input_section(Relobj* object, unsigned int shndx, const char *name,
const elfcpp::Shdr<size, big_endian>& shdr);
add_input_section(Sized_relobj<size, big_endian>* object, unsigned int shndx,
const char *name,
const elfcpp::Shdr<size, big_endian>& shdr,
unsigned int reloc_shndx);
// Add generated data POSD to this output section.
void
@ -1326,6 +1334,29 @@ class Output_section : public Output_data
this->dynsym_index_ = index;
}
// Return whether this section should be written after all the input
// sections are complete.
bool
after_input_sections() const
{ return this->after_input_sections_; }
// Record that this section should be written after all the input
// sections are complete.
void
set_after_input_sections()
{ this->after_input_sections_ = true; }
// Return whether the offset OFFSET in the input section SHNDX in
// object OBJECT is being included in the link.
bool
is_input_address_mapped(const Relobj* object, unsigned int shndx,
off_t offset) const;
// Return the offset within the output section of OFFSET relative to
// the start of input section SHNDX in object OBJECT.
off_t
output_offset(const Relobj* object, unsigned int shndx, off_t offset) const;
// Return the output virtual address of OFFSET relative to the start
// of input section SHNDX in object OBJECT.
uint64_t
@ -1477,13 +1508,12 @@ class Output_section : public Output_data
// 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 output address is known.
// OUTPUT_SECTION_ADDRESS is the address of the output section
// which this is a part of. If this function returns true, it
// sets *POUTPUT to the output address.
// section, return whether or not the output offset is known. If
// this function returns true, it sets *POUTPUT to the output
// offset.
bool
output_address(const Relobj* object, unsigned int shndx, off_t offset,
uint64_t output_section_address, uint64_t *poutput) const;
output_offset(const Relobj* object, unsigned int shndx, off_t offset,
off_t *poutput) const;
// Write out the data. This does nothing for an input section.
void
@ -1648,6 +1678,9 @@ class Output_section : public Output_data
// Whether the link field of this output section should point to the
// dynamic symbol table.
bool should_link_to_dynsym_ : 1;
// Whether this section should be written after all the input
// sections are complete.
bool after_input_sections_ : 1;
};
// An output segment. PT_LOAD segments are built from collections of
@ -1847,6 +1880,28 @@ class Output_file
write_output_view(off_t, off_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, off_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, off_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, off_t size)
{ return this->get_output_view(start, size); }
// Release a read bfufer.
void
free_input_view(off_t, off_t, const unsigned char*)
{ }
private:
// General options.
const General_options& options_;

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2007-11-02 16:01-0700\n"
"POT-Creation-Date: 2007-11-08 22:56-0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -66,110 +66,110 @@ msgstr ""
msgid "%s: can not read directory: %s"
msgstr ""
#: dynobj.cc:128
#: dynobj.cc:151
#, c-format
msgid "unexpected duplicate type %u section: %u, %u"
msgstr ""
#: dynobj.cc:164
#: dynobj.cc:187
#, c-format
msgid "unexpected link in section %u header: %u != %u"
msgstr ""
#: dynobj.cc:199
#: dynobj.cc:222
#, c-format
msgid "DYNAMIC section %u link out of range: %u"
msgstr ""
#: dynobj.cc:207
#: dynobj.cc:230
#, c-format
msgid "DYNAMIC section %u link %u is not a strtab"
msgstr ""
#: dynobj.cc:227
#: dynobj.cc:250
#, c-format
msgid "DT_SONAME value out of range: %lld >= %lld"
msgstr ""
#: dynobj.cc:242
#: dynobj.cc:265
msgid "missing DT_NULL in dynamic segment"
msgstr ""
#: dynobj.cc:285
#: dynobj.cc:309
#, c-format
msgid "invalid dynamic symbol table name index: %u"
msgstr ""
#: dynobj.cc:292
#: dynobj.cc:316
#, c-format
msgid "dynamic symbol table name section has wrong type: %u"
msgstr ""
#: dynobj.cc:365 object.cc:447
#: dynobj.cc:389 object.cc:233 object.cc:568
#, c-format
msgid "bad section name offset for section %u: %lu"
msgstr ""
#: dynobj.cc:394
#: dynobj.cc:418
#, c-format
msgid "duplicate definition for version %u"
msgstr ""
#: dynobj.cc:423
#: dynobj.cc:447
#, c-format
msgid "unexpected verdef version %u"
msgstr ""
#: dynobj.cc:439
#: dynobj.cc:463
#, c-format
msgid "verdef vd_cnt field too small: %u"
msgstr ""
#: dynobj.cc:446
#: dynobj.cc:470
#, c-format
msgid "verdef vd_aux field out of range: %u"
msgstr ""
#: dynobj.cc:456
#: dynobj.cc:480
#, c-format
msgid "verdaux vda_name field out of range: %u"
msgstr ""
#: dynobj.cc:465
#: dynobj.cc:489
#, c-format
msgid "verdef vd_next field out of range: %u"
msgstr ""
#: dynobj.cc:498
#: dynobj.cc:522
#, c-format
msgid "unexpected verneed version %u"
msgstr ""
#: dynobj.cc:507
#: dynobj.cc:531
#, c-format
msgid "verneed vn_aux field out of range: %u"
msgstr ""
#: dynobj.cc:520
#: dynobj.cc:544
#, c-format
msgid "vernaux vna_name field out of range: %u"
msgstr ""
#: dynobj.cc:531
#: dynobj.cc:555
#, c-format
msgid "verneed vna_next field out of range: %u"
msgstr ""
#: dynobj.cc:542
#: dynobj.cc:566
#, c-format
msgid "verneed vn_next field out of range: %u"
msgstr ""
#: dynobj.cc:588
#: dynobj.cc:613
msgid "size of dynamic symbols is not multiple of symbol size"
msgstr ""
#: dynobj.cc:1265
#: dynobj.cc:1290
#, c-format
msgid "symbol %s has undefined version %s"
msgstr ""
@ -317,54 +317,54 @@ msgid "pthread_cond_signal failed: %s"
msgstr ""
#. FIXME: This needs to specify the location somehow.
#: i386.cc:150 i386.cc:1296 x86_64.cc:162 x86_64.cc:1228
#: i386.cc:153 i386.cc:1301 x86_64.cc:165 x86_64.cc:1233
msgid "missing expected TLS relocation"
msgstr ""
#: i386.cc:746 x86_64.cc:709 x86_64.cc:876
#: i386.cc:749 x86_64.cc:712 x86_64.cc:879
#, c-format
msgid "%s: unsupported reloc %u against local symbol"
msgstr ""
#: i386.cc:840 i386.cc:1070 x86_64.cc:817 x86_64.cc:1055
#: i386.cc:843 i386.cc:1073 x86_64.cc:820 x86_64.cc:1058
#, c-format
msgid "%s: unexpected reloc %u in object file"
msgstr ""
#: i386.cc:926 x86_64.cc:890 x86_64.cc:1114
#: i386.cc:929 x86_64.cc:893 x86_64.cc:1117
#, c-format
msgid "%s: unsupported reloc %u against global symbol %s"
msgstr ""
#: i386.cc:1166
#: i386.cc:1170
#, c-format
msgid "%s: unsupported RELA reloc section"
msgstr ""
#: i386.cc:1423 x86_64.cc:1426
#: i386.cc:1428 x86_64.cc:1431
#, c-format
msgid "unexpected reloc %u in object file"
msgstr ""
#: i386.cc:1455 i386.cc:1502 i386.cc:1509 i386.cc:1529 i386.cc:1558
#: x86_64.cc:1447 x86_64.cc:1496 x86_64.cc:1507
#: i386.cc:1460 i386.cc:1507 i386.cc:1514 i386.cc:1534 i386.cc:1563
#: x86_64.cc:1452 x86_64.cc:1501 x86_64.cc:1512
#, c-format
msgid "unsupported reloc %u"
msgstr ""
#: i386.cc:1480 x86_64.cc:1472
#: i386.cc:1485 x86_64.cc:1477
msgid "TLS reloc but no TLS segment"
msgstr ""
#: i386.cc:1517
#: i386.cc:1522
msgid "both SUN and GNU model TLS relocations"
msgstr ""
#: merge.cc:258
#: merge.cc:283
msgid "mergeable string section length not multiple of character size"
msgstr ""
#: merge.cc:274
#: merge.cc:299
msgid "entry in mergeable string section not null terminated"
msgstr ""
@ -383,112 +383,117 @@ msgstr ""
msgid "section name section has wrong type: %u"
msgstr ""
#: object.cc:244
#: object.cc:305
#, c-format
msgid "invalid symbol table name index: %u"
msgstr ""
#: object.cc:250
#: object.cc:311
#, c-format
msgid "symbol table name section has wrong type: %u"
msgstr ""
#: object.cc:305
#: object.cc:391
#, c-format
msgid "section group %u info %u out of range"
msgstr ""
#: object.cc:323
#: object.cc:409
#, c-format
msgid "symbol %u name offset %u out of range"
msgstr ""
#: object.cc:355
#: object.cc:441
#, c-format
msgid "section %u in section group %u out of range"
msgstr ""
#: object.cc:525
#: object.cc:531 reloc.cc:202 reloc.cc:469
#, c-format
msgid "relocation section %u has bad info %u"
msgstr ""
#: object.cc:703
msgid "size of symbols is not multiple of symbol size"
msgstr ""
#. FIXME: Handle SHN_XINDEX.
#: object.cc:615
#: object.cc:795
#, c-format
msgid "unknown section index %u for local symbol %u"
msgstr ""
#: object.cc:624
#: object.cc:804
#, c-format
msgid "local symbol %u section index %u out of range"
msgstr ""
#: object.cc:656
#: object.cc:836
#, c-format
msgid "local symbol %u section name out of range: %u >= %u"
msgstr ""
#: object.cc:892
#: object.cc:1054
#, c-format
msgid "%s: incompatible target"
msgstr ""
#: object.cc:994
#: object.cc:1175
#, c-format
msgid "%s: unsupported ELF file type %d"
msgstr ""
#: object.cc:1013 object.cc:1059 object.cc:1093
#: object.cc:1194 object.cc:1240 object.cc:1274
#, c-format
msgid "%s: ELF file too short"
msgstr ""
#: object.cc:1021
#: object.cc:1202
#, c-format
msgid "%s: invalid ELF version 0"
msgstr ""
#: object.cc:1023
#: object.cc:1204
#, c-format
msgid "%s: unsupported ELF version %d"
msgstr ""
#: object.cc:1030
#: object.cc:1211
#, c-format
msgid "%s: invalid ELF class 0"
msgstr ""
#: object.cc:1036
#: object.cc:1217
#, c-format
msgid "%s: unsupported ELF class %d"
msgstr ""
#: object.cc:1043
#: object.cc:1224
#, c-format
msgid "%s: invalid ELF data encoding"
msgstr ""
#: object.cc:1049
#: object.cc:1230
#, c-format
msgid "%s: unsupported ELF data encoding %d"
msgstr ""
#: object.cc:1069
#: object.cc:1250
#, c-format
msgid "%s: not configured to support 32-bit big-endian object"
msgstr ""
#: object.cc:1082
#: object.cc:1263
#, c-format
msgid "%s: not configured to support 32-bit little-endian object"
msgstr ""
#: object.cc:1103
#: object.cc:1284
#, c-format
msgid "%s: not configured to support 64-bit big-endian object"
msgstr ""
#: object.cc:1116
#: object.cc:1297
#, c-format
msgid "%s: not configured to support 64-bit little-endian object"
msgstr ""
@ -772,37 +777,37 @@ msgstr ""
msgid "%s: invalid thread count: %s\n"
msgstr ""
#: output.cc:1038
#: output.cc:1058
#, c-format
msgid "invalid alignment %lu for section \"%s\""
msgstr ""
#: output.cc:1703
#: output.cc:1784
#, c-format
msgid "%s: open: %s"
msgstr ""
#: output.cc:1708
#: output.cc:1789
#, c-format
msgid "%s: lseek: %s"
msgstr ""
#: output.cc:1711
#: output.cc:1792
#, c-format
msgid "%s: write: %s"
msgstr ""
#: output.cc:1717
#: output.cc:1798
#, c-format
msgid "%s: mmap: %s"
msgstr ""
#: output.cc:1727
#: output.cc:1808
#, c-format
msgid "%s: munmap: %s"
msgstr ""
#: output.cc:1731
#: output.cc:1812
#, c-format
msgid "%s: close: %s"
msgstr ""
@ -823,26 +828,26 @@ msgstr ""
msgid "%s: not an object or archive"
msgstr ""
#: reloc.cc:190 reloc.cc:431
#, c-format
msgid "relocation section %u has bad info %u"
msgstr ""
#: reloc.cc:208 reloc.cc:447
#: reloc.cc:221 reloc.cc:487
#, c-format
msgid "relocation section %u uses unexpected symbol table %u"
msgstr ""
#: reloc.cc:223 reloc.cc:465
#: reloc.cc:236 reloc.cc:505
#, c-format
msgid "unexpected entsize for reloc section %u: %lu != %u"
msgstr ""
#: reloc.cc:232 reloc.cc:474
#: reloc.cc:245 reloc.cc:514
#, c-format
msgid "reloc section %u size %lu uneven"
msgstr ""
#: reloc.cc:702
#, c-format
msgid "reloc section size %zu is not a multiple of reloc size %d\n"
msgstr ""
#: resolve.cc:165
#, c-format
msgid "%s: invalid STB_LOCAL symbol %s in external symbols"
@ -907,7 +912,7 @@ msgstr ""
msgid "%s: unsupported symbol section 0x%x"
msgstr ""
#: target-reloc.h:191
#: target-reloc.h:211
#, c-format
msgid "reloc has bad offset %zu"
msgstr ""
@ -935,12 +940,12 @@ msgid ""
"This program has absolutely no warranty.\n"
msgstr ""
#: x86_64.cc:1137
#: x86_64.cc:1141
#, c-format
msgid "%s: unsupported REL reloc section"
msgstr ""
#: x86_64.cc:1535
#: x86_64.cc:1540
#, c-format
msgid "unsupported reloc type %u"
msgstr ""

View File

@ -116,34 +116,44 @@ Scan_relocs::run(Workqueue*)
// Relocate_task methods.
// These tasks are always runnable.
// We may have to wait for the output sections to be written.
Task::Is_runnable_type
Relocate_task::is_runnable(Workqueue*)
{
if (this->object_->relocs_must_follow_section_writes()
&& this->output_sections_blocker_->is_blocked())
return IS_BLOCKED;
return IS_RUNNABLE;
}
// We want to lock the file while we run. We want to unblock
// FINAL_BLOCKER when we are done.
// INPUT_SECTIONS_BLOCKER and FINAL_BLOCKER when we are done.
class Relocate_task::Relocate_locker : public Task_locker
{
public:
Relocate_locker(Task_token& token, Workqueue* workqueue,
Relocate_locker(Task_token& input_sections_blocker,
Task_token& final_blocker, Workqueue* workqueue,
Object* object)
: blocker_(token, workqueue), objlock_(*object)
: input_sections_blocker_(input_sections_blocker, workqueue),
final_blocker_(final_blocker, workqueue),
objlock_(*object)
{ }
private:
Task_locker_block blocker_;
Task_block_token input_sections_blocker_;
Task_block_token final_blocker_;
Task_locker_obj<Object> objlock_;
};
Task_locker*
Relocate_task::locks(Workqueue* workqueue)
{
return new Relocate_locker(*this->final_blocker_, workqueue,
return new Relocate_locker(*this->input_sections_blocker_,
*this->final_blocker_,
workqueue,
this->object_);
}
@ -171,6 +181,8 @@ Sized_relobj<size, big_endian>::do_read_relocs(Read_relocs_data* rd)
rd->relocs.reserve(shnum / 2);
std::vector<Map_to_output>& map_sections(this->map_to_output());
const unsigned char *pshdrs = this->get_view(this->elf_file_.shoff(),
shnum * This::shdr_size,
true);
@ -192,7 +204,8 @@ Sized_relobj<size, big_endian>::do_read_relocs(Read_relocs_data* rd)
continue;
}
if (!this->is_section_included(shndx))
Output_section* os = map_sections[shndx].output_section;
if (os == NULL)
continue;
// We are scanning relocations in order to fill out the GOT and
@ -242,6 +255,8 @@ Sized_relobj<size, big_endian>::do_read_relocs(Read_relocs_data* rd)
true);
sr.sh_type = sh_type;
sr.reloc_count = reloc_count;
sr.output_section = os;
sr.needs_special_offset_handling = map_sections[shndx].offset == -1;
}
// Read the local symbols.
@ -286,9 +301,9 @@ Sized_relobj<size, big_endian>::do_scan_relocs(const General_options& options,
{
target->scan_relocs(options, symtab, layout, this, p->data_shndx,
p->sh_type, p->contents->data(), p->reloc_count,
p->output_section, p->needs_special_offset_handling,
this->local_symbol_count_,
local_symbols,
this->symbols_);
local_symbols);
delete p->contents;
p->contents = NULL;
}
@ -333,8 +348,14 @@ Sized_relobj<size, big_endian>::do_relocate(const General_options& options,
for (unsigned int i = 1; i < shnum; ++i)
{
if (views[i].view != NULL)
of->write_output_view(views[i].offset, views[i].view_size,
views[i].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);
}
}
// Write out the local symbols.
@ -361,34 +382,52 @@ Sized_relobj<size, big_endian>::write_sections(const unsigned char* pshdrs,
pvs->view = NULL;
if (map_sections[i].offset == -1)
continue;
const Output_section* os = map_sections[i].output_section;
if (os == NULL)
continue;
off_t output_offset = map_sections[i].offset;
typename This::Shdr shdr(p);
if (shdr.get_sh_type() == elfcpp::SHT_NOBITS)
continue;
off_t start = os->offset() + map_sections[i].offset;
off_t sh_size = shdr.get_sh_size();
off_t view_start;
off_t view_size;
if (output_offset != -1)
{
view_start = os->offset() + output_offset;
view_size = shdr.get_sh_size();
}
else
{
view_start = os->offset();
view_size = os->data_size();
}
if (sh_size == 0)
if (view_size == 0)
continue;
gold_assert(map_sections[i].offset >= 0
&& map_sections[i].offset + sh_size <= os->data_size());
gold_assert(output_offset == -1
|| (output_offset >= 0
&& output_offset + view_size <= os->data_size()));
unsigned char* view = of->get_output_view(start, sh_size);
this->read(shdr.get_sh_offset(), sh_size, view);
unsigned char* 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;
pvs->address = os->address() + map_sections[i].offset;
pvs->offset = start;
pvs->view_size = sh_size;
pvs->address = os->address();
if (output_offset != -1)
pvs->address += output_offset;
pvs->offset = view_start;
pvs->view_size = view_size;
pvs->is_input_output_view = output_offset == -1;
}
}
@ -407,14 +446,13 @@ Sized_relobj<size, big_endian>::relocate_sections(
unsigned int shnum = this->shnum();
Sized_target<size, big_endian>* target = this->sized_target();
std::vector<Map_to_output>& map_sections(this->map_to_output());
Relocate_info<size, big_endian> relinfo;
relinfo.options = &options;
relinfo.symtab = symtab;
relinfo.layout = layout;
relinfo.object = this;
relinfo.local_symbol_count = this->local_symbol_count_;
relinfo.local_values = &this->local_values_;
relinfo.symbols = this->symbols_;
const unsigned char* p = pshdrs + This::shdr_size;
for (unsigned int i = 1; i < shnum; ++i, p += This::shdr_size)
@ -433,12 +471,14 @@ Sized_relobj<size, big_endian>::relocate_sections(
continue;
}
if (!this->is_section_included(index))
Output_section* os = map_sections[index].output_section;
if (os == NULL)
{
// This relocation section is against a section which we
// discarded.
continue;
}
off_t output_offset = map_sections[index].offset;
gold_assert((*pviews)[index].view != NULL);
@ -464,7 +504,7 @@ Sized_relobj<size, big_endian>::relocate_sections(
{
gold_error(_("unexpected entsize for reloc section %u: %lu != %u"),
i, static_cast<unsigned long>(shdr.get_sh_entsize()),
reloc_size);
reloc_size);
continue;
}
@ -482,6 +522,8 @@ Sized_relobj<size, big_endian>::relocate_sections(
sh_type,
prelocs,
reloc_count,
os,
output_offset == -1,
(*pviews)[index].view,
(*pviews)[index].address,
(*pviews)[index].view_size);
@ -621,6 +663,104 @@ Copy_relocs<size, big_endian>::emit(
}
}
// Track_relocs methods.
// Initialize the class to track the relocs. This gets the object,
// the reloc section index, and the type of the relocs. This returns
// false if something goes wrong.
template<int size, bool big_endian>
bool
Track_relocs<size, big_endian>::initialize(
Sized_relobj<size, big_endian>* object,
unsigned int reloc_shndx,
unsigned int reloc_type)
{
this->object_ = object;
// If RELOC_SHNDX is -1U, it means there is more than one reloc
// section for the .eh_frame section. We can't handle that case.
if (reloc_shndx == -1U)
return false;
// If RELOC_SHNDX is 0, there is no reloc section.
if (reloc_shndx == 0)
return true;
// Get the contents of the reloc section.
this->prelocs_ = object->section_contents(reloc_shndx, &this->len_, false);
if (reloc_type == elfcpp::SHT_REL)
this->reloc_size_ = elfcpp::Elf_sizes<size>::rel_size;
else if (reloc_type == elfcpp::SHT_RELA)
this->reloc_size_ = elfcpp::Elf_sizes<size>::rela_size;
else
gold_unreachable();
if (this->len_ % this->reloc_size_ != 0)
{
object->error(_("reloc section size %zu is not a multiple of "
"reloc size %d\n"),
static_cast<size_t>(this->len_),
this->reloc_size_);
return false;
}
return true;
}
// Return the offset of the next reloc, or -1 if there isn't one.
template<int size, bool big_endian>
off_t
Track_relocs<size, big_endian>::next_offset() const
{
if (this->pos_ >= this->len_)
return -1;
// Rel and Rela start out the same, so we can always use Rel to find
// the r_offset value.
elfcpp::Rel<size, big_endian> rel(this->prelocs_ + this->pos_);
return rel.get_r_offset();
}
// Return the index of the symbol referenced by the next reloc, or -1U
// if there aren't any more relocs.
template<int size, bool big_endian>
unsigned int
Track_relocs<size, big_endian>::next_symndx() const
{
if (this->pos_ >= this->len_)
return -1U;
// Rel and Rela start out the same, so we can use Rel to find the
// symbol index.
elfcpp::Rel<size, big_endian> rel(this->prelocs_ + this->pos_);
return elfcpp::elf_r_sym<size>(rel.get_r_info());
}
// Advance to the next reloc whose r_offset is greater than or equal
// to OFFSET. Return the number of relocs we skip.
template<int size, bool big_endian>
int
Track_relocs<size, big_endian>::advance(off_t offset)
{
int ret = 0;
while (this->pos_ < this->len_)
{
// Rel and Rela start out the same, so we can always use Rel to
// find the r_offset value.
elfcpp::Rel<size, big_endian> rel(this->prelocs_ + this->pos_);
if (static_cast<off_t>(rel.get_r_offset()) >= offset)
break;
++ret;
this->pos_ += this->reloc_size_;
}
return ret;
}
// Instantiate the templates we need. We could use the configure
// script to restrict this to only the ones for implemented targets.
@ -796,4 +936,24 @@ Copy_relocs<64, true>::emit<elfcpp::SHT_RELA>(
Output_data_reloc<elfcpp::SHT_RELA, true, 64, true>*);
#endif
#ifdef HAVE_TARGET_32_LITTLE
template
class Track_relocs<32, false>;
#endif
#ifdef HAVE_TARGET_32_BIG
template
class Track_relocs<32, true>;
#endif
#ifdef HAVE_TARGET_64_LITTLE
template
class Track_relocs<64, false>;
#endif
#ifdef HAVE_TARGET_64_BIG
template
class Track_relocs<64, true>;
#endif
} // End namespace gold.

View File

@ -129,9 +129,12 @@ class Relocate_task : public Task
public:
Relocate_task(const General_options& options, const Symbol_table* symtab,
const Layout* layout, Relobj* object, Output_file* of,
Task_token* final_blocker)
Task_token* input_sections_blocker,
Task_token* output_sections_blocker, Task_token* final_blocker)
: options_(options), symtab_(symtab), layout_(layout), object_(object),
of_(of), final_blocker_(final_blocker)
of_(of), input_sections_blocker_(input_sections_blocker),
output_sections_blocker_(output_sections_blocker),
final_blocker_(final_blocker)
{ }
// The standard Task methods.
@ -153,6 +156,8 @@ class Relocate_task : public Task
const Layout* layout_;
Relobj* object_;
Output_file* of_;
Task_token* input_sections_blocker_;
Task_token* output_sections_blocker_;
Task_token* final_blocker_;
};
@ -594,6 +599,55 @@ class Copy_relocs
Copy_reloc_entries entries_;
};
// Track relocations while reading a section. This lets you ask for
// the relocation at a certain offset, and see how relocs occur
// between points of interest.
template<int size, bool big_endian>
class Track_relocs
{
public:
Track_relocs()
: object_(NULL), prelocs_(NULL), len_(0), pos_(0), reloc_size_(0)
{ }
// Initialize the Track_relocs object. OBJECT is the object holding
// the reloc section, RELOC_SHNDX is the section index of the reloc
// section, and RELOC_TYPE is the type of the reloc section
// (elfcpp::SHT_REL or elfcpp::SHT_RELA). This returns false if
// something went wrong.
bool
initialize(Sized_relobj<size, big_endian>* object, unsigned int reloc_shndx,
unsigned int reloc_type);
// Return the offset in the data section to which the next reloc
// applies. THis returns -1 if there is no next reloc.
off_t
next_offset() const;
// Return the symbol index of the next reloc. This returns -1U if
// there is no next reloc.
unsigned int
next_symndx() const;
// Advance to OFFSET within the data section, and return the number
// of relocs which would be skipped.
int
advance(off_t offset);
private:
// The object file.
Sized_relobj<size, big_endian>* object_;
// The contents of the reloc section.
const unsigned char* prelocs_;
// The length of the reloc section.
off_t len_;
// Our current position in the reloc section.
off_t pos_;
// The size of the relocs in the section.
int reloc_size_;
};
} // End namespace gold.
#endif // !defined(GOLD_RELOC_H)

View File

@ -103,7 +103,7 @@ Stringpool_template<Stringpool_char>::Stringpool_hash::operator()(
const Stringpool_char* s) const
{
// Fowler/Noll/Vo (FNV) hash (type FNV-1a).
if (sizeof(size_t) == 8)
if (sizeof(size_t) > 4)
{
size_t result = static_cast<size_t>(14695981039346656037ULL);
while (*s != 0)

View File

@ -521,7 +521,7 @@ Symbol_table::add_from_relobj(
size_t count,
const char* sym_names,
size_t sym_name_size,
Symbol** sympointers)
typename Sized_relobj<size, big_endian>::Symbols* sympointers)
{
gold_assert(size == relobj->target()->get_size());
gold_assert(size == parameters->get_size());
@ -592,7 +592,7 @@ Symbol_table::add_from_relobj(
def, *psym);
}
*sympointers++ = res;
(*sympointers)[i] = res;
}
}
@ -1870,7 +1870,7 @@ Symbol_table::add_from_relobj<32, false>(
size_t count,
const char* sym_names,
size_t sym_name_size,
Symbol** sympointers);
Sized_relobj<32, true>::Symbols* sympointers);
#endif
#ifdef HAVE_TARGET_32_BIG
@ -1882,7 +1882,7 @@ Symbol_table::add_from_relobj<32, true>(
size_t count,
const char* sym_names,
size_t sym_name_size,
Symbol** sympointers);
Sized_relobj<32, false>::Symbols* sympointers);
#endif
#ifdef HAVE_TARGET_64_LITTLE
@ -1894,7 +1894,7 @@ Symbol_table::add_from_relobj<64, false>(
size_t count,
const char* sym_names,
size_t sym_name_size,
Symbol** sympointers);
Sized_relobj<64, true>::Symbols* sympointers);
#endif
#ifdef HAVE_TARGET_64_BIG
@ -1906,7 +1906,7 @@ Symbol_table::add_from_relobj<64, true>(
size_t count,
const char* sym_names,
size_t sym_name_size,
Symbol** sympointers);
Sized_relobj<64, false>::Symbols* sympointers);
#endif
#ifdef HAVE_TARGET_32_LITTLE

View File

@ -833,7 +833,7 @@ class Symbol_table
add_from_relobj(Sized_relobj<size, big_endian>* relobj,
const unsigned char* syms, size_t count,
const char* sym_names, size_t sym_name_size,
Symbol** sympointers);
typename Sized_relobj<size, big_endian>::Symbols*);
// Add COUNT dynamic symbols from the dynamic object DYNOBJ to the
// symbol table. SYMS is the symbols. SYM_NAMES is their names.

View File

@ -24,7 +24,6 @@
#define GOLD_TARGET_RELOC_H
#include "elfcpp.h"
#include "object.h"
#include "symtab.h"
#include "reloc-types.h"
@ -49,9 +48,10 @@ scan_relocs(
unsigned int data_shndx,
const unsigned char* prelocs,
size_t reloc_count,
Output_section* output_section,
bool needs_special_offset_handling,
size_t local_count,
const unsigned char* plocal_syms,
Symbol** global_syms)
const unsigned char* plocal_syms)
{
typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype;
const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
@ -62,6 +62,11 @@ scan_relocs(
{
Reltype reloc(prelocs);
if (needs_special_offset_handling
&& !output_section->is_input_address_mapped(object, data_shndx,
reloc.get_r_offset()))
continue;
typename elfcpp::Elf_types<size>::Elf_WXword r_info = reloc.get_r_info();
unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
@ -99,7 +104,7 @@ scan_relocs(
}
else
{
Symbol* gsym = global_syms[r_sym - local_count];
Symbol* gsym = object->global_symbol(r_sym);
gold_assert(gsym != NULL);
if (gsym->is_forwarder())
gsym = symtab->resolve_forwards(gsym);
@ -122,8 +127,14 @@ scan_relocs(
// RELOCATE implements operator() to do a relocation.
// PRELOCS points to the relocation data. RELOC_COUNT is the number
// of relocs. VIEW is the section data, VIEW_ADDRESS is its memory
// address, and VIEW_SIZE is the size.
// of relocs. OUTPUT_SECTION is the output section.
// NEEDS_SPECIAL_OFFSET_HANDLING is true if input offsets need to be
// mapped to output offsets.
// VIEW is the section data, VIEW_ADDRESS is its memory address, and
// VIEW_SIZE is the size. These refer to the input section, unless
// NEEDS_SPECIAL_OFFSET_HANDLING is true, in which case they refer to
// the output section.
template<int size, bool big_endian, typename Target_type, int sh_type,
typename Relocate>
@ -133,6 +144,8 @@ relocate_section(
Target_type* target,
const unsigned char* prelocs,
size_t reloc_count,
Output_section* output_section,
bool needs_special_offset_handling,
unsigned char* view,
typename elfcpp::Elf_types<size>::Elf_Addr view_address,
off_t view_size)
@ -141,10 +154,8 @@ relocate_section(
const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
Relocate relocate;
unsigned int local_count = relinfo->local_symbol_count;
const typename Sized_relobj<size, big_endian>::Local_values* local_values =
relinfo->local_values;
const Symbol* const * global_syms = relinfo->symbols;
Sized_relobj<size, big_endian>* object = relinfo->object;
unsigned int local_count = object->local_symbol_count();
for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
{
@ -152,6 +163,15 @@ relocate_section(
off_t offset = reloc.get_r_offset();
if (needs_special_offset_handling)
{
offset = output_section->output_offset(relinfo->object,
relinfo->data_shndx,
offset);
if (offset == -1)
continue;
}
typename elfcpp::Elf_types<size>::Elf_WXword r_info = reloc.get_r_info();
unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
@ -163,11 +183,11 @@ relocate_section(
if (r_sym < local_count)
{
sym = NULL;
psymval = &(*local_values)[r_sym];
psymval = object->local_symbol(r_sym);
}
else
{
const Symbol* gsym = global_syms[r_sym - local_count];
const Symbol* gsym = object->global_symbol(r_sym);
gold_assert(gsym != NULL);
if (gsym->is_forwarder())
gsym = relinfo->symtab->resolve_forwards(gsym);

View File

@ -43,11 +43,12 @@ class Object;
template<int size, bool big_endian>
class Sized_relobj;
template<int size, bool big_endian>
struct Relocate_info;
class Relocate_info;
class Symbol;
template<int size>
class Sized_symbol;
class Symbol_table;
class Output_section;
// The abstract class for target specific handling.
@ -228,9 +229,11 @@ class Sized_target : public Target
// relocs apply to. SH_TYPE is the type of the relocation section,
// SHT_REL or SHT_RELA. PRELOCS points to the relocation data.
// RELOC_COUNT is the number of relocs. LOCAL_SYMBOL_COUNT is the
// number of local symbols. PLOCAL_SYMBOLS points to the local
// symbol data from OBJECT. GLOBAL_SYMBOLS is the array of pointers
// to the global symbol table from OBJECT.
// number of local symbols. OUTPUT_SECTION is the output section.
// NEEDS_SPECIAL_OFFSET_HANDLING is true if offsets to the output
// sections are not mapped as usual. PLOCAL_SYMBOLS points to the
// local symbol data from OBJECT. GLOBAL_SYMBOLS is the array of
// pointers to the global symbol table from OBJECT.
virtual void
scan_relocs(const General_options& options,
Symbol_table* symtab,
@ -240,21 +243,29 @@ class Sized_target : public Target
unsigned int sh_type,
const unsigned char* prelocs,
size_t reloc_count,
Output_section* output_section,
bool needs_special_offset_handling,
size_t local_symbol_count,
const unsigned char* plocal_symbols,
Symbol** global_symbols) = 0;
const unsigned char* plocal_symbols) = 0;
// Relocate section data. SH_TYPE is the type of the relocation
// section, SHT_REL or SHT_RELA. PRELOCS points to the relocation
// information. RELOC_COUNT is the number of relocs. VIEW is a
// view into the output file holding the section contents,
// VIEW_ADDRESS is the virtual address of the view, and VIEW_SIZE is
// the size of the view.
// information. RELOC_COUNT is the number of relocs.
// OUTPUT_SECTION is the output section.
// NEEDS_SPECIAL_OFFSET_HANDLING is true if offsets must be mapped
// to correspond to the output section. VIEW is a view into the
// output file holding the section contents, VIEW_ADDRESS is the
// virtual address of the view, and VIEW_SIZE is the size of the
// view. If NEEDS_SPECIAL_OFFSET_HANDLING is true, the VIEW_xx
// parameters refer to the complete output section data, not just
// the input section data.
virtual void
relocate_section(const Relocate_info<size, big_endian>*,
unsigned int sh_type,
const unsigned char* prelocs,
size_t reloc_count,
Output_section* output_section,
bool needs_special_offset_handling,
unsigned char* view,
typename elfcpp::Elf_types<size>::Elf_Addr view_address,
off_t view_size) = 0;

View File

@ -46,14 +46,15 @@ class Target_test : public Sized_target<size, big_endian>
void
scan_relocs(const General_options&, Symbol_table*, Layout*,
Sized_relobj<size, big_endian>*, unsigned int,
unsigned int, const unsigned char*, size_t, size_t,
const unsigned char*, Symbol**)
unsigned int, const unsigned char*, size_t, Output_section*,
bool, size_t, const unsigned char*)
{ ERROR("call to Target_test::scan_relocs"); }
void
relocate_section(const Relocate_info<size, big_endian>*, unsigned int,
const unsigned char*, size_t, unsigned char*,
typename elfcpp::Elf_types<size>::Elf_Addr, off_t)
const unsigned char*, size_t, Output_section*, bool,
unsigned char*, typename elfcpp::Elf_types<size>::Elf_Addr,
off_t)
{ ERROR("call to Target_test::relocate_section"); }
static const Target::Target_info test_target_info;

View File

@ -83,9 +83,10 @@ class Target_x86_64 : public Sized_target<64, false>
unsigned int sh_type,
const unsigned char* prelocs,
size_t reloc_count,
Output_section* output_section,
bool needs_special_offset_handling,
size_t local_symbol_count,
const unsigned char* plocal_symbols,
Symbol** global_symbols);
const unsigned char* plocal_symbols);
// Finalize the sections.
void
@ -102,6 +103,8 @@ class Target_x86_64 : public Sized_target<64, false>
unsigned int sh_type,
const unsigned char* prelocs,
size_t reloc_count,
Output_section* output_section,
bool needs_special_offset_handling,
unsigned char* view,
elfcpp::Elf_types<64>::Elf_Addr view_address,
off_t view_size);
@ -1128,9 +1131,10 @@ Target_x86_64::scan_relocs(const General_options& options,
unsigned int sh_type,
const unsigned char* prelocs,
size_t reloc_count,
Output_section* output_section,
bool needs_special_offset_handling,
size_t local_symbol_count,
const unsigned char* plocal_symbols,
Symbol** global_symbols)
const unsigned char* plocal_symbols)
{
if (sh_type == elfcpp::SHT_REL)
{
@ -1149,9 +1153,10 @@ Target_x86_64::scan_relocs(const General_options& options,
data_shndx,
prelocs,
reloc_count,
output_section,
needs_special_offset_handling,
local_symbol_count,
plocal_symbols,
global_symbols);
plocal_symbols);
}
// Finalize the sections.
@ -1670,6 +1675,8 @@ Target_x86_64::relocate_section(const Relocate_info<64, false>* relinfo,
unsigned int sh_type,
const unsigned char* prelocs,
size_t reloc_count,
Output_section* output_section,
bool needs_special_offset_handling,
unsigned char* view,
elfcpp::Elf_types<64>::Elf_Addr address,
off_t view_size)
@ -1682,6 +1689,8 @@ Target_x86_64::relocate_section(const Relocate_info<64, false>* relinfo,
this,
prelocs,
reloc_count,
output_section,
needs_special_offset_handling,
view,
address,
view_size);