diff options
-rw-r--r-- | gold/ChangeLog | 102 | ||||
-rw-r--r-- | gold/layout.cc | 9 | ||||
-rw-r--r-- | gold/layout.h | 5 | ||||
-rw-r--r-- | gold/merge.h | 26 | ||||
-rw-r--r-- | gold/object.cc | 2 | ||||
-rw-r--r-- | gold/object.h | 73 | ||||
-rw-r--r-- | gold/options.cc | 10 | ||||
-rw-r--r-- | gold/options.h | 15 | ||||
-rw-r--r-- | gold/output.cc | 341 | ||||
-rw-r--r-- | gold/output.h | 225 | ||||
-rw-r--r-- | gold/script-sections.cc | 17 | ||||
-rw-r--r-- | gold/symtab.cc | 87 | ||||
-rw-r--r-- | gold/symtab.h | 20 | ||||
-rw-r--r-- | gold/target.cc | 8 | ||||
-rw-r--r-- | gold/target.h | 20 |
15 files changed, 839 insertions, 121 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog index eb37d39..2b31fa6 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,105 @@ +2009-10-09 Doug Kwan <dougkwan@google.com> + + * layout.cc (Layout::make_output_section): Call target hook to make + ordinary output section. + (Layout::finalize): Adjust parameter list of call the + Target::may_relax(). + * layout.h (class Layout::section_list): New method. + * merge.h (Output_merge_base::entsize): Change visibility to public. + (Output_merge_base::is_string, Output_merge_base::do_is_string): + New methods. + (Output_merge_string::do_is_string): New method. + * object.cc (Sized_relobj::do_setup): renamed from + Sized_relobj::set_up. + * object.h (Sized_relobj::adjust_shndx, + Sized_relobj::initializ_input_to_output_maps, + Sized_relobj::free_input_to_output_maps): Change visibilities to + protected. + (Sized_relobj::setup): Virtualize. + (Sized_relobj::do_setup): New method declaration. + (Sized_relobj::invalidate_section_offset, + Sized_relobj::do_invalidate_section_offset): New method decfinitions. + (Sized_relobj::elf_file, Sized_relobj::local_values): New methods. + * options.cc (parse_int): New function. + * options.h (parse_int): New declaration. + (DEFINE_int): New macro. + (stub_group_size): New option. + * output.cc (Output_section::Output_section): Initialize memebers + merge_section_map_, merge_section_by_properties_map_, + relaxed_input_section_map_, is_relaxed_input_section_map_valid_. + (Output_section::add_input_section): Handled deferred code-fill + generation and remove an old comment. + (Output_section::add_relaxed_input_section): New method definition. + (Output_section::add_merge_input_section): Use merge section by + properties map to speed to search. Update merge section maps + as appropriate. + (Output_section::build_relaxation_map): New method definition. + (Output_section::convert_input_sections_in_list_to_relaxed_sections): + Same. + (Output_section::relax_input_section): Renamed to + Output_section::convert_input_sections_to_relaxed_sections and change + interface to take a vector of pointers to relaxed sections. + (Output_section::find_merge_section, + Output_section::find_relaxed_input_section): New method definitions. + (Output_section::is_input_address_mapped, + Output_section::output_offset, Output_section::output_address): + Use output section data maps to speed up searching. + (Output_section::find_starting_output_address): Add comments. + (Output_section::do_write, + Output_section::write_to_postprocessing_buffer): Do code-fill + generation as appropriate. + (Output_section::get_input_sections): Invalidate relaxed input section + map. + (Output_section::restore_states): Adjust type of checkpoint . + Invalidate relaxed input section map. + * output.h (Output_merge_base): New class declaration. + (Input_section_specifier): New class defintion. + (class Output_relaxed_input_section) Change base class to + Output_section_data_build. + (Output_relaxed_input_section::Output_relaxed_input_section): Adjust + base class initializer. + (Output_section::add_relaxed_input_section): New method declaration. + (Output_section::Input_section): Change visibility to protected. + (Output_section::Input_section::relobj, + Output_section::Input_section::shndx): Handle relaxed input sections. + Output_section::input_sections) Change visibility to protected. Also + define overload to return a non-const pointer. + (Output_section::Merge_section_properties): New class defintion. + (Output_section::Merge_section_by_properties_map, + Output_section::Output_section_data_by_input_section_map, + Output_section::Relaxation_map): New types. + (Output_section::relax_input_section): Rename method to + Output_section::convert_input_sections_to_relaxed_sections and change + interface to take a vector of relaxed section pointers. + (Output_section::find_merge_section, + Output_section::find_relaxed_input_section, + Output_section::build_relaxation_map, + Output_section::convert_input_sections_in_list_to_relaxed_sections): + New method declarations. + (Output_section::merge_section_map_ + Output_section::merge_section_by_properties_map_, + Output_section::relaxed_input_section_map_, + Output_section::is_relaxed_input_section_map_valid_, + Output_section::generate_code_fills_at_write_): New data members. + * script-sections.cc + (Output_section_element_input::set_section_addresses): Call + current_data_size and addralign methods of relaxed input sections. + (Orphan_output_section::set_section_addresses): Call current_data_size + and addralign methods of relaxed input sections. + * symtab.cc (Symbol_table::compute_final_value): Extract template + from the body of Symbol_table::sized_finalize_symbol. + (Symbol_table::sized_finalized_symbol): Call + Symbol_table::compute_final_value. + * symtab.h (Symbol_table::Compute_final_value_status): New enum type. + (Symbol_table::compute_final_value): New templated method declaration. + * target.cc (Target::do_make_output_section): New method defintion. + * target.h (Target::make_output_section): New method declaration. + (Target::relax): Add more parameters for input objects, symbol table + and layout. Adjust call to do_relax. + (Target::do_make_output_section): New method declaration. + (Target::do_relax): Add parameters for input objects, symbol table + and layout. + 2009-10-09 Andrew Pinski <andrew_pinski@playstation.sony.com> * pread.c: Include stdio.h. diff --git a/gold/layout.cc b/gold/layout.cc index e7d6377..0e26116 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -870,7 +870,11 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type, this->debug_info_->set_abbreviations(this->debug_abbrev_); } else - os = new Output_section(name, type, flags); + { + // FIXME: const_cast is ugly. + Target* target = const_cast<Target*>(¶meters->target()); + os = target->make_output_section(name, type, flags); + } parameters->target().new_output_section(os); @@ -1592,7 +1596,8 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab, &shndx); pass++; } - while (target->may_relax() && target->relax(pass)); + while (target->may_relax() + && target->relax(pass, input_objects, symtab, this)); // Set the file offsets of all the non-data sections we've seen so // far which don't have to wait for the input sections. We need diff --git a/gold/layout.h b/gold/layout.h index 8856125..675c658 100644 --- a/gold/layout.h +++ b/gold/layout.h @@ -602,6 +602,11 @@ class Layout this->script_output_section_data_list_.push_back(posd); } + // Return section list. + const Section_list& + section_list() const + { return this->section_list_; } + private: Layout(const Layout&); Layout& operator=(const Layout&); diff --git a/gold/merge.h b/gold/merge.h index fb6721d..345b115 100644 --- a/gold/merge.h +++ b/gold/merge.h @@ -219,6 +219,17 @@ class Output_merge_base : public Output_section_data : Output_section_data(addralign), merge_map_(), entsize_(entsize) { } + // Return the entry size. + uint64_t + entsize() const + { return this->entsize_; } + + // Whether this is a merge string section. This is only true of + // Output_merge_string. + bool + is_string() + { return this->do_is_string(); } + protected: // Return the output offset for an input offset. bool @@ -230,11 +241,6 @@ class Output_merge_base : public Output_section_data bool do_is_merge_section_for(const Relobj*, unsigned int shndx) const; - // Return the entry size. - uint64_t - entsize() const - { return this->entsize_; } - // Add a mapping from an OFFSET in input section SHNDX in object // OBJECT to an OUTPUT_OFFSET in the output section. OUTPUT_OFFSET // is the offset from the start of the merged data in the output @@ -246,6 +252,11 @@ class Output_merge_base : public Output_section_data this->merge_map_.add_mapping(object, shndx, offset, length, output_offset); } + // This may be overriden by the child class. + virtual bool + do_is_string() + { return false; } + private: // A mapping from input object/section/offset to offset in output // section. @@ -424,6 +435,11 @@ class Output_merge_string : public Output_merge_base clear_stringpool() { this->stringpool_.clear(); } + // Whether this is a merge string section. + virtual bool + do_is_string() + { return true; } + private: // The name of the string type, for stats. const char* diff --git a/gold/object.cc b/gold/object.cc index b8d9eb8..e09a71f 100644 --- a/gold/object.cc +++ b/gold/object.cc @@ -359,7 +359,7 @@ Sized_relobj<size, big_endian>::~Sized_relobj() template<int size, bool big_endian> void -Sized_relobj<size, big_endian>::setup() +Sized_relobj<size, big_endian>::do_setup() { const unsigned int shnum = this->elf_file_.shnum(); this->set_shnum(shnum); diff --git a/gold/object.h b/gold/object.h index bbc1a10..66f5dbb 100644 --- a/gold/object.h +++ b/gold/object.h @@ -1324,7 +1324,8 @@ class Sized_relobj : public Relobj // Set up the object file based on TARGET. void - setup(); + setup() + { this->do_setup(); } // Return the number of symbols. This is only valid after // Object::add_symbols has been called. @@ -1462,7 +1463,16 @@ class Sized_relobj : public Relobj Address map_to_kept_section(unsigned int shndx, bool* found) const; + // Make section offset invalid. This is needed for relaxation. + void + invalidate_section_offset(unsigned int shndx) + { this->do_invalidate_section_offset(shndx); } + protected: + // Set up. + virtual void + do_setup(); + // Read the symbols. void do_read_symbols(Read_symbols_data*); @@ -1596,6 +1606,48 @@ class Sized_relobj : public Relobj this->section_offsets_[shndx] = convert_types<Address, uint64_t>(off); } + // Set the offset of a section to invalid_address. + virtual void + do_invalidate_section_offset(unsigned int shndx) + { + gold_assert(shndx < this->section_offsets_.size()); + this->section_offsets_[shndx] = invalid_address; + } + + // Adjust a section index if necessary. + unsigned int + adjust_shndx(unsigned int shndx) + { + if (shndx >= elfcpp::SHN_LORESERVE) + shndx += this->elf_file_.large_shndx_offset(); + return shndx; + } + + // Initialize input to output maps for section symbols in merged + // sections. + void + initialize_input_to_output_maps(); + + // Free the input to output maps for section symbols in merged + // sections. + void + free_input_to_output_maps(); + + // Return symbol table section index. + unsigned int + symtab_shndx() const + { return this->symtab_shndx_; } + + // Allow a child class to access the ELF file. + elfcpp::Elf_file<size, big_endian, Object>* + elf_file() + { return &this->elf_file_; } + + // Allow a child class to access the local values. + Local_values* + local_values() + { return &this->local_values_; } + private: // For convenience. typedef Sized_relobj<size, big_endian> This; @@ -1618,15 +1670,6 @@ class Sized_relobj : public Relobj typedef std::map<unsigned int, Kept_comdat_section> Kept_comdat_section_table; - // Adjust a section index if necessary. - unsigned int - adjust_shndx(unsigned int shndx) - { - if (shndx >= elfcpp::SHN_LORESERVE) - shndx += this->elf_file_.large_shndx_offset(); - return shndx; - } - // Find the SHT_SYMTAB section, given the section headers. void find_symtab(const unsigned char* pshdrs); @@ -1742,16 +1785,6 @@ class Sized_relobj : public Relobj find_functions(const unsigned char* pshdrs, unsigned int shndx, Function_offsets*); - // Initialize input to output maps for section symbols in merged - // sections. - void - initialize_input_to_output_maps(); - - // Free the input to output maps for section symbols in merged - // sections. - void - free_input_to_output_maps(); - // Write out the local symbols. void write_local_symbols(Output_file*, diff --git a/gold/options.cc b/gold/options.cc index bf3eb55..1c0383a 100644 --- a/gold/options.cc +++ b/gold/options.cc @@ -195,6 +195,16 @@ parse_uint(const char* option_name, const char* arg, int* retval) } void +parse_int(const char* option_name, const char* arg, int* retval) +{ + char* endptr; + *retval = strtol(arg, &endptr, 0); + if (*endptr != '\0') + gold_fatal(_("%s: invalid option value (expected an integer): %s"), + option_name, arg); +} + +void parse_uint64(const char* option_name, const char* arg, uint64_t *retval) { char* endptr; diff --git a/gold/options.h b/gold/options.h index f590630..7266a96 100644 --- a/gold/options.h +++ b/gold/options.h @@ -83,6 +83,9 @@ extern void parse_bool(const char* option_name, const char* arg, bool* retval); extern void +parse_int(const char* option_name, const char* arg, int* retval); + +extern void parse_uint(const char* option_name, const char* arg, int* retval); extern void @@ -333,6 +336,12 @@ struct Struct_special : public Struct_var }; \ Struct_disable_##varname__ disable_##varname__##_initializer_ +#define DEFINE_int(varname__, dashes__, shortname__, default_value__, \ + helpstring__, helparg__) \ + DEFINE_var(varname__, dashes__, shortname__, default_value__, \ + #default_value__, helpstring__, helparg__, false, \ + int, int, options::parse_int) + #define DEFINE_uint(varname__, dashes__, shortname__, default_value__, \ helpstring__, helparg__) \ DEFINE_var(varname__, dashes__, shortname__, default_value__, \ @@ -802,6 +811,12 @@ class General_options DEFINE_bool(strip_lto_sections, options::TWO_DASHES, '\0', true, N_("Strip LTO intermediate code sections"), NULL); + DEFINE_int(stub_group_size, options::TWO_DASHES , '\0', 1, + N_("(ARM only) The maximum distance from instructions in a group " + "of sections to their stubs. Negative values mean stubs " + "are always after the group. 1 means using default size.\n"), + N_("SIZE")); + DEFINE_bool(no_keep_memory, options::TWO_DASHES, '\0', false, N_("Use less memory and more disk I/O " "(included only for compatibility with GNU ld)"), NULL); diff --git a/gold/output.cc b/gold/output.cc index e3b1171..7d869b3 100644 --- a/gold/output.cc +++ b/gold/output.cc @@ -1801,7 +1801,12 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type, is_small_section_(false), is_large_section_(false), tls_offset_(0), - checkpoint_(NULL) + checkpoint_(NULL), + merge_section_map_(), + merge_section_by_properties_map_(), + relaxed_input_section_map_(), + is_relaxed_input_section_map_valid_(true), + generate_code_fills_at_write_(false) { // An unallocated section has no address. Forcing this means that // we don't need special treatment for symbols defined in debug @@ -1892,7 +1897,21 @@ Output_section::add_input_section(Sized_relobj<size, big_endian>* object, off_t aligned_offset_in_section = align_address(offset_in_section, addralign); + // Determine if we want to delay code-fill generation until the output + // section is written. When the target is relaxing, we want to delay fill + // generating to avoid adjusting them during relaxation. + if (!this->generate_code_fills_at_write_ + && !have_sections_script + && (sh_flags & elfcpp::SHF_EXECINSTR) != 0 + && parameters->target().has_code_fill() + && parameters->target().may_relax()) + { + gold_assert(this->fills_.empty()); + this->generate_code_fills_at_write_ = true; + } + if (aligned_offset_in_section > offset_in_section + && !this->generate_code_fills_at_write_ && !have_sections_script && (sh_flags & elfcpp::SHF_EXECINSTR) != 0 && parameters->target().has_code_fill()) @@ -1905,8 +1924,6 @@ Output_section::add_input_section(Sized_relobj<size, big_endian>* object, this->fills_.push_back(Fill(offset_in_section, fill_len)); else { - // FIXME: When relaxing, the size needs to adjust to - // maintain a constant alignment. std::string fill_data(parameters->target().code_fill(fill_len)); Output_data_const* odc = new Output_data_const(fill_data, 1); this->input_sections_.push_back(Input_section(odc)); @@ -1951,6 +1968,31 @@ Output_section::add_output_section_data(Output_section_data* posd) } } +// Add a relaxed input section. + +void +Output_section::add_relaxed_input_section(Output_relaxed_input_section* poris) +{ + Input_section inp(poris); + this->add_output_section_data(&inp); + if (this->is_relaxed_input_section_map_valid_) + { + Input_section_specifier iss(poris->relobj(), poris->shndx()); + this->relaxed_input_section_map_[iss] = poris; + } + + // For a relaxed section, we use the current data size. Linker scripts + // get all the input sections, including relaxed one from an output + // section and add them back to them same output section to compute the + // output section size. If we do not account for sizes of relaxed input + // sections, an output section would be incorrectly sized. + off_t offset_in_section = this->current_data_size_for_child(); + off_t aligned_offset_in_section = align_address(offset_in_section, + poris->addralign()); + this->set_current_data_size_for_child(aligned_offset_in_section + + poris->current_data_size()); +} + // Add arbitrary data to an output section by Input_section. void @@ -1995,73 +2037,151 @@ Output_section::add_merge_input_section(Relobj* object, unsigned int shndx, // We cannot restore merged input section states. gold_assert(this->checkpoint_ == NULL); - Input_section_list::iterator p; - for (p = this->input_sections_.begin(); - p != this->input_sections_.end(); - ++p) - if (p->is_merge_section(is_string, entsize, addralign)) - { - p->add_input_section(object, shndx); - return true; - } + // Look up merge sections by required properties. + Merge_section_properties msp(is_string, entsize, addralign); + Merge_section_by_properties_map::const_iterator p = + this->merge_section_by_properties_map_.find(msp); + if (p != this->merge_section_by_properties_map_.end()) + { + Output_merge_base* merge_section = p->second; + merge_section->add_input_section(object, shndx); + gold_assert(merge_section->is_string() == is_string + && merge_section->entsize() == entsize + && merge_section->addralign() == addralign); + + // Link input section to found merge section. + Input_section_specifier iss(object, shndx); + this->merge_section_map_[iss] = merge_section; + return true; + } // We handle the actual constant merging in Output_merge_data or // Output_merge_string_data. - Output_section_data* posd; + Output_merge_base* pomb; if (!is_string) - posd = new Output_merge_data(entsize, addralign); + pomb = new Output_merge_data(entsize, addralign); else { switch (entsize) { case 1: - posd = new Output_merge_string<char>(addralign); + pomb = new Output_merge_string<char>(addralign); break; case 2: - posd = new Output_merge_string<uint16_t>(addralign); + pomb = new Output_merge_string<uint16_t>(addralign); break; case 4: - posd = new Output_merge_string<uint32_t>(addralign); + pomb = new Output_merge_string<uint32_t>(addralign); break; default: return false; } } - this->add_output_merge_section(posd, is_string, entsize); - posd->add_input_section(object, shndx); + // Add new merge section to this output section and link merge section + // properties to new merge section in map. + this->add_output_merge_section(pomb, is_string, entsize); + this->merge_section_by_properties_map_[msp] = pomb; + + // Add input section to new merge section and link input section to new + // merge section in map. + pomb->add_input_section(object, shndx); + Input_section_specifier iss(object, shndx); + this->merge_section_map_[iss] = pomb; return true; } -// Relax an existing input section. +// Build a relaxation map to speed up relaxation of existing input sections. +// Look up to the first LIMIT elements in INPUT_SECTIONS. + void -Output_section::relax_input_section(Output_relaxed_input_section *psection) +Output_section::build_relaxation_map( + const Input_section_list& input_sections, + size_t limit, + Relaxation_map* relaxation_map) const { - Relobj* relobj = psection->relobj(); - unsigned int shndx = psection->shndx(); + for (size_t i = 0; i < limit; ++i) + { + const Input_section& is(input_sections[i]); + if (is.is_input_section() || is.is_relaxed_input_section()) + { + Input_section_specifier iss(is.relobj(), is.shndx()); + (*relaxation_map)[iss] = i; + } + } +} + +// Convert regular input sections in INPUT_SECTIONS into relaxed input +// sections in RELAXED_SECTIONS. MAP is a prebuilt map from input section +// specifier to indices of INPUT_SECTIONS. + +void +Output_section::convert_input_sections_in_list_to_relaxed_sections( + const std::vector<Output_relaxed_input_section*>& relaxed_sections, + const Relaxation_map& map, + Input_section_list* input_sections) +{ + for (size_t i = 0; i < relaxed_sections.size(); ++i) + { + Output_relaxed_input_section* poris = relaxed_sections[i]; + Input_section_specifier iss(poris->relobj(), poris->shndx()); + Relaxation_map::const_iterator p = map.find(iss); + gold_assert(p != map.end()); + gold_assert((*input_sections)[p->second].is_input_section()); + (*input_sections)[p->second] = Input_section(poris); + } +} + +// Convert regular input sections into relaxed input sections. RELAXED_SECTIONS +// is a vector of pointers to Output_relaxed_input_section or its derived +// classes. The relaxed sections must correspond to existing input sections. +void +Output_section::convert_input_sections_to_relaxed_sections( + const std::vector<Output_relaxed_input_section*>& relaxed_sections) +{ gold_assert(parameters->target().may_relax()); - // This is not very efficient if we a going to relax a number of sections - // in an Output_section with lot of Input_sections. - for (Input_section_list::iterator p = this->input_sections_.begin(); - p != this->input_sections_.end(); - ++p) + // We want to make sure that restore_states does not undo the effect of + // this. If there is no checkpoint active, just search the current + // input section list and replace the sections there. If there is + // a checkpoint, also replace the sections there. + + // By default, we look at the whole list. + size_t limit = this->input_sections_.size(); + + if (this->checkpoint_ != NULL) { - if (p->is_input_section()) + // Replace input sections with relaxed input section in the saved + // copy of the input section list. + if (this->checkpoint_->input_sections_saved()) { - if (p->relobj() == relobj && p->shndx() == shndx) - { - gold_assert(p->addralign() == psection->addralign()); - *p = Input_section(psection); - return; - } + Relaxation_map map; + this->build_relaxation_map( + *(this->checkpoint_->input_sections()), + this->checkpoint_->input_sections()->size(), + &map); + this->convert_input_sections_in_list_to_relaxed_sections( + relaxed_sections, + map, + this->checkpoint_->input_sections()); + } + else + { + // We have not copied the input section list yet. Instead, just + // look at the portion that would be saved. + limit = this->checkpoint_->input_sections_size(); } - else if (p->is_relaxed_input_section()) - gold_assert(p->relobj() != relobj || p->shndx() != shndx); - } + + // Convert input sections in input_section_list. + Relaxation_map map; + this->build_relaxation_map(this->input_sections_, limit, &map); + this->convert_input_sections_in_list_to_relaxed_sections( + relaxed_sections, + map, + &this->input_sections_); } // Update the output section flags based on input section flags. @@ -2082,6 +2202,60 @@ Output_section::update_flags_for_input_section(elfcpp::Elf_Xword flags) | elfcpp::SHF_EXECINSTR)); } +// Find the merge section into which an input section with index SHNDX in +// OBJECT has been added. Return NULL if none found. + +Output_section_data* +Output_section::find_merge_section(const Relobj* object, + unsigned int shndx) const +{ + Input_section_specifier iss(object, shndx); + Output_section_data_by_input_section_map::const_iterator p = + this->merge_section_map_.find(iss); + if (p != this->merge_section_map_.end()) + { + Output_section_data* posd = p->second; + gold_assert(posd->is_merge_section_for(object, shndx)); + return posd; + } + else + return NULL; +} + +// Find an relaxed input section corresponding to an input section +// in OBJECT with index SHNDX. + +const Output_section_data* +Output_section::find_relaxed_input_section(const Relobj* object, + unsigned int shndx) const +{ + // Be careful that the map may not be valid due to input section export + // to scripts or a check-point restore. + if (!this->is_relaxed_input_section_map_valid_) + { + // Rebuild the map as needed. + this->relaxed_input_section_map_.clear(); + for (Input_section_list::const_iterator p = this->input_sections_.begin(); + p != this->input_sections_.end(); + ++p) + if (p->is_relaxed_input_section()) + { + Input_section_specifier iss(p->relobj(), p->shndx()); + this->relaxed_input_section_map_[iss] = + p->relaxed_input_section(); + } + this->is_relaxed_input_section_map_valid_ = true; + } + + Input_section_specifier iss(object, shndx); + Output_section_data_by_input_section_map::const_iterator p = + this->relaxed_input_section_map_.find(iss); + if (p != this->relaxed_input_section_map_.end()) + return p->second; + else + return NULL; +} + // Given an address OFFSET relative to the start of input section // SHNDX in OBJECT, return whether this address is being included in // the final link. This should only be called if SHNDX in OBJECT has @@ -2092,6 +2266,20 @@ Output_section::is_input_address_mapped(const Relobj* object, unsigned int shndx, off_t offset) const { + // Look at the Output_section_data_maps first. + const Output_section_data* posd = this->find_merge_section(object, shndx); + if (posd == NULL) + posd = this->find_relaxed_input_section(object, shndx); + + if (posd != NULL) + { + section_offset_type output_offset; + bool found = posd->output_offset(object, shndx, offset, &output_offset); + gold_assert(found); + return output_offset != -1; + } + + // Fall back to the slow look-up. for (Input_section_list::const_iterator p = this->input_sections_.begin(); p != this->input_sections_.end(); ++p) @@ -2116,9 +2304,23 @@ section_offset_type Output_section::output_offset(const Relobj* object, unsigned int shndx, section_offset_type offset) const { - // This can only be called meaningfully when layout is complete. - gold_assert(Output_data::is_layout_complete()); + // This can only be called meaningfully when we know the data size + // of this. + gold_assert(this->is_data_size_valid()); + // Look at the Output_section_data_maps first. + const Output_section_data* posd = this->find_merge_section(object, shndx); + if (posd == NULL) + posd = this->find_relaxed_input_section(object, shndx); + if (posd != NULL) + { + section_offset_type output_offset; + bool found = posd->output_offset(object, shndx, offset, &output_offset); + gold_assert(found); + return output_offset; + } + + // Fall back to the slow look-up. for (Input_section_list::const_iterator p = this->input_sections_.begin(); p != this->input_sections_.end(); ++p) @@ -2138,6 +2340,20 @@ Output_section::output_address(const Relobj* object, unsigned int shndx, off_t offset) const { uint64_t addr = this->address() + this->first_input_offset_; + + // Look at the Output_section_data_maps first. + const Output_section_data* posd = this->find_merge_section(object, shndx); + if (posd == NULL) + posd = this->find_relaxed_input_section(object, shndx); + if (posd != NULL && posd->is_address_valid()) + { + section_offset_type output_offset; + bool found = posd->output_offset(object, shndx, offset, &output_offset); + gold_assert(found); + return posd->address() + output_offset; + } + + // Fall back to the slow look-up. for (Input_section_list::const_iterator p = this->input_sections_.begin(); p != this->input_sections_.end(); ++p) @@ -2169,6 +2385,9 @@ Output_section::find_starting_output_address(const Relobj* object, unsigned int shndx, uint64_t* paddr) const { + // FIXME: This becomes a bottle-neck if we have many relaxed sections. + // Looking up the merge section map does not always work as we sometimes + // find a merge section without its address set. uint64_t addr = this->address() + this->first_input_offset_; for (Input_section_list::const_iterator p = this->input_sections_.begin(); p != this->input_sections_.end(); @@ -2532,6 +2751,9 @@ Output_section::do_write(Output_file* of) { gold_assert(!this->requires_postprocessing()); + // If the target performs relaxation, we delay filler generation until now. + gold_assert(!this->generate_code_fills_at_write_ || this->fills_.empty()); + off_t output_section_file_offset = this->offset(); for (Fill_list::iterator p = this->fills_.begin(); p != this->fills_.end(); @@ -2542,10 +2764,22 @@ Output_section::do_write(Output_file* of) fill_data.data(), fill_data.size()); } + off_t off = this->offset() + this->first_input_offset_; for (Input_section_list::iterator p = this->input_sections_.begin(); p != this->input_sections_.end(); ++p) - p->write(of); + { + off_t aligned_off = align_address(off, p->addralign()); + if (this->generate_code_fills_at_write_ && (off != aligned_off)) + { + size_t fill_len = aligned_off - off; + std::string fill_data(parameters->target().code_fill(fill_len)); + of->write(off, fill_data.data(), fill_data.size()); + } + + p->write(of); + off = aligned_off + p->data_size(); + } } // If a section requires postprocessing, create the buffer to use. @@ -2586,6 +2820,9 @@ Output_section::write_to_postprocessing_buffer() { gold_assert(this->requires_postprocessing()); + // If the target performs relaxation, we delay filler generation until now. + gold_assert(!this->generate_code_fills_at_write_ || this->fills_.empty()); + unsigned char* buffer = this->postprocessing_buffer(); for (Fill_list::iterator p = this->fills_.begin(); p != this->fills_.end(); @@ -2601,9 +2838,16 @@ Output_section::write_to_postprocessing_buffer() p != this->input_sections_.end(); ++p) { - off = align_address(off, p->addralign()); - p->write_to_buffer(buffer + off); - off += p->data_size(); + off_t aligned_off = align_address(off, p->addralign()); + if (this->generate_code_fills_at_write_ && (off != aligned_off)) + { + size_t fill_len = aligned_off - off; + std::string fill_data(parameters->target().code_fill(fill_len)); + memcpy(buffer + off, fill_data.data(), fill_data.size()); + } + + p->write_to_buffer(buffer + aligned_off); + off = aligned_off + p->data_size(); } } @@ -2627,6 +2871,9 @@ Output_section::get_input_sections( && !this->checkpoint_->input_sections_saved()) this->checkpoint_->save_input_sections(); + // Invalidate the relaxed input section map. + this->is_relaxed_input_section_map_valid_ = false; + uint64_t orig_address = address; address = align_address(address, this->addralign()); @@ -2738,11 +2985,15 @@ Output_section::restore_states() // extremely large output with hundreads of thousands of input // objects. We may need to re-think how we should pass sections // to scripts. - this->input_sections_ = checkpoint->input_sections(); + this->input_sections_ = *checkpoint->input_sections(); } this->attached_input_sections_are_sorted_ = checkpoint->attached_input_sections_are_sorted(); + + // Simply invalidate the relaxed input section map since we do not keep + // track of it. + this->is_relaxed_input_section_map_valid_ = false; } // Print to the map file. diff --git a/gold/output.h b/gold/output.h index 377864c..bc10950 100644 --- a/gold/output.h +++ b/gold/output.h @@ -38,6 +38,7 @@ class General_options; class Object; class Symbol; class Output_file; +class Output_merge_base; class Output_section; class Relocatable_relocs; class Target; @@ -46,6 +47,71 @@ class Sized_target; template<int size, bool big_endian> class Sized_relobj; +// This class specifies an input section. It is used as a key type +// for maps. + +class Input_section_specifier +{ + public: + Input_section_specifier(const Relobj* relobj, unsigned int shndx) + : relobj_(relobj), shndx_(shndx) + { } + + // Return Relobj of this. + const Relobj* + relobj() const + { return this->relobj_; } + + // Return section index of this. + unsigned int + shndx() const + { return this->shndx_; } + + // Whether this equals to another specifier ISS. + bool + eq(const Input_section_specifier& iss) const + { return this->relobj_ == iss.relobj_ && this->shndx_ == iss.shndx_; } + + // Compute a hash value of this. + size_t + hash_value() const + { return this->string_hash(this->relobj_->name().c_str()) ^ this->shndx_; } + + // Functors for containers. + struct equal_to + { + bool + operator()(const Input_section_specifier& iss1, + const Input_section_specifier& iss2) const + { return iss1.eq(iss2); } + }; + + struct hash + { + size_t + operator()(const Input_section_specifier& iss) const + { return iss.hash_value(); } + }; + + private: + // For portability, we use our own string hash function instead of assuming + // __gnu_cxx::hash or std::tr1::hash is available. This is the same hash + // function used in Stringpool_template::string_hash. + static size_t + string_hash(const char* s) + { + size_t h = 5381; + while (*s != '\0') + h = h * 33 + *s++; + return h; + } + + // An object. + const Relobj* relobj_; + // A section index. + unsigned int shndx_; +}; + // An abtract class for data which has to go into the output file. class Output_data @@ -1987,7 +2053,7 @@ class Output_symtab_xindex : public Output_section_data }; // A relaxed input section. -class Output_relaxed_input_section : public Output_section_data +class Output_relaxed_input_section : public Output_section_data_build { public: // We would like to call relobj->section_addralign(shndx) to get the @@ -1995,7 +2061,7 @@ class Output_relaxed_input_section : public Output_section_data // are repsonsible for ensuring that. Output_relaxed_input_section(Relobj* relobj, unsigned int shndx, uint64_t addralign) - : Output_section_data(addralign), relobj_(relobj), shndx_(shndx) + : Output_section_data_build(addralign), relobj_(relobj), shndx_(shndx) { } // Return the Relobj of this relaxed input section. @@ -2041,6 +2107,10 @@ class Output_section : public Output_data void add_output_section_data(Output_section_data* posd); + // Add a relaxed input section PORIS to this output section. + void + add_relaxed_input_section(Output_relaxed_input_section* poris); + // Return the section name. const char* name() const @@ -2510,6 +2580,11 @@ class Output_section : public Output_data void restore_states(); + // Convert existing input sections to relaxed input sections. + void + convert_input_sections_to_relaxed_sections( + const std::vector<Output_relaxed_input_section*>& sections); + // Print merge statistics to stderr. void print_merge_stats(); @@ -2625,7 +2700,6 @@ class Output_section : public Output_data void write_to_postprocessing_buffer(); - private: // In some cases we need to keep a list of the input sections // associated with this output section. We only need the list if we // might have to change the offsets of the input section within the @@ -2741,16 +2815,24 @@ class Output_section : public Output_data Relobj* relobj() const { - gold_assert(this->is_input_section()); - return this->u2_.object; + if (this->is_input_section()) + return this->u2_.object; + else if (this->is_relaxed_input_section()) + return this->u2_.poris->relobj(); + else + gold_unreachable(); } // Return the input section index for an input section. unsigned int shndx() const { - gold_assert(this->is_input_section()); - return this->shndx_; + if (this->is_input_section()) + return this->shndx_; + else if (this->is_relaxed_input_section()) + return this->u2_.poris->shndx(); + else + gold_unreachable(); } // For non-input-sections, return the associated Output_section_data @@ -2891,6 +2973,12 @@ class Output_section : public Output_data typedef std::vector<Input_section> Input_section_list; + // Allow a child class to access the input sections. + const Input_section_list& + input_sections() const + { return this->input_sections_; } + + private: // We only save enough information to undo the effects of section layout. class Checkpoint_output_section { @@ -2921,9 +3009,9 @@ class Output_section : public Output_data { return this->flags_; } // Return a reference to the input section list copy. - const Input_section_list& - input_sections() const - { return this->input_sections_copy_; } + Input_section_list* + input_sections() + { return &this->input_sections_copy_; } // Return the size of input_sections at the time when checkpoint is // taken. @@ -2974,7 +3062,6 @@ class Output_section : public Output_data bool attached_input_sections_are_sorted_; }; - private: // This class is used to sort the input sections. class Input_section_sort_entry; @@ -3018,6 +3105,82 @@ class Output_section : public Output_data typedef std::vector<Fill> Fill_list; + // This class describes properties of merge data sections. It is used + // as a key type for maps. + class Merge_section_properties + { + public: + Merge_section_properties(bool is_string, uint64_t entsize, + uint64_t addralign) + : is_string_(is_string), entsize_(entsize), addralign_(addralign) + { } + + // Whether this equals to another Merge_section_properties MSP. + bool + eq(const Merge_section_properties& msp) const + { + return ((this->is_string_ == msp.is_string_) + && (this->entsize_ == msp.entsize_) + && (this->addralign_ == msp.addralign_)); + } + + // Compute a hash value for this using 64-bit FNV-1a hash. + size_t + hash_value() const + { + uint64_t h = 14695981039346656037ULL; // FNV offset basis. + uint64_t prime = 1099511628211ULL; + h = (h ^ static_cast<uint64_t>(this->is_string_)) * prime; + h = (h ^ static_cast<uint64_t>(this->entsize_)) * prime; + h = (h ^ static_cast<uint64_t>(this->addralign_)) * prime; + return h; + } + + // Functors for associative containers. + struct equal_to + { + bool + operator()(const Merge_section_properties& msp1, + const Merge_section_properties& msp2) const + { return msp1.eq(msp2); } + }; + + struct hash + { + size_t + operator()(const Merge_section_properties& msp) const + { return msp.hash_value(); } + }; + + private: + // Whether this merge data section is for strings. + bool is_string_; + // Entsize of this merge data section. + uint64_t entsize_; + // Address alignment. + uint64_t addralign_; + }; + + // Map that link Merge_section_properties to Output_merge_base. + typedef Unordered_map<Merge_section_properties, Output_merge_base*, + Merge_section_properties::hash, + Merge_section_properties::equal_to> + Merge_section_by_properties_map; + + // Map that link Input_section_specifier to Output_section_data. + typedef Unordered_map<Input_section_specifier, Output_section_data*, + Input_section_specifier::hash, + Input_section_specifier::equal_to> + Output_section_data_by_input_section_map; + + // Map used during relaxation of existing sections. This map + // an input section specifier to an input section list index. + // We assume that Input_section_list is a vector. + typedef Unordered_map<Input_section_specifier, size_t, + Input_section_specifier::hash, + Input_section_specifier::equal_to> + Relaxation_map; + // Add a new output section by Input_section. void add_output_section_data(Input_section*); @@ -3036,14 +3199,34 @@ class Output_section : public Output_data add_output_merge_section(Output_section_data* posd, bool is_string, uint64_t entsize); - // Relax an existing input section. - void - relax_input_section(Output_relaxed_input_section*); - // Sort the attached input sections. void sort_attached_input_sections(); + // Find the merge section into which an input section with index SHNDX in + // OBJECT has been added. Return NULL if none found. + Output_section_data* + find_merge_section(const Relobj* object, unsigned int shndx) const; + + // Find a relaxed input section to an input section in OBJECT + // with index SHNDX. Return NULL if none is found. + const Output_section_data* + find_relaxed_input_section(const Relobj* object, unsigned int shndx) const; + + // Build a relaxation map. + void + build_relaxation_map( + const Input_section_list& input_sections, + size_t limit, + Relaxation_map* map) const; + + // Convert input sections in an input section list into relaxed sections. + void + convert_input_sections_in_list_to_relaxed_sections( + const std::vector<Output_relaxed_input_section*>& relaxed_sections, + const Relaxation_map& map, + Input_section_list* input_sections); + // Most of these fields are only valid after layout. // The name of the section. This will point into a Stringpool. @@ -3149,6 +3332,18 @@ class Output_section : public Output_data uint64_t tls_offset_; // Saved checkpoint. Checkpoint_output_section* checkpoint_; + // Map from input sections to merge sections. + Output_section_data_by_input_section_map merge_section_map_; + // Map from merge section properties to merge_sections; + Merge_section_by_properties_map merge_section_by_properties_map_; + // Map from input sections to relaxed input sections. This is mutable + // beacause it is udpated lazily. We may need to update it in a + // const qualified method. + mutable Output_section_data_by_input_section_map relaxed_input_section_map_; + // Whether relaxed_input_section_map_ is valid. + mutable bool is_relaxed_input_section_map_valid_; + // Whether code-fills are generated at write. + bool generate_code_fills_at_write_; }; // An output segment. PT_LOAD segments are built from collections of diff --git a/gold/script-sections.cc b/gold/script-sections.cc index d6e2b72..15d22d6 100644 --- a/gold/script-sections.cc +++ b/gold/script-sections.cc @@ -1325,10 +1325,17 @@ Output_section_element_input::set_section_addresses( isi.set_section_name(relobj->section_name(shndx)); if (p->is_relaxed_input_section()) - isi.set_size(p->relaxed_input_section()->data_size()); + { + // We use current data size because relxed section sizes may not + // have finalized yet. + isi.set_size(p->relaxed_input_section()->current_data_size()); + isi.set_addralign(p->relaxed_input_section()->addralign()); + } else - isi.set_size(relobj->section_size(shndx)); - isi.set_addralign(relobj->section_addralign(shndx)); + { + isi.set_size(relobj->section_size(shndx)); + isi.set_addralign(relobj->section_addralign(shndx)); + } } if (!this->match_file_name(relobj->name().c_str())) @@ -2292,7 +2299,9 @@ Orphan_output_section::set_section_addresses(Symbol_table*, Layout*, Task_lock_obj<Object> tl(task, p->relobj()); addralign = p->relobj()->section_addralign(p->shndx()); if (p->is_relaxed_input_section()) - size = p->relaxed_input_section()->data_size(); + // We use current data size because relxed section sizes may not + // have finalized yet. + size = p->relaxed_input_section()->current_data_size(); else size = p->relobj()->section_size(p->shndx()); } diff --git a/gold/symtab.cc b/gold/symtab.cc index 562e1fc..8a9e6f1 100644 --- a/gold/symtab.cc +++ b/gold/symtab.cc @@ -2355,30 +2355,17 @@ Symbol_table::sized_finalize(off_t off, Stringpool* pool, return off; } -// Finalize the symbol SYM. This returns true if the symbol should be -// added to the symbol table, false otherwise. +// Compute the final value of SYM and store status in location PSTATUS. +// During relaxation, this may be called multiple times for a symbol to +// compute its would-be final value in each relaxation pass. template<int size> -bool -Symbol_table::sized_finalize_symbol(Symbol* unsized_sym) +typename Sized_symbol<size>::Value_type +Symbol_table::compute_final_value( + const Sized_symbol<size>* sym, + Compute_final_value_status* pstatus) const { typedef typename Sized_symbol<size>::Value_type Value_type; - - Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(unsized_sym); - - // The default version of a symbol may appear twice in the symbol - // table. We only need to finalize it once. - if (sym->has_symtab_index()) - return false; - - if (!sym->in_reg()) - { - gold_assert(!sym->has_symtab_index()); - sym->set_symtab_index(-1U); - gold_assert(sym->dynsym_index() == -1U); - return false; - } - Value_type value; switch (sym->source()) @@ -2392,9 +2379,8 @@ Symbol_table::sized_finalize_symbol(Symbol* unsized_sym) && shndx != elfcpp::SHN_ABS && !Symbol::is_common_shndx(shndx)) { - gold_error(_("%s: unsupported symbol section 0x%x"), - sym->demangled_name().c_str(), shndx); - shndx = elfcpp::SHN_UNDEF; + *pstatus = CFVS_UNSUPPORTED_SYMBOL_SECTION; + return 0; } Object* symobj = sym->object(); @@ -2435,12 +2421,12 @@ Symbol_table::sized_finalize_symbol(Symbol* unsized_sym) if (os == NULL) { - sym->set_symtab_index(-1U); bool static_or_reloc = (parameters->doing_static_link() || parameters->options().relocatable()); gold_assert(static_or_reloc || sym->dynsym_index() == -1U); - return false; + *pstatus = CFVS_NO_OUTPUT_SECTION; + return 0; } if (secoff64 == -1ULL) @@ -2513,6 +2499,57 @@ Symbol_table::sized_finalize_symbol(Symbol* unsized_sym) gold_unreachable(); } + *pstatus = CFVS_OK; + return value; +} + +// Finalize the symbol SYM. This returns true if the symbol should be +// added to the symbol table, false otherwise. + +template<int size> +bool +Symbol_table::sized_finalize_symbol(Symbol* unsized_sym) +{ + typedef typename Sized_symbol<size>::Value_type Value_type; + + Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(unsized_sym); + + // The default version of a symbol may appear twice in the symbol + // table. We only need to finalize it once. + if (sym->has_symtab_index()) + return false; + + if (!sym->in_reg()) + { + gold_assert(!sym->has_symtab_index()); + sym->set_symtab_index(-1U); + gold_assert(sym->dynsym_index() == -1U); + return false; + } + + // Compute final symbol value. + Compute_final_value_status status; + Value_type value = this->compute_final_value(sym, &status); + + switch (status) + { + case CFVS_OK: + break; + case CFVS_UNSUPPORTED_SYMBOL_SECTION: + { + bool is_ordinary; + unsigned int shndx = sym->shndx(&is_ordinary); + gold_error(_("%s: unsupported symbol section 0x%x"), + sym->demangled_name().c_str(), shndx); + } + break; + case CFVS_NO_OUTPUT_SECTION: + sym->set_symtab_index(-1U); + return false; + default: + gold_unreachable(); + } + sym->set_value(value); if (parameters->options().strip_all() diff --git a/gold/symtab.h b/gold/symtab.h index 8dd7a72..148634e 100644 --- a/gold/symtab.h +++ b/gold/symtab.h @@ -1377,6 +1377,26 @@ class Symbol_table finalize(off_t off, off_t dynoff, size_t dyn_global_index, size_t dyncount, Stringpool* pool, unsigned int *plocal_symcount); + // Status code of Symbol_table::compute_final_value. + enum Compute_final_value_status + { + // No error. + CFVS_OK, + // Unspported symbol section. + CFVS_UNSUPPORTED_SYMBOL_SECTION, + // No output section. + CFVS_NO_OUTPUT_SECTION + }; + + // Compute the final value of SYM and store status in location PSTATUS. + // During relaxation, this may be called multiple times for a symbol to + // compute its would-be final value in each relaxation pass. + + template<int size> + typename Sized_symbol<size>::Value_type + compute_final_value(const Sized_symbol<size>* sym, + Compute_final_value_status* pstatus) const; + // Write out the global symbols. void write_globals(const Stringpool*, const Stringpool*, diff --git a/gold/target.cc b/gold/target.cc index b129b59..0ddc13d 100644 --- a/gold/target.cc +++ b/gold/target.cc @@ -23,6 +23,7 @@ #include "gold.h" #include "target.h" #include "dynobj.h" +#include "output.h" #include "elfcpp.h" namespace gold @@ -136,6 +137,13 @@ Target::do_make_elf_object(const std::string& name, Input_file* input_file, } #endif +Output_section* +Target::do_make_output_section(const char* name, elfcpp::Elf_Word type, + elfcpp::Elf_Xword flags) +{ + return new Output_section(name, type, flags); +} + // Default conversion for -fsplit-stack is to give an error. void diff --git a/gold/target.h b/gold/target.h index 68d89dc..67397c3 100644 --- a/gold/target.h +++ b/gold/target.h @@ -242,6 +242,12 @@ class Target off_t offset, const elfcpp::Ehdr<size, big_endian>& ehdr) { return this->do_make_elf_object(name, input_file, offset, ehdr); } + // Make an output section. + Output_section* + make_output_section(const char* name, elfcpp::Elf_Word type, + elfcpp::Elf_Xword flags) + { return this->do_make_output_section(name, type, flags); } + // Return true if target wants to perform relaxation. bool may_relax() const @@ -255,14 +261,15 @@ class Target // Perform a relaxation pass. Return true if layout may be changed. bool - relax(int pass) + relax(int pass, const Input_objects* input_objects, Symbol_table* symtab, + Layout* layout) { // Run the dummy relaxation pass twice if relaxation debugging is enabled. if (is_debugging_enabled(DEBUG_RELAXATION)) return pass < 2; - return this->do_relax(pass); - } + return this->do_relax(pass, input_objects, symtab, layout); + } protected: // This struct holds the constant information for a child class. We @@ -386,6 +393,11 @@ class Target off_t offset, const elfcpp::Ehdr<64, true>& ehdr); #endif + // Virtual functions which may be overriden by the child class. + virtual Output_section* + do_make_output_section(const char* name, elfcpp::Elf_Word type, + elfcpp::Elf_Xword flags); + // Virtual function which may be overriden by the child class. virtual bool do_may_relax() const @@ -393,7 +405,7 @@ class Target // Virtual function which may be overriden by the child class. virtual bool - do_relax(int) + do_relax(int, const Input_objects*, Symbol_table*, Layout*) { return false; } // A function for targets to call. Return whether BYTES/LEN matches |