aboutsummaryrefslogtreecommitdiff
path: root/gold/output.cc
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@airs.com>2008-05-20 04:00:47 +0000
committerIan Lance Taylor <ian@airs.com>2008-05-20 04:00:47 +0000
commit9f1d377b33ab688f86e1cc9a454d87f991d65f19 (patch)
treec1b3a61a840a01d29858641f0db6b017124501d4 /gold/output.cc
parent3285cf2c2fa75927a67ef845d47f5eb81770ac21 (diff)
downloadfsf-binutils-gdb-9f1d377b33ab688f86e1cc9a454d87f991d65f19.zip
fsf-binutils-gdb-9f1d377b33ab688f86e1cc9a454d87f991d65f19.tar.gz
fsf-binutils-gdb-9f1d377b33ab688f86e1cc9a454d87f991d65f19.tar.bz2
* options.h (class General_options): Add -z relro.
* layout.cc (Layout::Layout): Initialize relro_segment_. (Layout::add_output_section_data): Return the output section. (Layout::make_output_section): Rcognize relro sections and mark them appropriately. (Layout::attach_allocated_section_to_segment): Put relro sections in a PT_GNU_RELRO segment. (Layout::create_initial_dynamic_sections): Mark the .dynamic section as relro. (Layout::segment_precedes): Sort PT_GNU_RELRO segments after PT_TLS segments. (Layout::linkonce_mapping): Map d.rel.ro.local to .data.rel.ro.local. (Layout::output_section_name): Us .data.rel.ro.local for any section which begins with that. * layout.h (class Layout): Update add_output_section_data declaration. Add relro_segment_ field. * output.cc (Output_section::Output_section): Initialize is_relro_ and is_relro_local_ fields. (Output_segment::add_output_section): Group relro sections. (Output_segment::is_first_section_relro): New function. (Output_segment::maximum_alignment): If there is a relro section, align the segment to the common page size. (Output_segment::set_section_addresses): Track whether we are looking at relro sections. If the last section is a relro section, align to the common page size. (Output_segment::set_section_list_addresses): Add in_relro parameter. Change all callers. Align to the page size when moving from relro to non-relro section. (Output_segment::set_offset): Align memsz of a PT_GNU_RELRO segment. * output.h (class Output_section): Add is_relro_ and is_relro_local_ fields. (Output_section::is_relro): New function. (Output_section::set_is_relro): New function. (Output_section::is_relro_local): New function. (Output_section::set_is_relro_local): New function. (class Output_segment): Update declarations. * i386.cc (Target_i386::got_section): Mark .got section as relro. * sparc.cc (Target_sparc::got_section): Likewise. * x86_64.cc (Target_x86_64::got_section): Likewise. * testsuite/relro_test_main.cc: New file. * testsuite/relro_test.cc: New file. * testsuite/Makefile.am (check_PROGRAMS): Add relro_test. (relro_test_SOURCES, relro_test_DEPENDENCIES): New variables. (relro_test_LDFLAGS, relro_test_LDADD): New variables. (relro_test.so, relro_test_pic.o): New targets. * testsuite/Makefile.in: Rebuild.
Diffstat (limited to 'gold/output.cc')
-rw-r--r--gold/output.cc88
1 files changed, 84 insertions, 4 deletions
diff --git a/gold/output.cc b/gold/output.cc
index 5459a57..b5791f4 100644
--- a/gold/output.cc
+++ b/gold/output.cc
@@ -1737,6 +1737,8 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
may_sort_attached_input_sections_(false),
must_sort_attached_input_sections_(false),
attached_input_sections_are_sorted_(false),
+ is_relro_(false),
+ is_relro_local_(false),
tls_offset_(0)
{
// An unallocated section has no address. Forcing this means that
@@ -2645,7 +2647,7 @@ Output_segment::add_output_section(Output_section* os,
{
sawtls = true;
// Put a NOBITS section after the first TLS section.
- // But a PROGBITS section after the first TLS/PROGBITS
+ // Put a PROGBITS section after the first TLS/PROGBITS
// section.
insert = nobits || !(*p)->is_section_type(elfcpp::SHT_NOBITS);
}
@@ -2669,6 +2671,28 @@ 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())
+ {
+ 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;
+ }
+
+ pdl->insert(p, os);
+ return;
+ }
+
pdl->push_back(os);
}
@@ -2703,6 +2727,16 @@ Output_segment::add_initial_output_data(Output_data* od)
this->output_data_.push_front(od);
}
+// 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());
+}
+
// Return the maximum alignment of the Output_data in Output_segment.
uint64_t
@@ -2720,6 +2754,17 @@ 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 (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;
}
@@ -2792,11 +2837,15 @@ 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);
+ addr, poff, pshndx, &in_tls,
+ &in_relro);
this->filesz_ = *poff - orig_off;
off_t off = *poff;
@@ -2804,7 +2853,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_tls, &in_relro);
// 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
@@ -2815,6 +2864,14 @@ 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
@@ -2832,7 +2889,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_tls, bool* in_relro)
{
off_t startoff = *poff;
@@ -2883,6 +2940,19 @@ 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);
}
@@ -2976,6 +3046,16 @@ 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.