// output.h -- manage the output file for gold -*- C++ -*-
-// Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
class Sized_target;
template<int size, bool big_endian>
class Sized_relobj;
+template<int size, bool big_endian>
+class Sized_relobj_file;
// An abtract class for data which has to go into the output file.
: 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
return this->data_size_;
}
+ // Get the current data size.
+ off_t
+ current_data_size() const
+ { return this->current_data_size_for_child(); }
+
// Return true if data size is fixed.
bool
is_data_size_fixed() const
this->is_offset_valid_ = true;
}
+ // Update the data size without finalizing it.
+ void
+ pre_finalize_data_size()
+ {
+ if (!this->is_data_size_valid_)
+ {
+ // Tell the child class to update the data size.
+ this->update_data_size();
+ }
+ }
+
// Finalize the data size.
void
finalize_data_size()
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_set_out_shndx(unsigned int)
{ gold_unreachable(); }
+ // This is a hook for derived classes to set the preliminary data size.
+ // This is called by pre_finalize_data_size, normally called during
+ // Layout::finalize, before the section address is set, and is used
+ // during an incremental update, when we need to know the size of a
+ // section before allocating space in the output file. For classes
+ // where the current data size is up to date, this default version of
+ // the method can be inherited.
+ virtual void
+ update_data_size()
+ { }
+
// This is a hook for derived classes to set the data size. This is
// called by finalize_data_size, normally called during
// Layout::finalize, when the section address is set.
// 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.
do_print_to_mapfile(Mapfile* mapfile) const
{ mapfile->print_output_data(this, _("** section headers")); }
+ // Update the data size.
+ void
+ update_data_size()
+ { this->set_data_size(this->do_size()); }
+
// Set final data size.
void
set_final_data_size()
{ }
// 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
: Output_section_data(addralign)
{ }
- // Get the current data size.
- off_t
- current_data_size() const
- { return this->current_data_size_for_child(); }
+ Output_section_data_build(off_t data_size, uint64_t addralign)
+ : Output_section_data(data_size, addralign, false)
+ { }
// Set the current data size.
void
map_name_(map_name)
{ }
+ explicit Output_data_space(off_t data_size, uint64_t addralign,
+ const char* map_name)
+ : Output_section_data_build(data_size, addralign),
+ map_name_(map_name)
+ { }
+
// Set the alignment.
void
set_space_alignment(uint64_t align)
{ }
protected:
+ // This is called to update the section size prior to assigning
+ // the address and file offset.
+ void
+ update_data_size()
+ { this->set_final_data_size(); }
+
// This is called to set the address and file offset. Here we make
// sure that the Stringpool is finalized.
void
Address
symbol_value(Addend addend) const;
+ // If this relocation is against an input section, return the
+ // relocatable object containing the input section.
+ Sized_relobj<size, big_endian>*
+ get_relobj() const
+ {
+ if (this->shndx_ == INVALID_CODE)
+ return NULL;
+ return this->u2_.relobj;
+ }
+
// Write the reloc entry to an output view.
void
write(unsigned char* pov) const;
is_symbolless() const
{ return this->rel_.is_symbolless(); }
+ // If this relocation is against an input section, return the
+ // relocatable object containing the input section.
+ Sized_relobj<size, big_endian>*
+ get_relobj() const
+ { return this->rel_.get_relobj(); }
+
// Write the reloc entry to an output view.
void
write(unsigned char* pov) const;
// 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();
+ Sized_relobj<size, big_endian>* relobj = reloc.get_relobj();
+ if (relobj != NULL)
+ relobj->add_dyn_reloc(this->relocs_.size() - 1);
}
private:
void
add_local_section(Sized_relobj<size, big_endian>* relobj,
- unsigned int input_shndx, unsigned int type,
- Output_data* od, unsigned int shndx, Address address,
- Addend addend)
+ unsigned int input_shndx, unsigned int type,
+ Output_data* od, unsigned int shndx, Address address,
+ Addend addend)
{
this->add(od, Output_reloc_type(relobj, input_shndx, type, shndx,
address, addend, false, false, true));
void
add_output_section(Output_section* os, unsigned int type, Output_data* od,
Address address, Addend addend)
- { this->add(os, Output_reloc_type(os, type, od, address, addend)); }
+ { this->add(od, Output_reloc_type(os, type, od, address, addend)); }
void
- add_output_section(Output_section* os, unsigned int type,
+ add_output_section(Output_section* os, unsigned int type, Output_data* od,
Sized_relobj<size, big_endian>* relobj,
unsigned int shndx, Address address, Addend addend)
- { this->add(os, Output_reloc_type(os, type, relobj, shndx, address,
+ { this->add(od, Output_reloc_type(os, type, relobj, shndx, address,
addend)); }
// Add an absolute relocation.
{
public:
// The constructor clears *INPUT_SHNDXES.
- Output_data_group(Sized_relobj<size, big_endian>* relobj,
+ Output_data_group(Sized_relobj_file<size, big_endian>* relobj,
section_size_type entry_count,
elfcpp::Elf_Word flags,
std::vector<unsigned int>* input_shndxes);
private:
// The input object.
- Sized_relobj<size, big_endian>* relobj_;
+ Sized_relobj_file<size, big_endian>* relobj_;
// The group flag word.
elfcpp::Elf_Word flags_;
// The section indexes of the input sections in this group.
Output_data_got()
: Output_section_data_build(Output_data::default_alignment_for_size(size)),
- entries_()
+ entries_(), free_list_()
{ }
+ Output_data_got(off_t data_size)
+ : Output_section_data_build(data_size,
+ Output_data::default_alignment_for_size(size)),
+ entries_(), free_list_()
+ {
+ // For an incremental update, we have an existing GOT section.
+ // Initialize the list of entries and the free list.
+ this->entries_.resize(data_size / (size / 8));
+ this->free_list_.init(data_size, false);
+ }
+
// Add an entry for a global symbol to the GOT. Return true if this
// is a new GOT entry, false if the symbol was already in the GOT.
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
// this is a new GOT entry, false if the symbol already has a GOT
// entry.
bool
- add_local(Sized_relobj<size, big_endian>* object, unsigned int sym_index,
+ add_local(Sized_relobj_file<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_file<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
- add_local_with_rel(Sized_relobj<size, big_endian>* object,
+ add_local_with_rel(Sized_relobj_file<size, big_endian>* object,
unsigned int sym_index, unsigned int got_type,
Rel_dyn* rel_dyn, unsigned int r_type);
void
- add_local_with_rela(Sized_relobj<size, big_endian>* object,
+ add_local_with_rela(Sized_relobj_file<size, big_endian>* object,
unsigned int sym_index, unsigned int got_type,
Rela_dyn* rela_dyn, unsigned int r_type);
// Add a pair of entries for a local symbol to the GOT, and add
// dynamic relocations of type R_TYPE_1 and R_TYPE_2, respectively.
void
- add_local_pair_with_rel(Sized_relobj<size, big_endian>* object,
+ add_local_pair_with_rel(Sized_relobj_file<size, big_endian>* object,
unsigned int sym_index, unsigned int shndx,
unsigned int got_type, Rel_dyn* rel_dyn,
unsigned int r_type_1, unsigned int r_type_2);
void
- add_local_pair_with_rela(Sized_relobj<size, big_endian>* object,
+ add_local_pair_with_rela(Sized_relobj_file<size, big_endian>* object,
unsigned int sym_index, unsigned int shndx,
unsigned int got_type, Rela_dyn* rela_dyn,
unsigned int r_type_1, unsigned int r_type_2);
unsigned int
add_constant(Valtype constant)
{
- this->entries_.push_back(Got_entry(constant));
- this->set_got_size();
- return this->last_got_offset();
+ unsigned int got_offset = this->add_got_entry(Got_entry(constant));
+ return got_offset;
}
+ // Reserve a slot in the GOT.
+ void
+ reserve_slot(unsigned int i)
+ { this->free_list_.remove(i * size / 8, (i + 1) * size / 8); }
+
+ // Reserve a slot in the GOT for a local symbol.
+ void
+ reserve_local(unsigned int i, Sized_relobj<size, big_endian>* object,
+ unsigned int sym_index, unsigned int got_type);
+
+ // Reserve a slot in the GOT for a global symbol.
+ void
+ reserve_global(unsigned int i, Symbol* gsym, unsigned int got_type);
+
protected:
// Write out the GOT table.
void
public:
// Create a zero entry.
Got_entry()
- : local_sym_index_(CONSTANT_CODE)
+ : local_sym_index_(RESERVED_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)
+ Got_entry(Sized_relobj_file<size, big_endian>* object,
+ 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 != RESERVED_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,
+ RESERVED_CODE = 0x7ffffffd
};
union
{
// For a local symbol, the object.
- Sized_relobj<size, big_endian>* object;
+ Sized_relobj_file<size, big_endian>* object;
// For a global symbol, the symbol.
Symbol* gsym;
// For a constant, the constant.
} 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;
+ // Create a new GOT entry and return its offset.
+ unsigned int
+ add_got_entry(Got_entry got_entry);
+
+ // Create a pair of new GOT entries and return the offset of the first.
+ unsigned int
+ add_got_entry_pair(Got_entry got_entry_1, Got_entry got_entry_2);
+
// Return the offset into the GOT of GOT entry I.
unsigned int
got_offset(unsigned int i) const
// The list of GOT entries.
Got_entries entries_;
+
+ // List of available regions within the section, for incremental
+ // update links.
+ Free_list free_list_;
};
// Output_data_dynamic is used to hold the data in SHT_DYNAMIC
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(value.second);
+ gold_assert(result.second);
}
// Add a mapping from a merged input section in OBJECT with index 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(value.second);
+ gold_assert(result.second);
}
// Find a relaxed input section of OBJECT with index SHNDX.
value(csid, poris);
std::pair<Relaxed_input_sections_by_id::iterator, bool> result =
this->relaxed_input_sections_by_id_.insert(value);
- gold_assert(value.second);
+ gold_assert(result.second);
}
private:
// 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_file<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 to this output section.
+ // Add a relaxed input section PORIS called NAME to this output section
+ // with LAYOUT.
void
- add_relaxed_input_section(Output_relaxed_input_section* poris);
+ add_relaxed_input_section(Layout* layout,
+ Output_relaxed_input_section* poris,
+ const std::string& name);
// Return the section name.
const char*
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 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
is_large_data_section()
{ return this->is_large_section_ && this->type_ != elfcpp::SHT_NOBITS; }
- // True if this is the .interp section which goes into the PT_INTERP
- // segment.
- bool
- is_interp() const
- { return this->is_interp_; }
-
- // Record that this is the interp section.
- void
- set_is_interp()
- { this->is_interp_ = true; }
-
- // True if this is a section used by the dynamic linker.
- bool
- is_dynamic_linker_section() const
- { return this->is_dynamic_linker_section_; }
-
- // Record that this is a section used by the dynamic linker.
- void
- set_is_dynamic_linker_section()
- { this->is_dynamic_linker_section_ = true; }
-
// Return whether this section should be written after all the input
// sections are complete.
bool
Input_section(Relobj* object, unsigned int shndx, off_t data_size,
uint64_t addralign)
: shndx_(shndx),
- p2align_(ffsll(static_cast<long long>(addralign)))
+ p2align_(ffsll(static_cast<long long>(addralign))),
+ section_order_index_(0)
{
gold_assert(shndx != OUTPUT_SECTION_CODE
&& shndx != MERGE_DATA_SECTION_CODE
// 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
}
}
+ // Return the current required size, without finalization.
+ off_t
+ current_data_size() const;
+
// Return the required size.
off_t
data_size() 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 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
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.
void
print_merge_stats();
+ // Set a fixed layout for the section. Used for incremental update links.
+ void
+ set_fixed_layout(uint64_t sh_addr, off_t sh_offset, off_t sh_size,
+ uint64_t sh_addralign);
+
+ // Return TRUE if the section has a fixed layout.
+ bool
+ has_fixed_layout() const
+ { return this->has_fixed_layout_; }
+
+ // Reserve space within the fixed layout for the section. Used for
+ // incremental update links.
+ void
+ reserve(uint64_t sh_offset, uint64_t sh_size);
+
protected:
// Return the output section--i.e., the object itself.
Output_section*
this->out_shndx_ = shndx;
}
+ // Update the 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 do a trial layout
+ // here.
+ virtual void
+ update_data_size();
+
// 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
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
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
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 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_large_section_ : 1;
- // True if this is the .interp section going into the PT_INTERP
- // segment.
- bool is_interp_ : 1;
- // True if this is section is read by the dynamic linker.
- 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 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;
+ // Whether this section has a fixed layout, for incremental update links.
+ bool has_fixed_layout_ : 1;
// For SHT_TLS sections, the offset of this section relative to the base
// of the TLS segment.
uint64_t tls_offset_;
Checkpoint_output_section* checkpoint_;
// Fast lookup maps for merged and relaxed input sections.
Output_section_lookup_maps* lookup_maps_;
+ // List of available regions within the section, for incremental
+ // update links.
+ Free_list free_list_;
};
// An output segment. PT_LOAD segments are built from collections of
uint64_t
maximum_alignment();
- // Add the Output_section OS to this segment. SEG_FLAGS is the
- // segment flags to use. DO_SORT is true if we should sort the
- // placement of the input section for more efficient generated code.
+ // Add the Output_section OS to this PT_LOAD segment. SEG_FLAGS is
+ // the segment flags to use.
void
- add_output_section(Output_section* os, elfcpp::Elf_Word seg_flags,
- bool do_sort);
+ 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_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.
// 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
// 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,
- unsigned int increase_relro, off_t* poff,
- unsigned int* pshndx);
+ set_section_addresses(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.
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
// Set the section addresses in an Output_data_list.
uint64_t
- set_section_list_addresses(const Layout*, bool reset, Output_data_list*,
+ set_section_list_addresses(Layout*, bool reset, Output_data_list*,
uint64_t addr, off_t* poff, unsigned int* pshndx,
bool* in_tls);
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.
// Try to open an existing file. Returns false if the file doesn't
// exist, has a size of 0 or can't be mmaped. This method is
- // thread-unsafe.
+ // thread-unsafe. If BASE_NAME is not NULL, use the contents of
+ // that file as the base for incremental linking.
bool
- open_for_modification();
+ open_base_file(const char* base_name, bool writable);
// Open the output file. FILE_SIZE is the final size of the file.
// If the file already exists, it is deleted/truncated. This method
// Map the file into memory.
bool
- map_no_anonymous();
+ map_no_anonymous(bool);
// Unmap the file from memory (and flush to disk buffers).
void
unsigned char* base_;
// True iff base_ points to a memory buffer rather than an output file.
bool map_is_anonymous_;
+ // True if base_ was allocated using new rather than mmap.
+ bool map_is_allocated_;
// True if this is a temporary file which should not be output.
bool is_temporary_;
};