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 2/6] ld: Add TEXT_SEGMENT_ALIGN/TEXT_SEGMENT_{RELRO_}END


Text-only LOAD segment has the same requirement for segment alignment
and page sizes as GNU_RELRO segment.  But for GNU_RELRO segment, the
segment may not end at the same address of the end of data segment.  But
text-only LOAD segment is exactly the same as text LOAD segment.

This patch adds TEXT_SEGMENT_ALIGN, TEXT_SEGMENT_RELRO_END and
TEXT_SEGMENT_END, which mimic DATA_SEGMENT_ALIGN, DATA_SEGMENT_RELRO_END
and DATA_SEGMENT_END.  They work on text segment, instead of data
segment.  TEXT_SEGMENT_ALIGN is placed at the start of text sections.
Both TEXT_SEGMENT_RELRO_END and TEXT_SEGMENT_END are placed at the end
of text sections.  TEXT_SEGMENT_ALIGN is created from DATA_SEGMENT_ALIGN
by replacing DATA_SEGMENT_ALIGN with TEXT_SEGMENT_ALIGN.  It simply sets
text_start and text_end from TEXT_SEGMENT_ALIGN, TEXT_SEGMENT_RELRO_END
and TEXT_SEGMENT_END the same way as relro_start and relro_end are set
from DATA_SEGMENT_ALIGN, DATA_SEGMENT_RELRO_END and DATA_SEGMENT_END.

include/

	PR ld/22393
	* bfdlink.h (bfd_link_info): Add text_start and text_end.

ld/

	PR ld/22393
	* ldexp.c (exp_print_token): Add TEXT_SEGMENT_ALIGN,
	TEXT_SEGMENT_RELRO_END and TEXT_SEGMENT_END.
	(fold_unary): Handle TEXT_SEGMENT_END.
	(fold_binary): Handle TEXT_SEGMENT_RELRO_END and
	TEXT_SEGMENT_END.
	(exp_unop): Also check TEXT_SEGMENT_END.
	* ldexp.h (ldexp_control): Add textseg.
	* ldgram.y: Handle TEXT_SEGMENT_ALIGN, TEXT_SEGMENT_RELRO_END
	and TEXT_SEGMENT_END.
	* ldlang.c (strip_excluded_output_sections): Also set
	expld.textseg.phase to exp_seg_none.
	(lang_size_sections_1): Also call ldlang_check_relro_region with
	&expld.textseg.
	(lang_size_relro_segment): Also handle expld.textseg.
	(lang_size_sections): Also handle expld.textseg.  Set
	link_info.text_start and link_info.text_end for -z textonly.
	(lang_find_relro_sections): Also check expld.textseg.
	* ldlex.l: Add TEXT_SEGMENT_ALIGN, TEXT_SEGMENT_RELRO_END and
	TEXT_SEGMENT_END.
	* scripttempl/elf.sc (TEXT_SEGMENT_ALIGN): New.
	(TEXT_SEGMENT_RELRO_END): Likewise.
	(TEXT_SEGMENT_END): Likewise.
	Add ${TEXT_SEGMENT_ALIGN} before text sections and add
	${TEXT_SEGMENT_RELRO_END}/${TEXT_SEGMENT_END} after text
	sections for non-relocatable link.
---
 include/bfdlink.h     |   3 ++
 ld/ldexp.c            |  18 ++++++++-
 ld/ldexp.h            |   3 ++
 ld/ldgram.y           |   7 ++++
 ld/ldlang.c           | 109 +++++++++++++++++++++++++++++++++++++-------------
 ld/ldlex.l            |   3 ++
 ld/scripttempl/elf.sc |  21 ++++++++++
 7 files changed, 135 insertions(+), 29 deletions(-)

diff --git a/include/bfdlink.h b/include/bfdlink.h
index d283429fdb..2fdfb2ab71 100644
--- a/include/bfdlink.h
+++ b/include/bfdlink.h
@@ -626,6 +626,9 @@ struct bfd_link_info
   /* May be used to set DT_FLAGS_1 for ELF. */
   bfd_vma flags_1;
 
+  /* Start and end of text-only region.  */
+  bfd_vma text_start, text_end;
+
   /* Start and end of RELRO region.  */
   bfd_vma relro_start, relro_end;
 
diff --git a/ld/ldexp.c b/ld/ldexp.c
index 83d9f8f2a7..71051ceb19 100644
--- a/ld/ldexp.c
+++ b/ld/ldexp.c
@@ -134,6 +134,9 @@ exp_print_token (token_code_type code, int infix_p)
     { DATA_SEGMENT_ALIGN, "DATA_SEGMENT_ALIGN" },
     { DATA_SEGMENT_RELRO_END, "DATA_SEGMENT_RELRO_END" },
     { DATA_SEGMENT_END, "DATA_SEGMENT_END" },
+    { TEXT_SEGMENT_ALIGN, "TEXT_SEGMENT_ALIGN" },
+    { TEXT_SEGMENT_RELRO_END, "TEXT_SEGMENT_RELRO_END" },
+    { TEXT_SEGMENT_END, "TEXT_SEGMENT_END" },
     { ORIGIN, "ORIGIN" },
     { LENGTH, "LENGTH" },
     { SEGMENT_START, "SEGMENT_START" }
@@ -416,6 +419,10 @@ fold_unary (etree_type *tree)
 	  fold_segment_end (&expld.dataseg);
 	  break;
 
+	case TEXT_SEGMENT_END:
+	  fold_segment_end (&expld.textseg);
+	  break;
+
 	default:
 	  FAIL ();
 	  break;
@@ -664,6 +671,14 @@ fold_binary (etree_type *tree)
 	  fold_segment_relro_end (&expld.dataseg, &lhs);
 	  break;
 
+	case TEXT_SEGMENT_ALIGN:
+	  fold_segment_align (&expld.textseg, &lhs);
+	  break;
+
+	case TEXT_SEGMENT_RELRO_END:
+	  fold_segment_relro_end (&expld.textseg, &lhs);
+	  break;
+
 	default:
 	  FAIL ();
 	}
@@ -1342,7 +1357,8 @@ exp_unop (int code, etree_type *child)
       && code != ALIGN_K
       && code != ABSOLUTE
       && code != NEXT
-      && code != DATA_SEGMENT_END)
+      && code != DATA_SEGMENT_END
+      && code != TEXT_SEGMENT_END)
     exp_value_fold (new_e);
   return new_e;
 }
diff --git a/ld/ldexp.h b/ld/ldexp.h
index 5ff0fa0a1f..d1429353e1 100644
--- a/ld/ldexp.h
+++ b/ld/ldexp.h
@@ -173,6 +173,9 @@ struct ldexp_control {
 
   /* State machine and results for DATASEG.  */
   seg_align_type dataseg;
+
+  /* State machine and results for TEXTSEG.  */
+  seg_align_type textseg;
 };
 
 extern struct ldexp_control expld;
diff --git a/ld/ldgram.y b/ld/ldgram.y
index d701e076a2..53da2d062a 100644
--- a/ld/ldgram.y
+++ b/ld/ldgram.y
@@ -127,6 +127,7 @@ static int error_index;
 %token <token> ALIGN_K BLOCK BIND QUAD SQUAD LONG SHORT BYTE
 %token SECTIONS PHDRS INSERT_K AFTER BEFORE
 %token DATA_SEGMENT_ALIGN DATA_SEGMENT_RELRO_END DATA_SEGMENT_END
+%token TEXT_SEGMENT_ALIGN TEXT_SEGMENT_RELRO_END TEXT_SEGMENT_END
 %token SORT_BY_NAME SORT_BY_ALIGNMENT SORT_NONE
 %token SORT_BY_INIT_PRIORITY
 %token '{' '}'
@@ -993,6 +994,12 @@ exp	:
 			{ $$ = exp_binop (DATA_SEGMENT_RELRO_END, $5, $3); }
 	|	DATA_SEGMENT_END '(' exp ')'
 			{ $$ = exp_unop (DATA_SEGMENT_END, $3); }
+	|	TEXT_SEGMENT_ALIGN '(' exp ',' exp ')'
+			{ $$ = exp_binop (TEXT_SEGMENT_ALIGN, $3, $5); }
+	|	TEXT_SEGMENT_RELRO_END '(' exp ',' exp ')'
+			{ $$ = exp_binop (TEXT_SEGMENT_RELRO_END, $5, $3); }
+	|	TEXT_SEGMENT_END '(' exp ')'
+			{ $$ = exp_unop (TEXT_SEGMENT_END, $3); }
 	|	SEGMENT_START '(' NAME ',' exp ')'
 			{ /* The operands to the expression node are
 			     placed in the opposite order from the way
diff --git a/ld/ldlang.c b/ld/ldlang.c
index 674004ee38..ea45bc5639 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -3891,6 +3891,7 @@ strip_excluded_output_sections (void)
     {
       expld.phase = lang_mark_phase_enum;
       expld.dataseg.phase = exp_seg_none;
+      expld.textseg.phase = exp_seg_none;
       one_lang_size_sections_pass (NULL, FALSE);
       lang_reset_memory_regions ();
     }
@@ -5450,14 +5451,17 @@ lang_size_sections_1
 	    bfd_vma newdot = dot;
 	    etree_type *tree = s->assignment_statement.exp;
 
+	    expld.textseg.relro = exp_seg_relro_none;
 	    expld.dataseg.relro = exp_seg_relro_none;
 
 	    exp_fold_tree (tree,
 			   output_section_statement->bfd_section,
 			   &newdot);
 
+	    ldlang_check_relro_region (s, &expld.textseg);
 	    ldlang_check_relro_region (s, &expld.dataseg);
 
+	    expld.textseg.relro = exp_seg_relro_none;
 	    expld.dataseg.relro = exp_seg_relro_none;
 
 	    /* This symbol may be relative to this section.  */
@@ -5664,35 +5668,56 @@ static bfd_boolean
 lang_size_relro_segment (bfd_boolean *relax, bfd_boolean check_regions)
 {
   bfd_boolean do_reset = FALSE;
-  bfd_boolean do_data_relro;
-  bfd_vma data_initial_base, data_relro_end;
+  bfd_boolean do_text_relro = FALSE;
+  bfd_boolean do_data_relro = FALSE;
 
-  if (link_info.relro && expld.dataseg.relro_end)
+  if (link_info.relro)
     {
-      do_data_relro = TRUE;
-      data_initial_base = expld.dataseg.base;
-      data_relro_end = lang_size_relro_segment_1 (&expld.dataseg);
-    }
-  else
-    {
-      do_data_relro = FALSE;
-      data_initial_base = data_relro_end = 0;
-    }
+      bfd_vma text_initial_base, text_relro_end;
+      bfd_vma data_initial_base, data_relro_end;
 
-  if (do_data_relro)
-    {
-      lang_reset_memory_regions ();
-      one_lang_size_sections_pass (relax, check_regions);
+      if (link_info.relro > 1 && expld.textseg.relro_end)
+	{
+	  do_text_relro = TRUE;
+	  text_initial_base = expld.textseg.base;
+	  text_relro_end = lang_size_relro_segment_1 (&expld.textseg);
+	}
+      else
+	text_initial_base = text_relro_end = 0;
 
-      /* Assignments to dot, or to output section address in a user
-	 script have increased padding over the original.  Revert.  */
-      if (do_data_relro && expld.dataseg.relro_end > data_relro_end)
+      if (expld.dataseg.relro_end)
 	{
-	  expld.dataseg.base = data_initial_base;;
-	  do_reset = TRUE;
+	  do_data_relro = TRUE;
+	  data_initial_base = expld.dataseg.base;
+	  data_relro_end = lang_size_relro_segment_1 (&expld.dataseg);
+	}
+      else
+	data_initial_base = data_relro_end = 0;
+
+      if (do_text_relro || do_data_relro)
+	{
+	  lang_reset_memory_regions ();
+	  one_lang_size_sections_pass (relax, check_regions);
+
+	  /* Assignments to dot, or to output section address in a user
+	     script have increased padding over the original.  Revert.  */
+	  if (do_text_relro && expld.textseg.relro_end > text_relro_end)
+	    {
+	      expld.textseg.base = text_initial_base;
+	      do_reset = TRUE;
+	    }
+
+	  if (do_data_relro && expld.dataseg.relro_end > data_relro_end)
+	    {
+	      expld.dataseg.base = data_initial_base;;
+	      do_reset = TRUE;
+	    }
 	}
     }
 
+  if (!do_text_relro && lang_size_segment (&expld.textseg))
+    do_reset = TRUE;
+
   if (!do_data_relro && lang_size_segment (&expld.dataseg))
     do_reset = TRUE;
 
@@ -5704,13 +5729,17 @@ lang_size_sections (bfd_boolean *relax, bfd_boolean check_regions)
 {
   expld.phase = lang_allocating_phase_enum;
   expld.dataseg.phase = exp_seg_none;
+  expld.textseg.phase = exp_seg_none;
 
   one_lang_size_sections_pass (relax, check_regions);
 
+  if (expld.textseg.phase != exp_seg_end_seen)
+    expld.textseg.phase = exp_seg_done;
   if (expld.dataseg.phase != exp_seg_end_seen)
     expld.dataseg.phase = exp_seg_done;
 
-  if (expld.dataseg.phase == exp_seg_end_seen)
+  if (expld.textseg.phase == exp_seg_end_seen
+      || expld.dataseg.phase == exp_seg_end_seen)
     {
       bfd_boolean do_reset
 	= lang_size_relro_segment (relax, check_regions);
@@ -5721,6 +5750,12 @@ lang_size_sections (bfd_boolean *relax, bfd_boolean check_regions)
 	  one_lang_size_sections_pass (relax, check_regions);
 	}
 
+      if (link_info.relro > 1 && expld.textseg.relro_end)
+	{
+	  link_info.text_start = expld.textseg.base;
+	  link_info.text_end = expld.textseg.relro_end;
+	}
+
       if (link_info.relro && expld.dataseg.relro_end)
 	{
 	  link_info.relro_start = expld.dataseg.base;
@@ -6906,15 +6941,33 @@ lang_find_relro_sections_1 (lang_statement_union_type *s,
 static void
 lang_find_relro_sections (void)
 {
-  bfd_boolean has_relro_section = FALSE;
-
   /* Check all sections in the link script.  */
+  if (link_info.relro)
+    {
+      bfd_boolean has_relro_section;
 
-  lang_find_relro_sections_1 (expld.dataseg.relro_start_stat,
-			      &expld.dataseg, &has_relro_section);
+      if (link_info.relro > 1)
+	{
+	  has_relro_section = FALSE;
+	  lang_find_relro_sections_1 (expld.textseg.relro_start_stat,
+				      &expld.textseg,
+				      &has_relro_section);
+	  if (!has_relro_section)
+	    link_info.relro = 1;
+	}
 
-  if (!has_relro_section)
-    link_info.relro = FALSE;
+      /* We can't turn off RELRO if we need to generate read-only
+	 PT_LOAD segment.  */
+      if (link_info.relro == 1)
+	{
+	  has_relro_section = FALSE;
+	  lang_find_relro_sections_1 (expld.dataseg.relro_start_stat,
+				      &expld.dataseg,
+				      &has_relro_section);
+	  if (!has_relro_section)
+	    link_info.relro = 0;
+	}
+    }
 }
 
 /* Relax all sections until bfd_relax_section gives up.  */
diff --git a/ld/ldlex.l b/ld/ldlex.l
index 207c97f323..538c372a0f 100644
--- a/ld/ldlex.l
+++ b/ld/ldlex.l
@@ -250,6 +250,9 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)*
 <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>"TEXT_SEGMENT_ALIGN"	{ RTOKEN(TEXT_SEGMENT_ALIGN);}
+<EXPRESSION,BOTH,SCRIPT>"TEXT_SEGMENT_RELRO_END"	{ RTOKEN(TEXT_SEGMENT_RELRO_END);}
+<EXPRESSION,BOTH,SCRIPT>"TEXT_SEGMENT_END"	{ RTOKEN(TEXT_SEGMENT_END);}
 <EXPRESSION,BOTH,SCRIPT>"ADDR"		{ RTOKEN(ADDR);}
 <EXPRESSION,BOTH,SCRIPT>"LOADADDR"	{ RTOKEN(LOADADDR);}
 <EXPRESSION,BOTH,SCRIPT>"ALIGNOF"	{ RTOKEN(ALIGNOF); }
diff --git a/ld/scripttempl/elf.sc b/ld/scripttempl/elf.sc
index 9f291b359f..9eb024e809 100644
--- a/ld/scripttempl/elf.sc
+++ b/ld/scripttempl/elf.sc
@@ -139,6 +139,23 @@ if test -z "$DATA_SEGMENT_ALIGN"; then
     DATA_SEGMENT_RELRO_END=". = DATA_SEGMENT_RELRO_END (${SEPARATE_GOTPLT-0}, .);"
   fi
 fi
+# Don't bother with text-only segment when there are data sections between
+# .plt and .text.
+if test -n "$TINY_READONLY_SECTION"; then
+  TEXT_SEGMENT_ALIGN=" "
+  TEXT_SEGMENT_RELRO_END=" "
+  TEXT_SEGMENT_END=" "
+fi
+if test -z "$TEXT_SEGMENT_ALIGN" && test -n "$DATA_SEGMENT_ALIGN"; then
+  case "$LD_FLAG" in
+    *textonly*)
+      TEXT_SEGMENT_ALIGN=`echo $DATA_SEGMENT_ALIGN | sed -e "s/DATA/TEXT/g"`
+      TEXT_SEGMENT_ALIGN=". = $TEXT_SEGMENT_ALIGN;"
+      TEXT_SEGMENT_RELRO_END=". = TEXT_SEGMENT_RELRO_END (0, .);"
+      TEXT_SEGMENT_END=". = TEXT_SEGMENT_END (.);"
+      ;;
+  esac
+fi
 if test -z "${INITIAL_READONLY_SECTIONS}${CREATE_SHLIB}"; then
   INITIAL_READONLY_SECTIONS=".interp       ${RELOCATING-0} : { *(.interp) }"
 fi
@@ -478,6 +495,8 @@ emit_dyn()
 test -n "${NON_ALLOC_DYN}${SEPARATE_CODE}" || emit_dyn
 
 cat <<EOF
+  ${RELOCATING+${TEXT_SEGMENT_ALIGN}}
+
   .init         ${RELOCATING-0}${RELOCATING+${INIT_ADDR}} :
   {
     ${RELOCATING+${INIT_START}}
@@ -508,6 +527,8 @@ cat <<EOF
   ${RELOCATING+PROVIDE (__${ETEXT_NAME} = .);}
   ${RELOCATING+PROVIDE (_${ETEXT_NAME} = .);}
   ${RELOCATING+PROVIDE (${ETEXT_NAME} = .);}
+  ${RELOCATING+${TEXT_SEGMENT_RELRO_END}}
+  ${RELOCATING+${TEXT_SEGMENT_END}}
 EOF
 
 if test -n "${SEPARATE_CODE}"; then
-- 
2.14.3


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