Add new NOCROSSREFS_TO linker script command
authorMatthew Fortune <matthew.fortune@imgtec.com>
Thu, 14 Apr 2016 10:49:53 +0000 (11:49 +0100)
committerMatthew Fortune <matthew.fortune@imgtec.com>
Mon, 18 Apr 2016 11:45:46 +0000 (12:45 +0100)
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.

13 files changed:
ld/ChangeLog
ld/NEWS
ld/ld.texinfo
ld/ldcref.c
ld/ldgram.y
ld/ldlang.c
ld/ldlang.h
ld/ldlex.l
ld/testsuite/ld-scripts/cross4.t [new file with mode: 0644]
ld/testsuite/ld-scripts/cross5.t [new file with mode: 0644]
ld/testsuite/ld-scripts/cross6.t [new file with mode: 0644]
ld/testsuite/ld-scripts/cross7.t [new file with mode: 0644]
ld/testsuite/ld-scripts/crossref.exp

index b340125254bd38bc9ea2ea22b22598a224ad6864..0701b128584f80aff4260649dc32cf64f37a0e8b 100644 (file)
@@ -1,3 +1,23 @@
+2016-04-18  Matthew Fortune  <matthew.fortune@imgtec.com>
+
+       * 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  <hongjiu.lu@intel.com>
 
        * Makefile.in: Regenerated with automake 1.11.6.
diff --git a/ld/NEWS b/ld/NEWS
index b88da5cbb095f79841f1eb4aa8e272dacfe656a4..b4abd0b5b8d22e1daa622db5c60017843cbdb2c6 100644 (file)
--- 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
index d3d8dc608aa6c7ccbdfbe46ebef4c6e31bcfcdcf..7a2ed3abed3391d4022ddc794014e9ea54a93a6c 100644 (file)
@@ -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})
index b87f384754d92fd04cd20c2afa0b64a02380f122..d96db203d95fc3290622be48bc3b5d1d67e78738 100644 (file)
@@ -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;
 }
index a6642584a5bb6f835a6511951aaeb41d007f9375..9973b07fcc7b33537a5505985bf500d3970882b0 100644 (file)
@@ -141,7 +141,7 @@ static int error_index;
 %token DEFINED TARGET_K SEARCH_DIR MAP ENTRY
 %token <integer> 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); }
index 1947efc158d7fac2bad14effa6d707a3359f6f0f..856e3e268a68bf43f10a1eb7bf3120b142bf6477 100644 (file)
@@ -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;
+}
 \f
 /* Overlay handling.  We handle overlays with some static variables.  */
 
index 65d768b0d2dcd5a6f8c9d79b99b9722260494dfb..0cb147c56223f8ef3452fdc91a3d5f90a7dd274c 100644 (file)
@@ -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
index d70fad1a975d816362b609369d653e91e00e5e75..2eb8fc1020fbbca22751256b0987176d7047b524 100644 (file)
@@ -298,6 +298,7 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)*
 <BOTH,SCRIPT>"BYTE"                    { RTOKEN( BYTE);}
 <BOTH,SCRIPT>"NOFLOAT"                 { RTOKEN(NOFLOAT);}
 <EXPRESSION,BOTH,SCRIPT>"NOCROSSREFS"  { RTOKEN(NOCROSSREFS);}
+<EXPRESSION,BOTH,SCRIPT>"NOCROSSREFS_TO" { RTOKEN(NOCROSSREFS_TO);}
 <BOTH,SCRIPT>"OVERLAY"                 { RTOKEN(OVERLAY); }
 <BOTH,SCRIPT>"SORT_BY_NAME"            { RTOKEN(SORT_BY_NAME); }
 <BOTH,SCRIPT>"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 (file)
index 0000000..7f91b81
--- /dev/null
@@ -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 (file)
index 0000000..43657f1
--- /dev/null
@@ -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 (file)
index 0000000..4664221
--- /dev/null
@@ -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 (file)
index 0000000..dad2103
--- /dev/null
@@ -0,0 +1,9 @@
+NOCROSSREFS_TO(.data .text)
+
+SECTIONS
+{
+  .text : { *(.text) }
+  .data : { *(.data) *(.opd) }
+  .bss : { *(.bss) *(COMMON) }
+  /DISCARD/ : { *(*) }
+}
index 7244b90c5640f76154e78dcefbb7f28499dd85e7..437132083e246fced4d602b0846c9120bec4d453 100644 (file)
 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"