// 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.
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()
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.
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
// within the output section.
template<int size, bool big_endian>
off_t
- add_input_section(Layout* layout, 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*
}
// For a relaxed input section.
- Input_section(Output_relaxed_input_section *psection)
+ Input_section(Output_relaxed_input_section* psection)
: shndx_(RELAXED_INPUT_SECTION_CODE), p2align_(0),
section_order_index_(0)
{
}
}
+ // 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.
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
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
// 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.
// 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);
// 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_;
};