From cdf969539c718acb1f3f031b2c55d5274a538717 Mon Sep 17 00:00:00 2001 From: Matthew Fortune Date: Thu, 14 Apr 2016 11:49:53 +0100 Subject: [PATCH] Add new NOCROSSREFS_TO linker script command NOCROSSREFS_TO is similar to the existing NOCROSSREFS command but only checks one direction of cross referencing. ld/ChangeLog * ld.texinfo: Document NOCROSSREFS_TO script command. * ldlang.h (struct lang_nocrossrefs): Add onlyfirst field. (lang_add_nocrossref_to): New prototype. * ldcref.c (check_local_sym_xref): Use onlyfirst to only look for symbols defined in the first section. (check_nocrossref): Likewise. * ldgram.y (NOCROSSREFS_TO): New script command. * ldlang.c (lang_add_nocrossref): Set onlyfirst to FALSE. (lang_add_nocrossref_to): New function. * ldlex.l (NOCROSSREFS_TO): New token. * NEWS: Mention NOCROSSREFS_TO. * testsuite/ld-scripts/cross4.t: New file. * testsuite/ld-scripts/cross5.t: Likewise. * testsuite/ld-scripts/cross6.t: Likewise. * testsuite/ld-scripts/cross7.t: Likewise. * testsuite/ld-scripts/crossref.exp: Run 4 new NOCROSSREFS_TO tests. --- ld/ChangeLog | 20 +++++++++ ld/NEWS | 2 + ld/ld.texinfo | 19 +++++++++ ld/ldcref.c | 24 ++++++++--- ld/ldgram.y | 6 ++- ld/ldlang.c | 10 +++++ ld/ldlang.h | 3 ++ ld/ldlex.l | 1 + ld/testsuite/ld-scripts/cross4.t | 10 +++++ ld/testsuite/ld-scripts/cross5.t | 10 +++++ ld/testsuite/ld-scripts/cross6.t | 9 ++++ ld/testsuite/ld-scripts/cross7.t | 9 ++++ ld/testsuite/ld-scripts/crossref.exp | 64 ++++++++++++++++++++++++++++ 13 files changed, 180 insertions(+), 7 deletions(-) create mode 100644 ld/testsuite/ld-scripts/cross4.t create mode 100644 ld/testsuite/ld-scripts/cross5.t create mode 100644 ld/testsuite/ld-scripts/cross6.t create mode 100644 ld/testsuite/ld-scripts/cross7.t diff --git a/ld/ChangeLog b/ld/ChangeLog index b340125254b..0701b128584 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,23 @@ +2016-04-18 Matthew Fortune + + * ld.texinfo: Document NOCROSSREFS_TO script command. + * ldlang.h (struct lang_nocrossrefs): Add onlyfirst field. + (lang_add_nocrossref_to): New prototype. + * ldcref.c (check_local_sym_xref): Use onlyfirst to only look for + symbols defined in the first section. + (check_nocrossref): Likewise. + * ldgram.y (NOCROSSREFS_TO): New script command. + * ldlang.c (lang_add_nocrossref): Set onlyfirst to FALSE. + (lang_add_nocrossref_to): New function. + * ldlex.l (NOCROSSREFS_TO): New token. + * NEWS: Mention NOCROSSREFS_TO. + * testsuite/ld-scripts/cross4.t: New file. + * testsuite/ld-scripts/cross5.t: Likewise. + * testsuite/ld-scripts/cross6.t: Likewise. + * testsuite/ld-scripts/cross7.t: Likewise. + * testsuite/ld-scripts/crossref.exp: Run 4 new NOCROSSREFS_TO + tests. + 2016-04-15 H.J. Lu * Makefile.in: Regenerated with automake 1.11.6. diff --git a/ld/NEWS b/ld/NEWS index b88da5cbb09..b4abd0b5b8d 100644 --- a/ld/NEWS +++ b/ld/NEWS @@ -9,6 +9,8 @@ * Support for -z nodynamic-undefined-weak in the x86 ELF linker, which avoids dynamic relocations against undefined weak symbols in executable. +* The NOCROSSREFSTO command was added to the linker script language. + Changes in 2.26: * Add --fix-stm32l4xx-629360 to the ARM linker to enable a link-time diff --git a/ld/ld.texinfo b/ld/ld.texinfo index d3d8dc608aa..7a2ed3abed3 100644 --- a/ld/ld.texinfo +++ b/ld/ld.texinfo @@ -3674,6 +3674,25 @@ an error and returns a non-zero exit status. Note that the @code{NOCROSSREFS} command uses output section names, not input section names. +@item NOCROSSREFS_TO(@var{tosection} @var{fromsection} @dots{}) +@kindex NOCROSSREFS_TO(@var{tosection} @var{fromsections}) +@cindex cross references +This command may be used to tell @command{ld} to issue an error about any +references to one section from a list of other sections. + +The @code{NOCROSSREFS} command is useful when ensuring that two or more +output sections are entirely independent but there are situations where +a one-way dependency is needed. For example, in a multi-core application +there may be shared code that can be called from each core but for safety +must never call back. + +The @code{NOCROSSREFS_TO} command takes a list of output section names. +The first section can not be referenced from any of the other sections. +If @command{ld} detects any references to the first section from any of +the other sections, it reports an error and returns a non-zero exit +status. Note that the @code{NOCROSSREFS_TO} command uses output section +names, not input section names. + @ifclear SingleFormat @item OUTPUT_ARCH(@var{bfdarch}) @kindex OUTPUT_ARCH(@var{bfdarch}) diff --git a/ld/ldcref.c b/ld/ldcref.c index b87f384754d..d96db203d95 100644 --- a/ld/ldcref.c +++ b/ld/ldcref.c @@ -534,8 +534,14 @@ check_local_sym_xref (lang_input_statement_type *statement) symname = sym->name; for (ncrs = nocrossref_list; ncrs != NULL; ncrs = ncrs->next) for (ncr = ncrs->list; ncr != NULL; ncr = ncr->next) - if (strcmp (ncr->name, outsecname) == 0) - check_refs (symname, FALSE, sym->section, abfd, ncrs); + { + if (strcmp (ncr->name, outsecname) == 0) + check_refs (symname, FALSE, sym->section, abfd, ncrs); + /* The NOCROSSREFS_TO command only checks symbols defined in + the first section in the list. */ + if (ncrs->onlyfirst) + break; + } } } } @@ -572,10 +578,16 @@ check_nocrossref (struct cref_hash_entry *h, void *ignore ATTRIBUTE_UNUSED) for (ncrs = nocrossref_list; ncrs != NULL; ncrs = ncrs->next) for (ncr = ncrs->list; ncr != NULL; ncr = ncr->next) - if (strcmp (ncr->name, defsecname) == 0) - for (ref = h->refs; ref != NULL; ref = ref->next) - check_refs (hl->root.string, TRUE, hl->u.def.section, - ref->abfd, ncrs); + { + if (strcmp (ncr->name, defsecname) == 0) + for (ref = h->refs; ref != NULL; ref = ref->next) + check_refs (hl->root.string, TRUE, hl->u.def.section, + ref->abfd, ncrs); + /* The NOCROSSREFS_TO command only checks symbols defined in the first + section in the list. */ + if (ncrs->onlyfirst) + break; + } return TRUE; } diff --git a/ld/ldgram.y b/ld/ldgram.y index a6642584a5b..9973b07fcc7 100644 --- a/ld/ldgram.y +++ b/ld/ldgram.y @@ -141,7 +141,7 @@ static int error_index; %token DEFINED TARGET_K SEARCH_DIR MAP ENTRY %token NEXT %token SIZEOF ALIGNOF ADDR LOADADDR MAX_K MIN_K -%token STARTUP HLL SYSLIB FLOAT NOFLOAT NOCROSSREFS +%token STARTUP HLL SYSLIB FLOAT NOFLOAT NOCROSSREFS NOCROSSREFS_TO %token ORIGIN FILL %token LENGTH CREATE_OBJECT_SYMBOLS INPUT GROUP OUTPUT CONSTRUCTORS %token ALIGNMOD AT SUBALIGN HIDDEN PROVIDE PROVIDE_HIDDEN AS_NEEDED @@ -353,6 +353,10 @@ ifile_p1: { lang_add_nocrossref ($3); } + | NOCROSSREFS_TO '(' nocrossref_list ')' + { + lang_add_nocrossref_to ($3); + } | EXTERN '(' extern_name_list ')' | INSERT_K AFTER NAME { lang_add_insert ($3, 0); } diff --git a/ld/ldlang.c b/ld/ldlang.c index 1947efc158d..856e3e268a6 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -7486,11 +7486,21 @@ lang_add_nocrossref (lang_nocrossref_type *l) n = (struct lang_nocrossrefs *) xmalloc (sizeof *n); n->next = nocrossref_list; n->list = l; + n->onlyfirst = FALSE; nocrossref_list = n; /* Set notice_all so that we get informed about all symbols. */ link_info.notice_all = TRUE; } + +/* Record a section that cannot be referenced from a list of sections. */ + +void +lang_add_nocrossref_to (lang_nocrossref_type *l) +{ + lang_add_nocrossref (l); + nocrossref_list->onlyfirst = TRUE; +} /* Overlay handling. We handle overlays with some static variables. */ diff --git a/ld/ldlang.h b/ld/ldlang.h index 65d768b0d2d..0cb147c5622 100644 --- a/ld/ldlang.h +++ b/ld/ldlang.h @@ -464,6 +464,7 @@ struct lang_nocrossrefs { struct lang_nocrossrefs *next; lang_nocrossref_type *list; + bfd_boolean onlyfirst; }; /* This structure is used to hold a list of input section names which @@ -654,6 +655,8 @@ extern void lang_new_phdr etree_type *); extern void lang_add_nocrossref (lang_nocrossref_type *); +extern void lang_add_nocrossref_to + (lang_nocrossref_type *); extern void lang_enter_overlay (etree_type *, etree_type *); extern void lang_enter_overlay_section diff --git a/ld/ldlex.l b/ld/ldlex.l index d70fad1a975..2eb8fc1020f 100644 --- a/ld/ldlex.l +++ b/ld/ldlex.l @@ -298,6 +298,7 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)* "BYTE" { RTOKEN( BYTE);} "NOFLOAT" { RTOKEN(NOFLOAT);} "NOCROSSREFS" { RTOKEN(NOCROSSREFS);} +"NOCROSSREFS_TO" { RTOKEN(NOCROSSREFS_TO);} "OVERLAY" { RTOKEN(OVERLAY); } "SORT_BY_NAME" { RTOKEN(SORT_BY_NAME); } "SORT_BY_ALIGNMENT" { RTOKEN(SORT_BY_ALIGNMENT); } diff --git a/ld/testsuite/ld-scripts/cross4.t b/ld/testsuite/ld-scripts/cross4.t new file mode 100644 index 00000000000..7f91b817efa --- /dev/null +++ b/ld/testsuite/ld-scripts/cross4.t @@ -0,0 +1,10 @@ +NOCROSSREFS_TO(.data .nocrossrefs) + +SECTIONS +{ + .text : { *(.text) } + .nocrossrefs : { *(.nocrossrefs) } + .data : { *(.data) *(.opd) } + .bss : { *(.bss) *(COMMON) } + /DISCARD/ : { *(*) } +} diff --git a/ld/testsuite/ld-scripts/cross5.t b/ld/testsuite/ld-scripts/cross5.t new file mode 100644 index 00000000000..43657f17b4e --- /dev/null +++ b/ld/testsuite/ld-scripts/cross5.t @@ -0,0 +1,10 @@ +NOCROSSREFS_TO(.nocrossrefs .data) + +SECTIONS +{ + .text : { *(.text) } + .nocrossrefs : { *(.nocrossrefs) } + .data : { *(.data) *(.opd) } + .bss : { *(.bss) *(COMMON) } + /DISCARD/ : { *(*) } +} diff --git a/ld/testsuite/ld-scripts/cross6.t b/ld/testsuite/ld-scripts/cross6.t new file mode 100644 index 00000000000..466422171ab --- /dev/null +++ b/ld/testsuite/ld-scripts/cross6.t @@ -0,0 +1,9 @@ +NOCROSSREFS_TO(.text .data) + +SECTIONS +{ + .text : { *(.text) } + .data : { *(.data) *(.opd) } + .bss : { *(.bss) *(COMMON) } + /DISCARD/ : { *(*) } +} diff --git a/ld/testsuite/ld-scripts/cross7.t b/ld/testsuite/ld-scripts/cross7.t new file mode 100644 index 00000000000..dad21031edb --- /dev/null +++ b/ld/testsuite/ld-scripts/cross7.t @@ -0,0 +1,9 @@ +NOCROSSREFS_TO(.data .text) + +SECTIONS +{ + .text : { *(.text) } + .data : { *(.data) *(.opd) } + .bss : { *(.bss) *(COMMON) } + /DISCARD/ : { *(*) } +} diff --git a/ld/testsuite/ld-scripts/crossref.exp b/ld/testsuite/ld-scripts/crossref.exp index 7244b90c564..437132083e2 100644 --- a/ld/testsuite/ld-scripts/crossref.exp +++ b/ld/testsuite/ld-scripts/crossref.exp @@ -22,11 +22,19 @@ set test1 "NOCROSSREFS 1" set test2 "NOCROSSREFS 2" set test3 "NOCROSSREFS 3" +set test4 "NOCROSSREFS_TO 1" +set test5 "NOCROSSREFS_TO 2" +set test6 "NOCROSSREFS_TO 3" +set test7 "NOCROSSREFS_TO 4" if { ![is_remote host] && [which $CC] == 0 } { untested $test1 untested $test2 untested $test3 + untested $test4 + untested $test5 + untested $test6 + untested $test7 return } @@ -158,5 +166,61 @@ if [string match "" $exec_output] then { fail $test3 } +set exec_output [run_host_cmd "$ld" "$flags -o tmpdir/cross4 -T $srcdir/$subdir/cross4.t tmpdir/cross4.o"] +set exec_output [prune_warnings $exec_output] + +regsub -all "(^|\n)($ld: warning: cannot find entry symbol\[^\n\]*\n?)" $exec_output "\\1" exec_output + +if [string match "" $exec_output] then { + pass $test4 +} else { + verbose -log "$exec_output" + fail $test4 +} + +set exec_output [run_host_cmd "$ld" "$flags -o tmpdir/cross5 -T $srcdir/$subdir/cross5.t tmpdir/cross4.o"] +set exec_output [prune_warnings $exec_output] + +regsub -all "(^|\n)($ld: warning: cannot find entry symbol\[^\n\]*\n?)" $exec_output "\\1" exec_output + +if [string match "" $exec_output] then { + fail $test5 +} else { + verbose -log "$exec_output" + if [regexp "prohibited cross reference from .* to `.*' in" $exec_output] { + pass $test5 + } else { + fail $test5 + } +} + +set exec_output [run_host_cmd "$ld" "$flags -o tmpdir/cross6 -T $srcdir/$subdir/cross6.t tmpdir/cross3.o"] +set exec_output [prune_warnings $exec_output] + +regsub -all "(^|\n)($ld: warning: cannot find entry symbol\[^\n\]*\n?)" $exec_output "\\1" exec_output + +if [string match "" $exec_output] then { + pass $test6 +} else { + verbose -log "$exec_output" + fail $test6 +} + +set exec_output [run_host_cmd "$ld" "$flags -o tmpdir/cross7 -T $srcdir/$subdir/cross7.t tmpdir/cross3.o"] +set exec_output [prune_warnings $exec_output] + +regsub -all "(^|\n)($ld: warning: cannot find entry symbol\[^\n\]*\n?)" $exec_output "\\1" exec_output + +if [string match "" $exec_output] then { + fail $test7 +} else { + verbose -log "$exec_output" + if [regexp "prohibited cross reference from .* to `.*' in" $exec_output] { + pass $test7 + } else { + fail $test7 + } +} + set CFLAGS "$old_CFLAGS" set CC "$old_CC" -- 2.30.2