diff options
author | Fangrui Song <maskray@google.com> | 2020-06-03 06:37:39 -0700 |
---|---|---|
committer | H.J. Lu <hjl.tools@gmail.com> | 2020-06-03 06:37:39 -0700 |
commit | 37a141bfed4dd3c33d77c15dfde00e4b4f5b24c7 (patch) | |
tree | 05fc3a047c219a7e59357a758472a566e926a570 /ld/lexsup.c | |
parent | 433953ffa1a59531a5537327a4e3ce24565e609c (diff) | |
download | binutils-gdb-37a141bfed4dd3c33d77c15dfde00e4b4f5b24c7.tar.gz |
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.
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.
Diffstat (limited to 'ld/lexsup.c')
-rw-r--r-- | ld/lexsup.c | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/ld/lexsup.c b/ld/lexsup.c index 412e2e60267..4808f7443d1 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: |