elfcpp::ET e_type;
if (parameters->options().relocatable())
e_type = elfcpp::ET_REL;
- else if (parameters->options().shared())
+ else if (parameters->options().output_is_position_independent())
e_type = elfcpp::ET_DYN;
else
e_type = elfcpp::ET_EXEC;
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.
&& (os->flags() & elfcpp::SHF_TLS) != 0)
{
pdl = &this->output_data_;
- bool nobits = os->type() == elfcpp::SHT_NOBITS;
- bool sawtls = false;
- Output_segment::Output_data_list::iterator p = pdl->end();
- do
+ if (!pdl->empty())
{
- --p;
- bool insert;
- if ((*p)->is_section_flag_set(elfcpp::SHF_TLS))
- {
- sawtls = true;
- // Put a NOBITS section after the first TLS section.
- // Put a PROGBITS section after the first TLS/PROGBITS
- // section.
- insert = nobits || !(*p)->is_section_type(elfcpp::SHT_NOBITS);
- }
- else
+ bool nobits = os->type() == elfcpp::SHT_NOBITS;
+ bool sawtls = false;
+ Output_segment::Output_data_list::iterator p = pdl->end();
+ gold_assert(p != pdl->begin());
+ do
{
- // If we've gone past the TLS sections, but we've seen a
- // TLS section, then we need to insert this section now.
- insert = sawtls;
- }
+ --p;
+ bool insert;
+ if ((*p)->is_section_flag_set(elfcpp::SHF_TLS))
+ {
+ sawtls = true;
+ // Put a NOBITS section after the first TLS section.
+ // Put a PROGBITS section after the first
+ // TLS/PROGBITS section.
+ insert = nobits || !(*p)->is_section_type(elfcpp::SHT_NOBITS);
+ }
+ else
+ {
+ // If we've gone past the TLS sections, but we've
+ // seen a TLS section, then we need to insert this
+ // section now.
+ insert = sawtls;
+ }
- if (insert)
- {
- ++p;
- pdl->insert(p, os);
- return;
+ if (insert)
+ {
+ ++p;
+ pdl->insert(p, os);
+ return;
+ }
}
+ while (p != pdl->begin());
}
- while (p != pdl->begin());
// There are no TLS sections yet; put this one at the requested
// location in the section list.
{
// The script may have inserted a skip forward, but it
// better not have moved backward.
- gold_assert((*p)->address() >= addr + (off - startoff));
- off += (*p)->address() - (addr + (off - startoff));
+ if ((*p)->address() >= addr + (off - startoff))
+ off += (*p)->address() - (addr + (off - startoff));
+ else
+ {
+ if (!layout->script_options()->saw_sections_clause())
+ gold_unreachable();
+ else
+ {
+ Output_section* os = (*p)->output_section();
+
+ // Cast to unsigned long long to avoid format warnings.
+ unsigned long long previous_dot =
+ static_cast<unsigned long long>(addr + (off - startoff));
+ unsigned long long dot =
+ static_cast<unsigned long long>((*p)->address());
+
+ if (os == NULL)
+ gold_error(_("dot moves backward in linker script "
+ "from 0x%llx to 0x%llx"), previous_dot, dot);
+ else
+ gold_error(_("address of section '%s' moves backward "
+ "from 0x%llx to 0x%llx"),
+ os->name(), previous_dot, dot);
+ }
+ }
(*p)->set_file_offset(off);
(*p)->finalize_data_size();
}