summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2017-11-10 13:53:20 -0800
committerH.J. Lu <hjl.tools@gmail.com>2018-01-09 09:14:32 -0800
commitc91ad020c2d0c10cb41ecd1516baa0321ce0c895 (patch)
treeabd733e940018b0d1456f8224fbcdb4a61fe62cf
parent972d6cb518582722cb6162dd76b0486673dcdd55 (diff)
downloadbinutils-gdb-c91ad020c2d0c10cb41ecd1516baa0321ce0c895.tar.gz
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.
-rw-r--r--include/bfdlink.h3
-rw-r--r--ld/ldexp.c18
-rw-r--r--ld/ldexp.h3
-rw-r--r--ld/ldgram.y7
-rw-r--r--ld/ldlang.c109
-rw-r--r--ld/ldlex.l3
-rw-r--r--ld/scripttempl/elf.sc21
7 files changed, 135 insertions, 29 deletions
diff --git a/include/bfdlink.h b/include/bfdlink.h
index 0fa74a71bdd..a04e7886ae5 100644
--- a/include/bfdlink.h
+++ b/include/bfdlink.h
@@ -627,6 +627,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 9fbc892e4b5..86ae7110bfb 100644
--- a/ld/ldexp.c
+++ b/ld/ldexp.c
@@ -131,6 +131,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" }
@@ -411,6 +414,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;
@@ -659,6 +666,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 ();
}
@@ -1311,7 +1326,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 572b703c203..d7b6981418b 100644
--- a/ld/ldexp.h
+++ b/ld/ldexp.h
@@ -178,6 +178,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 ba89a4fe3a7..0c0bcb4155c 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 294e6323012..eee8b875ce4 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -3889,6 +3889,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 ();
}
@@ -5448,14 +5449,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. */
@@ -5662,35 +5666,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;
@@ -5702,13 +5727,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);
@@ -5719,6 +5748,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;
@@ -6904,15 +6939,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 2f59d79d12c..1f4080e6320 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 841a831437e..29e5f085b97 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