off += ssym->symsize();
}
- poc->set_space_size(off);
+ poc->set_current_data_size(off);
this->commons_.clear();
}
{
}
-// Set the final address and size of the exception frame header.
+// Set the size of the exception frame header.
void
-Eh_frame_hdr::do_set_address(uint64_t, off_t)
+Eh_frame_hdr::set_final_data_size()
{
unsigned int data_size = eh_frame_hdr_size + 4;
if (!this->any_unrecognized_eh_frame_sections_)
// Set the final data size.
void
-Eh_frame::do_set_address(uint64_t, off_t start_file_offset)
+Eh_frame::set_final_data_size()
{
+ off_t start_file_offset = this->offset();
off_t output_offset = 0;
for (Unmergeable_cie_offsets::iterator p =
// Set the final data size.
void
- do_set_address(uint64_t address, off_t offset);
+ set_final_data_size();
// Write the data to the file.
void
// Set the final data size.
void
- do_set_address(uint64_t, off_t);
+ set_final_data_size();
// Return the output address for an input address.
bool
queue_final_tasks(const General_options& options,
const Input_objects* input_objects,
const Symbol_table* symtab,
- const Layout* layout,
+ Layout* layout,
Workqueue* workqueue,
Output_file* of)
{
queue_final_tasks(const General_options&,
const Input_objects*,
const Symbol_table*,
- const Layout*,
+ Layout*,
Workqueue*,
Output_file* of);
this->got_plt_);
// The first three entries are reserved.
- this->got_plt_->set_space_size(3 * 4);
+ this->got_plt_->set_current_data_size(3 * 4);
// Define _GLOBAL_OFFSET_TABLE_ at the start of the PLT.
symtab->define_in_output_data(this, "_GLOBAL_OFFSET_TABLE_", NULL,
// Set the final size.
void
- do_set_address(uint64_t, off_t)
+ set_final_data_size()
{ this->set_data_size((this->count_ + 1) * plt_entry_size); }
// Write out the PLT data.
++this->count_;
- off_t got_offset = this->got_plt_->data_size();
+ off_t got_offset = this->got_plt_->current_data_size();
// Every PLT entry needs a GOT entry which points back to the PLT
// entry (this will be changed by the dynamic linker, normally
// lazily when the function is called).
- this->got_plt_->set_space_size(got_offset + 4);
+ this->got_plt_->set_current_data_size(got_offset + 4);
// Every PLT entry needs a reloc.
gsym->set_needs_dynsym_entry();
if (align > dynbss->addralign())
dynbss->set_space_alignment(align);
- off_t dynbss_size = dynbss->data_size();
+ off_t dynbss_size = dynbss->current_data_size();
dynbss_size = align_address(dynbss_size, align);
off_t offset = dynbss_size;
- dynbss->set_space_size(dynbss_size + symsize);
+ dynbss->set_current_data_size(dynbss_size + symsize);
symtab->define_with_copy_reloc(this, ssym, dynbss, offset);
: options_(options), namepool_(), sympool_(), dynpool_(), signatures_(),
section_name_map_(), segment_list_(), section_list_(),
unattached_section_list_(), special_output_list_(),
- tls_segment_(NULL), symtab_section_(NULL),
+ section_headers_(NULL), tls_segment_(NULL), symtab_section_(NULL),
dynsym_section_(NULL), dynamic_section_(NULL), dynamic_data_(NULL),
eh_frame_section_(NULL), output_file_size_(-1),
input_requires_executable_stack_(false),
// This is just for efficiency--it's OK if we wind up needing more.
this->segment_list_.reserve(12);
- // We expect three unattached Output_data objects: the file header,
- // the segment headers, and the section headers.
- this->special_output_list_.reserve(3);
+ // We expect two unattached Output_data objects: the file header and
+ // the segment headers.
+ this->special_output_list_.reserve(2);
}
// Hash a key we use to look up an output section mapping.
this->special_output_list_.push_back(file_header);
// We set the output section indexes in set_segment_offsets and
- // set_section_offsets.
+ // set_section_indexes.
unsigned int shndx = 1;
// Set the file offsets of all the segments, and all the sections
// they contain.
off_t off = this->set_segment_offsets(target, load_seg, &shndx);
- // Set the file offsets of all the data sections not associated with
- // segments. This makes sure that debug sections have their offsets
- // before symbols are finalized.
- off = this->set_section_offsets(off, true);
-
// Create the symbol table sections.
this->create_symtab_sections(input_objects, symtab, &off);
// Create the .shstrtab section.
Output_section* shstrtab_section = this->create_shstrtab();
- // Set the file offsets of all the non-data sections not associated with
- // segments.
+ // Set the file offsets of all the non-data sections which don't
+ // have to wait for the input sections.
off = this->set_section_offsets(off, false);
// Now that all sections have been created, set the section indexes.
shndx = this->set_section_indexes(shndx);
// Create the section table header.
- Output_section_headers* oshdrs = this->create_shdrs(&off);
+ this->create_shdrs(&off);
- file_header->set_section_info(oshdrs, shstrtab_section);
+ file_header->set_section_info(this->section_headers_, shstrtab_section);
- // Now we know exactly where everything goes in the output file.
+ // Now we know exactly where everything goes in the output file
+ // (except for non-allocated sections which require postprocessing).
Output_data::layout_complete();
this->output_file_size_ = off;
// segment.
off_t
-Layout::set_section_offsets(off_t off,
- bool do_bits_sections)
+Layout::set_section_offsets(off_t off, bool after_input_sections)
{
for (Section_list::iterator p = this->unattached_section_list_.begin();
p != this->unattached_section_list_.end();
++p)
{
- bool is_bits_section = ((*p)->type() == elfcpp::SHT_PROGBITS
- || (*p)->type() == elfcpp::SHT_NOBITS);
- if (is_bits_section != do_bits_sections)
- continue;
- if ((*p)->offset() != -1)
+ // The symtab section is handled in create_symtab_sections.
+ if (*p == this->symtab_section_)
continue;
+
+ if ((*p)->after_input_sections() != after_input_sections)
+ continue;
+
off = align_address(off, (*p)->addralign());
- (*p)->set_address(0, off);
+ (*p)->set_file_offset(off);
+ (*p)->finalize_data_size();
off += (*p)->data_size();
}
return off;
0);
this->symtab_section_ = osymtab;
- Output_section_data* pos = new Output_data_space(off - startoff,
- align);
+ Output_section_data* pos = new Output_data_fixed_space(off - startoff,
+ align);
osymtab->add_output_section_data(pos);
const char* strtab_name = this->namepool_.add(".strtab", false, NULL);
Output_section_data* pstr = new Output_data_strtab(&this->sympool_);
ostrtab->add_output_section_data(pstr);
- osymtab->set_address(0, startoff);
+ osymtab->set_file_offset(startoff);
+ osymtab->finalize_data_size();
osymtab->set_link_section(ostrtab);
osymtab->set_info(local_symcount);
osymtab->set_entsize(symsize);
const char* name = this->namepool_.add(".shstrtab", false, NULL);
- this->namepool_.set_string_offsets();
-
Output_section* os = this->make_output_section(name, elfcpp::SHT_STRTAB, 0);
+ // We can't write out this section until we've set all the section
+ // names, and we don't set the names of compressed output sections
+ // until relocations are complete.
+ os->set_after_input_sections();
+
Output_section_data* posd = new Output_data_strtab(&this->namepool_);
os->add_output_section_data(posd);
// Create the section headers. SIZE is 32 or 64. OFF is the file
// offset.
-Output_section_headers*
+void
Layout::create_shdrs(off_t* poff)
{
Output_section_headers* oshdrs;
&this->unattached_section_list_,
&this->namepool_);
off_t off = align_address(*poff, oshdrs->addralign());
- oshdrs->set_address(0, off);
+ oshdrs->set_address_and_file_offset(0, off);
off += oshdrs->data_size();
*poff = off;
- this->special_output_list_.push_back(oshdrs);
- return oshdrs;
+ this->section_headers_ = oshdrs;
}
// Create the dynamic symbol table.
elfcpp::SHT_DYNSYM,
elfcpp::SHF_ALLOC);
- Output_section_data* odata = new Output_data_space(index * symsize,
- align);
+ Output_section_data* odata = new Output_data_fixed_space(index * symsize,
+ align);
dynsym->add_output_section_data(odata);
dynsym->set_info(local_symcount);
// input sections are complete.
void
-Layout::write_sections_after_input_sections(Output_file* of) const
+Layout::write_sections_after_input_sections(Output_file* of)
{
+ // Determine the final section offsets, and thus the final output
+ // file size.
+ off_t off = this->output_file_size_;
+ off = this->set_section_offsets(off, true);
+ if (off > this->output_file_size_)
+ {
+ of->resize(off);
+ this->output_file_size_ = off;
+ }
+
for (Section_list::const_iterator p = this->section_list_.begin();
p != this->section_list_.end();
++p)
if ((*p)->after_input_sections())
(*p)->write(of);
}
+
+ for (Section_list::const_iterator p = this->unattached_section_list_.begin();
+ p != this->unattached_section_list_.end();
+ ++p)
+ {
+ if ((*p)->after_input_sections())
+ (*p)->write(of);
+ }
+
+ this->section_headers_->write(of);
}
// Write_sections_task methods.
// Write out output sections which can not be written until all the
// input sections are complete.
void
- write_sections_after_input_sections(Output_file* of) const;
+ write_sections_after_input_sections(Output_file* of);
// Return an output section named NAME, or NULL if there is none.
Output_section*
create_shstrtab();
// Create the section header table.
- Output_section_headers*
+ void
create_shdrs(off_t*);
// Create the dynamic symbol table.
// Set the final file offsets of all the sections not associated
// with a segment.
off_t
- set_section_offsets(off_t, bool do_bits_sections);
+ set_section_offsets(off_t, bool after_input_sections);
// Set the final section indexes of all the sections not associated
// with a segment. Returns the next unused index.
// The list of unattached Output_data objects which require special
// handling because they are not Output_sections.
Data_list special_output_list_;
+ // The section headers.
+ Output_section_headers* section_headers_;
// A pointer to the PT_TLS segment if there is one.
Output_segment* tls_segment_;
// The SHT_SYMTAB output section.
class Write_after_input_sections_task : public Task
{
public:
- Write_after_input_sections_task(const Layout* layout, Output_file* of,
+ Write_after_input_sections_task(Layout* layout, Output_file* of,
Task_token* input_sections_blocker,
Task_token* final_blocker)
: layout_(layout), of_(of),
private:
class Write_sections_locker;
- const Layout* layout_;
+ Layout* layout_;
Output_file* of_;
Task_token* input_sections_blocker_;
Task_token* final_blocker_;
// constants.
void
-Output_merge_data::do_set_address(uint64_t, off_t)
+Output_merge_data::set_final_data_size()
{
// Release the memory we don't need.
this->p_ = static_cast<unsigned char*>(realloc(this->p_, this->len_));
template<typename Char_type>
void
-Output_merge_string<Char_type>::do_set_address(uint64_t, off_t)
+Output_merge_string<Char_type>::set_final_data_size()
{
this->stringpool_.set_string_offsets();
// Set the final data size.
void
- do_set_address(uint64_t, off_t);
+ set_final_data_size();
// Write the data to the file.
void
// Set the final data size.
void
- do_set_address(uint64_t, off_t);
+ set_final_data_size();
// Write the data to the file.
void
// Output_data variables.
-bool Output_data::sizes_are_fixed;
+bool Output_data::allocated_sizes_are_fixed;
// Output_data methods.
{
}
-// Set the address and offset.
-
-void
-Output_data::set_address(uint64_t addr, off_t off)
-{
- this->address_ = addr;
- this->offset_ = off;
-
- // Let the child class know.
- this->do_set_address(addr, off);
-}
-
// Return the default alignment for the target size.
uint64_t
void
Output_file_header::do_write(Output_file* of)
{
+ gold_assert(this->offset() == 0);
+
if (parameters->get_size() == 32)
{
if (parameters->is_big_endian())
// Output_data_strtab methods.
-// Set the address. We don't actually care about the address, but we
-// do set our final size.
+// Set the final data size.
void
-Output_data_strtab::do_set_address(uint64_t, off_t)
+Output_data_strtab::set_final_data_size()
{
this->strtab_->set_string_offsets();
this->set_data_size(this->strtab_->get_strtab_size());
// Set the final data size.
void
-Output_data_dynamic::do_set_address(uint64_t, off_t)
+Output_data_dynamic::set_final_data_size()
{
// Add the terminating entry.
this->add_constant(elfcpp::DT_NULL, 0);
if (this->is_input_section())
this->u2_.object->set_section_offset(this->shndx_, off - secoff);
else
- this->u2_.posd->set_address(addr, off);
+ this->u2_.posd->set_address_and_file_offset(addr, off);
}
// Try to turn an input offset into an output offset.
needs_dynsym_index_(false),
should_link_to_symtab_(false),
should_link_to_dynsym_(false),
- after_input_sections_(false)
+ after_input_sections_(false),
+ requires_postprocessing_(false)
{
+ // An unallocated section has no address. Forcing this means that
+ // we don't need special treatment for symbols defined in debug
+ // sections.
+ if ((flags & elfcpp::SHF_ALLOC) == 0)
+ this->set_address(0);
}
Output_section::~Output_section()
}
}
- off_t offset_in_section = this->data_size();
+ off_t offset_in_section = this->current_data_size_for_child();
off_t aligned_offset_in_section = align_address(offset_in_section,
addralign);
}
}
- this->set_data_size(aligned_offset_in_section + shdr.get_sh_size());
+ this->set_current_data_size_for_child(aligned_offset_in_section
+ + shdr.get_sh_size());
// We need to keep track of this section if we are already keeping
// track of sections, or if we are relaxing. FIXME: Add test for
Output_section::add_output_section_data(Input_section* inp)
{
if (this->input_sections_.empty())
- this->first_input_offset_ = this->data_size();
+ this->first_input_offset_ = this->current_data_size_for_child();
this->input_sections_.push_back(*inp);
gold_unreachable();
}
-// Set the address of an Output_section. This is where we handle
+// Set the data size of an Output_section. This is where we handle
// setting the addresses of any Output_section_data objects.
void
-Output_section::do_set_address(uint64_t address, off_t startoff)
+Output_section::set_final_data_size()
{
if (this->input_sections_.empty())
- return;
+ {
+ this->set_data_size(this->current_data_size_for_child());
+ return;
+ }
+ uint64_t address = this->address();
+ off_t startoff = this->offset();
off_t off = startoff + this->first_input_offset_;
for (Input_section_list::iterator p = this->input_sections_.begin();
p != this->input_sections_.end();
++p)
{
off = align_address(off, (*p)->addralign());
- (*p)->set_address(addr + (off - startoff), off);
+ (*p)->set_address_and_file_offset(addr + (off - startoff), off);
// Unless this is a PT_TLS segment, we want to ignore the size
// of a SHF_TLS/SHT_NOBITS section. Such a section does not
gold_fatal(_("%s: open: %s"), this->name_, strerror(errno));
this->o_ = o;
+ this->map();
+}
+
+// Resize the output file.
+
+void
+Output_file::resize(off_t file_size)
+{
+ if (::munmap(this->base_, this->file_size_) < 0)
+ gold_error(_("%s: munmap: %s"), this->name_, strerror(errno));
+ this->file_size_ = file_size;
+ this->map();
+}
+
+// Map the file into memory.
+
+void
+Output_file::map()
+{
+ int o = this->o_;
+
// Write out one byte to make the file the right size.
- if (::lseek(o, file_size - 1, SEEK_SET) < 0)
+ if (::lseek(o, this->file_size_ - 1, SEEK_SET) < 0)
gold_fatal(_("%s: lseek: %s"), this->name_, strerror(errno));
char b = 0;
if (::write(o, &b, 1) != 1)
gold_fatal(_("%s: write: %s"), this->name_, strerror(errno));
// Map the file into memory.
- void* base = ::mmap(NULL, file_size, PROT_READ | PROT_WRITE,
+ void* base = ::mmap(NULL, this->file_size_, PROT_READ | PROT_WRITE,
MAP_SHARED, o, 0);
if (base == MAP_FAILED)
gold_fatal(_("%s: mmap: %s"), this->name_, strerror(errno));
class Output_data
{
public:
- explicit Output_data(off_t data_size = 0)
- : address_(0), data_size_(data_size), offset_(-1),
+ explicit Output_data()
+ : address_(0), data_size_(0), offset_(-1),
+ is_address_valid_(false), is_data_size_valid_(false),
+ is_offset_valid_(false),
dynamic_reloc_count_(0)
{ }
virtual
~Output_data();
- // Return the address. This is only valid after Layout::finalize is
- // finished.
+ // Return the address. For allocated sections, this is only valid
+ // after Layout::finalize is finished.
uint64_t
address() const
- { return this->address_; }
+ {
+ gold_assert(this->is_address_valid_);
+ return this->address_;
+ }
- // Return the size of the data. This must be valid after
- // Layout::finalize calls set_address, but need not be valid before
- // then.
+ // Return the size of the data. For allocated sections, this must
+ // be valid after Layout::finalize calls set_address, but need not
+ // be valid before then.
off_t
data_size() const
- { return this->data_size_; }
+ {
+ gold_assert(this->is_data_size_valid_);
+ return this->data_size_;
+ }
// Return the file offset. This is only valid after
- // Layout::finalize is finished.
+ // Layout::finalize is finished. For some non-allocated sections,
+ // it may not be valid until near the end of the link.
off_t
offset() const
- { return this->offset_; }
+ {
+ gold_assert(this->is_offset_valid_);
+ return this->offset_;
+ }
// Return the required alignment.
uint64_t
set_out_shndx(unsigned int shndx)
{ this->do_set_out_shndx(shndx); }
- // Set the address and file offset of this data. This is called
- // during Layout::finalize.
+ // Set the address and file offset of this data, and finalize the
+ // size of the data. This is called during Layout::finalize for
+ // allocated sections.
void
- set_address(uint64_t addr, off_t off);
+ set_address_and_file_offset(uint64_t addr, off_t off)
+ {
+ this->set_address(addr);
+ this->set_file_offset(off);
+ this->finalize_data_size();
+ }
+
+ // Set the address.
+ void
+ set_address(uint64_t addr)
+ {
+ gold_assert(!this->is_address_valid_);
+ this->address_ = addr;
+ this->is_address_valid_ = true;
+ }
+
+ // Set the file offset.
+ void
+ set_file_offset(off_t off)
+ {
+ gold_assert(!this->is_offset_valid_);
+ this->offset_ = off;
+ this->is_offset_valid_ = true;
+ }
+
+ // Finalize the data size.
+ void
+ finalize_data_size()
+ {
+ if (!this->is_data_size_valid_)
+ {
+ // Tell the child class to set the data size.
+ this->set_final_data_size();
+ gold_assert(this->is_data_size_valid_);
+ }
+ }
// Write the data to the output file. This is called after
// Layout::finalize is complete.
write(Output_file* file)
{ this->do_write(file); }
- // This is called by Layout::finalize to note that all sizes must
- // now be fixed.
+ // This is called by Layout::finalize to note that the sizes of
+ // allocated sections must now be fixed.
static void
layout_complete()
- { Output_data::sizes_are_fixed = true; }
+ { Output_data::allocated_sizes_are_fixed = true; }
// Used to check that layout has been done.
static bool
is_layout_complete()
- { return Output_data::sizes_are_fixed; }
+ { return Output_data::allocated_sizes_are_fixed; }
// Count the number of dynamic relocations applied to this section.
void
do_set_out_shndx(unsigned int)
{ gold_unreachable(); }
- // Set the address and file offset of the data. This only needs to
- // be implemented if the child needs to know. The child class can
- // set its size in this call.
+ // 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.
virtual void
- do_set_address(uint64_t, off_t)
- { }
+ set_final_data_size()
+ { gold_unreachable(); }
// Functions that child classes may call.
+ // Whether the address is valid.
+ bool
+ is_address_valid() const
+ { return this->is_address_valid_; }
+
+ // Whether the file offset is valid.
+ bool
+ is_offset_valid() const
+ { return this->is_offset_valid_; }
+
+ // Whether the data size is valid.
+ bool
+ is_data_size_valid() const
+ { return this->is_data_size_valid_; }
+
// Set the size of the data.
void
set_data_size(off_t data_size)
{
- gold_assert(!Output_data::sizes_are_fixed);
+ gold_assert(!this->is_data_size_valid_);
+ this->data_size_ = data_size;
+ this->is_data_size_valid_ = true;
+ }
+
+ // Get the current data size--this is for the convenience of
+ // sections which build up their size over time.
+ off_t
+ current_data_size_for_child() const
+ { return this->data_size_; }
+
+ // Set the current data size--this is for the convenience of
+ // sections which build up their size over time.
+ void
+ set_current_data_size_for_child(off_t data_size)
+ {
+ gold_assert(!this->is_data_size_valid_);
this->data_size_ = data_size;
}
Output_data& operator=(const Output_data&);
// This is used for verification, to make sure that we don't try to
- // change any sizes after we set the section addresses.
- static bool sizes_are_fixed;
+ // change any sizes of allocated sections after we set the section
+ // addresses.
+ static bool allocated_sizes_are_fixed;
- // Memory address in file (not always meaningful).
+ // Memory address in output file.
uint64_t address_;
- // Size of data in file.
+ // Size of data in output file.
off_t data_size_;
- // Offset within file.
+ // File offset of contents in output file.
off_t offset_;
+ // Whether address_ is valid.
+ bool is_address_valid_;
+ // Whether data_size_ is valid.
+ bool is_data_size_valid_;
+ // Whether offset_ is valid.
+ bool is_offset_valid_;
// Count of dynamic relocations applied to this section.
unsigned int dynamic_reloc_count_;
};
const Layout::Section_list*,
const Stringpool*);
+ protected:
// Write the data to the file.
void
do_write(Output_file*);
public:
Output_segment_headers(const Layout::Segment_list& segment_list);
+ protected:
// Write the data to the file.
void
do_write(Output_file*);
void set_section_info(const Output_section_headers*,
const Output_section* shstrtab);
+ protected:
// Write the data to the file.
void
do_write(Output_file*);
do_addralign() const
{ return Output_data::default_alignment(); }
- // Set the address and offset--we only implement this for error
- // checking.
- void
- do_set_address(uint64_t, off_t off) const
- { gold_assert(off == 0); }
-
private:
// Write the data to the file with the right size and endianness.
template<int size, bool big_endian>
{
public:
Output_section_data(off_t data_size, uint64_t addralign)
- : Output_data(data_size), output_section_(NULL), addralign_(addralign)
- { }
+ : Output_data(), output_section_(NULL), addralign_(addralign)
+ { this->set_data_size(data_size); }
Output_section_data(uint64_t addralign)
- : Output_data(0), output_section_(NULL), addralign_(addralign)
+ : Output_data(), output_section_(NULL), addralign_(addralign)
{ }
// Return the output section.
uint64_t addralign_;
};
+// Some Output_section_data classes build up their data step by step,
+// rather than all at once. This class provides an interface for
+// them.
+
+class Output_section_data_build : public Output_section_data
+{
+ public:
+ Output_section_data_build(uint64_t addralign)
+ : Output_section_data(addralign)
+ { }
+
+ // Get the current data size.
+ off_t
+ current_data_size() const
+ { return this->current_data_size_for_child(); }
+
+ // Set the current data size.
+ void
+ set_current_data_size(off_t data_size)
+ { this->set_current_data_size_for_child(data_size); }
+
+ protected:
+ // Set the final data size.
+ virtual void
+ set_final_data_size()
+ { this->set_data_size(this->current_data_size_for_child()); }
+};
+
// A simple case of Output_data in which we have constant data to
// output.
data_(reinterpret_cast<const char*>(p), len)
{ }
- // Add more data.
- void
- add_data(const std::string& add)
- {
- this->data_.append(add);
- this->set_data_size(this->data_.size());
- }
-
+ protected:
// Write the data to the output file.
void
do_write(Output_file*);
: Output_section_data(len, addralign), p_(p)
{ }
+ protected:
// Write the data the output file.
void
do_write(Output_file*);
const unsigned char* p_;
};
-// A place holder for data written out via some other mechanism.
+// A place holder for a fixed amount of data written out via some
+// other mechanism.
-class Output_data_space : public Output_section_data
+class Output_data_fixed_space : public Output_section_data
{
public:
- Output_data_space(off_t data_size, uint64_t addralign)
+ Output_data_fixed_space(off_t data_size, uint64_t addralign)
: Output_section_data(data_size, addralign)
{ }
- explicit Output_data_space(uint64_t addralign)
- : Output_section_data(addralign)
+ protected:
+ // Write out the data--the actual data must be written out
+ // elsewhere.
+ void
+ do_write(Output_file*)
{ }
+};
- // Set the size.
- void
- set_space_size(off_t space_size)
- { this->set_data_size(space_size); }
+// A place holder for variable sized data written out via some other
+// mechanism.
+
+class Output_data_space : public Output_section_data_build
+{
+ public:
+ explicit Output_data_space(uint64_t addralign)
+ : Output_section_data_build(addralign)
+ { }
// Set the alignment.
void
set_space_alignment(uint64_t align)
{ this->set_addralign(align); }
- // Write out the data--this must be handled elsewhere.
+ protected:
+ // Write out the data--the actual data must be written out
+ // elsewhere.
void
do_write(Output_file*)
{ }
: Output_section_data(1), strtab_(strtab)
{ }
+ protected:
// This is called to set the address and file offset. Here we make
// sure that the Stringpool is finalized.
void
- do_set_address(uint64_t, off_t);
+ set_final_data_size();
// Write out the data.
void
// the reloc type.
template<int sh_type, bool dynamic, int size, bool big_endian>
-class Output_data_reloc_base : public Output_section_data
+class Output_data_reloc_base : public Output_section_data_build
{
public:
typedef Output_reloc<sh_type, dynamic, size, big_endian> Output_reloc_type;
// Construct the section.
Output_data_reloc_base()
- : Output_section_data(Output_data::default_alignment_for_size(size))
+ : Output_section_data_build(Output_data::default_alignment_for_size(size))
{ }
+ protected:
// Write out the data.
void
do_write(Output_file*);
- protected:
// Set the entry size and the link.
void
do_adjust_output_section(Output_section *os);
add(Output_data *od, const Output_reloc_type& reloc)
{
this->relocs_.push_back(reloc);
- this->set_data_size(this->relocs_.size() * reloc_size);
+ this->set_current_data_size(this->relocs_.size() * reloc_size);
od->add_dynamic_reloc();
}
// needed.
template<int size, bool big_endian>
-class Output_data_got : public Output_section_data
+class Output_data_got : public Output_section_data_build
{
public:
typedef typename elfcpp::Elf_types<size>::Elf_Addr Valtype;
Output_data_got()
- : Output_section_data(Output_data::default_alignment_for_size(size)),
+ : Output_section_data_build(Output_data::default_alignment_for_size(size)),
entries_()
{ }
return this->last_got_offset();
}
+ protected:
// Write out the GOT table.
void
do_write(Output_file*);
// Set the size of the section.
void
set_got_size()
- { this->set_data_size(this->got_offset(this->entries_.size())); }
+ { this->set_current_data_size(this->got_offset(this->entries_.size())); }
// The list of GOT entries.
Got_entries entries_;
add_string(elfcpp::DT tag, const std::string& str)
{ this->add_string(tag, str.c_str()); }
+ protected:
+ // Adjust the output section to set the entry size.
+ void
+ do_adjust_output_section(Output_section*);
+
// Set the final data size.
void
- do_set_address(uint64_t, off_t);
+ set_final_data_size();
// Write out the dynamic entries.
void
do_write(Output_file*);
- protected:
- // Adjust the output section to set the entry size.
- void
- do_adjust_output_section(Output_section*);
-
private:
// This POD class holds a single dynamic entry.
class Dynamic_entry
flags() const
{ return this->flags_; }
- // 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;
- }
-
// Return the entsize field.
uint64_t
entsize() const
set_after_input_sections()
{ this->after_input_sections_ = true; }
+ // Return whether this section requires postprocessing after all
+ // relocations have been applied.
+ bool
+ requires_postprocessing() const
+ { return this->requires_postprocessing_; }
+
+ // Record that this section requires postprocessing after all
+ // relocations have been applied.
+ void
+ set_requires_postprocessing()
+ { this->requires_postprocessing_ = true; }
+
// Return whether the offset OFFSET in the input section SHNDX in
// object OBJECT is being included in the link.
bool
output_address(const Relobj* object, unsigned int shndx,
off_t offset) const;
- // Set the address of the Output_section. For a typical
+ // Write the section header into *OPHDR.
+ template<int size, bool big_endian>
+ void
+ write_header(const Layout*, const Stringpool*,
+ elfcpp::Shdr_write<size, big_endian>*) const;
+
+ protected:
+ // 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;
+ }
+
+ // 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 the final addresses
+ // Output_section_data objects we need to set their final addresses
// here.
void
- do_set_address(uint64_t, off_t);
+ set_final_data_size();
// Write the data to the file. For a typical Output_section, this
// does nothing: the data is written out by calling Object::Relocate
do_is_section_flag_set(elfcpp::Elf_Xword flag) const
{ return (this->flags_ & flag) != 0; }
- // Write the section header into *OPHDR.
- template<int size, bool big_endian>
- void
- write_header(const Layout*, const Stringpool*,
- elfcpp::Shdr_write<size, big_endian>*) const;
-
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
// Most of these fields are only valid after layout.
// The name of the section. This will point into a Stringpool.
- const char* name_;
+ const char* const name_;
// The section address is in the parent class.
// The section alignment.
uint64_t addralign_;
// If info_section_ is NULL, this is the section info field.
unsigned int info_;
// The section type.
- elfcpp::Elf_Word type_;
+ const elfcpp::Elf_Word type_;
// The section flags.
- elfcpp::Elf_Xword flags_;
+ const elfcpp::Elf_Xword flags_;
// The section index.
unsigned int out_shndx_;
// If there is a STT_SECTION for this output section in the normal
// Whether this section should be written after all the input
// sections are complete.
bool after_input_sections_ : 1;
+ // Whether this section requires post processing after all
+ // relocations have been applied.
+ bool requires_postprocessing_ : 1;
};
// An output segment. PT_LOAD segments are built from collections of
void
open(off_t file_size);
+ // Resize the output file.
+ void
+ resize(off_t file_size);
+
// Close the output file and make sure there are no error.
void
close();
{ }
private:
+ // Map the file into memory.
+ void
+ map();
+
// General options.
const General_options& options_;
// Target.
this->got_plt_);
// The first three entries are reserved.
- this->got_plt_->set_space_size(3 * 8);
+ this->got_plt_->set_current_data_size(3 * 8);
// Define _GLOBAL_OFFSET_TABLE_ at the start of the PLT.
symtab->define_in_output_data(this, "_GLOBAL_OFFSET_TABLE_", NULL,
// Set the final size.
void
- do_set_address(uint64_t, off_t)
+ set_final_data_size()
{ this->set_data_size((this->count_ + 1) * plt_entry_size); }
// Write out the PLT data.
++this->count_;
- off_t got_offset = this->got_plt_->data_size();
+ off_t got_offset = this->got_plt_->current_data_size();
// Every PLT entry needs a GOT entry which points back to the PLT
// entry (this will be changed by the dynamic linker, normally
// lazily when the function is called).
- this->got_plt_->set_space_size(got_offset + 8);
+ this->got_plt_->set_current_data_size(got_offset + 8);
// Every PLT entry needs a reloc.
gsym->set_needs_dynsym_entry();
if (align > dynbss->addralign())
dynbss->set_space_alignment(align);
- off_t dynbss_size = dynbss->data_size();
+ off_t dynbss_size = dynbss->current_data_size();
dynbss_size = align_address(dynbss_size, align);
off_t offset = dynbss_size;
- dynbss->set_space_size(dynbss_size + symsize);
+ dynbss->set_current_data_size(dynbss_size + symsize);
symtab->define_with_copy_reloc(this, ssym, dynbss, offset);