aboutsummaryrefslogtreecommitdiff
path: root/gold/layout.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/layout.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/layout.cc')
-rw-r--r--gold/layout.cc72
1 files changed, 64 insertions, 8 deletions
diff --git a/gold/layout.cc b/gold/layout.cc
index 07e9056..eae6679 100644
--- a/gold/layout.cc
+++ b/gold/layout.cc
@@ -90,6 +90,7 @@ Layout::Layout(const General_options& options, Script_options* script_options)
special_output_list_(),
section_headers_(NULL),
tls_segment_(NULL),
+ relro_segment_(NULL),
symtab_section_(NULL),
symtab_xindex_(NULL),
dynsym_section_(NULL),
@@ -637,9 +638,10 @@ Layout::layout_eh_frame(Sized_relobj<size, big_endian>* object,
return os;
}
-// Add POSD to an output section using NAME, TYPE, and FLAGS.
+// Add POSD to an output section using NAME, TYPE, and FLAGS. Return
+// the output section.
-void
+Output_section*
Layout::add_output_section_data(const char* name, elfcpp::Elf_Word type,
elfcpp::Elf_Xword flags,
Output_section_data* posd)
@@ -648,6 +650,7 @@ Layout::add_output_section_data(const char* name, elfcpp::Elf_Word type,
false);
if (os != NULL)
os->add_output_section_data(posd);
+ return os;
}
// Map section flags to segment flags.
@@ -706,6 +709,23 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
|| 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();
+ }
+ }
+
// If we have already attached the sections to segments, then we
// need to attach this one now. This happens for sections created
// directly by the linker.
@@ -831,6 +851,17 @@ Layout::attach_allocated_section_to_segment(Output_section* os)
seg_flags);
this->tls_segment_->add_output_section(os, seg_flags);
}
+
+ // If -z relro is in effect, and we see a relro section, we create a
+ // PT_GNU_RELRO segment. There can only be one such segment.
+ if (os->is_relro() && parameters->options().relro())
+ {
+ gold_assert(seg_flags == (elfcpp::PF_R | elfcpp::PF_W));
+ if (this->relro_segment_ == NULL)
+ this->relro_segment_ = this->make_output_segment(elfcpp::PT_GNU_RELRO,
+ seg_flags);
+ this->relro_segment_->add_output_section(os, seg_flags);
+ }
}
// Make an output section for a script.
@@ -901,6 +932,7 @@ Layout::create_initial_dynamic_sections(Symbol_table* symtab)
(elfcpp::SHF_ALLOC
| elfcpp::SHF_WRITE),
false);
+ this->dynamic_section_->set_is_relro();
symtab->define_in_output_data("_DYNAMIC", NULL, this->dynamic_section_, 0, 0,
elfcpp::STT_OBJECT, elfcpp::STB_LOCAL,
@@ -1508,12 +1540,25 @@ Layout::segment_precedes(const Output_segment* seg1,
if (type2 == elfcpp::PT_LOAD && type1 != elfcpp::PT_LOAD)
return false;
- // We put the PT_TLS segment last, because that is where the dynamic
- // linker expects to find it (this is just for efficiency; other
- // positions would also work correctly).
- if (type1 == elfcpp::PT_TLS && type2 != elfcpp::PT_TLS)
+ // We put the PT_TLS segment last except for the PT_GNU_RELRO
+ // segment, because that is where the dynamic linker expects to find
+ // it (this is just for efficiency; other positions would also work
+ // correctly).
+ if (type1 == elfcpp::PT_TLS
+ && type2 != elfcpp::PT_TLS
+ && type2 != elfcpp::PT_GNU_RELRO)
+ return false;
+ if (type2 == elfcpp::PT_TLS
+ && type1 != elfcpp::PT_TLS
+ && type1 != elfcpp::PT_GNU_RELRO)
+ return true;
+
+ // We put the PT_GNU_RELRO segment last, because that is where the
+ // dynamic linker expects to find it (as with PT_TLS, this is just
+ // for efficiency).
+ if (type1 == elfcpp::PT_GNU_RELRO && type2 != elfcpp::PT_GNU_RELRO)
return false;
- if (type2 == elfcpp::PT_TLS && type1 != elfcpp::PT_TLS)
+ if (type2 == elfcpp::PT_GNU_RELRO && type1 != elfcpp::PT_GNU_RELRO)
return true;
const elfcpp::Elf_Word flags1 = seg1->flags();
@@ -2634,7 +2679,8 @@ Layout::finish_dynamic_section(const Input_objects* input_objects,
#define MAPPING_INIT(f, t) { f, sizeof(f) - 1, t, sizeof(t) - 1 }
const Layout::Linkonce_mapping Layout::linkonce_mapping[] =
{
- MAPPING_INIT("d.rel.ro", ".data.rel.ro"), // Must be before "d".
+ MAPPING_INIT("d.rel.ro.local", ".data.rel.ro.local"), // Before "d.rel.ro".
+ MAPPING_INIT("d.rel.ro", ".data.rel.ro"), // Before "d".
MAPPING_INIT("t", ".text"),
MAPPING_INIT("r", ".rodata"),
MAPPING_INIT("d", ".data"),
@@ -2736,6 +2782,9 @@ Layout::output_section_name(const char* name, size_t* plen)
// initial '.', we use the name unchanged (i.e., "mysection" and
// ".text" are unchanged).
+ // If the name starts with ".data.rel.ro.local" we use
+ // ".data.rel.ro.local".
+
// If the name starts with ".data.rel.ro" we use ".data.rel.ro".
// Otherwise, we drop the second '.' and everything that comes after
@@ -2749,6 +2798,13 @@ Layout::output_section_name(const char* name, size_t* plen)
if (sdot == NULL)
return name;
+ const char* const data_rel_ro_local = ".data.rel.ro.local";
+ if (strncmp(name, data_rel_ro_local, strlen(data_rel_ro_local)) == 0)
+ {
+ *plen = strlen(data_rel_ro_local);
+ return data_rel_ro_local;
+ }
+
const char* const data_rel_ro = ".data.rel.ro";
if (strncmp(name, data_rel_ro, strlen(data_rel_ro)) == 0)
{