diff options
author | Ian Lance Taylor <ian@airs.com> | 2008-05-20 04:00:47 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@airs.com> | 2008-05-20 04:00:47 +0000 |
commit | 9f1d377b33ab688f86e1cc9a454d87f991d65f19 (patch) | |
tree | c1b3a61a840a01d29858641f0db6b017124501d4 /gold/output.cc | |
parent | 3285cf2c2fa75927a67ef845d47f5eb81770ac21 (diff) | |
download | gdb-9f1d377b33ab688f86e1cc9a454d87f991d65f19.zip gdb-9f1d377b33ab688f86e1cc9a454d87f991d65f19.tar.gz 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.cc | 88 |
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. |