#include <vector>
#include "elfcpp.h"
+#include "mapfile.h"
#include "layout.h"
#include "reloc-types.h"
is_data_size_valid() const
{ return this->is_data_size_valid_; }
+ // Print information to the map file.
+ void
+ print_to_mapfile(Mapfile* mapfile) const
+ { return this->do_print_to_mapfile(mapfile); }
+
protected:
// Functions that child classes may or in some cases must implement.
do_tls_offset() const
{ gold_unreachable(); }
+ // Print to the map file. This only needs to be implemented by
+ // classes which may appear in a PT_LOAD segment.
+ virtual void
+ do_print_to_mapfile(Mapfile*) const
+ { gold_unreachable(); }
+
// Functions that child classes may call.
// Set the size of the data.
do_addralign() const
{ return Output_data::default_alignment(); }
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, _("** section headers")); }
+
private:
// Write the data to the file with the right size and endianness.
template<int size, bool big_endian>
do_addralign() const
{ return Output_data::default_alignment(); }
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, _("** segment headers")); }
+
private:
// Write the data to the file with the right size and endianness.
template<int size, bool big_endian>
do_addralign() const
{ return Output_data::default_alignment(); }
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, _("** file header")); }
+
private:
// Write the data to the file with the right size and endianness.
template<int size, bool big_endian>
do_write_to_buffer(unsigned char* buffer)
{ memcpy(buffer, this->data_.data(), this->data_.size()); }
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, _("** fill")); }
+
private:
std::string data_;
};
{
public:
Output_data_const_buffer(const unsigned char* p, off_t len,
- uint64_t addralign)
- : Output_section_data(len, addralign), p_(p)
+ uint64_t addralign, const char* map_name)
+ : Output_section_data(len, addralign),
+ p_(p), map_name_(map_name)
{ }
protected:
do_write_to_buffer(unsigned char* buffer)
{ memcpy(buffer, this->p_, this->data_size()); }
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, _(this->map_name_)); }
+
private:
+ // The data to output.
const unsigned char* p_;
+ // Name to use in a map file. Maps are a rarely used feature, but
+ // the space usage is minor as aren't very many of these objects.
+ const char* map_name_;
};
// A place holder for a fixed amount of data written out via some
class Output_data_fixed_space : public Output_section_data
{
public:
- Output_data_fixed_space(off_t data_size, uint64_t addralign)
- : Output_section_data(data_size, addralign)
+ Output_data_fixed_space(off_t data_size, uint64_t addralign,
+ const char* map_name)
+ : Output_section_data(data_size, addralign),
+ map_name_(map_name)
{ }
protected:
void
do_write(Output_file*)
{ }
+
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, _(this->map_name_)); }
+
+ private:
+ // Name to use in a map file. Maps are a rarely used feature, but
+ // the space usage is minor as aren't very many of these objects.
+ const char* map_name_;
};
// A place holder for variable sized data written out via some other
class Output_data_space : public Output_section_data_build
{
public:
- explicit Output_data_space(uint64_t addralign)
- : Output_section_data_build(addralign)
+ explicit Output_data_space(uint64_t addralign, const char* map_name)
+ : Output_section_data_build(addralign),
+ map_name_(map_name)
{ }
// Set the alignment.
void
do_write(Output_file*)
{ }
+
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, _(this->map_name_)); }
+
+ private:
+ // Name to use in a map file. Maps are a rarely used feature, but
+ // the space usage is minor as aren't very many of these objects.
+ const char* map_name_;
+};
+
+// Fill fixed space with zeroes. This is just like
+// Output_data_fixed_space, except that the map name is known.
+
+class Output_data_zero_fill : public Output_section_data
+{
+ public:
+ Output_data_zero_fill(off_t data_size, uint64_t addralign)
+ : Output_section_data(data_size, addralign)
+ { }
+
+ protected:
+ // There is no data to write out.
+ void
+ do_write(Output_file*)
+ { }
+
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, "** zero fill"); }
};
// A string table which goes into an output section.
do_write_to_buffer(unsigned char* buffer)
{ this->strtab_->write_to_buffer(buffer, this->data_size()); }
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, _("** string table")); }
+
private:
Stringpool* strtab_;
};
Output_reloc(Symbol* gsym, unsigned int type, Output_data* od,
Address address, bool is_relative);
- Output_reloc(Symbol* gsym, unsigned int type, Relobj* relobj,
+ Output_reloc(Symbol* gsym, unsigned int type,
+ Sized_relobj<size, big_endian>* relobj,
unsigned int shndx, Address address, bool is_relative);
// A reloc against a local symbol or local section symbol.
Output_reloc(Output_section* os, unsigned int type, Output_data* od,
Address address);
- Output_reloc(Output_section* os, unsigned int type, Relobj* relobj,
+ Output_reloc(Output_section* os, unsigned int type,
+ Sized_relobj<size, big_endian>* relobj,
unsigned int shndx, Address address);
// Return TRUE if this is a RELATIVE relocation.
// 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.
- section_offset_type
+ Address
local_section_offset(Addend addend) const;
// Get the value of the symbol referred to by a Rel relocation when
template<typename Write_rel>
void write_rel(Write_rel*) const;
+ // This is used when sorting dynamic relocs. Return -1 to sort this
+ // reloc before R2, 0 to sort the same as R2, 1 to sort after R2.
+ int
+ compare(const Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>& r2)
+ const;
+
+ // Return whether this reloc should be sorted before the argument
+ // when sorting dynamic relocs.
+ bool
+ sort_before(const Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>&
+ r2) const
+ { return this->compare(r2) < 0; }
+
private:
// Record that we need a dynamic symbol index.
void
unsigned int
get_symbol_index() const;
+ // Return the output address.
+ Address
+ get_address() const;
+
// Codes for local_sym_index_.
enum
{
{
// If this->shndx_ is not INVALID CODE, the object which holds the
// input section being used to specify the reloc address.
- Relobj* relobj;
+ Sized_relobj<size, big_endian>* relobj;
// If this->shndx_ is INVALID_CODE, the output data being used to
// specify the reloc address. This may be NULL if the reloc
// address is absolute.
: rel_(gsym, type, od, address, is_relative), addend_(addend)
{ }
- Output_reloc(Symbol* gsym, unsigned int type, Relobj* relobj,
+ 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)
: rel_(os, type, od, address), addend_(addend)
{ }
- Output_reloc(Output_section* os, unsigned int type, Relobj* relobj,
+ Output_reloc(Output_section* os, unsigned int type,
+ Sized_relobj<size, big_endian>* relobj,
unsigned int shndx, Address address, Addend addend)
: rel_(os, type, relobj, shndx, address), addend_(addend)
{ }
void
write(unsigned char* pov) const;
+ // Return whether this reloc should be sorted before the argument
+ // when sorting dynamic relocs.
+ bool
+ sort_before(const Output_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>&
+ r2) const
+ {
+ int i = this->rel_.compare(r2.rel_);
+ if (i < 0)
+ return true;
+ else if (i > 0)
+ return false;
+ else
+ return this->addend_ < r2.addend_;
+ }
+
private:
// The basic reloc.
Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian> rel_;
Reloc_types<sh_type, size, big_endian>::reloc_size;
// Construct the section.
- Output_data_reloc_base()
- : Output_section_data_build(Output_data::default_alignment_for_size(size))
+ Output_data_reloc_base(bool sort_relocs)
+ : Output_section_data_build(Output_data::default_alignment_for_size(size)),
+ sort_relocs_(sort_relocs)
{ }
protected:
void
do_adjust_output_section(Output_section *os);
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ {
+ mapfile->print_output_data(this,
+ (dynamic
+ ? _("** dynamic relocs")
+ : _("** relocs")));
+ }
+
// Add a relocation entry.
void
add(Output_data *od, const Output_reloc_type& reloc)
private:
typedef std::vector<Output_reloc_type> Relocs;
+ // The class used to sort the relocations.
+ struct Sort_relocs_comparison
+ {
+ bool
+ operator()(const Output_reloc_type& r1, const Output_reloc_type& r2) const
+ { return r1.sort_before(r2); }
+ };
+
+ // 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.
typedef typename Base::Output_reloc_type Output_reloc_type;
typedef typename Output_reloc_type::Address Address;
- Output_data_reloc()
- : Output_data_reloc_base<elfcpp::SHT_REL, dynamic, size, big_endian>()
+ Output_data_reloc(bool sr)
+ : Output_data_reloc_base<elfcpp::SHT_REL, dynamic, size, big_endian>(sr)
{ }
// Add a reloc against a global symbol.
{ this->add(od, Output_reloc_type(gsym, type, od, address, false)); }
void
- add_global(Symbol* gsym, unsigned int type, Output_data* od, Relobj* relobj,
+ 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)); }
}
void
- add_global(Symbol* gsym, unsigned int type, Output_data* od, Relobj* relobj,
+ add_global(Symbol* gsym, unsigned int type, Output_data* od,
+ Sized_relobj<size, big_endian>* relobj,
unsigned int shndx, Address address, Address addend)
{
gold_assert(addend == 0);
void
add_global_relative(Symbol* gsym, unsigned int type, Output_data* od,
- Relobj* relobj, unsigned int shndx, Address address)
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address)
{
this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
true));
void
add_output_section(Output_section* os, unsigned int type, Output_data* od,
- Relobj* relobj, unsigned int shndx, Address address)
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address)
{ this->add(od, Output_reloc_type(os, type, relobj, shndx, address)); }
};
typedef typename Output_reloc_type::Address Address;
typedef typename Output_reloc_type::Addend Addend;
- Output_data_reloc()
- : Output_data_reloc_base<elfcpp::SHT_RELA, dynamic, size, big_endian>()
+ Output_data_reloc(bool sr)
+ : Output_data_reloc_base<elfcpp::SHT_RELA, dynamic, size, big_endian>(sr)
{ }
// Add a reloc against a global symbol.
false)); }
void
- add_global(Symbol* gsym, unsigned int type, Output_data* od, Relobj* relobj,
+ add_global(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,
void
add_global_relative(Symbol* gsym, unsigned int type, Output_data* od,
- Relobj* relobj, unsigned int shndx, Address address,
- Addend addend)
+ 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)); }
{ this->add(os, Output_reloc_type(os, type, od, address, addend)); }
void
- add_output_section(Output_section* os, unsigned int type, Relobj* relobj,
+ add_output_section(Output_section* os, unsigned int type,
+ Sized_relobj<size, big_endian>* relobj,
unsigned int shndx, Address address, Addend addend)
{ this->add(os, Output_reloc_type(os, type, relobj, shndx, address,
addend)); }
do_write(Output_file*)
{ }
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, _("** relocs")); }
+
private:
// The relocs associated with this input section.
Relocatable_relocs* rr_;
void
do_write(Output_file*);
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, _("** group")); }
+
private:
// The input object.
Sized_relobj<size, big_endian>* relobj_;
void
do_write(Output_file*);
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, _("** GOT")); }
+
private:
// This POD class holds a single GOT entry.
class Got_entry
void
do_write(Output_file*);
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, _("** dynamic")); }
+
private:
// This POD class holds a single dynamic entry.
class Dynamic_entry
void
do_write(Output_file*);
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, _("** symtab xindex")); }
+
private:
template<bool big_endian>
void
set_must_sort_attached_input_sections()
{ this->must_sort_attached_input_sections_ = true; }
+ // 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.
+ bool
+ is_relro() const
+ { return this->is_relro_; }
+
+ // Record that this section holds relro data.
+ void
+ set_is_relro()
+ { this->is_relro_ = true; }
+
+ // 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; }
+
// Return whether this section should be written after all the input
// sections are complete.
bool
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
// For a non-merge output section.
Input_section(Output_section_data* posd)
- : shndx_(OUTPUT_SECTION_CODE),
- p2align_(ffsll(static_cast<long long>(posd->addralign())))
+ : shndx_(OUTPUT_SECTION_CODE), p2align_(0)
{
this->u1_.data_size = 0;
this->u2_.posd = posd;
: shndx_(is_string
? MERGE_STRING_SECTION_CODE
: MERGE_DATA_SECTION_CODE),
- p2align_(ffsll(static_cast<long long>(posd->addralign())))
+ p2align_(0)
{
this->u1_.entsize = entsize;
this->u2_.posd = posd;
uint64_t
addralign() const
{
+ if (!this->is_input_section())
+ return this->u2_.posd->addralign();
return (this->p2align_ == 0
? 0
: static_cast<uint64_t>(1) << (this->p2align_ - 1));
void
write_to_buffer(unsigned char*);
+ // Print to a map file.
+ void
+ print_to_mapfile(Mapfile*) const;
+
// Print statistics about merge sections to stderr.
void
print_merge_stats(const char* section_name)
// True if the input sections attached to this output section have
// already been sorted.
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;
// For SHT_TLS sections, the offset of this section relative to the base
// of the TLS segment.
uint64_t tls_offset_;
// Add an Output_section to this segment.
void
- add_output_section(Output_section* os, elfcpp::Elf_Word seg_flags)
- { this->add_output_section(os, seg_flags, false); }
-
- // Add an Output_section to the start of this segment.
- void
- add_initial_output_section(Output_section* os, elfcpp::Elf_Word seg_flags)
- { this->add_output_section(os, seg_flags, true); }
+ add_output_section(Output_section* os, elfcpp::Elf_Word seg_flags);
// Remove an Output_section from this segment. It is an error if it
// is not present.
write_section_headers(const Layout*, const Stringpool*, unsigned char* v,
unsigned int* pshndx) const;
+ // Print the output sections in the map file.
+ void
+ print_sections_to_mapfile(Mapfile*) const;
+
private:
Output_segment(const Output_segment&);
Output_segment& operator=(const Output_segment&);
typedef std::list<Output_data*> Output_data_list;
- // Add an Output_section to this segment, specifying front or back.
- void
- add_output_section(Output_section*, elfcpp::Elf_Word seg_flags,
- bool front);
-
// Find the maximum alignment in an Output_data_list.
static uint64_t
maximum_alignment_list(const Output_data_list*);
+ // Return whether the first data section is a relro section.
+ bool
+ is_first_section_relro() const;
+
// Set the section addresses in an Output_data_list.
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_tls, bool* in_relro);
// Return the number of Output_sections in an Output_data_list.
unsigned int
const Output_data_list*, unsigned char* v,
unsigned int* pshdx) const;
+ // Print a section list to the mapfile.
+ void
+ print_section_list_to_mapfile(Mapfile*, const Output_data_list*) const;
+
// 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.