+2010-08-03 Ian Lance Taylor <iant@google.com>
+
+ PR 11805
+ * layout.h (enum Output_section_order): Define.
+ (class Layout): Update declarations.
+ * layout.cc (Layout::get_output_section): Add order parameter.
+ Remove is_interp, is_dynamic_linker_section, is_last_relro, and
+ is_first_non_relro parameters. Change all callers.
+ (Layout::choose_output_section): Likewise.
+ (Layout::add_output_section_data): Likewise.
+ (Layout::make_output_section): Likewise. Set order.
+ (Layout::default_section_order): New function.
+ (Layout::layout_eh_frame): Call add_output_section_to_nonload.
+ * output.cc (Output_section::Output_section): Initialize order_.
+ Don't initialize deleted fields.
+ (Output_segment::Output_segment): Don't initialize deleted
+ fields.
+ (Output_segment::add_output_section_to_load): New function
+ replacing add_output_section. Change all callers to call this or
+ add_output_section_to_nonload.
+ (Output_segment::add_output_section_to_nonload): New function.
+ (Output_segment::remove_output_section): Rewrite.
+ (Output_segment::add_initial_output_data): Likewise.
+ (Output_segment::has_any_data_sections): Likewise.
+ (Output_segment::is_first_section_relro): Likewise.
+ (Output_segment::maximum_alignment): Likewise.
+ (Output_segment::has_dynamic_reloc): New function replacing
+ dynamic_reloc_count. Change all callers.
+ (Output_segment::has_dynamic_reloc_list): New function replacing
+ dynamic_reloc_count_list. Change all callers.
+ (Output_segment::set_section_addresses): Rewrite.
+ (Output_segment::set_offset): Rewrite.
+ (Output_segment::find_first_and_last_list): Remove.
+ (Output_segment::set_tls_offsets): Rewrite.
+ (Output_segment::first_section_load_address): Likewise.
+ (Output_segment::output_section_count): Likewise.
+ (Output_segment::section_with_lowest_load_address): Likewise.
+ (Output_segment::write_section_headers): Likewise.
+ (Output_segment::print_sections_to_map): Likewise.
+ * output.h (class Output_data): Remove dynamic_reloc_count_
+ field. Add has_dynamic_reloc_ field. Make bools into bitfields.
+ (Output_data::add_dynamic_reloc): Rewrite.
+ (Output_data::has_dynamic_reloc): New function.
+ (Output_data::dynamic_reloc_count): Remove.
+ (class Output_section): Add order_ field. Remvoe is_relro_local_,
+ is_last_relro_, is_first_non_relro_, is_interp_,
+ is_dynamic_linker_section_ fields. Add order and set_order
+ functions. Remove is_relro_local, set_is_relro_local,
+ is_last_relro, set_is_last_relro, is_first_non_relro,
+ set_is_first_non_relro functions, is_interp, set_is_interp,
+ is_dynamic_linker_section, and set_is_dynamic_linker_section
+ functions.
+ (class Output_segment): Change Output_data_list from std::list to
+ std:;vector. Add output_lists_ field. Remove output_data_ and
+ output_bss_ fields. Update declarations.
+
2010-08-02 Ian Lance Taylor <iant@google.com>
* arm.cc (Target_arm::gc_process_relocs): Use typename.
layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
(elfcpp::SHF_ALLOC
| elfcpp::SHF_WRITE),
- this->got_, false, false, false, true);
+ this->got_, ORDER_RELRO, true);
+
// The old GNU linker creates a .got.plt section. We just
// create another set of data in the .got section. Note that we
// always create a PLT if we create a GOT, although the PLT
layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
(elfcpp::SHF_ALLOC
| elfcpp::SHF_WRITE),
- this->got_plt_, false, false, false,
- false);
+ this->got_plt_, ORDER_DATA, false);
// The first three entries are reserved.
this->got_plt_->set_current_data_size(3 * 4);
gold_assert(layout != NULL);
this->rel_dyn_ = new Reloc_section(parameters->options().combreloc());
layout->add_output_section_data(".rel.dyn", elfcpp::SHT_REL,
- elfcpp::SHF_ALLOC, this->rel_dyn_, true,
- false, false, false);
+ elfcpp::SHF_ALLOC, this->rel_dyn_,
+ ORDER_DYNAMIC_RELOCS, false);
}
return this->rel_dyn_;
}
{
this->rel_ = new Reloc_section(false);
layout->add_output_section_data(".rel.plt", elfcpp::SHT_REL,
- elfcpp::SHF_ALLOC, this->rel_, true, false,
- false, false);
+ elfcpp::SHF_ALLOC, this->rel_,
+ ORDER_DYNAMIC_PLT_RELOCS, false);
}
template<bool big_endian>
layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
(elfcpp::SHF_ALLOC
| elfcpp::SHF_EXECINSTR),
- this->plt_, false, false, false, false);
+ this->plt_, ORDER_PLT, false);
}
this->plt_->add_entry(gsym);
}
== NULL);
Output_segment* exidx_segment =
layout->make_output_segment(elfcpp::PT_ARM_EXIDX, elfcpp::PF_R);
- exidx_segment->add_output_section(exidx_section, elfcpp::PF_R,
- false);
+ exidx_segment->add_output_section_to_nonload(exidx_section,
+ elfcpp::PF_R);
}
}
new Output_attributes_section_data(*this->attributes_section_data_);
layout->add_output_section_data(".ARM.attributes",
elfcpp::SHT_ARM_ATTRIBUTES, 0,
- attributes_section, false, false, false,
+ attributes_section, ORDER_INVALID,
false);
}
Output_data_space *poc = new Output_data_space(addralign, ds_name);
Output_section *os = layout->add_output_section_data(name,
elfcpp::SHT_NOBITS,
- flags, poc, false,
- false, false, false);
+ flags, poc,
+ ORDER_INVALID,
+ false);
if (os != NULL)
{
if (commons_section_type == COMMONS_SMALL)
layout->add_output_section_data(".bss",
elfcpp::SHT_NOBITS,
elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
- this->dynbss_, false, false, false,
- false);
+ this->dynbss_, ORDER_BSS, false);
}
Output_data_space* dynbss = this->dynbss_;
layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
(elfcpp::SHF_ALLOC
| elfcpp::SHF_WRITE),
- this->got_, false, true, true, false);
+ this->got_, ORDER_RELRO_LAST, true);
this->got_plt_ = new Output_data_space(4, "** GOT PLT");
layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS,
(elfcpp::SHF_ALLOC
| elfcpp::SHF_WRITE),
- this->got_plt_, false, false, false,
- true);
+ this->got_plt_, ORDER_NON_RELRO_FIRST,
+ false);
// The first three entries are reserved.
this->got_plt_->set_current_data_size(3 * 4);
layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS,
(elfcpp::SHF_ALLOC
| elfcpp::SHF_WRITE),
- this->got_tlsdesc_, false, false, false,
- true);
+ this->got_tlsdesc_,
+ ORDER_NON_RELRO_FIRST, false);
}
return this->got_;
gold_assert(layout != NULL);
this->rel_dyn_ = new Reloc_section(parameters->options().combreloc());
layout->add_output_section_data(".rel.dyn", elfcpp::SHT_REL,
- elfcpp::SHF_ALLOC, this->rel_dyn_, true,
- false, false, false);
+ elfcpp::SHF_ALLOC, this->rel_dyn_,
+ ORDER_DYNAMIC_RELOCS, false);
}
return this->rel_dyn_;
}
{
this->rel_ = new Reloc_section(false);
layout->add_output_section_data(".rel.plt", elfcpp::SHT_REL,
- elfcpp::SHF_ALLOC, this->rel_, true,
- false, false, false);
+ elfcpp::SHF_ALLOC, this->rel_,
+ ORDER_DYNAMIC_PLT_RELOCS, false);
}
void
this->tls_desc_rel_ = new Reloc_section(false);
layout->add_output_section_data(".rel.plt", elfcpp::SHT_REL,
elfcpp::SHF_ALLOC, this->tls_desc_rel_,
- true, false, false, false);
+ ORDER_DYNAMIC_PLT_RELOCS, false);
gold_assert(this->tls_desc_rel_->output_section() ==
this->rel_->output_section());
}
layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
(elfcpp::SHF_ALLOC
| elfcpp::SHF_EXECINSTR),
- this->plt_, false, false, false, false);
+ this->plt_, ORDER_PLT, false);
}
this->plt_->add_entry(gsym);
Output_section*
Layout::get_output_section(const char* name, Stringpool::Key name_key,
elfcpp::Elf_Word type, elfcpp::Elf_Xword flags,
- bool is_interp, bool is_dynamic_linker_section,
- bool is_relro, bool is_last_relro,
- bool is_first_non_relro)
+ Output_section_order order, bool is_relro)
{
elfcpp::Elf_Xword lookup_flags = flags;
}
if (os == NULL)
- os = this->make_output_section(name, type, flags, is_interp,
- is_dynamic_linker_section, is_relro,
- is_last_relro, is_first_non_relro);
+ os = this->make_output_section(name, type, flags, order, is_relro);
+
ins.first->second = os;
return os;
}
Output_section*
Layout::choose_output_section(const Relobj* relobj, const char* name,
elfcpp::Elf_Word type, elfcpp::Elf_Xword flags,
- bool is_input_section, bool is_interp,
- bool is_dynamic_linker_section, bool is_relro,
- bool is_last_relro, bool is_first_non_relro)
+ bool is_input_section, Output_section_order order,
+ bool is_relro)
{
// We should not see any input sections after we have attached
// sections to segments.
name = this->namepool_.add(name, false, NULL);
- Output_section* os =
- this->make_output_section(name, type, flags, is_interp,
- is_dynamic_linker_section, is_relro,
- is_last_relro, is_first_non_relro);
+ Output_section* os = this->make_output_section(name, type, flags,
+ order, is_relro);
+
os->set_found_in_sections_clause();
// Special handling for NOLOAD sections.
// Find or make the output section. The output section is selected
// based on the section name, type, and flags.
- return this->get_output_section(name, name_key, type, flags, is_interp,
- is_dynamic_linker_section, is_relro,
- is_last_relro, is_first_non_relro);
+ return this->get_output_section(name, name_key, type, flags, order, is_relro);
}
// Return the output section to use for input section SHNDX, with name
&& (shdr.get_sh_flags() & elfcpp::SHF_GROUP) != 0)
{
name = this->namepool_.add(name, true, NULL);
- os = this->make_output_section(name, sh_type, shdr.get_sh_flags(), false,
- false, false, false, false);
+ os = this->make_output_section(name, sh_type, shdr.get_sh_flags(),
+ ORDER_INVALID, false);
}
else
{
os = this->choose_output_section(object, name, sh_type,
- shdr.get_sh_flags(), true, false,
- false, false, false, false);
+ shdr.get_sh_flags(), true,
+ ORDER_INVALID, false);
if (os == NULL)
return NULL;
}
if (!parameters->options().relocatable()
|| (data_section->flags() & elfcpp::SHF_GROUP) == 0)
os = this->choose_output_section(object, name.c_str(), sh_type,
- shdr.get_sh_flags(), false, false,
- false, false, false, false);
+ shdr.get_sh_flags(), false,
+ ORDER_INVALID, false);
else
{
const char* n = this->namepool_.add(name.c_str(), true, NULL);
os = this->make_output_section(n, sh_type, shdr.get_sh_flags(),
- false, false, false, false, false);
+ ORDER_INVALID, false);
}
os->set_should_link_to_symtab();
Output_section* os = this->make_output_section(group_section_name,
elfcpp::SHT_GROUP,
shdr.get_sh_flags(),
- false, false, false,
- false, false);
+ ORDER_INVALID, false);
// We need to find a symbol with the signature in the symbol table.
// If we don't find one now, we need to look again later.
gold_assert((shdr.get_sh_flags() & elfcpp::SHF_ALLOC) != 0);
const char* const name = ".eh_frame";
- Output_section* os = this->choose_output_section(object,
- name,
+ Output_section* os = this->choose_output_section(object, name,
elfcpp::SHT_PROGBITS,
- elfcpp::SHF_ALLOC,
- false, false, false,
- false, false, false);
+ elfcpp::SHF_ALLOC, false,
+ ORDER_EHFRAME, false);
if (os == NULL)
return NULL;
if (parameters->options().eh_frame_hdr())
{
Output_section* hdr_os =
- this->choose_output_section(NULL,
- ".eh_frame_hdr",
+ this->choose_output_section(NULL, ".eh_frame_hdr",
elfcpp::SHT_PROGBITS,
- elfcpp::SHF_ALLOC,
- false, false, false,
- false, false, false);
+ elfcpp::SHF_ALLOC, false,
+ ORDER_EHFRAME, false);
if (hdr_os != NULL)
{
Output_segment* hdr_oseg;
hdr_oseg = this->make_output_segment(elfcpp::PT_GNU_EH_FRAME,
elfcpp::PF_R);
- hdr_oseg->add_output_section(hdr_os, elfcpp::PF_R, false);
+ hdr_oseg->add_output_section_to_nonload(hdr_os,
+ elfcpp::PF_R);
}
this->eh_frame_data_->set_eh_frame_hdr(hdr_posd);
Layout::add_output_section_data(const char* name, elfcpp::Elf_Word type,
elfcpp::Elf_Xword flags,
Output_section_data* posd,
- bool is_dynamic_linker_section,
- bool is_relro, bool is_last_relro,
- bool is_first_non_relro)
+ Output_section_order order, bool is_relro)
{
Output_section* os = this->choose_output_section(NULL, name, type, flags,
- false, false,
- is_dynamic_linker_section,
- is_relro, is_last_relro,
- is_first_non_relro);
+ false, order, is_relro);
if (os != NULL)
os->add_output_section_data(posd);
return os;
}
// Make a new Output_section, and attach it to segments as
-// appropriate. IS_INTERP is true if this is the .interp section.
-// IS_DYNAMIC_LINKER_SECTION is true if this section is used by the
-// dynamic linker. IS_RELRO is true if this is a relro section.
-// IS_LAST_RELRO is true if this is the last relro section.
-// IS_FIRST_NON_RELRO is true if this is the first non relro section.
+// appropriate. ORDER is the order in which this section should
+// appear in the output segment. IS_RELRO is true if this is a relro
+// (read-only after relocations) section.
Output_section*
Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
- elfcpp::Elf_Xword flags, bool is_interp,
- bool is_dynamic_linker_section, bool is_relro,
- bool is_last_relro, bool is_first_non_relro)
+ elfcpp::Elf_Xword flags,
+ Output_section_order order, bool is_relro)
{
Output_section* os;
if ((flags & elfcpp::SHF_ALLOC) == 0
os = target->make_output_section(name, type, flags);
}
- if (is_interp)
- os->set_is_interp();
- if (is_dynamic_linker_section)
- os->set_is_dynamic_linker_section();
+ // With -z relro, we have to recognize the special sections by name.
+ // There is no other way.
+ bool is_relro_local = false;
+ if (!this->script_options_->saw_sections_clause()
+ && parameters->options().relro()
+ && type == elfcpp::SHT_PROGBITS
+ && (flags & elfcpp::SHF_ALLOC) != 0
+ && (flags & elfcpp::SHF_WRITE) != 0)
+ {
+ if (strcmp(name, ".data.rel.ro") == 0)
+ is_relro = true;
+ else if (strcmp(name, ".data.rel.ro.local") == 0)
+ {
+ is_relro = true;
+ is_relro_local = true;
+ }
+ else if (type == elfcpp::SHT_INIT_ARRAY
+ || type == elfcpp::SHT_FINI_ARRAY
+ || type == elfcpp::SHT_PREINIT_ARRAY)
+ is_relro = true;
+ else if (strcmp(name, ".ctors") == 0
+ || strcmp(name, ".dtors") == 0
+ || strcmp(name, ".jcr") == 0)
+ is_relro = true;
+ }
+
if (is_relro)
os->set_is_relro();
- if (is_last_relro)
- os->set_is_last_relro();
- if (is_first_non_relro)
- os->set_is_first_non_relro();
+
+ if (order == ORDER_INVALID && (flags & elfcpp::SHF_ALLOC) != 0)
+ order = this->default_section_order(os, is_relro_local);
+
+ os->set_order(order);
parameters->target().new_output_section(os);
|| strcmp(name, ".fini_array") == 0))
os->set_may_sort_attached_input_sections();
- // With -z relro, we have to recognize the special sections by name.
- // There is no other way.
- if (!this->script_options_->saw_sections_clause()
- && parameters->options().relro()
- && type == elfcpp::SHT_PROGBITS
- && (flags & elfcpp::SHF_ALLOC) != 0
- && (flags & elfcpp::SHF_WRITE) != 0)
- {
- if (strcmp(name, ".data.rel.ro") == 0)
- os->set_is_relro();
- else if (strcmp(name, ".data.rel.ro.local") == 0)
- {
- os->set_is_relro();
- os->set_is_relro_local();
- }
- }
-
// Check for .stab*str sections, as .stab* sections need to link to
// them.
if (type == elfcpp::SHT_STRTAB
return os;
}
+// Return the default order in which a section should be placed in an
+// output segment. This function captures a lot of the ideas in
+// ld/scripttempl/elf.sc in the GNU linker. Note that the order of a
+// linker created section is normally set when the section is created;
+// this function is used for input sections.
+
+Output_section_order
+Layout::default_section_order(Output_section* os, bool is_relro_local)
+{
+ gold_assert((os->flags() & elfcpp::SHF_ALLOC) != 0);
+ bool is_write = (os->flags() & elfcpp::SHF_WRITE) != 0;
+ bool is_execinstr = (os->flags() & elfcpp::SHF_EXECINSTR) != 0;
+ bool is_bss = false;
+
+ switch (os->type())
+ {
+ default:
+ case elfcpp::SHT_PROGBITS:
+ break;
+ case elfcpp::SHT_NOBITS:
+ is_bss = true;
+ break;
+ case elfcpp::SHT_RELA:
+ case elfcpp::SHT_REL:
+ if (!is_write)
+ return ORDER_DYNAMIC_RELOCS;
+ break;
+ case elfcpp::SHT_HASH:
+ case elfcpp::SHT_DYNAMIC:
+ case elfcpp::SHT_SHLIB:
+ case elfcpp::SHT_DYNSYM:
+ case elfcpp::SHT_GNU_HASH:
+ case elfcpp::SHT_GNU_verdef:
+ case elfcpp::SHT_GNU_verneed:
+ case elfcpp::SHT_GNU_versym:
+ if (!is_write)
+ return ORDER_DYNAMIC_LINKER;
+ break;
+ case elfcpp::SHT_NOTE:
+ return is_write ? ORDER_RW_NOTE : ORDER_RO_NOTE;
+ }
+
+ if ((os->flags() & elfcpp::SHF_TLS) != 0)
+ return is_bss ? ORDER_TLS_BSS : ORDER_TLS_DATA;
+
+ if (!is_bss && !is_write)
+ {
+ if (is_execinstr)
+ {
+ if (strcmp(os->name(), ".init") == 0)
+ return ORDER_INIT;
+ else if (strcmp(os->name(), ".fini") == 0)
+ return ORDER_FINI;
+ }
+ return is_execinstr ? ORDER_TEXT : ORDER_READONLY;
+ }
+
+ if (os->is_relro())
+ return is_relro_local ? ORDER_RELRO_LOCAL : ORDER_RELRO;
+
+ if (os->is_small_section())
+ return is_bss ? ORDER_SMALL_BSS : ORDER_SMALL_DATA;
+ if (os->is_large_section())
+ return is_bss ? ORDER_LARGE_BSS : ORDER_LARGE_DATA;
+
+ return is_bss ? ORDER_BSS : ORDER_DATA;
+}
+
// Attach output sections to segments. This is called after we have
// seen all the input sections.
break;
}
- (*p)->add_output_section(os, seg_flags, true);
+ (*p)->add_output_section_to_load(this, os, seg_flags);
break;
}
seg_flags);
if (os->is_large_data_section())
oseg->set_is_large_data_segment();
- oseg->add_output_section(os, seg_flags, true);
+ oseg->add_output_section_to_load(this, os, seg_flags);
if (is_address_set)
oseg->set_addresses(addr, addr);
}
&& (((*p)->flags() & elfcpp::PF_W)
== (seg_flags & elfcpp::PF_W)))
{
- (*p)->add_output_section(os, seg_flags, false);
+ (*p)->add_output_section_to_nonload(os, seg_flags);
break;
}
}
{
Output_segment* oseg = this->make_output_segment(elfcpp::PT_NOTE,
seg_flags);
- oseg->add_output_section(os, seg_flags, false);
+ oseg->add_output_section_to_nonload(os, seg_flags);
}
}
{
if (this->tls_segment_ == NULL)
this->make_output_segment(elfcpp::PT_TLS, seg_flags);
- this->tls_segment_->add_output_section(os, seg_flags, false);
+ this->tls_segment_->add_output_section_to_nonload(os, seg_flags);
}
// If -z relro is in effect, and we see a relro section, we create a
gold_assert(seg_flags == (elfcpp::PF_R | elfcpp::PF_W));
if (this->relro_segment_ == NULL)
this->make_output_segment(elfcpp::PT_GNU_RELRO, seg_flags);
- this->relro_segment_->add_output_section(os, seg_flags, false);
+ this->relro_segment_->add_output_section_to_nonload(os, seg_flags);
}
}
if (section_type == Script_sections::ST_NOLOAD)
sh_flags = 0;
Output_section* os = this->make_output_section(name, elfcpp::SHT_PROGBITS,
- sh_flags, false,
- false, false, false, false);
+ sh_flags, ORDER_INVALID,
+ false);
os->set_found_in_sections_clause();
if (section_type == Script_sections::ST_NOLOAD)
os->set_is_noload();
elfcpp::SHT_DYNAMIC,
(elfcpp::SHF_ALLOC
| elfcpp::SHF_WRITE),
- false, false, true,
- true, false, false);
+ false, ORDER_RELRO,
+ true);
this->dynamic_symbol_ =
symtab->define_in_output_data("_DYNAMIC", NULL, Symbol_table::PREDEFINED,
memcpy(buffer + 3 * (size / 8), name, namesz);
elfcpp::Elf_Xword flags = 0;
+ Output_section_order order = ORDER_INVALID;
if (allocate)
- flags = elfcpp::SHF_ALLOC;
+ {
+ flags = elfcpp::SHF_ALLOC;
+ order = ORDER_RO_NOTE;
+ }
Output_section* os = this->choose_output_section(NULL, section_name,
elfcpp::SHT_NOTE,
- flags, false, false,
- false, false, false, false);
+ flags, false, order, false);
if (os == NULL)
return NULL;
elfcpp::Elf_Xword flags = 0;
if (is_stack_executable)
flags |= elfcpp::SHF_EXECINSTR;
- this->make_output_section(name, elfcpp::SHT_PROGBITS, flags, false,
- false, false, false, false);
+ this->make_output_section(name, elfcpp::SHT_PROGBITS, flags,
+ ORDER_INVALID, false);
}
else
{
Output_section* inputs_os =
this->make_output_section(incremental_inputs_name,
elfcpp::SHT_GNU_INCREMENTAL_INPUTS, 0,
- false, false, false, false, false);
+ ORDER_INVALID, false);
Output_section_data* posd =
this->incremental_inputs_->create_incremental_inputs_section_data();
inputs_os->add_output_section_data(posd);
this->namepool_.add(".gnu_incremental_strtab", false, NULL);
Output_section* strtab_os = this->make_output_section(incremental_strtab_name,
elfcpp::SHT_STRTAB,
- 0, false, false,
- false, false, false);
+ 0, ORDER_INVALID,
+ false);
Output_data_strtab* strtab_data =
new Output_data_strtab(this->incremental_inputs_->get_stringpool());
strtab_os->add_output_section_data(strtab_data);
const char* symtab_name = this->namepool_.add(".symtab", false, NULL);
Output_section* osymtab = this->make_output_section(symtab_name,
elfcpp::SHT_SYMTAB,
- 0, false, false,
- false, false, false);
+ 0, ORDER_INVALID,
+ false);
this->symtab_section_ = osymtab;
Output_section_data* pos = new Output_data_fixed_space(off - startoff,
false, NULL);
Output_section* osymtab_xindex =
this->make_output_section(symtab_xindex_name,
- elfcpp::SHT_SYMTAB_SHNDX, 0, false,
- false, false, false, false);
+ elfcpp::SHT_SYMTAB_SHNDX, 0,
+ ORDER_INVALID, false);
size_t symcount = (off - startoff) / symsize;
this->symtab_xindex_ = new Output_symtab_xindex(symcount);
const char* strtab_name = this->namepool_.add(".strtab", false, NULL);
Output_section* ostrtab = this->make_output_section(strtab_name,
elfcpp::SHT_STRTAB,
- 0, false, false,
- false, false, false);
+ 0, ORDER_INVALID,
+ false);
Output_section_data* pstr = new Output_data_strtab(&this->sympool_);
ostrtab->add_output_section_data(pstr);
const char* name = this->namepool_.add(".shstrtab", false, NULL);
Output_section* os = this->make_output_section(name, elfcpp::SHT_STRTAB, 0,
- false, false, false, false,
- false);
+ ORDER_INVALID, false);
if (strcmp(parameters->options().compress_debug_sections(), "none") != 0)
{
Output_section* dynsym = this->choose_output_section(NULL, ".dynsym",
elfcpp::SHT_DYNSYM,
elfcpp::SHF_ALLOC,
- false, false, true,
- false, false, false);
+ false,
+ ORDER_DYNAMIC_LINKER,
+ false);
Output_section_data* odata = new Output_data_fixed_space(index * symsize,
align,
this->choose_output_section(NULL, ".dynsym_shndx",
elfcpp::SHT_SYMTAB_SHNDX,
elfcpp::SHF_ALLOC,
- false, false, true, false, false, false);
+ false, ORDER_DYNAMIC_LINKER, false);
this->dynsym_xindex_ = new Output_symtab_xindex(index);
Output_section* dynstr = this->choose_output_section(NULL, ".dynstr",
elfcpp::SHT_STRTAB,
elfcpp::SHF_ALLOC,
- false, false, true,
- false, false, false);
+ false,
+ ORDER_DYNAMIC_LINKER,
+ false);
Output_section_data* strdata = new Output_data_strtab(&this->dynpool_);
dynstr->add_output_section_data(strdata);
Dynobj::create_elf_hash_table(*pdynamic_symbols, local_symcount,
&phash, &hashlen);
- Output_section* hashsec = this->choose_output_section(NULL, ".hash",
- elfcpp::SHT_HASH,
- elfcpp::SHF_ALLOC,
- false, false, true,
- false, false,
- false);
+ Output_section* hashsec =
+ this->choose_output_section(NULL, ".hash", elfcpp::SHT_HASH,
+ elfcpp::SHF_ALLOC, false,
+ ORDER_DYNAMIC_LINKER, false);
Output_section_data* hashdata = new Output_data_const_buffer(phash,
hashlen,
Dynobj::create_gnu_hash_table(*pdynamic_symbols, local_symcount,
&phash, &hashlen);
- Output_section* hashsec = this->choose_output_section(NULL, ".gnu.hash",
- elfcpp::SHT_GNU_HASH,
- elfcpp::SHF_ALLOC,
- false, false, true,
- false, false,
- false);
+ Output_section* hashsec =
+ this->choose_output_section(NULL, ".gnu.hash", elfcpp::SHT_GNU_HASH,
+ elfcpp::SHF_ALLOC, false,
+ ORDER_DYNAMIC_LINKER, false);
Output_section_data* hashdata = new Output_data_const_buffer(phash,
hashlen,
Output_section* vsec = this->choose_output_section(NULL, ".gnu.version",
elfcpp::SHT_GNU_versym,
elfcpp::SHF_ALLOC,
- false, false, true,
- false, false, false);
+ false,
+ ORDER_DYNAMIC_LINKER,
+ false);
unsigned char* vbuf;
unsigned int vsize;
vdsec= this->choose_output_section(NULL, ".gnu.version_d",
elfcpp::SHT_GNU_verdef,
elfcpp::SHF_ALLOC,
- false, false, true, false, false,
- false);
+ false, ORDER_DYNAMIC_LINKER, false);
unsigned char* vdbuf;
unsigned int vdsize;
vnsec = this->choose_output_section(NULL, ".gnu.version_r",
elfcpp::SHT_GNU_verneed,
elfcpp::SHF_ALLOC,
- false, false, true, false, false,
- false);
+ false, ORDER_DYNAMIC_LINKER, false);
unsigned char* vnbuf;
unsigned int vnsize;
Output_section* osec = this->choose_output_section(NULL, ".interp",
elfcpp::SHT_PROGBITS,
elfcpp::SHF_ALLOC,
- false, true, true,
- false, false, false);
+ false, ORDER_INTERP,
+ false);
osec->add_output_section_data(odata);
if (!this->script_options_->saw_phdrs_clause())
{
Output_segment* oseg = this->make_output_segment(elfcpp::PT_INTERP,
elfcpp::PF_R);
- oseg->add_output_section(osec, elfcpp::PF_R, false);
+ oseg->add_output_section_to_nonload(osec, elfcpp::PF_R);
}
}
Output_segment* oseg = this->make_output_segment(elfcpp::PT_DYNAMIC,
(elfcpp::PF_R
| elfcpp::PF_W));
- oseg->add_output_section(this->dynamic_section_,
- elfcpp::PF_R | elfcpp::PF_W,
- false);
+ oseg->add_output_section_to_nonload(this->dynamic_section_,
+ elfcpp::PF_R | elfcpp::PF_W);
}
Output_data_dynamic* const odyn = this->dynamic_data_;
++p)
{
if (((*p)->flags() & elfcpp::PF_W) == 0
- && (*p)->dynamic_reloc_count() > 0)
+ && (*p)->has_dynamic_reloc())
{
have_textrel = true;
break;
{
if (((*p)->flags() & elfcpp::SHF_ALLOC) != 0
&& ((*p)->flags() & elfcpp::SHF_WRITE) == 0
- && ((*p)->dynamic_reloc_count() > 0))
+ && ((*p)->has_dynamic_reloc()))
{
have_textrel = true;
break;
} u_;
};
+// The ordering for output sections. This controls how output
+// sections are ordered within a PT_LOAD output segment.
+
+enum Output_section_order
+{
+ // Unspecified. Used for non-load segments. Also used for the file
+ // and segment headers.
+ ORDER_INVALID,
+
+ // The PT_INTERP section should come first, so that the dynamic
+ // linker can pick it up quickly.
+ ORDER_INTERP,
+
+ // Loadable read-only note sections come next so that the PT_NOTE
+ // segment is on the first page of the executable.
+ ORDER_RO_NOTE,
+
+ // Put read-only sections used by the dynamic linker early in the
+ // executable to minimize paging.
+ ORDER_DYNAMIC_LINKER,
+
+ // Put reloc sections used by the dynamic linker after other
+ // sections used by the dynamic linker; otherwise, objcopy and strip
+ // get confused.
+ ORDER_DYNAMIC_RELOCS,
+
+ // Put the PLT reloc section after the other dynamic relocs;
+ // otherwise, prelink gets foncused.
+ ORDER_DYNAMIC_PLT_RELOCS,
+
+ // The .init section.
+ ORDER_INIT,
+
+ // The PLT.
+ ORDER_PLT,
+
+ // The regular text sections.
+ ORDER_TEXT,
+
+ // The .fini section.
+ ORDER_FINI,
+
+ // The read-only sections.
+ ORDER_READONLY,
+
+ // The exception frame sections.
+ ORDER_EHFRAME,
+
+ // The TLS sections come first in the data section.
+ ORDER_TLS_DATA,
+ ORDER_TLS_BSS,
+
+ // Local RELRO (read-only after relocation) sections come before
+ // non-local RELRO sections. This data will be fully resolved by
+ // the prelinker.
+ ORDER_RELRO_LOCAL,
+
+ // Non-local RELRO sections are grouped together after local RELRO
+ // sections. All RELRO sections must be adjacent so that they can
+ // all be put into a PT_GNU_RELRO segment.
+ ORDER_RELRO,
+
+ // We permit marking exactly one output section as the last RELRO
+ // section. We do this so that the read-only GOT can be adjacent to
+ // the writable GOT.
+ ORDER_RELRO_LAST,
+
+ // Similarly, we permit marking exactly one output section as the
+ // first non-RELRO section.
+ ORDER_NON_RELRO_FIRST,
+
+ // The regular data sections come after the RELRO sections.
+ ORDER_DATA,
+
+ // Large data sections normally go in large data segments.
+ ORDER_LARGE_DATA,
+
+ // Group writable notes so that we can have a single PT_NOTE
+ // segment.
+ ORDER_RW_NOTE,
+
+ // The small data sections must be at the end of the data sections,
+ // so that they can be adjacent to the small BSS sections.
+ ORDER_SMALL_DATA,
+
+ // The BSS sections start here.
+
+ // The small BSS sections must be at the start of the BSS sections,
+ // so that they can be adjacent to the small data sections.
+ ORDER_SMALL_BSS,
+
+ // The regular BSS sections.
+ ORDER_BSS,
+
+ // The large BSS sections come after the other BSS sections.
+ ORDER_LARGE_BSS,
+
+ // Maximum value.
+ ORDER_MAX
+};
+
// This class handles the details of laying out input sections.
class Layout
layout_gnu_stack(bool seen_gnu_stack, uint64_t gnu_stack_flags);
// Add an Output_section_data to the layout. This is used for
- // special sections like the GOT section. IS_DYNAMIC_LINKER_SECTION
- // is true for sections which are used by the dynamic linker, such
- // as dynamic reloc sections. IS_RELRO is true for relro sections.
- // IS_LAST_RELRO is true for the last relro section.
- // IS_FIRST_NON_RELRO is true for the first section after the relro
- // sections.
+ // special sections like the GOT section. ORDER is where the
+ // section should wind up in the output segment. IS_RELRO is true
+ // for relro sections.
Output_section*
add_output_section_data(const char* name, elfcpp::Elf_Word type,
elfcpp::Elf_Xword flags,
- Output_section_data*, bool is_dynamic_linker_section,
- bool is_relro, bool is_last_relro,
- bool is_first_non_relro);
+ Output_section_data*, Output_section_order order,
+ bool is_relro);
// Increase the size of the relro segment by this much.
void
Output_section*
get_output_section(const char* name, Stringpool::Key name_key,
elfcpp::Elf_Word type, elfcpp::Elf_Xword flags,
- bool is_interp, bool is_dynamic_linker_section,
- bool is_relro, bool is_last_relro,
- bool is_first_non_relro);
+ Output_section_order order, bool is_relro);
// Choose the output section for NAME in RELOBJ.
Output_section*
choose_output_section(const Relobj* relobj, const char* name,
elfcpp::Elf_Word type, elfcpp::Elf_Xword flags,
- bool is_input_section, bool is_interp,
- bool is_dynamic_linker_section, bool is_relro,
- bool is_last_relro, bool is_first_non_relro);
+ bool is_input_section, Output_section_order order,
+ bool is_relro);
// Create a new Output_section.
Output_section*
make_output_section(const char* name, elfcpp::Elf_Word type,
- elfcpp::Elf_Xword flags, bool is_interp,
- bool is_dynamic_linker_section, bool is_relro,
- bool is_last_relro, bool is_first_non_relro);
+ elfcpp::Elf_Xword flags, Output_section_order order,
+ bool is_relro);
// Attach a section to a segment.
void
attach_section_to_segment(Output_section*);
+ // Get section order.
+ Output_section_order
+ default_section_order(Output_section*, bool is_relro_local);
+
// Attach an allocated section to a segment.
void
attach_allocated_section_to_segment(Output_section*);
info_(0),
type_(type),
flags_(flags),
+ order_(ORDER_INVALID),
out_shndx_(-1U),
symtab_index_(0),
dynsym_index_(0),
must_sort_attached_input_sections_(false),
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),
// Output segment methods.
Output_segment::Output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags)
- : output_data_(),
- output_bss_(),
- vaddr_(0),
+ : vaddr_(0),
paddr_(0),
memsz_(0),
max_align_(0),
this->flags_ = elfcpp::PF_R;
}
-// Add an Output_section to an Output_segment.
+// Add an Output_section to a PT_LOAD Output_segment.
void
-Output_segment::add_output_section(Output_section* os,
- elfcpp::Elf_Word seg_flags,
- bool do_sort)
+Output_segment::add_output_section_to_load(Layout* layout,
+ Output_section* os,
+ elfcpp::Elf_Word seg_flags)
{
+ gold_assert(this->type() == elfcpp::PT_LOAD);
gold_assert((os->flags() & elfcpp::SHF_ALLOC) != 0);
gold_assert(!this->is_max_align_known_);
gold_assert(os->is_large_data_section() == this->is_large_data_segment());
- gold_assert(this->type() == elfcpp::PT_LOAD || !do_sort);
this->update_flags_for_output_section(seg_flags);
- Output_segment::Output_data_list* pdl;
- if (os->type() == elfcpp::SHT_NOBITS)
- pdl = &this->output_bss_;
+ // We don't want to change the ordering if we have a linker script
+ // with a SECTIONS clause.
+ Output_section_order order = os->order();
+ if (layout->script_options()->saw_sections_clause())
+ order = static_cast<Output_section_order>(0);
else
- pdl = &this->output_data_;
+ gold_assert(order != ORDER_INVALID);
- // Note that while there may be many input sections in an output
- // section, there are normally only a few output sections in an
- // output segment. The loops below are expected to be fast.
-
- // So that PT_NOTE segments will work correctly, we need to ensure
- // that all SHT_NOTE sections are adjacent.
- if (os->type() == elfcpp::SHT_NOTE && !pdl->empty())
- {
- Output_segment::Output_data_list::iterator p = pdl->end();
- do
- {
- --p;
- if ((*p)->is_section_type(elfcpp::SHT_NOTE))
- {
- ++p;
- pdl->insert(p, os);
- return;
- }
- }
- while (p != pdl->begin());
- }
-
- // Similarly, so that PT_TLS segments will work, we need to group
- // SHF_TLS sections. An SHF_TLS/SHT_NOBITS section is a special
- // case: we group the SHF_TLS/SHT_NOBITS sections right after the
- // SHF_TLS/SHT_PROGBITS sections. This lets us set up PT_TLS
- // correctly. SHF_TLS sections get added to both a PT_LOAD segment
- // and the PT_TLS segment; we do this grouping only for the PT_LOAD
- // segment.
- if (this->type_ != elfcpp::PT_TLS
- && (os->flags() & elfcpp::SHF_TLS) != 0)
- {
- pdl = &this->output_data_;
- if (!pdl->empty())
- {
- 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
- {
- --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;
- }
- }
- while (p != pdl->begin());
- }
-
- // There are no TLS sections yet; put this one at the requested
- // location in the section list.
- }
-
- if (do_sort)
- {
- // 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())
- {
- 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())
- || (!os->is_last_relro() && pos->is_last_relro()))
- break;
- }
-
- pdl->insert(p, os);
- return;
- }
+ this->output_lists_[order].push_back(os);
+}
- // 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;
+// Add an Output_section to a non-PT_LOAD Output_segment.
- Output_section* pos = (*p)->output_section();
- if (!pos->is_relro())
- break;
- }
+void
+Output_segment::add_output_section_to_nonload(Output_section* os,
+ elfcpp::Elf_Word seg_flags)
+{
+ gold_assert(this->type() != elfcpp::PT_LOAD);
+ gold_assert((os->flags() & elfcpp::SHF_ALLOC) != 0);
+ gold_assert(!this->is_max_align_known_);
- pdl->insert(p, os);
- return;
- }
- }
+ this->update_flags_for_output_section(seg_flags);
- // Small data sections go at the end of the list of data sections.
- // If OS is not small, and there are small sections, we have to
- // insert it before the first small section.
- if (os->type() != elfcpp::SHT_NOBITS
- && !os->is_small_section()
- && !pdl->empty()
- && pdl->back()->is_section()
- && pdl->back()->output_section()->is_small_section())
- {
- for (Output_segment::Output_data_list::iterator p = pdl->begin();
- p != pdl->end();
- ++p)
- {
- if ((*p)->is_section()
- && (*p)->output_section()->is_small_section())
- {
- pdl->insert(p, os);
- return;
- }
- }
- gold_unreachable();
- }
+ this->output_lists_[0].push_back(os);
+}
- // A small BSS section goes at the start of the BSS sections, after
- // other small BSS sections.
- if (os->type() == elfcpp::SHT_NOBITS && os->is_small_section())
- {
- for (Output_segment::Output_data_list::iterator p = pdl->begin();
- p != pdl->end();
- ++p)
- {
- if (!(*p)->is_section()
- || !(*p)->output_section()->is_small_section())
- {
- pdl->insert(p, os);
- return;
- }
- }
- }
+// Remove an Output_section from this segment. It is an error if it
+// is not present.
- // A large BSS section goes at the end of the BSS sections, which
- // means that one that is not large must come before the first large
- // one.
- if (os->type() == elfcpp::SHT_NOBITS
- && !os->is_large_section()
- && !pdl->empty()
- && pdl->back()->is_section()
- && pdl->back()->output_section()->is_large_section())
+void
+Output_segment::remove_output_section(Output_section* os)
+{
+ for (int i = 0; i < static_cast<int>(ORDER_MAX); ++i)
{
- for (Output_segment::Output_data_list::iterator p = pdl->begin();
- p != pdl->end();
- ++p)
+ Output_data_list* pdl = &this->output_lists_[i];
+ for (Output_data_list::iterator p = pdl->begin(); p != pdl->end(); ++p)
{
- if ((*p)->is_section()
- && (*p)->output_section()->is_large_section())
+ if (*p == os)
{
- pdl->insert(p, os);
+ pdl->erase(p);
return;
}
}
- gold_unreachable();
- }
-
- // We do some further output section sorting in order to make the
- // generated program run more efficiently. We should only do this
- // when not using a linker script, so it is controled by the DO_SORT
- // parameter.
- if (do_sort)
- {
- // FreeBSD requires the .interp section to be in the first page
- // of the executable. That is a more efficient location anyhow
- // for any OS, since it means that the kernel will have the data
- // handy after it reads the program headers.
- if (os->is_interp() && !pdl->empty())
- {
- pdl->insert(pdl->begin(), os);
- return;
- }
-
- // Put loadable non-writable notes immediately after the .interp
- // sections, so that the PT_NOTE segment is on the first page of
- // the executable.
- if (os->type() == elfcpp::SHT_NOTE
- && (os->flags() & elfcpp::SHF_WRITE) == 0
- && !pdl->empty())
- {
- Output_segment::Output_data_list::iterator p = pdl->begin();
- if ((*p)->is_section() && (*p)->output_section()->is_interp())
- ++p;
- pdl->insert(p, os);
- return;
- }
-
- // If this section is used by the dynamic linker, and it is not
- // writable, then put it first, after the .interp section and
- // any loadable notes. This makes it more likely that the
- // dynamic linker will have to read less data from the disk.
- if (os->is_dynamic_linker_section()
- && !pdl->empty()
- && (os->flags() & elfcpp::SHF_WRITE) == 0)
- {
- bool is_reloc = (os->type() == elfcpp::SHT_REL
- || os->type() == elfcpp::SHT_RELA);
- Output_segment::Output_data_list::iterator p = pdl->begin();
- while (p != pdl->end()
- && (*p)->is_section()
- && ((*p)->output_section()->is_dynamic_linker_section()
- || (*p)->output_section()->type() == elfcpp::SHT_NOTE))
- {
- // Put reloc sections after the other ones. Putting the
- // dynamic reloc sections first confuses BFD, notably
- // objcopy and strip.
- if (!is_reloc
- && ((*p)->output_section()->type() == elfcpp::SHT_REL
- || (*p)->output_section()->type() == elfcpp::SHT_RELA))
- break;
- ++p;
- }
- pdl->insert(p, os);
- return;
- }
}
-
- // If there were no constraints on the output section, just add it
- // to the end of the list.
- pdl->push_back(os);
-}
-
-// Remove an Output_section from this segment. It is an error if it
-// is not present.
-
-void
-Output_segment::remove_output_section(Output_section* os)
-{
- // We only need this for SHT_PROGBITS.
- gold_assert(os->type() == elfcpp::SHT_PROGBITS);
- for (Output_data_list::iterator p = this->output_data_.begin();
- p != this->output_data_.end();
- ++p)
- {
- if (*p == os)
- {
- this->output_data_.erase(p);
- return;
- }
- }
gold_unreachable();
}
Output_segment::add_initial_output_data(Output_data* od)
{
gold_assert(!this->is_max_align_known_);
- this->output_data_.push_front(od);
+ Output_data_list::iterator p = this->output_lists_[0].begin();
+ this->output_lists_[0].insert(p, od);
+}
+
+// Return true if this segment has any sections which hold actual
+// data, rather than being a BSS section.
+
+bool
+Output_segment::has_any_data_sections() const
+{
+ for (int i = 0; i < static_cast<int>(ORDER_MAX); ++i)
+ {
+ const Output_data_list* pdl = &this->output_lists_[i];
+ for (Output_data_list::const_iterator p = pdl->begin();
+ p != pdl->end();
+ ++p)
+ {
+ if (!(*p)->is_section())
+ return true;
+ if ((*p)->output_section()->type() != elfcpp::SHT_NOBITS)
+ return true;
+ }
+ }
+ return false;
}
// Return whether the first data section is a relro section.
bool
Output_segment::is_first_section_relro() const
{
- return (!this->output_data_.empty()
- && this->output_data_.front()->is_section()
- && this->output_data_.front()->output_section()->is_relro());
+ for (int i = 0; i < static_cast<int>(ORDER_MAX); ++i)
+ {
+ const Output_data_list* pdl = &this->output_lists_[i];
+ if (!pdl->empty())
+ {
+ Output_data* p = pdl->front();
+ return p->is_section() && p->output_section()->is_relro();
+ }
+ }
+ return false;
}
// Return the maximum alignment of the Output_data in Output_segment.
{
if (!this->is_max_align_known_)
{
- uint64_t addralign;
-
- addralign = Output_segment::maximum_alignment_list(&this->output_data_);
- if (addralign > this->max_align_)
- this->max_align_ = addralign;
-
- addralign = Output_segment::maximum_alignment_list(&this->output_bss_);
- if (addralign > this->max_align_)
- this->max_align_ = addralign;
-
+ for (int i = 0; i < static_cast<int>(ORDER_MAX); ++i)
+ {
+ const Output_data_list* pdl = &this->output_lists_[i];
+ uint64_t addralign = Output_segment::maximum_alignment_list(pdl);
+ if (addralign > this->max_align_)
+ this->max_align_ = addralign;
+ }
this->is_max_align_known_ = true;
}
return ret;
}
-// Return the number of dynamic relocs applied to this segment.
+// Return whether this segment has any dynamic relocs.
-unsigned int
-Output_segment::dynamic_reloc_count() const
+bool
+Output_segment::has_dynamic_reloc() const
{
- return (this->dynamic_reloc_count_list(&this->output_data_)
- + this->dynamic_reloc_count_list(&this->output_bss_));
+ for (int i = 0; i < static_cast<int>(ORDER_MAX); ++i)
+ if (this->has_dynamic_reloc_list(&this->output_lists_[i]))
+ return true;
+ return false;
}
-// Return the number of dynamic relocs applied to an Output_data_list.
+// Return whether this Output_data_list has any dynamic relocs.
-unsigned int
-Output_segment::dynamic_reloc_count_list(const Output_data_list* pdl) const
+bool
+Output_segment::has_dynamic_reloc_list(const Output_data_list* pdl) const
{
- unsigned int count = 0;
for (Output_data_list::const_iterator p = pdl->begin();
p != pdl->end();
++p)
- count += (*p)->dynamic_reloc_count();
- return count;
+ if ((*p)->has_dynamic_reloc())
+ return true;
+ return false;
}
// Set the section addresses for an Output_segment. If RESET is true,
{
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)
+ for (int i = 0; i < static_cast<int>(ORDER_MAX); ++i)
{
- 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
+ Output_data_list* pdl = &this->output_lists_[i];
+ Output_data_list::iterator p;
+ for (p = pdl->begin(); p != pdl->end(); ++p)
{
- // 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();
+ if (!(*p)->is_section())
+ break;
+ Output_section* pos = (*p)->output_section();
+ if (!pos->is_relro())
+ break;
+ 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();
+ }
}
+ if (p != pdl->end())
+ break;
}
relro_size += increase_relro;
this->offset_ = orig_off;
- addr = this->set_section_list_addresses(layout, reset, &this->output_data_,
- addr, poff, pshndx, &in_tls);
- this->filesz_ = *poff - orig_off;
-
- off_t off = *poff;
+ off_t off = 0;
+ uint64_t ret;
+ for (int i = 0; i < static_cast<int>(ORDER_MAX); ++i)
+ {
+ addr = this->set_section_list_addresses(layout, reset,
+ &this->output_lists_[i],
+ addr, poff, pshndx, &in_tls);
+ if (i < static_cast<int>(ORDER_SMALL_BSS))
+ {
+ this->filesz_ = *poff - orig_off;
+ off = *poff;
+ }
- uint64_t ret = this->set_section_list_addresses(layout, reset,
- &this->output_bss_,
- addr, poff, pshndx,
- &in_tls);
+ ret = addr;
+ }
// 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
gold_assert(!this->are_addresses_set_);
- if (this->output_data_.empty() && this->output_bss_.empty())
+ // A non-load section only uses output_lists_[0].
+
+ Output_data_list* pdl = &this->output_lists_[0];
+
+ if (pdl->empty())
{
gold_assert(increase == 0);
this->vaddr_ = 0;
return;
}
- // Find the first and last section by address. The sections may
- // have been sorted for the PT_LOAD segment.
+ // Find the first and last section by address.
const Output_data* first = NULL;
const Output_data* last_data = NULL;
const Output_data* last_bss = NULL;
- this->find_first_and_last_list(&this->output_data_, &first, &last_data);
- this->find_first_and_last_list(&this->output_bss_, &first, &last_bss);
+ for (Output_data_list::const_iterator p = pdl->begin();
+ p != pdl->end();
+ ++p)
+ {
+ if (first == NULL
+ || (*p)->address() < first->address()
+ || ((*p)->address() == first->address()
+ && (*p)->data_size() < first->data_size()))
+ first = *p;
+ const Output_data** plast;
+ if ((*p)->is_section()
+ && (*p)->output_section()->type() == elfcpp::SHT_NOBITS)
+ plast = &last_bss;
+ else
+ plast = &last_data;
+ if (*plast == NULL
+ || (*p)->address() > (*plast)->address()
+ || ((*p)->address() == (*plast)->address()
+ && (*p)->data_size() > (*plast)->data_size()))
+ *plast = *p;
+ }
this->vaddr_ = first->address();
this->paddr_ = (first->has_load_address()
this->are_addresses_set_ = true;
this->offset_ = first->offset();
- if (this->output_data_.empty())
+ if (last_data == NULL)
this->filesz_ = 0;
else
this->filesz_ = (last_data->address()
}
}
-// Look through a list of Output_data objects and find the first and
-// last by address.
-
-void
-Output_segment::find_first_and_last_list(const Output_data_list* pdl,
- const Output_data** pfirst,
- const Output_data** plast) const
-{
- const Output_data* first = *pfirst;
- const Output_data* last = *plast;
- for (Output_data_list::const_iterator p = pdl->begin(); p != pdl->end(); ++p)
- {
- if (first == NULL
- || (*p)->address() < first->address()
- || ((*p)->address() == first->address()
- && (*p)->data_size() < first->data_size()))
- {
- first = *p;
- *pfirst = first;
- }
- if (last == NULL
- || (*p)->address() > last->address()
- || ((*p)->address() == last->address()
- && (*p)->data_size() > last->data_size()))
- {
- last = *p;
- *plast = last;
- }
- }
-}
-
// Set the TLS offsets of the sections in the PT_TLS segment.
void
{
gold_assert(this->type_ == elfcpp::PT_TLS);
- for (Output_data_list::iterator p = this->output_data_.begin();
- p != this->output_data_.end();
- ++p)
- (*p)->set_tls_offset(this->vaddr_);
-
- for (Output_data_list::iterator p = this->output_bss_.begin();
- p != this->output_bss_.end();
+ for (Output_data_list::iterator p = this->output_lists_[0].begin();
+ p != this->output_lists_[0].end();
++p)
(*p)->set_tls_offset(this->vaddr_);
}
-// Return the address of the first section.
+// Return the load address of the first section.
uint64_t
Output_segment::first_section_load_address() const
{
- for (Output_data_list::const_iterator p = this->output_data_.begin();
- p != this->output_data_.end();
- ++p)
- if ((*p)->is_section())
- return (*p)->has_load_address() ? (*p)->load_address() : (*p)->address();
-
- for (Output_data_list::const_iterator p = this->output_bss_.begin();
- p != this->output_bss_.end();
- ++p)
- if ((*p)->is_section())
- return (*p)->has_load_address() ? (*p)->load_address() : (*p)->address();
-
+ for (int i = 0; i < static_cast<int>(ORDER_MAX); ++i)
+ {
+ const Output_data_list* pdl = &this->output_lists_[i];
+ for (Output_data_list::const_iterator p = pdl->begin();
+ p != pdl->end();
+ ++p)
+ {
+ if ((*p)->is_section())
+ return ((*p)->has_load_address()
+ ? (*p)->load_address()
+ : (*p)->address());
+ }
+ }
gold_unreachable();
}
unsigned int
Output_segment::output_section_count() const
{
- return (this->output_section_count_list(&this->output_data_)
- + this->output_section_count_list(&this->output_bss_));
+ unsigned int ret = 0;
+ for (int i = 0; i < static_cast<int>(ORDER_MAX); ++i)
+ ret += this->output_section_count_list(&this->output_lists_[i]);
+ return ret;
}
// Return the number of Output_sections in an Output_data_list.
{
Output_section* found = NULL;
uint64_t found_lma = 0;
- this->lowest_load_address_in_list(&this->output_data_, &found, &found_lma);
-
- Output_section* found_data = found;
- this->lowest_load_address_in_list(&this->output_bss_, &found, &found_lma);
- if (found != found_data && found_data != NULL)
- {
- gold_error(_("nobits section %s may not precede progbits section %s "
- "in same segment"),
- found->name(), found_data->name());
- return NULL;
- }
-
+ for (int i = 0; i < static_cast<int>(ORDER_MAX); ++i)
+ this->lowest_load_address_in_list(&this->output_lists_[i], &found,
+ &found_lma);
return found;
}
if (this->type_ != elfcpp::PT_LOAD)
return v;
- v = this->write_section_headers_list<size, big_endian>(layout, secnamepool,
- &this->output_data_,
- v, pshndx);
- v = this->write_section_headers_list<size, big_endian>(layout, secnamepool,
- &this->output_bss_,
- v, pshndx);
+ for (int i = 0; i < static_cast<int>(ORDER_MAX); ++i)
+ {
+ const Output_data_list* pdl = &this->output_lists_[i];
+ v = this->write_section_headers_list<size, big_endian>(layout,
+ secnamepool,
+ pdl,
+ v, pshndx);
+ }
+
return v;
}
{
if (this->type() != elfcpp::PT_LOAD)
return;
- this->print_section_list_to_mapfile(mapfile, &this->output_data_);
- this->print_section_list_to_mapfile(mapfile, &this->output_bss_);
+ for (int i = 0; i < static_cast<int>(ORDER_MAX); ++i)
+ this->print_section_list_to_mapfile(mapfile, &this->output_lists_[i]);
}
// Print an output section list to the map file.
: address_(0), data_size_(0), offset_(-1),
is_address_valid_(false), is_data_size_valid_(false),
is_offset_valid_(false), is_data_size_fixed_(false),
- dynamic_reloc_count_(0)
+ has_dynamic_reloc_(false)
{ }
virtual
is_layout_complete()
{ return Output_data::allocated_sizes_are_fixed; }
- // Count the number of dynamic relocations applied to this section.
+ // Note that a dynamic reloc has been applied to this data.
void
add_dynamic_reloc()
- { ++this->dynamic_reloc_count_; }
+ { this->has_dynamic_reloc_ = true; }
- // Return the number of dynamic relocations applied to this section.
- unsigned int
- dynamic_reloc_count() const
- { return this->dynamic_reloc_count_; }
+ // Return whether a dynamic reloc has been applied.
+ bool
+ has_dynamic_reloc() const
+ { return this->has_dynamic_reloc_; }
// Whether the address is valid.
bool
// File offset of contents in output file.
off_t offset_;
// Whether address_ is valid.
- bool is_address_valid_;
+ bool is_address_valid_ : 1;
// Whether data_size_ is valid.
- bool is_data_size_valid_;
+ bool is_data_size_valid_ : 1;
// Whether offset_ is valid.
- bool is_offset_valid_;
+ bool is_offset_valid_ : 1;
// Whether data size is fixed.
- bool is_data_size_fixed_;
- // Count of dynamic relocations applied to this section.
- unsigned int dynamic_reloc_count_;
+ bool is_data_size_fixed_ : 1;
+ // Whether any dynamic relocs have been applied to this section.
+ bool has_dynamic_reloc_ : 1;
};
// Output the section headers.
set_must_sort_attached_input_sections()
{ this->must_sort_attached_input_sections_ = true; }
+ // Get the order in which this section appears in the PT_LOAD output
+ // segment.
+ Output_section_order
+ order() const
+ { return this->order_; }
+
+ // Set the order for this section.
+ void
+ set_order(Output_section_order order)
+ { this->order_ = order; }
+
// Return whether this section holds relro data--data which has
// dynamic relocations but which may be marked read-only after the
// dynamic relocations have been completed.
clear_is_relro()
{ this->is_relro_ = false; }
- // True if this section holds relro local data--relro data for which
- // the dynamic relocations are all RELATIVE relocations.
- bool
- is_relro_local() const
- { return this->is_relro_local_; }
-
- // Record that this section holds relro local data.
- void
- set_is_relro_local()
- { this->is_relro_local_ = true; }
-
- // True if this must be the last relro section.
- bool
- is_last_relro() const
- { return this->is_last_relro_; }
-
- // Record that this must be the last relro section.
- void
- set_is_last_relro()
- {
- gold_assert(this->is_relro_);
- this->is_last_relro_ = true;
- }
-
- // True if this must be the first section following the relro sections.
- bool
- is_first_non_relro() const
- {
- gold_assert(!this->is_relro_);
- return this->is_first_non_relro_;
- }
-
- // Record that this must be the first non-relro section.
- void
- set_is_first_non_relro()
- {
- gold_assert(!this->is_relro_);
- this->is_first_non_relro_ = true;
- }
-
// True if this is a small section: a section which holds small
// variables.
bool
is_large_data_section()
{ return this->is_large_section_ && this->type_ != elfcpp::SHT_NOBITS; }
- // True if this is the .interp section which goes into the PT_INTERP
- // segment.
- bool
- is_interp() const
- { return this->is_interp_; }
-
- // Record that this is the interp section.
- void
- set_is_interp()
- { this->is_interp_ = true; }
-
- // True if this is a section used by the dynamic linker.
- bool
- is_dynamic_linker_section() const
- { return this->is_dynamic_linker_section_; }
-
- // Record that this is a section used by the dynamic linker.
- void
- set_is_dynamic_linker_section()
- { this->is_dynamic_linker_section_ = true; }
-
// Return whether this section should be written after all the input
// sections are complete.
bool
const elfcpp::Elf_Word type_;
// The section flags.
elfcpp::Elf_Xword flags_;
+ // The order of this section in the output segment.
+ Output_section_order order_;
// The section index.
unsigned int out_shndx_;
// If there is a STT_SECTION for this output section in the normal
bool attached_input_sections_are_sorted_ : 1;
// True if this section holds relro data.
bool is_relro_ : 1;
- // True if this section holds relro local data.
- bool is_relro_local_ : 1;
- // True if this must be the last relro section.
- bool is_last_relro_ : 1;
- // True if this must be the first section after the relro sections.
- bool is_first_non_relro_ : 1;
// True if this is a small section.
bool is_small_section_ : 1;
// True if this is a large section.
bool is_large_section_ : 1;
- // True if this is the .interp section going into the PT_INTERP
- // segment.
- bool is_interp_ : 1;
- // True if this is section is read by the dynamic linker.
- bool is_dynamic_linker_section_ : 1;
// Whether code-fills are generated at write.
bool generate_code_fills_at_write_ : 1;
// Whether the entry size field should be zero.
uint64_t
maximum_alignment();
- // Add the Output_section OS to this segment. SEG_FLAGS is the
- // segment flags to use. DO_SORT is true if we should sort the
- // placement of the input section for more efficient generated code.
+ // Add the Output_section OS to this PT_LOAD segment. SEG_FLAGS is
+ // the segment flags to use.
+ void
+ add_output_section_to_load(Layout* layout, Output_section* os,
+ elfcpp::Elf_Word seg_flags);
+
+ // Add the Output_section OS to this non-PT_LOAD segment. SEG_FLAGS
+ // is the segment flags to use.
void
- add_output_section(Output_section* os, elfcpp::Elf_Word seg_flags,
- bool do_sort);
+ add_output_section_to_nonload(Output_section* os,
+ elfcpp::Elf_Word seg_flags);
// Remove an Output_section from this segment. It is an error if it
// is not present.
// Return true if this segment has any sections which hold actual
// data, rather than being a BSS section.
bool
- has_any_data_sections() const
- { return !this->output_data_.empty(); }
+ has_any_data_sections() const;
- // Return the number of dynamic relocations applied to this segment.
- unsigned int
- dynamic_reloc_count() const;
+ // Whether this segment has a dynamic relocs.
+ bool
+ has_dynamic_reloc() const;
// Return the address of the first section.
uint64_t
print_sections_to_mapfile(Mapfile*) const;
private:
- typedef std::list<Output_data*> Output_data_list;
+ typedef std::vector<Output_data*> Output_data_list;
// Find the maximum alignment in an Output_data_list.
static uint64_t
unsigned int
output_section_count_list(const Output_data_list*) const;
- // Return the number of dynamic relocs in an Output_data_list.
- unsigned int
- dynamic_reloc_count_list(const Output_data_list*) const;
+ // Return whether an Output_data_list has a dynamic reloc.
+ bool
+ has_dynamic_reloc_list(const Output_data_list*) const;
// Find the section with the lowest load address in an
// Output_data_list.
// NOTE: We want to use the copy constructor. Currently, shallow copy
// works for us so we do not need to write our own copy constructor.
- // The list of output data with contents attached to this segment.
- Output_data_list output_data_;
- // The list of output data without contents attached to this segment.
- Output_data_list output_bss_;
+ // The list of output data attached to this segment.
+ Output_data_list output_lists_[ORDER_MAX];
// The segment virtual address.
uint64_t vaddr_;
// The segment physical address.
layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
- this->got_, false, false, false, false);
+ this->got_, ORDER_DATA, false);
// Create the GOT2 or TOC in the .got section.
if (size == 32)
layout->add_output_section_data(".got2", elfcpp::SHT_PROGBITS,
elfcpp::SHF_ALLOC
| elfcpp::SHF_WRITE,
- this->got2_, false, false, false,
- false);
+ this->got2_, ORDER_DATA, false);
}
else
{
layout->add_output_section_data(".toc", elfcpp::SHT_PROGBITS,
elfcpp::SHF_ALLOC
| elfcpp::SHF_WRITE,
- this->toc_, false, false, false,
- false);
+ this->toc_, ORDER_DATA, false);
}
// Define _GLOBAL_OFFSET_TABLE_ at the start of the .got section.
gold_assert(layout != NULL);
this->rela_dyn_ = new Reloc_section(parameters->options().combreloc());
layout->add_output_section_data(".rela.dyn", elfcpp::SHT_RELA,
- elfcpp::SHF_ALLOC, this->rela_dyn_, true,
- false, false, false);
+ elfcpp::SHF_ALLOC, this->rela_dyn_,
+ ORDER_DYNAMIC_RELOCS, false);
}
return this->rela_dyn_;
}
{
this->rel_ = new Reloc_section(false);
layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA,
- elfcpp::SHF_ALLOC, this->rel_, true, false,
- false, false);
+ elfcpp::SHF_ALLOC, this->rel_,
+ ORDER_DYNAMIC_PLT_RELOCS, false);
}
template<int size, bool big_endian>
(elfcpp::SHF_ALLOC
| elfcpp::SHF_EXECINSTR
| elfcpp::SHF_WRITE),
- this->plt_, false, false, false, false);
+ this->plt_, ORDER_PLT, false);
// Define _PROCEDURE_LINKAGE_TABLE_ at the start of the .plt section.
symtab->define_in_output_data("_PROCEDURE_LINKAGE_TABLE_", NULL,
Output_section* os = layout->add_output_section_data(".sdata", 0,
elfcpp::SHF_ALLOC
| elfcpp::SHF_WRITE,
- sdata, false,
- false, false, false);
+ sdata,
+ ORDER_SMALL_DATA,
+ false);
symtab->define_in_output_data("_SDA_BASE_", NULL,
Symbol_table::PREDEFINED,
os,
is_current_seg_readonly = true;
}
- current_seg->add_output_section(*p, seg_flags, false);
+ current_seg->add_output_section_to_load(layout, *p, seg_flags);
if (((*p)->flags() & elfcpp::SHF_WRITE) != 0)
is_current_seg_readonly = false;
Layout::section_flags_to_segment((*p)->flags());
Output_segment* oseg = layout->make_output_segment(elfcpp::PT_NOTE,
seg_flags);
- oseg->add_output_section(*p, seg_flags, false);
+ oseg->add_output_section_to_nonload(*p, seg_flags);
// Incorporate any subsequent SHT_NOTE sections, in the
// hopes that the script is sensible.
&& (*pnext)->type() == elfcpp::SHT_NOTE)
{
seg_flags = Layout::section_flags_to_segment((*pnext)->flags());
- oseg->add_output_section(*pnext, seg_flags, false);
+ oseg->add_output_section_to_nonload(*pnext, seg_flags);
p = pnext;
++pnext;
}
Layout::section_flags_to_segment((*p)->flags());
Output_segment* oseg = layout->make_output_segment(elfcpp::PT_TLS,
seg_flags);
- oseg->add_output_section(*p, seg_flags, false);
+ oseg->add_output_section_to_nonload(*p, seg_flags);
Layout::Section_list::const_iterator pnext = p + 1;
while (pnext != sections->end()
&& ((*pnext)->flags() & elfcpp::SHF_TLS) != 0)
{
seg_flags = Layout::section_flags_to_segment((*pnext)->flags());
- oseg->add_output_section(*pnext, seg_flags, false);
+ oseg->add_output_section_to_nonload(*pnext, seg_flags);
p = pnext;
++pnext;
}
elfcpp::Elf_Word seg_flags =
Layout::section_flags_to_segment(os->flags());
- r->second->add_output_section(os, seg_flags, false);
- if (r->second->type() == elfcpp::PT_LOAD)
+ if (r->second->type() != elfcpp::PT_LOAD)
+ r->second->add_output_section_to_nonload(os, seg_flags);
+ else
{
+ r->second->add_output_section_to_load(layout, os, seg_flags);
if (in_load_segment)
gold_error(_("section in two PT_LOAD segments"));
in_load_segment = true;
layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
(elfcpp::SHF_ALLOC
| elfcpp::SHF_WRITE),
- this->got_, false, true, false, false);
+ this->got_, ORDER_RELRO, true);
// Define _GLOBAL_OFFSET_TABLE_ at the start of the .got section.
symtab->define_in_output_data("_GLOBAL_OFFSET_TABLE_", NULL,
gold_assert(layout != NULL);
this->rela_dyn_ = new Reloc_section(parameters->options().combreloc());
layout->add_output_section_data(".rela.dyn", elfcpp::SHT_RELA,
- elfcpp::SHF_ALLOC, this->rela_dyn_, true,
- false, false, false);
+ elfcpp::SHF_ALLOC, this->rela_dyn_,
+ ORDER_DYNAMIC_RELOCS, false);
}
return this->rela_dyn_;
}
{
this->rel_ = new Reloc_section(false);
layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA,
- elfcpp::SHF_ALLOC, this->rel_, true,
- false, false, false);
+ elfcpp::SHF_ALLOC, this->rel_,
+ ORDER_DYNAMIC_PLT_RELOCS, false);
}
template<int size, bool big_endian>
(elfcpp::SHF_ALLOC
| elfcpp::SHF_EXECINSTR
| elfcpp::SHF_WRITE),
- this->plt_, false, false, false, false);
+ this->plt_, ORDER_PLT, false);
// Define _PROCEDURE_LINKAGE_TABLE_ at the start of the .plt section.
symtab->define_in_output_data("_PROCEDURE_LINKAGE_TABLE_", NULL,
layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
(elfcpp::SHF_ALLOC
| elfcpp::SHF_WRITE),
- this->got_, false, true, true, false);
+ this->got_, ORDER_RELRO_LAST,
+ true);
this->got_plt_ = new Output_data_space(8, "** GOT PLT");
layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS,
(elfcpp::SHF_ALLOC
| elfcpp::SHF_WRITE),
- this->got_plt_, false, false, false,
- true);
+ this->got_plt_, ORDER_NON_RELRO_FIRST,
+ false);
// The first three entries are reserved.
this->got_plt_->set_current_data_size(3 * 8);
layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS,
(elfcpp::SHF_ALLOC
| elfcpp::SHF_WRITE),
- this->got_tlsdesc_, false, false, false,
- true);
+ this->got_tlsdesc_,
+ ORDER_NON_RELRO_FIRST, false);
}
return this->got_;
gold_assert(layout != NULL);
this->rela_dyn_ = new Reloc_section(parameters->options().combreloc());
layout->add_output_section_data(".rela.dyn", elfcpp::SHT_RELA,
- elfcpp::SHF_ALLOC, this->rela_dyn_, true,
- false, false, false);
+ elfcpp::SHF_ALLOC, this->rela_dyn_,
+ ORDER_DYNAMIC_RELOCS, false);
}
return this->rela_dyn_;
}
{
this->rel_ = new Reloc_section(false);
layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA,
- elfcpp::SHF_ALLOC, this->rel_, true,
- false, false, false);
+ elfcpp::SHF_ALLOC, this->rel_,
+ ORDER_DYNAMIC_PLT_RELOCS, false);
}
void
this->tlsdesc_rel_ = new Reloc_section(false);
layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA,
elfcpp::SHF_ALLOC, this->tlsdesc_rel_,
- true, false, false, false);
+ ORDER_DYNAMIC_PLT_RELOCS, false);
gold_assert(this->tlsdesc_rel_->output_section() ==
this->rel_->output_section());
}
layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
(elfcpp::SHF_ALLOC
| elfcpp::SHF_EXECINSTR),
- this->plt_, false, false, false, false);
+ this->plt_, ORDER_PLT, false);
}
}