// output.h -- manage the output file for gold -*- C++ -*-
-// Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
// This file is part of gold.
class Object;
class Symbol;
class Output_file;
+class Output_merge_base;
class Output_section;
class Relocatable_relocs;
class Target;
: address_(0), data_size_(0), offset_(-1),
is_address_valid_(false), is_data_size_valid_(false),
is_offset_valid_(false), is_data_size_fixed_(false),
- dynamic_reloc_count_(0)
+ has_dynamic_reloc_(false)
{ }
virtual
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
is_layout_complete()
{ return Output_data::allocated_sizes_are_fixed; }
- // Count the number of dynamic relocations applied to this section.
+ // Note that a dynamic reloc has been applied to this data.
void
add_dynamic_reloc()
- { ++this->dynamic_reloc_count_; }
+ { this->has_dynamic_reloc_ = true; }
- // Return the number of dynamic relocations applied to this section.
- unsigned int
- dynamic_reloc_count() const
- { return this->dynamic_reloc_count_; }
+ // Return whether a dynamic reloc has been applied.
+ bool
+ has_dynamic_reloc() const
+ { return this->has_dynamic_reloc_; }
// Whether the address is valid.
bool
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
// File offset of contents in output file.
off_t offset_;
// Whether address_ is valid.
- bool is_address_valid_;
+ bool is_address_valid_ : 1;
// Whether data_size_ is valid.
- bool is_data_size_valid_;
+ bool is_data_size_valid_ : 1;
// Whether offset_ is valid.
- bool is_offset_valid_;
+ bool is_offset_valid_ : 1;
// Whether data size is fixed.
- bool is_data_size_fixed_;
- // Count of dynamic relocations applied to this section.
- unsigned int dynamic_reloc_count_;
+ bool is_data_size_fixed_ : 1;
+ // Whether any dynamic relocs have been applied to this section.
+ bool has_dynamic_reloc_ : 1;
};
// Output the section headers.
{ }
// Return the output section.
+ Output_section*
+ output_section()
+ { return this->output_section_; }
+
const Output_section*
output_section() const
{ return this->output_section_; }
bool
output_offset(const Relobj* object, unsigned int shndx,
section_offset_type offset,
- section_offset_type *poutput) const
+ section_offset_type* poutput) const
{ return this->do_output_offset(object, shndx, offset, poutput); }
// Return whether this is the merge section for the input section
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;
// 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 address, Addend addend, bool is_relative)
- : rel_(gsym, type, od, address, 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 address, Addend addend,
- bool is_relative)
- : rel_(gsym, type, relobj, shndx, address, is_relative), 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 address,
- Addend addend, bool is_relative, bool is_section_symbol)
+ Addend addend, bool is_relative,
+ bool is_symbolless, bool is_section_symbol)
: rel_(relobj, local_sym_index, type, od, address, is_relative,
- is_section_symbol),
+ 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 address,
- Addend addend, bool is_relative, bool is_section_symbol)
+ Addend addend, bool is_relative,
+ bool is_symbolless, bool is_section_symbol)
: rel_(relobj, local_sym_index, type, shndx, address, is_relative,
- is_section_symbol),
+ is_symbolless, is_section_symbol),
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:
// Set the entry size and the link.
void
- do_adjust_output_section(Output_section *os);
+ do_adjust_output_section(Output_section* os);
// Write to a map file.
void
// Add a relocation entry.
void
- add(Output_data *od, const Output_reloc_type& reloc)
+ add(Output_data* od, const Output_reloc_type& reloc)
{
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.
void
add_global(Symbol* gsym, unsigned int type, Output_data* od, Address address)
- { this->add(od, Output_reloc_type(gsym, type, od, address, false)); }
+ { 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 address)
{ this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
- false)); }
+ false, false)); }
// These are to simplify the Copy_relocs class.
void
add_global_relative(Symbol* gsym, unsigned int type, Output_data* od,
Address address)
- { this->add(od, Output_reloc_type(gsym, type, od, address, true)); }
+ { this->add(od, Output_reloc_type(gsym, type, od, address, true, true)); }
void
add_global_relative(Symbol* gsym, unsigned int type, Output_data* od,
unsigned int shndx, Address address)
{
this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
- true));
+ 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.
Output_data* od, Address address)
{
this->add(od, Output_reloc_type(relobj, local_sym_index, type, od,
- address, false, false));
+ address, false, false, false));
}
void
Output_data* od, unsigned int shndx, Address address)
{
this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
- address, false, false));
+ address, false, false, false));
}
// Add a RELATIVE reloc against a local symbol.
Output_data* od, Address address)
{
this->add(od, Output_reloc_type(relobj, local_sym_index, type, od,
- address, true, false));
+ address, true, true, false));
}
void
Output_data* od, unsigned int shndx, Address address)
{
this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
- address, 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
Output_data* od, Address address)
{
this->add(od, Output_reloc_type(relobj, input_shndx, type, od,
- address, false, true));
+ address, false, false, true));
}
void
Output_data* od, unsigned int shndx, Address address)
{
this->add(od, Output_reloc_type(relobj, input_shndx, type, shndx,
- address, false, true));
+ address, false, false, true));
}
// A reloc against the STT_SECTION symbol of an output section.
Sized_relobj<size, big_endian>* relobj,
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.
add_global(Symbol* gsym, unsigned int type, Output_data* od,
Address address, Addend addend)
{ this->add(od, Output_reloc_type(gsym, type, od, address, addend,
- false)); }
+ false, false)); }
void
add_global(Symbol* gsym, unsigned int type, Output_data* od,
unsigned int shndx, Address address,
Addend addend)
{ this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
- addend, false)); }
+ 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 address, Addend addend)
- { this->add(od, Output_reloc_type(gsym, type, od, address, addend, true)); }
+ { 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 address, Addend addend)
{ this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
- addend, true)); }
+ 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.
Output_data* od, Address address, Addend addend)
{
this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, address,
- addend, false, false));
+ addend, false, false, false));
}
void
Addend addend)
{
this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
- address, addend, false, false));
+ address, addend, false, false, false));
}
// Add a RELATIVE reloc against a local symbol.
Output_data* od, Address address, Addend addend)
{
this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, address,
- addend, true, false));
+ addend, true, true, false));
}
void
Addend addend)
{
this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
- address, 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
Output_data* od, Address address, Addend addend)
{
this->add(od, Output_reloc_type(relobj, input_shndx, type, od, address,
- addend, false, true));
+ addend, false, false, true));
}
void
Addend addend)
{
this->add(od, Output_reloc_type(relobj, input_shndx, type, shndx,
- address, addend, false, true));
+ address, addend, false, false, true));
}
// A reloc against the STT_SECTION symbol of an output section.
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
bool
add_global(Symbol* gsym, unsigned int got_type);
+ // Like add_global, but use the PLT offset of the global symbol if
+ // it has one.
+ bool
+ add_global_plt(Symbol* gsym, unsigned int got_type);
+
// Add an entry for a global symbol to the GOT, and add a dynamic
// relocation of type R_TYPE for the GOT entry.
void
add_local(Sized_relobj<size, big_endian>* object, unsigned int sym_index,
unsigned int got_type);
+ // Like add_local, but use the PLT offset of the local symbol if it
+ // has one.
+ bool
+ add_local_plt(Sized_relobj<size, big_endian>* object, unsigned int sym_index,
+ unsigned int got_type);
+
// Add an entry for a local symbol to the GOT, and add a dynamic
// relocation of type R_TYPE for the GOT entry.
void
public:
// Create a zero entry.
Got_entry()
- : local_sym_index_(CONSTANT_CODE)
+ : local_sym_index_(CONSTANT_CODE), use_plt_offset_(false)
{ this->u_.constant = 0; }
// Create a global symbol entry.
- explicit Got_entry(Symbol* gsym)
- : local_sym_index_(GSYM_CODE)
+ Got_entry(Symbol* gsym, bool use_plt_offset)
+ : local_sym_index_(GSYM_CODE), use_plt_offset_(use_plt_offset)
{ this->u_.gsym = gsym; }
// Create a local symbol entry.
Got_entry(Sized_relobj<size, big_endian>* object,
- unsigned int local_sym_index)
- : local_sym_index_(local_sym_index)
+ unsigned int local_sym_index, bool use_plt_offset)
+ : local_sym_index_(local_sym_index), use_plt_offset_(use_plt_offset)
{
gold_assert(local_sym_index != GSYM_CODE
- && local_sym_index != CONSTANT_CODE);
+ && local_sym_index != CONSTANT_CODE
+ && local_sym_index == this->local_sym_index_);
this->u_.object = object;
}
// Create a constant entry. The constant is a host value--it will
// be swapped, if necessary, when it is written out.
explicit Got_entry(Valtype constant)
- : local_sym_index_(CONSTANT_CODE)
+ : local_sym_index_(CONSTANT_CODE), use_plt_offset_(false)
{ this->u_.constant = constant; }
// Write the GOT entry to an output view.
private:
enum
{
- GSYM_CODE = -1U,
- CONSTANT_CODE = -2U
+ GSYM_CODE = 0x7fffffff,
+ CONSTANT_CODE = 0x7ffffffe
};
union
} u_;
// For a local symbol, the local symbol index. This is GSYM_CODE
// for a global symbol, or CONSTANT_CODE for a constant.
- unsigned int local_sym_index_;
+ unsigned int local_sym_index_ : 31;
+ // Whether to use the PLT offset of the symbol if it has one.
+ bool use_plt_offset_ : 1;
};
typedef std::vector<Got_entry> Got_entries;
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)
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 tag, const Output_data* od, unsigned int offset)
// 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.
};
// A relaxed input section.
-class Output_relaxed_input_section : public Output_section_data
+class Output_relaxed_input_section : public Output_section_data_build
{
public:
// We would like to call relobj->section_addralign(shndx) to get the
// are repsonsible for ensuring that.
Output_relaxed_input_section(Relobj* relobj, unsigned int shndx,
uint64_t addralign)
- : Output_section_data(addralign), relobj_(relobj), shndx_(shndx)
+ : Output_section_data_build(addralign), relobj_(relobj), shndx_(shndx)
{ }
// Return the Relobj of this relaxed input section.
unsigned int shndx_;
};
+// This class describes properties of merge data sections. It is used
+// as a key type for maps.
+class Merge_section_properties
+{
+ public:
+ Merge_section_properties(bool is_string, uint64_t entsize,
+ uint64_t addralign)
+ : is_string_(is_string), entsize_(entsize), addralign_(addralign)
+ { }
+
+ // Whether this equals to another Merge_section_properties MSP.
+ bool
+ eq(const Merge_section_properties& msp) const
+ {
+ return ((this->is_string_ == msp.is_string_)
+ && (this->entsize_ == msp.entsize_)
+ && (this->addralign_ == msp.addralign_));
+ }
+
+ // Compute a hash value for this using 64-bit FNV-1a hash.
+ size_t
+ hash_value() const
+ {
+ uint64_t h = 14695981039346656037ULL; // FNV offset basis.
+ uint64_t prime = 1099511628211ULL;
+ h = (h ^ static_cast<uint64_t>(this->is_string_)) * prime;
+ h = (h ^ static_cast<uint64_t>(this->entsize_)) * prime;
+ h = (h ^ static_cast<uint64_t>(this->addralign_)) * prime;
+ return h;
+ }
+
+ // Functors for associative containers.
+ struct equal_to
+ {
+ bool
+ operator()(const Merge_section_properties& msp1,
+ const Merge_section_properties& msp2) const
+ { return msp1.eq(msp2); }
+ };
+
+ struct hash
+ {
+ size_t
+ operator()(const Merge_section_properties& msp) const
+ { return msp.hash_value(); }
+ };
+
+ private:
+ // Whether this merge data section is for strings.
+ bool is_string_;
+ // Entsize of this merge data section.
+ uint64_t entsize_;
+ // Address alignment.
+ uint64_t addralign_;
+};
+
+// This class is used to speed up look up of special input sections in an
+// Output_section.
+
+class Output_section_lookup_maps
+{
+ public:
+ Output_section_lookup_maps()
+ : is_valid_(true), merge_sections_by_properties_(),
+ merge_sections_by_id_(), relaxed_input_sections_by_id_()
+ { }
+
+ // Whether the maps are valid.
+ bool
+ is_valid() const
+ { return this->is_valid_; }
+
+ // Invalidate the maps.
+ void
+ invalidate()
+ { this->is_valid_ = false; }
+
+ // Clear the maps.
+ void
+ clear()
+ {
+ this->merge_sections_by_properties_.clear();
+ this->merge_sections_by_id_.clear();
+ this->relaxed_input_sections_by_id_.clear();
+ // A cleared map is valid.
+ this->is_valid_ = true;
+ }
+
+ // Find a merge section by merge section properties. Return NULL if none
+ // is found.
+ Output_merge_base*
+ find_merge_section(const Merge_section_properties& msp) const
+ {
+ gold_assert(this->is_valid_);
+ Merge_sections_by_properties::const_iterator p =
+ this->merge_sections_by_properties_.find(msp);
+ return p != this->merge_sections_by_properties_.end() ? p->second : NULL;
+ }
+
+ // Find a merge section by section ID of a merge input section. Return NULL
+ // if none is found.
+ Output_merge_base*
+ find_merge_section(const Object* object, unsigned int shndx) const
+ {
+ gold_assert(this->is_valid_);
+ Merge_sections_by_id::const_iterator p =
+ this->merge_sections_by_id_.find(Const_section_id(object, shndx));
+ return p != this->merge_sections_by_id_.end() ? p->second : NULL;
+ }
+
+ // Add a merge section pointed by POMB with properties MSP.
+ void
+ add_merge_section(const Merge_section_properties& msp,
+ Output_merge_base* pomb)
+ {
+ std::pair<Merge_section_properties, Output_merge_base*> value(msp, pomb);
+ std::pair<Merge_sections_by_properties::iterator, bool> result =
+ this->merge_sections_by_properties_.insert(value);
+ gold_assert(result.second);
+ }
+
+ // Add a mapping from a merged input section in OBJECT with index SHNDX
+ // to a merge output section pointed by POMB.
+ void
+ add_merge_input_section(const Object* object, unsigned int shndx,
+ Output_merge_base* pomb)
+ {
+ Const_section_id csid(object, shndx);
+ std::pair<Const_section_id, Output_merge_base*> value(csid, pomb);
+ std::pair<Merge_sections_by_id::iterator, bool> result =
+ this->merge_sections_by_id_.insert(value);
+ gold_assert(result.second);
+ }
+
+ // Find a relaxed input section of OBJECT with index SHNDX.
+ Output_relaxed_input_section*
+ find_relaxed_input_section(const Object* object, unsigned int shndx) const
+ {
+ gold_assert(this->is_valid_);
+ Relaxed_input_sections_by_id::const_iterator p =
+ this->relaxed_input_sections_by_id_.find(Const_section_id(object, shndx));
+ return p != this->relaxed_input_sections_by_id_.end() ? p->second : NULL;
+ }
+
+ // Add a relaxed input section pointed by POMB and whose original input
+ // section is in OBJECT with index SHNDX.
+ void
+ add_relaxed_input_section(const Relobj* relobj, unsigned int shndx,
+ Output_relaxed_input_section* poris)
+ {
+ Const_section_id csid(relobj, shndx);
+ std::pair<Const_section_id, Output_relaxed_input_section*>
+ value(csid, poris);
+ std::pair<Relaxed_input_sections_by_id::iterator, bool> result =
+ this->relaxed_input_sections_by_id_.insert(value);
+ gold_assert(result.second);
+ }
+
+ private:
+ typedef Unordered_map<Const_section_id, Output_merge_base*,
+ Const_section_id_hash>
+ Merge_sections_by_id;
+
+ typedef Unordered_map<Merge_section_properties, Output_merge_base*,
+ Merge_section_properties::hash,
+ Merge_section_properties::equal_to>
+ Merge_sections_by_properties;
+
+ typedef Unordered_map<Const_section_id, Output_relaxed_input_section*,
+ Const_section_id_hash>
+ Relaxed_input_sections_by_id;
+
+ // Whether this is valid
+ bool is_valid_;
+ // Merge sections by merge section properties.
+ Merge_sections_by_properties merge_sections_by_properties_;
+ // Merge sections by section IDs.
+ Merge_sections_by_id merge_sections_by_id_;
+ // Relaxed sections by section IDs.
+ Relaxed_input_sections_by_id relaxed_input_sections_by_id_;
+};
+
// An output section. We don't expect to have too many output
// sections, so we don't bother to do a template on the size.
// within the output section.
template<int size, bool big_endian>
off_t
- add_input_section(Sized_relobj<size, big_endian>* object, unsigned int shndx,
- const char *name,
+ add_input_section(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, bool have_sections_script);
void
add_output_section_data(Output_section_data* posd);
+ // Add a relaxed input section PORIS called NAME to this output section
+ // with LAYOUT.
+ void
+ add_relaxed_input_section(Layout* layout,
+ Output_relaxed_input_section* poris,
+ const std::string& name);
+
// Return the section name.
const char*
name() const
set_may_sort_attached_input_sections()
{ this->may_sort_attached_input_sections_ = true; }
+ // Returns true if input sections must be sorted according to the
+ // order in which their name appear in the --section-ordering-file.
+ bool
+ input_section_order_specified()
+ { return this->input_section_order_specified_; }
+
+ // Record that input sections must be sorted as some of their names
+ // match the patterns specified through --section-ordering-file.
+ void
+ set_input_section_order_specified()
+ { this->input_section_order_specified_ = true; }
+
// Return whether the input sections attached to this output section
// require sorting. This is used to handle constructor priorities
// compatibly with GNU ld.
set_must_sort_attached_input_sections()
{ this->must_sort_attached_input_sections_ = true; }
+ // Get the order in which this section appears in the PT_LOAD output
+ // segment.
+ Output_section_order
+ order() const
+ { return this->order_; }
+
+ // Set the order for this section.
+ void
+ set_order(Output_section_order order)
+ { this->order_ = order; }
+
// Return whether this section holds relro data--data which has
// dynamic relocations but which may be marked read-only after the
// dynamic relocations have been completed.
clear_is_relro()
{ this->is_relro_ = false; }
- // True if this section holds relro local data--relro data for which
- // the dynamic relocations are all RELATIVE relocations.
- bool
- is_relro_local() const
- { return this->is_relro_local_; }
-
- // Record that this section holds relro local data.
- void
- set_is_relro_local()
- { this->is_relro_local_ = true; }
-
// True if this is a small section: a section which holds small
// variables.
bool
// The next few calls are for linker script support.
- // We need to export the input sections to linker scripts. Previously
- // we export a pair of Relobj pointer and section index. We now need to
- // handle relaxed input sections as well. So we use this class.
- class Simple_input_section
+ // In some cases we need to keep a list of the input sections
+ // associated with this output section. We only need the list if we
+ // might have to change the offsets of the input section within the
+ // output section after we add the input section. The ordinary
+ // input sections will be written out when we process the object
+ // file, and as such we don't need to track them here. We do need
+ // to track Output_section_data objects here. We store instances of
+ // this structure in a std::vector, so it must be a POD. There can
+ // be many instances of this structure, so we use a union to save
+ // some space.
+ class Input_section
{
- private:
- static const unsigned int invalid_shndx = static_cast<unsigned int>(-1);
-
public:
- Simple_input_section(Relobj *relobj, unsigned int shndx)
- : shndx_(shndx)
+ Input_section()
+ : shndx_(0), p2align_(0)
{
- gold_assert(shndx != invalid_shndx);
- this->u_.relobj = relobj;
+ this->u1_.data_size = 0;
+ this->u2_.object = NULL;
}
-
- Simple_input_section(Output_relaxed_input_section* section)
- : shndx_(invalid_shndx)
- { this->u_.relaxed_input_section = section; }
-
- // Whether this is a relaxed section.
- bool
- is_relaxed_input_section() const
- { return this->shndx_ == invalid_shndx; }
- // Return object of an input section.
- Relobj*
- relobj() const
+ // For an ordinary input section.
+ Input_section(Relobj* object, unsigned int shndx, off_t data_size,
+ uint64_t addralign)
+ : shndx_(shndx),
+ p2align_(ffsll(static_cast<long long>(addralign))),
+ section_order_index_(0)
{
- return ((this->shndx_ != invalid_shndx)
- ? this->u_.relobj
- : this->u_.relaxed_input_section->relobj());
- }
-
- // Return index of an input section.
- unsigned int
- shndx() const
- {
- return ((this->shndx_ != invalid_shndx)
- ? this->shndx_
- : this->u_.relaxed_input_section->shndx());
- }
-
- // Return the Output_relaxed_input_section object of a relaxed section.
- Output_relaxed_input_section*
- relaxed_input_section() const
- {
- gold_assert(this->shndx_ == invalid_shndx);
- return this->u_.relaxed_input_section;
- }
-
- private:
- // Pointer to either an Relobj or an Output_relaxed_input_section.
- union
- {
- Relobj* relobj;
- Output_relaxed_input_section* relaxed_input_section;
- } u_;
- // Section index for an non-relaxed section or invalid_shndx for
- // a relaxed section.
- unsigned int shndx_;
- };
-
- // Store the list of input sections for this Output_section into the
- // list passed in. This removes the input sections, leaving only
- // any Output_section_data elements. This returns the size of those
- // Output_section_data elements. ADDRESS is the address of this
- // output section. FILL is the fill value to use, in case there are
- // any spaces between the remaining Output_section_data elements.
- uint64_t
- get_input_sections(uint64_t address, const std::string& fill,
- std::list<Simple_input_section>*);
-
- // Add an input section from a script.
- void
- add_input_section_for_script(const Simple_input_section& input_section,
- off_t data_size, uint64_t addralign);
-
- // Set the current size of the output section.
- void
- set_current_data_size(off_t size)
- { this->set_current_data_size_for_child(size); }
-
- // Get the current size of the output section.
- off_t
- current_data_size() const
- { return this->current_data_size_for_child(); }
-
- // End of linker script support.
-
- // Save states before doing section layout.
- // This is used for relaxation.
- void
- save_states();
-
- // Restore states prior to section layout.
- void
- restore_states();
-
- // Print merge statistics to stderr.
- void
- print_merge_stats();
-
- protected:
- // Return the output section--i.e., the object itself.
- Output_section*
- do_output_section()
- { return this; }
-
- // Return the section index in the output file.
- unsigned int
- do_out_shndx() const
- {
- gold_assert(this->out_shndx_ != -1U);
- return this->out_shndx_;
- }
-
- // Set the output section index.
- void
- do_set_out_shndx(unsigned int shndx)
- {
- gold_assert(this->out_shndx_ == -1U || this->out_shndx_ == shndx);
- this->out_shndx_ = shndx;
- }
-
- // Set the final data size of the Output_section. For a typical
- // Output_section, there is nothing to do, but if there are any
- // Output_section_data objects we need to set their final addresses
- // here.
- virtual void
- set_final_data_size();
-
- // Reset the address and file offset.
- void
- do_reset_address_and_file_offset();
-
- // Return true if address and file offset already have reset values. In
- // other words, calling reset_address_and_file_offset will not change them.
- bool
- do_address_and_file_offset_have_reset_values() const;
-
- // Write the data to the file. For a typical Output_section, this
- // does nothing: the data is written out by calling Object::Relocate
- // on each input object. But if there are any Output_section_data
- // objects we do need to write them out here.
- virtual void
- do_write(Output_file*);
-
- // Return the address alignment--function required by parent class.
- uint64_t
- do_addralign() const
- { return this->addralign_; }
-
- // Return whether there is a load address.
- bool
- do_has_load_address() const
- { return this->has_load_address_; }
-
- // Return the load address.
- uint64_t
- do_load_address() const
- {
- gold_assert(this->has_load_address_);
- return this->load_address_;
- }
-
- // Return whether this is an Output_section.
- bool
- do_is_section() const
- { return true; }
-
- // Return whether this is a section of the specified type.
- bool
- do_is_section_type(elfcpp::Elf_Word type) const
- { return this->type_ == type; }
-
- // Return whether the specified section flag is set.
- bool
- do_is_section_flag_set(elfcpp::Elf_Xword flag) const
- { return (this->flags_ & flag) != 0; }
-
- // Set the TLS offset. Called only for SHT_TLS sections.
- void
- do_set_tls_offset(uint64_t tls_base);
-
- // Return the TLS offset, relative to the base of the TLS segment.
- // Valid only for SHT_TLS sections.
- uint64_t
- do_tls_offset() const
- { return this->tls_offset_; }
-
- // This may be implemented by a child class.
- virtual void
- do_finalize_name(Layout*)
- { }
-
- // Print to the map file.
- virtual void
- do_print_to_mapfile(Mapfile*) const;
-
- // Record that this section requires postprocessing after all
- // relocations have been applied. This is called by a child class.
- void
- set_requires_postprocessing()
- {
- this->requires_postprocessing_ = true;
- this->after_input_sections_ = true;
- }
-
- // Write all the data of an Output_section into the postprocessing
- // buffer.
- void
- write_to_postprocessing_buffer();
-
- private:
- // In some cases we need to keep a list of the input sections
- // associated with this output section. We only need the list if we
- // might have to change the offsets of the input section within the
- // output section after we add the input section. The ordinary
- // input sections will be written out when we process the object
- // file, and as such we don't need to track them here. We do need
- // to track Output_section_data objects here. We store instances of
- // this structure in a std::vector, so it must be a POD. There can
- // be many instances of this structure, so we use a union to save
- // some space.
- class Input_section
- {
- public:
- Input_section()
- : shndx_(0), p2align_(0)
- {
- this->u1_.data_size = 0;
- this->u2_.object = NULL;
- }
-
- // For an ordinary input section.
- 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(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;
+ 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;
}
// For a non-merge output section.
Input_section(Output_section_data* posd)
- : shndx_(OUTPUT_SECTION_CODE), p2align_(0)
+ : shndx_(OUTPUT_SECTION_CODE), p2align_(0),
+ section_order_index_(0)
{
this->u1_.data_size = 0;
this->u2_.posd = posd;
: shndx_(is_string
? MERGE_STRING_SECTION_CODE
: MERGE_DATA_SECTION_CODE),
- p2align_(0)
+ p2align_(0),
+ section_order_index_(0)
{
this->u1_.entsize = entsize;
this->u2_.posd = posd;
}
// For a relaxed input section.
- Input_section(Output_relaxed_input_section *psection)
- : shndx_(RELAXED_INPUT_SECTION_CODE), p2align_(0)
+ Input_section(Output_relaxed_input_section* psection)
+ : shndx_(RELAXED_INPUT_SECTION_CODE), p2align_(0),
+ section_order_index_(0)
{
this->u1_.data_size = 0;
this->u2_.poris = psection;
}
+ unsigned int
+ section_order_index() const
+ {
+ return this->section_order_index_;
+ }
+
+ void
+ set_section_order_index(unsigned int number)
+ {
+ this->section_order_index_ = number;
+ }
+
// The required alignment.
uint64_t
addralign() const
{
- if (!this->is_input_section())
+ if (this->p2align_ != 0)
+ return static_cast<uint64_t>(1) << (this->p2align_ - 1);
+ else if (!this->is_input_section())
return this->u2_.posd->addralign();
- return (this->p2align_ == 0
- ? 0
- : static_cast<uint64_t>(1) << (this->p2align_ - 1));
+ else
+ return 0;
}
+ // Set the required alignment, which must be either 0 or a power of 2.
+ // For input sections that are sub-classes of Output_section_data, a
+ // alignment of zero means asking the underlying object for alignment.
+ void
+ set_addralign(uint64_t addralign)
+ {
+ if (addralign == 0)
+ this->p2align_ = 0;
+ else
+ {
+ gold_assert((addralign & (addralign - 1)) == 0);
+ this->p2align_ = ffsll(static_cast<long long>(addralign));
+ }
+ }
+
// Return the required size.
off_t
data_size() const;
&& this->addralign() == addralign);
}
+ // Return whether this is a merge section for some input section.
+ bool
+ is_merge_section() const
+ {
+ return (this->shndx_ == MERGE_DATA_SECTION_CODE
+ || this->shndx_ == MERGE_STRING_SECTION_CODE);
+ }
+
// Return whether this is a relaxed input section.
bool
is_relaxed_input_section() const
// Return the object for an input section.
Relobj*
- relobj() const
- {
- gold_assert(this->is_input_section());
- return this->u2_.object;
- }
+ relobj() const;
// Return the input section index for an input section.
unsigned int
- shndx() const
- {
- gold_assert(this->is_input_section());
- return this->shndx_;
- }
+ shndx() const;
// For non-input-sections, return the associated Output_section_data
// object.
return this->u2_.posd;
}
+ // For a merge section, return the Output_merge_base pointer.
+ Output_merge_base*
+ output_merge_base() const
+ {
+ gold_assert(this->is_merge_section());
+ return this->u2_.pomb;
+ }
+
// Return the Output_relaxed_input_section object.
Output_relaxed_input_section*
relaxed_input_section() const
set_output_section(Output_section* os)
{
gold_assert(!this->is_input_section());
- Output_section_data *posd =
+ Output_section_data* posd =
this->is_relaxed_input_section() ? this->u2_.poris : this->u2_.posd;
posd->set_output_section(os);
}
bool
output_offset(const Relobj* object, unsigned int shndx,
section_offset_type offset,
- section_offset_type *poutput) const;
+ section_offset_type* poutput) const;
// Return whether this is the merge section for the input section
// SHNDX in OBJECT.
// For OUTPUT_SECTION_CODE or MERGE_DATA_SECTION_CODE or
// MERGE_STRING_SECTION_CODE, the data.
Output_section_data* posd;
+ Output_merge_base* pomb;
// For RELAXED_INPUT_SECTION_CODE, the data.
Output_relaxed_input_section* poris;
} u2_;
+ // The line number of the pattern it matches in the --section-ordering-file
+ // file. It is 0 if does not match any pattern.
+ unsigned int section_order_index_;
};
+ // Store the list of input sections for this Output_section into the
+ // list passed in. This removes the input sections, leaving only
+ // any Output_section_data elements. This returns the size of those
+ // Output_section_data elements. ADDRESS is the address of this
+ // output section. FILL is the fill value to use, in case there are
+ // any spaces between the remaining Output_section_data elements.
+ uint64_t
+ get_input_sections(uint64_t address, const std::string& fill,
+ std::list<Input_section>*);
+
+ // Add a script input section. A script input section can either be
+ // a plain input section or a sub-class of Output_section_data.
+ void
+ add_script_input_section(const Input_section& input_section);
+
+ // Set the current size of the output section.
+ void
+ set_current_data_size(off_t size)
+ { this->set_current_data_size_for_child(size); }
+
+ // Get the current size of the output section.
+ off_t
+ current_data_size() const
+ { return this->current_data_size_for_child(); }
+
+ // End of linker script support.
+
+ // Save states before doing section layout.
+ // This is used for relaxation.
+ void
+ save_states();
+
+ // Restore states prior to section layout.
+ void
+ restore_states();
+
+ // Discard states.
+ void
+ discard_states();
+
+ // Convert existing input sections to relaxed input sections.
+ void
+ convert_input_sections_to_relaxed_sections(
+ const std::vector<Output_relaxed_input_section*>& sections);
+
+ // Find a relaxed input section to an input section in OBJECT
+ // with index SHNDX. Return NULL if none is found.
+ 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();
+
+ // Whether this is a NOLOAD section.
+ bool
+ is_noload() const
+ { return this->is_noload_; }
+
+ // Set NOLOAD flag.
+ void
+ set_is_noload()
+ { this->is_noload_ = true; }
+
+ // Print merge statistics to stderr.
+ void
+ print_merge_stats();
+
+ protected:
+ // Return the output section--i.e., the object itself.
+ Output_section*
+ 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
+ {
+ gold_assert(this->out_shndx_ != -1U);
+ return this->out_shndx_;
+ }
+
+ // Set the output section index.
+ void
+ do_set_out_shndx(unsigned int shndx)
+ {
+ gold_assert(this->out_shndx_ == -1U || this->out_shndx_ == shndx);
+ this->out_shndx_ = shndx;
+ }
+
+ // Set the final data size of the Output_section. For a typical
+ // Output_section, there is nothing to do, but if there are any
+ // Output_section_data objects we need to set their final addresses
+ // here.
+ virtual void
+ set_final_data_size();
+
+ // Reset the address and file offset.
+ void
+ do_reset_address_and_file_offset();
+
+ // Return true if address and file offset already have reset values. In
+ // other words, calling reset_address_and_file_offset will not change them.
+ bool
+ do_address_and_file_offset_have_reset_values() const;
+
+ // Write the data to the file. For a typical Output_section, this
+ // does nothing: the data is written out by calling Object::Relocate
+ // on each input object. But if there are any Output_section_data
+ // objects we do need to write them out here.
+ virtual void
+ do_write(Output_file*);
+
+ // Return the address alignment--function required by parent class.
+ uint64_t
+ do_addralign() const
+ { return this->addralign_; }
+
+ // Return whether there is a load address.
+ bool
+ do_has_load_address() const
+ { return this->has_load_address_; }
+
+ // Return the load address.
+ uint64_t
+ do_load_address() const
+ {
+ gold_assert(this->has_load_address_);
+ return this->load_address_;
+ }
+
+ // Return whether this is an Output_section.
+ bool
+ do_is_section() const
+ { return true; }
+
+ // Return whether this is a section of the specified type.
+ bool
+ do_is_section_type(elfcpp::Elf_Word type) const
+ { return this->type_ == type; }
+
+ // Return whether the specified section flag is set.
+ bool
+ do_is_section_flag_set(elfcpp::Elf_Xword flag) const
+ { return (this->flags_ & flag) != 0; }
+
+ // Set the TLS offset. Called only for SHT_TLS sections.
+ void
+ do_set_tls_offset(uint64_t tls_base);
+
+ // Return the TLS offset, relative to the base of the TLS segment.
+ // Valid only for SHT_TLS sections.
+ uint64_t
+ do_tls_offset() const
+ { return this->tls_offset_; }
+
+ // This may be implemented by a child class.
+ virtual void
+ do_finalize_name(Layout*)
+ { }
+
+ // Print to the map file.
+ virtual void
+ do_print_to_mapfile(Mapfile*) const;
+
+ // Record that this section requires postprocessing after all
+ // relocations have been applied. This is called by a child class.
+ void
+ set_requires_postprocessing()
+ {
+ this->requires_postprocessing_ = true;
+ this->after_input_sections_ = true;
+ }
+
+ // Write all the data of an Output_section into the postprocessing
+ // buffer.
+ void
+ write_to_postprocessing_buffer();
+
typedef std::vector<Input_section> Input_section_list;
+ // Allow a child class to access the input sections.
+ const Input_section_list&
+ input_sections() const
+ { return this->input_sections_; }
+
+ // Whether this always keeps an input section list
+ bool
+ always_keeps_input_sections() const
+ { return this->always_keeps_input_sections_; }
+
+ // Always keep an input section list.
+ void
+ set_always_keeps_input_sections()
+ {
+ gold_assert(this->current_data_size_for_child() == 0);
+ this->always_keeps_input_sections_ = true;
+ }
+
+ private:
// We only save enough information to undo the effects of section layout.
class Checkpoint_output_section
{
{ return this->flags_; }
// Return a reference to the input section list copy.
- const Input_section_list&
- input_sections() const
- { return this->input_sections_copy_; }
+ Input_section_list*
+ input_sections()
+ { return &this->input_sections_copy_; }
// Return the size of input_sections at the time when checkpoint is
// taken.
bool attached_input_sections_are_sorted_;
};
- private:
// 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;
+ };
+
+ // This is the sort comparison function when a section order is specified
+ // from an input file.
+ struct Input_section_sort_section_order_index_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
typedef std::vector<Fill> Fill_list;
+ // Map used during relaxation of existing sections. This 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
add_output_section_data(Input_section*);
// Add an SHF_MERGE input section. Returns true if the section was
- // handled.
+ // handled. If KEEPS_INPUT_SECTIONS is true, the output merge section
+ // stores information about the merged input sections.
bool
add_merge_input_section(Relobj* object, unsigned int shndx, uint64_t flags,
- uint64_t entsize, uint64_t addralign);
+ uint64_t entsize, uint64_t addralign,
+ bool keeps_input_sections);
// Add an output SHF_MERGE section POSD to this output section.
// IS_STRING indicates whether it is a SHF_STRINGS section, and
add_output_merge_section(Output_section_data* posd, bool is_string,
uint64_t entsize);
- // Relax an existing input section.
- void
- relax_input_section(Output_relaxed_input_section*);
-
// Sort the attached input sections.
void
sort_attached_input_sections();
+ // Find the merge section into which an input section with index SHNDX in
+ // OBJECT has been added. Return NULL if none found.
+ Output_section_data*
+ find_merge_section(const Relobj* object, unsigned int shndx) const;
+
+ // Build a relaxation map.
+ void
+ build_relaxation_map(
+ const Input_section_list& input_sections,
+ size_t limit,
+ Relaxation_map* map) const;
+
+ // Convert input sections in an input section list into relaxed sections.
+ void
+ convert_input_sections_in_list_to_relaxed_sections(
+ const std::vector<Output_relaxed_input_section*>& relaxed_sections,
+ const Relaxation_map& map,
+ Input_section_list* input_sections);
+
+ // Build the lookup maps for merge and relaxed input sections.
+ void
+ build_lookup_maps() const;
+
// Most of these fields are only valid after layout.
// The name of the section. This will point into a Stringpool.
const elfcpp::Elf_Word type_;
// The section flags.
elfcpp::Elf_Xword flags_;
+ // The order of this section in the output segment.
+ Output_section_order order_;
// The section index.
unsigned int out_shndx_;
// If there is a STT_SECTION for this output section in the normal
// section, false if it means the symbol index of the corresponding
// section symbol.
bool info_uses_section_index_ : 1;
+ // True if input sections attached to this output section have to be
+ // sorted according to a specified order.
+ bool input_section_order_specified_ : 1;
// True if the input sections attached to this output section may
// need sorting.
bool may_sort_attached_input_sections_ : 1;
bool attached_input_sections_are_sorted_ : 1;
// True if this section holds relro data.
bool is_relro_ : 1;
- // True if this section holds relro local data.
- bool is_relro_local_ : 1;
// True if this is a small section.
bool is_small_section_ : 1;
// True if this is a large section.
bool is_large_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;
+ // Whether this is a NOLOAD section.
+ bool is_noload_ : 1;
+ // Whether this always keeps input section.
+ bool always_keeps_input_sections_ : 1;
// For SHT_TLS sections, the offset of this section relative to the base
// of the TLS segment.
uint64_t tls_offset_;
// Saved checkpoint.
Checkpoint_output_section* checkpoint_;
+ // Fast lookup maps for merged and relaxed input sections.
+ Output_section_lookup_maps* lookup_maps_;
};
// An output segment. PT_LOAD segments are built from collections of
uint64_t
maximum_alignment();
- // Add an Output_section to this segment.
+ // Add the Output_section OS to this PT_LOAD segment. SEG_FLAGS is
+ // the segment flags to use.
+ void
+ add_output_section_to_load(Layout* layout, Output_section* os,
+ elfcpp::Elf_Word seg_flags);
+
+ // Add the Output_section OS to this non-PT_LOAD segment. SEG_FLAGS
+ // is the segment flags to use.
void
- add_output_section(Output_section* os, elfcpp::Elf_Word seg_flags);
+ add_output_section_to_nonload(Output_section* os,
+ elfcpp::Elf_Word seg_flags);
// Remove an Output_section from this segment. It is an error if it
// is not present.
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*);
// Return true if this segment has any sections which hold actual
// data, rather than being a BSS section.
bool
- has_any_data_sections() const
- { return !this->output_data_.empty(); }
+ has_any_data_sections() const;
- // Return the number of dynamic relocations applied to this segment.
- unsigned int
- dynamic_reloc_count() const;
+ // Whether this segment has a dynamic relocs.
+ bool
+ has_dynamic_reloc() const;
// Return the address of the first section.
uint64_t
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
// 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,
- unsigned int* pshndx);
+ set_section_addresses(const Layout*, bool reset, uint64_t addr,
+ unsigned int increase_relro, bool* has_relro,
+ off_t* poff, unsigned int* pshndx);
// Set the minimum alignment of this segment. This may be adjusted
// upward based on the section alignments.
void
set_minimum_p_align(uint64_t align)
- { this->min_p_align_ = align; }
+ {
+ if (align > this->min_p_align_)
+ this->min_p_align_ = align;
+ }
// 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
print_sections_to_mapfile(Mapfile*) const;
private:
- typedef std::list<Output_data*> Output_data_list;
+ typedef std::vector<Output_data*> Output_data_list;
// Find the maximum alignment in an Output_data_list.
static uint64_t
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
output_section_count_list(const Output_data_list*) const;
- // Return the number of dynamic relocs in an Output_data_list.
- unsigned int
- dynamic_reloc_count_list(const Output_data_list*) const;
+ // Return whether an Output_data_list has a dynamic reloc.
+ bool
+ has_dynamic_reloc_list(const Output_data_list*) const;
// Find the section with the lowest load address in an
// Output_data_list.
Output_section** found,
uint64_t* found_lma) const;
+ // Find the first and last entries by address.
+ void
+ find_first_and_last_list(const Output_data_list* pdl,
+ const Output_data** pfirst,
+ const Output_data** plast) const;
+
// Write the section headers in the list into V.
template<int size, bool big_endian>
unsigned char*
// NOTE: We want to use the copy constructor. Currently, shallow copy
// works for us so we do not need to write our own copy constructor.
- // The list of output data with contents attached to this segment.
- Output_data_list output_data_;
- // The list of output data without contents attached to this segment.
- Output_data_list output_bss_;
+ // The list of output data attached to this segment.
+ Output_data_list output_lists_[ORDER_MAX];
// The segment virtual address.
uint64_t vaddr_;
// The segment physical address.
void
close();
+ // Return the size of this file.
+ off_t
+ filesize()
+ { return this->file_size_; }
+
+ // Return the name of this file.
+ const char*
+ filename()
+ { return this->name_; }
+
// We currently always use mmap which makes the view handling quite
// simple. In the future we may support other approaches.