aboutsummaryrefslogtreecommitdiff
path: root/ld
diff options
context:
space:
mode:
Diffstat (limited to 'ld')
-rw-r--r--ld/ChangeLog22
-rw-r--r--ld/NEWS3
-rw-r--r--ld/ld.h1
-rw-r--r--ld/ld.texinfo20
-rw-r--r--ld/ldgram.y91
-rw-r--r--ld/ldlang.c30
-rw-r--r--ld/ldlang.h3
-rw-r--r--ld/ldlex.l1
-rw-r--r--ld/mri.c2
-rw-r--r--ld/testsuite/ChangeLog8
-rw-r--r--ld/testsuite/ld-scripts/section-flags-1.s2
-rw-r--r--ld/testsuite/ld-scripts/section-flags-1.t21
-rw-r--r--ld/testsuite/ld-scripts/section-flags-2.s2
-rw-r--r--ld/testsuite/ld-scripts/section-flags-2.t12
-rw-r--r--ld/testsuite/ld-scripts/section-flags.exp52
15 files changed, 269 insertions, 1 deletions
diff --git a/ld/ChangeLog b/ld/ChangeLog
index 7ce5d7a..fbbb5bd 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,3 +1,25 @@
+2011-07-11 Catherine Moore <clm@codesourcery.com>
+
+ * ld.h (section_flag_list): Add field to struct wildcard_spec.
+ * ld.texinfo (INPUT_SECTION_FLAGS): Document.
+ * ldgram.y (flag_info_list, flag_info): Add to union.
+ (INPUT_SECTION_FLAGS): New token.
+ (wildcard_spec): Initialize section_flag_list to NULL for
+ each alternative.
+ (sect_flag_list, sect_flags): New rules.
+ (input_section_spec_no_keep): Add alternatives to recognize
+ sect_flags.
+ * ldlang.c (walk_wild_consider_section): Initialize
+ section_flag_info field of the section struct.
+ (lang_add_section): Check input section flags.
+ (lang_add_wild): Initialize section_flag_list field of
+ the statement struct.
+ * ldlang.h (lang_input_statement_struct): Add section_flag_list field.
+ (lang_wild_statement_struct): Likewise.
+ * ldlex.l (INPUT_SECTION_FLAGS): New token.
+ * mri.c (mri_draw_tree): Initialize section_flag_list to NULL.
+ * NEWS: Announce INPUT_SECTION_FLAGS enhancement.
+
2011-07-09 H.J. Lu <hongjiu.lu@intel.com>
PR ld/12942
diff --git a/ld/NEWS b/ld/NEWS
index 40a6b9f..e3fa540 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -1,5 +1,8 @@
-*- text -*-
+* INPUT_SECTION_FLAGS has been added to the linker script language
+to allow selection of input sections by section header section flags.
+
* Add support for the Tilera TILEPRO and TILE-Gx architectures.
* Added SORT_BY_INIT_PRIORITY to the linker script language to permit
diff --git a/ld/ld.h b/ld/ld.h
index 9391923..996cdd2 100644
--- a/ld/ld.h
+++ b/ld/ld.h
@@ -96,6 +96,7 @@ struct wildcard_spec {
const char *name;
struct name_list *exclude_name_list;
sort_type sorted;
+ struct flag_info *section_flag_list;
};
struct wildcard_list {
diff --git a/ld/ld.texinfo b/ld/ld.texinfo
index 5a8e190..4fb649a 100644
--- a/ld/ld.texinfo
+++ b/ld/ld.texinfo
@@ -3859,6 +3859,26 @@ needs to be at a particular location in memory. For example:
data.o(.data)
@end smallexample
+To refine the sections that are included based on the section flags
+of an input section, INPUT_SECTION_FLAGS may be used.
+
+Here is a simple example for using Section header flags for ELF sections:
+
+@smallexample
+@group
+SECTIONS @{
+ .text : @{ INPUT_SECTION_FLAGS (SHF_MERGE & SHF_STRINGS) *(.text) @}
+ .text2 : @{ INPUT_SECTION_FLAGS (!SHF_WRITE) *(.text) @}
+@}
+@end group
+@end smallexample
+
+In this example, the output section @samp{.text} will be comprised of any
+input section matching the name *(.text) whose section header flags
+@code{SHF_MERGE} and @code{SHF_STRINGS} are set. The output section
+@samp{.text2} will be comprised of any input section matching the name *(.text)
+whose section header flag @code{SHF_WRITE} is clear.
+
You can also specify files within archives by writing a pattern
matching the archive, a colon, then the pattern matching the file,
with no whitespace around the colon.
diff --git a/ld/ldgram.y b/ld/ldgram.y
index 3795ffe..36ccb5b 100644
--- a/ld/ldgram.y
+++ b/ld/ldgram.y
@@ -72,6 +72,8 @@ static int error_index;
struct wildcard_spec wildcard;
struct wildcard_list *wildcard_list;
struct name_list *name_list;
+ struct flag_info_list *flag_info_list;
+ struct flag_info *flag_info;
int token;
union etree_union *etree;
struct phdr_info
@@ -93,6 +95,8 @@ static int error_index;
%type <fill> fill_opt fill_exp
%type <name_list> exclude_name_list
%type <wildcard_list> file_NAME_list
+%type <flag_info_list> sect_flag_list
+%type <flag_info> sect_flags
%type <name> memspec_opt casesymlist
%type <name> memspec_at_opt
%type <cname> wildcard_name
@@ -150,7 +154,7 @@ static int error_index;
%token INPUT_SCRIPT INPUT_MRI_SCRIPT INPUT_DEFSYM CASE EXTERN START
%token <name> VERS_TAG VERS_IDENTIFIER
%token GLOBAL LOCAL VERSIONK INPUT_VERSION_SCRIPT
-%token KEEP ONLY_IF_RO ONLY_IF_RW SPECIAL
+%token KEEP ONLY_IF_RO ONLY_IF_RW SPECIAL INPUT_SECTION_FLAGS
%token EXCLUDE_FILE
%token CONSTANT
%type <versyms> vers_defns
@@ -437,60 +441,121 @@ wildcard_spec:
$$.name = $1;
$$.sorted = none;
$$.exclude_name_list = NULL;
+ $$.section_flag_list = NULL;
}
| EXCLUDE_FILE '(' exclude_name_list ')' wildcard_name
{
$$.name = $5;
$$.sorted = none;
$$.exclude_name_list = $3;
+ $$.section_flag_list = NULL;
}
| SORT_BY_NAME '(' wildcard_name ')'
{
$$.name = $3;
$$.sorted = by_name;
$$.exclude_name_list = NULL;
+ $$.section_flag_list = NULL;
}
| SORT_BY_ALIGNMENT '(' wildcard_name ')'
{
$$.name = $3;
$$.sorted = by_alignment;
$$.exclude_name_list = NULL;
+ $$.section_flag_list = NULL;
}
| SORT_BY_NAME '(' SORT_BY_ALIGNMENT '(' wildcard_name ')' ')'
{
$$.name = $5;
$$.sorted = by_name_alignment;
$$.exclude_name_list = NULL;
+ $$.section_flag_list = NULL;
}
| SORT_BY_NAME '(' SORT_BY_NAME '(' wildcard_name ')' ')'
{
$$.name = $5;
$$.sorted = by_name;
$$.exclude_name_list = NULL;
+ $$.section_flag_list = NULL;
}
| SORT_BY_ALIGNMENT '(' SORT_BY_NAME '(' wildcard_name ')' ')'
{
$$.name = $5;
$$.sorted = by_alignment_name;
$$.exclude_name_list = NULL;
+ $$.section_flag_list = NULL;
}
| SORT_BY_ALIGNMENT '(' SORT_BY_ALIGNMENT '(' wildcard_name ')' ')'
{
$$.name = $5;
$$.sorted = by_alignment;
$$.exclude_name_list = NULL;
+ $$.section_flag_list = NULL;
}
| SORT_BY_NAME '(' EXCLUDE_FILE '(' exclude_name_list ')' wildcard_name ')'
{
$$.name = $7;
$$.sorted = by_name;
$$.exclude_name_list = $5;
+ $$.section_flag_list = NULL;
}
| SORT_BY_INIT_PRIORITY '(' wildcard_name ')'
{
$$.name = $3;
$$.sorted = by_init_priority;
$$.exclude_name_list = NULL;
+ $$.section_flag_list = NULL;
+ }
+ ;
+
+sect_flag_list: NAME
+ {
+ struct flag_info_list *n;
+ n = ((struct flag_info_list *) xmalloc (sizeof *n));
+ if ($1[0] == '!')
+ {
+ n->with = without_flags;
+ n->name = &$1[1];
+ }
+ else
+ {
+ n->with = with_flags;
+ n->name = $1;
+ }
+ n->valid = FALSE;
+ n->next = NULL;
+ $$ = n;
+ }
+ | sect_flag_list '&' NAME
+ {
+ struct flag_info_list *n;
+ n = ((struct flag_info_list *) xmalloc (sizeof *n));
+ if ($3[0] == '!')
+ {
+ n->with = without_flags;
+ n->name = &$3[1];
+ }
+ else
+ {
+ n->with = with_flags;
+ n->name = $3;
+ }
+ n->valid = FALSE;
+ n->next = $1;
+ $$ = n;
+ }
+ ;
+
+sect_flags:
+ INPUT_SECTION_FLAGS '(' sect_flag_list ')'
+ {
+ struct flag_info *n;
+ n = ((struct flag_info *) xmalloc (sizeof *n));
+ n->flag_list = $3;
+ n->flags_initialized = FALSE;
+ n->not_with_flags = 0;
+ n->only_with_flags = 0;
+ $$ = n;
}
;
@@ -541,16 +606,40 @@ input_section_spec_no_keep:
tmp.name = $1;
tmp.exclude_name_list = NULL;
tmp.sorted = none;
+ tmp.section_flag_list = NULL;
+ lang_add_wild (&tmp, NULL, ldgram_had_keep);
+ }
+ | sect_flags NAME
+ {
+ struct wildcard_spec tmp;
+ tmp.name = $2;
+ tmp.exclude_name_list = NULL;
+ tmp.sorted = none;
+ tmp.section_flag_list = $1;
lang_add_wild (&tmp, NULL, ldgram_had_keep);
}
| '[' file_NAME_list ']'
{
lang_add_wild (NULL, $2, ldgram_had_keep);
}
+ | sect_flags '[' file_NAME_list ']'
+ {
+ struct wildcard_spec tmp;
+ tmp.name = NULL;
+ tmp.exclude_name_list = NULL;
+ tmp.sorted = none;
+ tmp.section_flag_list = $1;
+ lang_add_wild (NULL, $3, ldgram_had_keep);
+ }
| wildcard_spec '(' file_NAME_list ')'
{
lang_add_wild (&$1, $3, ldgram_had_keep);
}
+ | sect_flags wildcard_spec '(' file_NAME_list ')'
+ {
+ $2.section_flag_list = $1;
+ lang_add_wild (&$2, $4, ldgram_had_keep);
+ }
;
input_section_spec:
diff --git a/ld/ldlang.c b/ld/ldlang.c
index 860ce27..3e63eed 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -237,6 +237,9 @@ walk_wild_consider_section (lang_wild_statement_type *ptr,
{
struct name_list *list_tmp;
+ /* Propagate the section_flag_info from the wild statement to the section. */
+ s->section_flag_info = ptr->section_flag_list;
+
/* Don't process sections from files which were excluded. */
for (list_tmp = sec->spec.exclude_name_list;
list_tmp;
@@ -2261,8 +2264,11 @@ lang_add_section (lang_statement_list_type *ptr,
lang_output_section_statement_type *output)
{
flagword flags = section->flags;
+ struct flag_info *sflag_info = section->section_flag_info;
+
bfd_boolean discard;
lang_input_section_type *new_section;
+ bfd *abfd = link_info.output_bfd;
/* Discard sections marked with SEC_EXCLUDE. */
discard = (flags & SEC_EXCLUDE) != 0;
@@ -2288,6 +2294,28 @@ lang_add_section (lang_statement_list_type *ptr,
return;
}
+ if (sflag_info)
+ {
+ if (sflag_info->flags_initialized == FALSE)
+ bfd_lookup_section_flags (&link_info, sflag_info);
+
+ if (sflag_info->only_with_flags != 0
+ && sflag_info->not_with_flags != 0
+ && ((sflag_info->not_with_flags & flags) != 0
+ || (sflag_info->only_with_flags & flags)
+ != sflag_info->only_with_flags))
+ return;
+
+ if (sflag_info->only_with_flags != 0
+ && (sflag_info->only_with_flags & flags)
+ != sflag_info->only_with_flags)
+ return;
+
+ if (sflag_info->not_with_flags != 0
+ && (sflag_info->not_with_flags & flags) != 0)
+ return;
+ }
+
if (section->output_section != NULL)
return;
@@ -6719,10 +6747,12 @@ lang_add_wild (struct wildcard_spec *filespec,
new_stmt = new_stat (lang_wild_statement, stat_ptr);
new_stmt->filename = NULL;
new_stmt->filenames_sorted = FALSE;
+ new_stmt->section_flag_list = NULL;
if (filespec != NULL)
{
new_stmt->filename = filespec->name;
new_stmt->filenames_sorted = filespec->sorted == by_name;
+ new_stmt->section_flag_list = filespec->section_flag_list;
}
new_stmt->section_list = section_list;
new_stmt->keep_sections = keep_sections;
diff --git a/ld/ldlang.h b/ld/ldlang.h
index d172c34..a6d22ce 100644
--- a/ld/ldlang.h
+++ b/ld/ldlang.h
@@ -240,6 +240,8 @@ typedef struct lang_input_statement_struct
bfd *the_bfd;
+ struct flag_info *section_flag_list;
+
/* Point to the next file - whatever it is, wanders up and down
archives */
union lang_statement_union *next;
@@ -337,6 +339,7 @@ struct lang_wild_statement_struct
walk_wild_section_handler_t walk_wild_section_handler;
struct wildcard_list *handler_data[4];
lang_section_bst_type *tree;
+ struct flag_info *section_flag_list;
};
typedef struct lang_address_statement_struct
diff --git a/ld/ldlex.l b/ld/ldlex.l
index 013c07e..4e859b0 100644
--- a/ld/ldlex.l
+++ b/ld/ldlex.l
@@ -313,6 +313,7 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)*
<BOTH,SCRIPT>"org" { RTOKEN(ORIGIN);}
<BOTH,SCRIPT>"l" { RTOKEN( LENGTH);}
<BOTH,SCRIPT>"len" { RTOKEN( LENGTH);}
+<EXPRESSION,BOTH,SCRIPT>"INPUT_SECTION_FLAGS" { RTOKEN(INPUT_SECTION_FLAGS); }
<EXPRESSION,BOTH,SCRIPT>"INCLUDE" { RTOKEN(INCLUDE);}
<BOTH,SCRIPT>"PHDRS" { RTOKEN (PHDRS); }
<EXPRESSION,BOTH,SCRIPT>"AT" { RTOKEN(AT);}
diff --git a/ld/mri.c b/ld/mri.c
index ce1406a..91b40dc 100644
--- a/ld/mri.c
+++ b/ld/mri.c
@@ -215,6 +215,7 @@ mri_draw_tree (void)
tmp->spec.name = p->name;
tmp->spec.exclude_name_list = NULL;
tmp->spec.sorted = none;
+ tmp->spec.section_flag_list = NULL;
lang_add_wild (NULL, tmp, FALSE);
/* If there is an alias for this section, add it too. */
@@ -226,6 +227,7 @@ mri_draw_tree (void)
tmp->spec.name = aptr->name;
tmp->spec.exclude_name_list = NULL;
tmp->spec.sorted = none;
+ tmp->spec.section_flag_list = NULL;
lang_add_wild (NULL, tmp, FALSE);
}
diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog
index 4fe8d0c..64c2d10 100644
--- a/ld/testsuite/ChangeLog
+++ b/ld/testsuite/ChangeLog
@@ -1,3 +1,11 @@
+2011-07-11 Catherine Moore <clm@cm00re.com>
+
+ * ld-scripts/section-flags-1.s: New.
+ * ld-scripts/section-flags-1.t: New.
+ * ld-scripts/section-flags-2.s: New.
+ * ld-scripts/section-flags-2.t: New.
+ * ld-scripts/section-flags.exp: New.
+
2011-07-11 Alan Modra <amodra@gmail.com>
* ld-powerpc/tocopt2.s, * ld-powerpc/tocopt2.out,
diff --git a/ld/testsuite/ld-scripts/section-flags-1.s b/ld/testsuite/ld-scripts/section-flags-1.s
new file mode 100644
index 0000000..566e3c6
--- /dev/null
+++ b/ld/testsuite/ld-scripts/section-flags-1.s
@@ -0,0 +1,2 @@
+ .text
+ .space 16
diff --git a/ld/testsuite/ld-scripts/section-flags-1.t b/ld/testsuite/ld-scripts/section-flags-1.t
new file mode 100644
index 0000000..3380489
--- /dev/null
+++ b/ld/testsuite/ld-scripts/section-flags-1.t
@@ -0,0 +1,21 @@
+MEMORY
+{
+ ram (rwx) : ORIGIN = 0x100000, LENGTH = 144M
+}
+
+SECTIONS
+{
+ .text :
+ {
+ INPUT_SECTION_FLAGS (!SHF_TLS) *(.text .text.* .text_* .gnu.linkonce.t.*)
+ } >ram
+
+ .text_vle :
+ {
+ INPUT_SECTION_FLAGS (SHF_MERGE & SHF_STRINGS & SHF_LINK_ORDER) *(.text .text.* .text_* .gnu.linkonce.t.*)
+ } >ram
+ .text_other :
+ {
+ INPUT_SECTION_FLAGS (SHF_MERGE & !SHF_STRINGS) *(.text .text.* .text_* .gnu.linkonce.t.*)
+ }
+}
diff --git a/ld/testsuite/ld-scripts/section-flags-2.s b/ld/testsuite/ld-scripts/section-flags-2.s
new file mode 100644
index 0000000..566e3c6
--- /dev/null
+++ b/ld/testsuite/ld-scripts/section-flags-2.s
@@ -0,0 +1,2 @@
+ .text
+ .space 16
diff --git a/ld/testsuite/ld-scripts/section-flags-2.t b/ld/testsuite/ld-scripts/section-flags-2.t
new file mode 100644
index 0000000..ca5ae63
--- /dev/null
+++ b/ld/testsuite/ld-scripts/section-flags-2.t
@@ -0,0 +1,12 @@
+MEMORY
+{
+ ram (rwx) : ORIGIN = 0x100000, LENGTH = 144M
+}
+
+SECTIONS
+{
+ .text :
+ {
+ INPUT_SECTION_FLAGS (!SHF_TLS) *(EXCLUDE_FILE (section-flags-1.o) .text .text.* .text_* .gnu.linkonce.t.*)
+ } >ram
+}
diff --git a/ld/testsuite/ld-scripts/section-flags.exp b/ld/testsuite/ld-scripts/section-flags.exp
new file mode 100644
index 0000000..700c3d3
--- /dev/null
+++ b/ld/testsuite/ld-scripts/section-flags.exp
@@ -0,0 +1,52 @@
+# Test SECTION_FLAGS in a linker script.
+#
+# This file is part of the GNU Binutils.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+set testname "SECTION_FLAGS-1"
+
+
+# This test only works for ELF targets
+if {! [is_elf_format]} {
+ unsupported $testname
+ return
+}
+
+if ![ld_assemble $as $srcdir/$subdir/section-flags-1.s tmpdir/section-flags-1.o] {
+ unresolved $testname
+ return
+}
+
+if ![ld_simple_link $ld tmpdir/section-flags-1 "-T $srcdir/$subdir/section-flags-1.t tmpdir/section-flags-1.o"] {
+ fail $testname
+ return
+}
+
+pass $testname
+
+set testname "SECTION_FLAGS-2"
+if ![ld_assemble $as $srcdir/$subdir/section-flags-2.s tmpdir/section-flags-2.o] {
+ unresolved $testname
+ return
+}
+
+if ![ld_simple_link $ld tmpdir/section-flags-2 "-T $srcdir/$subdir/section-flags-2.t tmpdir/section-flags-1.o tmpdir/section-flags-2.o"] {
+ fail $testname
+ return
+}
+
+pass $testname