aboutsummaryrefslogtreecommitdiff
path: root/gold/layout.cc
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@google.com>2006-09-29 19:58:17 +0000
committerIan Lance Taylor <iant@google.com>2006-09-29 19:58:17 +0000
commit61ba1cf93601b0a0877a8ade94ba3c674a09f77e (patch)
treeffa744ec1dffd7f2dae13150b1dd7784728ed0a4 /gold/layout.cc
parent4dba4b2419ccdbf48fd016edb7e0e10016897827 (diff)
downloadgdb-61ba1cf93601b0a0877a8ade94ba3c674a09f77e.zip
gdb-61ba1cf93601b0a0877a8ade94ba3c674a09f77e.tar.gz
gdb-61ba1cf93601b0a0877a8ade94ba3c674a09f77e.tar.bz2
Snapshot. Now able to produce a minimal executable which actually
runs.
Diffstat (limited to 'gold/layout.cc')
-rw-r--r--gold/layout.cc220
1 files changed, 197 insertions, 23 deletions
diff --git a/gold/layout.cc b/gold/layout.cc
index d91f731..2448bf8 100644
--- a/gold/layout.cc
+++ b/gold/layout.cc
@@ -43,23 +43,34 @@ Layout_task::locks(Workqueue*)
// have been read.
void
-Layout_task::run(Workqueue*)
+Layout_task::run(Workqueue* workqueue)
{
- Layout layout(this->options_);
- layout.init();
+ // Nothing ever frees this.
+ Layout* layout = new Layout(this->options_);
+ layout->init();
for (Input_objects::Object_list::const_iterator p =
this->input_objects_->begin();
p != this->input_objects_->end();
++p)
- (*p)->layout(&layout);
- layout.finalize(this->input_objects_, this->symtab_);
+ (*p)->layout(layout);
+ off_t file_size = layout->finalize(this->input_objects_, this->symtab_);
+
+ // Now we know the final size of the output file and we know where
+ // each piece of information goes.
+ Output_file* of = new Output_file(this->options_);
+ of->open(file_size);
+
+ // Queue up the final set of tasks.
+ gold::queue_final_tasks(this->options_, this->input_objects_,
+ this->symtab_, layout, workqueue, of);
}
// Layout methods.
Layout::Layout(const General_options& options)
- : options_(options), namepool_(), sympool_(), signatures_(),
- section_name_map_(), segment_list_(), section_list_()
+ : options_(options), last_shndx_(0), namepool_(), sympool_(), signatures_(),
+ section_name_map_(), segment_list_(), section_list_(),
+ special_output_list_()
{
}
@@ -121,6 +132,10 @@ Output_section*
Layout::layout(Object* object, const char* name,
const elfcpp::Shdr<size, big_endian>& shdr, off_t* off)
{
+ // We discard empty input sections.
+ if (shdr.get_sh_size() == 0)
+ return NULL;
+
if (!this->include_section(object, name, shdr))
return NULL;
@@ -188,7 +203,9 @@ Output_section*
Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
elfcpp::Elf_Xword flags)
{
- Output_section* os = new Output_section(name, type, flags);
+ ++this->last_shndx_;
+ Output_section* os = new Output_section(name, type, flags,
+ this->last_shndx_);
if ((flags & elfcpp::SHF_ALLOC) == 0)
this->section_list_.push_back(os);
@@ -354,19 +371,24 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
// Lay out the segment headers.
int size = input_objects->target()->get_size();
+ bool big_endian = input_objects->target()->is_big_endian();
Output_segment_headers* segment_headers;
- segment_headers = new Output_segment_headers(size, this->segment_list_);
+ segment_headers = new Output_segment_headers(size, big_endian,
+ this->segment_list_);
load_seg->add_initial_output_data(segment_headers);
+ this->special_output_list_.push_back(segment_headers);
// FIXME: Attach them to PT_PHDRS if necessary.
// Lay out the file header.
Output_file_header* file_header;
file_header = new Output_file_header(size,
+ big_endian,
this->options_,
input_objects->target(),
symtab,
segment_headers);
load_seg->add_initial_output_data(file_header);
+ this->special_output_list_.push_back(file_header);
// Set the file offsets of all the segments.
off_t off = this->set_segment_offsets(input_objects->target(), load_seg);
@@ -375,7 +397,8 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
// FIXME: We don't need to do this if we are stripping symbols.
Output_section* osymtab;
Output_section* ostrtab;
- this->create_symtab_sections(input_objects, symtab, &osymtab, &ostrtab);
+ this->create_symtab_sections(size, input_objects, symtab, &off,
+ &osymtab, &ostrtab);
// Create the .shstrtab section.
Output_section* shstrtab_section = this->create_shstrtab();
@@ -385,8 +408,7 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
off = this->set_section_offsets(off);
// Create the section table header.
- Output_section_headers* oshdrs = this->create_shdrs(size, off);
- off += oshdrs->data_size();
+ Output_section_headers* oshdrs = this->create_shdrs(size, big_endian, &off);
file_header->set_section_info(oshdrs, shstrtab_section);
@@ -577,8 +599,11 @@ Layout::set_section_offsets(off_t off)
p != this->section_list_.end();
++p)
{
+ if ((*p)->offset() != -1)
+ continue;
uint64_t addralign = (*p)->addralign();
- off = (off + addralign - 1) & ~ (addralign - 1);
+ if (addralign != 0)
+ off = (off + addralign - 1) & ~ (addralign - 1);
(*p)->set_address(0, off);
off += (*p)->data_size();
}
@@ -588,12 +613,35 @@ Layout::set_section_offsets(off_t off)
// Create the symbol table sections.
void
-Layout::create_symtab_sections(const Input_objects* input_objects,
+Layout::create_symtab_sections(int size, const Input_objects* input_objects,
Symbol_table* symtab,
+ off_t* poff,
Output_section** posymtab,
Output_section** postrtab)
{
- off_t off = 0;
+ int symsize;
+ unsigned int align;
+ if (size == 32)
+ {
+ symsize = elfcpp::Elf_sizes<32>::sym_size;
+ align = 4;
+ }
+ else if (size == 64)
+ {
+ symsize = elfcpp::Elf_sizes<64>::sym_size;
+ align = 8;
+ }
+ else
+ abort();
+
+ off_t off = *poff;
+ off = (off + align - 1) & ~ (align - 1);
+ off_t startoff = off;
+
+ // Save space for the dummy symbol at the start of the section. We
+ // never bother to write this out--it will just be left as zero.
+ off += symsize;
+
for (Input_objects::Object_list::const_iterator p = input_objects->begin();
p != input_objects->end();
++p)
@@ -602,11 +650,37 @@ Layout::create_symtab_sections(const Input_objects* input_objects,
off = (*p)->finalize_local_symbols(off, &this->sympool_);
}
+ unsigned int local_symcount = (off - startoff) / symsize;
+ assert(local_symcount * symsize == off - startoff);
+
off = symtab->finalize(off, &this->sympool_);
- *posymtab = new Output_section_symtab(this->namepool_.add(".symtab"), off);
- *postrtab = new Output_section_strtab(this->namepool_.add(".strtab"),
- &this->sympool_);
+ this->sympool_.set_string_offsets();
+
+ ++this->last_shndx_;
+ const char* symtab_name = this->namepool_.add(".symtab");
+ Output_section* osymtab = new Output_section_symtab(symtab_name,
+ off - startoff,
+ this->last_shndx_);
+ this->section_list_.push_back(osymtab);
+
+ ++this->last_shndx_;
+ const char* strtab_name = this->namepool_.add(".strtab");
+ Output_section *ostrtab = new Output_section_strtab(strtab_name,
+ &this->sympool_,
+ this->last_shndx_);
+ this->section_list_.push_back(ostrtab);
+ this->special_output_list_.push_back(ostrtab);
+
+ osymtab->set_address(0, startoff);
+ osymtab->set_link(ostrtab->shndx());
+ osymtab->set_info(local_symcount);
+ osymtab->set_entsize(symsize);
+ osymtab->set_addralign(align);
+
+ *poff = off;
+ *posymtab = osymtab;
+ *postrtab = ostrtab;
}
// Create the .shstrtab section, which holds the names of the
@@ -621,10 +695,15 @@ Layout::create_shstrtab()
const char* name = this->namepool_.add(".shstrtab");
+ this->namepool_.set_string_offsets();
+
+ ++this->last_shndx_;
Output_section* os = new Output_section_strtab(name,
- &this->namepool_);
+ &this->namepool_,
+ this->last_shndx_);
this->section_list_.push_back(os);
+ this->special_output_list_.push_back(os);
return os;
}
@@ -633,14 +712,18 @@ Layout::create_shstrtab()
// offset.
Output_section_headers*
-Layout::create_shdrs(int size, off_t off)
+Layout::create_shdrs(int size, bool big_endian, off_t* poff)
{
Output_section_headers* oshdrs;
- oshdrs = new Output_section_headers(size, this->segment_list_,
- this->section_list_);
+ oshdrs = new Output_section_headers(size, big_endian, this->segment_list_,
+ this->section_list_,
+ &this->namepool_);
uint64_t addralign = oshdrs->addralign();
- off = (off + addralign - 1) & ~ (addralign - 1);
+ off_t off = (*poff + addralign - 1) & ~ (addralign - 1);
oshdrs->set_address(0, off);
+ off += oshdrs->data_size();
+ *poff = off;
+ this->special_output_list_.push_back(oshdrs);
return oshdrs;
}
@@ -733,6 +816,97 @@ Layout::add_comdat(const char* signature, bool group)
}
}
+// Write out data not associated with a section or the symbol table.
+
+void
+Layout::write_data(Output_file* of) const
+{
+ for (Data_list::const_iterator p = this->special_output_list_.begin();
+ p != this->special_output_list_.end();
+ ++p)
+ (*p)->write(of);
+}
+
+// Write_data_task methods.
+
+// We can always run this task.
+
+Task::Is_runnable_type
+Write_data_task::is_runnable(Workqueue*)
+{
+ return IS_RUNNABLE;
+}
+
+// We need to unlock FINAL_BLOCKER when finished.
+
+Task_locker*
+Write_data_task::locks(Workqueue* workqueue)
+{
+ return new Task_locker_block(*this->final_blocker_, workqueue);
+}
+
+// Run the task--write out the data.
+
+void
+Write_data_task::run(Workqueue*)
+{
+ this->layout_->write_data(this->of_);
+}
+
+// Write_symbols_task methods.
+
+// We can always run this task.
+
+Task::Is_runnable_type
+Write_symbols_task::is_runnable(Workqueue*)
+{
+ return IS_RUNNABLE;
+}
+
+// We need to unlock FINAL_BLOCKER when finished.
+
+Task_locker*
+Write_symbols_task::locks(Workqueue* workqueue)
+{
+ return new Task_locker_block(*this->final_blocker_, workqueue);
+}
+
+// Run the task--write out the symbols.
+
+void
+Write_symbols_task::run(Workqueue*)
+{
+ this->symtab_->write_globals(this->target_, this->sympool_, this->of_);
+}
+
+// Close_task methods.
+
+// We can't run until FINAL_BLOCKER is unblocked.
+
+Task::Is_runnable_type
+Close_task::is_runnable(Workqueue*)
+{
+ if (this->final_blocker_->is_blocked())
+ return IS_BLOCKED;
+ return IS_RUNNABLE;
+}
+
+// We don't lock anything.
+
+Task_locker*
+Close_task::locks(Workqueue*)
+{
+ return NULL;
+}
+
+// Run the task--close the file.
+
+void
+Close_task::run(Workqueue*)
+{
+ this->of_->close();
+}
+
// Instantiate the templates we need. We could use the configure
// script to restrict this to only the ones for implemented targets.