aboutsummaryrefslogtreecommitdiff
path: root/gold/output.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gold/output.cc')
-rw-r--r--gold/output.cc169
1 files changed, 99 insertions, 70 deletions
diff --git a/gold/output.cc b/gold/output.cc
index d75b45b..e643fb7 100644
--- a/gold/output.cc
+++ b/gold/output.cc
@@ -1795,6 +1795,8 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
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),
@@ -3157,26 +3159,52 @@ Output_segment::add_output_section(Output_section* os,
// 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.
@@ -3365,19 +3393,6 @@ Output_segment::maximum_alignment()
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;
}
@@ -3431,11 +3446,57 @@ Output_segment::dynamic_reloc_count_list(const Output_data_list* pdl) const
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);
@@ -3450,15 +3511,10 @@ Output_segment::set_section_addresses(const Layout* layout, bool reset,
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;
@@ -3466,7 +3522,7 @@ Output_segment::set_section_addresses(const Layout* layout, bool reset,
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
@@ -3477,14 +3533,6 @@ Output_segment::set_section_addresses(const Layout* layout, bool reset,
*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
@@ -3502,7 +3550,7 @@ Output_segment::set_section_list_addresses(const Layout* layout, bool reset,
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;
@@ -3553,19 +3601,6 @@ Output_segment::set_section_list_addresses(const Layout* layout, bool reset,
}
}
- // 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);
}
@@ -3621,10 +3656,10 @@ Output_segment::set_section_list_addresses(const Layout* layout, bool reset,
}
// 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);
@@ -3632,6 +3667,7 @@ Output_segment::set_offset()
if (this->output_data_.empty() && this->output_bss_.empty())
{
+ gold_assert(increase == 0);
this->vaddr_ = 0;
this->paddr_ = 0;
this->are_addresses_set_ = true;
@@ -3673,6 +3709,9 @@ Output_segment::set_offset()
+ 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.
@@ -3682,16 +3721,6 @@ Output_segment::set_offset()
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.