This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Add new NOCROSSREFSTO linker script command


This patch introduces a new linker script command NOCROSSREFSTO.

The command performs a one-way cross referencing check instead
of the bi-directional checks done by NOCROSSREFS.

The idea of this feature is to support multi-core layouts where
each core has a private memory region that is inaccessible to the
other core as well as some shared memory. Functions and data
in shared memory can be safely referenced from core specific
memory. If a reference were allowed in the reverse direction then
one core may end up trying to access another core's memory by
calling into shared memory and then back out.

The feature does not give absolute safety as there remain ways
to circumvent the rules; it is however much better than no checks
at all.

New tests pass on x86_64-pc-linux-gnu and no new regressions.

Does anyone else think they or their users would use this
feature?  I and other MIPS users would of course :-)

Comments on implementation most welcome. I tried to keep it
lightweight.

Thanks,
Matthew

ld/
	* ldlang.h (struct lang_nocrossrefs): Add onlyfirst field.
	(lang_add_nocrossrefto): New prototype.
	* ldlex.l (NOCROSSREFSTO): New token.
	* ldgram.y (NOCROSSREFSTO): New script command.
	* ldlang.c (lang_add_nocrossref): Set onlyfirst to FALSE.
	(lang_add_nocrossrefto): New function.
	* ldcref.c (check_local_sym_xref): Use onlyfirst to only look for
	symbols defined in the first section.
	(check_nocrossref): Likewise.
	* ld.texinfo: Document NOCROSSREFSTO script command.
	* NEWS: Mention NOCROSSREFSTO.

ld/testsuite/

	* ld-scripts/cross4.t: New file.
	* ld-scripts/cross5.t: Likewise.
	* ld-scripts/cross6.t: Likewise.
	* ld-scripts/cross7.t: Likewise.
	* ld-scripts/crossref.exp: Run 4 new NOCROSSREFSTO tests.
---
 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 ++++++++++++++++++++++++++++++++++++
 12 files changed, 160 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/NEWS b/ld/NEWS
index b88da5c..b4abd0b 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 d3d8dc6..f6b8def 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 NOCROSSREFSTO(@var{tosection} @var{fromsection} @dots{})
+@kindex NOCROSSREFSTO(@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{NOCROSSREFSTO} 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{NOCROSSREFSTO} 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 b87f384..3b4f683 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 NOCROSSREFSTO 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 NOCROSSREFSTO 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 a664258..460d8e5 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 <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 NOCROSSREFSTO
 %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);
 		}
+	|	NOCROSSREFSTO '(' nocrossref_list ')'
+		{
+		  lang_add_nocrossrefto ($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 1947efc..fa3b665 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_nocrossrefto (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 65d768b..44ab422 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_nocrossrefto
+  (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 d70fad1..f677e70 100644
--- a/ld/ldlex.l
+++ b/ld/ldlex.l
@@ -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>"NOCROSSREFSTO"	{ RTOKEN(NOCROSSREFSTO);}
 <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
index 0000000..7858a37
--- /dev/null
+++ b/ld/testsuite/ld-scripts/cross4.t
@@ -0,0 +1,10 @@
+NOCROSSREFSTO(.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 0000000..ae55033
--- /dev/null
+++ b/ld/testsuite/ld-scripts/cross5.t
@@ -0,0 +1,10 @@
+NOCROSSREFSTO(.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 0000000..9ba5b87
--- /dev/null
+++ b/ld/testsuite/ld-scripts/cross6.t
@@ -0,0 +1,9 @@
+NOCROSSREFSTO(.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 0000000..22fc786
--- /dev/null
+++ b/ld/testsuite/ld-scripts/cross7.t
@@ -0,0 +1,9 @@
+NOCROSSREFSTO(.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 7244b90..940ac7c 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 "NOCROSSREFSTO 1"
+set test5 "NOCROSSREFSTO 2"
+set test6 "NOCROSSREFSTO 3"
+set test7 "NOCROSSREFSTO 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.2.1


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]