This is the mail archive of the binutils-cvs@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]

[binutils-gdb] ld: Add '--require-defined' command line option.


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=0a61824343c98b9440fe13752f800d65f765c4c1

commit 0a61824343c98b9440fe13752f800d65f765c4c1
Author: Andrew Burgess <andrew.burgess@embecosm.com>
Date:   Wed Jul 15 18:37:30 2015 +0100

    ld: Add '--require-defined' command line option.
    
    Add a new command line option '--require-defined' to the linker.  This
    option operates identically to the '--undefined' option, except that if
    the symbol is not defined in the final output file then the linker will
    exit with an error.
    
    When making use of --gc-section, or just when trying to pull in parts of
    a library, it is not uncommon for a user to use the '--undefined'
    command line option to specify a symbol that the user then expects to be
    defined by one of the object files supplied to the link.
    
    However, if for any reason the symbol is not satisfied by an object
    provided to the link the user will be left with an undefined symbol in
    the output file, instead of a defined symbol.
    
    In some cases the above behaviour is what the user wants, in other cases
    though we can do better.  The '--require-defined' option tries to fill
    this gap.  The symbol passed to the '--require-defined' option is
    treated exactly as if the symbol was passed to '--undefined', however,
    before the linker exits a check is made that all symbols passed to
    '--require-defined' are actually defined, if any are not then the link
    will fail with an error.
    
    ld/ChangeLog:
    
    	* ld.texinfo (Options): Document --require-defined option.
    	* ldlang.c (struct require_defined_symbol): New structure.
    	(require_defined_symbol_list): New variable.
    	(ldlang_add_require_defined): New function.
    	(ldlang_check_require_defined_symbols): New function.
    	(lang_process): Check required symbols are defined.
    	* ldlang.h (ldlang_add_require_defined): Declare.
    	* ldlex.h (enum option_values): Add OPTION_REQUIRE_DEFINED_SYMBOL.
    	* lexsup.c (ld_options): Add '--require-defined' entry.
    	(parse_args): Handle '--require-defined' entry.
    	* NEWS: Mention new '--require-defined' option.
    
    ld/testsuite/ChangeLog:
    
    	* ld-undefined/require-defined-1.d: New file.
    	* ld-undefined/require-defined-2.d: New file.
    	* ld-undefined/require-defined-3.d: New file.
    	* ld-undefined/require-defined-4.d: New file.
    	* ld-undefined/require-defined-5.d: New file.
    	* ld-undefined/require-defined.exp: New file.
    	* ld-undefined/require-defined.s: New file.

Diff:
---
 ld/ChangeLog                                  | 14 +++++++
 ld/NEWS                                       |  3 ++
 ld/ld.texinfo                                 | 16 ++++++++
 ld/ldlang.c                                   | 52 ++++++++++++++++++++++++
 ld/ldlang.h                                   |  2 +
 ld/ldlex.h                                    |  1 +
 ld/lexsup.c                                   |  6 +++
 ld/testsuite/ChangeLog                        | 10 +++++
 ld/testsuite/ld-undefined/require-defined-1.d |  4 ++
 ld/testsuite/ld-undefined/require-defined-2.d |  8 ++++
 ld/testsuite/ld-undefined/require-defined-3.d |  8 ++++
 ld/testsuite/ld-undefined/require-defined-4.d |  8 ++++
 ld/testsuite/ld-undefined/require-defined-5.d | 10 +++++
 ld/testsuite/ld-undefined/require-defined.exp | 58 +++++++++++++++++++++++++++
 ld/testsuite/ld-undefined/require-defined.s   |  9 +++++
 15 files changed, 209 insertions(+)

diff --git a/ld/ChangeLog b/ld/ChangeLog
index e040329..23b12c8 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,3 +1,17 @@
+2015-08-04  Andrew Burgess  <andrew.burgess@embecosm.com>
+
+	* ld.texinfo (Options): Document --require-defined option.
+	* ldlang.c (struct require_defined_symbol): New structure.
+	(require_defined_symbol_list): New variable.
+	(ldlang_add_require_defined): New function.
+	(ldlang_check_require_defined_symbols): New function.
+	(lang_process): Check required symbols are defined.
+	* ldlang.h (ldlang_add_require_defined): Declare.
+	* ldlex.h (enum option_values): Add OPTION_REQUIRE_DEFINED_SYMBOL.
+	* lexsup.c (ld_options): Add '--require-defined' entry.
+	(parse_args): Handle '--requre-defined' entry.
+	* NEWS: Mention new '--require-defined' option.
+
 2015-08-03  Andrew Burgess  <andrew.burgess@embecosm.com>
 
 	* ld.texinfo (MEMORY): Explain that multiple MEMORY commands are
diff --git a/ld/NEWS b/ld/NEWS
index e3de432..f9ef88d 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -12,6 +12,9 @@
 
 * Add --print-memory-usage option to report memory blocks usage.
 
+* Add --require-defined option, it's like --undefined except the new symbol
+  must be defined by the end of the link.
+
 Changes in 2.25:
 
 * PE binaries now once again contain real timestamps by default.  To disable
diff --git a/ld/ld.texinfo b/ld/ld.texinfo
index 8a7a08f..bddf926 100644
--- a/ld/ld.texinfo
+++ b/ld/ld.texinfo
@@ -973,6 +973,22 @@ modules from standard libraries.  @samp{-u} may be repeated with
 different option arguments to enter additional undefined symbols.  This
 option is equivalent to the @code{EXTERN} linker script command.
 
+If this option is being used to force additional modules to be pulled
+into the link, and if it is an error for the symbol to remain
+undefined, then the option @option{--require-defined} should be used
+instead.
+
+@kindex --require-defined=@var{symbol}
+@cindex symbols, require defined
+@cindex defined symbol
+@item --require-defined=@var{symbol}
+Require that @var{symbol} is defined in the output file.  This option
+is the same as option @option{--undefined} except that if @var{symbol}
+is not defined in the output file then the linker will issue an error
+and exit.  The same effect can be achieved in a linker script by using
+@code{EXTERN}, @code{ASSERT} and @code{DEFINED} together.  This option
+can be used multiple times to require additional symbols.
+
 @kindex -Ur
 @cindex constructors
 @item -Ur
diff --git a/ld/ldlang.c b/ld/ldlang.c
index b816d69..0d6419d 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -3413,6 +3413,55 @@ lang_place_undefineds (void)
     insert_undefined (ptr->name);
 }
 
+/* Structure used to build the list of symbols that the user has required
+   be defined.  */
+
+struct require_defined_symbol
+{
+  const char *name;
+  struct require_defined_symbol *next;
+};
+
+/* The list of symbols that the user has required be defined.  */
+
+static struct require_defined_symbol *require_defined_symbol_list;
+
+/* Add a new symbol NAME to the list of symbols that are required to be
+   defined.  */
+
+void
+ldlang_add_require_defined (const char * const name)
+{
+  struct require_defined_symbol *ptr;
+
+  ldlang_add_undef (name, TRUE);
+  ptr = (struct require_defined_symbol *) stat_alloc (sizeof (*ptr));
+  ptr->next = require_defined_symbol_list;
+  ptr->name = strdup (name);
+  require_defined_symbol_list = ptr;
+}
+
+/* Check that all symbols the user required to be defined, are defined,
+   raise an error if we find a symbol that is not defined.  */
+
+static void
+ldlang_check_require_defined_symbols (void)
+{
+  struct require_defined_symbol *ptr;
+
+  for (ptr = require_defined_symbol_list; ptr != NULL; ptr = ptr->next)
+    {
+      struct bfd_link_hash_entry *h;
+
+      h = bfd_link_hash_lookup (link_info.hash, ptr->name,
+                                FALSE, FALSE, TRUE);
+      if (h == NULL
+          || (h->type != bfd_link_hash_defined
+              && h->type != bfd_link_hash_defweak))
+        einfo(_("%P%X: required symbol `%s' not defined\n"), ptr->name);
+    }
+}
+
 /* Check for all readonly or some readwrite sections.  */
 
 static void
@@ -6805,6 +6854,9 @@ lang_process (void)
   if (command_line.check_section_addresses)
     lang_check_section_addresses ();
 
+  /* Check any required symbols are known.  */
+  ldlang_check_require_defined_symbols ();
+
   lang_end ();
 }
 
diff --git a/ld/ldlang.h b/ld/ldlang.h
index 475cf71..4b7e65d 100644
--- a/ld/ldlang.h
+++ b/ld/ldlang.h
@@ -609,6 +609,8 @@ extern lang_output_section_statement_type *next_matching_output_section_statemen
   (lang_output_section_statement_type *, int);
 extern void ldlang_add_undef
   (const char *const, bfd_boolean);
+extern void ldlang_add_require_defined
+  (const char *const);
 extern void lang_add_output_format
   (const char *, const char *, const char *, int);
 extern void lang_list_init
diff --git a/ld/ldlex.h b/ld/ldlex.h
index 7885de0..59bd14f 100644
--- a/ld/ldlex.h
+++ b/ld/ldlex.h
@@ -143,6 +143,7 @@ enum option_values
   OPTION_PUSH_STATE,
   OPTION_POP_STATE,
   OPTION_PRINT_MEMORY_USAGE,
+  OPTION_REQUIRE_DEFINED_SYMBOL,
 };
 
 /* The initial parser states.  */
diff --git a/ld/lexsup.c b/ld/lexsup.c
index 0aa67f5..2854134 100644
--- a/ld/lexsup.c
+++ b/ld/lexsup.c
@@ -212,6 +212,9 @@ static const struct ld_option ld_options[] =
   { {"undefined", required_argument, NULL, 'u'},
     'u', N_("SYMBOL"), N_("Start with undefined reference to SYMBOL"),
     TWO_DASHES },
+  { {"require-defined", required_argument, NULL, OPTION_REQUIRE_DEFINED_SYMBOL},
+    '\0', N_("SYMBOL"), N_("Require SYMBOL be defined in the final output"),
+    TWO_DASHES },
   { {"unique", optional_argument, NULL, OPTION_UNIQUE},
     '\0', N_("[=SECTION]"),
     N_("Don't merge input [SECTION | orphan] sections"), TWO_DASHES },
@@ -1247,6 +1250,9 @@ parse_args (unsigned argc, char **argv)
 	case 'u':
 	  ldlang_add_undef (optarg, TRUE);
 	  break;
+        case OPTION_REQUIRE_DEFINED_SYMBOL:
+          ldlang_add_require_defined (optarg);
+	  break;
 	case OPTION_UNIQUE:
 	  if (optarg != NULL)
 	    lang_add_unique (optarg);
diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog
index c35d4a7..512abc3 100644
--- a/ld/testsuite/ChangeLog
+++ b/ld/testsuite/ChangeLog
@@ -1,3 +1,13 @@
+2015-08-04  Andrew Burgess  <andrew.burgess@embecosm.com>
+
+	* ld-undefined/require-defined-1.d: New file.
+	* ld-undefined/require-defined-2.d: New file.
+	* ld-undefined/require-defined-3.d: New file.
+	* ld-undefined/require-defined-4.d: New file.
+	* ld-undefined/require-defined-5.d: New file.
+	* ld-undefined/require-defined.exp: New file.
+	* ld-undefined/require-defined.s: New file.
+
 2015-07-30  H.J. Lu  <hongjiu.lu@intel.com>
 
 	PR ld/18735
diff --git a/ld/testsuite/ld-undefined/require-defined-1.d b/ld/testsuite/ld-undefined/require-defined-1.d
new file mode 100644
index 0000000..12b0cf5
--- /dev/null
+++ b/ld/testsuite/ld-undefined/require-defined-1.d
@@ -0,0 +1,4 @@
+#name: Check require-defined with an undefined symbol
+#source: require-defined.s
+#ld: -e _start --gc-sections --require-defined=xxx
+#error: required symbol `xxx' not defined
diff --git a/ld/testsuite/ld-undefined/require-defined-2.d b/ld/testsuite/ld-undefined/require-defined-2.d
new file mode 100644
index 0000000..e770eea
--- /dev/null
+++ b/ld/testsuite/ld-undefined/require-defined-2.d
@@ -0,0 +1,8 @@
+#name: Check require-defined can require a symbol from an object
+#source: require-defined.s
+#ld: -e _start --gc-sections --require-defined=bar
+#nm: -n
+
+#...
+[0-9a-f]+ T bar
+#...
diff --git a/ld/testsuite/ld-undefined/require-defined-3.d b/ld/testsuite/ld-undefined/require-defined-3.d
new file mode 100644
index 0000000..c61ed34
--- /dev/null
+++ b/ld/testsuite/ld-undefined/require-defined-3.d
@@ -0,0 +1,8 @@
+#name: Check require-defined does no error on a defined symbol
+#source: require-defined.s
+#ld: -e _start --require-defined=bar
+#nm: -n
+
+#...
+[0-9a-f]+ T bar
+#...
diff --git a/ld/testsuite/ld-undefined/require-defined-4.d b/ld/testsuite/ld-undefined/require-defined-4.d
new file mode 100644
index 0000000..2922c99
--- /dev/null
+++ b/ld/testsuite/ld-undefined/require-defined-4.d
@@ -0,0 +1,8 @@
+#name: Check require-defined can require a symbol from an archive
+#source: require-defined.s
+#ld: -e _start --require-defined=foo tmpdir/libfoo.a
+#nm: -n
+
+#...
+[0-9a-f]+ T foo
+#...
diff --git a/ld/testsuite/ld-undefined/require-defined-5.d b/ld/testsuite/ld-undefined/require-defined-5.d
new file mode 100644
index 0000000..ea288a9
--- /dev/null
+++ b/ld/testsuite/ld-undefined/require-defined-5.d
@@ -0,0 +1,10 @@
+#name: Check require-defined can require two symbols
+#source: require-defined.s
+#ld: -e _start --gc-sections --require-defined=bar --require-defined=foo tmpdir/libfoo.a
+#nm: -n
+
+#...
+[0-9a-f]+ T foo
+#...
+[0-9a-f]+ T bar
+#...
\ No newline at end of file
diff --git a/ld/testsuite/ld-undefined/require-defined.exp b/ld/testsuite/ld-undefined/require-defined.exp
new file mode 100644
index 0000000..16013dc
--- /dev/null
+++ b/ld/testsuite/ld-undefined/require-defined.exp
@@ -0,0 +1,58 @@
+# Expect script for ld --undefined and --require-defined testing.
+#   Copyright (C) 2015 Free Software Foundation, Inc.
+#
+# 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.
+#
+
+# Some of these tests use --gc-sections.  For now we don't attempt any
+# if --gc-sections is unavailable, as most major targets do support
+# this option.
+if ![check_gc_sections_available] {
+    unsupported "require-defined testing"
+    return
+}
+
+# The following targets all fail these tests for reasons that appear
+# to be unrelated to the test themselves (for example some of these
+# targets require more complex linker scripts).  Given the small
+# number of targets, I'm just skipping the tests in these cases.]
+if { [istarget "powerpcle-*-*"] \
+     || [istarget "cris-axis-elf"] \
+     || [istarget "ns32k-*-netbsd"] \
+     || [istarget "*-*-coff"] \
+     || [istarget "*-*-xcoff"] \
+     || [istarget "*-*-*aout*"] \
+     || [istarget "*-*-*aix*"] } {
+    unsupported "require-defined testing"
+    return
+}
+
+set build_tests {
+  {"Build libfoo.a"
+   "" "" ""
+   {entry.s} {} "libfoo.a"}
+}
+
+run_ld_link_tests $build_tests
+
+set test_list [lsort [glob -nocomplain $srcdir/$subdir/require-defined*.d]]
+foreach t $test_list {
+    # We need to strip the ".d", but can leave the dirname.
+    verbose [file rootname $t]
+    run_dump_test [file rootname $t]
+}
diff --git a/ld/testsuite/ld-undefined/require-defined.s b/ld/testsuite/ld-undefined/require-defined.s
new file mode 100644
index 0000000..2bda640
--- /dev/null
+++ b/ld/testsuite/ld-undefined/require-defined.s
@@ -0,0 +1,9 @@
+        .text
+        .global _start
+_start:
+        .word 0
+
+        .section .text.1, "ax"
+        .global bar
+bar:
+        .word 0


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