diff options
author | Ian Lance Taylor <iant@google.com> | 2006-09-27 22:53:42 +0000 |
---|---|---|
committer | Ian Lance Taylor <iant@google.com> | 2006-09-27 22:53:42 +0000 |
commit | 75f65a3e309b8cd885c782f6af106d1e2a1876f6 (patch) | |
tree | 0f21c32a5e40156d007fd6a676b5d74a8c423c90 | |
parent | 6b89cc2108a525fdc4186bae5365acc258e9c23c (diff) | |
download | gdb-75f65a3e309b8cd885c782f6af106d1e2a1876f6.zip gdb-75f65a3e309b8cd885c782f6af106d1e2a1876f6.tar.gz gdb-75f65a3e309b8cd885c782f6af106d1e2a1876f6.tar.bz2 |
Finished layout code.
-rw-r--r-- | gold/gold.cc | 3 | ||||
-rw-r--r-- | gold/i386.cc | 16 | ||||
-rw-r--r-- | gold/layout.cc | 420 | ||||
-rw-r--r-- | gold/layout.h | 46 | ||||
-rw-r--r-- | gold/object.cc | 176 | ||||
-rw-r--r-- | gold/object.h | 43 | ||||
-rw-r--r-- | gold/output.cc | 341 | ||||
-rw-r--r-- | gold/output.h | 252 | ||||
-rw-r--r-- | gold/po/gold.pot | 67 | ||||
-rw-r--r-- | gold/symtab.cc | 103 | ||||
-rw-r--r-- | gold/symtab.h | 33 | ||||
-rw-r--r-- | gold/target.h | 72 |
12 files changed, 1223 insertions, 349 deletions
diff --git a/gold/gold.cc b/gold/gold.cc index f4642cf..9576e4a 100644 --- a/gold/gold.cc +++ b/gold/gold.cc @@ -91,7 +91,8 @@ queue_initial_tasks(const General_options& options, this_blocker = next_blocker; } - workqueue->queue(new Layout_task(options, input_objects, this_blocker)); + workqueue->queue(new Layout_task(options, input_objects, symtab, + this_blocker)); } } // end anonymous namespace. diff --git a/gold/i386.cc b/gold/i386.cc index 5ecd2e3..21dd57a 100644 --- a/gold/i386.cc +++ b/gold/i386.cc @@ -16,8 +16,22 @@ class Target_i386 : public Sized_target<32, false> { public: Target_i386() - : Sized_target<32, false>(false, false) + : Sized_target<32, false>(&i386_info) { } + + private: + static const Target::Target_info i386_info; +}; + +const Target::Target_info Target_i386::i386_info = +{ + 32, // size + false, // is_big_endian + false, // has_make_symbol + false, // has_resolve, + 0x08048000, // text_segment_address, + 0x1000, // abi_pagesize + 0x1000 // common_pagesize }; // The selector for i386 object files. diff --git a/gold/layout.cc b/gold/layout.cc index 1584380..d91f731 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -52,15 +52,14 @@ Layout_task::run(Workqueue*) p != this->input_objects_->end(); ++p) (*p)->layout(&layout); - layout.finalize(this->input_objects_); + layout.finalize(this->input_objects_, this->symtab_); } // Layout methods. Layout::Layout(const General_options& options) - : options_(options), namepool_(), signatures_(), - section_name_map_(), segment_list_(), section_list_(), - data_list_() + : options_(options), namepool_(), sympool_(), signatures_(), + section_name_map_(), segment_list_(), section_list_() { } @@ -169,82 +168,6 @@ Layout::layout(Object* object, const char* name, return os; } -// Return whether SEG1 should be before SEG2 in the output file. This -// is based entirely on the segment type and flags. When this is -// called the segment addresses has normally not yet been set. - -bool -Layout::segment_precedes(const Output_segment* seg1, - const Output_segment* seg2) -{ - elfcpp::Elf_Word type1 = seg1->type(); - elfcpp::Elf_Word type2 = seg2->type(); - - // The single PT_PHDR segment is required to precede any loadable - // segment. We simply make it always first. - if (type1 == elfcpp::PT_PHDR) - { - assert(type2 != elfcpp::PT_PHDR); - return true; - } - if (type2 == elfcpp::PT_PHDR) - return false; - - // The single PT_INTERP segment is required to precede any loadable - // segment. We simply make it always second. - if (type1 == elfcpp::PT_INTERP) - { - assert(type2 != elfcpp::PT_INTERP); - return true; - } - if (type2 == elfcpp::PT_INTERP) - return false; - - // We then put PT_LOAD segments before any other segments. - if (type1 == elfcpp::PT_LOAD && type2 != elfcpp::PT_LOAD) - return true; - if (type2 == elfcpp::PT_LOAD && type1 != elfcpp::PT_LOAD) - return false; - - const elfcpp::Elf_Word flags1 = seg1->flags(); - const elfcpp::Elf_Word flags2 = seg2->flags(); - - // The order of non-PT_LOAD segments is unimportant. We simply sort - // by the numeric segment type and flags values. There should not - // be more than one segment with the same type and flags. - if (type1 != elfcpp::PT_LOAD) - { - if (type1 != type2) - return type1 < type2; - assert(flags1 != flags2); - return flags1 < flags2; - } - - // We sort PT_LOAD segments based on the flags. Readonly segments - // come before writable segments. Then executable segments come - // before non-executable segments. Then the unlikely case of a - // non-readable segment comes before the normal case of a readable - // segment. If there are multiple segments with the same type and - // flags, we require that the address be set, and we sort by - // virtual address and then physical address. - if ((flags1 & elfcpp::PF_W) != (flags2 & elfcpp::PF_W)) - return (flags1 & elfcpp::PF_W) == 0; - if ((flags1 & elfcpp::PF_X) != (flags2 & elfcpp::PF_X)) - return (flags1 & elfcpp::PF_X) != 0; - if ((flags1 & elfcpp::PF_R) != (flags2 & elfcpp::PF_R)) - return (flags1 & elfcpp::PF_R) == 0; - - uint64_t vaddr1 = seg1->vaddr(); - uint64_t vaddr2 = seg2->vaddr(); - if (vaddr1 != vaddr2) - return vaddr1 < vaddr2; - - uint64_t paddr1 = seg1->paddr(); - uint64_t paddr2 = seg2->paddr(); - assert(paddr1 != paddr2); - return paddr1 < paddr2; -} - // Map section flags to segment flags. elfcpp::Elf_Word @@ -289,7 +212,7 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type, if ((*p)->type() == elfcpp::PT_LOAD && ((*p)->flags() & elfcpp::PF_W) == (seg_flags & elfcpp::PF_W)) { - (*p)->add_output_section(os); + (*p)->add_output_section(os, seg_flags); break; } } @@ -299,7 +222,7 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type, Output_segment* oseg = new Output_segment(elfcpp::PT_LOAD, seg_flags); this->segment_list_.push_back(oseg); - oseg->add_output_section(os); + oseg->add_output_section(os, seg_flags); } // If we see a loadable SHT_NOTE section, we create a PT_NOTE @@ -315,7 +238,7 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type, && (((*p)->flags() & elfcpp::PF_W) == (seg_flags & elfcpp::PF_W))) { - (*p)->add_output_section(os); + (*p)->add_output_section(os, seg_flags); break; } } @@ -325,7 +248,7 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type, Output_segment* oseg = new Output_segment(elfcpp::PT_NOTE, seg_flags); this->segment_list_.push_back(oseg); - oseg->add_output_section(os); + oseg->add_output_section(os, seg_flags); } } @@ -342,7 +265,7 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type, && (((*p)->flags() & elfcpp::PF_W) == (seg_flags & elfcpp::PF_W))) { - (*p)->add_output_section(os); + (*p)->add_output_section(os, seg_flags); break; } } @@ -352,7 +275,7 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type, Output_segment* oseg = new Output_segment(elfcpp::PT_TLS, seg_flags); this->segment_list_.push_back(oseg); - oseg->add_output_section(os); + oseg->add_output_section(os, seg_flags); } } } @@ -360,11 +283,25 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type, return os; } -// Create the sections for the symbol table. +// Find the first read-only PT_LOAD segment, creating one if +// necessary. -void -Layout::create_symtab_sections() +Output_segment* +Layout::find_first_load_seg() { + for (Segment_list::const_iterator p = this->segment_list_.begin(); + p != this->segment_list_.end(); + ++p) + { + if ((*p)->type() == elfcpp::PT_LOAD + && ((*p)->flags() & elfcpp::PF_R) != 0 + && ((*p)->flags() & elfcpp::PF_W) == 0) + return *p; + } + + Output_segment* load_seg = new Output_segment(elfcpp::PT_LOAD, elfcpp::PF_R); + this->segment_list_.push_back(load_seg); + return load_seg; } // Finalize the layout. When this is called, we have created all the @@ -383,13 +320,13 @@ Layout::create_symtab_sections() // 4) Determine the final file offset of all the SHF_ALLOC output // sections. -// 5) Finalize the symbol table: set symbol values to their final +// 5) Create the symbol table sections and the section name table +// section. + +// 6) Finalize the symbol table: set symbol values to their final // value and make a final determination of which symbols are going // into the output symbol table. -// 6) Create the symbol table sections and the section name table -// section. - // 7) Create the section table header. // 8) Determine the final file offset of all the output sections which @@ -397,8 +334,10 @@ Layout::create_symtab_sections() // 9) Finalize the ELF file header. -void -Layout::finalize(const Input_objects* input_objects) +// This function returns the size of the output file. + +off_t +Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab) { if (input_objects->any_dynamic()) { @@ -411,11 +350,298 @@ Layout::finalize(const Input_objects* input_objects) // FIXME: Handle PT_GNU_STACK. + Output_segment* load_seg = this->find_first_load_seg(); + + // Lay out the segment headers. + int size = input_objects->target()->get_size(); + Output_segment_headers* segment_headers; + segment_headers = new Output_segment_headers(size, this->segment_list_); + load_seg->add_initial_output_data(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, + this->options_, + input_objects->target(), + symtab, + segment_headers); + load_seg->add_initial_output_data(file_header); + + // Set the file offsets of all the segments. + off_t off = this->set_segment_offsets(input_objects->target(), load_seg); + + // Create the symbol table sections. + // 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); + + // Create the .shstrtab section. + Output_section* shstrtab_section = this->create_shstrtab(); + + // Set the file offsets of all the sections not associated with + // segments. + off = this->set_section_offsets(off); + + // Create the section table header. + Output_section_headers* oshdrs = this->create_shdrs(size, off); + off += oshdrs->data_size(); + + file_header->set_section_info(oshdrs, shstrtab_section); + + // Now we know exactly where everything goes in the output file. + + return off; +} + +// Return whether SEG1 should be before SEG2 in the output file. This +// is based entirely on the segment type and flags. When this is +// called the segment addresses has normally not yet been set. + +bool +Layout::segment_precedes(const Output_segment* seg1, + const Output_segment* seg2) +{ + elfcpp::Elf_Word type1 = seg1->type(); + elfcpp::Elf_Word type2 = seg2->type(); + + // The single PT_PHDR segment is required to precede any loadable + // segment. We simply make it always first. + if (type1 == elfcpp::PT_PHDR) + { + assert(type2 != elfcpp::PT_PHDR); + return true; + } + if (type2 == elfcpp::PT_PHDR) + return false; + + // The single PT_INTERP segment is required to precede any loadable + // segment. We simply make it always second. + if (type1 == elfcpp::PT_INTERP) + { + assert(type2 != elfcpp::PT_INTERP); + return true; + } + if (type2 == elfcpp::PT_INTERP) + return false; + + // We then put PT_LOAD segments before any other segments. + if (type1 == elfcpp::PT_LOAD && type2 != elfcpp::PT_LOAD) + return true; + if (type2 == elfcpp::PT_LOAD && type1 != elfcpp::PT_LOAD) + return false; + + const elfcpp::Elf_Word flags1 = seg1->flags(); + const elfcpp::Elf_Word flags2 = seg2->flags(); + + // The order of non-PT_LOAD segments is unimportant. We simply sort + // by the numeric segment type and flags values. There should not + // be more than one segment with the same type and flags. + if (type1 != elfcpp::PT_LOAD) + { + if (type1 != type2) + return type1 < type2; + assert(flags1 != flags2); + return flags1 < flags2; + } + + // We sort PT_LOAD segments based on the flags. Readonly segments + // come before writable segments. Then executable segments come + // before non-executable segments. Then the unlikely case of a + // non-readable segment comes before the normal case of a readable + // segment. If there are multiple segments with the same type and + // flags, we require that the address be set, and we sort by + // virtual address and then physical address. + if ((flags1 & elfcpp::PF_W) != (flags2 & elfcpp::PF_W)) + return (flags1 & elfcpp::PF_W) == 0; + if ((flags1 & elfcpp::PF_X) != (flags2 & elfcpp::PF_X)) + return (flags1 & elfcpp::PF_X) != 0; + if ((flags1 & elfcpp::PF_R) != (flags2 & elfcpp::PF_R)) + return (flags1 & elfcpp::PF_R) == 0; + + uint64_t vaddr1 = seg1->vaddr(); + uint64_t vaddr2 = seg2->vaddr(); + if (vaddr1 != vaddr2) + return vaddr1 < vaddr2; + + uint64_t paddr1 = seg1->paddr(); + uint64_t paddr2 = seg2->paddr(); + assert(paddr1 != paddr2); + return paddr1 < paddr2; +} + +// Set the file offsets of all the segments. They have all been +// created. LOAD_SEG must be be laid out first. Return the offset of +// the data to follow. + +off_t +Layout::set_segment_offsets(const Target* target, Output_segment* load_seg) +{ + // Sort them into the final order. std::sort(this->segment_list_.begin(), this->segment_list_.end(), Layout::Compare_segments()); - Output_segment_headers* segment_headers; - segment_headers = new Output_segment_headers(this->segment_list_); + // Find the PT_LOAD segments, and set their addresses and offsets + // and their section's addresses and offsets. + uint64_t addr = target->text_segment_address(); + off_t off = 0; + bool was_readonly = false; + for (Segment_list::iterator p = this->segment_list_.begin(); + p != this->segment_list_.end(); + ++p) + { + if ((*p)->type() == elfcpp::PT_LOAD) + { + if (load_seg != NULL && load_seg != *p) + abort(); + load_seg = NULL; + + // If the last segment was readonly, and this one is not, + // then skip the address forward one page, maintaining the + // same position within the page. This lets us store both + // segments overlapping on a single page in the file, but + // the loader will put them on different pages in memory. + + uint64_t orig_addr = addr; + uint64_t orig_off = off; + + uint64_t aligned_addr = addr; + uint64_t abi_pagesize = target->abi_pagesize(); + if (was_readonly && ((*p)->flags() & elfcpp::PF_W) != 0) + { + uint64_t align = (*p)->max_data_align(); + + addr = (addr + align - 1) & ~ (align - 1); + aligned_addr = addr; + if ((addr & (abi_pagesize - 1)) != 0) + addr = addr + abi_pagesize; + } + + off = orig_off + ((addr - orig_addr) & (abi_pagesize - 1)); + uint64_t new_addr = (*p)->set_section_addresses(addr, &off); + + // Now that we know the size of this segment, we may be able + // to save a page in memory, at the cost of wasting some + // file space, by instead aligning to the start of a new + // page. Here we use the real machine page size rather than + // the ABI mandated page size. + + if (aligned_addr != addr) + { + uint64_t common_pagesize = target->common_pagesize(); + uint64_t first_off = (common_pagesize + - (aligned_addr + & (common_pagesize - 1))); + uint64_t last_off = new_addr & (common_pagesize - 1); + if (first_off > 0 + && last_off > 0 + && ((aligned_addr & ~ (common_pagesize - 1)) + != (new_addr & ~ (common_pagesize - 1))) + && first_off + last_off <= common_pagesize) + { + addr = ((aligned_addr + common_pagesize - 1) + & ~ (common_pagesize - 1)); + off = orig_off + ((addr - orig_addr) & (abi_pagesize - 1)); + new_addr = (*p)->set_section_addresses(addr, &off); + } + } + + addr = new_addr; + + if (((*p)->flags() & elfcpp::PF_W) == 0) + was_readonly = true; + } + } + + // Handle the non-PT_LOAD segments, setting their offsets from their + // section's offsets. + for (Segment_list::iterator p = this->segment_list_.begin(); + p != this->segment_list_.end(); + ++p) + { + if ((*p)->type() != elfcpp::PT_LOAD) + (*p)->set_offset(); + } + + return off; +} + +// Set the file offset of all the sections not associated with a +// segment. + +off_t +Layout::set_section_offsets(off_t off) +{ + for (Layout::Section_list::iterator p = this->section_list_.begin(); + p != this->section_list_.end(); + ++p) + { + uint64_t addralign = (*p)->addralign(); + off = (off + addralign - 1) & ~ (addralign - 1); + (*p)->set_address(0, off); + off += (*p)->data_size(); + } + return off; +} + +// Create the symbol table sections. + +void +Layout::create_symtab_sections(const Input_objects* input_objects, + Symbol_table* symtab, + Output_section** posymtab, + Output_section** postrtab) +{ + off_t off = 0; + for (Input_objects::Object_list::const_iterator p = input_objects->begin(); + p != input_objects->end(); + ++p) + { + Task_lock_obj<Object> tlo(**p); + off = (*p)->finalize_local_symbols(off, &this->sympool_); + } + + 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_); +} + +// Create the .shstrtab section, which holds the names of the +// sections. At the time this is called, we have created all the +// output sections except .shstrtab itself. + +Output_section* +Layout::create_shstrtab() +{ + // FIXME: We don't need to create a .shstrtab section if we are + // stripping everything. + + const char* name = this->namepool_.add(".shstrtab"); + + Output_section* os = new Output_section_strtab(name, + &this->namepool_); + + this->section_list_.push_back(os); + + return os; +} + +// Create the section headers. SIZE is 32 or 64. OFF is the file +// offset. + +Output_section_headers* +Layout::create_shdrs(int size, off_t off) +{ + Output_section_headers* oshdrs; + oshdrs = new Output_section_headers(size, this->segment_list_, + this->section_list_); + uint64_t addralign = oshdrs->addralign(); + off = (off + addralign - 1) & ~ (addralign - 1); + oshdrs->set_address(0, off); + return oshdrs; } // The mapping of .gnu.linkonce section names to real section names. diff --git a/gold/layout.h b/gold/layout.h index 89ad8c4..75b2151 100644 --- a/gold/layout.h +++ b/gold/layout.h @@ -17,8 +17,10 @@ namespace gold { class Input_objects; +class Symbol_table; class Output_section; class Output_section_symtab; +class Output_section_headers; class Output_segment; class Output_data; @@ -33,8 +35,9 @@ class Layout_task : public Task // from executing until all the input symbols have been read. Layout_task(const General_options& options, const Input_objects* input_objects, + Symbol_table* symtab, Task_token* this_blocker) - : options_(options), input_objects_(input_objects), + : options_(options), input_objects_(input_objects), symtab_(symtab), this_blocker_(this_blocker) { } @@ -57,6 +60,7 @@ class Layout_task : public Task const General_options& options_; const Input_objects* input_objects_; + Symbol_table* symtab_; Task_token* this_blocker_; }; @@ -94,8 +98,8 @@ class Layout add_comdat(const char*, bool group); // Finalize the layout after all the input sections have been added. - void - finalize(const Input_objects*); + off_t + finalize(const Input_objects*, Symbol_table*); // The list of segments. @@ -123,18 +127,33 @@ class Layout static const Linkonce_mapping linkonce_mapping[]; static const int linkonce_mapping_count; - // Lay out the local symbols from a SHT_SYMTAB section. - template<int size, bool big_endian> - void - add_symtab_locals(Object* object, const elfcpp::Shdr<size, big_endian>&); + // Find the first read-only PT_LOAD segment, creating one if + // necessary. + Output_segment* + find_first_load_seg(); + + // Set the final file offsets of all the segments. + off_t + set_segment_offsets(const Target*, Output_segment*); + + // Set the final file offsets of all the sections not associated + // with a segment. + off_t + set_section_offsets(off_t); // Create the output sections for the symbol table. void - create_symtab_sections(); + create_symtab_sections(const Input_objects*, Symbol_table*, + Output_section** osymtab, + Output_section** ostrtab); - // Finalize the symbol table. - void - finalize_symtab(); + // Create the .shstrtab section. + Output_section* + create_shstrtab(); + + // Create the section header table. + Output_section_headers* + create_shdrs(int size, off_t); // Return whether to include this section in the link. template<int size, bool big_endian> @@ -190,6 +209,8 @@ class Layout const General_options& options_; // The output section names. Stringpool namepool_; + // The output symbol names. + Stringpool sympool_; // The list of group sections and linkonce sections which we have seen. Signatures signatures_; // The mapping from input section name/type/flags to output sections. @@ -199,9 +220,6 @@ class Layout // The list of output sections which are not attached to any output // segment. Section_list section_list_; - // The list of output data objects which are not attached to any - // output section or output segment. - Data_list data_list_; }; } // End namespace gold. diff --git a/gold/object.cc b/gold/object.cc index 04a31bd..85019fb 100644 --- a/gold/object.cc +++ b/gold/object.cc @@ -47,7 +47,8 @@ Sized_object<size, big_endian>::Sized_object( shoff_(ehdr.get_e_shoff()), shstrndx_(0), symtab_shnum_(0), - symbols_(NULL) + symbols_(NULL), + local_symbol_offset_(0) { if (ehdr.get_e_ehsize() != This::ehdr_size) { @@ -70,6 +71,16 @@ Sized_object<size, big_endian>::~Sized_object() { } +// Read the section header for section SHNUM. + +template<int size, bool big_endian> +const unsigned char* +Sized_object<size, big_endian>::section_header(unsigned int shnum) +{ + off_t symtabshdroff = this->shoff_ + shnum * This::shdr_size; + return this->get_view(symtabshdroff, This::shdr_size); +} + // Set up an object file bsaed on the file header. This sets up the // target and reads the section information. @@ -94,8 +105,7 @@ Sized_object<size, big_endian>::setup( if ((shnum == 0 || shstrndx == elfcpp::SHN_XINDEX) && this->shoff_ != 0) { - const unsigned char* p = this->get_view (this->shoff_, This::shdr_size); - elfcpp::Shdr<size, big_endian> shdr(p); + typename This::Shdr shdr(this->section_header(0)); if (shnum == 0) shnum = shdr.get_sh_size(); if (shstrndx == elfcpp::SHN_XINDEX) @@ -114,7 +124,7 @@ Sized_object<size, big_endian>::setup( p += This::shdr_size; for (unsigned int i = 1; i < shnum; ++i) { - elfcpp::Shdr<size, big_endian> shdr(p); + typename This::Shdr shdr(p); if (shdr.get_sh_type() == elfcpp::SHT_SYMTAB) { this->symtab_shnum_ = i; @@ -136,23 +146,23 @@ Sized_object<size, big_endian>::do_read_symbols() Read_symbols_data ret; ret.symbols = NULL; ret.symbols_size = 0; - ret.first_global = 0; ret.symbol_names = NULL; ret.symbol_names_size = 0; return ret; } - const int shdr_size = This::shdr_size; - // Read the symbol table section header. - off_t symtabshdroff = this->shoff_ + (this->symtab_shnum_ * shdr_size); - const unsigned char* psymtabshdr = this->get_view(symtabshdroff, shdr_size); - elfcpp::Shdr<size, big_endian> symtabshdr(psymtabshdr); + typename This::Shdr symtabshdr(this->section_header(this->symtab_shnum_)); assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB); + // We only need the external symbols. + const int sym_size = This::sym_size; + off_t locsize = symtabshdr.get_sh_info() * sym_size; + off_t extoff = symtabshdr.get_sh_offset() + locsize; + off_t extsize = symtabshdr.get_sh_size() - locsize; + // Read the symbol table. - File_view* fvsymtab = this->get_lasting_view(symtabshdr.get_sh_offset(), - symtabshdr.get_sh_size()); + File_view* fvsymtab = this->get_lasting_view(extoff, extsize); // Read the section header for the symbol names. unsigned int strtab_shnum = symtabshdr.get_sh_link(); @@ -162,9 +172,7 @@ Sized_object<size, big_endian>::do_read_symbols() program_name, this->name().c_str(), strtab_shnum); gold_exit(false); } - off_t strtabshdroff = this->shoff_ + (strtab_shnum * shdr_size); - const unsigned char *pstrtabshdr = this->get_view(strtabshdroff, shdr_size); - elfcpp::Shdr<size, big_endian> strtabshdr(pstrtabshdr); + typename This::Shdr strtabshdr(this->section_header(strtab_shnum)); if (strtabshdr.get_sh_type() != elfcpp::SHT_STRTAB) { fprintf(stderr, @@ -180,8 +188,7 @@ Sized_object<size, big_endian>::do_read_symbols() Read_symbols_data ret; ret.symbols = fvsymtab; - ret.symbols_size = symtabshdr.get_sh_size(); - ret.first_global = symtabshdr.get_sh_info(); + ret.symbols_size = extsize; ret.symbol_names = fvstrtab; ret.symbol_names_size = strtabshdr.get_sh_size(); @@ -211,29 +218,14 @@ Sized_object<size, big_endian>::do_add_symbols(Symbol_table* symtab, gold_exit(false); } - const char* sym_names = - reinterpret_cast<const char*>(sd.symbol_names->data()); - - // We only add the global symbols to the symbol table. - if (symcount > sd.first_global) - { - this->symbols_ = new Symbol*[symcount - sd.first_global]; - - const unsigned char* symdata = sd.symbols->data(); - symdata += sd.first_global * sym_size; - const elfcpp::Sym<size, big_endian>* syms = - reinterpret_cast<const elfcpp::Sym<size, big_endian>*>(symdata); - - symtab->add_from_object(this, syms, symcount - sd.first_global, - sym_names, sd.symbol_names_size, this->symbols_); - } + this->symbols_ = new Symbol*[symcount]; - // Add the names of the local symbols. FIXME: We shouldn't do this - // if we are stripping symbols. - const elfcpp::Sym<size, big_endian>* local_syms = + const elfcpp::Sym<size, big_endian>* syms = reinterpret_cast<const elfcpp::Sym<size, big_endian>*>(sd.symbols->data()); - symtab->add_local_symbol_names(this, local_syms, sd.first_global, - sym_names, sd.symbol_names_size); + const char* sym_names = + reinterpret_cast<const char*>(sd.symbol_names->data()); + symtab->add_from_object(this, syms, symcount, sym_names, + sd.symbol_names_size, this->symbols_); delete sd.symbols; delete sd.symbol_names; @@ -279,9 +271,8 @@ Sized_object<size, big_endian>::include_section_group( program_name, this->name().c_str(), index, shdr.get_sh_link()); gold_exit(false); } - off_t off = this->shoff_ + shdr.get_sh_link() * This::shdr_size; - const unsigned char* psymshdr = this->get_view(off, This::shdr_size); - elfcpp::Shdr<size, big_endian> symshdr(psymshdr); + + typename This::Shdr symshdr(this->section_header(shdr.get_sh_link())); // Read the symbol table entry. if (shdr.get_sh_info() >= symshdr.get_sh_size() / This::sym_size) @@ -302,10 +293,8 @@ Sized_object<size, big_endian>::include_section_group( symshdr.get_sh_link()); gold_exit(false); } - off_t symnameoff = this->shoff_ + symshdr.get_sh_link() * This::shdr_size; - const unsigned char* psymnamehdr = this->get_view(symnameoff, - This::shdr_size); - elfcpp::Shdr<size, big_endian> symnamehdr(psymnamehdr); + + typename This::Shdr symnamehdr(this->section_header(symshdr.get_sh_link())); // Read the symbol table names. const unsigned char *psymnamesu = this->get_view(symnamehdr.get_sh_offset(), @@ -396,7 +385,7 @@ Sized_object<size, big_endian>::do_layout(Layout* layout) // Get the section names. const unsigned char* pshdrnames = pshdrs + this->shstrndx_ * This::shdr_size; - elfcpp::Shdr<size, big_endian> shdrnames(pshdrnames); + typename This::Shdr shdrnames(pshdrnames); typename elfcpp::Elf_types<size>::Elf_WXword names_size = shdrnames.get_sh_size(); const unsigned char* pnamesu = this->get_view(shdrnames.get_sh_offset(), @@ -411,7 +400,7 @@ Sized_object<size, big_endian>::do_layout(Layout* layout) for (unsigned int i = 0; i < shnum; ++i) { - elfcpp::Shdr<size, big_endian> shdr(pshdrs); + typename This::Shdr shdr(pshdrs); if (shdr.get_sh_name() >= names_size) { @@ -456,12 +445,105 @@ Sized_object<size, big_endian>::do_layout(Layout* layout) } } +// Finalize the local symbols. Here we record the file offset at +// which they should be output and we add their names to *POOL. +// Return the new file offset. This function is always called from +// the main thread. The actual output of the local symbols will occur +// in a separate task. + +template<int size, bool big_endian> +off_t +Sized_object<size, big_endian>::do_finalize_local_symbols(off_t off, + Stringpool* pool) +{ + this->local_symbol_offset_ = off; + + // Read the symbol table section header. + typename This::Shdr symtabshdr(this->section_header(this->symtab_shnum_)); + assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB); + + // Read the local symbols. + unsigned int loccount = symtabshdr.get_sh_info(); + const int sym_size = This::sym_size; + off_t locsize = loccount * sym_size; + const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(), + locsize); + + // Read the section header for the symbol names. + typename This::Shdr strtabshdr( + this->section_header(symtabshdr.get_sh_link())); + assert(strtabshdr.get_sh_type() == elfcpp::SHT_STRTAB); + + // Read the symbol names. + const unsigned char* pnamesu = this->get_view(strtabshdr.get_sh_offset(), + strtabshdr.get_sh_size()); + const char* pnames = reinterpret_cast<const char*>(pnamesu); + + // Loop over the local symbols. + + std::vector<Map_to_output>& mo(this->map_to_output()); + unsigned int shnum = this->shnum(); + // Skip the first, dummy, symbol. + psyms += sym_size; + for (unsigned int i = 1; i < loccount; ++i) + { + elfcpp::Sym<size, big_endian> sym(psyms); + + unsigned int shndx = sym.get_st_shndx(); + + if (shndx >= elfcpp::SHN_LORESERVE) + { + if (shndx != elfcpp::SHN_ABS) + { + fprintf(stderr, + _("%s: %s: unknown section index %u " + "for local symbol %u\n"), + program_name, this->name().c_str(), shndx, i); + gold_exit(false); + } + // FIXME: Handle SHN_XINDEX. + } + else + { + if (shndx >= shnum) + { + fprintf(stderr, + _("%s: %s: local symbol %u section index %u " + "out of range\n"), + program_name, this->name().c_str(), i, shndx); + gold_exit(false); + } + + if (mo[shndx].output_section == NULL) + continue; + } + + pool->add(pnames + sym.get_st_name()); + off += sym_size; + + psyms += sym_size; + } + + return off; +} + // Input_objects methods. void Input_objects::add_object(Object* obj) { this->object_list_.push_back(obj); + + Target* target = obj->target(); + if (this->target_ == NULL) + this->target_ = target; + else if (this->target_ != target) + { + fprintf(stderr, "%s: %s: incompatible target\n", + program_name, obj->name().c_str()); + gold_exit(false); + } + if (obj->is_dynamic()) this->any_dynamic_ = true; } diff --git a/gold/object.h b/gold/object.h index 36cf949..e3df36d 100644 --- a/gold/object.h +++ b/gold/object.h @@ -14,6 +14,7 @@ namespace gold { +class Stringpool; class Output_section; class Layout; @@ -25,8 +26,6 @@ struct Read_symbols_data File_view* symbols; // Size of symbol data in bytes. off_t symbols_size; - // Index of first global symbol. - unsigned int first_global; // Symbol names. File_view* symbol_names; // Size of symbol name data in bytes. @@ -110,7 +109,13 @@ class Object layout(Layout* lay) { this->do_layout(lay); } - protected: + // Initial local symbol processing: set the offset where local + // symbol information will be stored; add local symbol names to + // *POOL; return the offset following the local symbols. + off_t + finalize_local_symbols(off_t off, Stringpool* pool) + { return this->do_finalize_local_symbols(off, pool); } + // What we need to know to map an input section to an output // section. We keep an array of these, one for each input section, // indexed by the input section number. @@ -123,6 +128,13 @@ class Object off_t offset; }; + // Given a section index, return the corresponding Map_to_output + // information. + const Map_to_output* + section_output_info(unsigned int shnum) const + { return &this->map_to_output_[shnum]; } + + protected: // Read the symbols--implemented by child class. virtual Read_symbols_data do_read_symbols() = 0; @@ -136,6 +148,10 @@ class Object virtual void do_layout(Layout*) = 0; + // Finalize local symbols--implemented by child class. + virtual off_t + do_finalize_local_symbols(off_t, Stringpool*) = 0; + // Get the file. Input_file* input_file() const @@ -152,7 +168,7 @@ class Object // Get the number of sections. unsigned int - shnum(void) const + shnum() const { return this->shnum_; } // Set the number of sections. @@ -243,6 +259,10 @@ class Sized_object : public Object void do_layout(Layout*); + // Finalize the local symbols. + off_t + do_finalize_local_symbols(off_t, Stringpool*); + // Return the appropriate Sized_target structure. Sized_target<size, big_endian>* sized_target() @@ -264,6 +284,11 @@ class Sized_object : public Object static const int ehdr_size = elfcpp::Elf_sizes<size>::ehdr_size; static const int shdr_size = elfcpp::Elf_sizes<size>::shdr_size; static const int sym_size = elfcpp::Elf_sizes<size>::sym_size; + typedef elfcpp::Shdr<size, big_endian> Shdr; + + // Read the section header for section SHNUM. + const unsigned char* + section_header(unsigned int shnum); // Whether to include a section group in the link. bool @@ -286,6 +311,8 @@ class Sized_object : public Object unsigned int symtab_shnum_; // The entries in the symbol table for the external symbols. Symbol** symbols_; + // File offset for local symbols. + off_t local_symbol_offset_; }; // A class to manage the list of all objects. @@ -294,7 +321,7 @@ class Input_objects { public: Input_objects() - : object_list_(), any_dynamic_(false) + : object_list_(), target_(NULL), any_dynamic_(false) { } // The type of the list of input objects. @@ -304,6 +331,11 @@ class Input_objects void add_object(Object*); + // Get the target we should use for the output file. + Target* + target() const + { return this->target_; } + // Iterate over all objects. Object_list::const_iterator begin() const @@ -323,6 +355,7 @@ class Input_objects Input_objects& operator=(const Input_objects&); Object_list object_list_; + Target* target_; bool any_dynamic_; }; diff --git a/gold/output.cc b/gold/output.cc index 9092301..3940f82 100644 --- a/gold/output.cc +++ b/gold/output.cc @@ -3,6 +3,7 @@ #include "gold.h" #include <cstdlib> +#include <algorithm> #include "object.h" #include "output.h" @@ -16,18 +17,116 @@ Output_data::~Output_data() { } +// 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 a size--32 or 64. + +uint64_t +Output_data::default_alignment(int size) +{ + if (size == 32) + return 4; + else if (size == 64) + return 8; + else + abort(); +} + // Output_data_const methods. void -Output_data_const::write(Output_file* output, off_t off) +Output_data_const::do_write(Output_file* output) +{ + output->write(this->offset(), data_.data(), data_.size()); +} + +// Output_section_header methods. This currently assumes that the +// segment and section lists are complete at construction time. + +Output_section_headers::Output_section_headers( + int size, + const Layout::Segment_list& segment_list, + const Layout::Section_list& section_list) + : size_(size), + segment_list_(segment_list), + section_list_(section_list) +{ + // Count all the sections. + off_t count = 0; + for (Layout::Segment_list::const_iterator p = segment_list.begin(); + p != segment_list.end(); + ++p) + count += (*p)->output_section_count(); + count += section_list.size(); + + int shdr_size; + if (size == 32) + shdr_size = elfcpp::Elf_sizes<32>::shdr_size; + else if (size == 64) + shdr_size = elfcpp::Elf_sizes<64>::shdr_size; + else + abort(); + + this->set_data_size(count * shdr_size); +} + +void +Output_section_headers::do_write(Output_file*) { - output->write(off, data_.data(), data_.size()); + // FIXME: Unimplemented. + abort(); } // Output_segment_header methods. void -Output_segment_headers::write(Output_file*, off_t) +Output_segment_headers::do_write(Output_file*) +{ + // FIXME: Unimplemented. + abort(); +} + +// Output_file_header methods. + +Output_file_header::Output_file_header(int size, + const General_options& options, + const Target* target, + const Symbol_table* symtab, + const Output_segment_headers* osh) + : size_(size), + options_(options), + target_(target), + symtab_(symtab), + program_header_(osh), + section_header_(NULL), + shstrtab_(NULL) +{ +} + +// Set the section table information for a file header. + +void +Output_file_header::set_section_info(const Output_section_headers* shdrs, + const Output_section* shstrtab) +{ + this->section_header_ = shdrs; + this->shstrtab_ = shstrtab; +} + +// Write out the file header. + +void +Output_file_header::do_write(Output_file*) { // FIXME: Unimplemented. abort(); @@ -40,10 +139,8 @@ Output_segment_headers::write(Output_file*, off_t) Output_section::Output_section(const char* name, elfcpp::Elf_Word type, elfcpp::Elf_Xword flags) : name_(name), - addr_(0), addralign_(0), entsize_(0), - offset_(0), link_(0), info_(0), type_(type), @@ -76,18 +173,49 @@ Output_section::add_input_section(Object* object, const char* secname, if (addralign > this->addralign_) this->addralign_ = addralign; - off_t ssize = this->get_size(); + off_t ssize = this->data_size(); ssize = (ssize + addralign - 1) &~ (addralign - 1); - this->set_size(ssize + shdr.get_sh_size()); + // SHF_TLS/SHT_NOBITS sections are handled specially: they are + // treated as having no size and taking up no space. We only use + // the real size when setting the pt_memsz field of the PT_TLS + // segment. + if ((this->flags_ & elfcpp::SHF_TLS) == 0 + || this->type_ != elfcpp::SHT_NOBITS) + this->set_data_size(ssize + shdr.get_sh_size()); return size; } +// Output_section_symtab methods. + +Output_section_symtab::Output_section_symtab(const char* name, off_t size) + : Output_section(name, elfcpp::SHT_SYMTAB, 0) +{ + this->set_data_size(size); +} + +// Output_section_strtab methods. + +Output_section_strtab::Output_section_strtab(const char* name, + Stringpool* contents) + : Output_section(name, elfcpp::SHT_STRTAB, 0), + contents_(contents) +{ +} + +void +Output_section_strtab::do_write(Output_file*) +{ + // FIXME: Unimplemented. + abort(); +} + // Output segment methods. Output_segment::Output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags) : output_data_(), + output_bss_(), vaddr_(0), paddr_(0), memsz_(0), @@ -102,10 +230,22 @@ Output_segment::Output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags) // Add an Output_section to an Output_segment. void -Output_segment::add_output_section(Output_section* os) +Output_segment::add_output_section(Output_section* os, + elfcpp::Elf_Word seg_flags) { - // Update the segment flags. - this->flags_ |= os->flags() & (elfcpp::PF_R | elfcpp::PF_W | elfcpp::PF_X); + assert((os->flags() & elfcpp::SHF_ALLOC) != 0); + + // Update the segment flags and alignment. + this->flags_ |= seg_flags; + uint64_t addralign = os->addralign(); + if (addralign > this->align_) + this->align_ = addralign; + + Output_segment::Output_data_list* pdl; + if (os->type() == elfcpp::SHT_NOBITS) + pdl = &this->output_bss_; + else + pdl = &this->output_data_; // So that PT_NOTE segments will work correctly, we need to ensure // that all SHT_NOTE sections are adjacent. This will normally @@ -122,37 +262,196 @@ Output_segment::add_output_section(Output_section* os) if (os->type() == elfcpp::SHT_NOTE) { - for (Layout::Data_list::iterator p = this->output_data_.begin(); - p != this->output_data_.end(); - ++p) + Layout::Data_list::iterator p = pdl->end(); + do { + --p; if ((*p)->is_section_type(elfcpp::SHT_NOTE)) { ++p; - this->output_data_.insert(p, os); + pdl->insert(p, os); return; } } + while (p != pdl->begin()); } // Similarly, so that PT_TLS segments will work, we need to group - // SHF_TLS sections. + // SHF_TLS sections. An SHF_TLS/SHT_NOBITS section is a special + // case: we group the SHF_TLS/SHT_NOBITS sections right after the + // SHF_TLS/SHT_PROGBITS sections. This lets us set up PT_TLS + // correctly. if ((os->flags() & elfcpp::SHF_TLS) != 0) { - for (Layout::Data_list::iterator p = this->output_data_.begin(); - p != this->output_data_.end(); - ++p) + pdl = &this->output_data_; + bool nobits = os->type() == elfcpp::SHT_NOBITS; + Layout::Data_list::iterator p = pdl->end(); + do { - if ((*p)->is_section_flag_set(elfcpp::SHF_TLS)) + --p; + if ((*p)->is_section_flag_set(elfcpp::SHF_TLS) + && (nobits || !(*p)->is_section_type(elfcpp::SHT_NOBITS))) { ++p; - this->output_data_.insert(p, os); + pdl->insert(p, os); return; } } + while (p != pdl->begin()); } - this->output_data_.push_back(os); + pdl->push_back(os); +} + +// Add an Output_data (which is not an Output_section) to the start of +// a segment. + +void +Output_segment::add_initial_output_data(Output_data* od) +{ + uint64_t addralign = od->addralign(); + if (addralign > this->align_) + this->align_ = addralign; + + this->output_data_.push_front(od); +} + +// Return the maximum alignment of the Output_data in Output_segment. +// We keep this up to date as we add Output_sections and Output_data. + +uint64_t +Output_segment::max_data_align() const +{ + return this->align_; +} + +// Set the section addresses for an Output_segment. ADDR is the +// address and *POFF is the file offset. Return the address of the +// immediately following segment. Update *POFF. + +uint64_t +Output_segment::set_section_addresses(uint64_t addr, off_t* poff) +{ + assert(this->type_ == elfcpp::PT_LOAD); + + this->vaddr_ = addr; + this->paddr_ = addr; + + off_t orig_off = *poff; + this->offset_ = orig_off; + + addr = this->set_section_list_addresses(&this->output_data_, addr, poff); + this->filesz_ = *poff - orig_off; + + off_t off = *poff; + + return this->set_section_list_addresses(&this->output_bss_, addr, poff); + this->memsz_ = *poff - orig_off; + + // Ignore the file offset adjustments made by the BSS Output_data + // objects. + *poff = off; +} + +// Set the addresses in a list of Output_data structures. + +uint64_t +Output_segment::set_section_list_addresses(Output_data_list* pdl, + uint64_t addr, off_t* poff) +{ + off_t off = *poff; + + for (Output_data_list::iterator p = pdl->begin(); + p != pdl->end(); + ++p) + { + uint64_t addralign = (*p)->addralign(); + addr = (addr + addralign - 1) & ~ (addralign - 1); + off = (off + addralign - 1) & ~ (addralign - 1); + (*p)->set_address(addr, off); + + uint64_t size = (*p)->data_size(); + addr += size; + off += size; + } + + *poff = off; + return addr; +} + +// For a non-PT_LOAD segment, set the offset from the sections, if +// any. + +void +Output_segment::set_offset() +{ + assert(this->type_ != elfcpp::PT_LOAD); + + if (this->output_data_.empty() && this->output_bss_.empty()) + { + this->vaddr_ = 0; + this->paddr_ = 0; + this->memsz_ = 0; + this->align_ = 0; + this->offset_ = 0; + this->filesz_ = 0; + return; + } + + const Output_data* first; + if (this->output_data_.empty()) + first = this->output_bss_.front(); + else + first = this->output_data_.front(); + this->vaddr_ = first->address(); + this->paddr_ = this->vaddr_; + this->offset_ = first->offset(); + + if (this->output_data_.empty()) + this->filesz_ = 0; + else + { + const Output_data* last_data = this->output_data_.back(); + this->filesz_ = (last_data->address() + + last_data->data_size() + - this->vaddr_); + } + + const Output_data* last; + if (this->output_bss_.empty()) + last = this->output_data_.back(); + else + last = this->output_bss_.back(); + this->memsz_ = (last->address() + + last->data_size() + - this->vaddr_); + + // this->align_ was set as we added items. +} + +// Return the number of Output_sections in an Output_segment. + +unsigned int +Output_segment::output_section_count() const +{ + return (this->output_section_count_list(&this->output_data_) + + this->output_section_count_list(&this->output_bss_)); +} + +// Return the number of Output_sections in an Output_data_list. + +unsigned int +Output_segment::output_section_count_list(const Output_data_list* pdl) const +{ + unsigned int count = 0; + for (Output_data_list::const_iterator p = pdl->begin(); + p != pdl->end(); + ++p) + { + if ((*p)->is_section()) + ++count; + } + return count; } // Output_file methods. diff --git a/gold/output.h b/gold/output.h index b0d3f80..25c5b2a 100644 --- a/gold/output.h +++ b/gold/output.h @@ -3,6 +3,7 @@ #ifndef GOLD_OUTPUT_H #define GOLD_OUTPUT_H +#include <cassert> #include <list> #include "elfcpp.h" @@ -22,47 +23,113 @@ class Sized_target; class Output_data { public: - Output_data(off_t size = 0) - : size_(size) + explicit Output_data(off_t data_size = 0) + : address_(0), data_size_(data_size), offset_(0) { } virtual ~Output_data(); - // Return the size of the data. This can't be called "size" since - // that interferes with the widely used template parameter name. + // Return the address. + uint64_t + address() const + { return this->address_; } + + // Return the size of the data. off_t - get_size() - { return this->size_; } + data_size() const + { return this->data_size_; } + + // Return the file offset. + off_t + offset() const + { return this->offset_; } + + // Return the required alignment. + uint64_t + addralign() const + { return this->do_addralign(); } + + // Return whether this is an Output_section. + bool + is_section() const + { return this->do_is_section(); } + + // Return whether this is an Output_section of the specified type. + bool + is_section_type(elfcpp::Elf_Word stt) const + { return this->do_is_section_type(stt); } + + // Return whether this is an Output_section with the specified flag + // set. + bool + is_section_flag_set(elfcpp::Elf_Xword shf) const + { return this->do_is_section_flag_set(shf); } + + // Set the address and file offset of this data. + void + set_address(uint64_t addr, off_t off); + + // Write the data to the output file. + void + write(Output_file* file) + { this->do_write(file); } - // Write the data to the output file at the specified offset. This - // must be implemented by the real class. + protected: + // Functions that child classes may or in some cases must implement. + + // Write the data to the output file. virtual void - write(Output_file*, off_t off) = 0; + do_write(Output_file*) = 0; + + // Return the required alignment. + virtual uint64_t + do_addralign() const = 0; + + // Return whether this is an Output_section. + virtual bool + do_is_section() const + { return false; } // Return whether this is an Output_section of the specified type. + // This only needs to be implement by Output_section. virtual bool - is_section_type(elfcpp::Elf_Word) + do_is_section_type(elfcpp::Elf_Word) const { return false; } - // Return whether this is an Output_section with the specified flag - // set. + // Return whether this is an Output_section with the specific flag + // set. This only needs to be implemented by Output_section. virtual bool - is_section_flag_set(elfcpp::Elf_Xword) + do_is_section_flag_set(elfcpp::Elf_Xword) const { return false; } - protected: + // Set the address and file offset of the data. This only needs to + // be implemented if the child needs to know. + virtual void + do_set_address(uint64_t, off_t) + { } + + // Functions that child classes may call. + // Set the size of the data. void - set_size(off_t size) - { this->size_ = size; } + set_data_size(off_t data_size) + { this->data_size_ = data_size; } + + // Return default alignment for a size--32 or 64. + static uint64_t + default_alignment(int size); private: Output_data(const Output_data&); Output_data& operator=(const Output_data&); + // Memory address in file (not always meaningful). + uint64_t address_; // Size of data in file. - off_t size_; + off_t data_size_; + // Offset within file. + off_t offset_; }; // A simple case of Output_data in which we have constant data to @@ -71,20 +138,26 @@ class Output_data class Output_data_const : public Output_data { public: - Output_data_const(const std::string& data) - : Output_data(data.size()), data_(data) + Output_data_const(const std::string& data, uint64_t addralign) + : Output_data(data.size()), data_(data), addralign_(addralign) { } - Output_data_const(const char* p, off_t len) - : Output_data(len), data_(p, len) + Output_data_const(const char* p, off_t len, uint64_t addralign) + : Output_data(len), data_(p, len), addralign_(addralign) { } // Write the data to the file. void - write(Output_file* output, off_t off); + do_write(Output_file* output); + + // Return the required alignment. + uint64_t + do_addralign() const + { return this->addralign_; } private: std::string data_; + uint64_t addralign_; }; // Output the section headers. @@ -92,14 +165,21 @@ class Output_data_const : public Output_data class Output_section_headers : public Output_data { public: - Output_section_headers(const Layout::Segment_list&, + Output_section_headers(int size, + const Layout::Segment_list&, const Layout::Section_list&); // Write the data to the file. void - write(Output_file*, off_t); + do_write(Output_file*); + + // Return the required alignment. + uint64_t + do_addralign() const + { return Output_data::default_alignment(this->size_); } private: + int size_; const Layout::Segment_list& segment_list_; const Layout::Section_list& section_list_; }; @@ -109,15 +189,21 @@ class Output_section_headers : public Output_data class Output_segment_headers : public Output_data { public: - Output_segment_headers(const Layout::Segment_list& segment_list) - : segment_list_(segment_list) + Output_segment_headers(int size, const Layout::Segment_list& segment_list) + : size_(size), segment_list_(segment_list) { } // Write the data to the file. void - write(Output_file*, off_t); + do_write(Output_file*); + + // Return the required alignment. + uint64_t + do_addralign() const + { return Output_data::default_alignment(this->size_); } private: + int size_; const Layout::Segment_list& segment_list_; }; @@ -126,18 +212,34 @@ class Output_segment_headers : public Output_data class Output_file_header : public Output_data { public: - Output_file_header(const General_options&, + Output_file_header(int size, + const General_options&, const Target*, const Symbol_table*, - const Output_segment_headers*, - const Output_section_headers*, - const Output_section* shstrtab); + const Output_segment_headers*); + + // Add information about the section headers. We lay out the ELF + // file header before we create the section headers. + void set_section_info(const Output_section_headers*, + const Output_section* shstrtab); // Write the data to the file. void - write(Output_file*, off_t); + do_write(Output_file*); + + // Return the required alignment. + uint64_t + do_addralign() const + { return Output_data::default_alignment(this->size_); } + + // Set the address and offset--we only implement this for error + // checking. + void + do_set_address(uint64_t, off_t off) const + { assert(off == 0); } private: + int size_; const General_options& options_; const Target* target_; const Symbol_table* symtab_; @@ -178,21 +280,36 @@ class Output_section : public Output_data flags() const { return this->flags_; } + // Return the address alignment. + uint64_t + addralign() const + { return this->addralign_; } + // Write the data to the file. For a typical Output_section, this // does nothing. We write out the data by looping over all the // input sections. virtual void - write(Output_file*, off_t) + do_write(Output_file*) { } + // Return the address alignment--function required by parent class. + uint64_t + do_addralign() const + { return this->addralign_; } + + // Return whether this is an Output_section. + bool + do_is_section() const + { return true; } + // Return whether this is a section of the specified type. bool - is_section_type(elfcpp::Elf_Word type) + do_is_section_type(elfcpp::Elf_Word type) const { return this->type_ == type; } // Return whether the specified section flag is set. bool - is_section_flag_set(elfcpp::Elf_Xword flag) + do_is_section_flag_set(elfcpp::Elf_Xword flag) const { return (this->flags_ & flag) != 0; } private: @@ -200,14 +317,12 @@ class Output_section : public Output_data // The name of the section. This will point into a Stringpool. const char* name_; - // The section address. - uint64_t addr_; + // The section address is in the parent class. // The section alignment. uint64_t addralign_; // The section entry size. uint64_t entsize_; - // The file offset. - off_t offset_; + // The file offset is in the parent class. // The section link field. unsigned int link_; // The section info field. @@ -224,8 +339,22 @@ class Output_section : public Output_data class Output_section_symtab : public Output_section { public: - Output_section_symtab(); - ~Output_section_symtab(); + Output_section_symtab(const char* name, off_t size); +}; + +// A special Output_section which holds a string table. + +class Output_section_strtab : public Output_section +{ + public: + Output_section_strtab(const char* name, Stringpool* contents); + + // Write out the data. + void + do_write(Output_file*); + + private: + Stringpool* contents_; }; // An output segment. PT_LOAD segments are built from collections of @@ -258,9 +387,35 @@ class Output_segment flags() const { return this->flags_; } + // Return the maximum alignment of the Output_data. + uint64_t + max_data_align() const; + // Add an Output_section to this segment. void - add_output_section(Output_section*); + add_output_section(Output_section*, elfcpp::Elf_Word seg_flags); + + // Add an Output_data (which is not an Output_section) to the start + // of this segment. + void + add_initial_output_data(Output_data*); + + // Set the address of the segment to ADDR and the offset to *POFF + // (aligned if necessary), and set the addresses and offsets of all + // contained output sections accordingly. Return the address of the + // immediately following segment. Update *POFF. This should only + // be called for a PT_LOAD segment. + uint64_t + set_section_addresses(uint64_t addr, off_t* poff); + + // Set the offset of this segment based on the section. This should + // only be called for a non-PT_LOAD segment. + void + set_offset(); + + // Return the number of output sections. + unsigned int + output_section_count() const; private: Output_segment(const Output_segment&); @@ -268,9 +423,18 @@ class Output_segment typedef std::list<Output_data*> Output_data_list; - // The list of output sections attached to this segment. This is - // cleared after layout. + // Set the section addresses in an Output_data_list. + uint64_t + set_section_list_addresses(Output_data_list*, uint64_t addr, off_t* poff); + + // Return the number of Output_sections in an Output_data_list. + unsigned int + output_section_count_list(const Output_data_list*) const; + + // The list of output data with contents attached to this segment. Output_data_list output_data_; + // The list of output data without contents attached to this segment. + Output_data_list output_bss_; // The segment virtual address. uint64_t vaddr_; // The segment physical address. diff --git a/gold/po/gold.pot b/gold/po/gold.pot index ec385f4..b0852a3 100644 --- a/gold/po/gold.pot +++ b/gold/po/gold.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2006-09-26 14:19-0700\n" +"POT-Creation-Date: 2006-09-27 15:38-0700\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" @@ -99,103 +99,113 @@ msgstr "" msgid "pthread_cond_signal failed" msgstr "" -#: object.cc:54 +#: object.cc:55 #, c-format msgid "%s: %s: bad e_ehsize field (%d != %d)\n" msgstr "" -#: object.cc:61 +#: object.cc:62 #, c-format msgid "%s: %s: bad e_shentsize field (%d != %d)\n" msgstr "" -#: object.cc:87 +#: object.cc:98 #, c-format msgid "%s: %s: unsupported ELF machine number %d\n" msgstr "" -#: object.cc:161 +#: object.cc:171 #, c-format msgid "%s: %s: invalid symbol table name index: %u\n" msgstr "" -#: object.cc:171 +#: object.cc:179 #, c-format msgid "%s: %s: symbol table name section has wrong type: %u\n" msgstr "" -#: object.cc:209 +#: object.cc:216 #, c-format msgid "%s: %s: size of symbols is not multiple of symbol size\n" msgstr "" -#: object.cc:278 +#: object.cc:270 #, c-format msgid "%s: %s: section group %u link %u out of range\n" msgstr "" -#: object.cc:289 +#: object.cc:280 #, c-format msgid "%s: %s: section group %u info %u out of range\n" msgstr "" -#: object.cc:300 +#: object.cc:291 #, c-format msgid "%s; %s: symtab section %u link %u out of range\n" msgstr "" -#: object.cc:318 +#: object.cc:307 #, c-format msgid "%s: %s: symbol %u name offset %u out of range\n" msgstr "" -#: object.cc:340 +#: object.cc:329 #, c-format msgid "%s: %s: section %u in section group %u out of range" msgstr "" -#: object.cc:419 +#: object.cc:408 #, c-format msgid "%s: %s: bad section name offset for section %u: %lu\n" msgstr "" +#: object.cc:499 +#, c-format +msgid "%s: %s: unknown section index %u for local symbol %u\n" +msgstr "" + +#: object.cc:511 +#, c-format +msgid "%s: %s: local symbol %u section index %u out of range\n" +msgstr "" + #. elfcpp::ET_DYN -#: object.cc:502 +#: object.cc:584 #, c-format msgid "%s: %s: dynamic objects are not yet supported\n" msgstr "" -#: object.cc:526 object.cc:579 object.cc:600 +#: object.cc:608 object.cc:661 object.cc:682 #, c-format msgid "%s: %s: ELF file too short\n" msgstr "" -#: object.cc:535 +#: object.cc:617 #, c-format msgid "%s: %s: invalid ELF version 0\n" msgstr "" -#: object.cc:538 +#: object.cc:620 #, c-format msgid "%s: %s: unsupported ELF version %d\n" msgstr "" -#: object.cc:546 +#: object.cc:628 #, c-format msgid "%s: %s: invalid ELF class 0\n" msgstr "" -#: object.cc:553 +#: object.cc:635 #, c-format msgid "%s: %s: unsupported ELF class %d\n" msgstr "" -#: object.cc:561 +#: object.cc:643 #, c-format msgid "%s: %s: invalid ELF data encoding\n" msgstr "" -#: object.cc:568 +#: object.cc:650 #, c-format msgid "%s: %s: unsupported ELF data encoding %d\n" msgstr "" @@ -250,32 +260,27 @@ msgstr "" msgid "%s: -%c: %s\n" msgstr "" -#: output.cc:70 +#: output.cc:167 #, c-format msgid "%s: %s: invalid alignment %lu for section \"%s\"\n" msgstr "" -#: resolve.cc:135 +#: resolve.cc:144 #, c-format msgid "%s: %s: invalid STB_LOCAL symbol %s in external symbols\n" msgstr "" -#: resolve.cc:141 +#: resolve.cc:150 #, c-format msgid "%s: %s: unsupported symbol binding %d for symbol %s\n" msgstr "" -#: symtab.cc:271 +#: symtab.cc:322 #, c-format msgid "%s: %s: mixing 32-bit and 64-bit ELF objects\n" msgstr "" -#: symtab.cc:285 +#: symtab.cc:336 #, c-format msgid "%s: %s: bad global symbol name offset %u at %lu\n" msgstr "" - -#: symtab.cc:342 -#, c-format -msgid "%s: %s: bad local symbol name offset %u at %lu\n" -msgstr "" diff --git a/gold/symtab.cc b/gold/symtab.cc index 189032d..a317f99 100644 --- a/gold/symtab.cc +++ b/gold/symtab.cc @@ -8,6 +8,7 @@ #include <utility> #include "object.h" +#include "output.h" #include "symtab.h" namespace gold @@ -52,7 +53,7 @@ Sized_symbol<size>::init(const char* name, const char* version, Object* object, // Class Symbol_table. Symbol_table::Symbol_table() - : size_(0), table_(), namepool_(), output_pool_(), forwarders_() + : size_(0), offset_(0), table_(), namepool_(), forwarders_() { } @@ -371,32 +372,58 @@ Symbol_table::add_from_object( } } -// Record the names of the local symbols for an object. +// Set the final values for all the symbols. Record the file offset +// OFF. Add their names to POOL. Return the new file offset. -template<int size, bool big_endian> -void -Symbol_table::add_local_symbol_names(Sized_object<size, big_endian>* object, - const elfcpp::Sym<size, big_endian>* syms, - size_t count, const char* sym_names, - size_t sym_name_size) +off_t +Symbol_table::finalize(off_t off, Stringpool* pool) { - const unsigned char* p = reinterpret_cast<const unsigned char*>(syms); - for (size_t i = 0; i < count; ++i) + if (this->size_ == 32) + return this->sized_finalize<32>(off, pool); + else + return this->sized_finalize<64>(off, pool); +} + +// Set the final value for all the symbols. + +template<int size> +off_t +Symbol_table::sized_finalize(off_t off, Stringpool* pool) +{ + off = (off + size - 1) & ~ (size - 1); + this->offset_ = off; + + const int sym_size = elfcpp::Elf_sizes<size>::sym_size; + Symbol_table_type::iterator p = this->table_.begin(); + while (p != this->table_.end()) { - elfcpp::Sym<size, big_endian> sym(p); + Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(p->second); - unsigned int st_name = sym.get_st_name(); - if (st_name >= sym_name_size) + // FIXME: Here we need to decide which symbols should go into + // the output file. + + const Object::Map_to_output* mo = + sym->object()->section_output_info(sym->shnum()); + + if (mo->output_section == NULL) { - fprintf(stderr, - _("%s: %s: bad local symbol name offset %u at %lu\n"), - program_name, object->name().c_str(), st_name, - static_cast<unsigned long>(i)); - gold_exit(false); + // We should be able to erase this symbol from the symbol + // table, but at least with gcc 4.0.2 + // std::unordered_map::erase doesn't appear to return the + // new iterator. + // p = this->table_.erase(p); + ++p; + } + else + { + sym->set_value(mo->output_section->address() + mo->offset); + pool->add(sym->name()); + ++p; + off += sym_size; } - - this->output_pool_.add(sym_names + st_name); } + + return off; } // Instantiate the templates we need. We could use the configure @@ -443,40 +470,4 @@ Symbol_table::add_from_object<64, false>( size_t sym_name_size, Symbol** sympointers); -template -void -Symbol_table::add_local_symbol_names<32, true>( - Sized_object<32, true>* object, - const elfcpp::Sym<32, true>* syms, - size_t count, - const char* sym_names, - size_t sym_name_size); - -template -void -Symbol_table::add_local_symbol_names<32, false>( - Sized_object<32, false>* object, - const elfcpp::Sym<32, false>* syms, - size_t count, - const char* sym_names, - size_t sym_name_size); - -template -void -Symbol_table::add_local_symbol_names<64, true>( - Sized_object<64, true>* object, - const elfcpp::Sym<64, true>* syms, - size_t count, - const char* sym_names, - size_t sym_name_size); - -template -void -Symbol_table::add_local_symbol_names<64, false>( - Sized_object<64, false>* object, - const elfcpp::Sym<64, false>* syms, - size_t count, - const char* sym_names, - size_t sym_name_size); - } // End namespace gold. diff --git a/gold/symtab.h b/gold/symtab.h index 09aff03..91a1f4d 100644 --- a/gold/symtab.h +++ b/gold/symtab.h @@ -182,6 +182,12 @@ class Sized_symbol : public Symbol symsize() const { return this->size_; } + // Set the symbol value. This is called when we store the final + // values of the symbols into the symbol table. + void + set_value(Value_type value) + { this->value_ = value; } + private: Sized_symbol(const Sized_symbol&); Sized_symbol& operator=(const Sized_symbol&); @@ -230,13 +236,12 @@ class Symbol_table const Sized_symbol<size>* get_sized_symbol(const Symbol*) const; - // Record the names of the local symbols for an object. - template<int size, bool big_endian> - void - add_local_symbol_names(Sized_object<size, big_endian>* object, - const elfcpp::Sym<size, big_endian>* syms, - size_t count, const char* sym_names, - size_t sym_name_size); + // Finalize the symbol table after we have set the final addresses + // of all the input sections. This sets the final symbol values and + // adds the names to *POOL. It records the file offset OFF, and + // returns the new file offset. + off_t + finalize(off_t, Stringpool*); private: Symbol_table(const Symbol_table&); @@ -276,6 +281,11 @@ class Symbol_table bool big_endian); #endif + // Finalize symbols specialized for size. + template<int size> + off_t + sized_finalize(off_t, Stringpool*); + // The type of the symbol hash table. typedef std::pair<const char*, const char*> Symbol_table_key; @@ -298,6 +308,10 @@ class Symbol_table // The size of the symbols in the symbol table (32 or 64). int size_; + // The file offset within the output symtab section where we should + // write the table. + off_t offset_; + // The symbol hash table. Symbol_table_type table_; @@ -305,11 +319,6 @@ class Symbol_table // Entries in the hash table point into this pool. Stringpool namepool_; - // A pool of symbol names to go into the output file. This is used - // for all symbols, global and local, but only the names of symbols - // which will definitely be output are added to this pool. - Stringpool output_pool_; - // Forwarding symbols. Unordered_map<Symbol*, Symbol*> forwarders_; }; diff --git a/gold/target.h b/gold/target.h index 161c75d..bba3d5a 100644 --- a/gold/target.h +++ b/gold/target.h @@ -13,6 +13,8 @@ #ifndef GOLD_TARGET_H #define GOLD_TARGET_H +#include <cassert> + #include "symtab.h" #include "elfcpp.h" @@ -33,43 +35,70 @@ class Target // return 32 or 64. int get_size() const - { return this->size_; } + { return this->pti_->size; } // Return whether this target is big-endian. bool is_big_endian() const - { return this->is_big_endian_; } + { return this->pti_->is_big_endian; } // Whether this target has a specific make_symbol function. bool has_make_symbol() const - { return this->has_make_symbol_; } + { return this->pti_->has_make_symbol; } // Whether this target has a specific resolve function. bool has_resolve() const - { return this->has_resolve_; } + { return this->pti_->has_resolve; } + + // Return the default address to use for the text segment. + uint64_t + text_segment_address() const + { return this->pti_->text_segment_address; } + + // Return the ABI specified page size. + uint64_t + abi_pagesize() const + { return this->pti_->abi_pagesize; } + + // Return the common page size used on actual systems. + uint64_t + common_pagesize() const + { return this->pti_->common_pagesize; } protected: - Target(int size, bool is_big_endian, bool has_make_symbol, bool has_resolve) - : size_(size), - is_big_endian_(is_big_endian), - has_make_symbol_(has_make_symbol), - has_resolve_(has_resolve) + // This struct holds the constant information for a child class. We + // use a struct to avoid the overhead of virtual function calls for + // simple information. + struct Target_info + { + // Address size (32 or 64). + int size; + // Whether the target is big endian. + bool is_big_endian; + // Whether this target has a specific make_symbol function. + bool has_make_symbol; + // Whether this target has a specific resolve function. + bool has_resolve; + // The default text segment address. + uint64_t text_segment_address; + // The ABI specified page size. + uint64_t abi_pagesize; + // The common page size used by actual implementations. + uint64_t common_pagesize; + }; + + Target(const Target_info* pti) + : pti_(pti) { } private: Target(const Target&); Target& operator=(const Target&); - // The target size. - int size_; - // Whether this target is big endian. - bool is_big_endian_; - // Whether this target has a special make_symbol function. - bool has_make_symbol_; - // Whether this target has a special resolve function. - bool has_resolve_; + // The target information. + const Target_info* pti_; }; // The abstract class for a specific size and endianness of target. @@ -96,9 +125,12 @@ class Sized_target : public Target { abort(); } protected: - Sized_target(bool has_make_symbol, bool has_resolve) - : Target(size, big_endian, has_make_symbol, has_resolve) - { } + Sized_target(const Target::Target_info* pti) + : Target(pti) + { + assert(pti->size == size); + assert(pti->is_big_endian ? big_endian : !big_endian); + } }; } // End namespace gold. |