Generate a complete exception frame header. Discard duplicate
exception frame information.
This commit is contained in:
parent
0abe36f50d
commit
730cdc88f7
24 changed files with 2831 additions and 368 deletions
|
@ -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"));
|
||||
|
|
|
@ -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)
|
||||
|
|
1047
gold/ehframe.cc
1047
gold/ehframe.cc
File diff suppressed because it is too large
Load diff
359
gold/ehframe.h
359
gold/ehframe.h
|
@ -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.
|
||||
|
|
24
gold/gold.cc
24
gold/gold.cc
|
@ -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),
|
||||
|
|
21
gold/i386.cc
21
gold/i386.cc
|
@ -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);
|
||||
|
|
278
gold/layout.cc
278
gold/layout.cc
|
@ -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.
|
||||
|
|
130
gold/layout.h
130
gold/layout.h
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
|
94
gold/merge.h
94
gold/merge.h
|
@ -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)
|
||||
{ }
|
||||
};
|
||||
|
||||
|
|
210
gold/object.cc
210
gold/object.cc
|
@ -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;
|
||||
|
|
120
gold/object.h
120
gold/object.h
|
@ -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.
|
||||
|
|
153
gold/output.cc
153
gold/output.cc
|
@ -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
|
||||
|
|
119
gold/output.h
119
gold/output.h
|
@ -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_;
|
||||
|
|
155
gold/po/gold.pot
155
gold/po/gold.pot
|
@ -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 ""
|
||||
|
|
218
gold/reloc.cc
218
gold/reloc.cc
|
@ -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.
|
||||
|
|
58
gold/reloc.h
58
gold/reloc.h
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue