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

Message ID CAMe9rOpVi_wEXw+fwzUEjO4xWX-AT9TrxQX-c_gx3ypsA-4msg@mail.gmail.com
State Superseded
Headers show
Series
  • V4 [PATCH] ld: Add --export-dynamic-symbol and --export-dynamic-symbol-list
Related show

Commit Message

On Sat, May 23, 2020 at 2:56 PM Fangrui Song <maskray@google.com> wrote:
>

> On 2020-05-23, H.J. Lu wrote:

> >On Sat, May 23, 2020 at 11:29 AM Fangrui Song <maskray@google.com> wrote:

> >>

> >> On 2020-05-23, H.J. Lu wrote:

> >> >From: Fangrui Song <maskray@google.com>

> >> >

> >> >--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                                   | 75 +++++++++++++++++++

> >> > .../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      | 39 ++++++++++

> >> > .../ld-dynamic/export-dynamic-symbol.s        |  9 +++

> >> > 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                | 36 +++++++++

> >> > 21 files changed, 258 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 9f5bbe51cf..870c480bde 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 command-line options --enable-non-contiguous-regions and

> >> >   --enable-non-contiguous-regions-warnings.

> >> >

> >> >diff --git a/ld/ld.texi b/ld/ld.texi

> >> >index 4dc78e65fa..92e47c6324 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.

> >>

> >> Is --export-dynamic-symbol still effective for -shared?

> >> I think either way is ok.

> >

> >Yes.

> >

> >> >+@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 22b928d2d9..2c8d043a09 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 fe9526b527..2bac1631d6 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},

> >> >@@ -581,6 +585,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 *)

> >> >@@ -1418,6 +1423,7 @@ 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)

> >> >@@ -1425,6 +1431,29 @@ parse_args (unsigned argc, char **argv)

> >> >         if (opt_symbolic == symbolic)

> >> >           opt_symbolic = symbolic_unset;

> >> >         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;

> >> >@@ -1632,6 +1661,52 @@ parse_args (unsigned argc, char **argv)

> >> >       && command_line.check_section_addresses < 0)

> >> >     command_line.check_section_addresses = 0;

> >> >

> >> >+  if (export_list && !bfd_link_relocatable (&link_info))

> >> >+    {

> >> >+      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.

> >> >+       */

> >> >+      bfd_boolean kept = (bfd_link_executable (&link_info)

> >> >+                        || opt_symbolic != symbolic_unset

> >> >+                        || opt_dynamic_list != dynamic_list_unset);

> >> >+

> >> >+      if (kept)

> >> >+      {

> >> >+        /* 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;

> >> >+        if (opt_symbolic == symbolic)

> >> >+          opt_symbolic = symbolic_unset;

> >>

> >> The interaction with -Bsymbolic appears to be more complex now.

> >> I think users will pretty much avoid the combination of -Bsymbolic and

> >> (--dynamic-list or --export-dynamic-symbol or --export-dynamic-symbol-list).

> >>

> >> So I beg for a re-consideration of

> >> https://sourceware.org/bugzilla/show_bug.cgi?id=26018

> >> https://sourceware.org/pipermail/binutils/2020-May/111223.html

> >>

> >

> >Here is the updated patch on top of

> >

> >https://sourceware.org/pipermail/binutils/2020-May/111228.html

>

> Thanks for PATCH v3. LGTM.

>

> I have verified the semantics of new tests dl2d ~ dl2k.


The updated patch to adjust ld-dynamic/export-dynamic-symbol.s
for all ELF targets:


-- 
H.J.

Comments

On 2020-05-27, H.J. Lu wrote:
>On Sat, May 23, 2020 at 2:56 PM Fangrui Song <maskray@google.com> wrote:

>>

>> On 2020-05-23, H.J. Lu wrote:

>> >On Sat, May 23, 2020 at 11:29 AM Fangrui Song <maskray@google.com> wrote:

>> >>

>> >> On 2020-05-23, H.J. Lu wrote:

>> >> >From: Fangrui Song <maskray@google.com>

>> >> >

>> >> >--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                                   | 75 +++++++++++++++++++

>> >> > .../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      | 39 ++++++++++

>> >> > .../ld-dynamic/export-dynamic-symbol.s        |  9 +++

>> >> > 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                | 36 +++++++++

>> >> > 21 files changed, 258 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 9f5bbe51cf..870c480bde 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 command-line options --enable-non-contiguous-regions and

>> >> >   --enable-non-contiguous-regions-warnings.

>> >> >

>> >> >diff --git a/ld/ld.texi b/ld/ld.texi

>> >> >index 4dc78e65fa..92e47c6324 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.

>> >>

>> >> Is --export-dynamic-symbol still effective for -shared?

>> >> I think either way is ok.

>> >

>> >Yes.

>> >

>> >> >+@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 22b928d2d9..2c8d043a09 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 fe9526b527..2bac1631d6 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},

>> >> >@@ -581,6 +585,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 *)

>> >> >@@ -1418,6 +1423,7 @@ 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)

>> >> >@@ -1425,6 +1431,29 @@ parse_args (unsigned argc, char **argv)

>> >> >         if (opt_symbolic == symbolic)

>> >> >           opt_symbolic = symbolic_unset;

>> >> >         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;

>> >> >@@ -1632,6 +1661,52 @@ parse_args (unsigned argc, char **argv)

>> >> >       && command_line.check_section_addresses < 0)

>> >> >     command_line.check_section_addresses = 0;

>> >> >

>> >> >+  if (export_list && !bfd_link_relocatable (&link_info))

>> >> >+    {

>> >> >+      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.

>> >> >+       */

>> >> >+      bfd_boolean kept = (bfd_link_executable (&link_info)

>> >> >+                        || opt_symbolic != symbolic_unset

>> >> >+                        || opt_dynamic_list != dynamic_list_unset);

>> >> >+

>> >> >+      if (kept)

>> >> >+      {

>> >> >+        /* 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;

>> >> >+        if (opt_symbolic == symbolic)

>> >> >+          opt_symbolic = symbolic_unset;

>> >>

>> >> The interaction with -Bsymbolic appears to be more complex now.

>> >> I think users will pretty much avoid the combination of -Bsymbolic and

>> >> (--dynamic-list or --export-dynamic-symbol or --export-dynamic-symbol-list).

>> >>

>> >> So I beg for a re-consideration of

>> >> https://sourceware.org/bugzilla/show_bug.cgi?id=26018

>> >> https://sourceware.org/pipermail/binutils/2020-May/111223.html

>> >>

>> >

>> >Here is the updated patch on top of

>> >

>> >https://sourceware.org/pipermail/binutils/2020-May/111228.html

>>

>> Thanks for PATCH v3. LGTM.

>>

>> I have verified the semantics of new tests dl2d ~ dl2k.

>

>The updated patch to adjust ld-dynamic/export-dynamic-symbol.s

>for all ELF targets:

>

>diff --git a/ld/testsuite/ld-dynamic/export-dynamic-symbol.s

>b/ld/testsuite/ld-dynamic/export-dynamic-symbol.s

>index 4b1b8ebd5c..c55da536c5 100644

>--- a/ld/testsuite/ld-dynamic/export-dynamic-symbol.s

>+++ b/ld/testsuite/ld-dynamic/export-dynamic-symbol.s

>@@ -1,6 +1,14 @@

>   .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"

>

>-- 

>H.J.


Still looks good.
On Wed, May 27, 2020 at 9:19 AM Fangrui Song <maskray@google.com> wrote:
>

> On 2020-05-27, H.J. Lu wrote:

> >On Sat, May 23, 2020 at 2:56 PM Fangrui Song <maskray@google.com> wrote:

> >>

> >> On 2020-05-23, H.J. Lu wrote:

> >> >On Sat, May 23, 2020 at 11:29 AM Fangrui Song <maskray@google.com> wrote:

> >> >>

> >> >> On 2020-05-23, H.J. Lu wrote:

> >> >> >From: Fangrui Song <maskray@google.com>

> >> >> >

> >> >> >--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                                   | 75 +++++++++++++++++++

> >> >> > .../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      | 39 ++++++++++

> >> >> > .../ld-dynamic/export-dynamic-symbol.s        |  9 +++

> >> >> > 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                | 36 +++++++++

> >> >> > 21 files changed, 258 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 9f5bbe51cf..870c480bde 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 command-line options --enable-non-contiguous-regions and

> >> >> >   --enable-non-contiguous-regions-warnings.

> >> >> >

> >> >> >diff --git a/ld/ld.texi b/ld/ld.texi

> >> >> >index 4dc78e65fa..92e47c6324 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.

> >> >>

> >> >> Is --export-dynamic-symbol still effective for -shared?

> >> >> I think either way is ok.

> >> >

> >> >Yes.

> >> >

> >> >> >+@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 22b928d2d9..2c8d043a09 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 fe9526b527..2bac1631d6 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},

> >> >> >@@ -581,6 +585,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 *)

> >> >> >@@ -1418,6 +1423,7 @@ 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)

> >> >> >@@ -1425,6 +1431,29 @@ parse_args (unsigned argc, char **argv)

> >> >> >         if (opt_symbolic == symbolic)

> >> >> >           opt_symbolic = symbolic_unset;

> >> >> >         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;

> >> >> >@@ -1632,6 +1661,52 @@ parse_args (unsigned argc, char **argv)

> >> >> >       && command_line.check_section_addresses < 0)

> >> >> >     command_line.check_section_addresses = 0;

> >> >> >

> >> >> >+  if (export_list && !bfd_link_relocatable (&link_info))

> >> >> >+    {

> >> >> >+      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.

> >> >> >+       */

> >> >> >+      bfd_boolean kept = (bfd_link_executable (&link_info)

> >> >> >+                        || opt_symbolic != symbolic_unset

> >> >> >+                        || opt_dynamic_list != dynamic_list_unset);

> >> >> >+

> >> >> >+      if (kept)

> >> >> >+      {

> >> >> >+        /* 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;

> >> >> >+        if (opt_symbolic == symbolic)

> >> >> >+          opt_symbolic = symbolic_unset;

> >> >>

> >> >> The interaction with -Bsymbolic appears to be more complex now.

> >> >> I think users will pretty much avoid the combination of -Bsymbolic and

> >> >> (--dynamic-list or --export-dynamic-symbol or --export-dynamic-symbol-list).

> >> >>

> >> >> So I beg for a re-consideration of

> >> >> https://sourceware.org/bugzilla/show_bug.cgi?id=26018

> >> >> https://sourceware.org/pipermail/binutils/2020-May/111223.html

> >> >>

> >> >

> >> >Here is the updated patch on top of

> >> >

> >> >https://sourceware.org/pipermail/binutils/2020-May/111228.html

> >>

> >> Thanks for PATCH v3. LGTM.

> >>

> >> I have verified the semantics of new tests dl2d ~ dl2k.

> >

> >The updated patch to adjust ld-dynamic/export-dynamic-symbol.s

> >for all ELF targets:

> >

> >diff --git a/ld/testsuite/ld-dynamic/export-dynamic-symbol.s

> >b/ld/testsuite/ld-dynamic/export-dynamic-symbol.s

> >index 4b1b8ebd5c..c55da536c5 100644

> >--- a/ld/testsuite/ld-dynamic/export-dynamic-symbol.s

> >+++ b/ld/testsuite/ld-dynamic/export-dynamic-symbol.s

> >@@ -1,6 +1,14 @@

> >   .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"

> >

> >--

> >H.J.

>

> Still looks good.


More changes are needed:
diff --git a/ld/testsuite/ld-dynamic/export-dynamic-symbol.exp
b/ld/testsuite/ld-dynamic/export-dynamic-symbol.exp
index d0b4bc4eb0..c879a5f65f 100644
--- a/ld/testsuite/ld-dynamic/export-dynamic-symbol.exp
+++ b/ld/testsuite/ld-dynamic/export-dynamic-symbol.exp
@@ -23,6 +23,26 @@ 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 build_tests {
   {"Build libfoo.a"
    "" "" ""
@@ -37,3 +57,5 @@ foreach test_file $test_list {
     verbose $test_name
     run_dump_test $test_name
 }
+
+set ASFLAGS $old_ASFLAGS

-- 
H.J.

Patch

From 204662941af859a203a84c201a2445f73d71d2a2 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      | 39 ++++++++++
 .../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, 269 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 0aaa13d487..01f653533b 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 command-line option for ELF linker, --warn-textrel, to warn that
   DT_TEXTREL is set in a position-independent executable or shared object.
 
diff --git a/ld/ld.texi b/ld/ld.texi
index a7ec0d01b3..843975dc97 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 3733a7c893..98f244bee1 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},
@@ -583,6 +587,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 *)
@@ -1414,11 +1419,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;
@@ -1626,6 +1655,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..c1dd4e2f55
--- /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/libfoo.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..7ec4eed3ed
--- /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/libfoo.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..05a6e15b3b
--- /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/libfoo.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..aa1b8839e6
--- /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/libfoo.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..367a07c1bb
--- /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/libfoo.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..f0e3427306
--- /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/libfoo.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..d0b4bc4eb0
--- /dev/null
+++ b/ld/testsuite/ld-dynamic/export-dynamic-symbol.exp
@@ -0,0 +1,39 @@ 
+# 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
+}
+
+set build_tests {
+  {"Build libfoo.a"
+   "" "" ""
+   {foo.s} {} "libfoo.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
+}
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