V6 [PATCH] ld: Add --export-dynamic-symbol and --export-dynamic-symbol-list

Message ID CAMe9rOos-S_sS5=HujgFNhkZ3DD9WUVf_FVuW6YN+=PvaBF65Q@mail.gmail.com
State New
Headers show
Series
  • V6 [PATCH] ld: Add --export-dynamic-symbol and --export-dynamic-symbol-list
Related show

Commit Message

Here is the rebased patch.  Nick, Alan, is it OK for master?  Thanks.

--export-dynamic-symbol-list is like a dynamic list, but without
the symbolic property for unspecified symbols.

When creating an executable, --export-dynamic-symbol-list is treated
like --dynamic-list.

When creating a shared library, it is treated like --dynamic-list if
-Bsymbolic or --dynamic-list are used,  otherwise, it is ignored, so
that references to matched symbols will not be bound to the definitions
within the shared library.

-- 
H.J.

Comments

Hi H.J. 

> Here is the rebased patch.  Nick, Alan, is it OK for master?  Thanks.


Short version: Approved - please apply.

Long version: The patch looks mostly fine to me.  But there is a problem: 
some regressions in the linker testsuite for various targets:

  Checking Binutils in: mips-sgi-irix6 ... 
    LD REGRESSION: -u --export-dynamic-symbol foo archive 
    LD REGRESSION: -u --export-dynamic-symbol "f*" archive 
    LD REGRESSION: -u --export-dynamic-symbol-list foo bar archive
    LD REGRESSION: -u --export-dynamic-symbol-list fstar archive 

The failures here all look like:

  extra regexps in ld/testsuite/ld-dynamic/export-dynamic-symbol-2.d starting with "^[0-9a-f]+ T +bar$"

I suspect that this is a target that can be skipped/xfailed.

Next:

  Checking Binutils in: mn10300-elf ... 
    LD REGRESSION: --export-dynamic-symbol foo archive  
    LD REGRESSION: -u --export-dynamic-symbol foo archive 
    LD REGRESSION: -u --export-dynamic-symbol "f*" archive 

These failures are from:

  ./ld-new: tmpdir/dump: error: PHDR segment not covered by LOAD segment

However this failure is showing up for a lot more tests than just your new ones,
so please ignore.  It is obviously a mn10300 specific problem.

Finally:

  Checking Binutils in: sanitize-undefined ... LD: 400  done
    LD REGRESSION: Build libdl2e.so with --export-dynamic-symbol=foo 
    LD REGRESSION: Build libdl2f.so with --dynamic-list=dlempty.list and
    LD REGRESSION: Build libdl2g.so with --export-dynamic-symbol-list=dl2.list 
    LD REGRESSION: Build libdl2h.so with --dynamic-list=dlempty.list and
    LD REGRESSION: Build libdl2i.so with -Bsymbolic and
    LD REGRESSION: Build libdl2j.so with -Bsymbolic and
    LD REGRESSION: Build libdl2k.so with --export-dynamic-symbol-list=dl2.list and

Which are all due to:

  bfd/elf64-x86-64.c:3233:8: runtime error: member access within null pointer of type 'struct elf_x86_link_hash_entry'

I remember trying to look into this before and getting nowhere.  It is however 
another generic problem for linker tests run with the undefined sanitizer enabled
so it is not something that should hold up your patch.

Cheers
  Nick
On Wed, Jun 03, 2020 at 11:51:30AM +0100, Nick Clifton wrote:
> Which are all due to:

> 

>   bfd/elf64-x86-64.c:3233:8: runtime error: member access within null pointer of type 'struct elf_x86_link_hash_entry'


This will be "&(EH)->elf" in elfxx-x86.h:GENERATE_DYNAMIC_RELOCATION_P.
Fixable by using "(struct elf_link_hash_entry *) (EH)" instead.

-- 
Alan Modra
Australia Development Lab, IBM

Patch

From 9b7df61dcd8f2147d8966a6261e7ff4219443ad3 Mon Sep 17 00:00:00 2001
From: Fangrui Song <maskray@google.com>
Date: Wed, 22 Apr 2020 22:12:42 -0700
Subject: [PATCH] ld: Add --export-dynamic-symbol and
 --export-dynamic-symbol-list

--export-dynamic-symbol-list is like a dynamic list, but without
the symbolic property for unspecified symbols.

When creating an executable, --export-dynamic-symbol-list is treated
like --dynamic-list.

When creating a shared library, it is treated like --dynamic-list if
-Bsymbolic or --dynamic-list are used,  otherwise, it is ignored, so
that references to matched symbols will not be bound to the definitions
within the shared library.

2020-05-XX  Fangrui Song  <maskray@google.com>
	    H.J. Lu  <hongjiu.lu@intel.com>

	PR ld/25910
	* NEWS: Mention --export-dynamic-symbol[-list].
	* ld.texi: Document --export-dynamic-symbol[-list].
	* ldgram.y: Pass current_dynamic_list_p to
	lang_append_dynamic_list.
	* ldlang.c (current_dynamic_list_p): New.
	(ang_append_dynamic_list): Updated to take a pointer to
	struct bfd_elf_dynamic_list * argument instead of using
	link_info.dynamic_list.
	(lang_append_dynamic_list_cpp_typeinfo): Pass
	&link_info.dynamic_list to ang_append_dynamic_list.
	(lang_append_dynamic_list_cpp_new): Likewise.
	* ldlang.h (current_dynamic_list_p): New.
	(lang_append_dynamic_list): Add a pointer to
	struct bfd_elf_dynamic_list * argument.
	* ldlex.h (option_values): Add OPTION_EXPORT_DYNAMIC_SYMBOL and
	OPTION_EXPORT_DYNAMIC_SYMBOL_LIST.
	* lexsup.c (ld_options): Add entries for
	OPTION_EXPORT_DYNAMIC_SYMBOL and
	OPTION_EXPORT_DYNAMIC_SYMBOL_LIST.
	(parse_args): Handle --export-dynamic-symbol and
	--export-dynamic-symbol-list.
	* testsuite/ld-dynamic/export-dynamic-symbol-1.d: New.
	* testsuite/ld-dynamic/export-dynamic-symbol-2.d: New.
	* testsuite/ld-dynamic/export-dynamic-symbol-glob.d: New.
	* testsuite/ld-dynamic/export-dynamic-symbol-list-1.d: New.
	* testsuite/ld-dynamic/export-dynamic-symbol-list-2.d: New.
	* testsuite/ld-dynamic/export-dynamic-symbol-list-glob.d: New.
	* testsuite/ld-dynamic/export-dynamic-symbol.exp: New.
	* testsuite/ld-dynamic/export-dynamic-symbol.s: New.
	* testsuite/ld-dynamic/foo-bar.list: New.
	* testsuite/ld-dynamic/foo.list: New.
	* testsuite/ld-dynamic/foo.s: New.
	* testsuite/ld-dynamic/fstar.list: New.
	* testsuite/ld-elf/dlempty.list: New.
	* testsuite/ld-elf/shared.exp: Add tests for
	--export-dynamic-symbol and --export-dynamic-symbol-list.
---
 ld/NEWS                                       |  3 +
 ld/ld.texi                                    | 18 +++++
 ld/ldgram.y                                   |  2 +-
 ld/ldlang.c                                   | 16 +++--
 ld/ldlang.h                                   |  5 +-
 ld/ldlex.h                                    |  2 +
 ld/lexsup.c                                   | 72 +++++++++++++++++++
 .../ld-dynamic/export-dynamic-symbol-1.d      |  9 +++
 .../ld-dynamic/export-dynamic-symbol-2.d      |  9 +++
 .../ld-dynamic/export-dynamic-symbol-glob.d   |  8 +++
 .../ld-dynamic/export-dynamic-symbol-list-1.d |  9 +++
 .../ld-dynamic/export-dynamic-symbol-list-2.d |  9 +++
 .../export-dynamic-symbol-list-glob.d         |  8 +++
 .../ld-dynamic/export-dynamic-symbol.exp      | 70 ++++++++++++++++++
 .../ld-dynamic/export-dynamic-symbol.s        | 17 +++++
 ld/testsuite/ld-dynamic/foo-bar.list          |  1 +
 ld/testsuite/ld-dynamic/foo.list              |  1 +
 ld/testsuite/ld-dynamic/foo.s                 |  4 ++
 ld/testsuite/ld-dynamic/fstar.list            |  1 +
 ld/testsuite/ld-elf/dlempty.list              |  3 +
 ld/testsuite/ld-elf/shared.exp                | 42 +++++++++++
 21 files changed, 300 insertions(+), 9 deletions(-)
 create mode 100644 ld/testsuite/ld-dynamic/export-dynamic-symbol-1.d
 create mode 100644 ld/testsuite/ld-dynamic/export-dynamic-symbol-2.d
 create mode 100644 ld/testsuite/ld-dynamic/export-dynamic-symbol-glob.d
 create mode 100644 ld/testsuite/ld-dynamic/export-dynamic-symbol-list-1.d
 create mode 100644 ld/testsuite/ld-dynamic/export-dynamic-symbol-list-2.d
 create mode 100644 ld/testsuite/ld-dynamic/export-dynamic-symbol-list-glob.d
 create mode 100644 ld/testsuite/ld-dynamic/export-dynamic-symbol.exp
 create mode 100644 ld/testsuite/ld-dynamic/export-dynamic-symbol.s
 create mode 100644 ld/testsuite/ld-dynamic/foo-bar.list
 create mode 100644 ld/testsuite/ld-dynamic/foo.list
 create mode 100644 ld/testsuite/ld-dynamic/foo.s
 create mode 100644 ld/testsuite/ld-dynamic/fstar.list
 create mode 100644 ld/testsuite/ld-elf/dlempty.list

diff --git a/ld/NEWS b/ld/NEWS
index 0dc5e9b368..485e1cf5b9 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -1,5 +1,8 @@ 
 -*- text -*-
 
+* Add ELF linker command-line options, --export-dynamic-symbol and
+  --export-dynamic-symbol-list, to make symbols dynamic.
+
 * Add a configure option, --enable-textrel-check=[no|yes|warning|error],
   to decide what ELF linker should do by default with DT_TEXTREL in an
   executable or shared library.  Default to yes for Linux/x86 targets.
diff --git a/ld/ld.texi b/ld/ld.texi
index cb38f47cd3..bf474d4c62 100644
--- a/ld/ld.texi
+++ b/ld/ld.texi
@@ -569,6 +569,24 @@  Note that this option is specific to ELF targeted ports.  PE targets
 support a similar function to export all symbols from a DLL or EXE; see
 the description of @samp{--export-all-symbols} below.
 
+@kindex --export-dynamic-symbol=@var{glob}
+@cindex export dynamic symbol
+@item --export-dynamic-symbol=@var{glob}
+When creating a dynamically linked executable, symbols matching
+@var{glob} will be added to the dynamic symbol table. When creating a
+shared library, references to symbols matching @var{glob} will not be
+bound to the definitions within the shared library. This option is a
+no-op when creating a shared library and @samp{-Bsymbolic} or
+@samp{--dynamic-list} are not specified. This option is only meaningful
+on ELF platforms which support shared libraries.
+
+@kindex --export-dynamic-symbol-list=@var{file}
+@cindex export dynamic symbol list
+@item --export-dynamic-symbol-list=@var{file}
+Specify a @samp{--export-dynamic-symbol} for each pattern in the file.
+The format of the file is the same as the version node without
+scope and node name.  See @ref{VERSION} for more information.
+
 @ifclear SingleFormat
 @cindex big-endian objects
 @cindex endianness
diff --git a/ld/ldgram.y b/ld/ldgram.y
index df5c035c03..36845c4c30 100644
--- a/ld/ldgram.y
+++ b/ld/ldgram.y
@@ -1313,7 +1313,7 @@  dynamic_list_node:
 dynamic_list_tag:
 		vers_defns ';'
 		{
-		  lang_append_dynamic_list ($1);
+		  lang_append_dynamic_list (current_dynamic_list_p, $1);
 		}
 	;
 
diff --git a/ld/ldlang.c b/ld/ldlang.c
index 3d653d460d..14a6a577d2 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -118,6 +118,7 @@  lang_statement_list_type file_chain = { NULL, NULL };
    lang_statement_union).  */
 lang_statement_list_type input_file_chain;
 static const char *current_input_file;
+struct bfd_elf_dynamic_list **current_dynamic_list_p;
 struct bfd_sym_chain entry_symbol = { NULL, NULL };
 const char *entry_section = ".text";
 struct lang_input_statement_flags input_flags;
@@ -9324,15 +9325,16 @@  lang_add_unique (const char *name)
 /* Append the list of dynamic symbols to the existing one.  */
 
 void
-lang_append_dynamic_list (struct bfd_elf_version_expr *dynamic)
+lang_append_dynamic_list (struct bfd_elf_dynamic_list **list_p,
+			  struct bfd_elf_version_expr *dynamic)
 {
-  if (link_info.dynamic_list)
+  if (*list_p)
     {
       struct bfd_elf_version_expr *tail;
       for (tail = dynamic; tail->next != NULL; tail = tail->next)
 	;
-      tail->next = link_info.dynamic_list->head.list;
-      link_info.dynamic_list->head.list = dynamic;
+      tail->next = (*list_p)->head.list;
+      (*list_p)->head.list = dynamic;
     }
   else
     {
@@ -9341,7 +9343,7 @@  lang_append_dynamic_list (struct bfd_elf_version_expr *dynamic)
       d = (struct bfd_elf_dynamic_list *) xcalloc (1, sizeof *d);
       d->head.list = dynamic;
       d->match = lang_vers_match;
-      link_info.dynamic_list = d;
+      *list_p = d;
     }
 }
 
@@ -9363,7 +9365,7 @@  lang_append_dynamic_list_cpp_typeinfo (void)
     dynamic = lang_new_vers_pattern (dynamic, symbols [i], "C++",
 				     FALSE);
 
-  lang_append_dynamic_list (dynamic);
+  lang_append_dynamic_list (&link_info.dynamic_list, dynamic);
 }
 
 /* Append the list of C++ operator new and delete dynamic symbols to the
@@ -9384,7 +9386,7 @@  lang_append_dynamic_list_cpp_new (void)
     dynamic = lang_new_vers_pattern (dynamic, symbols [i], "C++",
 				     FALSE);
 
-  lang_append_dynamic_list (dynamic);
+  lang_append_dynamic_list (&link_info.dynamic_list, dynamic);
 }
 
 /* Scan a space and/or comma separated string of features.  */
diff --git a/ld/ldlang.h b/ld/ldlang.h
index 3018c3e2ba..529ccd1585 100644
--- a/ld/ldlang.h
+++ b/ld/ldlang.h
@@ -513,6 +513,8 @@  extern bfd_boolean entry_from_cmdline;
 extern lang_statement_list_type file_chain;
 extern lang_statement_list_type input_file_chain;
 
+extern struct bfd_elf_dynamic_list **current_dynamic_list_p;
+
 extern int lang_statement_iteration;
 extern struct asneeded_minfo **asneeded_list_tail;
 
@@ -673,7 +675,8 @@  extern struct bfd_elf_version_deps *lang_add_vers_depend
   (struct bfd_elf_version_deps *, const char *);
 extern void lang_register_vers_node
   (const char *, struct bfd_elf_version_tree *, struct bfd_elf_version_deps *);
-extern void lang_append_dynamic_list (struct bfd_elf_version_expr *);
+extern void lang_append_dynamic_list (struct bfd_elf_dynamic_list **,
+				      struct bfd_elf_version_expr *);
 extern void lang_append_dynamic_list_cpp_typeinfo (void);
 extern void lang_append_dynamic_list_cpp_new (void);
 extern void lang_add_unique
diff --git a/ld/ldlex.h b/ld/ldlex.h
index 318ac7a789..6388247b45 100644
--- a/ld/ldlex.h
+++ b/ld/ldlex.h
@@ -81,6 +81,8 @@  enum option_values
   OPTION_DYNAMIC_LIST_CPP_NEW,
   OPTION_DYNAMIC_LIST_CPP_TYPEINFO,
   OPTION_DYNAMIC_LIST_DATA,
+  OPTION_EXPORT_DYNAMIC_SYMBOL,
+  OPTION_EXPORT_DYNAMIC_SYMBOL_LIST,
   OPTION_WARN_COMMON,
   OPTION_WARN_CONSTRUCTORS,
   OPTION_WARN_FATAL,
diff --git a/ld/lexsup.c b/ld/lexsup.c
index 412e2e6026..4808f7443d 100644
--- a/ld/lexsup.c
+++ b/ld/lexsup.c
@@ -504,6 +504,10 @@  static const struct ld_option ld_options[] =
     '\0', NULL, N_("Use C++ typeinfo dynamic list"), TWO_DASHES },
   { {"dynamic-list", required_argument, NULL, OPTION_DYNAMIC_LIST},
     '\0', N_("FILE"), N_("Read dynamic list"), TWO_DASHES },
+  { {"export-dynamic-symbol", required_argument, NULL, OPTION_EXPORT_DYNAMIC_SYMBOL},
+    '\0', N_("SYMBOL"), N_("Export the specified symbol"), EXACTLY_TWO_DASHES },
+  { {"export-dynamic-symbol-list", required_argument, NULL, OPTION_EXPORT_DYNAMIC_SYMBOL_LIST},
+    '\0', N_("FILE"), N_("Read export dynamic symbol list"), EXACTLY_TWO_DASHES },
   { {"warn-common", no_argument, NULL, OPTION_WARN_COMMON},
     '\0', NULL, N_("Warn about duplicate common symbols"), TWO_DASHES },
   { {"warn-constructors", no_argument, NULL, OPTION_WARN_CONSTRUCTORS},
@@ -588,6 +592,7 @@  parse_args (unsigned argc, char **argv)
     dynamic_list_data,
     dynamic_list
   } opt_dynamic_list = dynamic_list_unset;
+  struct bfd_elf_dynamic_list *export_list = NULL;
 
   shortopts = (char *) xmalloc (OPTION_COUNT * 3 + 2);
   longopts = (struct option *)
@@ -1419,11 +1424,35 @@  parse_args (unsigned argc, char **argv)
 	    ldfile_open_command_file (optarg);
 	    saved_script_handle = hold_script_handle;
 	    parser_input = input_dynamic_list;
+	    current_dynamic_list_p = &link_info.dynamic_list;
 	    yyparse ();
 	  }
 	  if (opt_dynamic_list != dynamic_list_data)
 	    opt_dynamic_list = dynamic_list;
 	  break;
+	case OPTION_EXPORT_DYNAMIC_SYMBOL:
+	  {
+	    struct bfd_elf_version_expr *expr
+	      = lang_new_vers_pattern (NULL, xstrdup (optarg), NULL,
+				       FALSE);
+	    lang_append_dynamic_list (&export_list, expr);
+          }
+	  break;
+	case OPTION_EXPORT_DYNAMIC_SYMBOL_LIST:
+	  /* This option indicates a small script that only specifies
+	     an export list.  Read it, but don't assume that we've
+	     seen a linker script.  */
+	  {
+	    FILE *hold_script_handle;
+
+	    hold_script_handle = saved_script_handle;
+	    ldfile_open_command_file (optarg);
+	    saved_script_handle = hold_script_handle;
+	    parser_input = input_dynamic_list;
+	    current_dynamic_list_p = &export_list;
+	    yyparse ();
+	  }
+	  break;
 	case OPTION_WARN_COMMON:
 	  config.warn_common = TRUE;
 	  break;
@@ -1666,6 +1695,49 @@  parse_args (unsigned argc, char **argv)
       && command_line.check_section_addresses < 0)
     command_line.check_section_addresses = 0;
 
+  if (export_list)
+    {
+      struct bfd_elf_version_expr *head = export_list->head.list;
+      struct bfd_elf_version_expr *next;
+
+      /* For --export-dynamic-symbol[-list]:
+	 1. When building executable, treat like --dynamic-list.
+	 2. When building shared object:
+	    a. If -Bsymbolic or --dynamic-list are used, treat like
+	       --dynamic-list.
+	    b. Otherwise, ignored.
+       */
+      if (!bfd_link_relocatable (&link_info)
+	  && (bfd_link_executable (&link_info)
+	      || opt_symbolic != symbolic_unset
+	      || opt_dynamic_list != dynamic_list_unset))
+	{
+	  /* Append the export list to link_info.dynamic_list.  */
+	  if (link_info.dynamic_list)
+	    {
+	      for (next = head; next->next != NULL; next = next->next)
+		;
+	      next->next = link_info.dynamic_list->head.list;
+	      link_info.dynamic_list->head.list = head;
+	    }
+	  else
+	    link_info.dynamic_list = export_list;
+
+	  if (opt_dynamic_list != dynamic_list_data)
+	    opt_dynamic_list = dynamic_list;
+	}
+      else
+	{
+	  /* Free the export list.  */
+	  for (; head->next != NULL; head = next)
+	    {
+	      next = head->next;
+	      free (head);
+	    }
+	  free (export_list);
+	}
+    }
+
   switch (opt_dynamic_list)
     {
     case dynamic_list_unset:
diff --git a/ld/testsuite/ld-dynamic/export-dynamic-symbol-1.d b/ld/testsuite/ld-dynamic/export-dynamic-symbol-1.d
new file mode 100644
index 0000000000..25ae13023e
--- /dev/null
+++ b/ld/testsuite/ld-dynamic/export-dynamic-symbol-1.d
@@ -0,0 +1,9 @@ 
+#name: --export-dynamic-symbol foo archive
+#source: export-dynamic-symbol.s
+#ld: -pie --export-dynamic-symbol foo tmpdir/libpr25910.a
+#nm: -n
+
+#failif
+#...
+[0-9a-f]+ T +foo
+#...
diff --git a/ld/testsuite/ld-dynamic/export-dynamic-symbol-2.d b/ld/testsuite/ld-dynamic/export-dynamic-symbol-2.d
new file mode 100644
index 0000000000..d38508a5b5
--- /dev/null
+++ b/ld/testsuite/ld-dynamic/export-dynamic-symbol-2.d
@@ -0,0 +1,9 @@ 
+#name: -u --export-dynamic-symbol foo archive
+#source: export-dynamic-symbol.s
+#ld: -pie -u foo --export-dynamic-symbol foo --export-dynamic-symbol=bar tmpdir/libpr25910.a
+#nm: -D
+
+#...
+[0-9a-f]+ T +bar
+[0-9a-f]+ T +foo
+#...
diff --git a/ld/testsuite/ld-dynamic/export-dynamic-symbol-glob.d b/ld/testsuite/ld-dynamic/export-dynamic-symbol-glob.d
new file mode 100644
index 0000000000..f8187be75c
--- /dev/null
+++ b/ld/testsuite/ld-dynamic/export-dynamic-symbol-glob.d
@@ -0,0 +1,8 @@ 
+#name: -u --export-dynamic-symbol "f*" archive
+#source: export-dynamic-symbol.s
+#ld: -pie -u foo --export-dynamic-symbol "f*" tmpdir/libpr25910.a
+#nm: -D
+
+#...
+[0-9a-f]+ T +foo
+#...
diff --git a/ld/testsuite/ld-dynamic/export-dynamic-symbol-list-1.d b/ld/testsuite/ld-dynamic/export-dynamic-symbol-list-1.d
new file mode 100644
index 0000000000..fc58af9357
--- /dev/null
+++ b/ld/testsuite/ld-dynamic/export-dynamic-symbol-list-1.d
@@ -0,0 +1,9 @@ 
+#name: --export-dynamic-symbol-list foo archive
+#source: export-dynamic-symbol.s
+#ld: -pie --export-dynamic-symbol-list foo.list tmpdir/libpr25910.a
+#nm: -n
+
+#failif
+#...
+[0-9a-f]+ T +foo
+#...
diff --git a/ld/testsuite/ld-dynamic/export-dynamic-symbol-list-2.d b/ld/testsuite/ld-dynamic/export-dynamic-symbol-list-2.d
new file mode 100644
index 0000000000..337f642ee9
--- /dev/null
+++ b/ld/testsuite/ld-dynamic/export-dynamic-symbol-list-2.d
@@ -0,0 +1,9 @@ 
+#name: -u --export-dynamic-symbol-list foo bar archive
+#source: export-dynamic-symbol.s
+#ld: -pie -u foo --export-dynamic-symbol-list foo-bar.list tmpdir/libpr25910.a
+#nm: -D
+
+#...
+[0-9a-f]+ T +bar
+[0-9a-f]+ T +foo
+#...
diff --git a/ld/testsuite/ld-dynamic/export-dynamic-symbol-list-glob.d b/ld/testsuite/ld-dynamic/export-dynamic-symbol-list-glob.d
new file mode 100644
index 0000000000..916a22ca23
--- /dev/null
+++ b/ld/testsuite/ld-dynamic/export-dynamic-symbol-list-glob.d
@@ -0,0 +1,8 @@ 
+#name: -u --export-dynamic-symbol-list fstar archive
+#source: export-dynamic-symbol.s
+#ld: -pie -u foo --export-dynamic-symbol-list fstar.list tmpdir/libpr25910.a
+#nm: -D
+
+#...
+[0-9a-f]+ T +foo
+#...
diff --git a/ld/testsuite/ld-dynamic/export-dynamic-symbol.exp b/ld/testsuite/ld-dynamic/export-dynamic-symbol.exp
new file mode 100644
index 0000000000..ae530361fb
--- /dev/null
+++ b/ld/testsuite/ld-dynamic/export-dynamic-symbol.exp
@@ -0,0 +1,70 @@ 
+# Expect script for ld --export-dynamic-symbol tests
+#   Copyright (C) 2020 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.
+#
+
+if ![is_elf_format] {
+    return
+}
+
+# Skip targets where -shared is not supported
+
+if ![check_shared_lib_support] {
+    return
+}
+
+set old_ASFLAGS $ASFLAGS
+
+# These targets require extra GAS options when building code for shared
+# libraries.
+if [istarget "nds32*-*"] {
+    append ASFLAGS " -mpic"
+}
+if [istarget "tic6x-*-*"] {
+    append ASFLAGS " -mpic -mpid=near"
+}
+if [istarget "sparc*-*-*"] {
+    append ASFLAGS " -K PIC -Av9"
+}
+
+set old_LDFLAGS $LDFLAGS
+
+# These targets require a non-default emulation for successful shared
+# library/executable builds.
+if [istarget "tic6x-*-*"] {
+    append LDFLAGS " -melf32_tic6x_le"
+}
+
+set build_tests {
+  {"Build libpr25910.a"
+   "" "" ""
+   {foo.s} {} "libpr25910.a"}
+}
+
+run_ld_link_tests $build_tests
+
+set test_list [lsort [glob -nocomplain $srcdir/$subdir/export-dynamic-symbol-*.d]]
+foreach test_file $test_list {
+    set test_name [file rootname $test_file]
+    verbose $test_name
+    run_dump_test $test_name
+}
+
+set ASFLAGS $old_ASFLAGS
+set LDFLAGS $old_LDFLAGS
diff --git a/ld/testsuite/ld-dynamic/export-dynamic-symbol.s b/ld/testsuite/ld-dynamic/export-dynamic-symbol.s
new file mode 100644
index 0000000000..c55da536c5
--- /dev/null
+++ b/ld/testsuite/ld-dynamic/export-dynamic-symbol.s
@@ -0,0 +1,17 @@ 
+	.text
+	.global start	/* Used by SH targets.  */
+start:
+	.global _start
+_start:
+	.global __start
+__start:
+	.global main	/* Used by HPPA targets.  */
+main:
+	.globl	_main	/* Used by LynxOS targets.  */
+_main:
+	.word 0
+
+	.section .text.1, "ax"
+	.global bar
+bar:
+	.word 0
diff --git a/ld/testsuite/ld-dynamic/foo-bar.list b/ld/testsuite/ld-dynamic/foo-bar.list
new file mode 100644
index 0000000000..87732e1de4
--- /dev/null
+++ b/ld/testsuite/ld-dynamic/foo-bar.list
@@ -0,0 +1 @@ 
+{ foo; bar; };
diff --git a/ld/testsuite/ld-dynamic/foo.list b/ld/testsuite/ld-dynamic/foo.list
new file mode 100644
index 0000000000..f89f569438
--- /dev/null
+++ b/ld/testsuite/ld-dynamic/foo.list
@@ -0,0 +1 @@ 
+{ foo; };
diff --git a/ld/testsuite/ld-dynamic/foo.s b/ld/testsuite/ld-dynamic/foo.s
new file mode 100644
index 0000000000..4a70181776
--- /dev/null
+++ b/ld/testsuite/ld-dynamic/foo.s
@@ -0,0 +1,4 @@ 
+	.text
+	.globl foo
+foo:
+	.byte 0
diff --git a/ld/testsuite/ld-dynamic/fstar.list b/ld/testsuite/ld-dynamic/fstar.list
new file mode 100644
index 0000000000..330d1dd2b8
--- /dev/null
+++ b/ld/testsuite/ld-dynamic/fstar.list
@@ -0,0 +1 @@ 
+{ f*; };
diff --git a/ld/testsuite/ld-elf/dlempty.list b/ld/testsuite/ld-elf/dlempty.list
new file mode 100644
index 0000000000..9b3884b10e
--- /dev/null
+++ b/ld/testsuite/ld-elf/dlempty.list
@@ -0,0 +1,3 @@ 
+{
+  empty;
+};
diff --git a/ld/testsuite/ld-elf/shared.exp b/ld/testsuite/ld-elf/shared.exp
index 7d35f3f379..5606c9937f 100644
--- a/ld/testsuite/ld-elf/shared.exp
+++ b/ld/testsuite/ld-elf/shared.exp
@@ -601,6 +601,27 @@  set build_tests {
   {"Build libdl2d.so with --dynamic-list-data -Bsymbolic"
    "-shared -Wl,-Bsymbolic,--dynamic-list-data" "-fPIC"
    {dl2.c dl2xxx.c} {} "libdl2d.so"}
+  {"Build libdl2e.so with --export-dynamic-symbol=foo"
+   "-shared -Wl,--export-dynamic-symbol=foo" "-fPIC"
+   {dl2.c dl2xxx.c} {} "libdl2e.so"}
+  {"Build libdl2f.so with --dynamic-list=dlempty.list and --export-dynamic-symbol=foo"
+   "-shared -Wl,--dynamic-list=dlempty.list,--export-dynamic-symbol=foo" "-fPIC"
+   {dl2.c dl2xxx.c} {} "libdl2f.so"}
+  {"Build libdl2g.so with --export-dynamic-symbol-list=dl2.list"
+   "-shared -Wl,--export-dynamic-symbol-list=dl2.list" "-fPIC"
+   {dl2.c dl2xxx.c} {} "libdl2g.so"}
+  {"Build libdl2h.so with --dynamic-list=dlempty.list and --export-dynamic-symbol-list=dl2.list"
+   "-shared -Wl,--dynamic-list=dlempty.list,--export-dynamic-symbol-list=dl2.list" "-fPIC"
+   {dl2.c dl2xxx.c} {} "libdl2h.so"}
+  {"Build libdl2i.so with -Bsymbolic and --export-dynamic-symbol=foo"
+   "-shared -Wl,-Bsymbolic,--export-dynamic-symbol=foo" "-fPIC"
+   {dl2.c dl2xxx.c} {} "libdl2i.so"}
+  {"Build libdl2j.so with -Bsymbolic and --export-dynamic-symbol-list=dl2.list"
+   "-shared -Wl,-Bsymbolic,--export-dynamic-symbol-list=dl2.list" "-fPIC"
+   {dl2.c dl2xxx.c} {} "libdl2j.so"}
+  {"Build libdl2k.so with --export-dynamic-symbol-list=dl2.list and -Bsymbolic"
+   "-shared -Wl,--export-dynamic-symbol-list=dl2.list,-Bsymbolic" "-fPIC"
+   {dl2.c dl2xxx.c} {} "libdl2k.so"}
   {"Build libdl4a.so with --dynamic-list=dl4.list"
    "-shared -Wl,--dynamic-list=dl4.list" "-fPIC"
    {dl4.c dl4xxx.c} {} "libdl4a.so"}
@@ -880,6 +901,27 @@  set run_tests [list \
     [list "Run with libdl2d.so" \
      "-Wl,--no-as-needed tmpdir/libdl2d.so" "" \
      {dl2main.c} "dl2d" "dl2a.out" ] \
+    [list "Run with libdl2e.so" \
+     "-Wl,--no-as-needed tmpdir/libdl2e.so" "" \
+     {dl2main.c} "dl2e" "dl2b.out" ] \
+    [list "Run with libdl2f.so" \
+     "-Wl,--no-as-needed tmpdir/libdl2f.so" "" \
+     {dl2main.c} "dl2f" "dl2a.out" ] \
+    [list "Run with libdl2g.so" \
+     "-Wl,--no-as-needed tmpdir/libdl2g.so" "" \
+     {dl2main.c} "dl2g" "dl2b.out" ] \
+    [list "Run with libdl2h.so" \
+     "-Wl,--no-as-needed tmpdir/libdl2h.so" "" \
+     {dl2main.c} "dl2h" "dl2a.out" ] \
+    [list "Run with libdl2i.so" \
+     "-Wl,--no-as-needed tmpdir/libdl2i.so" "" \
+     {dl2main.c} "dl2i" "dl2a.out" ] \
+    [list "Run with libdl2j.so" \
+     "-Wl,--no-as-needed tmpdir/libdl2j.so" "" \
+     {dl2main.c} "dl2j" "dl2a.out" ] \
+    [list "Run with libdl2k.so" \
+     "-Wl,--no-as-needed tmpdir/libdl2k.so" "" \
+     {dl2main.c} "dl2k" "dl2a.out" ] \
     [list "Run with libdl4a.so" \
      "-Wl,--no-as-needed tmpdir/libdl4a.so" "" \
      {dl4main.c} "dl4a" "dl4a.out" ] \
-- 
2.26.2