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.
os->set_needs_symtab_index();
}
+// An absolute relocation.
+
+template<bool dynamic, int size, bool big_endian>
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
+ unsigned int type,
+ Output_data* od,
+ Address address)
+ : address_(address), local_sym_index_(0), type_(type),
+ 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);
+ this->u1_.relobj = NULL;
+ this->u2_.od = od;
+}
+
+template<bool dynamic, int size, bool big_endian>
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
+ unsigned int type,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx,
+ Address address)
+ : address_(address), local_sym_index_(0), type_(type),
+ 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.
+ gold_assert(this->type_ == type);
+ this->u1_.relobj = NULL;
+ this->u2_.relobj = relobj;
+}
+
+// A target specific relocation.
+
+template<bool dynamic, int size, bool big_endian>
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
+ unsigned int type,
+ void* arg,
+ Output_data* od,
+ Address address)
+ : address_(address), local_sym_index_(TARGET_CODE), type_(type),
+ 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);
+ this->u1_.arg = arg;
+ this->u2_.od = od;
+}
+
+template<bool dynamic, int size, bool big_endian>
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
+ unsigned int type,
+ void* arg,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx,
+ Address address)
+ : address_(address), local_sym_index_(TARGET_CODE), type_(type),
+ 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.
+ gold_assert(this->type_ == type);
+ this->u1_.arg = arg;
+ this->u2_.relobj = relobj;
+}
+
// Record that we need a dynamic symbol index for this relocation.
template<bool dynamic, int size, bool big_endian>
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_)
{
this->u1_.os->set_needs_dynsym_index();
break;
+ case TARGET_CODE:
+ // The target must take care of this if necessary.
+ break;
+
case 0:
break;
const
{
unsigned int index;
+ if (this->is_symbolless_)
+ return 0;
switch (this->local_sym_index_)
{
case INVALID_CODE:
index = this->u1_.os->symtab_index();
break;
+ case TARGET_CODE:
+ index = parameters->target().reloc_symbol_index(this->u1_.arg,
+ this->type_);
+ break;
+
case 0:
// Relocations without symbols use a symbol index of 0.
index = 0;
{
gold_assert(this->local_sym_index_ != GSYM_CODE
&& this->local_sym_index_ != SECTION_CODE
+ && this->local_sym_index_ != TARGET_CODE
&& this->local_sym_index_ != INVALID_CODE
+ && this->local_sym_index_ != 0
&& this->is_section_symbol_);
const unsigned int lsi = this->local_sym_index_;
Output_section* os = this->u1_.relobj->output_section(lsi);
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_));
}
return sym->value() + addend;
}
gold_assert(this->local_sym_index_ != SECTION_CODE
+ && this->local_sym_index_ != TARGET_CODE
&& this->local_sym_index_ != INVALID_CODE
+ && this->local_sym_index_ != 0
&& !this->is_section_symbol_);
const unsigned int lsi = this->local_sym_index_;
const Symbol_value<size>* symval = this->u1_.relobj->local_symbol(lsi);
elfcpp::Rela_write<size, big_endian> orel(pov);
this->rel_.write_rel(&orel);
Addend addend = this->addend_;
- if (this->rel_.is_relative())
+ if (this->rel_.is_target_specific())
+ addend = parameters->target().reloc_addend(this->rel_.target_arg(),
+ this->rel_.type(), addend);
+ 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);
const off_t oview_size = this->data_size();
unsigned char* const oview = of->get_output_view(off, oview_size);
- if (this->sort_relocs_)
+ if (this->sort_relocs())
{
gold_assert(dynamic);
std::sort(this->relocs_.begin(), this->relocs_.end(),
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)
attached_input_sections_are_sorted_(false),
is_relro_(false),
is_relro_local_(false),
+ is_last_relro_(false),
+ is_first_non_relro_(false),
is_small_section_(false),
is_large_section_(false),
is_interp_(false),
is_dynamic_linker_section_(false),
generate_code_fills_at_write_(false),
+ is_entsize_zero_(false),
+ section_offsets_need_adjustment_(false),
tls_offset_(0),
checkpoint_(NULL),
merge_section_map_(),
void
Output_section::set_entsize(uint64_t v)
{
- if (this->entsize_ == 0)
+ if (this->is_entsize_zero_)
+ ;
+ else if (this->entsize_ == 0)
this->entsize_ = v;
- else
- gold_assert(this->entsize_ == v);
+ else if (this->entsize_ != v)
+ {
+ this->entsize_ = 0;
+ this->is_entsize_zero_ = 1;
+ }
}
// Add the input section SHNDX, with header SHDR, named SECNAME, in
this->addralign_ = addralign;
typename elfcpp::Elf_types<size>::Elf_WXword sh_flags = shdr.get_sh_flags();
- this->update_flags_for_input_section(sh_flags);
-
uint64_t entsize = shdr.get_sh_entsize();
// .debug_str is a mergeable string section, but is not always so
entsize = 1;
}
+ this->update_flags_for_input_section(sh_flags);
+ this->set_entsize(entsize);
+
// If this is a SHF_MERGE section, we pass all the input sections to
// a Output_data_merge. We don't try to handle relocations for such
// a section. We don't try to handle empty merge sections--they
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;
+ Const_section_id csid(poris->relobj(), poris->shndx());
+ this->relaxed_input_section_map_[csid] = poris;
}
// For a relaxed section, we use the current data size. Linker scripts
&& merge_section->addralign() == addralign);
// Link input section to found merge section.
- Input_section_specifier iss(object, shndx);
- this->merge_section_map_[iss] = merge_section;
+ Const_section_id csid(object, shndx);
+ this->merge_section_map_[csid] = merge_section;
return true;
}
// 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;
+ Const_section_id csid(object, shndx);
+ this->merge_section_map_[csid] = pomb;
return true;
}
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->is_relaxed_input_section_map_valid_)
+ for (size_t i = 0; i < relaxed_sections.size(); ++i)
+ {
+ Output_relaxed_input_section* poris = relaxed_sections[i];
+ Const_section_id csid(poris->relobj(), poris->shndx());
+ this->relaxed_input_section_map_[csid] = poris;
+ }
}
// Update the output section flags based on input section flags.
& (elfcpp::SHF_WRITE
| elfcpp::SHF_ALLOC
| elfcpp::SHF_EXECINSTR));
+
+ if ((flags & elfcpp::SHF_MERGE) == 0)
+ this->flags_ &=~ elfcpp::SHF_MERGE;
+ else
+ {
+ if (this->current_data_size_for_child() == 0)
+ this->flags_ |= elfcpp::SHF_MERGE;
+ }
+
+ if ((flags & elfcpp::SHF_STRINGS) == 0)
+ this->flags_ &=~ elfcpp::SHF_STRINGS;
+ else
+ {
+ if (this->current_data_size_for_child() == 0)
+ this->flags_ |= elfcpp::SHF_STRINGS;
+ }
}
// Find the merge section into which an input section with index SHNDX in
Output_section::find_merge_section(const Relobj* object,
unsigned int shndx) const
{
- Input_section_specifier iss(object, shndx);
+ Const_section_id csid(object, shndx);
Output_section_data_by_input_section_map::const_iterator p =
- this->merge_section_map_.find(iss);
+ this->merge_section_map_.find(csid);
if (p != this->merge_section_map_.end())
{
Output_section_data* posd = p->second;
// Find an relaxed input section corresponding to an input section
// in OBJECT with index SHNDX.
-const Output_section_data*
+const Output_relaxed_input_section*
Output_section::find_relaxed_input_section(const Relobj* object,
unsigned int shndx) const
{
++p)
if (p->is_relaxed_input_section())
{
- Input_section_specifier iss(p->relobj(), p->shndx());
- this->relaxed_input_section_map_[iss] =
+ Const_section_id csid(p->relobj(), p->shndx());
+ this->relaxed_input_section_map_[csid] =
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);
+ Const_section_id csid(object, shndx);
+ Output_relaxed_input_section_by_input_section_map::const_iterator p =
+ this->relaxed_input_section_map_.find(csid);
if (p != this->relaxed_input_section_map_.end())
return p->second;
else
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();
return data_size;
}
-// Add an input section from a script.
+// Add an simple input section.
void
-Output_section::add_input_section_for_script(const Simple_input_section& sis,
- off_t data_size,
- uint64_t addralign)
+Output_section::add_simple_input_section(const Simple_input_section& sis,
+ off_t data_size,
+ uint64_t addralign)
{
if (addralign > this->addralign_)
this->addralign_ = addralign;
this->input_sections_.push_back(is);
}
-//
+// 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 relaxed input section map since we do not keep
+ // track of it.
+ this->is_relaxed_input_section_map_valid_ = false;
+}
+
void
Output_section::restore_states()
{
this->is_relaxed_input_section_map_valid_ = false;
}
+// 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.
void
are_addresses_set_(false),
is_large_data_segment_(false)
{
+ // The ELF ABI specifies that a PT_TLS segment always has PF_R as
+ // the flags.
+ if (type == elfcpp::PT_TLS)
+ this->flags_ = elfcpp::PF_R;
}
// Add an Output_section to an Output_segment.
gold_assert(os->is_large_data_section() == this->is_large_data_segment());
gold_assert(this->type() == elfcpp::PT_LOAD || !do_sort);
- // Update the segment flags.
- this->flags_ |= seg_flags;
+ this->update_flags_for_output_section(seg_flags);
Output_segment::Output_data_list* pdl;
if (os->type() == elfcpp::SHT_NOBITS)
// location in the section list.
}
- // For the PT_GNU_RELRO segment, we need to group relro sections,
- // and we need to put them before any non-relro sections. Also,
- // relro local sections go before relro non-local sections.
- if (parameters->options().relro() && os->is_relro())
+ if (do_sort)
{
- gold_assert(pdl == &this->output_data_);
- Output_segment::Output_data_list::iterator p;
- for (p = pdl->begin(); p != pdl->end(); ++p)
+ // For the PT_GNU_RELRO segment, we need to group relro
+ // sections, and we need to put them before any non-relro
+ // sections. Any relro local sections go before relro non-local
+ // sections. One section may be marked as the last relro
+ // section.
+ if (os->is_relro())
{
- if (!(*p)->is_section())
- break;
+ gold_assert(pdl == &this->output_data_);
+ Output_segment::Output_data_list::iterator p;
+ for (p = pdl->begin(); p != pdl->end(); ++p)
+ {
+ if (!(*p)->is_section())
+ break;
- Output_section* pos = (*p)->output_section();
- if (!pos->is_relro()
- || (os->is_relro_local() && !pos->is_relro_local()))
- break;
+ Output_section* pos = (*p)->output_section();
+ if (!pos->is_relro()
+ || (os->is_relro_local() && !pos->is_relro_local())
+ || (!os->is_last_relro() && pos->is_last_relro()))
+ break;
+ }
+
+ pdl->insert(p, os);
+ return;
}
- pdl->insert(p, os);
- return;
+ // One section may be marked as the first section which follows
+ // the relro sections.
+ if (os->is_first_non_relro())
+ {
+ gold_assert(pdl == &this->output_data_);
+ Output_segment::Output_data_list::iterator p;
+ for (p = pdl->begin(); p != pdl->end(); ++p)
+ {
+ if (!(*p)->is_section())
+ break;
+
+ Output_section* pos = (*p)->output_section();
+ if (!pos->is_relro())
+ break;
+ }
+
+ pdl->insert(p, os);
+ return;
+ }
}
// Small data sections go at the end of the list of data sections.
gold_unreachable();
}
-// Add an Output_data (which is not an Output_section) to the start of
-// a segment.
+// Add an Output_data (which need not be an Output_section) to the
+// start of a segment.
void
Output_segment::add_initial_output_data(Output_data* od)
if (addralign > this->max_align_)
this->max_align_ = addralign;
- // If -z relro is in effect, and the first section in this
- // segment is a relro section, then the segment must be aligned
- // to at least the common page size. This ensures that the
- // PT_GNU_RELRO segment will start at a page boundary.
- if (this->type_ == elfcpp::PT_LOAD
- && parameters->options().relro()
- && this->is_first_section_relro())
- {
- addralign = parameters->target().common_pagesize();
- if (addralign > this->max_align_)
- this->max_align_ = addralign;
- }
-
this->is_max_align_known_ = true;
}
uint64_t
Output_segment::set_section_addresses(const Layout* layout, bool reset,
- uint64_t addr, off_t* poff,
+ uint64_t addr,
+ unsigned int increase_relro,
+ off_t* poff,
unsigned int* pshndx)
{
gold_assert(this->type_ == elfcpp::PT_LOAD);
+ off_t orig_off = *poff;
+
+ // If we have relro sections, we need to pad forward now so that the
+ // relro sections plus INCREASE_RELRO end on a common page boundary.
+ if (parameters->options().relro()
+ && this->is_first_section_relro()
+ && (!this->are_addresses_set_ || reset))
+ {
+ uint64_t relro_size = 0;
+ off_t off = *poff;
+ for (Output_data_list::iterator p = this->output_data_.begin();
+ p != this->output_data_.end();
+ ++p)
+ {
+ if (!(*p)->is_section())
+ break;
+ Output_section* pos = (*p)->output_section();
+ if (!pos->is_relro())
+ break;
+ gold_assert(!(*p)->is_section_flag_set(elfcpp::SHF_TLS));
+ if ((*p)->is_address_valid())
+ relro_size += (*p)->data_size();
+ else
+ {
+ // FIXME: This could be faster.
+ (*p)->set_address_and_file_offset(addr + relro_size,
+ off + relro_size);
+ relro_size += (*p)->data_size();
+ (*p)->reset_address_and_file_offset();
+ }
+ }
+ relro_size += increase_relro;
+
+ uint64_t page_align = parameters->target().common_pagesize();
+
+ // Align to offset N such that (N + RELRO_SIZE) % PAGE_ALIGN == 0.
+ uint64_t desired_align = page_align - (relro_size % page_align);
+ if (desired_align < *poff % page_align)
+ *poff += page_align - *poff % page_align;
+ *poff += desired_align - *poff % page_align;
+ addr += *poff - orig_off;
+ orig_off = *poff;
+ }
+
if (!reset && this->are_addresses_set_)
{
gold_assert(this->paddr_ == addr);
bool in_tls = false;
- bool in_relro = (parameters->options().relro()
- && this->is_first_section_relro());
-
- off_t orig_off = *poff;
this->offset_ = orig_off;
addr = this->set_section_list_addresses(layout, reset, &this->output_data_,
- addr, poff, pshndx, &in_tls,
- &in_relro);
+ addr, poff, pshndx, &in_tls);
this->filesz_ = *poff - orig_off;
off_t off = *poff;
uint64_t ret = this->set_section_list_addresses(layout, reset,
&this->output_bss_,
addr, poff, pshndx,
- &in_tls, &in_relro);
+ &in_tls);
// If the last section was a TLS section, align upward to the
// alignment of the TLS segment, so that the overall size of the TLS
*poff = align_address(*poff, segment_align);
}
- // If all the sections were relro sections, align upward to the
- // common page size.
- if (in_relro)
- {
- uint64_t page_align = parameters->target().common_pagesize();
- *poff = align_address(*poff, page_align);
- }
-
this->memsz_ = *poff - orig_off;
// Ignore the file offset adjustments made by the BSS Output_data
Output_data_list* pdl,
uint64_t addr, off_t* poff,
unsigned int* pshndx,
- bool* in_tls, bool* in_relro)
+ bool* in_tls)
{
off_t startoff = *poff;
}
}
- // If this is a non-relro section after a relro section,
- // align it to a common page boundary so that the dynamic
- // linker has a page to mark as read-only.
- if (*in_relro
- && (!(*p)->is_section()
- || !(*p)->output_section()->is_relro()))
- {
- uint64_t page_align = parameters->target().common_pagesize();
- if (page_align > align)
- align = page_align;
- *in_relro = false;
- }
-
off = align_address(off, align);
(*p)->set_address_and_file_offset(addr + (off - startoff), off);
}
off += (*p)->address() - (addr + (off - startoff));
else
{
-#if 0
if (!layout->script_options()->saw_sections_clause())
gold_unreachable();
else
-#endif
{
Output_section* os = (*p)->output_section();
}
// For a non-PT_LOAD segment, set the offset from the sections, if
-// any.
+// any. Add INCREASE to the file size and the memory size.
void
-Output_segment::set_offset()
+Output_segment::set_offset(unsigned int increase)
{
gold_assert(this->type_ != elfcpp::PT_LOAD);
if (this->output_data_.empty() && this->output_bss_.empty())
{
+ gold_assert(increase == 0);
this->vaddr_ = 0;
this->paddr_ = 0;
this->are_addresses_set_ = true;
+ last->data_size()
- this->vaddr_);
+ this->filesz_ += increase;
+ this->memsz_ += increase;
+
// If this is a TLS segment, align the memory size. The code in
// set_section_list ensures that the section after the TLS segment
// is aligned to give us room.
gold_assert(this->vaddr_ == align_address(this->vaddr_, segment_align));
this->memsz_ = align_address(this->memsz_, segment_align);
}
-
- // If this is a RELRO segment, align the memory size. The code in
- // set_section_list ensures that the section after the RELRO segment
- // is aligned to give us room.
- if (this->type_ == elfcpp::PT_GNU_RELRO)
- {
- uint64_t page_align = parameters->target().common_pagesize();
- gold_assert(this->vaddr_ == align_address(this->vaddr_, page_align));
- this->memsz_ = align_address(this->memsz_, page_align);
- }
}
// Set the TLS offsets of the sections in the PT_TLS segment.