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] Smarter aligning of data segment


On Sat, Feb 09, 2002 at 09:04:14AM +0000, Nick Clifton wrote:
> Approved - please apply.  (Although you may want to consider H-P's
> suggestions too).

Here is what I've commited to mainline:

2002-02-12  Jakub Jelinek  <jakub@redhat.com>

	* ldlex.l (DATA_SEGMENT_ALIGN, DATA_SEGMENT_END): New tokens.
	* ldgram.y (DATA_SEGMENT_ALIGN, DATA_SEGMENT_END): New tokens.
	(exp): Add DATA_SEGMENT_ALIGN (exp, exp) and DATA_SEGMENT_END (exp).
	* ldexp.c (exp_data_seg): New variable.
	(exp_print_token): Handle DATA_SEGMENT_ALIGN and DATA_SEGMENT_END.
	(fold_binary): Handle DATA_SEGMENT_ALIGN.
	(exp_fold_tree): Handle DATA_SEGMENT_END.
	Pass allocation_done when recursing instead of hardcoding
	lang_allocating_phase_enum.
	* ldexp.h (exp_data_seg): New.
	* ldlang.c (lang_size_sections_1): Renamed from lang_size_sections.
	(lang_size_sections): New.
	* ld.texinfo (DATA_SEGMENT_ALIGN, DATA_SEGMENT_END): Document.
	* scripttempl/elf.sc: Use DATA_SEGMENT_ALIGN and DATA_SEGMENT_END
	if COMMONPAGESIZE is defined.
	* emulparams/elf_i386.sh (COMMONPAGESIZE): Set to 4K.
	* emulparams/elf32_sparc.sh (COMMONPAGESIZE): Set to 8K.
	* emulparams/elf64_sparc.sh (COMMONPAGESIZE): Set to 8K.
	* emulparams/elf64alpha.sh (COMMONPAGESIZE): Set to 8K.
	* emulparams/elf64_ia64.sh (COMMONPAGESIZE): Set to 16K for shared
	libraries only.

--- ld/emulparams/elf_i386.sh.jj	Wed Nov 28 21:05:04 2001
+++ ld/emulparams/elf_i386.sh	Tue Feb 12 15:12:29 2002
@@ -2,6 +2,7 @@ SCRIPT_NAME=elf
 OUTPUT_FORMAT="elf32-i386"
 TEXT_START_ADDR=0x08048000
 MAXPAGESIZE=0x1000
+COMMONPAGESIZE=0x1000
 NONPAGED_TEXT_START_ADDR=0x08048000
 ARCH=i386
 MACHINE=
--- ld/emulparams/elf64_ia64.sh.jj	Fri Nov 23 14:22:21 2001
+++ ld/emulparams/elf64_ia64.sh	Tue Feb 12 15:28:00 2002
@@ -7,6 +7,10 @@ OUTPUT_FORMAT="elf64-ia64-little"
 ARCH=ia64
 MACHINE=
 MAXPAGESIZE=0x10000
+if test -n "$CREATE_SHLIB"; then
+  # Optimize shared libraries for 16K page size
+  COMMONPAGESIZE=0x4000
+fi
 TEXT_START_ADDR="0x4000000000000000"
 DATA_ADDR="0x6000000000000000 + (. & (${MAXPAGESIZE} - 1))"
 GENERATE_SHLIB_SCRIPT=yes
--- ld/emulparams/elf32_sparc.sh.jj	Wed Nov 28 21:05:04 2001
+++ ld/emulparams/elf32_sparc.sh	Tue Feb 12 15:28:32 2002
@@ -2,6 +2,7 @@ SCRIPT_NAME=elf
 OUTPUT_FORMAT="elf32-sparc"
 TEXT_START_ADDR=0x10000
 MAXPAGESIZE=0x10000
+COMMONPAGESIZE=0x2000
 NONPAGED_TEXT_START_ADDR=0x10000
 ALIGNMENT=8
 ARCH=sparc
--- ld/emulparams/elf64_sparc.sh.jj	Wed Nov 28 21:05:04 2001
+++ ld/emulparams/elf64_sparc.sh	Tue Feb 12 15:28:49 2002
@@ -3,6 +3,7 @@ ELFSIZE=64
 TEMPLATE_NAME=elf32
 OUTPUT_FORMAT="elf64-sparc"
 MAXPAGESIZE=0x100000
+COMMONPAGESIZE=0x2000
 ARCH="sparc:v9"
 MACHINE=
 DATA_PLT=
--- ld/emulparams/elf64alpha.sh.jj	Mon Jan 28 14:44:40 2002
+++ ld/emulparams/elf64alpha.sh	Tue Feb 12 15:30:05 2002
@@ -5,6 +5,7 @@ TEMPLATE_NAME=elf32
 OUTPUT_FORMAT="elf64-alpha"
 TEXT_START_ADDR="0x120000000"
 MAXPAGESIZE=0x10000
+COMMONPAGESIZE=0x2000
 NONPAGED_TEXT_START_ADDR="0x120000000"
 ARCH=alpha
 MACHINE=
--- ld/scripttempl/elf.sc.jj	Thu Dec 13 13:22:35 2001
+++ ld/scripttempl/elf.sc	Tue Feb 12 15:10:29 2002
@@ -70,6 +70,10 @@ if [ -z "$MACHINE" ]; then OUTPUT_ARCH=$
 test -z "${ELFSIZE}" && ELFSIZE=32
 test -z "${ALIGNMENT}" && ALIGNMENT="${ELFSIZE} / 8"
 test "$LD_FLAG" = "N" && DATA_ADDR=.
+DATA_SEGMENT_ALIGN="ALIGN(${MAXPAGESIZE}) + (. & (${MAXPAGESIZE} - 1))"
+if [ -n "${COMMONPAGESIZE}" ]; then
+  DATA_SEGMENT_ALIGN="DATA_SEGMENT_ALIGN(${MAXPAGESIZE}, ${COMMONPAGESIZE})"
+fi
 INTERP=".interp       ${RELOCATING-0} : { *(.interp) }"
 PLT=".plt          ${RELOCATING-0} : { *(.plt) }"
 DYNAMIC=".dynamic      ${RELOCATING-0} : { *(.dynamic) }"
@@ -269,8 +273,8 @@ cat <<EOF
 
   /* Adjust the address for the data segment.  We want to adjust up to
      the same address within the page on the next page up.  */
-  ${CREATE_SHLIB-${RELOCATING+. = ${DATA_ADDR-ALIGN(${MAXPAGESIZE}) + (. & (${MAXPAGESIZE} - 1))};}}
-  ${CREATE_SHLIB+${RELOCATING+. = ${SHLIB_DATA_ADDR-ALIGN(${MAXPAGESIZE}) + (. & (${MAXPAGESIZE} - 1))};}}
+  ${CREATE_SHLIB-${RELOCATING+. = ${DATA_ADDR-${DATA_SEGMENT_ALIGN}};}}
+  ${CREATE_SHLIB+${RELOCATING+. = ${SHLIB_DATA_ADDR-${DATA_SEGMENT_ALIGN}};}}
 
   .data         ${RELOCATING-0} :
   {
@@ -316,6 +320,7 @@ cat <<EOF
   ${RELOCATING+_end = .;}
   ${RELOCATING+${OTHER_BSS_END_SYMBOLS}}
   ${RELOCATING+PROVIDE (end = .);}
+  ${COMMONPAGESIZE+${RELOCATING+. = DATA_SEGMENT_END (.);}}
 
   /* Stabs debugging sections.  */
   .stab          0 : { *(.stab) }
--- ld/ldlex.l.jj	Mon Jan 28 14:46:22 2002
+++ ld/ldlex.l	Tue Feb 12 15:10:06 2002
@@ -239,6 +239,8 @@ V_IDENTIFIER [*?.$_a-zA-Z]([*?.$_a-zA-Z0
 <EXPRESSION,BOTH,SCRIPT>"BIND"		{ RTOKEN(BIND);}
 <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_END"	{ RTOKEN(DATA_SEGMENT_END);}
 <EXPRESSION,BOTH,SCRIPT>"ADDR"			{ RTOKEN(ADDR);}
 <EXPRESSION,BOTH,SCRIPT>"LOADADDR"		{ RTOKEN(LOADADDR);}
 <EXPRESSION,BOTH>"MAX"			{ RTOKEN(MAX_K); }
--- ld/ldgram.y.jj	Tue Dec 18 14:30:32 2001
+++ ld/ldgram.y	Tue Feb 12 15:10:07 2002
@@ -122,7 +122,7 @@ static int error_index;
 %token END 
 %left <token> '('
 %token <token> ALIGN_K BLOCK BIND QUAD SQUAD LONG SHORT BYTE
-%token SECTIONS PHDRS SORT
+%token SECTIONS PHDRS SORT DATA_SEGMENT_ALIGN DATA_SEGMENT_END
 %token '{' '}'
 %token SIZEOF_HEADERS OUTPUT_FORMAT FORCE_COMMON_ALLOCATION OUTPUT_ARCH
 %token INHIBIT_COMMON_ALLOCATION
@@ -795,6 +795,10 @@ exp	:
 			{ $$ = exp_unop(ABSOLUTE, $3); }
 	|	ALIGN_K '(' exp ')'
 			{ $$ = exp_unop(ALIGN_K,$3); }
+	|	DATA_SEGMENT_ALIGN '(' exp ',' exp ')'
+			{ $$ = exp_binop (DATA_SEGMENT_ALIGN, $3, $5); }
+	|	DATA_SEGMENT_END '(' exp ')'
+			{ $$ = exp_unop(DATA_SEGMENT_END, $3); }
 	|	BLOCK '(' exp ')'
 			{ $$ = exp_unop(ALIGN_K,$3); }
 	|	NAME
--- ld/ldexp.c.jj	Wed Dec  5 14:45:44 2001
+++ ld/ldexp.c	Tue Feb 12 15:10:07 2002
@@ -64,6 +64,8 @@ static etree_value_type exp_fold_tree_no
 	   lang_output_section_statement_type *current_section,
 	   lang_phase_type allocation_done));
 
+struct exp_data_seg exp_data_seg;
+
 static void
 exp_print_token (code)
      token_code_type code;
@@ -114,6 +116,8 @@ exp_print_token (code)
     { LOADADDR, "LOADADDR" },
     { MAX_K, "MAX_K" },
     { REL, "relocateable" },
+    { DATA_SEGMENT_ALIGN, "DATA_SEGMENT_ALIGN" },
+    { DATA_SEGMENT_END, "DATA_SEGMENT_END" }
   };
   unsigned int idx;
 
@@ -314,6 +318,33 @@ fold_binary (tree, current_section, allo
 		result = other;
 	      break;
 
+	    case DATA_SEGMENT_ALIGN:
+	      if (allocation_done != lang_first_phase_enum
+		  && current_section == abs_output_section
+		  && (exp_data_seg.phase == exp_dataseg_none
+		      || exp_data_seg.phase == exp_dataseg_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)
+		    {
+		      result.value += dot & (maxpage - 1);
+		      if (allocation_done == lang_allocating_phase_enum)
+			{
+			  exp_data_seg.phase = exp_dataseg_align_seen;
+			  exp_data_seg.base = result.value;
+			  exp_data_seg.pagesize = other.value;
+			}
+		    }
+		  else if (other.value < maxpage)
+		    result.value += dot & (maxpage - other.value);
+		}
+	      else
+		result.valid_p = false;
+	      break;
+
 	    default:
 	      FAIL ();
 	    }
@@ -578,6 +609,23 @@ exp_fold_tree (tree, current_section, al
 		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_adjust
+		      || allocation_done != lang_allocating_phase_enum))
+		{
+		  if (exp_data_seg.phase == exp_dataseg_align_seen)
+		    {
+		      exp_data_seg.phase = exp_dataseg_end_seen;
+		      exp_data_seg.end = result.value;
+		    }
+		}
+	      else
+		result.valid_p = false;
+	      break;
+
 	    default:
 	      FAIL ();
 	      break;
@@ -615,7 +663,7 @@ exp_fold_tree (tree, current_section, al
 	    {
 	      result = exp_fold_tree (tree->assign.src,
 				      current_section,
-				      lang_allocating_phase_enum, dot,
+				      allocation_done, dot,
 				      dotp);
 	      if (! result.valid_p)
 		einfo (_("%F%S invalid assignment to location counter\n"));
--- ld/ldexp.h.jj	Tue Mar 13 07:14:27 2001
+++ ld/ldexp.h	Tue Feb 12 15:10:07 2002
@@ -88,6 +88,16 @@ typedef union etree_union {
   } assert_s;
 } etree_type;
 
+extern struct exp_data_seg {
+  enum {
+    exp_dataseg_none,
+    exp_dataseg_align_seen,
+    exp_dataseg_end_seen,
+    exp_dataseg_adjust
+  } phase;
+  bfd_vma base, end, pagesize;
+} exp_data_seg;
+
 etree_type *exp_intop PARAMS ((bfd_vma));
 etree_type *exp_relop PARAMS ((asection *, bfd_vma));
 etree_value_type invalid PARAMS ((void));
--- ld/ldlang.c.jj	Tue Feb 12 15:04:05 2002
+++ ld/ldlang.c	Tue Feb 12 15:10:07 2002
@@ -150,6 +150,9 @@ static void lang_check_section_addresses
 static void os_region_check
   PARAMS ((lang_output_section_statement_type *,
 	   struct memory_region_struct *, etree_type *, bfd_vma));
+static bfd_vma lang_size_sections_1
+  PARAMS ((lang_statement_union_type *, lang_output_section_statement_type *,
+	   lang_statement_union_type **, fill_type, bfd_vma, boolean *));
 
 typedef void (*callback_t) PARAMS ((lang_wild_statement_type *,
 				    struct wildcard_list *,
@@ -2823,8 +2826,8 @@ os_region_check (os, region, tree, base)
 
 /* Set the sizes for all the output sections.  */
 
-bfd_vma
-lang_size_sections (s, output_section_statement, prev, fill, dot, relax)
+static bfd_vma
+lang_size_sections_1 (s, output_section_statement, prev, fill, dot, relax)
      lang_statement_union_type *s;
      lang_output_section_statement_type *output_section_statement;
      lang_statement_union_type **prev;
@@ -2949,8 +2952,8 @@ lang_size_sections (s, output_section_st
 		os->bfd_section->output_offset = 0;
 	      }
 
-	    lang_size_sections (os->children.head, os, &os->children.head,
-				os->fill, dot, relax);
+	    lang_size_sections_1 (os->children.head, os, &os->children.head,
+				  os->fill, dot, relax);
 
 	    /* Put the section within the requested block size, or
 	       align at the block boundary.  */
@@ -3018,10 +3021,10 @@ lang_size_sections (s, output_section_st
 	  break;
 
 	case lang_constructors_statement_enum:
-	  dot = lang_size_sections (constructor_list.head,
-				    output_section_statement,
-				    &s->wild_statement.children.head,
-				    fill, dot, relax);
+	  dot = lang_size_sections_1 (constructor_list.head,
+				      output_section_statement,
+				      &s->wild_statement.children.head,
+				      fill, dot, relax);
 	  break;
 
 	case lang_data_statement_enum:
@@ -3082,10 +3085,10 @@ lang_size_sections (s, output_section_st
 
 	case lang_wild_statement_enum:
 
-	  dot = lang_size_sections (s->wild_statement.children.head,
-				    output_section_statement,
-				    &s->wild_statement.children.head,
-				    fill, dot, relax);
+	  dot = lang_size_sections_1 (s->wild_statement.children.head,
+				      output_section_statement,
+				      &s->wild_statement.children.head,
+				      fill, dot, relax);
 
 	  break;
 
@@ -3180,10 +3183,10 @@ lang_size_sections (s, output_section_st
 	  break;
 
 	case lang_group_statement_enum:
-	  dot = lang_size_sections (s->group_statement.children.head,
-				    output_section_statement,
-				    &s->group_statement.children.head,
-				    fill, dot, relax);
+	  dot = lang_size_sections_1 (s->group_statement.children.head,
+				      output_section_statement,
+				      &s->group_statement.children.head,
+				      fill, dot, relax);
 	  break;
 
 	default:
@@ -3200,6 +3203,42 @@ lang_size_sections (s, output_section_st
 }
 
 bfd_vma
+lang_size_sections (s, output_section_statement, prev, fill, dot, relax)
+     lang_statement_union_type *s;
+     lang_output_section_statement_type *output_section_statement;
+     lang_statement_union_type **prev;
+     fill_type fill;
+     bfd_vma dot;
+     boolean *relax;
+{
+  bfd_vma result;
+
+  exp_data_seg.phase = exp_dataseg_none;
+  result = lang_size_sections_1 (s, output_section_statement, prev, fill,
+				 dot, relax);
+  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.  */
+      bfd_vma first, last;
+
+      first = -exp_data_seg.base & (exp_data_seg.pagesize - 1);
+      last = exp_data_seg.end & (exp_data_seg.pagesize - 1);
+      if (first && last
+	  && ((exp_data_seg.base & ~(exp_data_seg.pagesize - 1))
+	      != (exp_data_seg.end & ~(exp_data_seg.pagesize - 1)))
+	  && first + last <= exp_data_seg.pagesize)
+	{
+	  exp_data_seg.phase = exp_dataseg_adjust;
+	  result = lang_size_sections_1 (s, output_section_statement, prev,
+					 fill, dot, relax);
+	}
+    }
+
+  return result;
+}
+
+bfd_vma
 lang_do_assignments (s, output_section_statement, fill, dot)
      lang_statement_union_type *s;
      lang_output_section_statement_type *output_section_statement;
--- ld/ld.texinfo.jj	Tue Feb 12 15:04:05 2002
+++ ld/ld.texinfo	Tue Feb 12 15:10:07 2002
@@ -4159,6 +4159,45 @@ This is a synonym for @code{ALIGN}, for 
 scripts.  It is most often seen when setting the address of an output
 section.
 
+@item DATA_SEGMENT_ALIGN(@var{maxpagesize}, @var{commonpagesize})
+@kindex DATA_SEGMENT_ALIGN(@var{maxpagesize}, @var{commonpagesize})
+This is equivalent to either
+@smallexample
+(ALIGN(@var{maxpagesize}) + (. & (@var{maxpagesize} - 1)))
+@end smallexample
+or
+@smallexample
+(ALIGN(@var{maxpagesize}) + (. & (@var{maxpagesize} - @var{commonpagesize})))
+@end smallexample
+@noindent
+depending on whether the latter uses fewer @var{commonpagesize} sized pages
+for the data segment (area between the result of this expression and
+@code{DATA_SEGMENT_END}) than the former or not.
+If the latter form is used, it means @var{commonpagesize} bytes of runtime
+memory will be saved at the expense of up to @var{commonpagesize} wasted
+bytes in the on-disk file.
+
+This expression can only be used directly in @code{SECTIONS} commands, not in
+any output section descriptions and only once in the linker script.
+@var{commonpagesize} should be less or equal to @var{maxpagesize} and should
+be the system page size the object wants to be optimized for (while still
+working on system page sizes up to @var{maxpagesize}).
+
+@noindent
+Example:
+@smallexample
+  . = DATA_SEGMENT_ALIGN(0x10000, 0x2000);
+@end smallexample
+
+@item DATA_SEGMENT_END(@var{exp})
+@kindex DATA_SEGMENT_END(@var{exp})
+This defines the end of data segment for @code{DATA_SEGMENT_ALIGN}
+evaluation purposes.
+
+@smallexample
+  . = DATA_SEGMENT_END(.);
+@end smallexample
+
 @item DEFINED(@var{symbol})
 @kindex DEFINED(@var{symbol})
 @cindex symbol defaults


	Jakub


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