else
oshdr.put_sh_link(shstrndx);
- oshdr.put_sh_info(0);
+ size_t segment_count = this->segment_list_->size();
+ oshdr.put_sh_info(segment_count >= elfcpp::PN_XNUM ? segment_count : 0);
+
oshdr.put_sh_addralign(0);
oshdr.put_sh_entsize(0);
}
else
{
oehdr.put_e_phentsize(elfcpp::Elf_sizes<size>::phdr_size);
- oehdr.put_e_phnum(this->segment_header_->data_size()
- / elfcpp::Elf_sizes<size>::phdr_size);
+ size_t phnum = (this->segment_header_->data_size()
+ / elfcpp::Elf_sizes<size>::phdr_size);
+ if (phnum > elfcpp::PN_XNUM)
+ phnum = elfcpp::PN_XNUM;
+ oehdr.put_e_phnum(phnum);
}
oehdr.put_e_shentsize(elfcpp::Elf_sizes<size>::shdr_size);
unsigned int type,
Output_data* od,
Address address,
- bool is_relative)
+ bool is_relative,
+ bool is_symbolless)
: address_(address), local_sym_index_(GSYM_CODE), type_(type),
- is_relative_(is_relative), is_section_symbol_(false), shndx_(INVALID_CODE)
+ is_relative_(is_relative), is_symbolless_(is_symbolless),
+ is_section_symbol_(false), shndx_(INVALID_CODE)
{
// this->type_ is a bitfield; make sure TYPE fits.
gold_assert(this->type_ == type);
Sized_relobj<size, big_endian>* relobj,
unsigned int shndx,
Address address,
- bool is_relative)
+ bool is_relative,
+ bool is_symbolless)
: address_(address), local_sym_index_(GSYM_CODE), type_(type),
- is_relative_(is_relative), is_section_symbol_(false), shndx_(shndx)
+ is_relative_(is_relative), is_symbolless_(is_symbolless),
+ is_section_symbol_(false), shndx_(shndx)
{
gold_assert(shndx != INVALID_CODE);
// this->type_ is a bitfield; make sure TYPE fits.
Output_data* od,
Address address,
bool is_relative,
+ bool is_symbolless,
bool is_section_symbol)
: address_(address), local_sym_index_(local_sym_index), type_(type),
- is_relative_(is_relative), is_section_symbol_(is_section_symbol),
- shndx_(INVALID_CODE)
+ is_relative_(is_relative), is_symbolless_(is_symbolless),
+ is_section_symbol_(is_section_symbol), shndx_(INVALID_CODE)
{
gold_assert(local_sym_index != GSYM_CODE
&& local_sym_index != INVALID_CODE);
unsigned int shndx,
Address address,
bool is_relative,
+ bool is_symbolless,
bool is_section_symbol)
: address_(address), local_sym_index_(local_sym_index), type_(type),
- is_relative_(is_relative), is_section_symbol_(is_section_symbol),
- shndx_(shndx)
+ is_relative_(is_relative), is_symbolless_(is_symbolless),
+ is_section_symbol_(is_section_symbol), shndx_(shndx)
{
gold_assert(local_sym_index != GSYM_CODE
&& local_sym_index != INVALID_CODE);
Output_data* od,
Address address)
: address_(address), local_sym_index_(SECTION_CODE), type_(type),
- is_relative_(false), is_section_symbol_(true), shndx_(INVALID_CODE)
+ is_relative_(false), is_symbolless_(false),
+ is_section_symbol_(true), shndx_(INVALID_CODE)
{
// this->type_ is a bitfield; make sure TYPE fits.
gold_assert(this->type_ == type);
unsigned int shndx,
Address address)
: address_(address), local_sym_index_(SECTION_CODE), type_(type),
- is_relative_(false), is_section_symbol_(true), shndx_(shndx)
+ is_relative_(false), is_symbolless_(false),
+ is_section_symbol_(true), shndx_(shndx)
{
gold_assert(shndx != INVALID_CODE);
// this->type_ is a bitfield; make sure TYPE fits.
Output_data* od,
Address address)
: address_(address), local_sym_index_(0), type_(type),
- is_relative_(false), is_section_symbol_(false), shndx_(INVALID_CODE)
+ is_relative_(false), is_symbolless_(false),
+ is_section_symbol_(false), shndx_(INVALID_CODE)
{
// this->type_ is a bitfield; make sure TYPE fits.
gold_assert(this->type_ == type);
unsigned int shndx,
Address address)
: address_(address), local_sym_index_(0), type_(type),
- is_relative_(false), is_section_symbol_(false), shndx_(shndx)
+ is_relative_(false), is_symbolless_(false),
+ is_section_symbol_(false), shndx_(shndx)
{
gold_assert(shndx != INVALID_CODE);
// this->type_ is a bitfield; make sure TYPE fits.
Output_data* od,
Address address)
: address_(address), local_sym_index_(TARGET_CODE), type_(type),
- is_relative_(false), is_section_symbol_(false), shndx_(INVALID_CODE)
+ is_relative_(false), is_symbolless_(false),
+ is_section_symbol_(false), shndx_(INVALID_CODE)
{
// this->type_ is a bitfield; make sure TYPE fits.
gold_assert(this->type_ == type);
unsigned int shndx,
Address address)
: address_(address), local_sym_index_(TARGET_CODE), type_(type),
- is_relative_(false), is_section_symbol_(false), shndx_(shndx)
+ is_relative_(false), is_symbolless_(false),
+ is_section_symbol_(false), shndx_(shndx)
{
gold_assert(shndx != INVALID_CODE);
// this->type_ is a bitfield; make sure TYPE fits.
Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::
set_needs_dynsym_index()
{
- if (this->is_relative_)
+ if (this->is_symbolless_)
return;
switch (this->local_sym_index_)
{
const
{
unsigned int index;
+ if (this->is_symbolless_)
+ return 0;
switch (this->local_sym_index_)
{
case INVALID_CODE:
Write_rel* wr) const
{
wr->put_r_offset(this->get_address());
- unsigned int sym_index = this->is_relative_ ? 0 : this->get_symbol_index();
+ unsigned int sym_index = this->get_symbol_index();
wr->put_r_info(elfcpp::elf_r_info<size>(sym_index, this->type_));
}
if (this->rel_.is_target_specific())
addend = parameters->target().reloc_addend(this->rel_.target_arg(),
this->rel_.type(), addend);
- else if (this->rel_.is_relative())
+ else if (this->rel_.is_symbolless())
addend = this->rel_.symbol_value(addend);
else if (this->rel_.is_local_section_symbol())
addend = this->rel_.local_section_offset(addend);
case DYNAMIC_SECTION_SIZE:
val = this->u_.od->data_size();
+ if (this->od2 != NULL)
+ val += this->od2->data_size();
break;
case DYNAMIC_SYMBOL:
{
// Add the terminating entry if it hasn't been added.
// Because of relaxation, we can run this multiple times.
- if (this->entries_.empty()
- || this->entries_.rbegin()->tag() != elfcpp::DT_NULL)
- this->add_constant(elfcpp::DT_NULL, 0);
+ if (this->entries_.empty() || this->entries_.back().tag() != elfcpp::DT_NULL)
+ {
+ int extra = parameters->options().spare_dynamic_tags();
+ for (int i = 0; i < extra; ++i)
+ this->add_constant(elfcpp::DT_NULL, 0);
+ this->add_constant(elfcpp::DT_NULL, 0);
+ }
int dyn_size;
if (parameters->target().get_size() == 32)
return this->u2_.posd->data_size();
}
+// Return the object for an input section.
+
+Relobj*
+Output_section::Input_section::relobj() const
+{
+ if (this->is_input_section())
+ return this->u2_.object;
+ else if (this->is_merge_section())
+ {
+ gold_assert(this->u2_.pomb->first_relobj() != NULL);
+ return this->u2_.pomb->first_relobj();
+ }
+ 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
+Output_section::Input_section::shndx() const
+{
+ if (this->is_input_section())
+ return this->shndx_;
+ else if (this->is_merge_section())
+ {
+ gold_assert(this->u2_.pomb->first_relobj() != NULL);
+ return this->u2_.pomb->first_shndx();
+ }
+ else if (this->is_relaxed_input_section())
+ return this->u2_.poris->shndx();
+ else
+ gold_unreachable();
+}
+
// Set the address and file offset.
void
is_dynamic_linker_section_(false),
generate_code_fills_at_write_(false),
is_entsize_zero_(false),
+ section_offsets_need_adjustment_(false),
+ is_noload_(false),
tls_offset_(0),
checkpoint_(NULL),
- merge_section_map_(),
- merge_section_by_properties_map_(),
- relaxed_input_section_map_(),
- is_relaxed_input_section_map_valid_(true)
+ lookup_maps_(new Output_section_lookup_maps)
{
// An unallocated section has no address. Forcing this means that
// we don't need special treatment for symbols defined in debug
&& reloc_shndx == 0
&& shdr.get_sh_size() > 0)
{
- if (this->add_merge_input_section(object, shndx, sh_flags,
- entsize, addralign))
+ // Keep information about merged input sections for rebuilding fast
+ // lookup maps if we have sections-script or we do relaxation.
+ bool keeps_input_sections =
+ have_sections_script || parameters->target().may_relax();
+ if (this->add_merge_input_section(object, shndx, sh_flags, entsize,
+ addralign, keeps_input_sections))
{
// Tell the relocation routines that they need to call the
// output_offset method to determine the final address.
{
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;
- }
+ if (this->lookup_maps_->is_valid())
+ this->lookup_maps_->add_relaxed_input_section(poris->relobj(),
+ poris->shndx(), poris);
// For a relaxed section, we use the current data size. Linker scripts
// get all the input sections, including relaxed one from an output
bool
Output_section::add_merge_input_section(Relobj* object, unsigned int shndx,
uint64_t flags, uint64_t entsize,
- uint64_t addralign)
+ uint64_t addralign,
+ bool keeps_input_sections)
{
bool is_string = (flags & elfcpp::SHF_STRINGS) != 0;
gold_assert(this->checkpoint_ == NULL);
// Look up merge sections by required properties.
+ // Currently, we only invalidate the lookup maps in script processing
+ // and relaxation. We should not have done either when we reach here.
+ // So we assume that the lookup maps are valid to simply code.
+ gold_assert(this->lookup_maps_->is_valid());
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* pomb = this->lookup_maps_->find_merge_section(msp);
+ bool is_new = false;
+ if (pomb != NULL)
{
- 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;
+ gold_assert(pomb->is_string() == is_string
+ && pomb->entsize() == entsize
+ && pomb->addralign() == addralign);
}
-
- // We handle the actual constant merging in Output_merge_data or
- // Output_merge_string_data.
- Output_merge_base* pomb;
- if (!is_string)
- pomb = new Output_merge_data(entsize, addralign);
else
{
- switch (entsize)
+ // Create a new Output_merge_data or Output_merge_string_data.
+ if (!is_string)
+ pomb = new Output_merge_data(entsize, addralign);
+ else
{
- case 1:
- pomb = new Output_merge_string<char>(addralign);
- break;
- case 2:
- pomb = new Output_merge_string<uint16_t>(addralign);
- break;
- case 4:
- pomb = new Output_merge_string<uint32_t>(addralign);
- break;
- default:
- return false;
+ switch (entsize)
+ {
+ case 1:
+ pomb = new Output_merge_string<char>(addralign);
+ break;
+ case 2:
+ pomb = new Output_merge_string<uint16_t>(addralign);
+ break;
+ case 4:
+ pomb = new Output_merge_string<uint32_t>(addralign);
+ break;
+ default:
+ return false;
+ }
}
+ // If we need to do script processing or relaxation, we need to keep
+ // the original input sections to rebuild the fast lookup maps.
+ if (keeps_input_sections)
+ pomb->set_keeps_input_sections();
+ is_new = true;
}
- // 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;
+ if (pomb->add_input_section(object, shndx))
+ {
+ // Add new merge section to this output section and link merge
+ // section properties to new merge section in map.
+ if (is_new)
+ {
+ this->add_output_merge_section(pomb, is_string, entsize);
+ this->lookup_maps_->add_merge_section(msp, pomb);
+ }
- return true;
+ // Add input section to new merge section and link input section to new
+ // merge section in map.
+ this->lookup_maps_->add_merge_input_section(object, shndx, pomb);
+ return true;
+ }
+ else
+ {
+ // If add_input_section failed, delete new merge section to avoid
+ // exporting empty merge sections in Output_section::get_input_section.
+ if (is_new)
+ delete pomb;
+ return false;
+ }
}
// Build a relaxation map to speed up relaxation of existing input sections.
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;
+ Section_id sid(is.relobj(), is.shndx());
+ (*relaxation_map)[sid] = 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.
+// sections in RELAXED_SECTIONS. MAP is a prebuilt map from section id
+// indices of INPUT_SECTIONS.
void
Output_section::convert_input_sections_in_list_to_relaxed_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);
+ Section_id sid(poris->relobj(), poris->shndx());
+ Relaxation_map::const_iterator p = map.find(sid);
gold_assert(p != map.end());
gold_assert((*input_sections)[p->second].is_input_section());
(*input_sections)[p->second] = Input_section(poris);
relaxed_sections,
map,
&this->input_sections_);
+
+ // Update fast look-up map.
+ if (this->lookup_maps_->is_valid())
+ for (size_t i = 0; i < relaxed_sections.size(); ++i)
+ {
+ Output_relaxed_input_section* poris = relaxed_sections[i];
+ this->lookup_maps_->add_relaxed_input_section(poris->relobj(),
+ poris->shndx(), poris);
+ }
}
// Update the output section flags based on input section flags.
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())
+ if (!this->lookup_maps_->is_valid())
+ this->build_lookup_maps();
+ return this->lookup_maps_->find_merge_section(object, shndx);
+}
+
+// Build the lookup maps for merge and relaxed sections. This is needs
+// to be declared as a const methods so that it is callable with a const
+// Output_section pointer. The method only updates states of the maps.
+
+void
+Output_section::build_lookup_maps() const
+{
+ this->lookup_maps_->clear();
+ for (Input_section_list::const_iterator p = this->input_sections_.begin();
+ p != this->input_sections_.end();
+ ++p)
{
- Output_section_data* posd = p->second;
- gold_assert(posd->is_merge_section_for(object, shndx));
- return posd;
+ if (p->is_merge_section())
+ {
+ Output_merge_base* pomb = p->output_merge_base();
+ Merge_section_properties msp(pomb->is_string(), pomb->entsize(),
+ pomb->addralign());
+ this->lookup_maps_->add_merge_section(msp, pomb);
+ for (Output_merge_base::Input_sections::const_iterator is =
+ pomb->input_sections_begin();
+ is != pomb->input_sections_end();
+ ++is)
+ {
+ const Const_section_id& csid = *is;
+ this->lookup_maps_->add_merge_input_section(csid.first,
+ csid.second, pomb);
+ }
+
+ }
+ else if (p->is_relaxed_input_section())
+ {
+ Output_relaxed_input_section* poris = p->relaxed_input_section();
+ this->lookup_maps_->add_relaxed_input_section(poris->relobj(),
+ poris->shndx(), poris);
+ }
}
- else
- return NULL;
}
// Find an relaxed input section corresponding to an input section
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_relaxed_input_section_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;
+ if (!this->lookup_maps_->is_valid())
+ this->build_lookup_maps();
+ return this->lookup_maps_->find_relaxed_input_section(object, shndx);
}
// Given an address OFFSET relative to the start of input section
{
// An unallocated section has no address. Forcing this means that
// we don't need special treatment for symbols defined in debug
- // sections. We do the same in the constructor.
- if ((this->flags_ & elfcpp::SHF_ALLOC) == 0)
+ // sections. We do the same in the constructor. This does not
+ // apply to NOLOAD sections though.
+ if (((this->flags_ & elfcpp::SHF_ALLOC) == 0) && !this->is_noload_)
this->set_address(0);
for (Input_section_list::iterator p = this->input_sections_.begin();
has_priority() const
{
gold_assert(this->section_has_name_);
- return this->section_name_.find('.', 1);
+ return this->section_name_.find('.', 1) != std::string::npos;
}
// Return true if this an input file whose base name matches
}
// A section with a priority follows a section without a priority.
- // The GNU linker does this for all but .init_array sections; until
- // further notice we'll assume that that is an mistake.
bool s1_has_priority = s1.has_priority();
bool s2_has_priority = s2.has_priority();
if (s1_has_priority && !s2_has_priority)
return s1.index() < s2.index();
}
+// Return true if S1 should come before S2 in an .init_array or .fini_array
+// output section.
+
+bool
+Output_section::Input_section_sort_init_fini_compare::operator()(
+ const Output_section::Input_section_sort_entry& s1,
+ const Output_section::Input_section_sort_entry& s2) const
+{
+ // We sort all the sections with no names to the end.
+ if (!s1.section_has_name() || !s2.section_has_name())
+ {
+ if (s1.section_has_name())
+ return true;
+ if (s2.section_has_name())
+ return false;
+ return s1.index() < s2.index();
+ }
+
+ // A section without a priority follows a section with a priority.
+ // This is the reverse of .ctors and .dtors sections.
+ bool s1_has_priority = s1.has_priority();
+ bool s2_has_priority = s2.has_priority();
+ if (s1_has_priority && !s2_has_priority)
+ return true;
+ if (!s1_has_priority && s2_has_priority)
+ return false;
+
+ // Otherwise we sort by name.
+ int compare = s1.section_name().compare(s2.section_name());
+ if (compare != 0)
+ return compare < 0;
+
+ // Otherwise we keep the input order.
+ return s1.index() < s2.index();
+}
+
// Sort the input sections attached to an output section.
void
sort_list.push_back(Input_section_sort_entry(*p, i));
// Sort the input sections.
- std::sort(sort_list.begin(), sort_list.end(), Input_section_sort_compare());
+ if (this->type() == elfcpp::SHT_PREINIT_ARRAY
+ || this->type() == elfcpp::SHT_INIT_ARRAY
+ || this->type() == elfcpp::SHT_FINI_ARRAY)
+ std::sort(sort_list.begin(), sort_list.end(),
+ Input_section_sort_init_fini_compare());
+ else
+ std::sort(sort_list.begin(), sort_list.end(),
+ Input_section_sort_compare());
// Copy the sorted input sections back to our list.
this->input_sections_.clear();
Output_section::get_input_sections(
uint64_t address,
const std::string& fill,
- std::list<Simple_input_section>* input_sections)
+ std::list<Input_section>* input_sections)
{
if (this->checkpoint_ != NULL
&& !this->checkpoint_->input_sections_saved())
this->checkpoint_->save_input_sections();
- // Invalidate the relaxed input section map.
- this->is_relaxed_input_section_map_valid_ = false;
+ // Invalidate fast look-up maps.
+ this->lookup_maps_->invalidate();
uint64_t orig_address = address;
p != this->input_sections_.end();
++p)
{
- if (p->is_input_section())
- input_sections->push_back(Simple_input_section(p->relobj(),
- p->shndx()));
- else if (p->is_relaxed_input_section())
- input_sections->push_back(
- Simple_input_section(p->relaxed_input_section()));
+ if (p->is_input_section()
+ || p->is_relaxed_input_section()
+ || p->is_merge_section())
+ input_sections->push_back(*p);
else
{
uint64_t aligned_address = align_address(address, p->addralign());
return data_size;
}
-// Add an input section from a script.
+// Add a script input section. SIS is an Output_section::Input_section,
+// which can be either a plain input section or a special input section like
+// a relaxed input section. For a special input section, its size must be
+// finalized.
void
-Output_section::add_input_section_for_script(const Simple_input_section& sis,
- off_t data_size,
- uint64_t addralign)
+Output_section::add_script_input_section(const Input_section& sis)
{
+ uint64_t data_size = sis.data_size();
+ uint64_t addralign = sis.addralign();
if (addralign > this->addralign_)
this->addralign_ = addralign;
this->set_current_data_size_for_child(aligned_offset_in_section
+ data_size);
- Input_section is =
- (sis.is_relaxed_input_section()
- ? Input_section(sis.relaxed_input_section())
- : Input_section(sis.relobj(), sis.shndx(), data_size, addralign));
- this->input_sections_.push_back(is);
+ this->input_sections_.push_back(sis);
+
+ // Update fast lookup maps if necessary.
+ if (this->lookup_maps_->is_valid())
+ {
+ if (sis.is_merge_section())
+ {
+ Output_merge_base* pomb = sis.output_merge_base();
+ Merge_section_properties msp(pomb->is_string(), pomb->entsize(),
+ pomb->addralign());
+ this->lookup_maps_->add_merge_section(msp, pomb);
+ for (Output_merge_base::Input_sections::const_iterator p =
+ pomb->input_sections_begin();
+ p != pomb->input_sections_end();
+ ++p)
+ this->lookup_maps_->add_merge_input_section(p->first, p->second,
+ pomb);
+ }
+ else if (sis.is_relaxed_input_section())
+ {
+ Output_relaxed_input_section* poris = sis.relaxed_input_section();
+ this->lookup_maps_->add_relaxed_input_section(poris->relobj(),
+ poris->shndx(), poris);
+ }
+ }
}
-//
+// Save states for relaxation.
void
Output_section::save_states()
gold_assert(this->fills_.empty());
}
+void
+Output_section::discard_states()
+{
+ gold_assert(this->checkpoint_ != NULL);
+ delete this->checkpoint_;
+ this->checkpoint_ = NULL;
+ gold_assert(this->fills_.empty());
+
+ // Simply invalidate the fast lookup maps since we do not keep
+ // track of them.
+ this->lookup_maps_->invalidate();
+}
+
void
Output_section::restore_states()
{
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;
+ // Simply invalidate the fast lookup maps since we do not keep
+ // track of them.
+ this->lookup_maps_->invalidate();
+}
+
+// Update the section offsets of input sections in this. This is required if
+// relaxation causes some input sections to change sizes.
+
+void
+Output_section::adjust_section_offsets()
+{
+ if (!this->section_offsets_need_adjustment_)
+ return;
+
+ off_t off = 0;
+ for (Input_section_list::iterator p = this->input_sections_.begin();
+ p != this->input_sections_.end();
+ ++p)
+ {
+ off = align_address(off, p->addralign());
+ if (p->is_input_section())
+ p->relobj()->set_section_offset(p->shndx(), off);
+ off += p->data_size();
+ }
+
+ this->section_offsets_need_adjustment_ = false;
}
// Print to the map file.