This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

PATCH COMMITTED: Implement -z relro


I committed this patch to implement -z relro for gold.

This is pretty straightforward given how relro works
(http://www.airs.com/blog/archives/189).  I don't think there is
anything to call out here.

Ian


2008-05-19  Ian Lance Taylor  <iant@google.com>

	* 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.


Index: i386.cc
===================================================================
RCS file: /cvs/src/src/gold/i386.cc,v
retrieving revision 1.75
diff -p -u -r1.75 i386.cc
--- i386.cc	16 May 2008 20:44:22 -0000	1.75
+++ i386.cc	20 May 2008 03:49:24 -0000
@@ -426,18 +426,23 @@ Target_i386::got_section(Symbol_table* s
 
       this->got_ = new Output_data_got<32, false>();
 
-      layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
-				      elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
-				      this->got_);
+      Output_section* os;
+      os = layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
+					   (elfcpp::SHF_ALLOC
+					    | elfcpp::SHF_WRITE),
+					   this->got_);
+      os->set_is_relro();
 
       // 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);
-      layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
-				      elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
-				      this->got_plt_);
+      os = layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
+					   (elfcpp::SHF_ALLOC
+					    | elfcpp::SHF_WRITE),
+					   this->got_plt_);
+      os->set_is_relro();
 
       // The first three entries are reserved.
       this->got_plt_->set_current_data_size(3 * 4);
Index: layout.cc
===================================================================
RCS file: /cvs/src/src/gold/layout.cc,v
retrieving revision 1.103
diff -p -u -r1.103 layout.cc
--- layout.cc	16 May 2008 22:29:04 -0000	1.103
+++ layout.cc	20 May 2008 03:49:25 -0000
@@ -90,6 +90,7 @@ Layout::Layout(const General_options& op
     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<siz
   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 ch
 						   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* 
 	  || 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_segm
                                                        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(
 						       (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_se
   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 Inp
 #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* 
   // 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* 
   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)
     {
Index: layout.h
===================================================================
RCS file: /cvs/src/src/gold/layout.h,v
retrieving revision 1.57
diff -p -u -r1.57 layout.h
--- layout.h	5 May 2008 19:16:43 -0000	1.57
+++ layout.h	20 May 2008 03:49:25 -0000
@@ -158,7 +158,7 @@ class Layout
 
   // Add an Output_section_data to the layout.  This is used for
   // special sections like the GOT section.
-  void
+  Output_section*
   add_output_section_data(const char* name, elfcpp::Elf_Word type,
 			  elfcpp::Elf_Xword flags,
 			  Output_section_data*);
@@ -636,6 +636,8 @@ class Layout
   Output_section_headers* section_headers_;
   // A pointer to the PT_TLS segment if there is one.
   Output_segment* tls_segment_;
+  // A pointer to the PT_GNU_RELRO segment if there is one.
+  Output_segment* relro_segment_;
   // The SHT_SYMTAB output section.
   Output_section* symtab_section_;
   // The SHT_SYMTAB_SHNDX for the regular symbol table if there is one.
Index: options.h
===================================================================
RCS file: /cvs/src/src/gold/options.h,v
retrieving revision 1.77
diff -p -u -r1.77 options.h
--- options.h	7 May 2008 06:08:01 -0000	1.77
+++ options.h	20 May 2008 03:49:25 -0000
@@ -811,6 +811,9 @@ class General_options
   DEFINE_bool(nodump, options::DASH_Z, '\0', false,
 	      N_("Mark DSO not available to dldump"),
 	      NULL);
+  DEFINE_bool(relro, options::DASH_Z, '\0', false,
+	      N_("Where possible mark variables read-only after relocation"),
+	      N_("Don't mark variables read-only after relocation"));
 
  public:
   typedef options::Dir_list Dir_list;
Index: output.cc
===================================================================
RCS file: /cvs/src/src/gold/output.cc,v
retrieving revision 1.77
diff -p -u -r1.77 output.cc
--- output.cc	16 May 2008 22:29:04 -0000	1.77
+++ output.cc	20 May 2008 03:49:25 -0000
@@ -1737,6 +1737,8 @@ Output_section::Output_section(const cha
     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(Outpu
 	    {
 	      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(Outpu
       // 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(
   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(co
 
   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(co
   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(co
       *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_address
                                            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_address
                 }
             }
 
+	  // 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.
Index: output.h
===================================================================
RCS file: /cvs/src/src/gold/output.h,v
retrieving revision 1.70
diff -p -u -r1.70 output.h
--- output.h	16 May 2008 22:29:04 -0000	1.70
+++ output.h	20 May 2008 03:49:26 -0000
@@ -2028,6 +2028,29 @@ class Output_section : public Output_dat
   set_must_sort_attached_input_sections()
   { this->must_sort_attached_input_sections_ = true; }
 
+  // Return whether this section holds relro data--data which has
+  // dynamic relocations but which may be marked read-only after the
+  // dynamic relocations have been completed.
+  bool
+  is_relro() const
+  { return this->is_relro_; }
+
+  // Record that this section holds relro data.
+  void
+  set_is_relro()
+  { this->is_relro_ = true; }
+
+  // True if this section holds relro local data--relro data for which
+  // the dynamic relocations are all RELATIVE relocations.
+  bool
+  is_relro_local() const
+  { return this->is_relro_local_; }
+
+  // Record that this section holds relro local data.
+  void
+  set_is_relro_local()
+  { this->is_relro_local_ = true; }
+
   // Return whether this section should be written after all the input
   // sections are complete.
   bool
@@ -2626,6 +2649,10 @@ class Output_section : public Output_dat
   // True if the input sections attached to this output section have
   // already been sorted.
   bool attached_input_sections_are_sorted_ : 1;
+  // True if this section holds relro data.
+  bool is_relro_ : 1;
+  // True if this section holds relro local data.
+  bool is_relro_local_ : 1;
   // For SHT_TLS sections, the offset of this section relative to the base
   // of the TLS segment.
   uint64_t tls_offset_;
@@ -2785,11 +2812,15 @@ class Output_segment
   static uint64_t
   maximum_alignment_list(const Output_data_list*);
 
+  // Return whether the first data section is a relro section.
+  bool
+  is_first_section_relro() const;
+
   // Set the section addresses in an Output_data_list.
   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_tls, bool* in_relro);
 
   // Return the number of Output_sections in an Output_data_list.
   unsigned int
Index: sparc.cc
===================================================================
RCS file: /cvs/src/src/gold/sparc.cc,v
retrieving revision 1.6
diff -p -u -r1.6 sparc.cc
--- sparc.cc	6 May 2008 05:03:15 -0000	1.6
+++ sparc.cc	20 May 2008 03:49:26 -0000
@@ -1001,9 +1001,12 @@ Target_sparc<size, big_endian>::got_sect
 
       this->got_ = new Output_data_got<size, big_endian>();
 
-      layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
-				      elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
-				      this->got_);
+      Output_section* os;
+      os = layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
+					   (elfcpp::SHF_ALLOC
+					    | elfcpp::SHF_WRITE),
+					   this->got_);
+      os->set_is_relro();
 
       // Define _GLOBAL_OFFSET_TABLE_ at the start of the .got section.
       symtab->define_in_output_data("_GLOBAL_OFFSET_TABLE_", NULL,
Index: x86_64.cc
===================================================================
RCS file: /cvs/src/src/gold/x86_64.cc,v
retrieving revision 1.68
diff -p -u -r1.68 x86_64.cc
--- x86_64.cc	16 May 2008 20:44:22 -0000	1.68
+++ x86_64.cc	20 May 2008 03:49:26 -0000
@@ -435,18 +435,23 @@ Target_x86_64::got_section(Symbol_table*
 
       this->got_ = new Output_data_got<64, false>();
 
-      layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
-				      elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
-				      this->got_);
+      Output_section* os;
+      os = layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
+					   (elfcpp::SHF_ALLOC
+					    | elfcpp::SHF_WRITE),
+					   this->got_);
+      os->set_is_relro();
 
       // 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);
-      layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
-				      elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
-				      this->got_plt_);
+      os = layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
+					   (elfcpp::SHF_ALLOC
+					    | elfcpp::SHF_WRITE),
+					   this->got_plt_);
+      os->set_is_relro();
 
       // The first three entries are reserved.
       this->got_plt_->set_current_data_size(3 * 8);
Index: testsuite/Makefile.am
===================================================================
RCS file: /cvs/src/src/gold/testsuite/Makefile.am,v
retrieving revision 1.69
diff -p -u -r1.69 Makefile.am
--- testsuite/Makefile.am	8 May 2008 18:44:33 -0000	1.69
+++ testsuite/Makefile.am	20 May 2008 03:49:26 -0000
@@ -782,6 +782,16 @@ protected_2_DEPENDENCIES = gcctestdir/ld
 protected_2_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
 protected_2_LDADD = protected_1.so
 
+check_PROGRAMS += relro_test
+relro_test_SOURCES = relro_test_main.cc
+relro_test_DEPENDENCIES = gcctestdir/ld relro_test.so
+relro_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+relro_test_LDADD = relro_test.so
+relro_test.so: gcctestdir/ld relro_test_pic.o
+	$(CXXLINK) -Bgcctestdir/ -shared -Wl,-z,relro relro_test_pic.o
+relro_test_pic.o: relro_test.cc
+	$(CXXCOMPILE) -c -fpic -o $@ $<
+
 check_PROGRAMS += script_test_1
 script_test_1_SOURCES = script_test_1.cc
 script_test_1_DEPENDENCIES = gcctestdir/ld script_test_1.t
Index: testsuite/Makefile.in
===================================================================
RCS file: /cvs/src/src/gold/testsuite/Makefile.in,v
retrieving revision 1.73
diff -p -u -r1.73 Makefile.in
--- testsuite/Makefile.in	8 May 2008 18:44:33 -0000	1.73
+++ testsuite/Makefile.in	20 May 2008 03:49:27 -0000
@@ -228,9 +228,9 @@ check_PROGRAMS = object_unittest$(EXEEXT
 @GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_19 = ver_test ver_test_2 \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	ver_test_6 ver_test_8 \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	protected_1 protected_2 \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@	script_test_1 script_test_2 \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@	justsyms binary_test \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@	script_test_3
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	relro_test script_test_1 \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	script_test_2 justsyms \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	binary_test script_test_3
 @GCC_FALSE@script_test_1_DEPENDENCIES = libgoldtest.a ../libgold.a \
 @GCC_FALSE@	../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
 @GCC_FALSE@	$(am__DEPENDENCIES_1)
@@ -346,6 +346,7 @@ libgoldtest_a_OBJECTS = $(am_libgoldtest
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	ver_test_8$(EXEEXT) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	protected_1$(EXEEXT) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	protected_2$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	relro_test$(EXEEXT) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	script_test_1$(EXEEXT) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	script_test_2$(EXEEXT) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	justsyms$(EXEEXT) \
@@ -514,6 +515,10 @@ am__protected_2_SOURCES_DIST = protected
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	protected_main_1.$(OBJEXT) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	protected_3.$(OBJEXT)
 protected_2_OBJECTS = $(am_protected_2_OBJECTS)
+am__relro_test_SOURCES_DIST = relro_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_relro_test_OBJECTS =  \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	relro_test_main.$(OBJEXT)
+relro_test_OBJECTS = $(am_relro_test_OBJECTS)
 am__script_test_1_SOURCES_DIST = script_test_1.cc
 @GCC_TRUE@@NATIVE_LINKER_TRUE@am_script_test_1_OBJECTS =  \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	script_test_1.$(OBJEXT)
@@ -760,9 +765,9 @@ SOURCES = $(libgoldtest_a_SOURCES) basic
 	$(initpri1_SOURCES) $(justsyms_SOURCES) many_sections_r_test.c \
 	$(many_sections_test_SOURCES) $(object_unittest_SOURCES) \
 	$(protected_1_SOURCES) $(protected_2_SOURCES) \
-	$(script_test_1_SOURCES) $(script_test_2_SOURCES) \
-	script_test_3.c $(tls_pic_test_SOURCES) \
-	$(tls_shared_gd_to_ie_test_SOURCES) \
+	$(relro_test_SOURCES) $(script_test_1_SOURCES) \
+	$(script_test_2_SOURCES) script_test_3.c \
+	$(tls_pic_test_SOURCES) $(tls_shared_gd_to_ie_test_SOURCES) \
 	$(tls_shared_gnu2_gd_to_ie_test_SOURCES) \
 	$(tls_shared_gnu2_test_SOURCES) $(tls_shared_ie_test_SOURCES) \
 	$(tls_shared_nonpic_test_SOURCES) $(tls_shared_test_SOURCES) \
@@ -808,7 +813,7 @@ DIST_SOURCES = $(libgoldtest_a_SOURCES) 
 	$(am__initpri1_SOURCES_DIST) $(am__justsyms_SOURCES_DIST) \
 	many_sections_r_test.c $(am__many_sections_test_SOURCES_DIST) \
 	$(object_unittest_SOURCES) $(am__protected_1_SOURCES_DIST) \
-	$(am__protected_2_SOURCES_DIST) \
+	$(am__protected_2_SOURCES_DIST) $(am__relro_test_SOURCES_DIST) \
 	$(am__script_test_1_SOURCES_DIST) \
 	$(am__script_test_2_SOURCES_DIST) script_test_3.c \
 	$(am__tls_pic_test_SOURCES_DIST) \
@@ -1304,6 +1309,10 @@ binary_unittest_SOURCES = binary_unittes
 @GCC_TRUE@@NATIVE_LINKER_TRUE@protected_2_DEPENDENCIES = gcctestdir/ld protected_1.so
 @GCC_TRUE@@NATIVE_LINKER_TRUE@protected_2_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
 @GCC_TRUE@@NATIVE_LINKER_TRUE@protected_2_LDADD = protected_1.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@relro_test_SOURCES = relro_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@relro_test_DEPENDENCIES = gcctestdir/ld relro_test.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@relro_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@relro_test_LDADD = relro_test.so
 @GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_1_SOURCES = script_test_1.cc
 @GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_1_DEPENDENCIES = gcctestdir/ld script_test_1.t
 @GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_1_LDFLAGS = -Bgcctestdir/ -Wl,-R,. -T $(srcdir)/script_test_1.t
@@ -1468,6 +1477,9 @@ protected_1$(EXEEXT): $(protected_1_OBJE
 protected_2$(EXEEXT): $(protected_2_OBJECTS) $(protected_2_DEPENDENCIES) 
 	@rm -f protected_2$(EXEEXT)
 	$(CXXLINK) $(protected_2_LDFLAGS) $(protected_2_OBJECTS) $(protected_2_LDADD) $(LIBS)
+relro_test$(EXEEXT): $(relro_test_OBJECTS) $(relro_test_DEPENDENCIES) 
+	@rm -f relro_test$(EXEEXT)
+	$(CXXLINK) $(relro_test_LDFLAGS) $(relro_test_OBJECTS) $(relro_test_LDADD) $(LIBS)
 script_test_1$(EXEEXT): $(script_test_1_OBJECTS) $(script_test_1_DEPENDENCIES) 
 	@rm -f script_test_1$(EXEEXT)
 	$(CXXLINK) $(script_test_1_LDFLAGS) $(script_test_1_OBJECTS) $(script_test_1_LDADD) $(LIBS)
@@ -1627,6 +1639,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protected_main_1.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protected_main_2.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protected_main_3.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/relro_test_main.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script_test_1.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script_test_2.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script_test_2a.Po@am__quote@
@@ -2191,6 +2204,10 @@ uninstall-am: uninstall-info-am
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXCOMPILE) -c -fpic -o $@ $<
 @GCC_TRUE@@NATIVE_LINKER_TRUE@protected_3_pic.o: protected_3.cc
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXCOMPILE) -c -fpic -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@relro_test.so: gcctestdir/ld relro_test_pic.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Bgcctestdir/ -shared -Wl,-z,relro relro_test_pic.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@relro_test_pic.o: relro_test.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXCOMPILE) -c -fpic -o $@ $<
 @GCC_TRUE@@NATIVE_LINKER_TRUE@justsyms_2.o: justsyms_2.cc
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXCOMPILE) -c -o $@ $<
 @GCC_TRUE@@NATIVE_LINKER_TRUE@justsyms_2r.o: justsyms_2.o gcctestdir/ld $(srcdir)/justsyms.t
Index: testsuite/relro_test.cc
===================================================================
RCS file: testsuite/relro_test.cc
diff -N testsuite/relro_test.cc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/relro_test.cc	20 May 2008 03:49:27 -0000
@@ -0,0 +1,114 @@
+// relro_test.cc -- test -z relro for gold
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// This file is part of gold.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
+#include <cassert>
+#include <csignal>
+#include <stdint.h>
+#include <unistd.h>
+
+// This code is put into a shared library linked with -z relro.
+
+// i1 and i2 are not relro variables.
+int i1 = 1;
+static int i2 = 2;
+
+// P1 is a global relro variable.
+int* const p1 = &i1;
+
+// P2 is a local relro variable.
+int* const p2 = &i2;
+
+// Test symbol addresses.
+
+bool
+t1()
+{
+  void* i1addr = static_cast<void*>(&i1);
+  void* i2addr = static_cast<void*>(&i2);
+  const void* p1addr = static_cast<const void*>(&p1);
+  const void* p2addr = static_cast<const void*>(&p2);
+
+  // The relro variables should precede the non-relro variables in the
+  // memory image.
+  assert(i1addr > p1addr);
+  assert(i1addr > p2addr);
+  assert(i2addr > p1addr);
+  assert(i2addr > p2addr);
+
+  // The relro variables should not be on the same page as the
+  // non-relro variables.
+  const size_t page_size = getpagesize();
+  uintptr_t i1page = reinterpret_cast<uintptr_t>(i1addr) & ~ (page_size - 1);
+  uintptr_t i2page = reinterpret_cast<uintptr_t>(i2addr) & ~ (page_size - 1);
+  uintptr_t p1page = reinterpret_cast<uintptr_t>(p1addr) & ~ (page_size - 1);
+  uintptr_t p2page = reinterpret_cast<uintptr_t>(p2addr) & ~ (page_size - 1);
+  assert(i1page != p1page);
+  assert(i1page != p2page);
+  assert(i2page != p1page);
+  assert(i2page != p2page);
+
+  return true;
+}
+
+// A signal handler for SIGSEGV.
+
+extern "C"
+void
+sigsegv_handler(int)
+{
+  throw 0;
+}
+
+// Use a separate function to throw the exception, so that we don't
+// need to use -fnon-call-exceptions.
+
+void f2() __attribute__ ((noinline));
+void
+f2()
+{
+  int** pp1 = const_cast<int**>(&p1);
+  *pp1 = &i2;
+
+  // We shouldn't get here--the assignment to *pp1 should write to
+  // memory which the dynamic linker marked as read-only, giving us a
+  // SIGSEGV, causing sigsegv_handler to be invoked, to throw past us.
+  assert(0);
+}
+
+// Changing a relro variable should give us a SIGSEGV.
+
+bool
+t2()
+{
+  signal(SIGSEGV, sigsegv_handler);
+
+  try
+    {
+      f2();
+      return false;
+    }
+  catch (int i)
+    {
+      assert(i == 0);
+      return true;
+    }
+}
Index: testsuite/relro_test_main.cc
===================================================================
RCS file: testsuite/relro_test_main.cc
diff -N testsuite/relro_test_main.cc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/relro_test_main.cc	20 May 2008 03:49:27 -0000
@@ -0,0 +1,33 @@
+// relro_test_main.cc -- test -z relro for gold, main function
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// This file is part of gold.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
+#include <cassert>
+
+extern bool t1();
+extern bool t2();
+
+int
+main()
+{
+  assert(t1());
+  assert(t2());
+}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]