[PATCH] ld: Add --export-dynamic-symbol

Fangrui Song maskray@google.com
Mon May 4 17:48:51 GMT 2020


On 2020-05-03, H.J. Lu wrote:
>On Sat, May 2, 2020 at 11:15 PM Fangrui Song via Binutils
><binutils@sourceware.org> wrote:
>>
>>         PR ld/25910
>>         * ldlang.c (export_dynamic_symbol_list): New.
>>         (ldlang_add_export_dynamic_symbol): New.
>>         (lang_place_export_dynamic_symbols): New.
>>         (lang_process): Handle export_dynamic_symbol_list.
>>         * ldlang.h (ldlang_add_export_dynamic_symbol): New.
>>         * ldlex.h (option_values): Add OPTION_EXPORT_DYNAMIC_SYMBOL.
>>         * lexsup.c (ld_options): Add entry for OPTION_EXPORT_DYNAMIC_SYMBOL.
>>         (parse_args): Handle it.
>>         * ld.texi: Add --export-dynamic-symbol documentation.
>>         * testsuite/ld-undefined/export-dynamic-symbol.exp: Run new test.
>>         * testsuite/ld-undefined/export-dynamic-symbol-1.d: New.
>> ---
>>  ld/ld.texi                                    |  8 +++++
>>  ld/ldlang.c                                   | 26 ++++++++++++++
>>  ld/ldlang.h                                   |  2 ++
>>  ld/ldlex.h                                    |  1 +
>>  ld/lexsup.c                                   |  7 ++++
>>  .../ld-undefined/export-dynamic-symbol-1.d    |  8 +++++
>>  .../ld-undefined/export-dynamic-symbol.exp    | 35 +++++++++++++++++++
>>  7 files changed, 87 insertions(+)
>>  create mode 100644 ld/testsuite/ld-undefined/export-dynamic-symbol-1.d
>>  create mode 100644 ld/testsuite/ld-undefined/export-dynamic-symbol.exp
>>
>> diff --git a/ld/ld.texi b/ld/ld.texi
>> index 4dc78e65fa..b3dc95f314 100644
>> --- a/ld/ld.texi
>> +++ b/ld/ld.texi
>> @@ -569,6 +569,14 @@ 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{symbol}
>> +@cindex export dynamic symbol
>> +@item --export-dynamic-symbol=@var{symbol}
>> +Specify a symbol that should be added to the dynamic symbol table.
>> +Additionally, force @var{symbol} to be entered in the output file as an
>> +undefined symbol.  Doing this may, for example, trigger linking of additional
>> +modules from archives.
>> +
>>  @ifclear SingleFormat
>>  @cindex big-endian objects
>>  @cindex endianness
>> diff --git a/ld/ldlang.c b/ld/ldlang.c
>> index b2cdb3603a..e7ecdfeaf0 100644
>> --- a/ld/ldlang.c
>> +++ b/ld/ldlang.c
>> @@ -3910,6 +3910,26 @@ lang_place_undefineds (void)
>>      insert_undefined (ptr->name);
>>  }
>>
>> +static struct bfd_sym_chain export_dynamic_symbol_list = { NULL, NULL };
>> +
>> +void
>> +ldlang_add_export_dynamic_symbol (const char *const name)
>> +{
>> +  struct bfd_sym_chain *sym;
>> +  sym = stat_alloc (sizeof (*sym));
>> +  sym->name = xstrdup (name);
>> +  sym->next = export_dynamic_symbol_list.next;
>> +  export_dynamic_symbol_list.next = sym;
>> +}
>> +
>> +static void
>> +lang_place_export_dynamic_symbols (void)
>> +{
>> +  struct bfd_sym_chain *sym;
>> +  for (sym = export_dynamic_symbol_list.next; sym != NULL; sym = sym->next)
>> +    insert_undefined (sym->name);
>> +}
>> +
>>  /* Structure used to build the list of symbols that the user has required
>>     be defined.  */
>>
>> @@ -7795,6 +7815,10 @@ void
>>  lang_process (void)
>>  {
>>    /* Finalize dynamic list.  */
>> +  struct bfd_sym_chain *sym;
>> +  for (sym = export_dynamic_symbol_list.next; sym != NULL; sym = sym->next)
>> +    lang_append_dynamic_list (
>> +        lang_new_vers_pattern (NULL, sym->name, NULL, FALSE));
>>    if (link_info.dynamic_list)
>>      lang_finalize_version_expr_head (&link_info.dynamic_list->head);
>>
>> @@ -7808,6 +7832,8 @@ lang_process (void)
>>
>>    /* Add to the hash table all undefineds on the command line.  */
>>    lang_place_undefineds ();
>> +  /* Add --export-dynamic-symbol symbols to the hash table.  */
>> +  lang_place_export_dynamic_symbols ();
>>
>>    if (!bfd_section_already_linked_table_init ())
>>      einfo (_("%F%P: can not create hash table: %E\n"));
>> diff --git a/ld/ldlang.h b/ld/ldlang.h
>> index 2aa3930f95..8c004b173c 100644
>> --- a/ld/ldlang.h
>> +++ b/ld/ldlang.h
>> @@ -606,6 +606,8 @@ extern lang_output_section_statement_type *next_matching_output_section_statemen
>>    (lang_output_section_statement_type *, int);
>>  extern void ldlang_add_undef
>>    (const char *const, bfd_boolean);
>> +extern void ldlang_add_export_dynamic_symbol
>> +  (const char *const);
>>  extern void ldlang_add_require_defined
>>    (const char *const);
>>  extern void lang_add_output_format
>> diff --git a/ld/ldlex.h b/ld/ldlex.h
>> index 22b928d2d9..70f2da5636 100644
>> --- a/ld/ldlex.h
>> +++ b/ld/ldlex.h
>> @@ -81,6 +81,7 @@ enum option_values
>>    OPTION_DYNAMIC_LIST_CPP_NEW,
>>    OPTION_DYNAMIC_LIST_CPP_TYPEINFO,
>>    OPTION_DYNAMIC_LIST_DATA,
>> +  OPTION_EXPORT_DYNAMIC_SYMBOL,
>>    OPTION_WARN_COMMON,
>>    OPTION_WARN_CONSTRUCTORS,
>>    OPTION_WARN_FATAL,
>> diff --git a/ld/lexsup.c b/ld/lexsup.c
>> index d1955b9afa..0a0c2f2873 100644
>> --- a/ld/lexsup.c
>> +++ b/ld/lexsup.c
>> @@ -504,6 +504,8 @@ 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_("Read dynamic list"), 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},
>> @@ -1425,6 +1427,11 @@ parse_args (unsigned argc, char **argv)
>>           if (opt_symbolic == symbolic)
>>             opt_symbolic = symbolic_unset;
>>           break;
>> +       case OPTION_EXPORT_DYNAMIC_SYMBOL:
>> +         ldlang_add_export_dynamic_symbol (optarg);
>> +         if (opt_dynamic_list != dynamic_list_data)
>> +           opt_dynamic_list = dynamic_list;
>> +         break;
>>         case OPTION_WARN_COMMON:
>>           config.warn_common = TRUE;
>>           break;
>> diff --git a/ld/testsuite/ld-undefined/export-dynamic-symbol-1.d b/ld/testsuite/ld-undefined/export-dynamic-symbol-1.d
>> new file mode 100644
>> index 0000000000..768bf0abd6
>> --- /dev/null
>> +++ b/ld/testsuite/ld-undefined/export-dynamic-symbol-1.d
>> @@ -0,0 +1,8 @@
>> +#name: --export-dynamic-symbol foo archive
>> +#source: require-defined.s
>> +#ld: -pie --export-dynamic-symbol foo tmpdir/libentry.a
>
>I assume that it supports
>
>$ ld -pie --export-dynamic-symbol foo --export-dynamic-symbol bar ...
>
>Please add another --export-dynamic-symbol to your test.
>
>-- 
>H.J.

I face a test difficulty. If I add another `#nm:`, runtest complains:

% cd Debug/ld
% runtest --tool ld --srcdir ../../ld/testsuite/ export-dynamic-symbol.exp
...
ERROR: option nm multiply set in ../../ld/testsuite/ld-undefined/export-dynamic-symbol-1.d

There may also be a problem of symbol table order determinism. I don't
know whether another symbol may be ordered before foo in some ports and
after foo in other ports.

Honestly, I think for a number of tests, even if they test generic
behavior, it might be fine to restrict them to run on certain hosts,
e.g. Linux x86. What I know about testing is lacking, though, I don't
know what can be tested.

Ideally `#nm:` should just be free-form shell scripts but unfortunately
it seems to support very limited features (undocumented?)


More information about the Binutils mailing list