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]

[PATCH] PT_GNU_STACK


Hi!

This patch introduces PT_GNU_STACK segment header, which tells the kernel or
dynamic linker whether the binary or library needs executable stack or not.
GCC would need to create
.section .note.GNU-stack, ""
in each object which does not require executable stack and
.section .note.GNU-stack, "x"
in each object which requires executable stack.
For backwards compatibility, objects without this section are considered
as needing executable stack, unless all input objects don't have this
section, in which case no PT_GNU_STACK segment header is created.
During linking, this can be overridden with -z execstack or -z noexecstack.

2003-05-23  Jakub Jelinek  <jakub@redhat.com>

binutils/
	* readelf.c (get_segment_type): Handle PT_GNU_STACK.
bfd/
	* elf.c (_bfd_elf_print_private_bfd_data): Handle PT_GNU_STACK.
	(bfd_section_from_phdr): Likewise.
	(map_sections_to_segments): Create PT_GNU_STACK segment header.
	(get_program_header_size): Count with PT_GNU_STACK.
	* elf-bfd.h (struct elf_obj_tdata): Add stack_flags.
	* elflink.h (bfd_elfNN_size_dynamic_sections): Set stack_flags.
include/
	* bfdlink.h (struct bfd_link_info): Add execstack and noexecstack.
	* elf/common.h (PT_GNU_STACK): Define.
ld/
	* ldgram.y (phdr_type): Grok PT_GNU_STACK.
	* emultempl/elf32.em (gld${EMULATION_NAME}_handle_option): Add
	-z execstack and -z noexecstack.
	(gld${EMULATION_NAME}_list_options): Likewise.
	* scripttempl/elf.sc: If not -r, discard .note.GNU-stack section.

--- binutils/readelf.c.jj	2003-05-23 09:24:40.000000000 -0400
+++ binutils/readelf.c	2003-05-23 10:50:05.000000000 -0400
@@ -2307,6 +2307,7 @@ get_segment_type (p_type)
 
     case PT_GNU_EH_FRAME:
 			return "GNU_EH_FRAME";
+    case PT_GNU_STACK:	return "STACK";
 
     default:
       if ((p_type >= PT_LOPROC) && (p_type <= PT_HIPROC))
--- bfd/elf.c.jj	2003-05-23 09:24:39.000000000 -0400
+++ bfd/elf.c	2003-05-23 16:15:02.000000000 -0400
@@ -1070,6 +1070,7 @@ _bfd_elf_print_private_bfd_data (abfd, f
 	    case PT_PHDR: pt = "PHDR"; break;
 	    case PT_TLS: pt = "TLS"; break;
 	    case PT_GNU_EH_FRAME: pt = "EH_FRAME"; break;
+	    case PT_GNU_STACK: pt = "STACK"; break;
 	    default: sprintf (buf, "0x%lx", p->p_type); pt = buf; break;
 	    }
 	  fprintf (f, "%8s off    0x", pt);
@@ -2296,6 +2297,9 @@ bfd_section_from_phdr (abfd, hdr, index)
       return _bfd_elf_make_section_from_phdr (abfd, hdr, index,
 					      "eh_frame_hdr");
 
+    case PT_GNU_STACK:
+      return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "stack");
+
     default:
       /* Check for any processor-specific program segment types.
          If no handler for them, default to making "segment" sections.  */
@@ -3513,6 +3517,21 @@ map_sections_to_segments (abfd)
       pm = &m->next;
     }
 
+  if (elf_tdata (abfd)->stack_flags)
+    {
+      amt = sizeof (struct elf_segment_map);
+      m = (struct elf_segment_map *) bfd_zalloc (abfd, amt);
+      if (m == NULL)
+	goto error_return;
+      m->next = NULL;
+      m->p_type = PT_GNU_STACK;
+      m->p_flags = elf_tdata (abfd)->stack_flags;
+      m->p_flags_valid = 1;
+
+      *pm = m;
+      pm = &m->next;
+    }
+
   free (sections);
   sections = NULL;
 
@@ -4099,6 +4118,12 @@ get_program_header_size (abfd)
       ++segs;
     }
 
+  if (elf_tdata (abfd)->stack_flags)
+    {
+      /* We need a PT_GNU_STACK segment.  */
+      ++segs;
+    }
+
   for (s = abfd->sections; s != NULL; s = s->next)
     {
       if ((s->flags & SEC_LOAD) != 0
--- bfd/elf-bfd.h.jj	2003-05-23 09:24:39.000000000 -0400
+++ bfd/elf-bfd.h	2003-05-23 10:30:28.000000000 -0400
@@ -1254,6 +1254,9 @@ struct elf_obj_tdata
   /* Number of symbol version references we are about to emit.  */
   unsigned int cverrefs;
 
+  /* Segment flags for the PT_GNU_STACK segment.  */
+  unsigned int stack_flags;  
+
   /* Symbol version definitions in external objects.  */
   Elf_Internal_Verdef *verdef;
 
--- bfd/elflink.h.jj	2003-05-23 09:24:40.000000000 -0400
+++ bfd/elflink.h	2003-05-23 16:35:55.000000000 -0400
@@ -1937,6 +1937,43 @@ NAME(bfd_elf,size_dynamic_sections) (out
   if (! is_elf_hash_table (info))
     return TRUE;
 
+  if (info->execstack)
+    elf_tdata (output_bfd)->stack_flags = PF_R | PF_W | PF_X;
+  else if (info->noexecstack)
+    elf_tdata (output_bfd)->stack_flags = PF_R | PF_W;
+  else
+    {
+      bfd *inputobj;
+      asection *notesec = NULL;
+      int exec = 0;
+
+      for (inputobj = info->input_bfds;
+	   inputobj;
+	   inputobj = inputobj->link_next)
+	{
+	  asection *s;
+
+	  if (inputobj->flags & DYNAMIC)
+	    continue;
+	  s = bfd_get_section_by_name (inputobj, ".note.GNU-stack");
+	  if (s)
+	    {
+	      if (s->flags & SEC_CODE)
+		exec = PF_X;
+	      notesec = s;
+	    }
+	  else
+	    exec = PF_X;
+	}
+      if (notesec)
+	{
+	  elf_tdata (output_bfd)->stack_flags = PF_R | PF_W | exec;
+	  if (exec && info->relocateable
+	      && notesec->output_section != bfd_abs_section_ptr)
+	    notesec->output_section->flags |= SEC_CODE;
+	}
+    }
+
   /* Any syms created from now on start with -1 in
      got.refcount/offset and plt.refcount/offset.  */
   elf_hash_table (info)->init_refcount = elf_hash_table (info)->init_offset;
--- include/bfdlink.h.jj	2003-05-23 09:24:43.000000000 -0400
+++ include/bfdlink.h	2003-05-23 10:07:06.000000000 -0400
@@ -291,6 +291,14 @@ struct bfd_link_info
   /* TRUE if relaxation is being finalized.  */
   unsigned int relax_finalizing: 1;
 
+  /* TRUE if PT_GNU_STACK segment should be created with PF_R|PF_W|PF_X
+     flags.  */
+  unsigned int execstack: 1;
+
+  /* TRUE if PT_GNU_STACK segment should be created with PF_R|PF_W
+     flags.  */
+  unsigned int noexecstack: 1;
+
   /* Which symbols to strip.  */
   enum bfd_link_strip strip;
 
--- include/elf/common.h.jj	2003-05-23 09:24:43.000000000 -0400
+++ include/elf/common.h	2003-05-23 09:32:48.000000000 -0400
@@ -288,6 +288,7 @@
 #define PT_HIPROC	0x7FFFFFFF	/* Processor-specific */
 
 #define PT_GNU_EH_FRAME	(PT_LOOS + 0x474e550)
+#define PT_GNU_STACK	(PT_LOOS + 0x474e551)
 
 /* Program segment permissions, in program header p_flags field.  */
 
--- ld/ldgram.y.jj	2003-05-05 18:28:06.000000000 -0400
+++ ld/ldgram.y	2003-05-23 16:52:09.000000000 -0400
@@ -1006,6 +1006,8 @@ phdr_type:
 			{
 			  if (strcmp (s, "PT_GNU_EH_FRAME") == 0)
 			    $$ = exp_intop (0x6474e550);
+			  else if (strcmp (s, "PT_GNU_STACK") == 0)
+			    $$ = exp_intop (0x6474e551);
 			  else
 			    {
 			      einfo (_("\
--- ld/emultempl/elf32.em.jj	2003-05-19 17:12:46.000000000 -0400
+++ ld/emultempl/elf32.em	2003-05-23 10:08:07.000000000 -0400
@@ -1664,6 +1664,16 @@ cat >>e${EMULATION_NAME}.c <<EOF
 	link_info.combreloc = FALSE;
       else if (strcmp (optarg, "nocopyreloc") == 0)
         link_info.nocopyreloc = TRUE;
+      else if (strcmp (optarg, "execstack") == 0)
+	{
+	  link_info.execstack = TRUE;
+	  link_info.noexecstack = FALSE;
+	}
+      else if (strcmp (optarg, "noexecstack") == 0)
+	{
+	  link_info.noexecstack = TRUE;
+	  link_info.execstack = FALSE;
+	}
       /* What about the other Solaris -z options? FIXME.  */
       break;
 EOF
@@ -1702,6 +1712,7 @@ cat >>e${EMULATION_NAME}.c <<EOF
   fprintf (file, _("  --eh-frame-hdr\tCreate .eh_frame_hdr section\n"));
   fprintf (file, _("  -z combreloc\t\tMerge dynamic relocs into one section and sort\n"));
   fprintf (file, _("  -z defs\t\tDisallows undefined symbols\n"));
+  fprintf (file, _("  -z execstack\t\tMark executable as requiring executable stack\n"));
   fprintf (file, _("  -z initfirst\t\tMark DSO to be initialized first at runtime\n"));
   fprintf (file, _("  -z interpose\t\tMark object to interpose all DSOs but executable\n"));
   fprintf (file, _("  -z loadfltr\t\tMark object requiring immediate process\n"));
@@ -1712,6 +1723,7 @@ cat >>e${EMULATION_NAME}.c <<EOF
   fprintf (file, _("  -z nodelete\t\tMark DSO non-deletable at runtime\n"));
   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\t\tMark executable as not requiring executable stack\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 KEYWORD\t\tIgnored for Solaris compatibility\n"));
--- ld/scripttempl/elf.sc.jj	2003-04-14 10:57:55.000000000 -0400
+++ ld/scripttempl/elf.sc	2003-05-23 16:23:06.000000000 -0400
@@ -84,6 +84,7 @@ INTERP=".interp       ${RELOCATING-0} : 
 PLT=".plt          ${RELOCATING-0} : { *(.plt) }"
 DYNAMIC=".dynamic      ${RELOCATING-0} : { *(.dynamic) }"
 RODATA=".rodata       ${RELOCATING-0} : { *(.rodata${RELOCATING+ .rodata.* .gnu.linkonce.r.*}) }"
+STACKNOTE="/DISCARD/ : { *(.note.GNU-stack) }"
 if test -z "${NO_SMALL_DATA}"; then
   SBSS=".sbss         ${RELOCATING-0} :
   {
@@ -395,5 +396,6 @@ cat <<EOF
   ${STACK_ADDR+${STACK}}
   ${OTHER_SECTIONS}
   ${RELOCATING+${OTHER_END_SYMBOLS}}
+  ${RELOCATING+${STACKNOTE}}
 }
 EOF

	Jakub


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