* 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.
This commit is contained in:
Craig Silverstein 2008-11-06 07:23:31 +00:00
parent e0bb29a584
commit c82fbeee59
11 changed files with 277 additions and 18 deletions

View file

@ -1,3 +1,35 @@
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.

View file

@ -347,6 +347,14 @@ General_options::parse_version_script(const char*, const char* arg,
gold::gold_fatal(_("unable to parse version script file %s"), 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)

View file

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

View file

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

View file

@ -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)

View file

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

View file

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

View file

@ -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 $@

50
gold/testsuite/dynamic_list.sh Executable file
View file

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

View file

@ -0,0 +1,11 @@
{
main;
not_a_symbol;
global;
extern "C++" { t1_6* };
};
{
extern "C++" { t16a* };
local;
extern;
};

View file

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