[gold patch] Fix relro problem on ARM

Cary Coutant ccoutant@google.com
Tue Nov 16 18:56:00 GMT 2010


Doug found that the PT_GNU_RELRO segment still wasn't being aligned
properly on ARM, and we discovered that if the ORDER_RELRO_LAST list
is empty (as it is for ARM), the padding we add doesn't get accounted
for when setting the segment size. This patch fixes that by adding the
padding to the increase_relro value, which is later added to the
segment size in Output_segment::set_offset(). We also added an assert
in set_offset() to verify that the RELRO segment is correctly aligned.

Tested on x86_64 and ARM. OK?

-cary (& Doug)

        * output.h (Output_segment::set_section_addresses): Pass increase_relro
        by reference; adjust all callers.
        * output.cc (Output_segment::set_section_addresses): Adjust references
        to increase_relro. Add padding to *increase_relro when ORDER_RELRO_LAST
        list is empty.
        (Output_segment::set_offset): Assert if PT_GNU_RELRO segment does not
        end at page boundary.
-------------- next part --------------
Index: layout.cc
===================================================================
RCS file: /cvs/src/src/gold/layout.cc,v
retrieving revision 1.186
diff -u -p -r1.186 layout.cc
--- layout.cc	9 Nov 2010 07:56:10 -0000	1.186
+++ layout.cc	15 Nov 2010 20:07:43 -0000
@@ -2662,7 +2662,7 @@ Layout::set_segment_offsets(const Target
 	  unsigned int shndx_hold = *pshndx;
 	  bool has_relro = false;
 	  uint64_t new_addr = (*p)->set_section_addresses(this, false, addr,
-							  increase_relro,
+							  &increase_relro,
 							  &has_relro,
                                                           &off, pshndx);
 
@@ -2692,7 +2692,7 @@ Layout::set_segment_offsets(const Target
 		  off = orig_off + ((addr - orig_addr) & (abi_pagesize - 1));
 		  off = align_file_offset(off, addr, abi_pagesize);
 		  new_addr = (*p)->set_section_addresses(this, true, addr,
-							 increase_relro,
+							 &increase_relro,
 							 &has_relro,
                                                          &off, pshndx);
 		}
Index: output.h
===================================================================
RCS file: /cvs/src/src/gold/output.h,v
retrieving revision 1.116
diff -u -p -r1.116 output.h
--- output.h	29 Oct 2010 20:49:20 -0000	1.116
+++ output.h	15 Nov 2010 20:07:43 -0000
@@ -3911,7 +3911,7 @@ class Output_segment
   // *PSHNDX.  This should only be called for a PT_LOAD segment.
   uint64_t
   set_section_addresses(const Layout*, bool reset, uint64_t addr,
-			unsigned int increase_relro, bool* has_relro,
+			unsigned int* increase_relro, bool* has_relro,
 			off_t* poff, unsigned int* pshndx);
 
   // Set the minimum alignment of this segment.  This may be adjusted
Index: output.cc
===================================================================
RCS file: /cvs/src/src/gold/output.cc,v
retrieving revision 1.137
diff -u -p -r1.137 output.cc
--- output.cc	29 Oct 2010 20:49:20 -0000	1.137
+++ output.cc	15 Nov 2010 20:07:43 -0000
@@ -3692,7 +3692,7 @@ Output_segment::has_dynamic_reloc_list(c
 uint64_t
 Output_segment::set_section_addresses(const Layout* layout, bool reset,
                                       uint64_t addr,
-				      unsigned int increase_relro,
+				      unsigned int* increase_relro,
 				      bool* has_relro,
 				      off_t* poff,
 				      unsigned int* pshndx)
@@ -3752,7 +3752,7 @@ Output_segment::set_section_addresses(co
 	  if (p != pdl->end())
 	    break;
 	}
-      relro_size += increase_relro;
+      relro_size += *increase_relro;
       // Pad the total relro size to a multiple of the maximum
       // section alignment seen.
       uint64_t aligned_size = align_address(relro_size, max_align);
@@ -3795,6 +3795,13 @@ Output_segment::set_section_addresses(co
 	{
 	  *poff += last_relro_pad;
 	  addr += last_relro_pad;
+	  if (this->output_lists_[i].empty())
+	    {
+	      // If there is nothing in the ORDER_RELRO_LAST list,
+	      // the padding will occur at the end of the relro
+	      // segment, and we need to add it to *INCREASE_RELRO.
+	      *increase_relro += last_relro_pad;
+	    }
 	}
       addr = this->set_section_list_addresses(layout, reset,
 					      &this->output_lists_[i],
@@ -4014,6 +4021,15 @@ Output_segment::set_offset(unsigned int 
   this->filesz_ += increase;
   this->memsz_ += increase;
 
+  // If this is a RELRO segment, verify that the segment ends at a
+  // page boundary.
+  if (this->type_ == elfcpp::PT_GNU_RELRO)
+    {
+      uint64_t page_align = parameters->target().common_pagesize();
+      uint64_t segment_end = this->vaddr_ + this->memsz_;
+      gold_assert(segment_end == align_address(segment_end, page_align));
+    }
+
   // 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.


More information about the Binutils mailing list