2009-12-29 Ian Lance Taylor <iant@google.com>
+ * layout.cc (Layout::Layout): Initialize increase_relro_.
+ (Layout::get_output_section): Add is_relro, 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.
+ (Layout::set_segment_offsets): Clear increase_relro when using a
+ linker script.
+ * layout.h (class Layout): Add increase_relro method. Add
+ increase_relro_ field. Update declarations.
+ * output.cc (Output_section::Output_section): Initialize
+ is_last_relro_ and is_first_non_relro_.
+ (Output_segment::add_output_section): Group relro sections is
+ do_sort is true. Handle is_last_relro and is_first_non_relro.
+ (Output_segment::maximum_alignment): Remove relro handling.
+ (Output_segment::set_section_addresses): Add increase_relro
+ parameter. Change all callers. Add initial alignment to align
+ relro sections on separate page. Remove old relro handling.
+ (Output_segment::set_section_list_addresses): Remove in_relro
+ parameter. Change all callers.
+ (Output_segment::set_offset): Add increase parameter. Change all
+ callers. Remove old relro handling.
+ * output.h (class Output_section): Add new methods: is_last_relro,
+ set_is_last_relro, is_first_non_relro, set_is_first_non_relro.
+ Add is_last_relro_ and is_first_non_relro_ fields.
+ * i386.cc (Target_i386::got_section): Don't call set_is_relro.
+ Create separate .got.plt section. Call increase_relro.
+ * x86_64.cc (Target_x86_64::got_section): Likewise.
+ * testsuite/relro_script_test.t: Add .got.plt.
+
PR 10450
* layout.cc (Layout::Layout): Initialize dynamic_symbol_ field.
(Layout::create_initial_dynamic_sections): Set dynamic_symbol_.
os = layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
(elfcpp::SHF_ALLOC
| elfcpp::SHF_WRITE),
- this->got_, false);
- os->set_is_relro();
+ this->got_, false, true, true,
+ false);
// The old GNU linker creates a .got.plt section. We just
// create another set of data in the .got section. Note that we
os = layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
(elfcpp::SHF_ALLOC
| elfcpp::SHF_WRITE),
- this->got_plt_, false);
- os->set_is_relro();
+ this->got_plt_, false, false,
+ false, true);
// 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);
+ elfcpp::SHF_ALLOC, this->rel_dyn_, true,
+ false, false, 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);
+ elfcpp::SHF_ALLOC, this->rel_, true, false,
+ false, false);
}
template<bool big_endian>
layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
(elfcpp::SHF_ALLOC
| elfcpp::SHF_EXECINSTR),
- this->plt_, false);
+ this->plt_, false, false, false, false);
}
this->plt_->add_entry(gsym);
}
new Output_attributes_section_data(*this->attributes_section_data_);
layout->add_output_section_data(".ARM.attributes",
elfcpp::SHT_ARM_ATTRIBUTES, 0,
- attributes_section, false);
+ attributes_section, false, false, false,
+ false);
}
// Return whether a direct absolute static relocation needs to be applied.
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);
+ flags, poc, false,
+ false, false, 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);
+ this->dynbss_, false, false, false,
+ false);
}
Output_data_space* dynbss = this->dynbss_;
os = layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
(elfcpp::SHF_ALLOC
| elfcpp::SHF_WRITE),
- this->got_, false);
- os->set_is_relro();
+ this->got_, false, true, true,
+ false);
- // 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
- // might be empty.
this->got_plt_ = new Output_data_space(4, "** GOT PLT");
- os = layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
+ os = layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS,
(elfcpp::SHF_ALLOC
| elfcpp::SHF_WRITE),
- this->got_plt_, false);
- os->set_is_relro();
+ this->got_plt_, false, false, false,
+ true);
// The first three entries are reserved.
this->got_plt_->set_current_data_size(3 * 4);
+ // Those bytes can go into the relro segment.
+ layout->increase_relro(3 * 4);
+
// Define _GLOBAL_OFFSET_TABLE_ at the start of the PLT.
symtab->define_in_output_data("_GLOBAL_OFFSET_TABLE_", NULL,
Symbol_table::PREDEFINED,
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);
+ elfcpp::SHF_ALLOC, this->rel_dyn_, true,
+ false, false, 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);
+ elfcpp::SHF_ALLOC, this->rel_, true,
+ false, false, false);
}
void
layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
(elfcpp::SHF_ALLOC
| elfcpp::SHF_EXECINSTR),
- this->plt_, false);
+ this->plt_, false, false, false, false);
}
this->plt_->add_entry(gsym);
section_headers_(NULL),
tls_segment_(NULL),
relro_segment_(NULL),
+ increase_relro_(0),
symtab_section_(NULL),
symtab_xindex_(NULL),
dynsym_section_(NULL),
// and section flags FLAGS. NAME must be canonicalized in the string
// pool, and NAME_KEY is the key. 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 used by the dynamic linker. IS_RELRO is true for a relro
+// section. IS_LAST_RELRO is true for the last relro section.
+// IS_FIRST_NON_RELRO is true for the first non-relro section.
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_interp, bool is_dynamic_linker_section,
+ bool is_relro, bool is_last_relro,
+ bool is_first_non_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_dynamic_linker_section, is_relro,
+ is_last_relro, is_first_non_relro);
ins.first->second = os;
return os;
}
// choosing an output section for an input section found in a input
// file. 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. This will return NULL if the input section should
-// be discarded.
+// dynamic linker. IS_RELRO is true for a relro section.
+// IS_LAST_RELRO is true for the last relro section.
+// IS_FIRST_NON_RELRO is true for the first non-relro section. This
+// will return NULL if the input section should be discarded.
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_dynamic_linker_section, bool is_relro,
+ bool is_last_relro, bool is_first_non_relro)
{
// We should not see any input sections after we have attached
// sections to segments.
Output_section* os =
this->make_output_section(name, type, flags, is_interp,
- is_dynamic_linker_section);
+ is_dynamic_linker_section, is_relro,
+ is_last_relro, is_first_non_relro);
os->set_found_in_sections_clause();
*output_section_slot = os;
return os;
// 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_dynamic_linker_section, is_relro,
+ is_last_relro, is_first_non_relro);
}
// Return the output section to use for input section SHNDX, with name
{
name = this->namepool_.add(name, true, NULL);
os = this->make_output_section(name, shdr.get_sh_type(),
- shdr.get_sh_flags(), false, false);
+ shdr.get_sh_flags(), false, false,
+ false, false, false);
}
else
{
os = this->choose_output_section(object, name, shdr.get_sh_type(),
shdr.get_sh_flags(), true, false,
- false);
+ false, false, false, false);
if (os == NULL)
return NULL;
}
Output_section* os = this->choose_output_section(object, name.c_str(),
sh_type,
shdr.get_sh_flags(),
+ false, false, false,
false, false, 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);
// We need to find a symbol with the signature in the symbol table.
name,
elfcpp::SHT_PROGBITS,
elfcpp::SHF_ALLOC,
+ false, false, false,
false, false, false);
if (os == NULL)
return NULL;
".eh_frame_hdr",
elfcpp::SHT_PROGBITS,
elfcpp::SHF_ALLOC,
+ false, false, false,
false, false, false);
if (hdr_os != NULL)
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_dynamic_linker_section,
+ bool is_relro, bool is_last_relro,
+ bool is_first_non_relro)
{
Output_section* os = this->choose_output_section(NULL, name, type, flags,
false, false,
- is_dynamic_linker_section);
+ is_dynamic_linker_section,
+ is_relro, is_last_relro,
+ is_first_non_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.
+// 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.
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_dynamic_linker_section, bool is_relro,
+ bool is_last_relro, bool is_first_non_relro)
{
Output_section* os;
if ((flags & elfcpp::SHF_ALLOC) == 0
os->set_is_interp();
if (is_dynamic_linker_section)
os->set_is_dynamic_linker_section();
+ 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();
parameters->target().new_output_section(os);
name = this->namepool_.add(name, false, NULL);
Output_section* os = this->make_output_section(name, elfcpp::SHT_PROGBITS,
elfcpp::SHF_ALLOC, false,
- false);
+ false, false, false, false);
os->set_found_in_sections_clause();
return os;
}
elfcpp::SHT_DYNAMIC,
(elfcpp::SHF_ALLOC
| elfcpp::SHF_WRITE),
- false, false, true);
- this->dynamic_section_->set_is_relro();
+ false, false, true,
+ true, false, false);
this->dynamic_symbol_ =
symtab->define_in_output_data("_DYNAMIC", NULL, Symbol_table::PREDEFINED,
Output_section* os = this->choose_output_section(NULL, section_name,
elfcpp::SHT_NOTE,
flags, false, false,
- false);
+ false, false, false, false);
if (os == NULL)
return NULL;
if (is_stack_executable)
flags |= elfcpp::SHF_EXECINSTR;
this->make_output_section(name, elfcpp::SHT_PROGBITS, flags, false,
- false);
+ false, false, false, false);
}
else
{
Output_section* inputs_os =
this->make_output_section(incremental_inputs_name,
elfcpp::SHT_GNU_INCREMENTAL_INPUTS, 0,
- false, false);
+ false, false, false, false, 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);
+ 0, false, false,
+ false, false, false);
Output_data_strtab* strtab_data =
new Output_data_strtab(this->incremental_inputs_->get_stringpool());
strtab_os->add_output_section_data(strtab_data);
}
}
+ unsigned int increase_relro = this->increase_relro_;
+ if (this->script_options_->saw_sections_clause())
+ increase_relro = 0;
+
const bool check_sections = parameters->options().check_sections();
Output_segment* last_load_segment = NULL;
unsigned int shndx_hold = *pshndx;
uint64_t new_addr = (*p)->set_section_addresses(this, false, addr,
+ increase_relro,
&off, pshndx);
// Now that we know the size of this segment, we may be able
off = orig_off + ((addr - orig_addr) & (abi_pagesize - 1));
off = align_file_offset(off, addr, abi_pagesize);
new_addr = (*p)->set_section_addresses(this, true, addr,
+ increase_relro,
&off, pshndx);
}
}
++p)
{
if ((*p)->type() != elfcpp::PT_LOAD)
- (*p)->set_offset();
+ (*p)->set_offset((*p)->type() == elfcpp::PT_GNU_RELRO
+ ? increase_relro
+ : 0);
}
// Set the TLS offsets for each section in the PT_TLS segment.
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);
+ 0, false, false,
+ false, false, false);
this->symtab_section_ = osymtab;
Output_section_data* pos = new Output_data_fixed_space(off - startoff,
Output_section* osymtab_xindex =
this->make_output_section(symtab_xindex_name,
elfcpp::SHT_SYMTAB_SHNDX, 0, false,
- false);
+ false, false, false, 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);
+ 0, false, false,
+ false, false, 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, false,
+ 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, true,
+ false, false, 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, true, false, false, 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, true,
+ false, false, false);
Output_section_data* strdata = new Output_data_strtab(&this->dynpool_);
dynstr->add_output_section_data(strdata);
Output_section* hashsec = this->choose_output_section(NULL, ".hash",
elfcpp::SHT_HASH,
elfcpp::SHF_ALLOC,
- false, false, true);
+ false, false, true,
+ false, false,
+ false);
Output_section_data* hashdata = new Output_data_const_buffer(phash,
hashlen,
Output_section* hashsec = this->choose_output_section(NULL, ".gnu.hash",
elfcpp::SHT_GNU_HASH,
elfcpp::SHF_ALLOC,
- false, false, true);
+ false, false, true,
+ false, false,
+ 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, true,
+ false, false, 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, true, false, false,
+ 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, true, false, false,
+ 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, true, true,
+ false, false, false);
osec->add_output_section_data(odata);
if (!this->script_options_->saw_phdrs_clause())
// 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.
+ // 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.
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);
+ Output_section_data*, bool is_dynamic_linker_section,
+ bool is_relro, bool is_last_relro,
+ bool is_first_non_relro);
+
+ // Increase the size of the relro segment by this much.
+ void
+ increase_relro(unsigned int s)
+ { this->increase_relro_ += s; }
// Create dynamic sections if necessary.
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_interp, bool is_dynamic_linker_section,
+ bool is_relro, bool is_last_relro,
+ bool is_first_non_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_dynamic_linker_section, bool is_relro,
+ bool is_last_relro, bool is_first_non_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_dynamic_linker_section, bool is_relro,
+ bool is_last_relro, bool is_first_non_relro);
// Attach a section to a segment.
void
Output_segment* tls_segment_;
// A pointer to the PT_GNU_RELRO segment if there is one.
Output_segment* relro_segment_;
+ // A backend may increase the size of the PT_GNU_RELRO segment if
+ // there is one. This is the amount to increase it by.
+ unsigned int increase_relro_;
// The SHT_SYMTAB output section.
Output_section* symtab_section_;
// The SHT_SYMTAB_SHNDX for the regular symbol table if there is one.
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),
// 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.
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);
}
}
// 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.
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
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.
// address of the immediately following segment. Update *POFF and
// *PSHNDX. This should only be called for a PT_LOAD segment.
uint64_t
- set_section_addresses(const Layout*, bool reset, uint64_t addr, off_t* poff,
+ set_section_addresses(const Layout*, bool reset, uint64_t addr,
+ unsigned int increase_relro, off_t* poff,
unsigned int* pshndx);
// Set the minimum alignment of this segment. This may be adjusted
// Set the offset of this segment based on the section. This should
// only be called for a non-PT_LOAD segment.
void
- set_offset();
+ set_offset(unsigned int increase);
// Set the TLS offsets of the sections contained in the PT_TLS segment.
void
uint64_t
set_section_list_addresses(const Layout*, bool reset, Output_data_list*,
uint64_t addr, off_t* poff, unsigned int* pshndx,
- bool* in_tls, bool* in_relro);
+ bool* in_tls);
// Return the number of Output_sections in an Output_data_list.
unsigned int
layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
- this->got_, false);
+ this->got_, false, false, false, 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);
+ this->got2_, false, false, false,
+ false);
}
else
{
layout->add_output_section_data(".toc", elfcpp::SHT_PROGBITS,
elfcpp::SHF_ALLOC
| elfcpp::SHF_WRITE,
- this->toc_, false);
+ this->toc_, false, false, false,
+ 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);
+ elfcpp::SHF_ALLOC, this->rela_dyn_, true,
+ false, false, 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);
+ elfcpp::SHF_ALLOC, this->rel_, true, false,
+ false, false);
}
template<int size, bool big_endian>
(elfcpp::SHF_ALLOC
| elfcpp::SHF_EXECINSTR
| elfcpp::SHF_WRITE),
- this->plt_, false);
+ this->plt_, false, false, false, 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);
+ sdata, false,
+ false, false, false);
symtab->define_in_output_data("_SDA_BASE_", NULL,
Symbol_table::PREDEFINED,
os,
os = layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
(elfcpp::SHF_ALLOC
| elfcpp::SHF_WRITE),
- this->got_, false);
- os->set_is_relro();
+ this->got_, false, true, false,
+ false);
// 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);
+ elfcpp::SHF_ALLOC, this->rela_dyn_, true,
+ false, false, 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);
+ elfcpp::SHF_ALLOC, this->rel_, true,
+ false, false, false);
}
template<int size, bool big_endian>
(elfcpp::SHF_ALLOC
| elfcpp::SHF_EXECINSTR
| elfcpp::SHF_WRITE),
- this->plt_, false);
+ this->plt_, false, false, false, false);
// Define _PROCEDURE_LINKAGE_TABLE_ at the start of the .plt section.
symtab->define_in_output_data("_PROCEDURE_LINKAGE_TABLE_", NULL,
. = DATA_SEGMENT_RELRO_END(0, .);
+ .got.plt : { *(.got.plt) }
+
.data : { *(.data .data.* .gnu.linkonce.d.*) }
. = DATA_SEGMENT_END (.);
os = layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
(elfcpp::SHF_ALLOC
| elfcpp::SHF_WRITE),
- this->got_, false);
- os->set_is_relro();
+ this->got_, false, true, true,
+ false);
- // 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
- // might be empty.
this->got_plt_ = new Output_data_space(8, "** GOT PLT");
- os = layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
+ os = layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS,
(elfcpp::SHF_ALLOC
| elfcpp::SHF_WRITE),
- this->got_plt_, false);
- os->set_is_relro();
+ this->got_plt_, false, false,
+ false, true);
// The first three entries are reserved.
this->got_plt_->set_current_data_size(3 * 8);
+ // Those bytes can go into the relro segment.
+ layout->increase_relro(3 * 8);
+
// Define _GLOBAL_OFFSET_TABLE_ at the start of the PLT.
symtab->define_in_output_data("_GLOBAL_OFFSET_TABLE_", NULL,
Symbol_table::PREDEFINED,
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);
+ elfcpp::SHF_ALLOC, this->rela_dyn_, true,
+ false, false, 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);
+ elfcpp::SHF_ALLOC, this->rel_, true,
+ false, false, false);
}
void
layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
(elfcpp::SHF_ALLOC
| elfcpp::SHF_EXECINSTR),
- this->plt_, false);
+ this->plt_, false, false, false, false);
}
}