diff options
-rw-r--r-- | gold/ChangeLog | 32 | ||||
-rw-r--r-- | gold/options.cc | 8 | ||||
-rw-r--r-- | gold/options.h | 21 | ||||
-rw-r--r-- | gold/script.cc | 59 | ||||
-rw-r--r-- | gold/script.h | 10 | ||||
-rw-r--r-- | gold/symtab.cc | 46 | ||||
-rw-r--r-- | gold/testsuite/Makefile.am | 15 | ||||
-rw-r--r-- | gold/testsuite/Makefile.in | 23 | ||||
-rwxr-xr-x | gold/testsuite/dynamic_list.sh | 50 | ||||
-rw-r--r-- | gold/testsuite/dynamic_list.t | 11 | ||||
-rw-r--r-- | gold/yyscript.y | 20 |
11 files changed, 277 insertions, 18 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog index 2850454..41c6162 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,5 +1,37 @@ 2008-11-05 Craig Silverstein <csilvers@google.com> + * options.cc (General_options::parse_dynamic_list): New function. + * options.h (General_options): New flags dynamic_list, + dynamic_list_data, dynamic_list_cpp_new, and + dynamic_list_cpp_typeinfo. New variable dynamic_list_. + (General_options::in_dynamic_list): New function. + * script.cc (Lex::Mode): New enum DYNAMIC_LIST. + (Lex::can_start_name): Add support for DYNAMIC_LIST mode. + (Lex::can_continue_name): Likewise. + (yylex): Likewise. + (read_script_file): New parameter script_options. + (read_dynamic_list): New function. + (Script_options::define_dynamic_list): New function. + (dynamic_list_keyword_parsecodes): New variable. + (dynamic_list_keywords): New variable. + * script.h (Script_options::define_dynamic_list): New function + prototype. + (read_dynamic_list): New function prototype. + * symtab.cc (strprefix): New macro. + (Symbol::should_add_dynsym_entry): Support dynamic_list, + dynamic_list_data, dynamic_list_cpp_new, and + dynamic_list_cpp_typeinfo. + * yyscript.y (PARSING_DYNAMIC_LIST): New token. + (dynamic_list_expr): New rule. + (dynamic_list_nodes): Likewise. + (dynamic_list_node): Likewise. + * testsuite/Makefile.am (dynamic_list): New test. + * testsuite/Makefile.in: Regenerated. + * testsuite/dynamic_list.t: New file. + * testsuite/dynamic_list.sh: New file. + +2008-11-05 Craig Silverstein <csilvers@google.com> + * testsuite/tls_test_c.c: Add prototype for t11 and t11_last. * testsuite/tls_test_c.c (t11): Add explicit "void" to prototype. (t11_last): Likewise. diff --git a/gold/options.cc b/gold/options.cc index 069c138..90fa163 100644 --- a/gold/options.cc +++ b/gold/options.cc @@ -348,6 +348,14 @@ General_options::parse_version_script(const char*, const char* arg, } void +General_options::parse_dynamic_list(const char*, const char* arg, + Command_line* cmdline) +{ + if (!read_dynamic_list(arg, cmdline, &this->dynamic_list_)) + gold::gold_fatal(_("unable to parse dynamic-list script file %s"), arg); +} + +void General_options::parse_start_group(const char*, const char*, Command_line* cmdline) { diff --git a/gold/options.h b/gold/options.h index 167e58a..be08d99 100644 --- a/gold/options.h +++ b/gold/options.h @@ -620,6 +620,18 @@ class General_options N_("Try to detect violations of the One Definition Rule"), NULL); + DEFINE_bool(dynamic_list_data, options::TWO_DASHES, '\0', false, + N_("Add data symbols to dynamic symbols"), NULL); + + DEFINE_bool(dynamic_list_cpp_new, options::TWO_DASHES, '\0', false, + N_("Add C++ operator new/delete to dynamic symbols"), NULL); + + DEFINE_bool(dynamic_list_cpp_typeinfo, options::TWO_DASHES, '\0', false, + N_("Add C++ typeinfo to dynamic symbols"), NULL); + + DEFINE_special(dynamic_list, options::TWO_DASHES, '\0', + N_("Read a list of dynamic symbols"), N_("FILE")); + DEFINE_string(entry, options::TWO_DASHES, 'e', NULL, N_("Set program start address"), N_("ADDRESS")); @@ -933,6 +945,11 @@ class General_options plugins() const { return this->plugins_; } + // True iff SYMBOL was found in the file specified by dynamic-list. + bool + in_dynamic_list(const char* symbol) const + { return this->dynamic_list_.version_script_info()->symbol_is_local(symbol); } + private: // Don't copy this structure. General_options(const General_options&); @@ -982,6 +999,10 @@ class General_options bool do_demangle_; // List of plugin libraries. Plugin_manager* plugins_; + // The parsed output of --dynamic-list files. For convenience in + // script.cc, we store this as a Script_options object, even though + // we only use a single Version_tree from it. + Script_options dynamic_list_; }; // The position-dependent options. We use this to store the state of diff --git a/gold/script.cc b/gold/script.cc index 53fcf66..9deb726 100644 --- a/gold/script.cc +++ b/gold/script.cc @@ -184,7 +184,9 @@ class Lex // Reading an expression in a linker script. EXPRESSION, // Reading a version script. - VERSION_SCRIPT + VERSION_SCRIPT, + // Reading a --dynamic-list file. + DYNAMIC_LIST }; Lex(const char* input_string, size_t input_length, int parsing_token) @@ -393,8 +395,9 @@ Lex::can_start_name(char c, char c2) case '~': return this->mode_ == LINKER_SCRIPT && can_continue_name(&c2); - case '*': case '[': + case '*': case '[': return (this->mode_ == VERSION_SCRIPT + || this->mode_ == DYNAMIC_LIST || (this->mode_ == LINKER_SCRIPT && can_continue_name(&c2))); @@ -429,6 +432,7 @@ Lex::can_continue_name(const char* c) case '5': case '6': case '7': case '8': case '9': return c + 1; + // TODO(csilvers): why not allow ~ in names for version-scripts? case '/': case '\\': case '~': case '=': case '+': case ',': @@ -437,19 +441,22 @@ Lex::can_continue_name(const char* c) return NULL; case '[': case ']': case '*': case '?': case '-': - if (this->mode_ == LINKER_SCRIPT || this->mode_ == VERSION_SCRIPT) + if (this->mode_ == LINKER_SCRIPT || this->mode_ == VERSION_SCRIPT + || this->mode_ == DYNAMIC_LIST) return c + 1; return NULL; + // TODO(csilvers): why allow this? ^ is meaningless in version scripts. case '^': - if (this->mode_ == VERSION_SCRIPT) + if (this->mode_ == VERSION_SCRIPT || this->mode_ == DYNAMIC_LIST) return c + 1; return NULL; case ':': if (this->mode_ == LINKER_SCRIPT) return c + 1; - else if (this->mode_ == VERSION_SCRIPT && (c[1] == ':')) + else if ((this->mode_ == VERSION_SCRIPT || this->mode_ == DYNAMIC_LIST) + && (c[1] == ':')) { // A name can have '::' in it, as that's a c++ namespace // separator. But a single colon is not part of a name. @@ -1161,7 +1168,7 @@ class Parser_closure command_line_(command_line), script_options_(script_options), version_script_info_(script_options->version_script_info()), lex_(lex), lineno_(0), charpos_(0), lex_mode_stack_(), inputs_(NULL) - { + { // We start out processing C symbols in the default lex mode. language_stack_.push_back(""); lex_mode_stack_.push_back(lex->mode()); @@ -1373,6 +1380,7 @@ read_input_script(Workqueue* workqueue, const General_options& options, static bool read_script_file(const char* filename, Command_line* cmdline, + Script_options* script_options, int first_token, Lex::Mode lex_mode) { // TODO: if filename is a relative filename, search for it manually @@ -1404,7 +1412,7 @@ read_script_file(const char* filename, Command_line* cmdline, false, input_file.is_in_sysroot(), cmdline, - &cmdline->script_options(), + script_options, &lex); if (yyparse(&closure) != 0) { @@ -1425,21 +1433,32 @@ read_script_file(const char* filename, Command_line* cmdline, bool read_commandline_script(const char* filename, Command_line* cmdline) { - return read_script_file(filename, cmdline, + return read_script_file(filename, cmdline, &cmdline->script_options(), PARSING_LINKER_SCRIPT, Lex::LINKER_SCRIPT); } -// FILE was found as an argument to --version-script. Read it as a -// version script, and store its contents in +// FILENAME was found as an argument to --version-script. Read it as +// a version script, and store its contents in // cmdline->script_options()->version_script_info(). bool read_version_script(const char* filename, Command_line* cmdline) { - return read_script_file(filename, cmdline, + return read_script_file(filename, cmdline, &cmdline->script_options(), PARSING_VERSION_SCRIPT, Lex::VERSION_SCRIPT); } +// FILENAME was found as an argument to --dynamic-list. Read it as a +// list of symbols, and store its contents in DYNAMIC_LIST. + +bool +read_dynamic_list(const char* filename, Command_line* cmdline, + Script_options* dynamic_list) +{ + return read_script_file(filename, cmdline, dynamic_list, + PARSING_DYNAMIC_LIST, Lex::DYNAMIC_LIST); +} + // Implement the --defsym option on the command line. Return true if // all is well. @@ -1622,6 +1641,19 @@ version_script_keywords(&version_script_keyword_parsecodes[0], (sizeof(version_script_keyword_parsecodes) / sizeof(version_script_keyword_parsecodes[0]))); +static const Keyword_to_parsecode::Keyword_parsecode +dynamic_list_keyword_parsecodes[] = +{ + { "extern", EXTERN }, +}; + +static const Keyword_to_parsecode +dynamic_list_keywords(&dynamic_list_keyword_parsecodes[0], + (sizeof(dynamic_list_keyword_parsecodes) + / sizeof(dynamic_list_keyword_parsecodes[0]))); + + + // Comparison function passed to bsearch. extern "C" @@ -1963,6 +1995,9 @@ yylex(YYSTYPE* lvalp, void* closurev) case Lex::VERSION_SCRIPT: parsecode = version_script_keywords.keyword_to_parsecode(str, len); break; + case Lex::DYNAMIC_LIST: + parsecode = dynamic_list_keywords.keyword_to_parsecode(str, len); + break; default: break; } @@ -2339,7 +2374,7 @@ script_start_output_section(void* closurev, const char* name, size_t namelen, // Finish processing entries for an output section. extern "C" void -script_finish_output_section(void* closurev, +script_finish_output_section(void* closurev, const struct Parser_output_section_trailer* trail) { Parser_closure* closure = static_cast<Parser_closure*>(closurev); diff --git a/gold/script.h b/gold/script.h index 3397bf0..6d65989 100644 --- a/gold/script.h +++ b/gold/script.h @@ -398,7 +398,7 @@ read_input_script(Workqueue*, const General_options&, Symbol_table*, Layout*, // Read it as a script, and execute its contents immediately. bool -read_commandline_script(const char* filename, Command_line*); +read_commandline_script(const char* filename, Command_line* cmdline); // FILE was found as an argument to --version-script. Read it as a // version script, and store its contents in @@ -407,6 +407,14 @@ read_commandline_script(const char* filename, Command_line*); bool read_version_script(const char* filename, Command_line* cmdline); +// FILENAME was found as an argument to --dynamic-list. Read it as a +// version script (actually, a versym_node from a version script), and +// store its contents in DYNAMIC_LIST. + +bool +read_dynamic_list(const char* filename, Command_line* cmdline, + Script_options* dynamic_list); + } // End namespace gold. #endif // !defined(GOLD_SCRIPT_H) diff --git a/gold/symtab.cc b/gold/symtab.cc index c2de3bc..90ddfae 100644 --- a/gold/symtab.cc +++ b/gold/symtab.cc @@ -37,6 +37,7 @@ #include "target.h" #include "workqueue.h" #include "symtab.h" +#include "demangle.h" // needed for --dynamic-list-cpp-new #include "plugin.h" namespace gold @@ -288,6 +289,9 @@ Sized_symbol<size>::allocate_common(Output_data* od, Value_type value) this->value_ = value; } +// The ""'s around str ensure str is a string literal, so sizeof works. +#define strprefix(var, str) (strncmp(var, str, sizeof("" str "") - 1) == 0) + // Return true if this symbol should be added to the dynamic symbol // table. @@ -302,6 +306,48 @@ Symbol::should_add_dynsym_entry() const if (this->is_forced_local()) return false; + // If the symbol was forced dynamic in a --dynamic-list file, add it. + if (parameters->options().in_dynamic_list(this->name())) + return true; + + // If dynamic-list-data was specified, add any STT_OBJECT. + if (parameters->options().dynamic_list_data() + && !this->is_from_dynobj() + && this->type() == elfcpp::STT_OBJECT) + return true; + + // If --dynamic-list-cpp-new was specified, add any new/delete symbol. + // If --dynamic-list-cpp-typeinfo was specified, add any typeinfo symbols. + if ((parameters->options().dynamic_list_cpp_new() + || parameters->options().dynamic_list_cpp_typeinfo()) + && !this->is_from_dynobj()) + { + // TODO(csilvers): We could probably figure out if we're an operator + // new/delete or typeinfo without the need to demangle. + char* demangled_name = cplus_demangle(this->name(), + DMGL_ANSI | DMGL_PARAMS); + if (demangled_name == NULL) + { + // Not a C++ symbol, so it can't satisfy these flags + } + else if (parameters->options().dynamic_list_cpp_new() + && (strprefix(demangled_name, "operator new") + || strprefix(demangled_name, "operator delete"))) + { + free(demangled_name); + return true; + } + else if (parameters->options().dynamic_list_cpp_typeinfo() + && (strprefix(demangled_name, "typeinfo name for") + || strprefix(demangled_name, "typeinfo for"))) + { + free(demangled_name); + return true; + } + else + free(demangled_name); + } + // If exporting all symbols or building a shared library, // and the symbol is defined in a regular object and is // externally visible, we need to add it. diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am index 57d96cd..dcb8bad 100644 --- a/gold/testsuite/Makefile.am +++ b/gold/testsuite/Makefile.am @@ -903,6 +903,21 @@ script_test_4: basic_test.o gcctestdir/ld $(srcdir)/script_test_4.t script_test_4.stdout: script_test_4 $(TEST_READELF) -SlW script_test_4 > script_test_4.stdout +# Test --dynamic-list, --dynamic-list-data, --dynamic-list-cpp-new, +# and --dynamic-list-cpp-typeinfo + +check_SCRIPTS += dynamic_list.sh +check_DATA += dynamic_list.stdout +MOSTLYCLEANFILES += dynamic_list.stdout +dynamic_list: basic_test.o gcctestdir/ld $(srcdir)/dynamic_list.t + $(CXXLINK) -Bgcctestdir/ basic_test.o \ + -Wl,--dynamic-list $(srcdir)/dynamic_list.t \ + -Wl,--dynamic-list-data \ + -Wl,--dynamic-list-cpp-new \ + -Wl,--dynamic-list-cpp-typeinfo +dynamic_list.stdout: dynamic_list + $(TEST_READELF) -DWs dynamic_list > dynamic_list.stdout + check_PROGRAMS += thin_archive_test_1 thin_archive_test_1_SOURCES = thin_archive_main.cc thin_archive_test_1_DEPENDENCIES = gcctestdir/ld libthin1.a alt/libthin2.a diff --git a/gold/testsuite/Makefile.in b/gold/testsuite/Makefile.in index 54b2364..7271bb0 100644 --- a/gold/testsuite/Makefile.in +++ b/gold/testsuite/Makefile.in @@ -162,13 +162,16 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \ # Test --detect-odr-violations # Similar to --detect-odr-violations: check for undefined symbols in .so's + +# Test --dynamic-list, --dynamic-list-data, --dynamic-list-cpp-new, +# and --dynamic-list-cpp-typeinfo @GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_6 = weak_plt.sh debug_msg.sh \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ undef_symbol.sh ver_test_2.sh \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_4.sh ver_test_5.sh \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_7.sh ver_test_10.sh \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_matching_test.sh \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_3.sh \ -@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_4.sh +@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_4.sh dynamic_list.sh # Create the data files that debug_msg.sh analyzes. @@ -184,7 +187,8 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_7.syms ver_test_10.syms \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_matching_test.stdout \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_3.stdout \ -@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_4.stdout +@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_4.stdout \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ dynamic_list.stdout @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@am__append_8 = tls_test \ @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ tls_pic_test \ @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ tls_shared_test \ @@ -229,7 +233,8 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ undef_symbol.err \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_matching_test.stdout \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_3.stdout \ -@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_4.stdout +@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_4.stdout \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ dynamic_list.stdout # Test -o when emitting to a special file (such as something in /dev). @GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_17 = flagstest_o_specialfile @@ -1458,9 +1463,9 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi exit 1;; \ esac; \ done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign testsuite/Makefile'; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu testsuite/Makefile'; \ cd $(top_srcdir) && \ - $(AUTOMAKE) --foreign testsuite/Makefile + $(AUTOMAKE) --gnu testsuite/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ @@ -2418,6 +2423,14 @@ uninstall-am: uninstall-info-am @GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ basic_test.o -T $(srcdir)/script_test_4.t @GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_4.stdout: script_test_4 @GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -SlW script_test_4 > script_test_4.stdout +@GCC_TRUE@@NATIVE_LINKER_TRUE@dynamic_list: basic_test.o gcctestdir/ld $(srcdir)/dynamic_list.t +@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ basic_test.o \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ -Wl,--dynamic-list $(srcdir)/dynamic_list.t \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ -Wl,--dynamic-list-data \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ -Wl,--dynamic-list-cpp-new \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ -Wl,--dynamic-list-cpp-typeinfo +@GCC_TRUE@@NATIVE_LINKER_TRUE@dynamic_list.stdout: dynamic_list +@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -DWs dynamic_list > dynamic_list.stdout @GCC_TRUE@@NATIVE_LINKER_TRUE@libthin1.a: thin_archive_test_1.o alt/thin_archive_test_2.o @GCC_TRUE@@NATIVE_LINKER_TRUE@ rm -f $@ diff --git a/gold/testsuite/dynamic_list.sh b/gold/testsuite/dynamic_list.sh new file mode 100755 index 0000000..dfd9f0f --- /dev/null +++ b/gold/testsuite/dynamic_list.sh @@ -0,0 +1,50 @@ +#!/bin/sh + +# dynamic_list.sh -- test --dynamic-list and --dynamic-list-* + +# Copyright 2008 Free Software Foundation, Inc. +# Written by Ian Lance Taylor <iant@google.com>. + +# This file is part of gold. + +# 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. + +# This file goes with dynamic_list.t, which is a dynamic-list script. + +check() +{ + if ! grep -qw "$2" "$1" + then + echo "Did not find expected text in $1:" + echo " $2" + echo "" + echo "Actual output below:" + cat "$1" + exit 1 + fi +} + +check dynamic_list.stdout "main" # comes via --dynamic-list +check dynamic_list.stdout "_ZdlPv" # "operator delete(void*)" +check dynamic_list.stdout "_Z4t1_6v" # t1_6() +check dynamic_list.stdout "_ZN4t16aC2Ev" # t16a:t16a() +check dynamic_list.stdout "_ZN4t16aD1Ev" # t16a:~t16a() +check dynamic_list.stdout "_ZN4t16a1tEv" # t16a:t() +check dynamic_list.stdout "_ZTI4t16a" # typeinfo for t16a +check dynamic_list.stdout "_ZTI4t16b" # typeinfo for t16b +check dynamic_list.stdout "_ZTS4t16a" # typeinfo name for t16a +check dynamic_list.stdout "_ZTS4t16b" # typeinfo name for t16b +check dynamic_list.stdout "t20v" # comes via --dynamic-list-data diff --git a/gold/testsuite/dynamic_list.t b/gold/testsuite/dynamic_list.t new file mode 100644 index 0000000..6457173 --- /dev/null +++ b/gold/testsuite/dynamic_list.t @@ -0,0 +1,11 @@ +{ + main; + not_a_symbol; + global; + extern "C++" { t1_6* }; +}; +{ + extern "C++" { t16a* }; + local; + extern; +}; diff --git a/gold/yyscript.y b/gold/yyscript.y index 683273b..5ce03c5 100644 --- a/gold/yyscript.y +++ b/gold/yyscript.y @@ -193,6 +193,7 @@ %token PARSING_LINKER_SCRIPT %token PARSING_VERSION_SCRIPT %token PARSING_DEFSYM +%token PARSING_DYNAMIC_LIST /* Non-terminal types, where needed. */ @@ -222,6 +223,7 @@ top: PARSING_LINKER_SCRIPT linker_script | PARSING_VERSION_SCRIPT version_script | PARSING_DEFSYM defsym_expr + | PARSING_DYNAMIC_LIST dynamic_list_expr ; /* A file contains a list of commands. */ @@ -836,6 +838,24 @@ defsym_expr: { script_set_symbol(closure, $1.value, $1.length, $3, 0, 0); } ; +/* Handle the --dynamic-list option. A dynamic list has the format + { sym1; sym2; extern "C++" { namespace::sym3 }; }; + We store the symbol we see in the "local" list; that is where + Command_line::in_dynamic_list() will look to do its check. + TODO(csilvers): More than one of these brace-lists can appear, and + should just be merged and treated as a single list. */ +dynamic_list_expr: dynamic_list_nodes ; + +dynamic_list_nodes: + dynamic_list_node + | dynamic_list_nodes dynamic_list_node + ; + +dynamic_list_node: + '{' vers_defns ';' '}' ';' + { script_new_vers_node (closure, NULL, $2); } + ; + /* A version script. */ version_script: vers_nodes |