aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ld/ChangeLog24
-rw-r--r--ld/emulparams/elf32_sparc.sh1
-rw-r--r--ld/emulparams/elf64_ia64.sh4
-rw-r--r--ld/emulparams/elf64_sparc.sh1
-rw-r--r--ld/emulparams/elf64alpha.sh1
-rw-r--r--ld/emulparams/elf_i386.sh1
-rw-r--r--ld/ld.texinfo39
-rw-r--r--ld/ldexp.c50
-rw-r--r--ld/ldexp.h10
-rw-r--r--ld/ldgram.y6
-rw-r--r--ld/ldlang.c71
-rw-r--r--ld/ldlex.l2
-rw-r--r--ld/scripttempl/elf.sc9
13 files changed, 199 insertions, 20 deletions
diff --git a/ld/ChangeLog b/ld/ChangeLog
index b4dfe65..261618c 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,3 +1,27 @@
+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.
+
2002-02-11 Alan Modra <amodra@bigpond.net.au>
* Makefile.in: Regenerate.
diff --git a/ld/emulparams/elf32_sparc.sh b/ld/emulparams/elf32_sparc.sh
index d8b81e7..15a837d 100644
--- a/ld/emulparams/elf32_sparc.sh
+++ b/ld/emulparams/elf32_sparc.sh
@@ -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
diff --git a/ld/emulparams/elf64_ia64.sh b/ld/emulparams/elf64_ia64.sh
index 0699d3d..4ff0ca9 100644
--- a/ld/emulparams/elf64_ia64.sh
+++ b/ld/emulparams/elf64_ia64.sh
@@ -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
diff --git a/ld/emulparams/elf64_sparc.sh b/ld/emulparams/elf64_sparc.sh
index dae3f21..a4706b5 100644
--- a/ld/emulparams/elf64_sparc.sh
+++ b/ld/emulparams/elf64_sparc.sh
@@ -3,6 +3,7 @@ ELFSIZE=64
TEMPLATE_NAME=elf32
OUTPUT_FORMAT="elf64-sparc"
MAXPAGESIZE=0x100000
+COMMONPAGESIZE=0x2000
ARCH="sparc:v9"
MACHINE=
DATA_PLT=
diff --git a/ld/emulparams/elf64alpha.sh b/ld/emulparams/elf64alpha.sh
index 39247ea..d0ca139 100644
--- a/ld/emulparams/elf64alpha.sh
+++ b/ld/emulparams/elf64alpha.sh
@@ -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=
diff --git a/ld/emulparams/elf_i386.sh b/ld/emulparams/elf_i386.sh
index 53dd54b..f1b8522 100644
--- a/ld/emulparams/elf_i386.sh
+++ b/ld/emulparams/elf_i386.sh
@@ -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=
diff --git a/ld/ld.texinfo b/ld/ld.texinfo
index 78afbbe..b7c289a 100644
--- a/ld/ld.texinfo
+++ b/ld/ld.texinfo
@@ -4159,6 +4159,45 @@ This is a synonym for @code{ALIGN}, for compatibility with older linker
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
diff --git a/ld/ldexp.c b/ld/ldexp.c
index ec449fd..4023639 100644
--- a/ld/ldexp.c
+++ b/ld/ldexp.c
@@ -64,6 +64,8 @@ static etree_value_type exp_fold_tree_no_dot
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, allocation_done, dot, dotp)
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, allocation_done, dot, dotp)
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, allocation_done, dot, dotp)
{
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"));
diff --git a/ld/ldexp.h b/ld/ldexp.h
index 36f88f8..fe152d8 100644
--- a/ld/ldexp.h
+++ b/ld/ldexp.h
@@ -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));
diff --git a/ld/ldgram.y b/ld/ldgram.y
index f1924a0..ad26902 100644
--- a/ld/ldgram.y
+++ b/ld/ldgram.y
@@ -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
diff --git a/ld/ldlang.c b/ld/ldlang.c
index bc705ad..eab970d 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -150,6 +150,9 @@ static void lang_check_section_addresses PARAMS ((void));
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_statement, prev, fill, dot, relax)
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_statement, prev, fill, dot, relax)
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_statement, prev, fill, dot, relax)
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_statement, prev, fill, dot, relax)
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_statement, prev, fill, dot, relax)
}
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;
diff --git a/ld/ldlex.l b/ld/ldlex.l
index 0b15ca2..1220852 100644
--- a/ld/ldlex.l
+++ b/ld/ldlex.l
@@ -239,6 +239,8 @@ V_IDENTIFIER [*?.$_a-zA-Z]([*?.$_a-zA-Z0-9]|::)*
<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); }
diff --git a/ld/scripttempl/elf.sc b/ld/scripttempl/elf.sc
index fe8e242..be6fc09 100644
--- a/ld/scripttempl/elf.sc
+++ b/ld/scripttempl/elf.sc
@@ -70,6 +70,10 @@ if [ -z "$MACHINE" ]; then OUTPUT_ARCH=${ARCH}; else OUTPUT_ARCH=${ARCH}:${MACHI
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) }