template<int size, bool big_endian>
class Sized_relobj;
-// This class specifies an input section. It is used as a key type
-// for maps.
-
-class Input_section_specifier
-{
- public:
- Input_section_specifier(const Relobj* robj, unsigned int sec_shndx)
- : relobj_(robj), shndx_(sec_shndx)
- { }
-
- // Return Relobj of this.
- const Relobj*
- relobj() const
- { return this->relobj_; }
-
- // Return section index of this.
- unsigned int
- shndx() const
- { return this->shndx_; }
-
- // Whether this equals to another specifier ISS.
- bool
- eq(const Input_section_specifier& iss) const
- { return this->relobj_ == iss.relobj_ && this->shndx_ == iss.shndx_; }
-
- // Compute a hash value of this.
- size_t
- hash_value() const
- {
- return (gold::string_hash<char>(this->relobj_->name().c_str())
- ^ this->shndx_);
- }
-
- // Functors for containers.
- struct equal_to
- {
- bool
- operator()(const Input_section_specifier& iss1,
- const Input_section_specifier& iss2) const
- { return iss1.eq(iss2); }
- };
-
- struct hash
- {
- size_t
- operator()(const Input_section_specifier& iss) const
- { return iss.hash_value(); }
- };
-
- private:
- // An object.
- const Relobj* relobj_;
- // A section index.
- unsigned int shndx_;
-};
-
// An abtract class for data which has to go into the output file.
class Output_data
output_section()
{ return this->do_output_section(); }
+ const Output_section*
+ output_section() const
+ { return this->do_output_section(); }
+
// Return the output section index, if there is an output section.
unsigned int
out_shndx() const
do_output_section()
{ return NULL; }
+ virtual const Output_section*
+ do_output_section() const
+ { return NULL; }
+
// Return the output section index, if there is an output section.
virtual unsigned int
do_out_shndx() const
// Set the size of the data.
void
- set_data_size(off_t datasize)
+ set_data_size(off_t data_size)
{
gold_assert(!this->is_data_size_valid_
&& !this->is_data_size_fixed_);
- this->data_size_ = datasize;
+ this->data_size_ = data_size;
this->is_data_size_valid_ = true;
}
// Set the current data size--this is for the convenience of
// sections which build up their size over time.
void
- set_current_data_size_for_child(off_t datasize)
+ set_current_data_size_for_child(off_t data_size)
{
gold_assert(!this->is_data_size_valid_);
- this->data_size_ = datasize;
+ this->data_size_ = data_size;
}
// Return default alignment for the target size.
class Output_section_data : public Output_data
{
public:
- Output_section_data(off_t datasize, uint64_t addr_align,
- bool is_datasize_fixed)
- : Output_data(), output_section_(NULL), addralign_(addr_align)
+ Output_section_data(off_t data_size, uint64_t addralign,
+ bool is_data_size_fixed)
+ : Output_data(), output_section_(NULL), addralign_(addralign)
{
- this->set_data_size(datasize);
- if (is_datasize_fixed)
+ this->set_data_size(data_size);
+ if (is_data_size_fixed)
this->fix_data_size();
}
- Output_section_data(uint64_t addr_align)
- : Output_data(), output_section_(NULL), addralign_(addr_align)
+ Output_section_data(uint64_t addralign)
+ : Output_data(), output_section_(NULL), addralign_(addralign)
{ }
// Return the output section.
// this input offset is being discarded.
bool
output_offset(const Relobj* object, unsigned int shndx,
- section_offset_type sec_offset,
+ section_offset_type offset,
section_offset_type *poutput) const
- { return this->do_output_offset(object, shndx, sec_offset, poutput); }
+ { return this->do_output_offset(object, shndx, offset, poutput); }
// Return whether this is the merge section for the input section
// SHNDX in OBJECT. This should return true when output_offset
do_output_section()
{ return this->output_section_; }
+ const Output_section*
+ do_output_section() const
+ { return this->output_section_; }
+
// Return the section index of the output section.
unsigned int
do_out_shndx() const;
class Output_section_data_build : public Output_section_data
{
public:
- Output_section_data_build(uint64_t addr_align)
- : Output_section_data(addr_align)
+ Output_section_data_build(uint64_t addralign)
+ : Output_section_data(addralign)
{ }
// Get the current data size.
// Set the current data size.
void
- set_current_data_size(off_t datasize)
- { this->set_current_data_size_for_child(datasize); }
+ set_current_data_size(off_t data_size)
+ { this->set_current_data_size_for_child(data_size); }
protected:
// Set the final data size.
class Output_data_const : public Output_section_data
{
public:
- Output_data_const(const std::string& data, uint64_t addr_align)
- : Output_section_data(data.size(), addr_align, true), data_(data)
+ Output_data_const(const std::string& data, uint64_t addralign)
+ : Output_section_data(data.size(), addralign, true), data_(data)
{ }
- Output_data_const(const char* p, off_t len, uint64_t addr_align)
- : Output_section_data(len, addr_align, true), data_(p, len)
+ Output_data_const(const char* p, off_t len, uint64_t addralign)
+ : Output_section_data(len, addralign, true), data_(p, len)
{ }
- Output_data_const(const unsigned char* p, off_t len, uint64_t addr_align)
- : Output_section_data(len, addr_align, true),
+ Output_data_const(const unsigned char* p, off_t len, uint64_t addralign)
+ : Output_section_data(len, addralign, true),
data_(reinterpret_cast<const char*>(p), len)
{ }
{
public:
Output_data_const_buffer(const unsigned char* p, off_t len,
- uint64_t addr_align, const char* map_name)
- : Output_section_data(len, addr_align, true),
+ uint64_t addralign, const char* map_name)
+ : Output_section_data(len, addralign, true),
p_(p), map_name_(map_name)
{ }
class Output_data_fixed_space : public Output_section_data
{
public:
- Output_data_fixed_space(off_t datasize, uint64_t addr_align,
+ Output_data_fixed_space(off_t data_size, uint64_t addralign,
const char* map_name)
- : Output_section_data(datasize, addr_align, true),
+ : Output_section_data(data_size, addralign, true),
map_name_(map_name)
{ }
class Output_data_space : public Output_section_data_build
{
public:
- explicit Output_data_space(uint64_t addr_align, const char* map_name)
- : Output_section_data_build(addr_align),
+ explicit Output_data_space(uint64_t addralign, const char* map_name)
+ : Output_section_data_build(addralign),
map_name_(map_name)
{ }
class Output_data_zero_fill : public Output_section_data
{
public:
- Output_data_zero_fill(off_t datasize, uint64_t addr_align)
- : Output_section_data(datasize, addr_align, true)
+ Output_data_zero_fill(off_t data_size, uint64_t addralign)
+ : Output_section_data(data_size, addralign, true)
{ }
protected:
// A reloc against a global symbol.
Output_reloc(Symbol* gsym, unsigned int type, Output_data* od,
- Address address, bool is_relative);
+ Address address, bool is_relative, bool is_symbolless);
Output_reloc(Symbol* gsym, unsigned int type,
Sized_relobj<size, big_endian>* relobj,
- unsigned int shndx, Address address, bool is_relative);
+ unsigned int shndx, Address address, bool is_relative,
+ bool is_symbolless);
// A reloc against a local symbol or local section symbol.
Output_reloc(Sized_relobj<size, big_endian>* relobj,
unsigned int local_sym_index, unsigned int type,
Output_data* od, Address address, bool is_relative,
- bool is_section_symbol);
+ bool is_symbolless, bool is_section_symbol);
Output_reloc(Sized_relobj<size, big_endian>* relobj,
unsigned int local_sym_index, unsigned int type,
unsigned int shndx, Address address, bool is_relative,
- bool is_section_symbol);
+ bool is_symbolless, bool is_section_symbol);
// A reloc against the STT_SECTION symbol of an output section.
Sized_relobj<size, big_endian>* relobj,
unsigned int shndx, Address address);
- // Return TRUE if this is a RELATIVE relocation.
+ // An absolute relocation with no symbol.
+
+ Output_reloc(unsigned int type, Output_data* od, Address address);
+
+ Output_reloc(unsigned int type, Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address);
+
+ // A target specific relocation. The target will be called to get
+ // the symbol index, passing ARG. The type and offset will be set
+ // as for other relocation types.
+
+ Output_reloc(unsigned int type, void* arg, Output_data* od,
+ Address address);
+
+ Output_reloc(unsigned int type, void* arg,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address);
+
+ // Return the reloc type.
+ unsigned int
+ type() const
+ { return this->type_; }
+
+ // Return whether this is a RELATIVE relocation.
bool
is_relative() const
{ return this->is_relative_; }
+ // Return whether this is a relocation which should not use
+ // a symbol, but which obtains its addend from a symbol.
+ bool
+ is_symbolless() const
+ { return this->is_symbolless_; }
+
// Return whether this is against a local section symbol.
bool
is_local_section_symbol() const
return (this->local_sym_index_ != GSYM_CODE
&& this->local_sym_index_ != SECTION_CODE
&& this->local_sym_index_ != INVALID_CODE
+ && this->local_sym_index_ != TARGET_CODE
&& this->is_section_symbol_);
}
+ // Return whether this is a target specific relocation.
+ bool
+ is_target_specific() const
+ { return this->local_sym_index_ == TARGET_CODE; }
+
+ // Return the argument to pass to the target for a target specific
+ // relocation.
+ void*
+ target_arg() const
+ {
+ gold_assert(this->local_sym_index_ == TARGET_CODE);
+ return this->u1_.arg;
+ }
+
// For a local section symbol, return the offset of the input
// section within the output section. ADDEND is the addend being
// applied to the input section.
GSYM_CODE = -1U,
// Output section.
SECTION_CODE = -2U,
+ // Target specific.
+ TARGET_CODE = -3U,
// Invalid uninitialized entry.
- INVALID_CODE = -3U
+ INVALID_CODE = -4U
};
union
// For a relocation against an output section
// (this->local_sym_index_ == SECTION_CODE), the output section.
Output_section* os;
+ // For a target specific relocation, an argument to pass to the
+ // target.
+ void* arg;
} u1_;
union
{
// The address offset within the input section or the Output_data.
Address address_;
// This is GSYM_CODE for a global symbol, or SECTION_CODE for a
- // relocation against an output section, or INVALID_CODE for an
- // uninitialized value. Otherwise, for a local symbol
- // (this->is_section_symbol_ is false), the local symbol index. For
- // a local section symbol (this->is_section_symbol_ is true), the
- // section index in the input file.
+ // relocation against an output section, or TARGET_CODE for a target
+ // specific relocation, or INVALID_CODE for an uninitialized value.
+ // Otherwise, for a local symbol (this->is_section_symbol_ is
+ // false), the local symbol index. For a local section symbol
+ // (this->is_section_symbol_ is true), the section index in the
+ // input file.
unsigned int local_sym_index_;
// The reloc type--a processor specific code.
- unsigned int type_ : 30;
+ unsigned int type_ : 29;
// True if the relocation is a RELATIVE relocation.
bool is_relative_ : 1;
+ // True if the relocation is one which should not use
+ // a symbol, but which obtains its addend from a symbol.
+ bool is_symbolless_ : 1;
// True if the relocation is against a section symbol.
bool is_section_symbol_ : 1;
// If the reloc address is an input section in an object, the
// A reloc against a global symbol.
Output_reloc(Symbol* gsym, unsigned int type, Output_data* od,
- Address addr, Addend addend, bool is_relative)
- : rel_(gsym, type, od, addr, is_relative), addend_(addend)
+ Address address, Addend addend, bool is_relative,
+ bool is_symbolless)
+ : rel_(gsym, type, od, address, is_relative, is_symbolless),
+ addend_(addend)
{ }
Output_reloc(Symbol* gsym, unsigned int type,
Sized_relobj<size, big_endian>* relobj,
- unsigned int shndx, Address addr, Addend addend,
- bool is_relative)
- : rel_(gsym, type, relobj, shndx, addr, is_relative), addend_(addend)
+ unsigned int shndx, Address address, Addend addend,
+ bool is_relative, bool is_symbolless)
+ : rel_(gsym, type, relobj, shndx, address, is_relative,
+ is_symbolless), addend_(addend)
{ }
// A reloc against a local symbol.
Output_reloc(Sized_relobj<size, big_endian>* relobj,
unsigned int local_sym_index, unsigned int type,
- Output_data* od, Address addr,
- Addend addend, bool is_relative, bool is_section_symbol)
- : rel_(relobj, local_sym_index, type, od, addr, is_relative,
- is_section_symbol),
+ Output_data* od, Address address,
+ Addend addend, bool is_relative,
+ bool is_symbolless, bool is_section_symbol)
+ : rel_(relobj, local_sym_index, type, od, address, is_relative,
+ is_symbolless, is_section_symbol),
addend_(addend)
{ }
Output_reloc(Sized_relobj<size, big_endian>* relobj,
unsigned int local_sym_index, unsigned int type,
- unsigned int shndx, Address addr,
- Addend addend, bool is_relative, bool is_section_symbol)
- : rel_(relobj, local_sym_index, type, shndx, addr, is_relative,
- is_section_symbol),
+ unsigned int shndx, Address address,
+ Addend addend, bool is_relative,
+ bool is_symbolless, bool is_section_symbol)
+ : rel_(relobj, local_sym_index, type, shndx, address, is_relative,
+ is_symbolless, is_section_symbol),
addend_(addend)
{ }
// A reloc against the STT_SECTION symbol of an output section.
Output_reloc(Output_section* os, unsigned int type, Output_data* od,
- Address addr, Addend addend)
- : rel_(os, type, od, addr), addend_(addend)
+ Address address, Addend addend)
+ : rel_(os, type, od, address), addend_(addend)
{ }
Output_reloc(Output_section* os, unsigned int type,
Sized_relobj<size, big_endian>* relobj,
- unsigned int shndx, Address addr, Addend addend)
- : rel_(os, type, relobj, shndx, addr), addend_(addend)
+ unsigned int shndx, Address address, Addend addend)
+ : rel_(os, type, relobj, shndx, address), addend_(addend)
+ { }
+
+ // An absolute relocation with no symbol.
+
+ Output_reloc(unsigned int type, Output_data* od, Address address,
+ Addend addend)
+ : rel_(type, od, address), addend_(addend)
{ }
+ Output_reloc(unsigned int type, Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address, Addend addend)
+ : rel_(type, relobj, shndx, address), addend_(addend)
+ { }
+
+ // A target specific relocation. The target will be called to get
+ // the symbol index and the addend, passing ARG. The type and
+ // offset will be set as for other relocation types.
+
+ Output_reloc(unsigned int type, void* arg, Output_data* od,
+ Address address, Addend addend)
+ : rel_(type, arg, od, address), addend_(addend)
+ { }
+
+ Output_reloc(unsigned int type, void* arg,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address, Addend addend)
+ : rel_(type, arg, relobj, shndx, address), addend_(addend)
+ { }
+
+ // Return whether this is a RELATIVE relocation.
+ bool
+ is_relative() const
+ { return this->rel_.is_relative(); }
+
+ // Return whether this is a relocation which should not use
+ // a symbol, but which obtains its addend from a symbol.
+ bool
+ is_symbolless() const
+ { return this->rel_.is_symbolless(); }
+
// Write the reloc entry to an output view.
void
write(unsigned char* pov) const;
Addend addend_;
};
+// Output_data_reloc_generic is a non-template base class for
+// Output_data_reloc_base. This gives the generic code a way to hold
+// a pointer to a reloc section.
+
+class Output_data_reloc_generic : public Output_section_data_build
+{
+ public:
+ Output_data_reloc_generic(int size, bool sort_relocs)
+ : Output_section_data_build(Output_data::default_alignment_for_size(size)),
+ relative_reloc_count_(0), sort_relocs_(sort_relocs)
+ { }
+
+ // Return the number of relative relocs in this section.
+ size_t
+ relative_reloc_count() const
+ { return this->relative_reloc_count_; }
+
+ // Whether we should sort the relocs.
+ bool
+ sort_relocs() const
+ { return this->sort_relocs_; }
+
+ protected:
+ // Note that we've added another relative reloc.
+ void
+ bump_relative_reloc_count()
+ { ++this->relative_reloc_count_; }
+
+ private:
+ // The number of relative relocs added to this section. This is to
+ // support DT_RELCOUNT.
+ size_t relative_reloc_count_;
+ // Whether to sort the relocations when writing them out, to make
+ // the dynamic linker more efficient.
+ bool sort_relocs_;
+};
+
// Output_data_reloc is used to manage a section containing relocs.
// SH_TYPE is either elfcpp::SHT_REL or elfcpp::SHT_RELA. DYNAMIC
// indicates whether this is a dynamic relocation or a normal
// the reloc type.
template<int sh_type, bool dynamic, int size, bool big_endian>
-class Output_data_reloc_base : public Output_section_data_build
+class Output_data_reloc_base : public Output_data_reloc_generic
{
public:
typedef Output_reloc<sh_type, dynamic, size, big_endian> Output_reloc_type;
// Construct the section.
Output_data_reloc_base(bool sort_relocs)
- : Output_section_data_build(Output_data::default_alignment_for_size(size)),
- sort_relocs_(sort_relocs)
+ : Output_data_reloc_generic(size, sort_relocs)
{ }
protected:
this->relocs_.push_back(reloc);
this->set_current_data_size(this->relocs_.size() * reloc_size);
od->add_dynamic_reloc();
+ if (reloc.is_relative())
+ this->bump_relative_reloc_count();
}
private:
// The relocations in this section.
Relocs relocs_;
- // Whether to sort the relocations when writing them out, to make
- // the dynamic linker more efficient.
- bool sort_relocs_;
};
// The class which callers actually create.
// Add a reloc against a global symbol.
void
- add_global(Symbol* gsym, unsigned int type, Output_data* od, Address addr)
- { this->add(od, Output_reloc_type(gsym, type, od, addr, false)); }
+ add_global(Symbol* gsym, unsigned int type, Output_data* od, Address address)
+ { this->add(od, Output_reloc_type(gsym, type, od, address, false, false)); }
void
add_global(Symbol* gsym, unsigned int type, Output_data* od,
Sized_relobj<size, big_endian>* relobj,
- unsigned int shndx, Address addr)
- { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, addr,
- false)); }
+ unsigned int shndx, Address address)
+ { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
+ false, false)); }
// These are to simplify the Copy_relocs class.
void
- add_global(Symbol* gsym, unsigned int type, Output_data* od, Address addr,
+ add_global(Symbol* gsym, unsigned int type, Output_data* od, Address address,
Address addend)
{
gold_assert(addend == 0);
- this->add_global(gsym, type, od, addr);
+ this->add_global(gsym, type, od, address);
}
void
add_global(Symbol* gsym, unsigned int type, Output_data* od,
Sized_relobj<size, big_endian>* relobj,
- unsigned int shndx, Address addr, Address addend)
+ unsigned int shndx, Address address, Address addend)
{
gold_assert(addend == 0);
- this->add_global(gsym, type, od, relobj, shndx, addr);
+ this->add_global(gsym, type, od, relobj, shndx, address);
}
// Add a RELATIVE reloc against a global symbol. The final relocation
void
add_global_relative(Symbol* gsym, unsigned int type, Output_data* od,
- Address addr)
- { this->add(od, Output_reloc_type(gsym, type, od, addr, true)); }
+ Address address)
+ { this->add(od, Output_reloc_type(gsym, type, od, address, true, true)); }
void
add_global_relative(Symbol* gsym, unsigned int type, Output_data* od,
Sized_relobj<size, big_endian>* relobj,
- unsigned int shndx, Address addr)
+ unsigned int shndx, Address address)
{
- this->add(od, Output_reloc_type(gsym, type, relobj, shndx, addr,
- true));
+ this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
+ true, true));
+ }
+
+ // Add a global relocation which does not use a symbol for the relocation,
+ // but which gets its addend from a symbol.
+
+ void
+ add_symbolless_global_addend(Symbol* gsym, unsigned int type,
+ Output_data* od, Address address)
+ { this->add(od, Output_reloc_type(gsym, type, od, address, false, true)); }
+
+ void
+ add_symbolless_global_addend(Symbol* gsym, unsigned int type,
+ Output_data* od,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address)
+ {
+ this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
+ false, true));
}
// Add a reloc against a local symbol.
void
add_local(Sized_relobj<size, big_endian>* relobj,
unsigned int local_sym_index, unsigned int type,
- Output_data* od, Address addr)
+ Output_data* od, Address address)
{
this->add(od, Output_reloc_type(relobj, local_sym_index, type, od,
- addr, false, false));
+ address, false, false, false));
}
void
add_local(Sized_relobj<size, big_endian>* relobj,
unsigned int local_sym_index, unsigned int type,
- Output_data* od, unsigned int shndx, Address addr)
+ Output_data* od, unsigned int shndx, Address address)
{
this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
- addr, false, false));
+ address, false, false, false));
}
// Add a RELATIVE reloc against a local symbol.
void
add_local_relative(Sized_relobj<size, big_endian>* relobj,
unsigned int local_sym_index, unsigned int type,
- Output_data* od, Address addr)
+ Output_data* od, Address address)
{
this->add(od, Output_reloc_type(relobj, local_sym_index, type, od,
- addr, true, false));
+ address, true, true, false));
}
void
add_local_relative(Sized_relobj<size, big_endian>* relobj,
unsigned int local_sym_index, unsigned int type,
- Output_data* od, unsigned int shndx, Address addr)
+ Output_data* od, unsigned int shndx, Address address)
{
this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
- addr, true, false));
+ address, true, true, false));
+ }
+
+ // Add a local relocation which does not use a symbol for the relocation,
+ // but which gets its addend from a symbol.
+
+ void
+ add_symbolless_local_addend(Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index, unsigned int type,
+ Output_data* od, Address address)
+ {
+ this->add(od, Output_reloc_type(relobj, local_sym_index, type, od,
+ address, false, true, false));
+ }
+
+ void
+ add_symbolless_local_addend(Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index, unsigned int type,
+ Output_data* od, unsigned int shndx,
+ Address address)
+ {
+ this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
+ address, false, true, false));
}
// Add a reloc against a local section symbol. This will be
void
add_local_section(Sized_relobj<size, big_endian>* relobj,
unsigned int input_shndx, unsigned int type,
- Output_data* od, Address addr)
+ Output_data* od, Address address)
{
this->add(od, Output_reloc_type(relobj, input_shndx, type, od,
- addr, false, true));
+ address, false, false, true));
}
void
add_local_section(Sized_relobj<size, big_endian>* relobj,
unsigned int input_shndx, unsigned int type,
- Output_data* od, unsigned int shndx, Address addr)
+ Output_data* od, unsigned int shndx, Address address)
{
this->add(od, Output_reloc_type(relobj, input_shndx, type, shndx,
- addr, false, true));
+ address, false, false, true));
}
// A reloc against the STT_SECTION symbol of an output section.
void
add_output_section(Output_section* os, unsigned int type,
- Output_data* od, Address addr)
- { this->add(od, Output_reloc_type(os, type, od, addr)); }
+ Output_data* od, Address address)
+ { this->add(od, Output_reloc_type(os, type, od, address)); }
void
add_output_section(Output_section* os, unsigned int type, Output_data* od,
Sized_relobj<size, big_endian>* relobj,
- unsigned int shndx, Address addr)
- { this->add(od, Output_reloc_type(os, type, relobj, shndx, addr)); }
+ unsigned int shndx, Address address)
+ { this->add(od, Output_reloc_type(os, type, relobj, shndx, address)); }
+
+ // Add an absolute relocation.
+
+ void
+ add_absolute(unsigned int type, Output_data* od, Address address)
+ { this->add(od, Output_reloc_type(type, od, address)); }
+
+ void
+ add_absolute(unsigned int type, Output_data* od,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address)
+ { this->add(od, Output_reloc_type(type, relobj, shndx, address)); }
+
+ // Add a target specific relocation. A target which calls this must
+ // define the reloc_symbol_index and reloc_addend virtual functions.
+
+ void
+ add_target_specific(unsigned int type, void* arg, Output_data* od,
+ Address address)
+ { this->add(od, Output_reloc_type(type, arg, od, address)); }
+
+ void
+ add_target_specific(unsigned int type, void* arg, Output_data* od,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address)
+ { this->add(od, Output_reloc_type(type, arg, relobj, shndx, address)); }
};
// The SHT_RELA version of Output_data_reloc.
void
add_global(Symbol* gsym, unsigned int type, Output_data* od,
- Address addr, Addend addend)
- { this->add(od, Output_reloc_type(gsym, type, od, addr, addend,
- false)); }
+ Address address, Addend addend)
+ { this->add(od, Output_reloc_type(gsym, type, od, address, addend,
+ false, false)); }
void
add_global(Symbol* gsym, unsigned int type, Output_data* od,
Sized_relobj<size, big_endian>* relobj,
- unsigned int shndx, Address addr,
+ unsigned int shndx, Address address,
Addend addend)
- { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, addr,
- addend, false)); }
+ { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
+ addend, false, false)); }
// Add a RELATIVE reloc against a global symbol. The final output
// relocation will not reference the symbol, but we must keep the symbol
void
add_global_relative(Symbol* gsym, unsigned int type, Output_data* od,
- Address addr, Addend addend)
- { this->add(od, Output_reloc_type(gsym, type, od, addr, addend, true)); }
+ Address address, Addend addend)
+ { this->add(od, Output_reloc_type(gsym, type, od, address, addend, true,
+ true)); }
void
add_global_relative(Symbol* gsym, unsigned int type, Output_data* od,
Sized_relobj<size, big_endian>* relobj,
- unsigned int shndx, Address addr, Addend addend)
- { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, addr,
- addend, true)); }
+ unsigned int shndx, Address address, Addend addend)
+ { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
+ addend, true, true)); }
+
+ // Add a global relocation which does not use a symbol for the relocation,
+ // but which gets its addend from a symbol.
+
+ void
+ add_symbolless_global_addend(Symbol* gsym, unsigned int type, Output_data* od,
+ Address address, Addend addend)
+ { this->add(od, Output_reloc_type(gsym, type, od, address, addend,
+ false, true)); }
+
+ void
+ add_symbolless_global_addend(Symbol* gsym, unsigned int type,
+ Output_data* od,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address, Addend addend)
+ { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
+ addend, false, true)); }
// Add a reloc against a local symbol.
void
add_local(Sized_relobj<size, big_endian>* relobj,
unsigned int local_sym_index, unsigned int type,
- Output_data* od, Address addr, Addend addend)
+ Output_data* od, Address address, Addend addend)
{
- this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, addr,
- addend, false, false));
+ this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, address,
+ addend, false, false, false));
}
void
add_local(Sized_relobj<size, big_endian>* relobj,
unsigned int local_sym_index, unsigned int type,
- Output_data* od, unsigned int shndx, Address addr,
+ Output_data* od, unsigned int shndx, Address address,
Addend addend)
{
this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
- addr, addend, false, false));
+ address, addend, false, false, false));
}
// Add a RELATIVE reloc against a local symbol.
void
add_local_relative(Sized_relobj<size, big_endian>* relobj,
unsigned int local_sym_index, unsigned int type,
- Output_data* od, Address addr, Addend addend)
+ Output_data* od, Address address, Addend addend)
{
- this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, addr,
- addend, true, false));
+ this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, address,
+ addend, true, true, false));
}
void
add_local_relative(Sized_relobj<size, big_endian>* relobj,
unsigned int local_sym_index, unsigned int type,
- Output_data* od, unsigned int shndx, Address addr,
+ Output_data* od, unsigned int shndx, Address address,
Addend addend)
{
this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
- addr, addend, true, false));
+ address, addend, true, true, false));
+ }
+
+ // Add a local relocation which does not use a symbol for the relocation,
+ // but which gets it's addend from a symbol.
+
+ void
+ add_symbolless_local_addend(Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index, unsigned int type,
+ Output_data* od, Address address, Addend addend)
+ {
+ this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, address,
+ addend, false, true, false));
+ }
+
+ void
+ add_symbolless_local_addend(Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index, unsigned int type,
+ Output_data* od, unsigned int shndx,
+ Address address, Addend addend)
+ {
+ this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
+ address, addend, false, true, false));
}
// Add a reloc against a local section symbol. This will be
void
add_local_section(Sized_relobj<size, big_endian>* relobj,
unsigned int input_shndx, unsigned int type,
- Output_data* od, Address addr, Addend addend)
+ Output_data* od, Address address, Addend addend)
{
- this->add(od, Output_reloc_type(relobj, input_shndx, type, od, addr,
- addend, false, true));
+ this->add(od, Output_reloc_type(relobj, input_shndx, type, od, address,
+ addend, false, false, true));
}
void
add_local_section(Sized_relobj<size, big_endian>* relobj,
unsigned int input_shndx, unsigned int type,
- Output_data* od, unsigned int shndx, Address addr,
+ Output_data* od, unsigned int shndx, Address address,
Addend addend)
{
this->add(od, Output_reloc_type(relobj, input_shndx, type, shndx,
- addr, addend, false, true));
+ address, addend, false, false, true));
}
// A reloc against the STT_SECTION symbol of an output section.
void
add_output_section(Output_section* os, unsigned int type, Output_data* od,
- Address addr, Addend addend)
- { this->add(os, Output_reloc_type(os, type, od, addr, addend)); }
+ Address address, Addend addend)
+ { this->add(os, Output_reloc_type(os, type, od, address, addend)); }
void
add_output_section(Output_section* os, unsigned int type,
Sized_relobj<size, big_endian>* relobj,
- unsigned int shndx, Address addr, Addend addend)
- { this->add(os, Output_reloc_type(os, type, relobj, shndx, addr,
+ unsigned int shndx, Address address, Addend addend)
+ { this->add(os, Output_reloc_type(os, type, relobj, shndx, address,
addend)); }
+
+ // Add an absolute relocation.
+
+ void
+ add_absolute(unsigned int type, Output_data* od, Address address,
+ Addend addend)
+ { this->add(od, Output_reloc_type(type, od, address, addend)); }
+
+ void
+ add_absolute(unsigned int type, Output_data* od,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address, Addend addend)
+ { this->add(od, Output_reloc_type(type, relobj, shndx, address, addend)); }
+
+ // Add a target specific relocation. A target which calls this must
+ // define the reloc_symbol_index and reloc_addend virtual functions.
+
+ void
+ add_target_specific(unsigned int type, void* arg, Output_data* od,
+ Address address, Addend addend)
+ { this->add(od, Output_reloc_type(type, arg, od, address, addend)); }
+
+ void
+ add_target_specific(unsigned int type, void* arg, Output_data* od,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address, Addend addend)
+ {
+ this->add(od, Output_reloc_type(type, arg, relobj, shndx, address,
+ addend));
+ }
};
// Output_relocatable_relocs represents a relocation section in a
// plus a constant offset.
void
add_section_plus_offset(elfcpp::DT tag, const Output_data* od,
- unsigned int sec_offset)
- { this->add_entry(Dynamic_entry(tag, od, sec_offset)); }
+ unsigned int offset)
+ { this->add_entry(Dynamic_entry(tag, od, offset)); }
// Add a new dynamic entry with the size of output data.
void
add_section_size(elfcpp::DT tag, const Output_data* od)
{ this->add_entry(Dynamic_entry(tag, od, true)); }
+ // Add a new dynamic entry with the total size of two output datas.
+ void
+ add_section_size(elfcpp::DT tag, const Output_data* od,
+ const Output_data* od2)
+ { this->add_entry(Dynamic_entry(tag, od, od2)); }
+
// Add a new dynamic entry with the address of a symbol.
void
add_symbol(elfcpp::DT tag, const Symbol* sym)
{
public:
// Create an entry with a fixed numeric value.
- Dynamic_entry(elfcpp::DT etag, unsigned int val)
- : tag_(etag), offset_(DYNAMIC_NUMBER)
+ Dynamic_entry(elfcpp::DT tag, unsigned int val)
+ : tag_(tag), offset_(DYNAMIC_NUMBER)
{ this->u_.val = val; }
// Create an entry with the size or address of a section.
- Dynamic_entry(elfcpp::DT etag, const Output_data* od, bool section_size)
- : tag_(etag),
+ Dynamic_entry(elfcpp::DT tag, const Output_data* od, bool section_size)
+ : tag_(tag),
offset_(section_size
? DYNAMIC_SECTION_SIZE
: DYNAMIC_SECTION_ADDRESS)
- { this->u_.od = od; }
+ {
+ this->u_.od = od;
+ this->od2 = NULL;
+ }
+
+ // Create an entry with the size of two sections.
+ Dynamic_entry(elfcpp::DT tag, const Output_data* od, const Output_data* od2)
+ : tag_(tag),
+ offset_(DYNAMIC_SECTION_SIZE)
+ {
+ this->u_.od = od;
+ this->od2 = od2;
+ }
// Create an entry with the address of a section plus a constant offset.
- Dynamic_entry(elfcpp::DT etag, const Output_data* od, unsigned int offset)
- : tag_(etag),
+ Dynamic_entry(elfcpp::DT tag, const Output_data* od, unsigned int offset)
+ : tag_(tag),
offset_(offset)
{ this->u_.od = od; }
// Create an entry with the address of a symbol.
- Dynamic_entry(elfcpp::DT etag, const Symbol* sym)
- : tag_(etag), offset_(DYNAMIC_SYMBOL)
+ Dynamic_entry(elfcpp::DT tag, const Symbol* sym)
+ : tag_(tag), offset_(DYNAMIC_SYMBOL)
{ this->u_.sym = sym; }
// Create an entry with a string.
- Dynamic_entry(elfcpp::DT etag, const char* str)
- : tag_(etag), offset_(DYNAMIC_STRING)
+ Dynamic_entry(elfcpp::DT tag, const char* str)
+ : tag_(tag), offset_(DYNAMIC_STRING)
{ this->u_.str = str; }
// Return the tag of this entry.
// For DYNAMIC_STRING.
const char* str;
} u_;
+ // For DYNAMIC_SYMBOL with two sections.
+ const Output_data* od2;
// The dynamic tag.
elfcpp::DT tag_;
// The type of entry (Classification) or offset within a section.
// We would like to call relobj->section_addralign(shndx) to get the
// alignment but we do not want the constructor to fail. So callers
// are repsonsible for ensuring that.
- Output_relaxed_input_section(Relobj* rel_obj, unsigned int sec_shndx,
- uint64_t addr_align)
- : Output_section_data_build(addr_align), relobj_(rel_obj), shndx_(sec_shndx)
+ Output_relaxed_input_section(Relobj* relobj, unsigned int shndx,
+ uint64_t addralign)
+ : Output_section_data_build(addralign), relobj_(relobj), shndx_(shndx)
{ }
// Return the Relobj of this relaxed input section.
// Set the load address.
void
- set_load_address(uint64_t load_addr)
+ set_load_address(uint64_t load_address)
{
- this->load_address_ = load_addr;
+ this->load_address_ = load_address;
this->has_load_address_ = true;
}
set_is_relro_local()
{ this->is_relro_local_ = true; }
+ // True if this must be the last relro section.
+ bool
+ is_last_relro() const
+ { return this->is_last_relro_; }
+
+ // Record that this must be the last relro section.
+ void
+ set_is_last_relro()
+ {
+ gold_assert(this->is_relro_);
+ this->is_last_relro_ = true;
+ }
+
+ // True if this must be the first section following the relro sections.
+ bool
+ is_first_non_relro() const
+ {
+ gold_assert(!this->is_relro_);
+ return this->is_first_non_relro_;
+ }
+
+ // Record that this must be the first non-relro section.
+ void
+ set_is_first_non_relro()
+ {
+ gold_assert(!this->is_relro_);
+ this->is_first_non_relro_ = true;
+ }
+
// True if this is a small section: a section which holds small
// variables.
bool
static const unsigned int invalid_shndx = static_cast<unsigned int>(-1);
public:
- Simple_input_section(Relobj *rel_obj, unsigned int sec_shndx)
- : shndx_(sec_shndx)
+ Simple_input_section(Relobj *relobj, unsigned int shndx)
+ : shndx_(shndx)
{
- gold_assert(sec_shndx != invalid_shndx);
- this->u_.relobj = rel_obj;
+ gold_assert(shndx != invalid_shndx);
+ this->u_.relobj = relobj;
}
Simple_input_section(Output_relaxed_input_section* section)
get_input_sections(uint64_t address, const std::string& fill,
std::list<Simple_input_section>*);
- // Add an input section from a script.
+ // Add a simple input section.
void
- add_input_section_for_script(const Simple_input_section& input_section,
- off_t data_size, uint64_t addralign);
+ add_simple_input_section(const Simple_input_section& input_section,
+ off_t data_size, uint64_t addralign);
// Set the current size of the output section.
void
void
restore_states();
+ // Discard states.
+ void
+ discard_states();
+
// Convert existing input sections to relaxed input sections.
void
convert_input_sections_to_relaxed_sections(
// Find a relaxed input section to an input section in OBJECT
// with index SHNDX. Return NULL if none is found.
- const Output_section_data*
+ const Output_relaxed_input_section*
find_relaxed_input_section(const Relobj* object, unsigned int shndx) const;
+ // Whether section offsets need adjustment due to relaxation.
+ bool
+ section_offsets_need_adjustment() const
+ { return this->section_offsets_need_adjustment_; }
+
+ // Set section_offsets_need_adjustment to be true.
+ void
+ set_section_offsets_need_adjustment()
+ { this->section_offsets_need_adjustment_ = true; }
+
+ // Adjust section offsets of input sections in this. This is
+ // requires if relaxation caused some input sections to change sizes.
+ void
+ adjust_section_offsets();
+
// Print merge statistics to stderr.
void
print_merge_stats();
do_output_section()
{ return this; }
+ const Output_section*
+ do_output_section() const
+ { return this; }
+
// Return the section index in the output file.
unsigned int
do_out_shndx() const
// Return whether this is a section of the specified type.
bool
- do_is_section_type(elfcpp::Elf_Word sec_type) const
- { return this->type_ == sec_type; }
+ do_is_section_type(elfcpp::Elf_Word type) const
+ { return this->type_ == type; }
// Return whether the specified section flag is set.
bool
}
// For an ordinary input section.
- Input_section(Relobj* object, unsigned int sec_shndx, off_t datasize,
- uint64_t addr_align)
- : shndx_(sec_shndx),
- p2align_(ffsll(static_cast<long long>(addr_align)))
+ Input_section(Relobj* object, unsigned int shndx, off_t data_size,
+ uint64_t addralign)
+ : shndx_(shndx),
+ p2align_(ffsll(static_cast<long long>(addralign)))
{
- gold_assert(sec_shndx != OUTPUT_SECTION_CODE
- && sec_shndx != MERGE_DATA_SECTION_CODE
- && sec_shndx != MERGE_STRING_SECTION_CODE
- && sec_shndx != RELAXED_INPUT_SECTION_CODE);
- this->u1_.data_size = datasize;
+ gold_assert(shndx != OUTPUT_SECTION_CODE
+ && shndx != MERGE_DATA_SECTION_CODE
+ && shndx != MERGE_STRING_SECTION_CODE
+ && shndx != RELAXED_INPUT_SECTION_CODE);
+ this->u1_.data_size = data_size;
this->u2_.object = object;
}
// parameters.
bool
is_merge_section(bool is_string, uint64_t entsize,
- uint64_t addr_align) const
+ uint64_t addralign) const
{
return (this->shndx_ == (is_string
? MERGE_STRING_SECTION_CODE
: MERGE_DATA_SECTION_CODE)
&& this->u1_.entsize == entsize
- && this->addralign() == addr_align);
+ && this->addralign() == addralign);
}
// Return whether this is a relaxed input section.
// Add an input section, for SHF_MERGE sections.
bool
- add_input_section(Relobj* object, unsigned int sec_shndx)
+ add_input_section(Relobj* object, unsigned int shndx)
{
gold_assert(this->shndx_ == MERGE_DATA_SECTION_CODE
|| this->shndx_ == MERGE_STRING_SECTION_CODE);
- return this->u2_.posd->add_input_section(object, sec_shndx);
+ return this->u2_.posd->add_input_section(object, shndx);
}
// Given an input OBJECT, an input section index SHNDX within that
class Checkpoint_output_section
{
public:
- Checkpoint_output_section(uint64_t addr_align, elfcpp::Elf_Xword sflags,
- const Input_section_list& sinput_sections,
- off_t first_input_off,
- bool attached_input_sections_sorted)
- : addralign_(addr_align), flags_(sflags),
- input_sections_(sinput_sections),
+ Checkpoint_output_section(uint64_t addralign, elfcpp::Elf_Xword flags,
+ const Input_section_list& input_sections,
+ off_t first_input_offset,
+ bool attached_input_sections_are_sorted)
+ : addralign_(addralign), flags_(flags),
+ input_sections_(input_sections),
input_sections_size_(input_sections_.size()),
- input_sections_copy_(), first_input_offset_(first_input_off),
- attached_input_sections_are_sorted_(attached_input_sections_sorted)
+ input_sections_copy_(), first_input_offset_(first_input_offset),
+ attached_input_sections_are_sorted_(attached_input_sections_are_sorted)
{ }
virtual
// This class is used to sort the input sections.
class Input_section_sort_entry;
- // This is the sort comparison function.
+ // This is the sort comparison function for ctors and dtors.
struct Input_section_sort_compare
{
bool
const Input_section_sort_entry&) const;
};
+ // This is the sort comparison function for .init_array and .fini_array.
+ struct Input_section_sort_init_fini_compare
+ {
+ bool
+ operator()(const Input_section_sort_entry&,
+ const Input_section_sort_entry&) const;
+ };
+
// Fill data. This is used to fill in data between input sections.
// It is also used for data statements (BYTE, WORD, etc.) in linker
// scripts. When we have to keep track of the input sections, we
class Fill
{
public:
- Fill(off_t section_off, off_t len)
- : section_offset_(section_off),
- length_(convert_to_section_size_type(len))
+ Fill(off_t section_offset, off_t length)
+ : section_offset_(section_offset),
+ length_(convert_to_section_size_type(length))
{ }
// Return section offset.
Merge_section_properties::equal_to>
Merge_section_by_properties_map;
- // Map that link Input_section_specifier to Output_section_data.
- typedef Unordered_map<Input_section_specifier, Output_section_data*,
- Input_section_specifier::hash,
- Input_section_specifier::equal_to>
+ // Map that link Const_section_id to Output_section_data.
+ typedef Unordered_map<Const_section_id, Output_section_data*,
+ Const_section_id_hash>
Output_section_data_by_input_section_map;
+ // Map that link Const_section_id to Output_relaxed_input_section.
+ typedef Unordered_map<Const_section_id, Output_relaxed_input_section*,
+ Const_section_id_hash>
+ Output_relaxed_input_section_by_input_section_map;
+
// Map used during relaxation of existing sections. This map
- // an input section specifier to an input section list index.
- // We assume that Input_section_list is a vector.
- typedef Unordered_map<Input_section_specifier, size_t,
- Input_section_specifier::hash,
- Input_section_specifier::equal_to>
- Relaxation_map;
+ // a section id an input section list index. We assume that
+ // Input_section_list is a vector.
+ typedef Unordered_map<Section_id, size_t, Section_id_hash> Relaxation_map;
// Add a new output section by Input_section.
void
bool is_relro_ : 1;
// True if this section holds relro local data.
bool is_relro_local_ : 1;
+ // True if this must be the last relro section.
+ bool is_last_relro_ : 1;
+ // True if this must be the first section after the relro sections.
+ bool is_first_non_relro_ : 1;
// True if this is a small section.
bool is_small_section_ : 1;
// True if this is a large section.
bool is_dynamic_linker_section_ : 1;
// Whether code-fills are generated at write.
bool generate_code_fills_at_write_ : 1;
+ // Whether the entry size field should be zero.
+ bool is_entsize_zero_ : 1;
+ // Whether section offsets need adjustment due to relaxation.
+ bool section_offsets_need_adjustment_ : 1;
// For SHT_TLS sections, the offset of this section relative to the base
// of the TLS segment.
uint64_t tls_offset_;
// Map from input sections to relaxed input sections. This is mutable
// because it is updated lazily. We may need to update it in a
// const qualified method.
- mutable Output_section_data_by_input_section_map relaxed_input_section_map_;
+ mutable Output_relaxed_input_section_by_input_section_map
+ relaxed_input_section_map_;
// Whether relaxed_input_section_map_ is valid.
mutable bool is_relaxed_input_section_map_valid_;
};
void
remove_output_section(Output_section* os);
- // Add an Output_data (which is not an Output_section) to the start
- // of this segment.
+ // Add an Output_data (which need not be an Output_section) to the
+ // start of this segment.
void
add_initial_output_data(Output_data*);
// Set the addresses.
void
- set_addresses(uint64_t v_addr, uint64_t p_addr)
+ set_addresses(uint64_t vaddr, uint64_t paddr)
{
- this->vaddr_ = v_addr;
- this->paddr_ = p_addr;
+ this->vaddr_ = vaddr;
+ this->paddr_ = paddr;
this->are_addresses_set_ = true;
}
+ // Update the flags for the flags of an output section added to this
+ // segment.
+ void
+ update_flags_for_output_section(elfcpp::Elf_Xword flags)
+ {
+ // The ELF ABI specifies that a PT_TLS segment should always have
+ // PF_R as the flags.
+ if (this->type() != elfcpp::PT_TLS)
+ this->flags_ |= flags;
+ }
+
// Set the segment flags. This is only used if we have a PHDRS
// clause which explicitly specifies the flags.
void
- set_flags(elfcpp::Elf_Word seg_flags)
- { this->flags_ = seg_flags; }
+ set_flags(elfcpp::Elf_Word flags)
+ { this->flags_ = flags; }
// Set the address of the segment to ADDR and the offset to *POFF
// and set the addresses and offsets of all contained output
// address of the immediately following segment. Update *POFF and
// *PSHNDX. This should only be called for a PT_LOAD segment.
uint64_t
- set_section_addresses(const Layout*, bool reset, uint64_t addr, off_t* poff,
+ set_section_addresses(const Layout*, bool reset, uint64_t addr,
+ unsigned int increase_relro, off_t* poff,
unsigned int* pshndx);
// Set the minimum alignment of this segment. This may be adjusted
// Set the offset of this segment based on the section. This should
// only be called for a non-PT_LOAD segment.
void
- set_offset();
+ set_offset(unsigned int increase);
// Set the TLS offsets of the sections contained in the PT_TLS segment.
void
uint64_t
set_section_list_addresses(const Layout*, bool reset, Output_data_list*,
uint64_t addr, off_t* poff, unsigned int* pshndx,
- bool* in_tls, bool* in_relro);
+ bool* in_tls);
// Return the number of Output_sections in an Output_data_list.
unsigned int