This is the mail archive of the binutils@sources.redhat.com 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]

[RFC PATCH] Little hardening DSOs/executables against exploits


Hi!

The following patch reorders the sections in the RW segment to make various
exploits a little bit harder.  If ATM some exploit e.g. overflows a buffer
in .data section, it may very well overwrite .got, .got.plt etc.
With this patch, sections which are writable only because of relocation
handling come first in the RW PT_LOAD segment.

Also, it adds new ld option, -z relro, with which the linker attempts to
align the RW segment such that the area which can be read-only after
relocation processing ends on a (commonly used) page boundary (which can
be smaller than ELF maximum page size) and adds a PT_GNU_RELRO program
header which tells the dynamic linker where the RELRO area is.
The dynamic linker can decide to mprotect this area after relocation
processing.

On IA-32/AMD64 (should be doable on s390/s390x as well) also splits
.got.plt from .got section and puts .got before .got.plt.  That way
.got can be in RELRO area (it is only written into during relocation
processing) and keep the .got.plt (with the exception of first 12 bytes in
it) outside of the RELRO area (as it is being written into after relocation
processing during lazy binding).

The patch doesn't move .got section on architectures with .sdata/.sbss yet.
The problem is that moving .got before .data could make the distance between
end of .sbss and .got too big and thus not reachable by the limited GOT
relative immediates.  What could perhaps be done is:
a) if the whole RW segment is small enough (everything is reachable with
   the machine dependent limit), move .got like on NO_SMALL_DATA arches
b) if .sbss is small enough, it could convert .sbss into SHT_PROGBITS
   section, move .got to the end of RELRO area, then put .sdata and .sbss
   and follow with .data etc.
c) otherwise leave .got where it is now
The question is how to write this into the linker script.

2004-01-06  Jakub Jelinek  <jakub@redhat.com>

bfd/
	* elf32-i386.c (elf_i386_finish_dynamic_sections): Point
	DT_PLTGOT to the start of .got.plt section instead of
	.got output section.
	* elf64-x86-64.c (elf64_x86_64_finish_dynamic_sections): Likewise.
	* elf.c (_bfd_elf_print_private_bfd_data): Handle PT_GNU_RELRO.
	(bfd_section_from_phdr): Likewise.
	(map_sections_to_segments): Likewise.
	(assign_file_positions_for_segments): Likewise.
	(get_program_header_size): Likewise.
	* elflink.h (size_dynamic_sections): Set elf_tdata (output_bfd)->relro
	from info->relro.
	* elf-bfd.h (struct elf_obj_tdata): Add relro field.
include/
	* bfdlink.h (struct bfd_link_info): Add relro, relro_start and
	relro_end fields.
	* elf/common.h (PT_GNU_EH_FRAME, PT_GNU_STACK): Add comments.
	(PT_GNU_RELRO): Define.
binutils/
	* readelf.c (get_segment_type): Handle PT_GNU_RELRO.
ld/
	* emulparams/elf_i386.sh (SEPARATE_GOTPLT): Set.
	* ldlex.l (DATA_SEGMENT_RELRO_END): Add.
	* emultempl/elf32.em (gld${EMULATION_NAME}_handle_option): Handle
	-z relro and -z norelro.
	(gld${EMULATION_NAME}_list_options): Add it to usage.
	* scripttempl/elf.sc: Create separate .got.plt section if
	SEPARATE_GOTPLT.  Move sections which are only written during
	relocation handling to the beginning of RW segment.  If
	NO_SMALL_DATA, move .got before .data.  Add DATA_SEGMENT_RELRO_END
	directive.
	* ldgram.y (DATA_SEGMENT_RELRO_END): Add.
	* ldexp.c (exp_print_token): Handle DATA_SEGMENT_RELRO_END.
	(fold_unary): Likewise.
	(fold_binary): Handle -z relro.
	* ldexp.h (struct exp_data_seg): Add exp_dataseg_relro_seen and
	exp_dataseg_relro_adjust phases.  Add relro_end field.
	* ldmain.c (main): Initialize link_info.relro to FALSE.
	* ldlang.c (lang_size_sections): Handle -z relro.

--- binutils/readelf.c.jj	2004-01-02 19:13:02.000000000 +0100
+++ binutils/readelf.c	2004-01-06 17:14:44.000000000 +0100
@@ -2144,6 +2144,7 @@ get_segment_type (unsigned long p_type)
     case PT_GNU_EH_FRAME:
 			return "GNU_EH_FRAME";
     case PT_GNU_STACK:	return "STACK";
+    case PT_GNU_RELRO:  return "GNU_RELRO";
 
     default:
       if ((p_type >= PT_LOPROC) && (p_type <= PT_HIPROC))
--- bfd/elf32-i386.c.jj	2004-01-02 19:13:01.000000000 +0100
+++ bfd/elf32-i386.c	2004-01-05 09:47:20.000000000 +0100
@@ -3167,7 +3167,8 @@ elf_i386_finish_dynamic_sections (bfd *o
 	      continue;
 
 	    case DT_PLTGOT:
-	      dyn.d_un.d_ptr = htab->sgot->output_section->vma;
+	      s = htab->sgotplt;
+	      dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
 	      break;
 
 	    case DT_JMPREL:
--- bfd/elf.c.jj	2003-12-22 10:54:05.000000000 +0100
+++ bfd/elf.c	2004-01-06 17:12:46.000000000 +0100
@@ -967,6 +967,7 @@ _bfd_elf_print_private_bfd_data (bfd *ab
 	    case PT_TLS: pt = "TLS"; break;
 	    case PT_GNU_EH_FRAME: pt = "EH_FRAME"; break;
 	    case PT_GNU_STACK: pt = "STACK"; break;
+	    case PT_GNU_RELRO: pt = "RELRO"; break;
 	    default: sprintf (buf, "0x%lx", p->p_type); pt = buf; break;
 	    }
 	  fprintf (f, "%8s off    0x", pt);
@@ -2291,6 +2292,9 @@ bfd_section_from_phdr (bfd *abfd, Elf_In
     case PT_GNU_STACK:
       return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "stack");
 
+    case PT_GNU_RELRO:
+      return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "relro");
+
     default:
       /* Check for any processor-specific program segment types.
          If no handler for them, default to making "segment" sections.  */
@@ -3501,6 +3505,21 @@ map_sections_to_segments (bfd *abfd)
       pm = &m->next;
     }
 
+  if (elf_tdata (abfd)->relro)
+    {
+      amt = sizeof (struct elf_segment_map);
+      m = bfd_zalloc (abfd, amt);
+      if (m == NULL)
+	goto error_return;
+      m->next = NULL;
+      m->p_type = PT_GNU_RELRO;
+      m->p_flags = PF_R;
+      m->p_flags_valid = 1;
+
+      *pm = m;
+      pm = &m->next;
+    }
+
   free (sections);
   sections = NULL;
 
@@ -4002,6 +4021,37 @@ Error: First section in segment (%s) sta
 	      if (! m->p_paddr_valid)
 		p->p_paddr = phdrs_paddr;
 	    }
+	  else if (p->p_type == PT_GNU_RELRO)
+	    {
+	      Elf_Internal_Phdr *lp;
+
+	      for (lp = phdrs; lp < phdrs + count; ++lp)
+		{
+		  if (lp->p_type == PT_LOAD
+		      && lp->p_vaddr <= link_info->relro_start
+		      && lp->p_vaddr + lp->p_filesz
+			 >= link_info->relro_end)
+		    break;
+		}
+
+	      if (lp < phdrs + count
+		  && link_info->relro_end > link_info->relro_start)
+		{
+		  bfd_vma diff = link_info->relro_start - lp->p_vaddr;
+		  p->p_vaddr = lp->p_vaddr + diff;
+		  p->p_paddr = lp->p_paddr + diff;
+		  p->p_offset = lp->p_offset + diff;
+		  p->p_filesz = link_info->relro_end - link_info->relro_start;
+		  p->p_memsz = p->p_filesz;
+		  p->p_align = 1;
+		  p->p_flags = (lp->p_flags & ~PF_W);
+		}
+	      else
+		{
+		  memset (p, 0, sizeof *p);
+		  p->p_type = PT_NULL;
+		}
+	    }
 	}
     }
 
@@ -4089,6 +4139,12 @@ get_program_header_size (bfd *abfd)
       ++segs;
     }
 
+  if (elf_tdata (abfd)->relro)
+    {
+      /* We need a PT_GNU_RELRO segment.  */
+      ++segs;
+    }
+
   for (s = abfd->sections; s != NULL; s = s->next)
     {
       if ((s->flags & SEC_LOAD) != 0
--- bfd/elflink.h.jj	2004-01-02 19:13:02.000000000 +0100
+++ bfd/elflink.h	2004-01-06 16:55:53.000000000 +0100
@@ -1909,6 +1909,7 @@ NAME(bfd_elf,size_dynamic_sections) (bfd
   if (!is_elf_hash_table (info->hash))
     return TRUE;
 
+  elf_tdata (output_bfd)->relro = info->relro;
   if (info->execstack)
     elf_tdata (output_bfd)->stack_flags = PF_R | PF_W | PF_X;
   else if (info->noexecstack)
--- bfd/elf64-x86-64.c.jj	2003-12-22 10:49:42.000000000 +0100
+++ bfd/elf64-x86-64.c	2004-01-05 09:50:07.000000000 +0100
@@ -2667,7 +2667,8 @@ elf64_x86_64_finish_dynamic_sections (bf
 	      continue;
 
 	    case DT_PLTGOT:
-	      dyn.d_un.d_ptr = htab->sgot->output_section->vma;
+	      s = htab->sgotplt;
+	      dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
 	      break;
 
 	    case DT_JMPREL:
--- bfd/elf-bfd.h.jj	2003-12-22 10:54:05.000000000 +0100
+++ bfd/elf-bfd.h	2004-01-06 16:57:09.000000000 +0100
@@ -1202,6 +1202,9 @@ struct elf_obj_tdata
   /* Segment flags for the PT_GNU_STACK segment.  */
   unsigned int stack_flags;  
 
+  /* Should the PT_GNU_RELRO segment be emitted?  */
+  bfd_boolean relro;
+
   /* Symbol version definitions in external objects.  */
   Elf_Internal_Verdef *verdef;
 
--- include/bfdlink.h.jj	2003-12-22 10:55:57.000000000 +0100
+++ include/bfdlink.h	2004-01-06 16:41:20.000000000 +0100
@@ -302,6 +302,9 @@ struct bfd_link_info
      flags.  */
   unsigned int noexecstack: 1;
 
+  /* TRUE if PT_GNU_RELRO segment should be created.  */
+  unsigned int relro: 1;
+
   /* What to do with unresolved symbols in an object file.
      When producing static binaries the default is GENERATE_ERROR.
      When producing dynamic binaries the default is IGNORE.  The
@@ -386,6 +389,9 @@ struct bfd_link_info
 
   /* May be used to set DT_FLAGS_1 for ELF. */
   bfd_vma flags_1;
+
+  /* Start and end of RELRO region.  */
+  bfd_vma relro_start, relro_end;
 };
 
 /* This structures holds a set of callback functions.  These are
--- include/elf/common.h.jj	2003-12-22 10:49:49.000000000 +0100
+++ include/elf/common.h	2004-01-05 09:56:57.000000000 +0100
@@ -287,8 +287,9 @@
 #define PT_LOPROC	0x70000000	/* Processor-specific */
 #define PT_HIPROC	0x7FFFFFFF	/* Processor-specific */
 
-#define PT_GNU_EH_FRAME	(PT_LOOS + 0x474e550)
-#define PT_GNU_STACK	(PT_LOOS + 0x474e551)
+#define PT_GNU_EH_FRAME	(PT_LOOS + 0x474e550) /* Frame unwind information */
+#define PT_GNU_STACK	(PT_LOOS + 0x474e551) /* Stack flags */
+#define PT_GNU_RELRO	(PT_LOOS + 0x474e552) /* Read-only after relocation */
 
 /* Program segment permissions, in program header p_flags field.  */
 
--- ld/emulparams/elf_i386.sh.jj	2003-05-30 17:19:17.000000000 +0200
+++ ld/emulparams/elf_i386.sh	2004-01-05 10:38:05.000000000 +0100
@@ -11,3 +11,4 @@ TEMPLATE_NAME=elf32
 GENERATE_SHLIB_SCRIPT=yes
 GENERATE_PIE_SCRIPT=yes
 NO_SMALL_DATA=yes
+SEPARATE_GOTPLT=12
--- ld/ldlex.l.jj	2003-10-30 15:12:10.000000000 +0100
+++ ld/ldlex.l	2004-01-05 11:13:43.000000000 +0100
@@ -254,6 +254,7 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([
 <BOTH,SCRIPT>"LENGTH"		{ RTOKEN(LENGTH);}
 <EXPRESSION,BOTH,SCRIPT>"ALIGN"			{ RTOKEN(ALIGN_K);}
 <EXPRESSION,BOTH,SCRIPT>"DATA_SEGMENT_ALIGN"	{ RTOKEN(DATA_SEGMENT_ALIGN);}
+<EXPRESSION,BOTH,SCRIPT>"DATA_SEGMENT_RELRO_END"	{ RTOKEN(DATA_SEGMENT_RELRO_END);}
 <EXPRESSION,BOTH,SCRIPT>"DATA_SEGMENT_END"	{ RTOKEN(DATA_SEGMENT_END);}
 <EXPRESSION,BOTH,SCRIPT>"ADDR"			{ RTOKEN(ADDR);}
 <EXPRESSION,BOTH,SCRIPT>"LOADADDR"		{ RTOKEN(LOADADDR);}
--- ld/emultempl/elf32.em.jj	2004-01-05 09:25:59.000000000 +0100
+++ ld/emultempl/elf32.em	2004-01-06 14:31:02.000000000 +0100
@@ -1645,6 +1645,10 @@ cat >>e${EMULATION_NAME}.c <<EOF
 	  link_info.noexecstack = TRUE;
 	  link_info.execstack = FALSE;
 	}
+      else if (strcmp (optarg, "relro") == 0)
+	link_info.relro = TRUE;
+      else if (strcmp (optarg, "norelro") == 0)
+	link_info.relro = FALSE;
       /* What about the other Solaris -z options? FIXME.  */
       break;
 EOF
@@ -1692,8 +1696,10 @@ cat >>e${EMULATION_NAME}.c <<EOF
   fprintf (file, _("  -z nodlopen\t\tMark DSO not available to dlopen\n"));
   fprintf (file, _("  -z nodump\t\tMark DSO not available to dldump\n"));
   fprintf (file, _("  -z noexecstack\tMark executable as not requiring executable stack\n"));
+  fprintf (file, _("  -z norelro\tDon't create RELRO program header\n"));
   fprintf (file, _("  -z now\t\tMark object non-lazy runtime binding\n"));
   fprintf (file, _("  -z origin\t\tMark object requiring immediate \$ORIGIN processing\n\t\t\t  at runtime\n"));
+  fprintf (file, _("  -z relro\tCreate RELRO program header\n"));
   fprintf (file, _("  -z KEYWORD\t\tIgnored for Solaris compatibility\n"));
 EOF
 fi
--- ld/scripttempl/elf.sc.jj	2003-10-15 17:45:41.000000000 +0200
+++ ld/scripttempl/elf.sc	2004-01-06 12:46:15.000000000 +0100
@@ -75,14 +75,27 @@ test "$LD_FLAG" = "N" && DATA_ADDR=.
 test -n "$CREATE_SHLIB$CREATE_PIE" && test -n "$SHLIB_DATA_ADDR" && COMMONPAGESIZE=""
 test -z "$CREATE_SHLIB$CREATE_PIE" && test -n "$DATA_ADDR" && COMMONPAGESIZE=""
 DATA_SEGMENT_ALIGN="ALIGN(${SEGMENT_SIZE}) + (. & (${MAXPAGESIZE} - 1))"
+DATA_SEGMENT_RELRO_END=""
+DATA_SEGMENT_RELRO_GOTPLT_END=""
 DATA_SEGMENT_END=""
 if test -n "${COMMONPAGESIZE}"; then
   DATA_SEGMENT_ALIGN="ALIGN (${SEGMENT_SIZE}) - ((${MAXPAGESIZE} - .) & (${MAXPAGESIZE} - 1)); . = DATA_SEGMENT_ALIGN (${MAXPAGESIZE}, ${COMMONPAGESIZE})"
   DATA_SEGMENT_END=". = DATA_SEGMENT_END (.);"
+  if test -n "${SEPARATE_GOTPLT}"; then
+    DATA_SEGMENT_RELRO_GOTPLT_END=". = DATA_SEGMENT_RELRO_END (. + ${SEPARATE_GOTPLT});"
+  else
+    DATA_SEGMENT_RELRO_END=". = DATA_SEGMENT_RELRO_END (.);"
+  fi
 fi
 INTERP=".interp       ${RELOCATING-0} : { *(.interp) }"
 PLT=".plt          ${RELOCATING-0} : { *(.plt) }"
-test -z "$GOT" && GOT=".got          ${RELOCATING-0} : { *(.got.plt) *(.got) }"
+if test -z "$GOT"; then
+  if test -z "$SEPARATE_GOTPLT"; then
+    GOT=".got          ${RELOCATING-0} : { *(.got.plt) *(.got) }"
+  else
+    GOT=".got          ${RELOCATING-0} : { *(.got) }"
+  fi
+fi
 DYNAMIC=".dynamic      ${RELOCATING-0} : { *(.dynamic) }"
 RODATA=".rodata       ${RELOCATING-0} : { *(.rodata${RELOCATING+ .rodata.* .gnu.linkonce.r.*}) }"
 STACKNOTE="/DISCARD/ : { *(.note.GNU-stack) }"
@@ -115,7 +128,10 @@ if test -z "${NO_SMALL_DATA}"; then
   .rela.sdata2  ${RELOCATING-0} : { *(.rela.sdata2${RELOCATING+ .rela.sdata2.* .rela.gnu.linkonce.s2.*}) }"
   REL_SBSS2=".rel.sbss2    ${RELOCATING-0} : { *(.rel.sbss2${RELOCATING+ .rel.sbss2.* .rel.gnu.linkonce.sb2.*}) }
   .rela.sbss2   ${RELOCATING-0} : { *(.rela.sbss2${RELOCATING+ .rela.sbss2.* .rela.gnu.linkonce.sb2.*}) }"
+else
+  NO_SMALL_DATA=" "
 fi
+test -n "$SEPARATE_GOTPLT" && SEPARATE_GOTPLT=" "
 CTOR=".ctors        ${CONSTRUCTING-0} : 
   {
     ${CONSTRUCTING+${CTOR_START}}
@@ -211,6 +227,8 @@ eval $COMBRELOCCAT <<EOF
   .rel.rodata   ${RELOCATING-0} : { *(.rel.rodata${RELOCATING+ .rel.rodata.* .rel.gnu.linkonce.r.*}) }
   .rela.rodata  ${RELOCATING-0} : { *(.rela.rodata${RELOCATING+ .rela.rodata.* .rela.gnu.linkonce.r.*}) }
   ${OTHER_READONLY_RELOC_SECTIONS}
+  .rel.data.rel.ro ${RELOCATING-0} : { *(.rel.data.rel.ro${RELOCATING+*}) }
+  .rela.data.rel.ro ${RELOCATING-0} : { *(.rel.data.rel.ro${RELOCATING+*}) }
   .rel.data     ${RELOCATING-0} : { *(.rel.data${RELOCATING+ .rel.data.* .rel.gnu.linkonce.d.*}) }
   .rela.data    ${RELOCATING-0} : { *(.rela.data${RELOCATING+ .rela.data.* .rela.gnu.linkonce.d.*}) }
   .rel.tdata	${RELOCATING-0} : { *(.rel.tdata${RELOCATING+ .rel.tdata.* .rel.gnu.linkonce.td.*}) }
@@ -290,6 +308,14 @@ cat <<EOF
   ${CREATE_SHLIB+${RELOCATING+. = ${SHLIB_DATA_ADDR-${DATA_SEGMENT_ALIGN}};}}
   ${CREATE_PIE+${RELOCATING+. = ${SHLIB_DATA_ADDR-${DATA_SEGMENT_ALIGN}};}}
 
+  /* Exception handling  */
+  .eh_frame     ${RELOCATING-0} : { KEEP (*(.eh_frame)) }
+  .gcc_except_table ${RELOCATING-0} : { *(.gcc_except_table) }
+
+  /* Thread Local Storage sections  */
+  .tdata	${RELOCATING-0} : { *(.tdata${RELOCATING+ .tdata.* .gnu.linkonce.td.*}) }
+  .tbss		${RELOCATING-0} : { *(.tbss${RELOCATING+ .tbss.* .gnu.linkonce.tb.*})${RELOCATING+ *(.tcommon)} }
+
   /* Ensure the __preinit_array_start label is properly aligned.  We
      could instead move the label definition inside the section, but
      the linker would then create the section even if it turns out to
@@ -307,6 +333,19 @@ cat <<EOF
   .fini_array   ${RELOCATING-0} : { *(.fini_array) }
   ${RELOCATING+${CREATE_SHLIB-PROVIDE (__fini_array_end = .);}}
 
+  ${RELOCATING+${CTOR}}
+  ${RELOCATING+${DTOR}}
+  .jcr          ${RELOCATING-0} : { KEEP (*(.jcr)) }
+
+  ${RELOCATING+.data.rel.ro : { *(.data.rel.ro.local) *(.data.rel.ro*) }}
+  ${TEXT_DYNAMIC-${DYNAMIC}}
+  ${NO_SMALL_DATA+${SEPARATE_GOTPLT+${GOT}}}
+  ${NO_SMALL_DATA+${SEPARATE_GOTPLT+.got.plt      ${RELOCATING-0} : { ${DATA_SEGMENT_RELRO_GOTPLT_END} *(.got.plt) }}}
+  ${DATA_SEGMENT_RELRO_END}
+  ${NO_SMALL_DATA+${SEPARATE_GOTPLT-${GOT}}}
+
+  ${DATA_PLT+${PLT}}
+
   .data         ${RELOCATING-0} :
   {
     ${RELOCATING+${DATA_START_SYMBOLS}}
@@ -314,19 +353,10 @@ cat <<EOF
     ${CONSTRUCTING+SORT(CONSTRUCTORS)}
   }
   .data1        ${RELOCATING-0} : { *(.data1) }
-  .tdata	${RELOCATING-0} : { *(.tdata${RELOCATING+ .tdata.* .gnu.linkonce.td.*}) }
-  .tbss		${RELOCATING-0} : { *(.tbss${RELOCATING+ .tbss.* .gnu.linkonce.tb.*})${RELOCATING+ *(.tcommon)} }
-  .eh_frame     ${RELOCATING-0} : { KEEP (*(.eh_frame)) }
-  .gcc_except_table ${RELOCATING-0} : { *(.gcc_except_table) }
   ${WRITABLE_RODATA+${RODATA}}
   ${OTHER_READWRITE_SECTIONS}
-  ${TEXT_DYNAMIC-${DYNAMIC}}
-  ${RELOCATING+${CTOR}}
-  ${RELOCATING+${DTOR}}
-  .jcr          ${RELOCATING-0} : { KEEP (*(.jcr)) }
-  ${DATA_PLT+${PLT}}
   ${RELOCATING+${OTHER_GOT_SYMBOLS}}
-  ${GOT}
+  ${NO_SMALL_DATA-${GOT}}
   ${OTHER_GOT_SECTIONS}
   ${CREATE_SHLIB+${SDATA2}}
   ${CREATE_SHLIB+${SBSS2}}
--- ld/ldgram.y.jj	2004-01-05 09:25:58.000000000 +0100
+++ ld/ldgram.y	2004-01-05 11:14:46.000000000 +0100
@@ -128,7 +128,7 @@ static int error_index;
 %token END
 %left <token> '('
 %token <token> ALIGN_K BLOCK BIND QUAD SQUAD LONG SHORT BYTE
-%token SECTIONS PHDRS SORT DATA_SEGMENT_ALIGN DATA_SEGMENT_END
+%token SECTIONS PHDRS SORT DATA_SEGMENT_ALIGN DATA_SEGMENT_RELRO_END DATA_SEGMENT_END
 %token '{' '}'
 %token SIZEOF_HEADERS OUTPUT_FORMAT FORCE_COMMON_ALLOCATION OUTPUT_ARCH
 %token INHIBIT_COMMON_ALLOCATION
@@ -803,6 +803,8 @@ exp	:
 			{ $$ = exp_unop(ALIGN_K,$3); }
 	|	DATA_SEGMENT_ALIGN '(' exp ',' exp ')'
 			{ $$ = exp_binop (DATA_SEGMENT_ALIGN, $3, $5); }
+	|	DATA_SEGMENT_RELRO_END '(' exp ')'
+			{ $$ = exp_unop(DATA_SEGMENT_RELRO_END, $3); }
 	|	DATA_SEGMENT_END '(' exp ')'
 			{ $$ = exp_unop(DATA_SEGMENT_END, $3); }
 	|	BLOCK '(' exp ')'
--- ld/ldexp.c.jj	2004-01-05 09:25:57.000000000 +0100
+++ ld/ldexp.c	2004-01-06 17:05:25.000000000 +0100
@@ -101,6 +101,7 @@ exp_print_token (token_code_type code, i
     { MAX_K, "MAX_K" },
     { REL, "relocatable" },
     { DATA_SEGMENT_ALIGN, "DATA_SEGMENT_ALIGN" },
+    { DATA_SEGMENT_RELRO_END, "DATA_SEGMENT_RELRO_END" },
     { DATA_SEGMENT_END, "DATA_SEGMENT_END" }
   };
   unsigned int idx;
@@ -275,14 +276,36 @@ fold_unary (etree_type *tree,
 	    result.valid_p = FALSE;
 	  break;
 
+	case DATA_SEGMENT_RELRO_END:
+	  if (allocation_done != lang_first_phase_enum
+	      && (exp_data_seg.phase == exp_dataseg_align_seen
+		  || exp_data_seg.phase == exp_dataseg_adjust
+		  || exp_data_seg.phase == exp_dataseg_relro_adjust
+		  || allocation_done != lang_allocating_phase_enum))
+	    {
+	      if (exp_data_seg.phase == exp_dataseg_align_seen
+		  || exp_data_seg.phase == exp_dataseg_relro_adjust)
+		exp_data_seg.relro_end
+		  = result.value + current_section->bfd_section->vma;
+	      if (exp_data_seg.phase == exp_dataseg_align_seen)
+		exp_data_seg.phase = exp_dataseg_relro_seen;
+	      result.value = dot - current_section->bfd_section->vma;
+	    }
+	  else
+	    result.valid_p = FALSE;
+	  break;
+
 	case DATA_SEGMENT_END:
 	  if (allocation_done != lang_first_phase_enum
 	      && current_section == abs_output_section
 	      && (exp_data_seg.phase == exp_dataseg_align_seen
+		  || exp_data_seg.phase == exp_dataseg_relro_seen
 		  || exp_data_seg.phase == exp_dataseg_adjust
+		  || exp_data_seg.phase == exp_dataseg_relro_adjust
 		  || allocation_done != lang_allocating_phase_enum))
 	    {
-	      if (exp_data_seg.phase == exp_dataseg_align_seen)
+	      if (exp_data_seg.phase == exp_dataseg_align_seen
+		  || exp_data_seg.phase == exp_dataseg_relro_seen)
 		{
 		  exp_data_seg.phase = exp_dataseg_end_seen;
 		  exp_data_seg.end = result.value;
@@ -399,12 +422,23 @@ fold_binary (etree_type *tree,
 		  && current_section == abs_output_section
 		  && (exp_data_seg.phase == exp_dataseg_none
 		      || exp_data_seg.phase == exp_dataseg_adjust
+		      || exp_data_seg.phase == exp_dataseg_relro_adjust
 		      || allocation_done != lang_allocating_phase_enum))
 		{
 		  bfd_vma maxpage = result.value;
 
 		  result.value = align_n (dot, maxpage);
-		  if (exp_data_seg.phase != exp_dataseg_adjust)
+		  if (exp_data_seg.phase == exp_dataseg_relro_adjust)
+		    {
+		      /* Attempt to align DATA_SEGMENT_RELRO_END at
+			 a common page boundary.  */
+		      bfd_vma relro;
+
+		      relro = exp_data_seg.relro_end - exp_data_seg.base;
+		      result.value += -relro & (other.value - 1);
+		      exp_data_seg.base = result.value;
+		    }
+		  else if (exp_data_seg.phase != exp_dataseg_adjust)
 		    {
 		      result.value += dot & (maxpage - 1);
 		      if (allocation_done == lang_allocating_phase_enum)
@@ -412,6 +446,7 @@ fold_binary (etree_type *tree,
 			  exp_data_seg.phase = exp_dataseg_align_seen;
 			  exp_data_seg.base = result.value;
 			  exp_data_seg.pagesize = other.value;
+			  exp_data_seg.relro_end = 0;
 			}
 		    }
 		  else if (other.value < maxpage)
--- ld/ldexp.h.jj	2004-01-05 09:25:57.000000000 +0100
+++ ld/ldexp.h	2004-01-06 14:36:26.000000000 +0100
@@ -95,10 +95,12 @@ extern struct exp_data_seg {
   enum {
     exp_dataseg_none,
     exp_dataseg_align_seen,
+    exp_dataseg_relro_seen,
     exp_dataseg_end_seen,
+    exp_dataseg_relro_adjust,
     exp_dataseg_adjust
   } phase;
-  bfd_vma base, end, pagesize;
+  bfd_vma base, relro_end, end, pagesize;
 } exp_data_seg;
 
 typedef struct _fill_type fill_type;
--- ld/ldmain.c.jj	2003-12-22 10:49:49.000000000 +0100
+++ ld/ldmain.c	2004-01-06 14:29:36.000000000 +0100
@@ -299,6 +299,7 @@ main (int argc, char **argv)
   link_info.new_dtags = FALSE;
   link_info.combreloc = TRUE;
   link_info.eh_frame_hdr = FALSE;
+  link_info.relro = FALSE;
   link_info.strip_discarded = TRUE;
   link_info.strip = strip_none;
   link_info.discard = discard_sec_merge;
--- ld/ldlang.c.jj	2004-01-05 09:25:58.000000000 +0100
+++ ld/ldlang.c	2004-01-06 16:42:54.000000000 +0100
@@ -3268,7 +3268,19 @@ lang_size_sections
   exp_data_seg.phase = exp_dataseg_none;
   result = lang_size_sections_1 (s, output_section_statement, prev, fill,
 				 dot, relax, check_regions);
-  if (exp_data_seg.phase == exp_dataseg_end_seen)
+  if (exp_data_seg.phase == exp_dataseg_end_seen
+      && link_info.relro && exp_data_seg.relro_end)
+    {
+      /* If DATA_SEGMENT_ALIGN DATA_SEGMENT_RELRO_END pair was seen, try
+	 to put exp_data_seg.relro on a (common) page boundary.  */
+
+      exp_data_seg.phase = exp_dataseg_relro_adjust;
+      result = lang_size_sections_1 (s, output_section_statement, prev, fill,
+				     dot, relax, check_regions);
+      link_info.relro_start = exp_data_seg.base;
+      link_info.relro_end = exp_data_seg.relro_end;
+    }
+  else if (exp_data_seg.phase == exp_dataseg_end_seen)
     {
       /* If DATA_SEGMENT_ALIGN DATA_SEGMENT_END pair was seen, check whether
 	 a page could be saved in the data segment.  */

	Jakub


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