// Queue a task to write out the symbol table.
final_blocker->add_blocker();
- workqueue->queue(new Write_symbols_task(symtab, input_objects->target(),
- layout->sympool(), of,
+ workqueue->queue(new Write_symbols_task(symtab,
+ input_objects->target(),
+ layout->sympool(),
+ layout->dynpool(),
+ of,
final_blocker));
// Queue a task to write out everything else.
// Finalize the sections.
void
- do_finalize_sections(Layout*);
+ do_finalize_sections(const General_options*, Layout*);
// Relocate a section.
void
this->got_ = new Output_data_got<32, false>(options);
layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
- elfcpp::SHF_ALLOC, this->got_);
+ elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
+ this->got_);
// The old GNU linker creates a .got.plt section. We just
// create another set of data in the .got section. Note that we
// might be empty.
this->got_plt_ = new Output_data_space(4);
layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
- elfcpp::SHF_ALLOC, this->got_plt_);
+ elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
+ this->got_plt_);
// The first three entries are reserved.
this->got_plt_->set_space_size(3 * 4);
symtab->define_in_output_data(this, "_GLOBAL_OFFSET_TABLE_",
this->got_plt_,
0, 0, elfcpp::STT_OBJECT,
- elfcpp::STB_GLOBAL,
+ elfcpp::STB_LOCAL,
elfcpp::STV_HIDDEN, 0,
false, false);
}
void
add_entry(Symbol* gsym);
+ // Return the .rel.plt section data.
+ const Reloc_section*
+ rel_plt() const
+ { return this->rel_; }
+
+ protected:
+ void
+ do_adjust_output_section(Output_section* os);
+
private:
// The size of an entry in the PLT.
static const int plt_entry_size = 16;
elfcpp::SHF_ALLOC, this->rel_);
}
+// For some reason
+
+void
+Output_data_plt_i386::do_adjust_output_section(Output_section* os)
+{
+ // UnixWare sets the entsize of .plt to 4, and so does the old GNU
+ // linker, and so do we.
+ os->set_entsize(4);
+}
+
// Add an entry to the PLT.
void
this->got_plt_->set_space_size(got_offset + 4);
// Every PLT entry needs a reloc.
+ gsym->set_needs_dynsym_entry();
this->rel_->add_global(gsym, elfcpp::R_386_JUMP_SLOT, this->got_plt_,
got_offset);
this->plt_ = new Output_data_plt_i386(layout, this->got_plt_,
options->is_shared());
+ layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
+ (elfcpp::SHF_ALLOC
+ | elfcpp::SHF_EXECINSTR),
+ this->plt_);
}
this->plt_->add_entry(gsym);
false, false);
// Add the COPY reloc.
+ ssym->set_needs_dynsym_entry();
Reloc_section* rel_dyn = this->rel_dyn_section(layout);
rel_dyn->add_global(ssym, elfcpp::R_386_COPY, dynbss, offset);
}
global_symbols);
}
-// Finalize the sections. This is where we emit any relocs we saved
-// in an attempt to avoid generating extra COPY relocs.
+// Finalize the sections.
void
-Target_i386::do_finalize_sections(Layout* layout)
+Target_i386::do_finalize_sections(const General_options* options,
+ Layout* layout)
{
+ // Fill in some more dynamic tags.
+ Output_data_dynamic* const odyn = layout->dynamic_data();
+ if (odyn != NULL)
+ {
+ if (this->got_plt_ != NULL)
+ odyn->add_section_address(elfcpp::DT_PLTGOT, this->got_plt_);
+
+ if (this->plt_ != NULL)
+ {
+ const Output_data* od = this->plt_->rel_plt();
+ odyn->add_section_size(elfcpp::DT_PLTRELSZ, od);
+ odyn->add_section_address(elfcpp::DT_JMPREL, od);
+ odyn->add_constant(elfcpp::DT_PLTREL, elfcpp::DT_REL);
+ }
+
+ if (this->rel_dyn_ != NULL)
+ {
+ const Output_data* od = this->rel_dyn_;
+ odyn->add_section_address(elfcpp::DT_REL, od);
+ odyn->add_section_size(elfcpp::DT_RELSZ, od);
+ odyn->add_constant(elfcpp::DT_RELENT,
+ elfcpp::Elf_sizes<32>::rel_size);
+ }
+
+ if (!options->is_shared())
+ {
+ // The value of the DT_DEBUG tag is filled in by the dynamic
+ // linker at run time, and used by the debugger.
+ odyn->add_constant(elfcpp::DT_DEBUG, 0);
+ }
+ }
+
+ // Emit any relocs we saved in an attempt to avoid generating COPY
+ // relocs.
if (this->copy_relocs_ == NULL)
return;
if (this->copy_relocs_->any_to_emit())
if (gsym != NULL && gsym->is_defined_in_dynobj())
{
if (gsym->has_plt_offset())
- address = target->plt_section()->address() + gsym->plt_offset();
+ value = target->plt_section()->address() + gsym->plt_offset();
else
gold_unreachable();
}
: 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), dynsym_section_(NULL)
+ tls_segment_(NULL), symtab_section_(NULL), dynsym_section_(NULL),
+ dynamic_section_(NULL), dynamic_data_(NULL)
{
// Make space for more than enough segments for a typical file.
// This is just for efficiency--it's OK if we wind up needing more.
this->dynamic_section_, 0, 0,
elfcpp::STT_OBJECT, elfcpp::STB_LOCAL,
elfcpp::STV_HIDDEN, 0, false, false);
+
+ this->dynamic_data_ = new Output_data_dynamic(input_objects->target(),
+ &this->dynpool_);
+
+ this->dynamic_section_->add_output_section_data(this->dynamic_data_);
}
// Find the first read-only PT_LOAD segment, creating one if
Target* const target = input_objects->target();
const int size = target->get_size();
- target->finalize_sections(this);
+ target->finalize_sections(&this->options_, this);
Output_segment* phdr_seg = NULL;
if (input_objects->any_dynamic())
phdr_seg = new Output_segment(elfcpp::PT_PHDR, elfcpp::PF_R);
this->segment_list_.push_back(phdr_seg);
- // This holds the dynamic tags.
- Output_data_dynamic* odyn;
- odyn = new Output_data_dynamic(input_objects->target(),
- &this->dynpool_);
-
// Create the dynamic symbol table, including the hash table,
// the dynamic relocations, and the version sections.
- this->create_dynamic_symtab(target, odyn, symtab);
+ this->create_dynamic_symtab(target, symtab);
// Create the .interp section to hold the name of the
// interpreter, and put it in a PT_INTERP segment.
// Finish the .dynamic section to hold the dynamic data, and put
// it in a PT_DYNAMIC segment.
- this->finish_dynamic_section(input_objects, symtab, odyn);
+ this->finish_dynamic_section(input_objects, symtab);
}
// FIXME: Handle PT_GNU_STACK.
// Create the symbol table sections.
// FIXME: We don't need to do this if we are stripping symbols.
- Output_section* ostrtab;
- this->create_symtab_sections(size, input_objects, symtab, &off,
- &ostrtab);
+ this->create_symtab_sections(size, input_objects, symtab, &off);
// Create the .shstrtab section.
Output_section* shstrtab_section = this->create_shstrtab();
// segments.
off = this->set_section_offsets(off, &shndx);
- // Now the section index of OSTRTAB is set.
- this->symtab_section_->set_link(ostrtab->out_shndx());
-
// Create the section table header.
Output_section_headers* oshdrs = this->create_shdrs(size, big_endian, &off);
void
Layout::create_symtab_sections(int size, const Input_objects* input_objects,
Symbol_table* symtab,
- off_t* poff,
- Output_section** postrtab)
+ off_t* poff)
{
int symsize;
unsigned int align;
unsigned int local_symcount = local_symbol_index;
gold_assert(local_symcount * symsize == off - startoff);
- off = symtab->finalize(local_symcount, off, &this->sympool_);
+ off_t dynoff;
+ size_t dyn_global_index;
+ size_t dyncount;
+ if (this->dynsym_section_ == NULL)
+ {
+ dynoff = 0;
+ dyn_global_index = 0;
+ dyncount = 0;
+ }
+ else
+ {
+ dyn_global_index = this->dynsym_section_->info();
+ off_t locsize = dyn_global_index * this->dynsym_section_->entsize();
+ dynoff = this->dynsym_section_->offset() + locsize;
+ dyncount = (this->dynsym_section_->data_size() - locsize) / symsize;
+ gold_assert(dyncount * symsize
+ == this->dynsym_section_->data_size() - locsize);
+ }
+
+ off = symtab->finalize(local_symcount, off, dynoff, dyn_global_index,
+ dyncount, &this->sympool_);
this->sympool_.set_string_offsets();
ostrtab->add_output_section_data(pstr);
osymtab->set_address(0, startoff);
+ osymtab->set_link_section(ostrtab);
osymtab->set_info(local_symcount);
osymtab->set_entsize(symsize);
*poff = off;
- *postrtab = ostrtab;
}
// Create the .shstrtab section, which holds the names of the
Layout::create_shdrs(int size, bool big_endian, off_t* poff)
{
Output_section_headers* oshdrs;
- oshdrs = new Output_section_headers(size, big_endian, this->segment_list_,
- this->unattached_section_list_,
+ oshdrs = new Output_section_headers(size, big_endian, this,
+ &this->segment_list_,
+ &this->unattached_section_list_,
&this->namepool_);
off_t off = align_address(*poff, oshdrs->addralign());
oshdrs->set_address(0, off);
// Create the dynamic symbol table.
void
-Layout::create_dynamic_symtab(const Target* target, Output_data_dynamic* odyn,
- Symbol_table* symtab)
+Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab)
{
// Count all the symbols in the dynamic symbol table, and set the
// dynamic symbol indexes.
this->dynsym_section_ = dynsym;
+ Output_data_dynamic* const odyn = this->dynamic_data_;
odyn->add_section_address(elfcpp::DT_SYMTAB, dynsym);
odyn->add_constant(elfcpp::DT_SYMENT, symsize);
Output_section_data* strdata = new Output_data_strtab(&this->dynpool_);
dynstr->add_output_section_data(strdata);
+ dynsym->set_link_section(dynstr);
+ this->dynamic_section_->set_link_section(dynstr);
+
odyn->add_section_address(elfcpp::DT_STRTAB, dynstr);
odyn->add_section_size(elfcpp::DT_STRSZ, dynstr);
align);
hashsec->add_output_section_data(hashdata);
+ hashsec->set_link_section(dynsym);
hashsec->set_entsize(4);
- // FIXME: .hash should link to .dynsym.
odyn->add_section_address(elfcpp::DT_HASH, hashsec);
}
void
Layout::finish_dynamic_section(const Input_objects* input_objects,
- const Symbol_table* symtab,
- Output_data_dynamic* odyn)
+ const Symbol_table* symtab)
{
- this->dynamic_section_->add_output_section_data(odyn);
-
Output_segment* oseg = new Output_segment(elfcpp::PT_DYNAMIC,
elfcpp::PF_R | elfcpp::PF_W);
this->segment_list_.push_back(oseg);
oseg->add_initial_output_section(this->dynamic_section_,
elfcpp::PF_R | elfcpp::PF_W);
+ Output_data_dynamic* const odyn = this->dynamic_data_;
+
for (Input_objects::Dynobj_iterator p = input_objects->dynobj_begin();
p != input_objects->dynobj_end();
++p)
void
Write_symbols_task::run(Workqueue*)
{
- this->symtab_->write_globals(this->target_, this->sympool_, this->of_);
+ this->symtab_->write_globals(this->target_, this->sympool_, this->dynpool_,
+ this->of_);
}
// Close_task_runner methods.
sympool() const
{ return &this->sympool_; }
+ // Return the Stringpool used for dynamic symbol names and dynamic
+ // tags.
+ const Stringpool*
+ dynpool() const
+ { return &this->dynpool_; }
+
// Return whether a section is a .gnu.linkonce section, given the
// section name.
static inline bool
off_t
finalize(const Input_objects*, Symbol_table*);
- // Return the TLS segment.
+ // Return the TLS segment. This will return NULL if there isn't
+ // one.
Output_segment*
tls_segment() const
{ return this->tls_segment_; }
+ // Return the normal symbol table.
+ Output_section*
+ symtab_section() const
+ {
+ gold_assert(this->symtab_section_ != NULL);
+ return this->symtab_section_;
+ }
+
+ // Return the dynamic symbol table.
+ Output_section*
+ dynsym_section() const
+ {
+ gold_assert(this->dynsym_section_ != NULL);
+ return this->dynsym_section_;
+ }
+
+ // Return the dynamic tags.
+ Output_data_dynamic*
+ dynamic_data() const
+ { return this->dynamic_data_; }
+
// Write out data not associated with an input file or the symbol
// table.
void
// Create the output sections for the symbol table.
void
- create_symtab_sections(int size, const Input_objects*, Symbol_table*, off_t*,
- Output_section** ostrtab);
+ create_symtab_sections(int size, const Input_objects*, Symbol_table*,
+ off_t*);
// Create the .shstrtab section.
Output_section*
// Create the dynamic symbol table.
void
- create_dynamic_symtab(const Target*, Output_data_dynamic*, Symbol_table*);
+ create_dynamic_symtab(const Target*, Symbol_table*);
// Finish the .dynamic section and PT_DYNAMIC segment.
void
- finish_dynamic_section(const Input_objects*, const Symbol_table*,
- Output_data_dynamic*);
+ finish_dynamic_section(const Input_objects*, const Symbol_table*);
// Create the .interp section and PT_INTERP segment.
void
Output_section* dynsym_section_;
// The SHT_DYNAMIC output section if there is one.
Output_section* dynamic_section_;
+ // The dynamic data which goes into dynamic_section_.
+ Output_data_dynamic* dynamic_data_;
};
// This task handles writing out data which is not part of a section
{
public:
Write_symbols_task(const Symbol_table* symtab, const Target* target,
- const Stringpool* sympool, Output_file* of,
- Task_token* final_blocker)
- : symtab_(symtab), target_(target), sympool_(sympool), of_(of),
- final_blocker_(final_blocker)
+ const Stringpool* sympool, const Stringpool* dynpool,
+ Output_file* of, Task_token* final_blocker)
+ : symtab_(symtab), target_(target), sympool_(sympool), dynpool_(dynpool),
+ of_(of), final_blocker_(final_blocker)
{ }
// The standard Task methods.
const Symbol_table* symtab_;
const Target* target_;
const Stringpool* sympool_;
+ const Stringpool* dynpool_;
Output_file* of_;
Task_token* final_blocker_;
};
Output_section_headers::Output_section_headers(
int size,
bool big_endian,
- const Layout::Segment_list& segment_list,
- const Layout::Section_list& unattached_section_list,
+ const Layout* layout,
+ const Layout::Segment_list* segment_list,
+ const Layout::Section_list* unattached_section_list,
const Stringpool* secnamepool)
: size_(size),
big_endian_(big_endian),
+ layout_(layout),
segment_list_(segment_list),
unattached_section_list_(unattached_section_list),
secnamepool_(secnamepool)
{
// Count all the sections. Start with 1 for the null section.
off_t count = 1;
- for (Layout::Segment_list::const_iterator p = segment_list.begin();
- p != segment_list.end();
+ for (Layout::Segment_list::const_iterator p = segment_list->begin();
+ p != segment_list->end();
++p)
if ((*p)->type() == elfcpp::PT_LOAD)
count += (*p)->output_section_count();
- count += unattached_section_list.size();
+ count += unattached_section_list->size();
int shdr_size;
if (size == 32)
v += shdr_size;
unsigned shndx = 1;
- for (Layout::Segment_list::const_iterator p = this->segment_list_.begin();
- p != this->segment_list_.end();
+ for (Layout::Segment_list::const_iterator p = this->segment_list_->begin();
+ p != this->segment_list_->end();
++p)
v = (*p)->write_section_headers SELECT_SIZE_ENDIAN_NAME(size, big_endian) (
- this->secnamepool_, v, &shndx
+ this->layout_, this->secnamepool_, v, &shndx
SELECT_SIZE_ENDIAN(size, big_endian));
for (Layout::Section_list::const_iterator p =
- this->unattached_section_list_.begin();
- p != this->unattached_section_list_.end();
+ this->unattached_section_list_->begin();
+ p != this->unattached_section_list_->end();
++p)
{
gold_assert(shndx == (*p)->out_shndx());
elfcpp::Shdr_write<size, big_endian> oshdr(v);
- (*p)->write_header(this->secnamepool_, &oshdr);
+ (*p)->write_header(this->layout_, this->secnamepool_, &oshdr);
v += shdr_size;
++shndx;
}
// Output_section_data methods.
+// Record the output section, and set the entry size and such.
+
+void
+Output_section_data::set_output_section(Output_section* os)
+{
+ gold_assert(this->output_section_ == NULL);
+ this->output_section_ = os;
+ this->do_adjust_output_section(os);
+}
+
+// Return the section index of the output section.
+
unsigned int
Output_section_data::do_out_shndx() const
{
// Output_data_reloc_base methods.
+// Adjust the output section.
+
+template<int sh_type, bool dynamic, int size, bool big_endian>
+void
+Output_data_reloc_base<sh_type, dynamic, size, big_endian>
+ ::do_adjust_output_section(Output_section* os)
+{
+ if (sh_type == elfcpp::SHT_REL)
+ os->set_entsize(elfcpp::Elf_sizes<size>::rel_size);
+ else if (sh_type == elfcpp::SHT_RELA)
+ os->set_entsize(elfcpp::Elf_sizes<size>::rela_size);
+ else
+ gold_unreachable();
+ if (dynamic)
+ os->set_should_link_to_dynsym();
+ else
+ os->set_should_link_to_symtab();
+}
+
// Write out relocation data.
template<int sh_type, bool dynamic, int size, bool big_endian>
break;
case DYNAMIC_SECTION_ADDRESS:
- val = this->u_.os->address();
+ val = this->u_.od->address();
break;
case DYNAMIC_SECTION_SIZE:
- val = this->u_.os->data_size();
+ val = this->u_.od->data_size();
break;
case DYNAMIC_SYMBOL:
{
- Sized_symbol<size>* s = static_cast<Sized_symbol<size>*>(this->u_.sym);
+ const Sized_symbol<size>* s =
+ static_cast<const Sized_symbol<size>*>(this->u_.sym);
val = s->value();
}
break;
// Output_data_dynamic methods.
+// Adjust the output section to set the entry size.
+
+void
+Output_data_dynamic::do_adjust_output_section(Output_section* os)
+{
+ if (this->target_->get_size() == 32)
+ os->set_entsize(elfcpp::Elf_sizes<32>::dyn_size);
+ else if (this->target_->get_size() == 64)
+ os->set_entsize(elfcpp::Elf_sizes<64>::dyn_size);
+ else
+ gold_unreachable();
+}
+
// Set the final data size.
void
: name_(name),
addralign_(0),
entsize_(0),
+ link_section_(NULL),
link_(0),
+ info_section_(NULL),
info_(0),
type_(type),
flags_(flags),
first_input_offset_(0),
may_add_data_(may_add_data),
needs_symtab_index_(false),
- needs_dynsym_index_(false)
+ needs_dynsym_index_(false),
+ should_link_to_symtab_(false),
+ should_link_to_dynsym_(false)
{
}
{
}
+// Set the entry size.
+
+void
+Output_section::set_entsize(uint64_t v)
+{
+ if (this->entsize_ == 0)
+ this->entsize_ = v;
+ else
+ gold_assert(this->entsize_ == v);
+}
+
// Add the input section SHNDX, with header SHDR, named SECNAME, in
// OBJECT, to the Output_section. Return the offset of the input
// section within the output section. We don't always keep track of
template<int size, bool big_endian>
void
-Output_section::write_header(const Stringpool* secnamepool,
+Output_section::write_header(const Layout* layout,
+ const Stringpool* secnamepool,
elfcpp::Shdr_write<size, big_endian>* oshdr) const
{
oshdr->put_sh_name(secnamepool->get_offset(this->name_));
oshdr->put_sh_addr(this->address());
oshdr->put_sh_offset(this->offset());
oshdr->put_sh_size(this->data_size());
- oshdr->put_sh_link(this->link_);
- oshdr->put_sh_info(this->info_);
+ if (this->link_section_ != NULL)
+ oshdr->put_sh_link(this->link_section_->out_shndx());
+ else if (this->should_link_to_symtab_)
+ oshdr->put_sh_link(layout->symtab_section()->out_shndx());
+ else if (this->should_link_to_dynsym_)
+ oshdr->put_sh_link(layout->dynsym_section()->out_shndx());
+ else
+ oshdr->put_sh_link(this->link_);
+ if (this->info_section_ != NULL)
+ oshdr->put_sh_info(this->info_section_->out_shndx());
+ else
+ oshdr->put_sh_info(this->info_);
oshdr->put_sh_addralign(this->addralign_);
oshdr->put_sh_entsize(this->entsize_);
}
template<int size, bool big_endian>
unsigned char*
-Output_segment::write_section_headers(const Stringpool* secnamepool,
+Output_segment::write_section_headers(const Layout* layout,
+ const Stringpool* secnamepool,
unsigned char* v,
unsigned int *pshndx
ACCEPT_SIZE_ENDIAN) const
v = this->write_section_headers_list
SELECT_SIZE_ENDIAN_NAME(size, big_endian) (
- secnamepool, &this->output_data_, v, pshndx
+ layout, secnamepool, &this->output_data_, v, pshndx
SELECT_SIZE_ENDIAN(size, big_endian));
v = this->write_section_headers_list
SELECT_SIZE_ENDIAN_NAME(size, big_endian) (
- secnamepool, &this->output_bss_, v, pshndx
+ layout, secnamepool, &this->output_bss_, v, pshndx
SELECT_SIZE_ENDIAN(size, big_endian));
return v;
}
template<int size, bool big_endian>
unsigned char*
-Output_segment::write_section_headers_list(const Stringpool* secnamepool,
+Output_segment::write_section_headers_list(const Layout* layout,
+ const Stringpool* secnamepool,
const Output_data_list* pdl,
unsigned char* v,
unsigned int* pshndx
const Output_section* ps = static_cast<const Output_section*>(*p);
gold_assert(*pshndx == ps->out_shndx());
elfcpp::Shdr_write<size, big_endian> oshdr(v);
- ps->write_header(secnamepool, &oshdr);
+ ps->write_header(layout, secnamepool, &oshdr);
v += shdr_size;
++*pshndx;
}
public:
Output_section_headers(int size,
bool big_endian,
- const Layout::Segment_list&,
- const Layout::Section_list&,
+ const Layout*,
+ const Layout::Segment_list*,
+ const Layout::Section_list*,
const Stringpool*);
// Write the data to the file.
int size_;
bool big_endian_;
- const Layout::Segment_list& segment_list_;
- const Layout::Section_list& unattached_section_list_;
+ const Layout* layout_;
+ const Layout::Segment_list* segment_list_;
+ const Layout::Section_list* unattached_section_list_;
const Stringpool* secnamepool_;
};
: Output_data(0), output_section_(NULL), addralign_(addralign)
{ }
+ // Return the output section.
+ const Output_section*
+ output_section() const
+ { return this->output_section_; }
+
// Record the output section.
void
- set_output_section(Output_section* os)
- {
- gold_assert(this->output_section_ == NULL);
- this->output_section_ = os;
- }
+ set_output_section(Output_section* os);
protected:
// The child class must implement do_write.
+ // The child class may implement specific adjustments to the output
+ // section.
+ virtual void
+ do_adjust_output_section(Output_section*)
+ { }
+
// Return the required alignment.
uint64_t
do_addralign() const
do_write(Output_file*);
protected:
+ // Set the entry size and the link.
+ void
+ do_adjust_output_section(Output_section *os);
+
// Add a relocation entry.
void
add(const Output_reloc_type& reloc)
add_constant(elfcpp::DT tag, unsigned int val)
{ this->add_entry(Dynamic_entry(tag, val)); }
- // Add a new dynamic entry with the address of a section.
+ // Add a new dynamic entry with the address of output data.
void
- add_section_address(elfcpp::DT tag, Output_section* os)
- { this->add_entry(Dynamic_entry(tag, os, false)); }
+ add_section_address(elfcpp::DT tag, const Output_data* od)
+ { this->add_entry(Dynamic_entry(tag, od, false)); }
- // Add a new dynamic entry with the size of a section.
+ // Add a new dynamic entry with the size of output data.
void
- add_section_size(elfcpp::DT tag, Output_section* os)
- { this->add_entry(Dynamic_entry(tag, os, true)); }
+ add_section_size(elfcpp::DT tag, const Output_data* od)
+ { this->add_entry(Dynamic_entry(tag, od, true)); }
// Add a new dynamic entry with the address of a symbol.
void
- add_symbol(elfcpp::DT tag, Symbol* sym)
+ add_symbol(elfcpp::DT tag, const Symbol* sym)
{ this->add_entry(Dynamic_entry(tag, sym)); }
// Add a new dynamic entry with a string.
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
{ this->u_.val = val; }
// Create an entry with the size or address of a section.
- Dynamic_entry(elfcpp::DT tag, Output_section* os, bool section_size)
+ Dynamic_entry(elfcpp::DT tag, const Output_data* od, bool section_size)
: tag_(tag),
classification_(section_size
? DYNAMIC_SECTION_SIZE
: DYNAMIC_SECTION_ADDRESS)
- { this->u_.os = os; }
+ { this->u_.od = od; }
// Create an entry with the address of a symbol.
- Dynamic_entry(elfcpp::DT tag, Symbol* sym)
+ Dynamic_entry(elfcpp::DT tag, const Symbol* sym)
: tag_(tag), classification_(DYNAMIC_SYMBOL)
{ this->u_.sym = sym; }
// For DYNAMIC_NUMBER.
unsigned int val;
// For DYNAMIC_SECTION_ADDRESS and DYNAMIC_SECTION_SIZE.
- Output_section* os;
+ const Output_data* od;
// For DYNAMIC_SYMBOL.
- Symbol* sym;
+ const Symbol* sym;
// For DYNAMIC_STRING.
const char* str;
} u_;
// Set the entsize field.
void
- set_entsize(uint64_t v)
- { this->entsize_ = v; }
+ set_entsize(uint64_t v);
- // Set the link field.
+ // Set the link field to the output section index of a section.
+ void
+ set_link_section(Output_data* od)
+ {
+ gold_assert(this->link_ == 0
+ && !this->should_link_to_symtab_
+ && !this->should_link_to_dynsym_);
+ this->link_section_ = od;
+ }
+
+ // Set the link field to a constant.
void
set_link(unsigned int v)
- { this->link_ = v; }
+ {
+ gold_assert(this->link_section_ == NULL
+ && !this->should_link_to_symtab_
+ && !this->should_link_to_dynsym_);
+ this->link_ = v;
+ }
- // Set the info field.
+ // Record that this section should link to the normal symbol table.
+ void
+ set_should_link_to_symtab()
+ {
+ gold_assert(this->link_section_ == NULL
+ && this->link_ == 0
+ && !this->should_link_to_dynsym_);
+ this->should_link_to_symtab_ = true;
+ }
+
+ // Record that this section should link to the dynamic symbol table.
+ void
+ set_should_link_to_dynsym()
+ {
+ gold_assert(this->link_section_ == NULL
+ && this->link_ == 0
+ && !this->should_link_to_symtab_);
+ this->should_link_to_dynsym_ = true;
+ }
+
+ // Return the info field.
+ unsigned int
+ info() const
+ {
+ gold_assert(this->info_section_ == NULL);
+ return this->info_;
+ }
+
+ // Set the info field to the output section index of a section.
+ void
+ set_info_section(Output_data* od)
+ {
+ gold_assert(this->info_ == 0);
+ this->info_section_ = od;
+ }
+
+ // Set the info field to a constant.
void
set_info(unsigned int v)
- { this->info_ = v; }
+ {
+ gold_assert(this->info_section_ == NULL);
+ this->info_ = v;
+ }
// Set the addralign field.
void
// Write the section header into *OPHDR.
template<int size, bool big_endian>
void
- write_header(const Stringpool*, elfcpp::Shdr_write<size, big_endian>*) const;
+ 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
// The section entry size.
uint64_t entsize_;
// The file offset is in the parent class.
- // The section link field.
+ // Set the section link field to the index of this section.
+ Output_data* link_section_;
+ // If link_section_ is NULL, this is the link field.
unsigned int link_;
- // The section info field.
+ // Set the section info field to the index of this section.
+ Output_data* info_section_;
+ // If info_section_ is NULL, this is the section info field.
unsigned int info_;
// The section type.
elfcpp::Elf_Word type_;
// dynamic symbol table. This will be true if there is a dynamic
// relocation which needs it.
bool needs_dynsym_index_ : 1;
+ // Whether the link field of this output section should point to the
+ // normal symbol table.
+ bool should_link_to_symtab_ : 1;
+ // Whether the link field of this output section should point to the
+ // dynamic symbol table.
+ bool should_link_to_dynsym_ : 1;
};
// An output segment. PT_LOAD segments are built from collections of
// Write the section headers of associated sections into V.
template<int size, bool big_endian>
unsigned char*
- write_section_headers(const Stringpool*,
- unsigned char* v,
+ write_section_headers(const Layout*, const Stringpool*, unsigned char* v,
unsigned int* pshndx ACCEPT_SIZE_ENDIAN) const;
private:
// Write the section headers in the list into V.
template<int size, bool big_endian>
unsigned char*
- write_section_headers_list(const Stringpool*, const Output_data_list*,
- unsigned char* v,
+ write_section_headers_list(const Layout*, const Stringpool*,
+ const Output_data_list*, unsigned char* v,
unsigned int* pshdx ACCEPT_SIZE_ENDIAN) const;
// The list of output data with contents attached to this segment.
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2006-11-30 15:37-0800\n"
+"POT-Creation-Date: 2006-12-01 08:46-0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
msgid "%s: missing expected TLS relocation\n"
msgstr ""
-#: i386.cc:702 i386.cc:843 i386.cc:1064
+#: i386.cc:729 i386.cc:870 i386.cc:1125
#, c-format
msgid "%s: %s: unexpected reloc %u in object file\n"
msgstr ""
-#: i386.cc:738 i386.cc:757
+#: i386.cc:765 i386.cc:784
#, c-format
msgid "%s: %s: unsupported reloc %u against local symbol\n"
msgstr ""
-#: i386.cc:879 i386.cc:900
+#: i386.cc:906 i386.cc:927
#, c-format
msgid "%s: %s: unsupported reloc %u against global symbol %s\n"
msgstr ""
-#: i386.cc:923
+#: i386.cc:950
#, c-format
msgid "%s: %s: unsupported RELA reloc section\n"
msgstr ""
-#: i386.cc:980
+#: i386.cc:1041
#, c-format
msgid "%s: %s: missing expected TLS relocation\n"
msgstr ""
-#: i386.cc:1096 i386.cc:1171 i386.cc:1182
+#: i386.cc:1157 i386.cc:1232 i386.cc:1243
#, c-format
msgid "%s: %s: unsupported reloc %u\n"
msgstr ""
-#: i386.cc:1123
+#: i386.cc:1184
#, c-format
msgid "%s: %s: TLS reloc but no TLS segment\n"
msgstr ""
-#: i386.cc:1156
+#: i386.cc:1217
#, c-format
msgid "%s: %s: unsupported reloc type %u\n"
msgstr ""
-#: i386.cc:1365
+#: i386.cc:1426
#, c-format
msgid "%s: %s: TLS relocation out of range\n"
msgstr ""
-#: i386.cc:1383
+#: i386.cc:1444
#, c-format
msgid "%s: %s: TLS relocation against invalid instruction\n"
msgstr ""
msgid "%s: -%c: %s\n"
msgstr ""
-#: output.cc:817
+#: output.cc:881
#, c-format
msgid "%s: %s: invalid alignment %lu for section \"%s\"\n"
msgstr ""
-#: output.cc:1316
+#: output.cc:1393
#, c-format
msgid "%s: %s: open: %s\n"
msgstr ""
-#: output.cc:1325
+#: output.cc:1402
#, c-format
msgid "%s: %s: lseek: %s\n"
msgstr ""
-#: output.cc:1332
+#: output.cc:1409
#, c-format
msgid "%s: %s: write: %s\n"
msgstr ""
-#: output.cc:1342
+#: output.cc:1419
#, c-format
msgid "%s: %s: mmap: %s\n"
msgstr ""
-#: output.cc:1356
+#: output.cc:1433
#, c-format
msgid "%s: %s: munmap: %s\n"
msgstr ""
-#: output.cc:1364
+#: output.cc:1441
#, c-format
msgid "%s: %s: close: %s\n"
msgstr ""
msgid "%s: %s: versym for symbol %zu has no name: %u\n"
msgstr ""
-#: symtab.cc:1050 symtab.cc:1201
+#: symtab.cc:1063 symtab.cc:1235
#, c-format
msgid "%s: %s: unsupported symbol section 0x%x\n"
msgstr ""
-#: symtab.cc:1364
+#: symtab.cc:1423
#, c-format
msgid "%s: %s: warning: %s\n"
msgstr ""
Copy_relocs<size, big_endian>::Copy_reloc_entry::emit(
Output_data_reloc<elfcpp::SHT_REL, true, size, big_endian>* reloc_data)
{
+ this->sym_->set_needs_dynsym_entry();
reloc_data->add_global(this->sym_, this->reloc_type_, this->relobj_,
this->shndx_, this->address_);
}
Copy_relocs<size, big_endian>::Copy_reloc_entry::emit(
Output_data_reloc<elfcpp::SHT_RELA, true, size, big_endian>* reloc_data)
{
+ this->sym_->set_needs_dynsym_entry();
reloc_data->add_global(this->sym_, this->reloc_type_, this->relobj_,
this->shndx_, this->address_, this->addend_);
}
gold_assert(this->source_ == FROM_OBJECT);
this->u_.from_object.object = object;
// FIXME: Handle SHN_XINDEX.
- this->u_.from_object.shnum = sym.get_st_shndx();
+ this->u_.from_object.shndx = sym.get_st_shndx();
this->type_ = sym.get_st_type();
this->binding_ = sym.get_st_bind();
this->visibility_ = sym.get_st_visibility();
&& to->object()->is_dynamic())
tobits |= (1 << 1);
- switch (to->shnum())
+ switch (to->shndx())
{
case elfcpp::SHN_UNDEF:
tobits |= (1 << 2);
sym.get_st_visibility(), sym.get_st_nonvis());
this->u_.from_object.object = object;
// FIXME: Handle SHN_XINDEX.
- this->u_.from_object.shnum = sym.get_st_shndx();
+ this->u_.from_object.shndx = sym.get_st_shndx();
this->source_ = FROM_OBJECT;
this->in_dyn_ = object->is_dynamic();
}
esym.put_st_size(from->symsize());
esym.put_st_info(from->binding(), from->type());
esym.put_st_other(from->visibility(), from->nonvis());
- esym.put_st_shndx(from->shnum());
+ esym.put_st_shndx(from->shndx());
Symbol_table::resolve(to, esym.sym(), from->object());
}
sym = this->get_sized_symbol SELECT_SIZE_NAME(size) (oldsym
SELECT_SIZE(size));
gold_assert(sym->source() == Symbol::FROM_OBJECT);
- const int old_shnum = sym->shnum();
- if (old_shnum != elfcpp::SHN_UNDEF
- && old_shnum != elfcpp::SHN_COMMON
+ const int old_shndx = sym->shndx();
+ if (old_shndx != elfcpp::SHN_UNDEF
+ && old_shndx != elfcpp::SHN_COMMON
&& !sym->object()->is_dynamic())
{
fprintf(stderr, "%s: linker defined: multiple definition of %s\n",
++p)
{
Symbol* sym = p->second;
- if (sym->needs_dynsym_entry())
+
+ // Note that SYM may already have a dynamic symbol index, since
+ // some symbols appear more than once in the symbol table, with
+ // and without a version.
+
+ if (!sym->needs_dynsym_entry())
+ sym->set_dynsym_index(-1U);
+ else if (!sym->has_dynsym_index())
{
sym->set_dynsym_index(index);
++index;
// OFF. Add their names to POOL. Return the new file offset.
off_t
-Symbol_table::finalize(unsigned int index, off_t off, Stringpool* pool)
+Symbol_table::finalize(unsigned int index, off_t off, off_t dynoff,
+ size_t dyn_global_index, size_t dyncount,
+ Stringpool* pool)
{
off_t ret;
gold_assert(index != 0);
this->first_global_index_ = index;
+ this->dynamic_offset_ = dynoff;
+ this->first_dynamic_global_index_ = dyn_global_index;
+ this->dynamic_count_ = dyncount;
+
if (this->size_ == 32)
ret = this->sized_finalize<32>(index, off, pool);
else if (this->size_ == 64)
{
case Symbol::FROM_OBJECT:
{
- unsigned int shnum = sym->shnum();
+ unsigned int shndx = sym->shndx();
// FIXME: We need some target specific support here.
- if (shnum >= elfcpp::SHN_LORESERVE
- && shnum != elfcpp::SHN_ABS)
+ if (shndx >= elfcpp::SHN_LORESERVE
+ && shndx != elfcpp::SHN_ABS)
{
fprintf(stderr, _("%s: %s: unsupported symbol section 0x%x\n"),
- program_name, sym->name(), shnum);
+ program_name, sym->name(), shndx);
gold_exit(false);
}
if (symobj->is_dynamic())
{
value = 0;
- shnum = elfcpp::SHN_UNDEF;
+ shndx = elfcpp::SHN_UNDEF;
}
- else if (shnum == elfcpp::SHN_UNDEF)
+ else if (shndx == elfcpp::SHN_UNDEF)
value = 0;
- else if (shnum == elfcpp::SHN_ABS)
+ else if (shndx == elfcpp::SHN_ABS)
value = sym->value();
else
{
Relobj* relobj = static_cast<Relobj*>(symobj);
off_t secoff;
- Output_section* os = relobj->output_section(shnum, &secoff);
+ Output_section* os = relobj->output_section(shndx, &secoff);
if (os == NULL)
{
sym->set_symtab_index(-1U);
+ gold_assert(sym->dynsym_index() == -1U);
continue;
}
void
Symbol_table::write_globals(const Target* target, const Stringpool* sympool,
- Output_file* of) const
+ const Stringpool* dynpool, Output_file* of) const
{
if (this->size_ == 32)
{
if (target->is_big_endian())
- this->sized_write_globals<32, true>(target, sympool, of);
+ this->sized_write_globals<32, true>(target, sympool, dynpool, of);
else
- this->sized_write_globals<32, false>(target, sympool, of);
+ this->sized_write_globals<32, false>(target, sympool, dynpool, of);
}
else if (this->size_ == 64)
{
if (target->is_big_endian())
- this->sized_write_globals<64, true>(target, sympool, of);
+ this->sized_write_globals<64, true>(target, sympool, dynpool, of);
else
- this->sized_write_globals<64, false>(target, sympool, of);
+ this->sized_write_globals<64, false>(target, sympool, dynpool, of);
}
else
gold_unreachable();
void
Symbol_table::sized_write_globals(const Target*,
const Stringpool* sympool,
+ const Stringpool* dynpool,
Output_file* of) const
{
const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
unsigned int index = this->first_global_index_;
const off_t oview_size = this->output_count_ * sym_size;
- unsigned char* psyms = of->get_output_view(this->offset_, oview_size);
+ unsigned char* const psyms = of->get_output_view(this->offset_, oview_size);
+
+ unsigned int dynamic_count = this->dynamic_count_;
+ off_t dynamic_size = dynamic_count * sym_size;
+ unsigned int first_dynamic_global_index = this->first_dynamic_global_index_;
+ unsigned char* dynamic_view;
+ if (this->dynamic_offset_ == 0)
+ dynamic_view = NULL;
+ else
+ dynamic_view = of->get_output_view(this->dynamic_offset_, dynamic_size);
unsigned char* ps = psyms;
for (Symbol_table_type::const_iterator p = this->table_.begin();
Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(p->second);
unsigned int sym_index = sym->symtab_index();
- if (sym_index == -1U)
+ unsigned int dynsym_index;
+ if (dynamic_view == NULL)
+ dynsym_index = -1U;
+ else
+ dynsym_index = sym->dynsym_index();
+
+ if (sym_index == -1U && dynsym_index == -1U)
{
// This symbol is not included in the output file.
continue;
}
- if (sym_index != index)
+
+ if (sym_index == index)
+ ++index;
+ else if (sym_index != -1U)
{
// We have already seen this symbol, because it has a
// default version.
gold_assert(sym_index < index);
- continue;
+ if (dynsym_index == -1U)
+ continue;
+ sym_index = -1U;
}
- ++index;
unsigned int shndx;
switch (sym->source())
{
case Symbol::FROM_OBJECT:
{
- unsigned int shnum = sym->shnum();
+ unsigned int in_shndx = sym->shndx();
// FIXME: We need some target specific support here.
- if (shnum >= elfcpp::SHN_LORESERVE
- && shnum != elfcpp::SHN_ABS)
+ if (in_shndx >= elfcpp::SHN_LORESERVE
+ && in_shndx != elfcpp::SHN_ABS)
{
fprintf(stderr, _("%s: %s: unsupported symbol section 0x%x\n"),
- program_name, sym->name(), sym->shnum());
+ program_name, sym->name(), in_shndx);
gold_exit(false);
}
// FIXME.
shndx = elfcpp::SHN_UNDEF;
}
- else if (shnum == elfcpp::SHN_UNDEF || shnum == elfcpp::SHN_ABS)
- shndx = shnum;
+ else if (in_shndx == elfcpp::SHN_UNDEF
+ || in_shndx == elfcpp::SHN_ABS)
+ shndx = in_shndx;
else
{
Relobj* relobj = static_cast<Relobj*>(symobj);
off_t secoff;
- Output_section* os = relobj->output_section(shnum, &secoff);
+ Output_section* os = relobj->output_section(in_shndx, &secoff);
gold_assert(os != NULL);
shndx = os->out_shndx();
}
gold_unreachable();
}
- elfcpp::Sym_write<size, big_endian> osym(ps);
- osym.put_st_name(sympool->get_offset(sym->name()));
- osym.put_st_value(sym->value());
- osym.put_st_size(sym->symsize());
- osym.put_st_info(elfcpp::elf_st_info(sym->binding(), sym->type()));
- osym.put_st_other(elfcpp::elf_st_other(sym->visibility(),
- sym->nonvis()));
- osym.put_st_shndx(shndx);
+ if (sym_index != -1U)
+ {
+ this->sized_write_symbol<size, big_endian>(sym, shndx, sympool, ps);
+ ps += sym_size;
+ }
- ps += sym_size;
+ if (dynsym_index != -1U)
+ {
+ dynsym_index -= first_dynamic_global_index;
+ gold_assert(dynsym_index < dynamic_count);
+ unsigned char* pd = dynamic_view + (dynsym_index * sym_size);
+ this->sized_write_symbol<size, big_endian>(sym, shndx, dynpool, pd);
+ }
}
gold_assert(ps - psyms == oview_size);
of->write_output_view(this->offset_, oview_size, psyms);
+ if (dynamic_view != NULL)
+ of->write_output_view(this->dynamic_offset_, dynamic_size, dynamic_view);
+}
+
+// Write out the symbol SYM, in section SHNDX, to P. POOL is the
+// strtab holding the name.
+
+template<int size, bool big_endian>
+void
+Symbol_table::sized_write_symbol(Sized_symbol<size>* sym,
+ unsigned int shndx,
+ const Stringpool* pool,
+ unsigned char* p) const
+{
+ elfcpp::Sym_write<size, big_endian> osym(p);
+ osym.put_st_name(pool->get_offset(sym->name()));
+ osym.put_st_value(sym->value());
+ osym.put_st_size(sym->symsize());
+ osym.put_st_info(elfcpp::elf_st_info(sym->binding(), sym->type()));
+ osym.put_st_other(elfcpp::elf_st_other(sym->visibility(), sym->nonvis()));
+ osym.put_st_shndx(shndx);
}
// Write out a section symbol. Return the update offset.
// Return the index of the section in the input relocatable or
// dynamic object file.
unsigned int
- shnum() const
+ shndx() const
{
gold_assert(this->source_ == FROM_OBJECT);
- return this->u_.from_object.shnum;
+ return this->u_.from_object.shndx;
}
// Return the output data section with which this symbol is
this->dynsym_index_ = index;
}
+ // Return whether this symbol already has an index in the dynamic
+ // symbol table.
+ bool
+ has_dynsym_index() const
+ { return this->dynsym_index_ != 0; }
+
// Return whether this symbol has an entry in the GOT section.
bool
has_got_offset() const
is_defined() const
{
return (this->source_ != FROM_OBJECT
- || (this->shnum() != elfcpp::SHN_UNDEF
- && this->shnum() != elfcpp::SHN_COMMON));
+ || (this->shndx() != elfcpp::SHN_UNDEF
+ && this->shndx() != elfcpp::SHN_COMMON));
}
// Return whether this symbol is defined in a dynamic object.
bool
is_undefined() const
{
- return this->source_ == FROM_OBJECT && this->shnum() == elfcpp::SHN_UNDEF;
+ return this->source_ == FROM_OBJECT && this->shndx() == elfcpp::SHN_UNDEF;
}
// Return whether this is a common symbol.
is_common() const
{
return (this->source_ == FROM_OBJECT
- && (this->shnum() == elfcpp::SHN_COMMON
+ && (this->shndx() == elfcpp::SHN_COMMON
|| this->type_ == elfcpp::STT_COMMON));
}
// seen.
Object* object;
// Section number in object_ in which symbol is defined.
- unsigned int shnum;
+ unsigned int shndx;
} from_object;
// This struct is used if SOURCE_ == IN_OUTPUT_DATA.
// Finalize the symbol table after we have set the final addresses
// of all the input sections. This sets the final symbol indexes,
// values and adds the names to *POOL. INDEX is the index of the
- // first global symbol. This records the file offset OFF, and
- // returns the new file offset.
+ // first global symbol. OFF is the file offset of the global symbol
+ // table, DYNOFF is the offset of the globals in the dynamic symbol
+ // table, DYN_GLOBAL_INDEX is the index of the first global dynamic
+ // symbol, and DYNCOUNT is the number of global dynamic symbols.
+ // This records the parameters, and returns the new file offset.
off_t
- finalize(unsigned int index, off_t off, Stringpool* pool);
+ finalize(unsigned int index, off_t off, off_t dynoff,
+ size_t dyn_global_index, size_t dyncount, Stringpool* pool);
// Write out the global symbols.
void
- write_globals(const Target*, const Stringpool*, Output_file*) const;
+ write_globals(const Target*, const Stringpool*, const Stringpool*,
+ Output_file*) const;
// Write out a section symbol. Return the updated offset.
void
// Write globals specialized for size and endianness.
template<int size, bool big_endian>
void
- sized_write_globals(const Target*, const Stringpool*, Output_file*) const;
+ sized_write_globals(const Target*, const Stringpool*, const Stringpool*,
+ Output_file*) const;
+
+ // Write out a symbol to P.
+ template<int size, bool big_endian>
+ void
+ sized_write_symbol(Sized_symbol<size>*, unsigned int shndx,
+ const Stringpool*, unsigned char* p) const;
// Write out a section symbol, specialized for size and endianness.
template<int size, bool big_endian>
// The number of global symbols we want to write out.
size_t output_count_;
+ // The file offset of the global dynamic symbols, or 0 if none.
+ off_t dynamic_offset_;
+
+ // The index of the first global dynamic symbol.
+ unsigned int first_dynamic_global_index_;
+
+ // The number of global dynamic symbols, or 0 if none.
+ off_t dynamic_count_;
+
// The symbol hash table.
Symbol_table_type table_;
// This is called to tell the target to complete any sections it is
// handling. After this all sections must have their final size.
void
- finalize_sections(Layout* layout)
- { return this->do_finalize_sections(layout); }
+ finalize_sections(const General_options* options, Layout* layout)
+ { return this->do_finalize_sections(options, layout); }
protected:
// This struct holds the constant information for a child class. We
// Virtual function which may be implemented by the child class.
virtual void
- do_finalize_sections(Layout*)
+ do_finalize_sections(const General_options*, Layout*)
{ }
private: