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]

Re: [RFC PATCH] Little hardening DSOs/executables against exploits (take 2)


Hi!

Below is an updated patch for the ELF DSO/executable section reshuffling
to make life harder for data section buffer overflows.
The previous patch had problems on IA-32, because elf32-i386.c assumed
in many places that _GLOBAL_OFFSET_TABLE_ is
htab->sgot->output_section->vma, while it actually is
htab->sgotplt->output_section->vma + htab->sgotplt->output_offset.

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

bfd/
	* elf32-i386.c (elf_i386_finish_dynamic_sections): Point
	DT_PLTGOT to the start of the .got.plt section instead of the
	.got output section.
	(elf_i386_relocate_section): Don't assume _GLOBAL_OFFSET_TABLE_
	is at sgot->output_section->vma.
	* elf64-x86-64.c (elf64_x86_64_finish_dynamic_sections): Point
	DT_PLTGOT to the start of the .got.plt section instead of the
	.got output section.
	(elf64_x86_64_relocate_section): Don't assume _GLOBAL_OFFSET_TABLE_
	is at sgot->output_section->vma.
	* 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.
	* emulparams/elf_x86_64.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-12 10:08:00.000000000 +0100
+++ binutils/readelf.c	2004-01-12 12:00:49.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-12 14:04:50.000000000 +0100
@@ -2269,24 +2269,29 @@ elf_i386_relocate_section (bfd *output_b
 	  if (off >= (bfd_vma) -2)
 	    abort ();
 
-	  relocation = htab->sgot->output_offset + off;
+	  relocation = htab->sgot->output_section->vma
+		       + htab->sgot->output_offset + off
+		       - htab->sgotplt->output_section->vma
+		       - htab->sgotplt->output_offset;
 	  break;
 
 	case R_386_GOTOFF:
 	  /* Relocation is relative to the start of the global offset
 	     table.  */
 
-	  /* Note that sgot->output_offset is not involved in this
-	     calculation.  We always want the start of .got.  If we
-	     defined _GLOBAL_OFFSET_TABLE in a different way, as is
+	  /* Note that sgot is not involved in this
+	     calculation.  We always want the start of .got.plt.  If we
+	     defined _GLOBAL_OFFSET_TABLE_ in a different way, as is
 	     permitted by the ABI, we might have to change this
 	     calculation.  */
-	  relocation -= htab->sgot->output_section->vma;
+	  relocation -= htab->sgotplt->output_section->vma
+			+ htab->sgotplt->output_offset;
 	  break;
 
 	case R_386_GOTPC:
 	  /* Use global offset table as symbol value.  */
-	  relocation = htab->sgot->output_section->vma;
+	  relocation = htab->sgotplt->output_section->vma
+		       + htab->sgotplt->output_offset;
 	  unresolved_reloc = FALSE;
 	  break;
 
@@ -2707,12 +2712,15 @@ elf_i386_relocate_section (bfd *output_b
 	    abort ();
 	  if (r_type == ELF32_R_TYPE (rel->r_info))
 	    {
-	      relocation = htab->sgot->output_offset + off;
+	      bfd_vma g_o_t = htab->sgotplt->output_section->vma
+			      + htab->sgotplt->output_offset;
+	      relocation = htab->sgot->output_section->vma
+			   + htab->sgot->output_offset + off - g_o_t;
 	      if ((r_type == R_386_TLS_IE || r_type == R_386_TLS_GOTIE)
 		  && tls_type == GOT_TLS_IE_BOTH)
 		relocation += 4;
 	      if (r_type == R_386_TLS_IE)
-		relocation += htab->sgot->output_section->vma;
+		relocation += g_o_t;
 	      unresolved_reloc = FALSE;
 	    }
 	  else
@@ -2769,7 +2777,11 @@ elf_i386_relocate_section (bfd *output_b
 		  if (tls_type == GOT_TLS_IE_BOTH)
 		    off += 4;
 		}
-	      bfd_put_32 (output_bfd, htab->sgot->output_offset + off,
+	      bfd_put_32 (output_bfd,
+			  htab->sgot->output_section->vma
+			  + htab->sgot->output_offset + off
+			  - htab->sgotplt->output_section->vma
+			  - htab->sgotplt->output_offset,
 			  contents + roff + 8);
 	      /* Skip R_386_PLT32.  */
 	      rel++;
@@ -2831,7 +2843,10 @@ elf_i386_relocate_section (bfd *output_b
 	      bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc);
 	      htab->tls_ldm_got.offset |= 1;
 	    }
-	  relocation = htab->sgot->output_offset + off;
+	  relocation = htab->sgot->output_section->vma
+		       + htab->sgot->output_offset + off
+		       - htab->sgotplt->output_section->vma
+		       - htab->sgotplt->output_offset;
 	  unresolved_reloc = FALSE;
 	  break;
 
@@ -3167,7 +3182,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-12 12:00:49.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-12 12:00:49.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-12 14:27:11.000000000 +0100
@@ -1919,9 +1919,11 @@ elf64_x86_64_relocate_section (bfd *outp
 	  if (off >= (bfd_vma) -2)
 	    abort ();
 
-	  relocation = htab->sgot->output_offset + off;
-	  if (r_type == R_X86_64_GOTPCREL)
-	    relocation += htab->sgot->output_section->vma;
+	  relocation = htab->sgot->output_section->vma
+		       + htab->sgot->output_offset + off;
+	  if (r_type != R_X86_64_GOTPCREL)
+	    relocation -= htab->sgotplt->output_section->vma
+			  - htab->sgotplt->output_offset;
 
 	  break;
 
@@ -2667,7 +2669,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-12 12:00:49.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-12 12:00:49.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-12 12:00:49.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-12 12:00:49.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/emulparams/elf_x86_64.sh.jj	2003-05-30 17:19:17.000000000 +0200
+++ ld/emulparams/elf_x86_64.sh	2004-01-12 12:00:49.000000000 +0100
@@ -12,6 +12,7 @@ TEMPLATE_NAME=elf32
 GENERATE_SHLIB_SCRIPT=yes
 GENERATE_PIE_SCRIPT=yes
 NO_SMALL_DATA=yes
+SEPARATE_GOTPLT=24
 
 if [ "x${host}" = "x${target}" ]; then
   case " $EMULATION_LIBPATH " in
--- ld/ldlex.l.jj	2004-01-12 11:53:40.000000000 +0100
+++ ld/ldlex.l	2004-01-12 12:00:49.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-12 11:53:40.000000000 +0100
+++ ld/emultempl/elf32.em	2004-01-12 12:00:49.000000000 +0100
@@ -1646,6 +1646,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
@@ -1693,8 +1697,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\t\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\t\tCreate RELRO program header\n"));
   fprintf (file, _("  -z KEYWORD\t\tIgnored for Solaris compatibility\n"));
 EOF
 fi
--- ld/scripttempl/elf.sc.jj	2004-01-12 11:53:40.000000000 +0100
+++ ld/scripttempl/elf.sc	2004-01-12 12:00:49.000000000 +0100
@@ -75,16 +75,31 @@ 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) }"
+    GOTPLT=".got.plt      ${RELOCATING-0} : { ${RELOCATING+${DATA_SEGMENT_RELRO_GOTPLT_END}} *(.got.plt) }"
+  fi
+fi
 DYNAMIC=".dynamic      ${RELOCATING-0} : { *(.dynamic) }"
 RODATA=".rodata       ${RELOCATING-0} : { *(.rodata${RELOCATING+ .rodata.* .gnu.linkonce.r.*}) }"
+DATARELRO=".data.rel.ro : { *(.data.rel.ro.local) *(.data.rel.ro*) }"
 STACKNOTE="/DISCARD/ : { *(.note.GNU-stack) }"
 if test -z "${NO_SMALL_DATA}"; then
   SBSS=".sbss         ${RELOCATING-0} :
@@ -115,7 +130,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 +229,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.*}) }
@@ -292,6 +312,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
@@ -309,6 +337,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+${DATARELRO}}
+  ${TEXT_DYNAMIC-${DYNAMIC}}
+  ${NO_SMALL_DATA+${SEPARATE_GOTPLT+${GOT}}}
+  ${NO_SMALL_DATA+${SEPARATE_GOTPLT+${GOTPLT}}}
+  ${RELOCATING+${DATA_SEGMENT_RELRO_END}}
+  ${NO_SMALL_DATA+${SEPARATE_GOTPLT-${GOT}}}
+
+  ${DATA_PLT+${PLT}}
+
   .data         ${RELOCATING-0} :
   {
     ${RELOCATING+${DATA_START_SYMBOLS}}
@@ -316,19 +357,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-12 11:56:21.000000000 +0100
+++ ld/ldgram.y	2004-01-12 12:00:49.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-12 12:00:49.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-12 12:00:49.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-12 12:00:49.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-12 11:56:52.000000000 +0100
+++ ld/ldlang.c	2004-01-12 12:00:49.000000000 +0100
@@ -3360,7 +3360,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]