+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.
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);
&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
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&);
: 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
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
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.
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*
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);
// 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.
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*);
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;
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);
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*,
option_name, arg);
}
+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)
{
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);
}; \
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__, \
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);
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
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())
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));
}
}
+// 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
// 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.
| 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
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)
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)
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)
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();
{
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();
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.
{
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();
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();
}
}
&& !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());
// 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.
class Object;
class Symbol;
class Output_file;
+class Output_merge_base;
class Output_section;
class Relocatable_relocs;
class 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
};
// 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
// 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.
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
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();
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
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
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
{
{ 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.
bool attached_input_sections_are_sorted_;
};
- private:
// This class is used to sort the input sections.
class Input_section_sort_entry;
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*);
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.
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
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()))
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());
}
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())
&& 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();
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)
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()
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*,
#include "gold.h"
#include "target.h"
#include "dynobj.h"
+#include "output.h"
#include "elfcpp.h"
namespace gold
}
#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
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
// 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
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
// 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