summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCary Coutant <ccoutant@google.com>2008-09-19 22:54:57 +0000
committerCary Coutant <ccoutant@google.com>2008-09-19 22:54:57 +0000
commit89fc34211be8b1d74b83e4e2b18cfa4b4cf65ba9 (patch)
treecd5675e9053bb0b9b68d98253003c08bc5e28bb9
parent14fc49fb1561bd620e790080ad27ed3890780b42 (diff)
downloadbinutils-gdb-89fc34211be8b1d74b83e4e2b18cfa4b4cf65ba9.tar.gz
Add plugin functionality for link-time optimization (LTO).
include/: * plugin-api.h: New file. gold/: * configure.ac (plugins): Add --enable-plugins option. * configure: Regenerate. * config.in: Regenerate. * Makefile.am (LIBDL): New variable. (CCFILES): Add plugin.cc. (HFILES): Add plugin.h. (ldadd_var): Add LIBDL. * Makefile.in: Regenerate. * archive.cc: Include "plugin.h". (Archive::setup): Don't preread archive symbols when using a plugin. (Archive::get_file_and_offset): Add memsize parameter. Change callers. (Archive::get_elf_object_for_member): Call plugin hooks for claiming files. (Archive::include_member): Add symbols from plugin objects. * archive.h (Archive::get_file_and_offset): Add memsize parameter. * descriptors.cc (Descriptors::open): Check for file descriptors abandoned by plugins. (Descriptors::claim_for_plugin): New function. * descriptors.h (Descriptors::claim_for_plugin): New function. (Open_descriptor::is_claimed): New field. (claim_descriptor_for_plugin): New function. * fileread.cc (File_read::claim_for_plugin): New function. * fileread.h (File_read::claim_for_plugin): New function. (File_read::descriptor): New function. * gold.cc: Include "plugin.h". (queue_initial_tasks): Add task to call plugin hooks for generating new object files. * main.cc: Include "plugin.h". (main): Load plugin libraries. * object.h (Pluginobj): Declare. (Object::pluginobj): New function. (Object::do_pluginobj): New function. (Object::set_target): New function. * options.cc: Include "plugin.h". (General_options::parse_plugin): New function. (General_options::General_options): Initialize plugins_ field. (General_options::add_plugin): New function. * options.h (Plugin_manager): Declare. (General_options): Add --plugin option. (General_options::has_plugins): New function. (General_options::plugins): New function. (General_options::add_plugin): New function. (General_options::plugins_): New field. * plugin.cc: New file. * plugin.h: New file. * readsyms.cc: Include "plugin.h". (Read_symbols::do_read_symbols): Check for archive before checking for ELF file. Call plugin hooks to claim files. * resolve.cc (Symbol_table::resolve): Record when symbol is referenced from a real object file; force override when processing replacement files. * symtab.cc (Symbol::init_fields): Initialize in_real_elf_ field. (Symbol::init_base_object): Likewise. (Symbol::init_base_output_data): Likewise. (Symbol::init_base_output_segment): Likewise. (Symbol::init_base_constant): Likewise. (Symbol::init_base_undefined): Likewise. (Symbol::output_section): Assert that object is not a plugin. (Symbol_table::add_from_pluginobj): New function. (Symbol_table::sized_finalize_symbol): Treat symbols from plugins as undefined. (Symbol_table::sized_write_globals): Likewise. (Symbol_table::add_from_pluginobj): Instantiate template. * symtab.h (Sized_pluginobj): Declare. (Symbol::in_real_elf): New function. (Symbol::set_in_real_elf): New function. (Symbol::in_real_elf_): New field. (Symbol_table::add_from_pluginobj): New function. * testsuite/Makefile.am (AM_CFLAGS): New variable. (LIBDL): New variable. (LDADD): Add LIBDL. (check_PROGRAMS): Add plugin_test_1 and plugin_test_2. (check_SCRIPTS): Add plugin_test_1.sh and plugin_test_2.sh. (check_DATA): Add plugin_test_1.err and plugin_test_2.err. (MOSTLYCLEANFILES): Likewise. * testsuite/Makefile.in: Regenerate. * testsuite/plugin_test.c: New file. * testsuite/plugin_test_1.sh: New file. * testsuite/plugin_test_2.sh: New file.
-rw-r--r--gold/ChangeLog85
-rw-r--r--gold/Makefile.am9
-rw-r--r--gold/Makefile.in14
-rw-r--r--gold/archive.cc37
-rw-r--r--gold/archive.h2
-rw-r--r--gold/config.in3
-rwxr-xr-xgold/configure41
-rw-r--r--gold/configure.ac14
-rw-r--r--gold/descriptors.cc22
-rw-r--r--gold/descriptors.h12
-rw-r--r--gold/fileread.cc13
-rw-r--r--gold/fileread.h13
-rw-r--r--gold/gold.cc11
-rw-r--r--gold/main.cc5
-rw-r--r--gold/object.h18
-rw-r--r--gold/options.cc22
-rw-r--r--gold/options.h23
-rw-r--r--gold/plugin.cc968
-rw-r--r--gold/plugin.h457
-rw-r--r--gold/readsyms.cc76
-rw-r--r--gold/resolve.cc19
-rw-r--r--gold/symtab.cc117
-rw-r--r--gold/symtab.h26
-rw-r--r--gold/testsuite/Makefile.am43
-rw-r--r--gold/testsuite/Makefile.in170
-rw-r--r--gold/testsuite/plugin_test.c427
-rwxr-xr-xgold/testsuite/plugin_test_1.sh56
-rwxr-xr-xgold/testsuite/plugin_test_2.sh54
-rw-r--r--include/ChangeLog5
-rw-r--r--include/plugin-api.h242
30 files changed, 2923 insertions, 81 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog
index 22e4263b9b5..6b1a4f6762d 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -1,3 +1,88 @@
+2008-09-19 Cary Coutant <ccoutant@google.com>
+
+ Add plugin functionality for link-time optimization (LTO).
+ * configure.ac (plugins): Add --enable-plugins option.
+ * configure: Regenerate.
+ * config.in: Regenerate.
+ * Makefile.am (LIBDL): New variable.
+ (CCFILES): Add plugin.cc.
+ (HFILES): Add plugin.h.
+ (ldadd_var): Add LIBDL.
+ * Makefile.in: Regenerate.
+
+ * archive.cc: Include "plugin.h".
+ (Archive::setup): Don't preread archive symbols when using a plugin.
+ (Archive::get_file_and_offset): Add memsize parameter. Change callers.
+ (Archive::get_elf_object_for_member): Call plugin hooks for claiming
+ files.
+ (Archive::include_member): Add symbols from plugin objects.
+ * archive.h (Archive::get_file_and_offset): Add memsize parameter.
+ * descriptors.cc (Descriptors::open): Check for file descriptors
+ abandoned by plugins.
+ (Descriptors::claim_for_plugin): New function.
+ * descriptors.h (Descriptors::claim_for_plugin): New function.
+ (Open_descriptor::is_claimed): New field.
+ (claim_descriptor_for_plugin): New function.
+ * fileread.cc (File_read::claim_for_plugin): New function.
+ * fileread.h (File_read::claim_for_plugin): New function.
+ (File_read::descriptor): New function.
+ * gold.cc: Include "plugin.h".
+ (queue_initial_tasks): Add task to call plugin hooks for generating
+ new object files.
+ * main.cc: Include "plugin.h".
+ (main): Load plugin libraries.
+ * object.h (Pluginobj): Declare.
+ (Object::pluginobj): New function.
+ (Object::do_pluginobj): New function.
+ (Object::set_target): New function.
+ * options.cc: Include "plugin.h".
+ (General_options::parse_plugin): New function.
+ (General_options::General_options): Initialize plugins_ field.
+ (General_options::add_plugin): New function.
+ * options.h (Plugin_manager): Declare.
+ (General_options): Add --plugin option.
+ (General_options::has_plugins): New function.
+ (General_options::plugins): New function.
+ (General_options::add_plugin): New function.
+ (General_options::plugins_): New field.
+ * plugin.cc: New file.
+ * plugin.h: New file.
+ * readsyms.cc: Include "plugin.h".
+ (Read_symbols::do_read_symbols): Check for archive before checking
+ for ELF file. Call plugin hooks to claim files.
+ * resolve.cc (Symbol_table::resolve): Record when symbol is referenced
+ from a real object file; force override when processing replacement
+ files.
+ * symtab.cc (Symbol::init_fields): Initialize in_real_elf_ field.
+ (Symbol::init_base_object): Likewise.
+ (Symbol::init_base_output_data): Likewise.
+ (Symbol::init_base_output_segment): Likewise.
+ (Symbol::init_base_constant): Likewise.
+ (Symbol::init_base_undefined): Likewise.
+ (Symbol::output_section): Assert that object is not a plugin.
+ (Symbol_table::add_from_pluginobj): New function.
+ (Symbol_table::sized_finalize_symbol): Treat symbols from plugins as
+ undefined.
+ (Symbol_table::sized_write_globals): Likewise.
+ (Symbol_table::add_from_pluginobj): Instantiate template.
+ * symtab.h (Sized_pluginobj): Declare.
+ (Symbol::in_real_elf): New function.
+ (Symbol::set_in_real_elf): New function.
+ (Symbol::in_real_elf_): New field.
+ (Symbol_table::add_from_pluginobj): New function.
+
+ * testsuite/Makefile.am (AM_CFLAGS): New variable.
+ (LIBDL): New variable.
+ (LDADD): Add LIBDL.
+ (check_PROGRAMS): Add plugin_test_1 and plugin_test_2.
+ (check_SCRIPTS): Add plugin_test_1.sh and plugin_test_2.sh.
+ (check_DATA): Add plugin_test_1.err and plugin_test_2.err.
+ (MOSTLYCLEANFILES): Likewise.
+ * testsuite/Makefile.in: Regenerate.
+ * testsuite/plugin_test.c: New file.
+ * testsuite/plugin_test_1.sh: New file.
+ * testsuite/plugin_test_2.sh: New file.
+
2008-09-16 Ian Lance Taylor <iant@google.com>
* target-reloc.h (relocate_section): Check whether a symbol is
diff --git a/gold/Makefile.am b/gold/Makefile.am
index e706703303b..74db37a336d 100644
--- a/gold/Makefile.am
+++ b/gold/Makefile.am
@@ -19,6 +19,10 @@ INCLUDES = \
LIBIBERTY = ../libiberty/libiberty.a
+if PLUGINS
+LIBDL = -ldl
+endif
+
if THREADS
THREADSLIB = -lpthread
endif
@@ -53,6 +57,7 @@ CCFILES = \
options.cc \
output.cc \
parameters.cc \
+ plugin.cc \
readsyms.cc \
reduced_debug_output.cc \
reloc.cc \
@@ -90,6 +95,7 @@ HFILES = \
options.h \
output.h \
parameters.h \
+ plugin.h \
readsyms.h \
reduced_debug_output.h \
reloc.h \
@@ -122,7 +128,8 @@ libgold_a_SOURCES = $(CCFILES) $(HFILES) $(YFILES)
sources_var = main.cc
deps_var = $(TARGETOBJS) libgold.a $(LIBIBERTY) $(LIBINTL_DEP)
-ldadd_var = $(TARGETOBJS) libgold.a $(LIBIBERTY) $(LIBINTL) $(THREADSLIB)
+ldadd_var = $(TARGETOBJS) libgold.a $(LIBIBERTY) $(LIBINTL) \
+ $(THREADSLIB) $(LIBDL)
ld_new_SOURCES = $(sources_var)
ld_new_DEPENDENCIES = $(deps_var) $(LIBOBJS)
diff --git a/gold/Makefile.in b/gold/Makefile.in
index bbc54171f2d..f6a80d020dc 100644
--- a/gold/Makefile.in
+++ b/gold/Makefile.in
@@ -82,7 +82,7 @@ am__objects_1 = archive.$(OBJEXT) binary.$(OBJEXT) common.$(OBJEXT) \
fileread.$(OBJEXT) gold.$(OBJEXT) gold-threads.$(OBJEXT) \
layout.$(OBJEXT) mapfile.$(OBJEXT) merge.$(OBJEXT) \
object.$(OBJEXT) options.$(OBJEXT) output.$(OBJEXT) \
- parameters.$(OBJEXT) readsyms.$(OBJEXT) \
+ parameters.$(OBJEXT) plugin.$(OBJEXT) readsyms.$(OBJEXT) \
reduced_debug_output.$(OBJEXT) reloc.$(OBJEXT) \
resolve.$(OBJEXT) script-sections.$(OBJEXT) script.$(OBJEXT) \
stringpool.$(OBJEXT) symtab.$(OBJEXT) target-select.$(OBJEXT) \
@@ -101,7 +101,7 @@ am__DEPENDENCIES_1 =
am__DEPENDENCIES_2 = ../libiberty/libiberty.a
am__DEPENDENCIES_3 = $(am__DEPENDENCIES_1) libgold.a \
$(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \
- $(am__DEPENDENCIES_1)
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
am__DEPENDENCIES_4 = @LIBOBJS@
am__ld1_SOURCES_DIST = main.cc
@GCC_TRUE@@NATIVE_LINKER_TRUE@am_ld1_OBJECTS = $(am__objects_4)
@@ -227,6 +227,8 @@ PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
+PLUGINS_FALSE = @PLUGINS_FALSE@
+PLUGINS_TRUE = @PLUGINS_TRUE@
POSUB = @POSUB@
RANDOM_SEED_CFLAGS = @RANDOM_SEED_CFLAGS@
RANLIB = @RANLIB@
@@ -308,6 +310,7 @@ INCLUDES = \
@INCINTL@
LIBIBERTY = ../libiberty/libiberty.a
+@PLUGINS_TRUE@LIBDL = -ldl
@THREADS_TRUE@THREADSLIB = -lpthread
AM_YFLAGS = -d
noinst_LIBRARIES = libgold.a
@@ -336,6 +339,7 @@ CCFILES = \
options.cc \
output.cc \
parameters.cc \
+ plugin.cc \
readsyms.cc \
reduced_debug_output.cc \
reloc.cc \
@@ -373,6 +377,7 @@ HFILES = \
options.h \
output.h \
parameters.h \
+ plugin.h \
readsyms.h \
reduced_debug_output.h \
reloc.h \
@@ -403,7 +408,9 @@ ALL_TARGETOBJS = \
libgold_a_SOURCES = $(CCFILES) $(HFILES) $(YFILES)
sources_var = main.cc
deps_var = $(TARGETOBJS) libgold.a $(LIBIBERTY) $(LIBINTL_DEP)
-ldadd_var = $(TARGETOBJS) libgold.a $(LIBIBERTY) $(LIBINTL) $(THREADSLIB)
+ldadd_var = $(TARGETOBJS) libgold.a $(LIBIBERTY) $(LIBINTL) \
+ $(THREADSLIB) $(LIBDL)
+
ld_new_SOURCES = $(sources_var)
ld_new_DEPENDENCIES = $(deps_var) $(LIBOBJS)
ld_new_LDADD = $(ldadd_var) $(LIBOBJS)
@@ -550,6 +557,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/options.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/output.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parameters.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/powerpc.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/readsyms.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reduced_debug_output.Po@am__quote@
diff --git a/gold/archive.cc b/gold/archive.cc
index f5ad5744ec9..7fd1a1785f4 100644
--- a/gold/archive.cc
+++ b/gold/archive.cc
@@ -37,6 +37,7 @@
#include "symtab.h"
#include "object.h"
#include "archive.h"
+#include "plugin.h"
namespace gold
{
@@ -126,6 +127,9 @@ Archive::setup(Input_objects* input_objects)
&& parameters->options().preread_archive_symbols());
#ifndef ENABLE_THREADS
preread_syms = false;
+#else
+ if (parameters->options().has_plugins())
+ preread_syms = false;
#endif
if (preread_syms)
this->read_all_symbols(input_objects);
@@ -439,11 +443,11 @@ Archive::end()
bool
Archive::get_file_and_offset(off_t off, Input_objects* input_objects,
Input_file** input_file, off_t* memoff,
- std::string* member_name)
+ off_t* memsize, std::string* member_name)
{
off_t nested_off;
- this->read_header(off, false, member_name, &nested_off);
+ *memsize = this->read_header(off, false, member_name, &nested_off);
*input_file = this->input_file_;
*memoff = off + static_cast<off_t>(sizeof(Archive_header));
@@ -488,8 +492,8 @@ Archive::get_file_and_offset(off_t off, Input_objects* input_objects,
this->nested_archives_.insert(std::make_pair(*member_name, arch));
gold_assert(ins.second);
}
- return arch->get_file_and_offset(nested_off, input_objects,
- input_file, memoff, member_name);
+ return arch->get_file_and_offset(nested_off, input_objects, input_file,
+ memoff, memsize, member_name);
}
// This is an external member of a thin archive. Open the
@@ -503,6 +507,7 @@ Archive::get_file_and_offset(off_t off, Input_objects* input_objects,
return false;
*memoff = 0;
+ *memsize = (*input_file)->file().filesize();
return true;
}
@@ -515,11 +520,26 @@ Archive::get_elf_object_for_member(off_t off, Input_objects* input_objects)
std::string member_name;
Input_file* input_file;
off_t memoff;
+ off_t memsize;
if (!this->get_file_and_offset(off, input_objects, &input_file, &memoff,
- &member_name))
+ &memsize, &member_name))
return NULL;
+ if (parameters->options().has_plugins())
+ {
+ Object* obj = parameters->options().plugins()->claim_file(input_file,
+ memoff,
+ memsize);
+ if (obj != NULL)
+ {
+ // The input file was claimed by a plugin, and its symbols
+ // have been provided by the plugin.
+ input_file->file().claim_for_plugin();
+ return obj;
+ }
+ }
+
off_t filesize = input_file->file().filesize();
int read_size = elfcpp::Elf_sizes<64>::ehdr_size;
if (filesize - memoff < read_size)
@@ -753,6 +773,13 @@ Archive::include_member(Symbol_table* symtab, Layout* layout,
if (mapfile != NULL)
mapfile->report_include_archive_member(obj->name(), sym, why);
+ Pluginobj* pluginobj = obj->pluginobj();
+ if (pluginobj != NULL)
+ {
+ pluginobj->add_symbols(symtab, layout);
+ return;
+ }
+
if (input_objects->add_object(obj))
{
Read_symbols_data sd;
diff --git a/gold/archive.h b/gold/archive.h
index 24fdb2b1f27..6b99aed1e80 100644
--- a/gold/archive.h
+++ b/gold/archive.h
@@ -184,7 +184,7 @@ class Archive
bool
get_file_and_offset(off_t off, Input_objects* input_objects,
Input_file** input_file, off_t* memoff,
- std::string* member_name);
+ off_t* memsize, std::string* member_name);
// Return an ELF object for the member at offset OFF. Set *MEMBER_NAME to
// the name of the member.
diff --git a/gold/config.in b/gold/config.in
index 73cc6e9eb58..309f84b6e52 100644
--- a/gold/config.in
+++ b/gold/config.in
@@ -4,6 +4,9 @@
language is requested. */
#undef ENABLE_NLS
+/* Define to enable linker plugins */
+#undef ENABLE_PLUGINS
+
/* Define to do multi-threaded linking */
#undef ENABLE_THREADS
diff --git a/gold/configure b/gold/configure
index f2ec1efa2bd..d898870a6e2 100755
--- a/gold/configure
+++ b/gold/configure
@@ -309,7 +309,7 @@ ac_includes_default="\
# include <unistd.h>
#endif"
-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar THREADS_TRUE THREADS_FALSE TARGETOBJS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE YACC RANLIB ac_ct_RANLIB LN_S USE_NLS LIBINTL LIBINTL_DEP INCINTL XGETTEXT GMSGFMT POSUB CATALOGS DATADIRNAME INSTOBJEXT GENCAT CATOBJEXT MKINSTALLDIRS MSGFMT MSGMERGE NATIVE_LINKER_TRUE NATIVE_LINKER_FALSE GCC_TRUE GCC_FALSE FN_PTRS_IN_SO_WITHOUT_PIC_TRUE FN_PTRS_IN_SO_WITHOUT_PIC_FALSE TLS_TRUE TLS_FALSE STATIC_TLS_TRUE STATIC_TLS_FALSE OMP_SUPPORT_TRUE OMP_SUPPORT_FALSE TLS_GNU2_DIALECT_TRUE TLS_GNU2_DIALECT_FALSE TLS_DESCRIPTORS_TRUE TLS_DESCRIPTORS_FALSE CONSTRUCTOR_PRIORITY_TRUE CONSTRUCTOR_PRIORITY_FALSE RANDOM_SEED_CFLAGS WARN_CFLAGS NO_WERROR WARN_CXXFLAGS LFS_CFLAGS LIBOBJS CPP EGREP HAVE_ZLIB_TRUE HAVE_ZLIB_FALSE CXXCPP MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT LTLIBOBJS'
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar THREADS_TRUE THREADS_FALSE PLUGINS_TRUE PLUGINS_FALSE TARGETOBJS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE YACC RANLIB ac_ct_RANLIB LN_S USE_NLS LIBINTL LIBINTL_DEP INCINTL XGETTEXT GMSGFMT POSUB CATALOGS DATADIRNAME INSTOBJEXT GENCAT CATOBJEXT MKINSTALLDIRS MSGFMT MSGMERGE NATIVE_LINKER_TRUE NATIVE_LINKER_FALSE GCC_TRUE GCC_FALSE FN_PTRS_IN_SO_WITHOUT_PIC_TRUE FN_PTRS_IN_SO_WITHOUT_PIC_FALSE TLS_TRUE TLS_FALSE STATIC_TLS_TRUE STATIC_TLS_FALSE OMP_SUPPORT_TRUE OMP_SUPPORT_FALSE TLS_GNU2_DIALECT_TRUE TLS_GNU2_DIALECT_FALSE TLS_DESCRIPTORS_TRUE TLS_DESCRIPTORS_FALSE CONSTRUCTOR_PRIORITY_TRUE CONSTRUCTOR_PRIORITY_FALSE RANDOM_SEED_CFLAGS WARN_CFLAGS NO_WERROR WARN_CXXFLAGS LFS_CFLAGS LIBOBJS CPP EGREP HAVE_ZLIB_TRUE HAVE_ZLIB_FALSE CXXCPP MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT LTLIBOBJS'
ac_subst_files=''
ac_pwd=`pwd`
@@ -866,6 +866,7 @@ Optional Features:
--disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
--enable-FEATURE[=ARG] include FEATURE [ARG=yes]
--enable-threads multi-threaded linking
+ --enable-plugins linker plugins
--enable-targets alternative target configurations
--disable-dependency-tracking speeds up one-time build
--enable-dependency-tracking do not reject slow dependency extractors
@@ -1959,6 +1960,35 @@ else
fi
+# Check whether --enable-plugins or --disable-plugins was given.
+if test "${enable_plugins+set}" = set; then
+ enableval="$enable_plugins"
+ case "${enableval}" in
+ yes | "") plugins=yes ;;
+ no) plugins=no ;;
+ *) plugins=yes ;;
+ esac
+else
+ plugins=no
+fi;
+if test "$plugins" = "yes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define ENABLE_PLUGINS 1
+_ACEOF
+
+fi
+
+
+if test "$plugins" = "yes"; then
+ PLUGINS_TRUE=
+ PLUGINS_FALSE='#'
+else
+ PLUGINS_TRUE='#'
+ PLUGINS_FALSE=
+fi
+
+
# Check whether --enable-targets or --disable-targets was given.
if test "${enable_targets+set}" = set; then
enableval="$enable_targets"
@@ -6720,6 +6750,13 @@ echo "$as_me: error: conditional \"THREADS\" was never defined.
Usually this means the macro was only invoked conditionally." >&2;}
{ (exit 1); exit 1; }; }
fi
+if test -z "${PLUGINS_TRUE}" && test -z "${PLUGINS_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"PLUGINS\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"PLUGINS\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
{ { echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined.
Usually this means the macro was only invoked conditionally." >&5
@@ -7396,6 +7433,8 @@ s,@am__tar@,$am__tar,;t t
s,@am__untar@,$am__untar,;t t
s,@THREADS_TRUE@,$THREADS_TRUE,;t t
s,@THREADS_FALSE@,$THREADS_FALSE,;t t
+s,@PLUGINS_TRUE@,$PLUGINS_TRUE,;t t
+s,@PLUGINS_FALSE@,$PLUGINS_FALSE,;t t
s,@TARGETOBJS@,$TARGETOBJS,;t t
s,@CC@,$CC,;t t
s,@CFLAGS@,$CFLAGS,;t t
diff --git a/gold/configure.ac b/gold/configure.ac
index 3fbcd0ea076..b0efef1e55c 100644
--- a/gold/configure.ac
+++ b/gold/configure.ac
@@ -53,6 +53,20 @@ if test "$threads" = "yes"; then
fi
AM_CONDITIONAL(THREADS, test "$threads" = "yes")
+AC_ARG_ENABLE([plugins],
+[ --enable-plugins linker plugins],
+[case "${enableval}" in
+ yes | "") plugins=yes ;;
+ no) plugins=no ;;
+ *) plugins=yes ;;
+ esac],
+[plugins=no])
+if test "$plugins" = "yes"; then
+ AC_DEFINE(ENABLE_PLUGINS, 1,
+ [Define to enable linker plugins])
+fi
+AM_CONDITIONAL(PLUGINS, test "$plugins" = "yes")
+
AC_ARG_ENABLE([targets],
[ --enable-targets alternative target configurations],
[case "${enableval}" in
diff --git a/gold/descriptors.cc b/gold/descriptors.cc
index 75a7a869c59..73c03bf4a45 100644
--- a/gold/descriptors.cc
+++ b/gold/descriptors.cc
@@ -115,7 +115,9 @@ Descriptors::open(int descriptor, const char* name, int flags, int mode)
pod->inuse = true;
pod->is_write = (flags & O_ACCMODE) != O_RDONLY;
- ++this->current_;
+ if (!pod->is_claimed)
+ ++this->current_;
+ pod->is_claimed = false;
if (this->current_ >= this->limit_)
this->close_some_descriptor();
@@ -166,6 +168,24 @@ Descriptors::release(int descriptor, bool permanent)
}
}
+// Claim the file descriptor DESCRIPTOR for a plugin. This effectively
+// removes the descriptor from the pool of linker-managed descriptors,
+// as the plugin will assume responsibility for closing it.
+// The IS_CLAIMED flag allows us to recognize when a file descriptor
+// has been reused after being closed by the plugin.
+
+void
+Descriptors::claim_for_plugin(int descriptor)
+{
+ Hold_lock hl(*this->lock_);
+
+ gold_assert(descriptor >= 0
+ && (static_cast<size_t>(descriptor)
+ < this->open_descriptors_.size()));
+ Open_descriptor* pod = &this->open_descriptors_[descriptor];
+ pod->is_claimed = true;
+}
+
// Close some descriptor. The lock is held when this is called. We
// close the descriptor on the top of the free stack. Note that this
// is the opposite of an LRU algorithm--we close the most recently
diff --git a/gold/descriptors.h b/gold/descriptors.h
index 6a6ab61be0d..359008c1f07 100644
--- a/gold/descriptors.h
+++ b/gold/descriptors.h
@@ -56,6 +56,12 @@ class Descriptors
void
release(int descriptor, bool permanent);
+ // Claim the file descriptor DESCRIPTOR for a plugin. This effectively
+ // removes the descriptor from the pool of linker-managed descriptors,
+ // as the plugin will assume responsibility for closing it.
+ void
+ claim_for_plugin(int descriptor);
+
private:
// Information kept for a descriptor.
struct Open_descriptor
@@ -69,6 +75,8 @@ class Descriptors
bool inuse;
// Whether this is a write descriptor.
bool is_write;
+ // Whether the descriptor has been claimed for a plugin.
+ bool is_claimed;
};
bool
@@ -100,6 +108,10 @@ inline void
release_descriptor(int descriptor, bool permanent)
{ descriptors.release(descriptor, permanent); }
+inline void
+claim_descriptor_for_plugin(int descriptor)
+{ descriptors.claim_for_plugin(descriptor); }
+
} // End namespace gold.
#endif // !defined(GOLD_DESCRIPTORS_H)
diff --git a/gold/fileread.cc b/gold/fileread.cc
index 883f8c80895..72abd6bc2ed 100644
--- a/gold/fileread.cc
+++ b/gold/fileread.cc
@@ -191,6 +191,19 @@ File_read::release()
this->released_ = true;
}
+// Claim the file for a plugin. This effectively releases the file without
+// closing it; the plugin will assume responsibility for closing it.
+
+void
+File_read::claim_for_plugin()
+{
+ gold_assert(this->is_locked());
+ claim_descriptor_for_plugin(this->descriptor_);
+ this->descriptor_ = -1;
+ this->is_descriptor_opened_ = false;
+ this->released_ = true;
+}
+
// Lock the file.
void
diff --git a/gold/fileread.h b/gold/fileread.h
index 4236ce0ccef..1b776f1c167 100644
--- a/gold/fileread.h
+++ b/gold/fileread.h
@@ -109,6 +109,11 @@ class File_read
void
release();
+ // Claim the file for a plugin. This effectively releases the file without
+ // closing it; the plugin will assume responsibility for closing it.
+ void
+ claim_for_plugin();
+
// Return the size of the file.
off_t
filesize() const
@@ -183,6 +188,14 @@ class File_read
static void
print_stats();
+ // Return the open file descriptor (for plugins).
+ int
+ descriptor() const
+ {
+ gold_assert(this->descriptor_ >= 0);
+ return this->descriptor_;
+ }
+
private:
// This class may not be copied.
File_read(const File_read&);
diff --git a/gold/gold.cc b/gold/gold.cc
index 42c6248d4b2..6a536b8c769 100644
--- a/gold/gold.cc
+++ b/gold/gold.cc
@@ -40,6 +40,7 @@
#include "layout.h"
#include "reloc.h"
#include "defstd.h"
+#include "plugin.h"
namespace gold
{
@@ -151,6 +152,16 @@ queue_initial_tasks(const General_options& options,
this_blocker = next_blocker;
}
+ if (options.has_plugins())
+ {
+ Task_token* next_blocker = new Task_token(true);
+ next_blocker->add_blocker();
+ workqueue->queue(new Plugin_hook(options, input_objects, symtab, layout,
+ &search_path, mapfile, this_blocker,
+ next_blocker));
+ this_blocker = next_blocker;
+ }
+
workqueue->queue(new Task_function(new Middle_runner(options,
input_objects,
symtab,
diff --git a/gold/main.cc b/gold/main.cc
index b8421590300..8e8e8f9d2f4 100644
--- a/gold/main.cc
+++ b/gold/main.cc
@@ -42,6 +42,7 @@
#include "archive.h"
#include "symtab.h"
#include "layout.h"
+#include "plugin.h"
using namespace gold;
@@ -190,6 +191,10 @@ main(int argc, char** argv)
if (parameters->options().relocatable())
command_line.script_options().version_script_info()->clear();
+ // Load plugin libraries.
+ if (command_line.options().has_plugins())
+ command_line.options().plugins()->load_plugins();
+
// The work queue.
Workqueue workqueue(command_line.options());
diff --git a/gold/object.h b/gold/object.h
index 188f1f208fe..1c4fc6768ce 100644
--- a/gold/object.h
+++ b/gold/object.h
@@ -42,6 +42,7 @@ class Layout;
class Output_section;
class Output_file;
class Output_symtab_xindex;
+class Pluginobj;
class Dynobj;
class Object_merge_map;
class Relocatable_relocs;
@@ -214,6 +215,12 @@ class Object
is_dynamic() const
{ return this->is_dynamic_; }
+ // Returns NULL for Objects that are not plugin objects. This method
+ // is overridden in the Pluginobj class.
+ Pluginobj*
+ pluginobj()
+ { return this->do_pluginobj(); }
+
// Return the target structure associated with this object.
Target*
target() const
@@ -431,7 +438,18 @@ class Object
size_t* used) const
{ this->do_get_global_symbol_counts(symtab, defined, used); }
+ // Set the target.
+ void
+ set_target(Target* target)
+ { this->target_ = target; }
+
protected:
+ // Returns NULL for Objects that are not plugin objects. This method
+ // is overridden in the Pluginobj class.
+ virtual Pluginobj*
+ do_pluginobj()
+ { return NULL; }
+
// Read the symbols--implemented by child class.
virtual void
do_read_symbols(Read_symbols_data*) = 0;
diff --git a/gold/options.cc b/gold/options.cc
index 78f0b1aa2ba..08b67fdf46b 100644
--- a/gold/options.cc
+++ b/gold/options.cc
@@ -36,6 +36,7 @@
#include "script.h"
#include "target-select.h"
#include "options.h"
+#include "plugin.h"
namespace gold
{
@@ -296,6 +297,15 @@ General_options::parse_library(const char*, const char* arg,
cmdline->inputs().add_file(file);
}
+#ifdef ENABLE_PLUGINS
+void
+General_options::parse_plugin(const char*, const char* arg,
+ Command_line*)
+{
+ this->add_plugin(arg);
+}
+#endif // ENABLE_PLUGINS
+
void
General_options::parse_R(const char* option, const char* arg,
Command_line* cmdline)
@@ -594,7 +604,7 @@ namespace gold
General_options::General_options()
: execstack_status_(General_options::EXECSTACK_FROM_INPUT), static_(false),
- do_demangle_(false)
+ do_demangle_(false), plugins_()
{
}
@@ -632,6 +642,16 @@ General_options::add_sysroot()
free(canonical_sysroot);
}
+// Add a plugin and its arguments to the list of plugins.
+
+void
+General_options::add_plugin(const char* arg)
+{
+ if (this->plugins_ == NULL)
+ this->plugins_ = new Plugin_manager(*this);
+ this->plugins_->add_plugin(arg);
+}
+
// Set up variables and other state that isn't set up automatically by
// the parse routine, and ensure options don't contradict each other
// and are otherwise kosher.
diff --git a/gold/options.h b/gold/options.h
index 292673018f0..167e58a09ea 100644
--- a/gold/options.h
+++ b/gold/options.h
@@ -54,6 +54,7 @@ class Search_directory;
class Input_file_group;
class Position_dependent_options;
class Target;
+class Plugin_manager;
// The nested namespace is to contain all the global variables and
// structs that need to be defined in the .h file, but do not need to
@@ -689,8 +690,14 @@ class General_options
DEFINE_string(oformat, options::EXACTLY_TWO_DASHES, '\0', "elf",
N_("Set output format"), N_("[binary]"));
+#ifdef ENABLE_PLUGINS
+ DEFINE_special(plugin, options::TWO_DASHES, '\0',
+ N_("Load a plugin library"), N_("PLUGIN[,ARG,...]"));
+#endif
+
DEFINE_bool(preread_archive_symbols, options::TWO_DASHES, '\0', false,
N_("Preread archive symbols when multi-threaded"), NULL);
+
DEFINE_string(print_symbol_counts, options::TWO_DASHES, '\0', NULL,
N_("Print symbols defined and used for each input"),
N_("FILENAME"));
@@ -916,6 +923,16 @@ class General_options
do_demangle() const
{ return this->do_demangle_; }
+ // Returns TRUE if any plugin libraries have been loaded.
+ bool
+ has_plugins() const
+ { return this->plugins_ != NULL; }
+
+ // Return a pointer to the plugin manager.
+ Plugin_manager*
+ plugins() const
+ { return this->plugins_; }
+
private:
// Don't copy this structure.
General_options(const General_options&);
@@ -953,12 +970,18 @@ class General_options
void
add_sysroot();
+ // Add a plugin and its arguments to the list of plugins.
+ void
+ add_plugin(const char* arg);
+
// Whether to mark the stack as executable.
Execstack execstack_status_;
// Whether to do a static link.
bool static_;
// Whether to do demangling.
bool do_demangle_;
+ // List of plugin libraries.
+ Plugin_manager* plugins_;
};
// The position-dependent options. We use this to store the state of
diff --git a/gold/plugin.cc b/gold/plugin.cc
new file mode 100644
index 00000000000..19f7619979b
--- /dev/null
+++ b/gold/plugin.cc
@@ -0,0 +1,968 @@
+// plugin.c -- plugin manager for gold -*- C++ -*-
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Cary Coutant <ccoutant@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.
+
+#include <cstdio>
+#include <cstdarg>
+#include <cstring>
+#include <string>
+#include <vector>
+#include <dlfcn.h>
+
+#include "gold.h"
+#include "parameters.h"
+#include "errors.h"
+#include "fileread.h"
+#include "layout.h"
+#include "options.h"
+#include "plugin.h"
+#include "target.h"
+#include "readsyms.h"
+#include "symtab.h"
+#include "elfcpp.h"
+
+namespace gold
+{
+
+#ifdef ENABLE_PLUGINS
+
+// The linker's exported interfaces.
+
+extern "C"
+{
+
+static enum ld_plugin_status
+register_claim_file(ld_plugin_claim_file_handler handler);
+
+static enum ld_plugin_status
+register_all_symbols_read(ld_plugin_all_symbols_read_handler handler);
+
+static enum ld_plugin_status
+register_cleanup(ld_plugin_cleanup_handler handler);
+
+static enum ld_plugin_status
+add_symbols(void *handle, int nsyms, const struct ld_plugin_symbol *syms);
+
+static enum ld_plugin_status
+get_symbols(const void *handle, int nsyms, struct ld_plugin_symbol *syms);
+
+static enum ld_plugin_status
+add_input_file(char *pathname);
+
+static enum ld_plugin_status
+message(int level, char *format, ...);
+
+};
+
+#endif // ENABLE_PLUGINS
+
+static Pluginobj* make_sized_plugin_object(Input_file* input_file,
+ off_t offset);
+
+// Plugin methods.
+
+// Load one plugin library.
+
+void
+Plugin::load()
+{
+#ifdef ENABLE_PLUGINS
+ std::string filename;
+ std::vector<std::string> args;
+
+ // Parse the filename and arguments, each separated by commas.
+ // FIXME: Temporarily allowing semicolon as an argument separator
+ // so args can be passed through gcc's -Wl,... option, which
+ // breaks arguments at the commas.
+ const char* p = this->args_;
+ int n = strcspn(p, ",;");
+ filename.assign(p, n);
+ p += n;
+ while (*p == ',' || *p == ';')
+ {
+ ++p;
+ n = strcspn(p, ",;");
+ args.push_back(std::string(p, n));
+ p += n;
+ }
+
+ // Load the plugin library.
+ // FIXME: Look for the library in standard locations.
+ this->handle_ = dlopen(filename.c_str(), RTLD_NOW);
+ if (this->handle_ == NULL)
+ {
+ gold_error(_("%s: could not load plugin library"), filename.c_str());
+ return;
+ }
+
+ // Find the plugin's onload entry point.
+ ld_plugin_onload onload = reinterpret_cast<ld_plugin_onload>
+ (dlsym(this->handle_, "onload"));
+ if (onload == NULL)
+ {
+ gold_error(_("%s: could not find onload entry point"), filename.c_str());
+ return;
+ }
+
+ // Get the linker's version number.
+ const char* ver = get_version_string();
+ int major = 0;
+ int minor = 0;
+ sscanf(ver, "%d.%d", &major, &minor);
+
+ // Allocate and populate a transfer vector.
+ const int tv_fixed_size = 11;
+ int tv_size = args.size() + tv_fixed_size;
+ ld_plugin_tv *tv = new ld_plugin_tv[tv_size];
+
+ int i = 0;
+ tv[i].tv_tag = LDPT_API_VERSION;
+ tv[i].tv_u.tv_val = LD_PLUGIN_API_VERSION;
+
+ ++i;
+ tv[i].tv_tag = LDPT_GOLD_VERSION;
+ tv[i].tv_u.tv_val = major * 100 + minor;
+
+ ++i;
+ tv[i].tv_tag = LDPT_LINKER_OUTPUT;
+ if (parameters->options().relocatable())
+ tv[i].tv_u.tv_val = LDPO_REL;
+ else if (parameters->options().shared())
+ tv[i].tv_u.tv_val = LDPO_DYN;
+ else
+ tv[i].tv_u.tv_val = LDPO_EXEC;
+
+ for (unsigned int j = 0; j < args.size(); ++j)
+ {
+ ++i;
+ tv[i].tv_tag = LDPT_OPTION;
+ tv[i].tv_u.tv_string = args[j].c_str();
+ }
+
+ ++i;
+ tv[i].tv_tag = LDPT_REGISTER_CLAIM_FILE_HOOK;
+ tv[i].tv_u.tv_register_claim_file = register_claim_file;
+
+ ++i;
+ tv[i].tv_tag = LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK;
+ tv[i].tv_u.tv_register_all_symbols_read = register_all_symbols_read;
+
+ ++i;
+ tv[i].tv_tag = LDPT_REGISTER_CLEANUP_HOOK;
+ tv[i].tv_u.tv_register_cleanup = register_cleanup;
+
+ ++i;
+ tv[i].tv_tag = LDPT_ADD_SYMBOLS;
+ tv[i].tv_u.tv_add_symbols = add_symbols;
+
+ ++i;
+ tv[i].tv_tag = LDPT_GET_SYMBOLS;
+ tv[i].tv_u.tv_get_symbols = get_symbols;
+
+ ++i;
+ tv[i].tv_tag = LDPT_ADD_INPUT_FILE;
+ tv[i].tv_u.tv_add_input_file = add_input_file;
+
+ ++i;
+ tv[i].tv_tag = LDPT_MESSAGE;
+ tv[i].tv_u.tv_message = message;
+
+ ++i;
+ tv[i].tv_tag = LDPT_NULL;
+ tv[i].tv_u.tv_val = 0;
+
+ gold_assert(i == tv_size - 1);
+
+ // Call the onload entry point.
+ (*onload)(tv);
+
+ delete tv;
+#endif // ENABLE_PLUGINS
+}
+
+// Call the plugin claim-file handler.
+
+inline bool
+Plugin::claim_file(struct ld_plugin_input_file *plugin_input_file)
+{
+ int claimed = 0;
+
+ if (this->claim_file_handler_ != NULL)
+ {
+ (*this->claim_file_handler_)(plugin_input_file, &claimed);
+ if (claimed)
+ return true;
+ }
+ return false;
+}
+
+// Call the all-symbols-read handler.
+
+inline void
+Plugin::all_symbols_read()
+{
+ if (this->all_symbols_read_handler_ != NULL)
+ (*this->all_symbols_read_handler_)();
+}
+
+// Call the cleanup handler.
+
+inline void
+Plugin::cleanup()
+{
+ if (this->cleanup_handler_ != NULL)
+ (*this->cleanup_handler_)();
+}
+
+// Plugin_manager methods.
+
+Plugin_manager::~Plugin_manager()
+{
+ for (Plugin_list::iterator p = this->plugins_.begin();
+ p != this->plugins_.end();
+ ++p)
+ delete *p;
+ this->plugins_.clear();
+ for (Object_list::iterator obj = this->objects_.begin();
+ obj != this->objects_.end();
+ ++obj)
+ delete *obj;
+ this->objects_.clear();
+}
+
+// Load all plugin libraries.
+
+void
+Plugin_manager::load_plugins()
+{
+ for (this->current_ = this->plugins_.begin();
+ this->current_ != this->plugins_.end();
+ ++this->current_)
+ (*this->current_)->load();
+}
+
+// Call the plugin claim-file handlers in turn to see if any claim the file.
+
+Pluginobj*
+Plugin_manager::claim_file(Input_file* input_file, off_t offset,
+ off_t filesize)
+{
+ if (this->in_replacement_phase_)
+ return NULL;
+
+ unsigned int handle = this->objects_.size();
+ this->input_file_ = input_file;
+ this->plugin_input_file_.name = input_file->filename().c_str();
+ this->plugin_input_file_.fd = input_file->file().descriptor();
+ this->plugin_input_file_.offset = offset;
+ this->plugin_input_file_.filesize = filesize;
+ this->plugin_input_file_.handle = reinterpret_cast<void*>(handle);
+
+ for (this->current_ = this->plugins_.begin();
+ this->current_ != this->plugins_.end();
+ ++this->current_)
+ {
+ if ((*this->current_)->claim_file(&this->plugin_input_file_))
+ {
+ if (this->objects_.size() <= handle)
+ {
+ gold_error(_("%s: plugin claimed the file "
+ "but did not provide any symbols"),
+ this->plugin_input_file_.name);
+ return NULL;
+ }
+ return this->objects_[handle];
+ }
+ }
+
+ return NULL;
+}
+
+// Call the all-symbols-read handlers.
+
+void
+Plugin_manager::all_symbols_read(Workqueue* workqueue,
+ Input_objects* input_objects,
+ Symbol_table* symtab, Layout* layout,
+ Dirsearch* dirpath, Mapfile* mapfile,
+ Task_token** last_blocker)
+{
+ this->in_replacement_phase_ = true;
+ this->workqueue_ = workqueue;
+ this->input_objects_ = input_objects;
+ this->symtab_ = symtab;
+ this->layout_ = layout;
+ this->dirpath_ = dirpath;
+ this->mapfile_ = mapfile;
+ this->this_blocker_ = NULL;
+
+ for (this->current_ = this->plugins_.begin();
+ this->current_ != this->plugins_.end();
+ ++this->current_)
+ (*this->current_)->all_symbols_read();
+
+ *last_blocker = this->this_blocker_;
+}
+
+// Call the cleanup handlers.
+
+void
+Plugin_manager::cleanup()
+{
+ for (this->current_ = this->plugins_.begin();
+ this->current_ != this->plugins_.end();
+ ++this->current_)
+ (*this->current_)->cleanup();
+}
+
+// Make a new Pluginobj object. This is called when the plugin calls
+// the add_symbols API.
+
+Pluginobj*
+Plugin_manager::make_plugin_object(unsigned int handle)
+{
+ // Make sure we aren't asked to make an object for the same handle twice.
+ if (this->objects_.size() != handle)
+ return NULL;
+
+ Pluginobj* obj = make_sized_plugin_object(this->input_file_,
+ this->plugin_input_file_.offset);
+ this->objects_.push_back(obj);
+ return obj;
+}
+
+// Add a new input file.
+
+ld_plugin_status
+Plugin_manager::add_input_file(char *pathname)
+{
+ Input_file_argument file(pathname, false, "", false, this->options_);
+ Input_argument* input_argument = new Input_argument(file);
+ Task_token* next_blocker = new Task_token(true);
+ next_blocker->add_blocker();
+ this->workqueue_->queue_soon(new Read_symbols(this->options_,
+ this->input_objects_,
+ this->symtab_,
+ this->layout_,
+ this->dirpath_,
+ this->mapfile_,
+ input_argument,
+ NULL,
+ this->this_blocker_,
+ next_blocker));
+ this->this_blocker_ = next_blocker;
+ return LDPS_OK;
+}
+
+// Class Pluginobj.
+
+Pluginobj::Pluginobj(const std::string& name, Input_file* input_file,
+ off_t offset)
+ : Object(name, input_file, false, offset),
+ nsyms_(0), syms_(NULL), symbols_(), comdat_map_()
+{
+}
+
+// Get symbol resolution info.
+
+ld_plugin_status
+Pluginobj::get_symbol_resolution_info(int nsyms, ld_plugin_symbol* syms) const
+{
+ if (this->nsyms_ == 0)
+ return LDPS_NO_SYMS;
+ for (int i = 0; i < nsyms; i++)
+ {
+ ld_plugin_symbol* isym = &syms[i];
+ Symbol* lsym = this->symbols_[i];
+ ld_plugin_symbol_resolution res = LDPR_UNKNOWN;
+
+ if (lsym->is_undefined())
+ // The symbol remains undefined.
+ res = LDPR_UNDEF;
+ else if (isym->def == LDPK_UNDEF
+ || isym->def == LDPK_WEAKUNDEF
+ || isym->def == LDPK_COMMON)
+ {
+ // The original symbol was undefined or common.
+ if (lsym->source() != Symbol::FROM_OBJECT)
+ res = LDPR_RESOLVED_EXEC;
+ else if (lsym->object()->pluginobj() != NULL)
+ res = LDPR_RESOLVED_IR;
+ else if (lsym->object()->is_dynamic())
+ res = LDPR_RESOLVED_DYN;
+ else
+ res = LDPR_RESOLVED_EXEC;
+ }
+ else
+ {
+ // The original symbol was a definition.
+ if (lsym->source() != Symbol::FROM_OBJECT)
+ res = LDPR_PREEMPTED_REG;
+ else if (lsym->object() == static_cast<const Object*>(this))
+ res = (lsym->in_real_elf()
+ ? LDPR_PREVAILING_DEF
+ : LDPR_PREVAILING_DEF_IRONLY);
+ else
+ res = (lsym->object()->pluginobj() != NULL
+ ? LDPR_PREEMPTED_IR
+ : LDPR_PREEMPTED_REG);
+ }
+ isym->resolution = res;
+ }
+ return LDPS_OK;
+}
+
+// Return TRUE if the comdat group with key COMDAT_KEY from this object
+// should be kept.
+
+bool
+Pluginobj::include_comdat_group(std::string comdat_key, Layout* layout)
+{
+ std::pair<Comdat_map::iterator, bool> ins =
+ this->comdat_map_.insert(std::make_pair(comdat_key, false));
+
+ // If this is the first time we've seen this comdat key, ask the
+ // layout object whether it should be included.
+ if (ins.second)
+ ins.first->second = layout->add_comdat(NULL, 1, comdat_key, true);
+
+ return ins.first->second;
+}
+
+// Class Sized_pluginobj.
+
+template<int size, bool big_endian>
+Sized_pluginobj<size, big_endian>::Sized_pluginobj(
+ const std::string& name,
+ Input_file* input_file,
+ off_t offset)
+ : Pluginobj(name, input_file, offset)
+{
+}
+
+// Read the symbols. Not used for plugin objects.
+
+template<int size, bool big_endian>
+void
+Sized_pluginobj<size, big_endian>::do_read_symbols(Read_symbols_data*)
+{
+ gold_unreachable();
+}
+
+// Lay out the input sections. Not used for plugin objects.
+
+template<int size, bool big_endian>
+void
+Sized_pluginobj<size, big_endian>::do_layout(Symbol_table*, Layout*,
+ Read_symbols_data*)
+{
+ gold_unreachable();
+}
+
+// Add the symbols to the symbol table.
+
+template<int size, bool big_endian>
+void
+Sized_pluginobj<size, big_endian>::do_add_symbols(Symbol_table*,
+ Read_symbols_data*)
+{
+ gold_unreachable();
+}
+
+template<int size, bool big_endian>
+void
+Sized_pluginobj<size, big_endian>::do_add_symbols(Symbol_table* symtab,
+ Layout* layout)
+{
+ const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+ unsigned char symbuf[sym_size];
+ elfcpp::Sym<size, big_endian> sym(symbuf);
+ elfcpp::Sym_write<size, big_endian> osym(symbuf);
+
+ typedef typename elfcpp::Elf_types<size>::Elf_WXword Elf_size_type;
+
+ this->symbols_.resize(this->nsyms_);
+
+ for (int i = 0; i < this->nsyms_; ++i)
+ {
+ const struct ld_plugin_symbol *isym = &this->syms_[i];
+ const char* name = isym->name;
+ const char* ver = isym->version;
+ elfcpp::Elf_Half shndx;
+ elfcpp::STB bind;
+ elfcpp::STV vis;
+
+ if (name != NULL && name[0] == '\0')
+ name = NULL;
+ if (ver != NULL && ver[0] == '\0')
+ ver = NULL;
+
+ switch (isym->def)
+ {
+ case LDPK_WEAKDEF:
+ case LDPK_WEAKUNDEF:
+ bind = elfcpp::STB_WEAK;
+ break;
+ case LDPK_DEF:
+ case LDPK_UNDEF:
+ case LDPK_COMMON:
+ default:
+ bind = elfcpp::STB_GLOBAL;
+ break;
+ }
+
+ switch (isym->def)
+ {
+ case LDPK_DEF:
+ case LDPK_WEAKDEF:
+ shndx = elfcpp::SHN_ABS;
+ break;
+ case LDPK_COMMON:
+ shndx = elfcpp::SHN_COMMON;
+ break;
+ case LDPK_UNDEF:
+ case LDPK_WEAKUNDEF:
+ default:
+ shndx = elfcpp::SHN_UNDEF;
+ break;
+ }
+
+ switch (isym->visibility)
+ {
+ case LDPV_PROTECTED:
+ vis = elfcpp::STV_DEFAULT;
+ break;
+ case LDPV_INTERNAL:
+ vis = elfcpp::STV_DEFAULT;
+ break;
+ case LDPV_HIDDEN:
+ vis = elfcpp::STV_DEFAULT;
+ break;
+ case LDPV_DEFAULT:
+ default:
+ vis = elfcpp::STV_DEFAULT;
+ break;
+ }
+
+ if (isym->comdat_key != NULL
+ && isym->comdat_key[0] != '\0'
+ && !this->include_comdat_group(isym->comdat_key, layout))
+ shndx = elfcpp::SHN_UNDEF;
+
+ osym.put_st_name(0);
+ osym.put_st_value(0);
+ osym.put_st_size(static_cast<Elf_size_type>(isym->size));
+ osym.put_st_info(bind, elfcpp::STT_NOTYPE);
+ osym.put_st_other(vis, 0);
+ osym.put_st_shndx(shndx);
+
+ this->symbols_[i] =
+ symtab->add_from_pluginobj<size, big_endian>(this, name, ver, &sym);
+ }
+}
+
+// Get the size of a section. Not used for plugin objects.
+
+template<int size, bool big_endian>
+uint64_t
+Sized_pluginobj<size, big_endian>::do_section_size(unsigned int)
+{
+ gold_unreachable();
+ return 0;
+}
+
+// Get the name of a section. Not used for plugin objects.
+
+template<int size, bool big_endian>
+std::string
+Sized_pluginobj<size, big_endian>::do_section_name(unsigned int)
+{
+ gold_unreachable();
+ return std::string();
+}
+
+// Return a view of the contents of a section. Not used for plugin objects.
+
+template<int size, bool big_endian>
+Object::Location
+Sized_pluginobj<size, big_endian>::do_section_contents(unsigned int)
+{
+ Location loc(0, 0);
+
+ gold_unreachable();
+ return loc;
+}
+
+// Return section flags. Not used for plugin objects.
+
+template<int size, bool big_endian>
+uint64_t
+Sized_pluginobj<size, big_endian>::do_section_flags(unsigned int)
+{
+ gold_unreachable();
+ return 0;
+}
+
+// Return section address. Not used for plugin objects.
+
+template<int size, bool big_endian>
+uint64_t
+Sized_pluginobj<size, big_endian>::do_section_address(unsigned int)
+{
+ gold_unreachable();
+ return 0;
+}
+
+// Return section type. Not used for plugin objects.
+
+template<int size, bool big_endian>
+unsigned int
+Sized_pluginobj<size, big_endian>::do_section_type(unsigned int)
+{
+ gold_unreachable();
+ return 0;
+}
+
+// Return the section link field. Not used for plugin objects.
+
+template<int size, bool big_endian>
+unsigned int
+Sized_pluginobj<size, big_endian>::do_section_link(unsigned int)
+{
+ gold_unreachable();
+ return 0;
+}
+
+// Return the section link field. Not used for plugin objects.
+
+template<int size, bool big_endian>
+unsigned int
+Sized_pluginobj<size, big_endian>::do_section_info(unsigned int)
+{
+ gold_unreachable();
+ return 0;
+}
+
+// Return the section alignment. Not used for plugin objects.
+
+template<int size, bool big_endian>
+uint64_t
+Sized_pluginobj<size, big_endian>::do_section_addralign(unsigned int)
+{
+ gold_unreachable();
+ return 0;
+}
+
+// Return the Xindex structure to use. Not used for plugin objects.
+
+template<int size, bool big_endian>
+Xindex*
+Sized_pluginobj<size, big_endian>::do_initialize_xindex()
+{
+ gold_unreachable();
+ return NULL;
+}
+
+// Get symbol counts. Not used for plugin objects.
+
+template<int size, bool big_endian>
+void
+Sized_pluginobj<size, big_endian>::do_get_global_symbol_counts(const Symbol_table*,
+ size_t*, size_t*) const
+{
+ gold_unreachable();
+}
+
+// Class Add_plugin_symbols.
+
+Add_plugin_symbols::~Add_plugin_symbols()
+{
+ if (this->this_blocker_ != NULL)
+ delete this->this_blocker_;
+ // next_blocker_ is deleted by the task associated with the next
+ // input file.
+}
+
+// We are blocked by this_blocker_. We block next_blocker_. We also
+// lock the file.
+
+Task_token*
+Add_plugin_symbols::is_runnable()
+{
+ if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
+ return this->this_blocker_;
+ if (this->obj_->is_locked())
+ return this->obj_->token();
+ return NULL;
+}
+
+void
+Add_plugin_symbols::locks(Task_locker* tl)
+{
+ tl->add(this, this->next_blocker_);
+ tl->add(this, this->obj_->token());
+}
+
+// Add the symbols in the object to the symbol table.
+
+void
+Add_plugin_symbols::run(Workqueue*)
+{
+ this->obj_->add_symbols(this->symtab_, this->layout_);
+}
+
+// Class Plugin_cleanup. This task calls the plugin cleanup hooks once all
+// replacement files have been added.
+
+class Plugin_cleanup : public Task
+{
+ public:
+ Plugin_cleanup(Task_token* this_blocker, Task_token* next_blocker)
+ : this_blocker_(this_blocker), next_blocker_(next_blocker)
+ { }
+
+ ~Plugin_cleanup()
+ {
+ if (this->this_blocker_ != NULL)
+ delete this->this_blocker_;
+ }
+
+ Task_token*
+ is_runnable()
+ {
+ if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
+ return this->this_blocker_;
+ return NULL;
+ }
+
+ void
+ locks(Task_locker* tl)
+ { tl->add(this, this->next_blocker_); }
+
+ void
+ run(Workqueue*)
+ { parameters->options().plugins()->cleanup(); }
+
+ std::string
+ get_name() const
+ { return "Plugin_cleanup"; }
+
+ private:
+ Task_token* this_blocker_;
+ Task_token* next_blocker_;
+};
+
+// Class Plugin_hook.
+
+Plugin_hook::~Plugin_hook()
+{
+}
+
+// Return whether a Plugin_hook task is runnable.
+
+Task_token*
+Plugin_hook::is_runnable()
+{
+ if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
+ return this->this_blocker_;
+ return NULL;
+}
+
+// Return a Task_locker for a Plugin_hook task. We don't need any
+// locks here.
+
+void
+Plugin_hook::locks(Task_locker*)
+{
+}
+
+// Run a Plugin_hook task.
+
+void
+Plugin_hook::run(Workqueue* workqueue)
+{
+ this->do_plugin_hook(workqueue);
+}
+
+// Run the "all symbols read" plugin hook.
+
+void
+Plugin_hook::do_plugin_hook(Workqueue* workqueue)
+{
+ gold_assert(this->options_.has_plugins());
+ this->options_.plugins()->all_symbols_read(workqueue,
+ this->input_objects_,
+ this->symtab_,
+ this->layout_,
+ this->dirpath_,
+ this->mapfile_,
+ &this->this_blocker_);
+ workqueue->queue_soon(new Plugin_cleanup(this->this_blocker_,
+ this->next_blocker_));
+}
+
+// The C interface routines called by the plugins.
+
+#ifdef ENABLE_PLUGINS
+
+// Register a claim-file handler.
+
+static enum ld_plugin_status
+register_claim_file(ld_plugin_claim_file_handler handler)
+{
+ gold_assert(parameters->options().has_plugins());
+ parameters->options().plugins()->set_claim_file_handler(handler);
+ return LDPS_OK;
+}
+
+// Register an all-symbols-read handler.
+
+static enum ld_plugin_status
+register_all_symbols_read(ld_plugin_all_symbols_read_handler handler)
+{
+ gold_assert(parameters->options().has_plugins());
+ parameters->options().plugins()->set_all_symbols_read_handler(handler);
+ return LDPS_OK;
+}
+
+// Register a cleanup handler.
+
+static enum ld_plugin_status
+register_cleanup(ld_plugin_cleanup_handler handler)
+{
+ gold_assert(parameters->options().has_plugins());
+ parameters->options().plugins()->set_cleanup_handler(handler);
+ return LDPS_OK;
+}
+
+// Add symbols from a plugin-claimed input file.
+
+static enum ld_plugin_status
+add_symbols(void* handle, int nsyms, const ld_plugin_symbol *syms)
+{
+ gold_assert(parameters->options().has_plugins());
+ Pluginobj* obj = parameters->options().plugins()->make_plugin_object(
+ static_cast<unsigned int>(reinterpret_cast<intptr_t>(handle)));
+ if (obj == NULL)
+ return LDPS_ERR;
+ obj->store_incoming_symbols(nsyms, syms);
+ return LDPS_OK;
+}
+
+// Get the symbol resolution info for a plugin-claimed input file.
+
+static enum ld_plugin_status
+get_symbols(const void * handle, int nsyms, ld_plugin_symbol* syms)
+{
+ gold_assert(parameters->options().has_plugins());
+ Pluginobj* obj = parameters->options().plugins()->object(
+ static_cast<unsigned int>(reinterpret_cast<intptr_t>(handle)));
+ if (obj == NULL)
+ return LDPS_ERR;
+ return obj->get_symbol_resolution_info(nsyms, syms);
+}
+
+// Add a new (real) input file generated by a plugin.
+
+static enum ld_plugin_status
+add_input_file(char *pathname)
+{
+ gold_assert(parameters->options().has_plugins());
+ return parameters->options().plugins()->add_input_file(pathname);
+}
+
+// Issue a diagnostic message from a plugin.
+
+static enum ld_plugin_status
+message(int level, char * format, ...)
+{
+ va_list args;
+ va_start(args, format);
+
+ switch (level)
+ {
+ case LDPL_INFO:
+ parameters->errors()->info(format, args);
+ break;
+ case LDPL_WARNING:
+ parameters->errors()->warning(format, args);
+ break;
+ case LDPL_ERROR:
+ default:
+ parameters->errors()->error(format, args);
+ break;
+ case LDPL_FATAL:
+ parameters->errors()->fatal(format, args);
+ break;
+ }
+
+ va_end(args);
+ return LDPS_OK;
+}
+
+#endif // ENABLE_PLUGINS
+
+// Allocate a Pluginobj object of the appropriate size and endianness.
+
+static Pluginobj*
+make_sized_plugin_object(Input_file* input_file, off_t offset)
+{
+ Target* target;
+ Pluginobj* obj = NULL;
+
+ if (parameters->target_valid())
+ target = const_cast<Target*>(&parameters->target());
+ else
+ target = const_cast<Target*>(&parameters->default_target());
+
+ if (target->get_size() == 32)
+ {
+#ifdef HAVE_TARGET_32_BIG
+ if (target->is_big_endian())
+ obj = new Sized_pluginobj<32, true>(input_file->filename(),
+ input_file, offset);
+#endif
+#ifdef HAVE_TARGET_32_LITTLE
+ else
+ obj = new Sized_pluginobj<32, false>(input_file->filename(),
+ input_file, offset);
+#endif
+ }
+ else if (target->get_size() == 64)
+ {
+#ifdef HAVE_TARGET_64_BIG
+ if (target->is_big_endian())
+ obj = new Sized_pluginobj<64, true>(input_file->filename(),
+ input_file, offset);
+#endif
+#ifdef HAVE_TARGET_64_LITTLE
+ else
+ obj = new Sized_pluginobj<64, false>(input_file->filename(),
+ input_file, offset);
+#endif
+ }
+
+ gold_assert(obj != NULL);
+ obj->set_target(target);
+ return obj;
+}
+
+} // End namespace gold.
diff --git a/gold/plugin.h b/gold/plugin.h
new file mode 100644
index 00000000000..3f573ced27b
--- /dev/null
+++ b/gold/plugin.h
@@ -0,0 +1,457 @@
+// plugin.h -- plugin manager for gold -*- C++ -*-
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Cary Coutant <ccoutant@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.
+
+#ifndef GOLD_PLUGIN_H
+#define GOLD_PLUGIN_H
+
+#include <list>
+#include <string>
+
+#include "object.h"
+#include "plugin-api.h"
+#include "workqueue.h"
+
+namespace gold
+{
+
+class General_options;
+class Input_file;
+class Input_objects;
+class Symbol_table;
+class Layout;
+class Dirsearch;
+class Mapfile;
+class Task_token;
+class Pluginobj;
+
+// This class represents a single plugin library.
+
+class Plugin
+{
+ public:
+ Plugin(const char* args)
+ : handle_(NULL),
+ args_(args),
+ claim_file_handler_(NULL),
+ all_symbols_read_handler_(NULL),
+ cleanup_handler_(NULL)
+ { }
+
+ ~Plugin()
+ { }
+
+ // Load the library and call its entry point.
+ void
+ load();
+
+ // Call the claim-file handler.
+ bool
+ claim_file(struct ld_plugin_input_file *plugin_input_file);
+
+ // Call the all-symbols-read handler.
+ void
+ all_symbols_read();
+
+ // Call the cleanup handler.
+ void
+ cleanup();
+
+ // Register a claim-file handler.
+ void
+ set_claim_file_handler(ld_plugin_claim_file_handler handler)
+ { this->claim_file_handler_ = handler; }
+
+ // Register an all-symbols-read handler.
+ void
+ set_all_symbols_read_handler(ld_plugin_all_symbols_read_handler handler)
+ { this->all_symbols_read_handler_ = handler; }
+
+ // Register a claim-file handler.
+ void
+ set_cleanup_handler(ld_plugin_cleanup_handler handler)
+ { this->cleanup_handler_ = handler; }
+
+ private:
+ Plugin(const Plugin&);
+ Plugin& operator=(const Plugin&);
+
+ // The shared library handle returned by dlopen.
+ void* handle_;
+ // The argument string given to --plugin.
+ const char* args_;
+ // The plugin's event handlers.
+ ld_plugin_claim_file_handler claim_file_handler_;
+ ld_plugin_all_symbols_read_handler all_symbols_read_handler_;
+ ld_plugin_cleanup_handler cleanup_handler_;
+};
+
+// A manager class for plugins.
+
+class Plugin_manager
+{
+ public:
+ Plugin_manager(const General_options& options)
+ : plugins_(), in_replacement_phase_(false), options_(options),
+ workqueue_(NULL), input_objects_(NULL), symtab_(NULL), layout_(NULL),
+ dirpath_(NULL), mapfile_(NULL), this_blocker_(NULL)
+ { this->current_ = plugins_.end(); }
+
+ ~Plugin_manager();
+
+ // Add a plugin library.
+ void
+ add_plugin(const char* args)
+ { this->plugins_.push_back(new Plugin(args)); }
+
+ // Load all plugin libraries.
+ void
+ load_plugins();
+
+ // Call the plugin claim-file handlers in turn to see if any claim the file.
+ Pluginobj*
+ claim_file(Input_file *input_file, off_t offset, off_t filesize);
+
+ // Call the all-symbols-read handlers.
+ void
+ all_symbols_read(Workqueue* workqueue, Input_objects* input_objects,
+ Symbol_table* symtab, Layout* layout, Dirsearch* dirpath,
+ Mapfile* mapfile, Task_token** last_blocker);
+
+ // Call the cleanup handlers.
+ void
+ cleanup();
+
+ // Register a claim-file handler.
+ void
+ set_claim_file_handler(ld_plugin_claim_file_handler handler)
+ {
+ gold_assert(this->current_ != plugins_.end());
+ (*this->current_)->set_claim_file_handler(handler);
+ }
+
+ // Register an all-symbols-read handler.
+ void
+ set_all_symbols_read_handler(ld_plugin_all_symbols_read_handler handler)
+ {
+ gold_assert(this->current_ != plugins_.end());
+ (*this->current_)->set_all_symbols_read_handler(handler);
+ }
+
+ // Register a claim-file handler.
+ void
+ set_cleanup_handler(ld_plugin_cleanup_handler handler)
+ {
+ gold_assert(this->current_ != plugins_.end());
+ (*this->current_)->set_cleanup_handler(handler);
+ }
+
+ // Make a new Pluginobj object. This is called when the plugin calls
+ // the add_symbols API.
+ Pluginobj*
+ make_plugin_object(unsigned int handle);
+
+ // Return the Pluginobj associated with the given HANDLE.
+ Pluginobj*
+ object(unsigned int handle) const
+ {
+ if (handle >= this->objects_.size())
+ return NULL;
+ return this->objects_[handle];
+ }
+
+ // Add a new input file.
+ ld_plugin_status
+ add_input_file(char *pathname);
+
+ // Return TRUE if we are in the replacement phase.
+ bool
+ in_replacement_phase() const
+ { return this->in_replacement_phase_; }
+
+ private:
+ Plugin_manager(const Plugin_manager&);
+ Plugin_manager& operator=(const Plugin_manager&);
+
+ typedef std::list<Plugin*> Plugin_list;
+ typedef std::vector<Pluginobj*> Object_list;
+
+ // The list of plugin libraries.
+ Plugin_list plugins_;
+ // A pointer to the current plugin. Used while loading plugins.
+ Plugin_list::iterator current_;
+
+ // The list of plugin objects. The index of an item in this list
+ // serves as the "handle" that we pass to the plugins.
+ Object_list objects_;
+
+ // The file currently up for claim by the plugins.
+ Input_file* input_file_;
+ struct ld_plugin_input_file plugin_input_file_;
+
+ // TRUE after the all symbols read event; indicates that we are
+ // processing replacement files whose symbols should replace the
+ // placeholder symbols from the Pluginobj objects.
+ bool in_replacement_phase_;
+
+ const General_options& options_;
+ Workqueue* workqueue_;
+ Input_objects* input_objects_;
+ Symbol_table* symtab_;
+ Layout* layout_;
+ Dirsearch* dirpath_;
+ Mapfile* mapfile_;
+ Task_token* this_blocker_;
+};
+
+
+// An object file claimed by a plugin. This is an abstract base class.
+// The implementation is the template class Sized_pluginobj.
+
+class Pluginobj : public Object
+{
+ public:
+
+ typedef std::vector<Symbol*> Symbols;
+
+ Pluginobj(const std::string& name, Input_file* input_file, off_t offset);
+
+ // Fill in the symbol resolution status for the given plugin symbols.
+ ld_plugin_status
+ get_symbol_resolution_info(int nsyms, ld_plugin_symbol* syms) const;
+
+ // Add symbol information to the global symbol table.
+ void
+ add_symbols(Symbol_table* symtab, Layout* layout)
+ { this->do_add_symbols(symtab, layout); }
+
+ // Store the incoming symbols from the plugin for later processing.
+ void
+ store_incoming_symbols(int nsyms, const struct ld_plugin_symbol* syms)
+ {
+ this->nsyms_ = nsyms;
+ this->syms_ = syms;
+ }
+
+ // Return TRUE if the comdat group with key COMDAT_KEY from this object
+ // should be kept.
+ bool
+ include_comdat_group(std::string comdat_key, Layout* layout);
+
+ protected:
+ // Return TRUE if this is an object claimed by a plugin.
+ virtual Pluginobj*
+ do_pluginobj()
+ { return this; }
+
+ // Add symbol information to the global symbol table--implemented by
+ // child class.
+ virtual void
+ do_add_symbols(Symbol_table*, Layout*) = 0;
+
+ // The number of symbols provided by the plugin.
+ int nsyms_;
+
+ // The symbols provided by the plugin.
+ const struct ld_plugin_symbol* syms_;
+
+ // The entries in the symbol table for the external symbols.
+ Symbols symbols_;
+
+ private:
+ // Map a comdat key symbol to a boolean indicating whether the comdat
+ // group in this object with that key should be kept.
+ typedef Unordered_map<std::string, bool> Comdat_map;
+ Comdat_map comdat_map_;
+};
+
+// A plugin object, size-specific version.
+
+template<int size, bool big_endian>
+class Sized_pluginobj : public Pluginobj
+{
+ public:
+ Sized_pluginobj(const std::string& name, Input_file* input_file,
+ off_t offset);
+
+ // Read the symbols.
+ void
+ do_read_symbols(Read_symbols_data*);
+
+ // Lay out the input sections.
+ void
+ do_layout(Symbol_table*, Layout*, Read_symbols_data*);
+
+ // Add the symbols to the symbol table.
+ void
+ do_add_symbols(Symbol_table*, Read_symbols_data*);
+
+ void
+ do_add_symbols(Symbol_table*, Layout*);
+
+ // Get the size of a section.
+ uint64_t
+ do_section_size(unsigned int shndx);
+
+ // Get the name of a section.
+ std::string
+ do_section_name(unsigned int shndx);
+
+ // Return a view of the contents of a section.
+ Object::Location
+ do_section_contents(unsigned int shndx);
+
+ // Return section flags.
+ uint64_t
+ do_section_flags(unsigned int shndx);
+
+ // Return section address.
+ uint64_t
+ do_section_address(unsigned int shndx);
+
+ // Return section type.
+ unsigned int
+ do_section_type(unsigned int shndx);
+
+ // Return the section link field.
+ unsigned int
+ do_section_link(unsigned int shndx);
+
+ // Return the section link field.
+ unsigned int
+ do_section_info(unsigned int shndx);
+
+ // Return the section alignment.
+ uint64_t
+ do_section_addralign(unsigned int shndx);
+
+ // Return the Xindex structure to use.
+ Xindex*
+ do_initialize_xindex();
+
+ // Get symbol counts.
+ void
+ do_get_global_symbol_counts(const Symbol_table*, size_t*, size_t*) const;
+
+ // Add placeholder symbols from a claimed file.
+ ld_plugin_status
+ add_symbols_from_plugin(int nsyms, const ld_plugin_symbol* syms);
+
+ protected:
+
+ private:
+};
+
+// This Task handles adding the symbols to the symbol table. These
+// tasks must be run in the same order as the arguments appear on the
+// command line.
+
+class Add_plugin_symbols : public Task
+{
+ public:
+ // THIS_BLOCKER is used to prevent this task from running before the
+ // one for the previous input file. NEXT_BLOCKER is used to prevent
+ // the next task from running.
+ Add_plugin_symbols(Symbol_table* symtab,
+ Layout* layout,
+ Pluginobj* obj,
+ Task_token* this_blocker,
+ Task_token* next_blocker)
+ : symtab_(symtab), layout_(layout), obj_(obj),
+ this_blocker_(this_blocker), next_blocker_(next_blocker)
+ { }
+
+ ~Add_plugin_symbols();
+
+ // The standard Task methods.
+
+ Task_token*
+ is_runnable();
+
+ void
+ locks(Task_locker*);
+
+ void
+ run(Workqueue*);
+
+ std::string
+ get_name() const
+ { return "Add_plugin_symbols " + this->obj_->name(); }
+
+private:
+ Symbol_table* symtab_;
+ Layout* layout_;
+ Pluginobj* obj_;
+ Task_token* this_blocker_;
+ Task_token* next_blocker_;
+};
+
+// This Task handles handles the "all symbols read" event hook.
+// The plugin may add additional input files at this time, which must
+// be queued for reading.
+
+class Plugin_hook : public Task
+{
+ public:
+ Plugin_hook(const General_options& options, Input_objects* input_objects,
+ Symbol_table* symtab, Layout* layout, Dirsearch* dirpath,
+ Mapfile* mapfile, Task_token* this_blocker,
+ Task_token* next_blocker)
+ : options_(options), input_objects_(input_objects), symtab_(symtab),
+ layout_(layout), dirpath_(dirpath), mapfile_(mapfile),
+ this_blocker_(this_blocker), next_blocker_(next_blocker)
+ { }
+
+ ~Plugin_hook();
+
+ // The standard Task methods.
+
+ Task_token*
+ is_runnable();
+
+ void
+ locks(Task_locker*);
+
+ void
+ run(Workqueue*);
+
+ std::string
+ get_name() const
+ { return "Plugin_hook"; }
+
+ private:
+ // Call the plugin hook.
+ void
+ do_plugin_hook(Workqueue*);
+
+ const General_options& options_;
+ Input_objects* input_objects_;
+ Symbol_table* symtab_;
+ Layout* layout_;
+ Dirsearch* dirpath_;
+ Mapfile* mapfile_;
+ Task_token* this_blocker_;
+ Task_token* next_blocker_;
+};
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_PLUGIN_H)
diff --git a/gold/readsyms.cc b/gold/readsyms.cc
index 05c80f8ff74..ac646d95d1c 100644
--- a/gold/readsyms.cc
+++ b/gold/readsyms.cc
@@ -32,6 +32,7 @@
#include "archive.h"
#include "script.h"
#include "readsyms.h"
+#include "plugin.h"
namespace gold
{
@@ -159,6 +160,53 @@ Read_symbols::do_read_symbols(Workqueue* workqueue)
const unsigned char* ehdr = input_file->file().get_view(0, 0, read_size,
true, false);
+ if (read_size >= Archive::sarmag)
+ {
+ bool is_thin_archive
+ = memcmp(ehdr, Archive::armagt, Archive::sarmag) == 0;
+ if (is_thin_archive
+ || memcmp(ehdr, Archive::armag, Archive::sarmag) == 0)
+ {
+ // This is an archive.
+ Archive* arch = new Archive(this->input_argument_->file().name(),
+ input_file, is_thin_archive,
+ this->dirpath_, this);
+ arch->setup(this->input_objects_);
+
+ // Unlock the archive so it can be used in the next task.
+ arch->unlock(this);
+
+ workqueue->queue_next(new Add_archive_symbols(this->symtab_,
+ this->layout_,
+ this->input_objects_,
+ this->mapfile_,
+ arch,
+ this->input_group_,
+ this->this_blocker_,
+ this->next_blocker_));
+ return true;
+ }
+ }
+
+ if (parameters->options().has_plugins())
+ {
+ Pluginobj* obj = parameters->options().plugins()->claim_file(input_file,
+ 0, filesize);
+ if (obj != NULL)
+ {
+ // The input file was claimed by a plugin, and its symbols
+ // have been provided by the plugin.
+ input_file->file().claim_for_plugin();
+ input_file->file().unlock(this);
+ workqueue->queue_next(new Add_plugin_symbols(this->symtab_,
+ this->layout_,
+ obj,
+ this->this_blocker_,
+ this->next_blocker_));
+ return true;
+ }
+ }
+
if (read_size >= 4)
{
static unsigned char elfmagic[4] =
@@ -201,34 +249,6 @@ Read_symbols::do_read_symbols(Workqueue* workqueue)
}
}
- if (read_size >= Archive::sarmag)
- {
- bool is_thin_archive
- = memcmp(ehdr, Archive::armagt, Archive::sarmag) == 0;
- if (is_thin_archive
- || memcmp(ehdr, Archive::armag, Archive::sarmag) == 0)
- {
- // This is an archive.
- Archive* arch = new Archive(this->input_argument_->file().name(),
- input_file, is_thin_archive,
- this->dirpath_, this);
- arch->setup(this->input_objects_);
-
- // Unlock the archive so it can be used in the next task.
- arch->unlock(this);
-
- workqueue->queue_next(new Add_archive_symbols(this->symtab_,
- this->layout_,
- this->input_objects_,
- this->mapfile_,
- arch,
- this->input_group_,
- this->this_blocker_,
- this->next_blocker_));
- return true;
- }
- }
-
// Queue up a task to try to parse this file as a script. We use a
// separate task so that the script will be read in order with other
// objects named on the command line. Also so that we don't try to
diff --git a/gold/resolve.cc b/gold/resolve.cc
index 0ad990cd055..17544f82a5c 100644
--- a/gold/resolve.cc
+++ b/gold/resolve.cc
@@ -26,6 +26,7 @@
#include "target.h"
#include "object.h"
#include "symtab.h"
+#include "plugin.h"
namespace gold
{
@@ -240,6 +241,24 @@ Symbol_table::resolve(Sized_symbol<size>* to,
to->set_in_dyn();
}
+ // Record if we've seen this symbol in a real ELF object (i.e., the
+ // symbol is referenced from outside the world known to the plugin).
+ if (object->pluginobj() == NULL)
+ to->set_in_real_elf();
+
+ // If we're processing replacement files, allow new symbols to override
+ // the placeholders from the plugin objects.
+ if (to->source() == Symbol::FROM_OBJECT)
+ {
+ Pluginobj* obj = to->object()->pluginobj();
+ if (obj != NULL
+ && parameters->options().plugins()->in_replacement_phase())
+ {
+ this->override(to, sym, st_shndx, is_ordinary, object, version);
+ return;
+ }
+ }
+
unsigned int frombits = symbol_to_bits(sym.get_st_bind(),
object->is_dynamic(),
st_shndx, is_ordinary,
diff --git a/gold/symtab.cc b/gold/symtab.cc
index 393d71aceac..3bb88d8b2be 100644
--- a/gold/symtab.cc
+++ b/gold/symtab.cc
@@ -37,6 +37,7 @@
#include "target.h"
#include "workqueue.h"
#include "symtab.h"
+#include "plugin.h"
namespace gold
{
@@ -73,6 +74,7 @@ Symbol::init_fields(const char* name, const char* version,
this->is_copied_from_dynobj_ = false;
this->is_forced_local_ = false;
this->is_ordinary_shndx_ = false;
+ this->in_real_elf_ = false;
}
// Return the demangled version of the symbol's name, but only
@@ -117,6 +119,7 @@ Symbol::init_base_object(const char* name, const char* version, Object* object,
this->source_ = FROM_OBJECT;
this->in_reg_ = !object->is_dynamic();
this->in_dyn_ = object->is_dynamic();
+ this->in_real_elf_ = object->pluginobj() == NULL;
}
// Initialize the fields in the base class Symbol for a symbol defined
@@ -133,6 +136,7 @@ Symbol::init_base_output_data(const char* name, const char* version,
this->u_.in_output_data.offset_is_from_end = offset_is_from_end;
this->source_ = IN_OUTPUT_DATA;
this->in_reg_ = true;
+ this->in_real_elf_ = true;
}
// Initialize the fields in the base class Symbol for a symbol defined
@@ -150,6 +154,7 @@ Symbol::init_base_output_segment(const char* name, const char* version,
this->u_.in_output_segment.offset_base = offset_base;
this->source_ = IN_OUTPUT_SEGMENT;
this->in_reg_ = true;
+ this->in_real_elf_ = true;
}
// Initialize the fields in the base class Symbol for a symbol defined
@@ -163,6 +168,7 @@ Symbol::init_base_constant(const char* name, const char* version,
this->init_fields(name, version, type, binding, visibility, nonvis);
this->source_ = IS_CONSTANT;
this->in_reg_ = true;
+ this->in_real_elf_ = true;
}
// Initialize the fields in the base class Symbol for an undefined
@@ -177,6 +183,7 @@ Symbol::init_base_undefined(const char* name, const char* version,
this->dynsym_index_ = -1U;
this->source_ = IS_UNDEFINED;
this->in_reg_ = true;
+ this->in_real_elf_ = true;
}
// Allocate a common symbol in the base.
@@ -357,6 +364,7 @@ Symbol::output_section() const
if (shndx != elfcpp::SHN_UNDEF && this->is_ordinary_shndx_)
{
gold_assert(!this->u_.from_object.object->is_dynamic());
+ gold_assert(this->u_.from_object.object->pluginobj() == NULL);
Relobj* relobj = static_cast<Relobj*>(this->u_.from_object.object);
return relobj->output_section(shndx);
}
@@ -973,6 +981,68 @@ Symbol_table::add_from_relobj(
}
}
+// Add a symbol from a plugin-claimed file.
+
+template<int size, bool big_endian>
+Symbol*
+Symbol_table::add_from_pluginobj(
+ Sized_pluginobj<size, big_endian>* obj,
+ const char* name,
+ const char* ver,
+ elfcpp::Sym<size, big_endian>* sym)
+{
+ unsigned int st_shndx = sym->get_st_shndx();
+
+ Stringpool::Key ver_key = 0;
+ bool def = false;
+ bool local = false;
+
+ if (ver != NULL)
+ {
+ ver = this->namepool_.add(ver, true, &ver_key);
+ }
+ // We don't want to assign a version to an undefined symbol,
+ // even if it is listed in the version script. FIXME: What
+ // about a common symbol?
+ else
+ {
+ if (!this->version_script_.empty()
+ && st_shndx != elfcpp::SHN_UNDEF)
+ {
+ // The symbol name did not have a version, but the
+ // version script may assign a version anyway.
+ std::string version;
+ if (this->version_script_.get_symbol_version(name, &version))
+ {
+ // The version can be empty if the version script is
+ // only used to force some symbols to be local.
+ if (!version.empty())
+ {
+ ver = this->namepool_.add_with_length(version.c_str(),
+ version.length(),
+ true,
+ &ver_key);
+ def = true;
+ }
+ }
+ else if (this->version_script_.symbol_is_local(name))
+ local = true;
+ }
+ }
+
+ Stringpool::Key name_key;
+ name = this->namepool_.add(name, true, &name_key);
+
+ Sized_symbol<size>* res;
+ res = this->add_from_object(obj, name, name_key, ver, ver_key,
+ def, *sym, st_shndx, true, st_shndx);
+
+ if (local)
+ this->force_local(res);
+
+ return res;
+}
+
// Add all the symbols in a dynamic object to the hash table.
template<int size, bool big_endian>
@@ -2043,6 +2113,11 @@ Symbol_table::sized_finalize_symbol(Symbol* unsized_sym)
value = 0;
shndx = elfcpp::SHN_UNDEF;
}
+ else if (symobj->pluginobj() != NULL)
+ {
+ value = 0;
+ shndx = elfcpp::SHN_UNDEF;
+ }
else if (shndx == elfcpp::SHN_UNDEF)
value = 0;
else if (!is_ordinary
@@ -2261,6 +2336,8 @@ Symbol_table::sized_write_globals(const Input_objects* input_objects,
dynsym_value = target.dynsym_value(sym);
shndx = elfcpp::SHN_UNDEF;
}
+ else if (symobj->pluginobj() != NULL)
+ shndx = elfcpp::SHN_UNDEF;
else if (in_shndx == elfcpp::SHN_UNDEF
|| (!is_ordinary
&& (in_shndx == elfcpp::SHN_ABS
@@ -2703,6 +2780,46 @@ Symbol_table::add_from_relobj<64, true>(
#ifdef HAVE_TARGET_32_LITTLE
template
+Symbol*
+Symbol_table::add_from_pluginobj<32, false>(
+ Sized_pluginobj<32, false>* obj,
+ const char* name,
+ const char* ver,
+ elfcpp::Sym<32, false>* sym);
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+Symbol*
+Symbol_table::add_from_pluginobj<32, true>(
+ Sized_pluginobj<32, true>* obj,
+ const char* name,
+ const char* ver,
+ elfcpp::Sym<32, true>* sym);
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+Symbol*
+Symbol_table::add_from_pluginobj<64, false>(
+ Sized_pluginobj<64, false>* obj,
+ const char* name,
+ const char* ver,
+ elfcpp::Sym<64, false>* sym);
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+Symbol*
+Symbol_table::add_from_pluginobj<64, true>(
+ Sized_pluginobj<64, true>* obj,
+ const char* name,
+ const char* ver,
+ elfcpp::Sym<64, true>* sym);
+#endif
+
+#ifdef HAVE_TARGET_32_LITTLE
+template
void
Symbol_table::add_from_dynobj<32, false>(
Sized_dynobj<32, false>* dynobj,
diff --git a/gold/symtab.h b/gold/symtab.h
index 043fb50f228..cfd0c73d423 100644
--- a/gold/symtab.h
+++ b/gold/symtab.h
@@ -43,6 +43,8 @@ class Object;
class Relobj;
template<int size, bool big_endian>
class Sized_relobj;
+template<int size, bool big_endian>
+class Sized_pluginobj;
class Dynobj;
template<int size, bool big_endian>
class Sized_dynobj;
@@ -273,6 +275,18 @@ class Symbol
set_in_dyn()
{ this->in_dyn_ = true; }
+ // Return whether this symbol has been seen in a real ELF object.
+ // (IN_REG will return TRUE if the symbol has been seen in either
+ // a real ELF object or an object claimed by a plugin.)
+ bool
+ in_real_elf() const
+ { return this->in_real_elf_; }
+
+ // Mark this symbol as having been seen in a real ELF object.
+ void
+ set_in_real_elf()
+ { this->in_real_elf_ = true; }
+
// Return the index of this symbol in the output file symbol table.
// A value of -1U means that this symbol is not going into the
// output file. This starts out as zero, and is set to a non-zero
@@ -871,8 +885,10 @@ class Symbol
bool is_forced_local_ : 1;
// True if the field u_.from_object.shndx is an ordinary section
// index, not one of the special codes from SHN_LORESERVE to
- // SHN_HIRESERVE.
+ // SHN_HIRESERVE (bit 31).
bool is_ordinary_shndx_ : 1;
+ // True if we've seen this symbol in a real ELF object.
+ bool in_real_elf_ : 1;
};
// The parts of a symbol which are size specific. Using a template
@@ -1139,6 +1155,14 @@ class Symbol_table
typename Sized_relobj<size, big_endian>::Symbols*,
size_t* defined);
+ // Add one external symbol from the plugin object OBJ to the symbol table.
+ // Returns a pointer to the resolved symbol in the symbol table.
+ template<int size, bool big_endian>
+ Symbol*
+ add_from_pluginobj(Sized_pluginobj<size, big_endian>* obj,
+ const char* name, const char* ver,
+ elfcpp::Sym<size, big_endian>* sym);
+
// Add COUNT dynamic symbols from the dynamic object DYNOBJ to the
// symbol table. SYMS is the symbols. SYM_NAMES is their names.
// SYM_NAME_SIZE is the size of SYM_NAMES. The other parameters are
diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am
index 1f08b5a30a9..14efd73093c 100644
--- a/gold/testsuite/Makefile.am
+++ b/gold/testsuite/Makefile.am
@@ -9,6 +9,7 @@ AUTOMAKE_OPTIONS =
# The two_file_test tests -fmerge-constants, so we simply always turn
# it on. This may need to be controlled by a configure option
# eventually.
+AM_CFLAGS = $(WARN_CFLAGS) $(LFS_CFLAGS) -fmerge-constants
AM_CXXFLAGS = $(WARN_CXXFLAGS) $(LFS_CFLAGS) -fmerge-constants
INCLUDES = \
@@ -22,6 +23,10 @@ TEST_OBJDUMP = $(top_builddir)/../binutils/objdump
TEST_CXXFILT = $(top_builddir)/../binutils/cxxfilt
TEST_STRIP = $(top_builddir)/../binutils/strip-new
+if PLUGINS
+LIBDL = -ldl
+endif
+
if THREADS
THREADSLIB = -lpthread
endif
@@ -57,7 +62,7 @@ libgoldtest_a_SOURCES = test.cc testmain.cc testfile.cc
DEPENDENCIES = \
libgoldtest.a ../libgold.a ../../libiberty/libiberty.a $(LIBINTL_DEP)
LDADD = libgoldtest.a ../libgold.a ../../libiberty/libiberty.a $(LIBINTL) \
- $(THREADSLIB)
+ $(THREADSLIB) $(LIBDL)
# The unittests themselves
@@ -897,5 +902,41 @@ 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
+if PLUGINS
+
+check_PROGRAMS += plugin_test_1
+check_SCRIPTS += plugin_test_1.sh
+check_DATA += plugin_test_1.err
+MOSTLYCLEANFILES += plugin_test_1.err
+plugin_test_1: two_file_test_main.o two_file_test_1.syms two_file_test_1b.syms two_file_test_2.syms gcctestdir/ld plugin_test.so
+ $(CXXLINK) -Bgcctestdir/ -Wl,--no-demangle,--plugin,"./plugin_test.so;_Z4f13iv" two_file_test_main.o two_file_test_1.syms two_file_test_1b.syms two_file_test_2.syms 2>plugin_test_1.err
+plugin_test_1.err: plugin_test_1
+ @touch plugin_test_1.err
+
+check_PROGRAMS += plugin_test_2
+check_SCRIPTS += plugin_test_2.sh
+check_DATA += plugin_test_2.err
+MOSTLYCLEANFILES += plugin_test_2.err
+plugin_test_2: two_file_test_main.o two_file_test_1.syms two_file_test_1b.syms two_file_shared_2.so gcctestdir/ld plugin_test.so
+ $(CXXLINK) -Bgcctestdir/ -Wl,--no-demangle,-R,.,--plugin,"./plugin_test.so" two_file_test_main.o two_file_test_1.syms two_file_test_1b.syms two_file_shared_2.so 2>plugin_test_2.err
+plugin_test_2.err: plugin_test_2
+ @touch plugin_test_2.err
+
+plugin_test.so: plugin_test.o
+ $(LINK) -Bgcctestdir/ -shared plugin_test.o
+plugin_test.o: plugin_test.c
+ $(COMPILE) -O0 -c -fpic -o $@ $<
+
+two_file_test_main.syms: two_file_test_main.o
+ $(TEST_READELF) -sW $< >$@ 2>/dev/null
+two_file_test_1.syms: two_file_test_1.o
+ $(TEST_READELF) -sW $< >$@ 2>/dev/null
+two_file_test_1b.syms: two_file_test_1b.o
+ $(TEST_READELF) -sW $< >$@ 2>/dev/null
+two_file_test_2.syms: two_file_test_2.o
+ $(TEST_READELF) -sW $< >$@ 2>/dev/null
+
+endif PLUGINS
+
endif GCC
endif NATIVE_LINKER
diff --git a/gold/testsuite/Makefile.in b/gold/testsuite/Makefile.in
index e3d8dcaef04..9860835c107 100644
--- a/gold/testsuite/Makefile.in
+++ b/gold/testsuite/Makefile.in
@@ -47,7 +47,8 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \
$(am__EXEEXT_4) $(am__EXEEXT_5) $(am__EXEEXT_6) \
$(am__EXEEXT_7) $(am__EXEEXT_8) $(am__EXEEXT_9) \
$(am__EXEEXT_10) $(am__EXEEXT_11) $(am__EXEEXT_12) \
- $(am__EXEEXT_13) $(am__EXEEXT_14) $(am__EXEEXT_15)
+ $(am__EXEEXT_13) $(am__EXEEXT_14) $(am__EXEEXT_15) \
+ $(am__EXEEXT_16)
@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_1 = basic_test \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ basic_static_test basic_pic_test \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ basic_static_pic_test \
@@ -66,33 +67,39 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_relocatable_test
@GCC_FALSE@constructor_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
@GCC_FALSE@ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
-@GCC_FALSE@ $(am__DEPENDENCIES_1)
+@GCC_FALSE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
@NATIVE_LINKER_FALSE@constructor_test_DEPENDENCIES = libgoldtest.a \
@NATIVE_LINKER_FALSE@ ../libgold.a ../../libiberty/libiberty.a \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \
+@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1)
@GCC_FALSE@constructor_static_test_DEPENDENCIES = libgoldtest.a \
@GCC_FALSE@ ../libgold.a ../../libiberty/libiberty.a \
-@GCC_FALSE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+@GCC_FALSE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+@GCC_FALSE@ $(am__DEPENDENCIES_1)
@NATIVE_LINKER_FALSE@constructor_static_test_DEPENDENCIES = \
@NATIVE_LINKER_FALSE@ libgoldtest.a ../libgold.a \
@NATIVE_LINKER_FALSE@ ../../libiberty/libiberty.a \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \
+@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1)
@GCC_FALSE@two_file_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
@GCC_FALSE@ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
-@GCC_FALSE@ $(am__DEPENDENCIES_1)
+@GCC_FALSE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
@NATIVE_LINKER_FALSE@two_file_test_DEPENDENCIES = libgoldtest.a \
@NATIVE_LINKER_FALSE@ ../libgold.a ../../libiberty/libiberty.a \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \
+@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1)
@GCC_FALSE@two_file_static_test_DEPENDENCIES = libgoldtest.a \
@GCC_FALSE@ ../libgold.a ../../libiberty/libiberty.a \
-@GCC_FALSE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+@GCC_FALSE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+@GCC_FALSE@ $(am__DEPENDENCIES_1)
@NATIVE_LINKER_FALSE@two_file_static_test_DEPENDENCIES = \
@NATIVE_LINKER_FALSE@ libgoldtest.a ../libgold.a \
@NATIVE_LINKER_FALSE@ ../../libiberty/libiberty.a \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \
+@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1)
# The nonpic tests will fail on platforms which can not put non-PIC
@@ -116,32 +123,37 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ weak_test weak_undef_test
@GCC_FALSE@common_test_1_DEPENDENCIES = libgoldtest.a ../libgold.a \
@GCC_FALSE@ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
-@GCC_FALSE@ $(am__DEPENDENCIES_1)
+@GCC_FALSE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
@NATIVE_LINKER_FALSE@common_test_1_DEPENDENCIES = libgoldtest.a \
@NATIVE_LINKER_FALSE@ ../libgold.a ../../libiberty/libiberty.a \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \
+@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1)
@GCC_FALSE@exception_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
@GCC_FALSE@ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
-@GCC_FALSE@ $(am__DEPENDENCIES_1)
+@GCC_FALSE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
@NATIVE_LINKER_FALSE@exception_test_DEPENDENCIES = libgoldtest.a \
@NATIVE_LINKER_FALSE@ ../libgold.a ../../libiberty/libiberty.a \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \
+@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1)
@GCC_FALSE@exception_static_test_DEPENDENCIES = libgoldtest.a \
@GCC_FALSE@ ../libgold.a ../../libiberty/libiberty.a \
-@GCC_FALSE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+@GCC_FALSE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+@GCC_FALSE@ $(am__DEPENDENCIES_1)
@NATIVE_LINKER_FALSE@exception_static_test_DEPENDENCIES = \
@NATIVE_LINKER_FALSE@ libgoldtest.a ../libgold.a \
@NATIVE_LINKER_FALSE@ ../../libiberty/libiberty.a \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \
+@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1)
@GCC_FALSE@weak_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
@GCC_FALSE@ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
-@GCC_FALSE@ $(am__DEPENDENCIES_1)
+@GCC_FALSE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
@NATIVE_LINKER_FALSE@weak_test_DEPENDENCIES = libgoldtest.a \
@NATIVE_LINKER_FALSE@ ../libgold.a ../../libiberty/libiberty.a \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \
+@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1)
@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_4 = weak_undef_nonpic_test
@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_5 = weak_alias_test weak_plt \
@@ -187,10 +199,12 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ many_sections_r_test
@GCC_FALSE@many_sections_test_DEPENDENCIES = libgoldtest.a \
@GCC_FALSE@ ../libgold.a ../../libiberty/libiberty.a \
-@GCC_FALSE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+@GCC_FALSE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+@GCC_FALSE@ $(am__DEPENDENCIES_1)
@NATIVE_LINKER_FALSE@many_sections_test_DEPENDENCIES = libgoldtest.a \
@NATIVE_LINKER_FALSE@ ../libgold.a ../../libiberty/libiberty.a \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \
+@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1)
@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_14 = many_sections_define.h \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ many_sections_check.h
@@ -199,13 +213,15 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \
@CONSTRUCTOR_PRIORITY_FALSE@ ../libgold.a \
@CONSTRUCTOR_PRIORITY_FALSE@ ../../libiberty/libiberty.a \
@CONSTRUCTOR_PRIORITY_FALSE@ $(am__DEPENDENCIES_1) \
+@CONSTRUCTOR_PRIORITY_FALSE@ $(am__DEPENDENCIES_1) \
@CONSTRUCTOR_PRIORITY_FALSE@ $(am__DEPENDENCIES_1)
@GCC_FALSE@initpri1_DEPENDENCIES = libgoldtest.a ../libgold.a \
@GCC_FALSE@ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
-@GCC_FALSE@ $(am__DEPENDENCIES_1)
+@GCC_FALSE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
@NATIVE_LINKER_FALSE@initpri1_DEPENDENCIES = libgoldtest.a \
@NATIVE_LINKER_FALSE@ ../libgold.a ../../libiberty/libiberty.a \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \
+@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1)
@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_16 = debug_msg.err \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ debug_msg_so.err \
@@ -235,32 +251,48 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_3
@GCC_FALSE@script_test_1_DEPENDENCIES = libgoldtest.a ../libgold.a \
@GCC_FALSE@ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
-@GCC_FALSE@ $(am__DEPENDENCIES_1)
+@GCC_FALSE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
@NATIVE_LINKER_FALSE@script_test_1_DEPENDENCIES = libgoldtest.a \
@NATIVE_LINKER_FALSE@ ../libgold.a ../../libiberty/libiberty.a \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \
+@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1)
@GCC_FALSE@script_test_2_DEPENDENCIES = libgoldtest.a ../libgold.a \
@GCC_FALSE@ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
-@GCC_FALSE@ $(am__DEPENDENCIES_1)
+@GCC_FALSE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
@NATIVE_LINKER_FALSE@script_test_2_DEPENDENCIES = libgoldtest.a \
@NATIVE_LINKER_FALSE@ ../libgold.a ../../libiberty/libiberty.a \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \
+@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1)
@GCC_FALSE@justsyms_DEPENDENCIES = libgoldtest.a ../libgold.a \
@GCC_FALSE@ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
-@GCC_FALSE@ $(am__DEPENDENCIES_1)
+@GCC_FALSE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
@NATIVE_LINKER_FALSE@justsyms_DEPENDENCIES = libgoldtest.a \
@NATIVE_LINKER_FALSE@ ../libgold.a ../../libiberty/libiberty.a \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \
+@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1)
@GCC_FALSE@binary_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
@GCC_FALSE@ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
-@GCC_FALSE@ $(am__DEPENDENCIES_1)
+@GCC_FALSE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
@NATIVE_LINKER_FALSE@binary_test_DEPENDENCIES = libgoldtest.a \
@NATIVE_LINKER_FALSE@ ../libgold.a ../../libiberty/libiberty.a \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \
+@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__append_20 = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_1 \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_2
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__append_21 = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_1.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_2.sh
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__append_22 = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_1.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_2.err
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__append_23 = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_1.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_2.err
subdir = testsuite
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@@ -358,31 +390,33 @@ libgoldtest_a_OBJECTS = $(am_libgoldtest_a_OBJECTS)
@GCC_TRUE@@NATIVE_LINKER_TRUE@ justsyms$(EXEEXT) \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ binary_test$(EXEEXT) \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_3$(EXEEXT)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__EXEEXT_16 = plugin_test_1$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_2$(EXEEXT)
basic_pic_test_SOURCES = basic_pic_test.c
basic_pic_test_OBJECTS = basic_pic_test.$(OBJEXT)
basic_pic_test_LDADD = $(LDADD)
am__DEPENDENCIES_1 =
basic_pic_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
- $(am__DEPENDENCIES_1)
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
basic_static_pic_test_SOURCES = basic_static_pic_test.c
basic_static_pic_test_OBJECTS = basic_static_pic_test.$(OBJEXT)
basic_static_pic_test_LDADD = $(LDADD)
basic_static_pic_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
- $(am__DEPENDENCIES_1)
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
basic_static_test_SOURCES = basic_static_test.c
basic_static_test_OBJECTS = basic_static_test.$(OBJEXT)
basic_static_test_LDADD = $(LDADD)
basic_static_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
- $(am__DEPENDENCIES_1)
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
basic_test_SOURCES = basic_test.c
basic_test_OBJECTS = basic_test.$(OBJEXT)
basic_test_LDADD = $(LDADD)
basic_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
- $(am__DEPENDENCIES_1)
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
am__binary_test_SOURCES_DIST = binary_test.cc
@GCC_TRUE@@NATIVE_LINKER_TRUE@am_binary_test_OBJECTS = \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ binary_test.$(OBJEXT)
@@ -393,7 +427,7 @@ binary_unittest_OBJECTS = $(am_binary_unittest_OBJECTS)
binary_unittest_LDADD = $(LDADD)
binary_unittest_DEPENDENCIES = libgoldtest.a ../libgold.a \
../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
- $(am__DEPENDENCIES_1)
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
am__common_test_1_SOURCES_DIST = common_test_1.c
@GCC_TRUE@@NATIVE_LINKER_TRUE@am_common_test_1_OBJECTS = \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ common_test_1.$(OBJEXT)
@@ -472,13 +506,13 @@ flagstest_compress_debug_sections_OBJECTS = \
flagstest_compress_debug_sections_LDADD = $(LDADD)
flagstest_compress_debug_sections_DEPENDENCIES = libgoldtest.a \
../libgold.a ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
- $(am__DEPENDENCIES_1)
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
flagstest_o_specialfile_SOURCES = flagstest_o_specialfile.c
flagstest_o_specialfile_OBJECTS = flagstest_o_specialfile.$(OBJEXT)
flagstest_o_specialfile_LDADD = $(LDADD)
flagstest_o_specialfile_DEPENDENCIES = libgoldtest.a ../libgold.a \
../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
- $(am__DEPENDENCIES_1)
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
flagstest_o_specialfile_and_compress_debug_sections_SOURCES = \
flagstest_o_specialfile_and_compress_debug_sections.c
flagstest_o_specialfile_and_compress_debug_sections_OBJECTS = \
@@ -486,7 +520,8 @@ flagstest_o_specialfile_and_compress_debug_sections_OBJECTS = \
flagstest_o_specialfile_and_compress_debug_sections_LDADD = $(LDADD)
flagstest_o_specialfile_and_compress_debug_sections_DEPENDENCIES = \
libgoldtest.a ../libgold.a ../../libiberty/libiberty.a \
- $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
am__initpri1_SOURCES_DIST = initpri1.c
@CONSTRUCTOR_PRIORITY_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am_initpri1_OBJECTS = initpri1.$(OBJEXT)
initpri1_OBJECTS = $(am_initpri1_OBJECTS)
@@ -501,7 +536,7 @@ many_sections_r_test_OBJECTS = many_sections_r_test.$(OBJEXT)
many_sections_r_test_LDADD = $(LDADD)
many_sections_r_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
- $(am__DEPENDENCIES_1)
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
am__many_sections_test_SOURCES_DIST = many_sections_test.cc
@GCC_TRUE@@NATIVE_LINKER_TRUE@am_many_sections_test_OBJECTS = \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ many_sections_test.$(OBJEXT)
@@ -512,7 +547,19 @@ object_unittest_OBJECTS = $(am_object_unittest_OBJECTS)
object_unittest_LDADD = $(LDADD)
object_unittest_DEPENDENCIES = libgoldtest.a ../libgold.a \
../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
- $(am__DEPENDENCIES_1)
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+plugin_test_1_SOURCES = plugin_test_1.c
+plugin_test_1_OBJECTS = plugin_test_1.$(OBJEXT)
+plugin_test_1_LDADD = $(LDADD)
+plugin_test_1_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+plugin_test_2_SOURCES = plugin_test_2.c
+plugin_test_2_OBJECTS = plugin_test_2.$(OBJEXT)
+plugin_test_2_LDADD = $(LDADD)
+plugin_test_2_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
am__protected_1_SOURCES_DIST = protected_main_1.cc protected_main_2.cc \
protected_main_3.cc
@GCC_TRUE@@NATIVE_LINKER_TRUE@am_protected_1_OBJECTS = \
@@ -551,7 +598,7 @@ script_test_3_OBJECTS = script_test_3.$(OBJEXT)
script_test_3_LDADD = $(LDADD)
script_test_3_DEPENDENCIES = libgoldtest.a ../libgold.a \
../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
- $(am__DEPENDENCIES_1)
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
am__tls_pic_test_SOURCES_DIST = tls_test_main.cc
@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@am_tls_pic_test_OBJECTS = tls_test_main.$(OBJEXT)
tls_pic_test_OBJECTS = $(am_tls_pic_test_OBJECTS)
@@ -708,7 +755,7 @@ two_file_strip_test_OBJECTS = two_file_strip_test.$(OBJEXT)
two_file_strip_test_LDADD = $(LDADD)
two_file_strip_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
- $(am__DEPENDENCIES_1)
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
am__two_file_test_SOURCES_DIST = two_file_test_1.cc \
two_file_test_1b.cc two_file_test_2.cc two_file_test_main.cc \
two_file_test.h
@@ -748,7 +795,7 @@ weak_plt_OBJECTS = weak_plt.$(OBJEXT)
weak_plt_LDADD = $(LDADD)
weak_plt_DEPENDENCIES = libgoldtest.a ../libgold.a \
../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
- $(am__DEPENDENCIES_1)
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
am__weak_test_SOURCES_DIST = weak_test.cc
@GCC_TRUE@@NATIVE_LINKER_TRUE@am_weak_test_OBJECTS = \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ weak_test.$(OBJEXT)
@@ -788,11 +835,11 @@ SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c \
flagstest_o_specialfile_and_compress_debug_sections.c \
$(initpri1_SOURCES) $(justsyms_SOURCES) many_sections_r_test.c \
$(many_sections_test_SOURCES) $(object_unittest_SOURCES) \
- $(protected_1_SOURCES) $(protected_2_SOURCES) \
- $(relro_script_test_SOURCES) $(relro_test_SOURCES) \
- $(script_test_1_SOURCES) $(script_test_2_SOURCES) \
- script_test_3.c $(tls_pic_test_SOURCES) \
- $(tls_shared_gd_to_ie_test_SOURCES) \
+ plugin_test_1.c plugin_test_2.c $(protected_1_SOURCES) \
+ $(protected_2_SOURCES) $(relro_script_test_SOURCES) \
+ $(relro_test_SOURCES) $(script_test_1_SOURCES) \
+ $(script_test_2_SOURCES) script_test_3.c \
+ $(tls_pic_test_SOURCES) $(tls_shared_gd_to_ie_test_SOURCES) \
$(tls_shared_gnu2_gd_to_ie_test_SOURCES) \
$(tls_shared_gnu2_test_SOURCES) $(tls_shared_ie_test_SOURCES) \
$(tls_shared_nonpic_test_SOURCES) $(tls_shared_test_SOURCES) \
@@ -838,7 +885,8 @@ DIST_SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c \
flagstest_o_specialfile_and_compress_debug_sections.c \
$(am__initpri1_SOURCES_DIST) $(am__justsyms_SOURCES_DIST) \
many_sections_r_test.c $(am__many_sections_test_SOURCES_DIST) \
- $(object_unittest_SOURCES) $(am__protected_1_SOURCES_DIST) \
+ $(object_unittest_SOURCES) plugin_test_1.c plugin_test_2.c \
+ $(am__protected_1_SOURCES_DIST) \
$(am__protected_2_SOURCES_DIST) \
$(am__relro_script_test_SOURCES_DIST) \
$(am__relro_test_SOURCES_DIST) \
@@ -954,6 +1002,8 @@ PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
+PLUGINS_FALSE = @PLUGINS_FALSE@
+PLUGINS_TRUE = @PLUGINS_TRUE@
POSUB = @POSUB@
RANDOM_SEED_CFLAGS = @RANDOM_SEED_CFLAGS@
RANLIB = @RANLIB@
@@ -1027,6 +1077,7 @@ AUTOMAKE_OPTIONS =
# The two_file_test tests -fmerge-constants, so we simply always turn
# it on. This may need to be controlled by a configure option
# eventually.
+AM_CFLAGS = $(WARN_CFLAGS) $(LFS_CFLAGS) -fmerge-constants
AM_CXXFLAGS = $(WARN_CXXFLAGS) $(LFS_CFLAGS) -fmerge-constants
INCLUDES = \
-I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../../include \
@@ -1038,6 +1089,7 @@ TEST_READELF = $(top_builddir)/../binutils/readelf
TEST_OBJDUMP = $(top_builddir)/../binutils/objdump
TEST_CXXFILT = $(top_builddir)/../binutils/cxxfilt
TEST_STRIP = $(top_builddir)/../binutils/strip-new
+@PLUGINS_TRUE@LIBDL = -ldl
@THREADS_TRUE@THREADSLIB = -lpthread
@OMP_SUPPORT_TRUE@TLS_TEST_C_CFLAGS = -fopenmp
@@ -1045,13 +1097,13 @@ TEST_STRIP = $(top_builddir)/../binutils/strip-new
# .o's), but not all of them (such as .so's and .err files). We
# improve on that here. automake-1.9 info docs say "mostlyclean" is
# the right choice for files 'make' builds that people rebuild.
-MOSTLYCLEANFILES = *.so $(am__append_16)
+MOSTLYCLEANFILES = *.so $(am__append_16) $(am__append_23)
# We will add to these later, for each individual test. Note
# that we add each test under check_SCRIPTS or check_PROGRAMS;
# the TESTS variable is automatically populated from these.
-check_SCRIPTS = $(am__append_6)
-check_DATA = $(am__append_7)
+check_SCRIPTS = $(am__append_6) $(am__append_21)
+check_DATA = $(am__append_7) $(am__append_22)
BUILT_SOURCES = $(am__append_14)
TESTS = $(check_SCRIPTS) $(check_PROGRAMS)
@@ -1065,7 +1117,7 @@ DEPENDENCIES = \
libgoldtest.a ../libgold.a ../../libiberty/libiberty.a $(LIBINTL_DEP)
LDADD = libgoldtest.a ../libgold.a ../../libiberty/libiberty.a $(LIBINTL) \
- $(THREADSLIB)
+ $(THREADSLIB) $(LIBDL)
object_unittest_SOURCES = object_unittest.cc
binary_unittest_SOURCES = binary_unittest.cc
@@ -1515,6 +1567,24 @@ many_sections_test$(EXEEXT): $(many_sections_test_OBJECTS) $(many_sections_test_
object_unittest$(EXEEXT): $(object_unittest_OBJECTS) $(object_unittest_DEPENDENCIES)
@rm -f object_unittest$(EXEEXT)
$(CXXLINK) $(object_unittest_LDFLAGS) $(object_unittest_OBJECTS) $(object_unittest_LDADD) $(LIBS)
+@GCC_FALSE@plugin_test_1$(EXEEXT): $(plugin_test_1_OBJECTS) $(plugin_test_1_DEPENDENCIES)
+@GCC_FALSE@ @rm -f plugin_test_1$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(plugin_test_1_LDFLAGS) $(plugin_test_1_OBJECTS) $(plugin_test_1_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@plugin_test_1$(EXEEXT): $(plugin_test_1_OBJECTS) $(plugin_test_1_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f plugin_test_1$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(plugin_test_1_LDFLAGS) $(plugin_test_1_OBJECTS) $(plugin_test_1_LDADD) $(LIBS)
+@PLUGINS_FALSE@plugin_test_1$(EXEEXT): $(plugin_test_1_OBJECTS) $(plugin_test_1_DEPENDENCIES)
+@PLUGINS_FALSE@ @rm -f plugin_test_1$(EXEEXT)
+@PLUGINS_FALSE@ $(LINK) $(plugin_test_1_LDFLAGS) $(plugin_test_1_OBJECTS) $(plugin_test_1_LDADD) $(LIBS)
+@GCC_FALSE@plugin_test_2$(EXEEXT): $(plugin_test_2_OBJECTS) $(plugin_test_2_DEPENDENCIES)
+@GCC_FALSE@ @rm -f plugin_test_2$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(plugin_test_2_LDFLAGS) $(plugin_test_2_OBJECTS) $(plugin_test_2_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@plugin_test_2$(EXEEXT): $(plugin_test_2_OBJECTS) $(plugin_test_2_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f plugin_test_2$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(plugin_test_2_LDFLAGS) $(plugin_test_2_OBJECTS) $(plugin_test_2_LDADD) $(LIBS)
+@PLUGINS_FALSE@plugin_test_2$(EXEEXT): $(plugin_test_2_OBJECTS) $(plugin_test_2_DEPENDENCIES)
+@PLUGINS_FALSE@ @rm -f plugin_test_2$(EXEEXT)
+@PLUGINS_FALSE@ $(LINK) $(plugin_test_2_LDFLAGS) $(plugin_test_2_OBJECTS) $(plugin_test_2_LDADD) $(LIBS)
protected_1$(EXEEXT): $(protected_1_OBJECTS) $(protected_1_DEPENDENCIES)
@rm -f protected_1$(EXEEXT)
$(CXXLINK) $(protected_1_LDFLAGS) $(protected_1_OBJECTS) $(protected_1_LDADD) $(LIBS)
@@ -1692,6 +1762,8 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/many_sections_r_test.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/many_sections_test.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/object_unittest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_test_1.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_test_2.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protected_3.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protected_main_1.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protected_main_2.Po@am__quote@
@@ -2313,6 +2385,28 @@ 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@@PLUGINS_TRUE@plugin_test_1: two_file_test_main.o two_file_test_1.syms two_file_test_1b.syms two_file_test_2.syms gcctestdir/ld plugin_test.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--no-demangle,--plugin,"./plugin_test.so;_Z4f13iv" two_file_test_main.o two_file_test_1.syms two_file_test_1b.syms two_file_test_2.syms 2>plugin_test_1.err
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_test_1.err: plugin_test_1
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ @touch plugin_test_1.err
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_test_2: two_file_test_main.o two_file_test_1.syms two_file_test_1b.syms two_file_shared_2.so gcctestdir/ld plugin_test.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--no-demangle,-R,.,--plugin,"./plugin_test.so" two_file_test_main.o two_file_test_1.syms two_file_test_1b.syms two_file_shared_2.so 2>plugin_test_2.err
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_test_2.err: plugin_test_2
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ @touch plugin_test_2.err
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_test.so: plugin_test.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(LINK) -Bgcctestdir/ -shared plugin_test.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_test.o: plugin_test.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(COMPILE) -O0 -c -fpic -o $@ $<
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@two_file_test_main.syms: two_file_test_main.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(TEST_READELF) -sW $< >$@ 2>/dev/null
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@two_file_test_1.syms: two_file_test_1.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(TEST_READELF) -sW $< >$@ 2>/dev/null
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@two_file_test_1b.syms: two_file_test_1b.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(TEST_READELF) -sW $< >$@ 2>/dev/null
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@two_file_test_2.syms: two_file_test_2.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(TEST_READELF) -sW $< >$@ 2>/dev/null
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
diff --git a/gold/testsuite/plugin_test.c b/gold/testsuite/plugin_test.c
new file mode 100644
index 00000000000..c60c7a1f858
--- /dev/null
+++ b/gold/testsuite/plugin_test.c
@@ -0,0 +1,427 @@
+/* test_plugin.c -- simple linker plugin test
+
+ Copyright 2008 Free Software Foundation, Inc.
+ Written by Cary Coutant <ccoutant@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. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "plugin-api.h"
+
+struct claimed_file
+{
+ const char* name;
+ void* handle;
+ int nsyms;
+ struct ld_plugin_symbol* syms;
+ struct claimed_file* next;
+};
+
+static struct claimed_file* first_claimed_file = NULL;
+static struct claimed_file* last_claimed_file = NULL;
+
+static ld_plugin_register_claim_file register_claim_file_hook = NULL;
+static ld_plugin_register_all_symbols_read register_all_symbols_read_hook = NULL;
+static ld_plugin_register_cleanup register_cleanup_hook = NULL;
+static ld_plugin_add_symbols add_symbols = NULL;
+static ld_plugin_get_symbols get_symbols = NULL;
+static ld_plugin_add_input_file add_input_file = NULL;
+static ld_plugin_message message = NULL;
+
+#define MAXOPTS 10
+
+static const char *opts[MAXOPTS];
+static int nopts = 0;
+
+enum ld_plugin_status onload(struct ld_plugin_tv *tv);
+enum ld_plugin_status claim_file_hook(const struct ld_plugin_input_file *file,
+ int *claimed);
+enum ld_plugin_status all_symbols_read_hook(void);
+enum ld_plugin_status cleanup_hook(void);
+
+enum ld_plugin_status
+onload(struct ld_plugin_tv *tv)
+{
+ struct ld_plugin_tv *entry;
+ int api_version = 0;
+ int gold_version = 0;
+ int i;
+
+ for (entry = tv; entry->tv_tag != LDPT_NULL; ++entry)
+ {
+ switch (entry->tv_tag)
+ {
+ case LDPT_API_VERSION:
+ api_version = entry->tv_u.tv_val;
+ break;
+ case LDPT_GOLD_VERSION:
+ gold_version = entry->tv_u.tv_val;
+ break;
+ case LDPT_LINKER_OUTPUT:
+ break;
+ case LDPT_OPTION:
+ if (nopts < MAXOPTS)
+ opts[nopts++] = entry->tv_u.tv_string;
+ break;
+ case LDPT_REGISTER_CLAIM_FILE_HOOK:
+ register_claim_file_hook = entry->tv_u.tv_register_claim_file;
+ break;
+ case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK:
+ register_all_symbols_read_hook =
+ entry->tv_u.tv_register_all_symbols_read;
+ break;
+ case LDPT_REGISTER_CLEANUP_HOOK:
+ register_cleanup_hook = entry->tv_u.tv_register_cleanup;
+ break;
+ case LDPT_ADD_SYMBOLS:
+ add_symbols = entry->tv_u.tv_add_symbols;
+ break;
+ case LDPT_GET_SYMBOLS:
+ get_symbols = entry->tv_u.tv_get_symbols;
+ break;
+ case LDPT_ADD_INPUT_FILE:
+ add_input_file = entry->tv_u.tv_add_input_file;
+ break;
+ case LDPT_MESSAGE:
+ message = entry->tv_u.tv_message;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (message == NULL)
+ {
+ fprintf(stderr, "tv_message interface missing\n");
+ return LDPS_ERR;
+ }
+
+ if (register_claim_file_hook == NULL)
+ {
+ fprintf(stderr, "tv_register_claim_file_hook interface missing\n");
+ return LDPS_ERR;
+ }
+
+ if (register_all_symbols_read_hook == NULL)
+ {
+ fprintf(stderr, "tv_register_all_symbols_read_hook interface missing\n");
+ return LDPS_ERR;
+ }
+
+ if (register_cleanup_hook == NULL)
+ {
+ fprintf(stderr, "tv_register_cleanup_hook interface missing\n");
+ return LDPS_ERR;
+ }
+
+ (*message)(LDPL_INFO, "API version: %d", api_version);
+ (*message)(LDPL_INFO, "gold version: %d", gold_version);
+
+ for (i = 0; i < nopts; ++i)
+ (*message)(LDPL_INFO, "option: %s", opts[i]);
+
+ if ((*register_claim_file_hook)(claim_file_hook) != LDPS_OK)
+ {
+ (*message)(LDPL_ERROR, "error registering claim file hook");
+ return LDPS_ERR;
+ }
+
+ if ((*register_all_symbols_read_hook)(all_symbols_read_hook) != LDPS_OK)
+ {
+ (*message)(LDPL_ERROR, "error registering all symbols read hook");
+ return LDPS_ERR;
+ }
+
+ if ((*register_cleanup_hook)(cleanup_hook) != LDPS_OK)
+ {
+ (*message)(LDPL_ERROR, "error registering cleanup hook");
+ return LDPS_ERR;
+ }
+
+ return LDPS_OK;
+}
+
+enum ld_plugin_status
+claim_file_hook (const struct ld_plugin_input_file* file, int* claimed)
+{
+ int len;
+ char buf[160];
+ struct claimed_file* claimed_file;
+ struct ld_plugin_symbol* syms;
+ int nsyms = 0;
+ int maxsyms = 0;
+ FILE* irfile;
+ char *p;
+ char *pbind;
+ char *pvis;
+ char *psect;
+ int weak;
+ int def;
+ int vis;
+ int size;
+ char* name;
+ int is_comdat;
+ int i;
+
+ (*message)(LDPL_INFO,
+ "%s: claim file hook called (offset = %ld, size = %ld)",
+ file->name, (long)file->offset, (long)file->filesize);
+
+ /* Look for the beginning of output from readelf -s. */
+ irfile = fdopen(file->fd, "r");
+ (void)fseek(irfile, file->offset, SEEK_SET);
+ len = fread(buf, 1, 13, irfile);
+ if (len < 13 || strncmp(buf, "\nSymbol table", 13) != 0)
+ return LDPS_OK;
+
+ /* Skip the two header lines. */
+ (void) fgets(buf, sizeof(buf), irfile);
+ (void) fgets(buf, sizeof(buf), irfile);
+
+ if (add_symbols == NULL)
+ {
+ fprintf(stderr, "tv_add_symbols interface missing\n");
+ return LDPS_ERR;
+ }
+
+ /* Parse the output from readelf. The columns are:
+ Index Value Size Type Binding Visibility Section Name. */
+ syms = (struct ld_plugin_symbol*)malloc(sizeof(struct ld_plugin_symbol) * 8);
+ if (syms == NULL)
+ return LDPS_ERR;
+ maxsyms = 8;
+ while (fgets(buf, sizeof(buf), irfile) != NULL)
+ {
+ p = buf;
+ p += strspn(p, " ");
+
+ /* Index field. */
+ p += strcspn(p, " ");
+ p += strspn(p, " ");
+
+ /* Value field. */
+ p += strcspn(p, " ");
+ p += strspn(p, " ");
+
+ /* Size field. */
+ size = atoi(p);
+ p += strcspn(p, " ");
+ p += strspn(p, " ");
+
+ /* Type field. */
+ p += strcspn(p, " ");
+ p += strspn(p, " ");
+
+ /* Binding field. */
+ pbind = p;
+ p += strcspn(p, " ");
+ p += strspn(p, " ");
+
+ /* Visibility field. */
+ pvis = p;
+ p += strcspn(p, " ");
+ p += strspn(p, " ");
+
+ /* Section field. */
+ psect = p;
+ p += strcspn(p, " ");
+ p += strspn(p, " ");
+
+ /* Name field. */
+ /* FIXME: Look for version. */
+ len = strlen(p);
+ if (p[len-1] == '\n')
+ p[--len] = '\0';
+ name = malloc(len + 1);
+ strncpy(name, p, len + 1);
+
+ /* Ignore local symbols. */
+ if (strncmp(pbind, "LOCAL", 5) == 0)
+ continue;
+
+ weak = strncmp(pbind, "WEAK", 4) == 0;
+ if (strncmp(psect, "UND", 3) == 0)
+ def = weak ? LDPK_WEAKUNDEF : LDPK_UNDEF;
+ else if (strncmp(psect, "COM", 3) == 0)
+ def = LDPK_COMMON;
+ else
+ def = weak ? LDPK_WEAKDEF : LDPK_DEF;
+
+ if (strncmp(pvis, "INTERNAL", 8) == 0)
+ vis = LDPV_INTERNAL;
+ else if (strncmp(pvis, "HIDDEN", 6) == 0)
+ vis = LDPV_HIDDEN;
+ else if (strncmp(pvis, "PROTECTED", 9) == 0)
+ vis = LDPV_PROTECTED;
+ else
+ vis = LDPV_DEFAULT;
+
+ /* If the symbol is listed in the options list, special-case
+ it as a comdat symbol. */
+ is_comdat = 0;
+ for (i = 0; i < nopts; ++i)
+ {
+ if (name != NULL && strcmp(name, opts[i]) == 0)
+ {
+ is_comdat = 1;
+ break;
+ }
+ }
+
+ if (nsyms >= maxsyms)
+ {
+ syms = (struct ld_plugin_symbol*)
+ realloc(syms, sizeof(struct ld_plugin_symbol) * maxsyms * 2);
+ if (syms == NULL)
+ return LDPS_ERR;
+ maxsyms *= 2;
+ }
+
+ syms[nsyms].name = name;
+ syms[nsyms].version = NULL;
+ syms[nsyms].def = def;
+ syms[nsyms].visibility = vis;
+ syms[nsyms].size = size;
+ syms[nsyms].comdat_key = is_comdat ? name : NULL;
+ syms[nsyms].resolution = LDPR_UNKNOWN;
+ ++nsyms;
+ }
+
+ claimed_file = (struct claimed_file*) malloc(sizeof(struct claimed_file));
+ if (claimed_file == NULL)
+ return LDPS_ERR;
+
+ claimed_file->name = file->name;
+ claimed_file->handle = file->handle;
+ claimed_file->nsyms = nsyms;
+ claimed_file->syms = syms;
+ claimed_file->next = NULL;
+ if (last_claimed_file == NULL)
+ first_claimed_file = claimed_file;
+ else
+ last_claimed_file->next = claimed_file;
+ last_claimed_file = claimed_file;
+
+ (*add_symbols)(file->handle, nsyms, syms);
+
+ *claimed = 1;
+ return LDPS_OK;
+}
+
+enum ld_plugin_status
+all_symbols_read_hook(void)
+{
+ int i;
+ const char* res;
+ struct claimed_file* claimed_file;
+ char buf[160];
+ char *p;
+
+ (*message)(LDPL_INFO, "all symbols read hook called");
+
+ if (get_symbols == NULL)
+ {
+ fprintf(stderr, "tv_get_symbols interface missing\n");
+ return LDPS_ERR;
+ }
+
+ for (claimed_file = first_claimed_file;
+ claimed_file != NULL;
+ claimed_file = claimed_file->next)
+ {
+ (*get_symbols)(claimed_file->handle, claimed_file->nsyms,
+ claimed_file->syms);
+ for (i = 0; i < claimed_file->nsyms; ++i)
+ {
+ switch (claimed_file->syms[i].resolution)
+ {
+ case LDPR_UNKNOWN:
+ res = "UNKNOWN";
+ break;
+ case LDPR_UNDEF:
+ res = "UNDEF";
+ break;
+ case LDPR_PREVAILING_DEF:
+ res = "PREVAILING_DEF_REG";
+ break;
+ case LDPR_PREVAILING_DEF_IRONLY:
+ res = "PREVAILING_DEF_IRONLY";
+ break;
+ case LDPR_PREEMPTED_REG:
+ res = "PREEMPTED_REG";
+ break;
+ case LDPR_PREEMPTED_IR:
+ res = "PREEMPTED_IR";
+ break;
+ case LDPR_RESOLVED_IR:
+ res = "RESOLVED_IR";
+ break;
+ case LDPR_RESOLVED_EXEC:
+ res = "RESOLVED_EXEC";
+ break;
+ case LDPR_RESOLVED_DYN:
+ res = "RESOLVED_DYN";
+ break;
+ default:
+ res = "?";
+ break;
+ }
+ (*message)(LDPL_INFO, "%s: %s: %s", claimed_file->name,
+ claimed_file->syms[i].name, res);
+ }
+ }
+
+ if (add_input_file == NULL)
+ {
+ fprintf(stderr, "tv_add_input_file interface missing\n");
+ return LDPS_ERR;
+ }
+
+ for (claimed_file = first_claimed_file;
+ claimed_file != NULL;
+ claimed_file = claimed_file->next)
+ {
+ if (strlen(claimed_file->name) >= sizeof(buf))
+ {
+ (*message)(LDPL_FATAL, "%s: filename too long", claimed_file->name);
+ return LDPS_ERR;
+ }
+ strcpy(buf, claimed_file->name);
+ p = strrchr(buf, '.');
+ if (p == NULL || strcmp(p, ".syms") != 0)
+ {
+ (*message)(LDPL_FATAL, "%s: filename must have '.syms' suffix",
+ claimed_file->name);
+ return LDPS_ERR;
+ }
+ p[1] = 'o';
+ p[2] = '\0';
+ (*add_input_file)(buf);
+ }
+
+ return LDPS_OK;
+}
+
+enum ld_plugin_status
+cleanup_hook(void)
+{
+ (*message)(LDPL_INFO, "cleanup hook called");
+ return LDPS_OK;
+}
diff --git a/gold/testsuite/plugin_test_1.sh b/gold/testsuite/plugin_test_1.sh
new file mode 100755
index 00000000000..5e161396ac5
--- /dev/null
+++ b/gold/testsuite/plugin_test_1.sh
@@ -0,0 +1,56 @@
+#!/bin/sh
+
+# plugin_test_1.sh -- a test case for the plugin API.
+
+# Copyright 2008 Free Software Foundation, Inc.
+# Written by Cary Coutant <ccoutant@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 plugin_test_1.c, a simple plug-in library that
+# exercises the basic interfaces and prints out version numbers and
+# options passed to the plugin.
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected output in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+check plugin_test_1.err "API version:"
+check plugin_test_1.err "gold version:"
+check plugin_test_1.err "option: _Z4f13iv"
+check plugin_test_1.err "two_file_test_main.o: claim file hook called"
+check plugin_test_1.err "two_file_test_1.syms: claim file hook called"
+check plugin_test_1.err "two_file_test_1b.syms: claim file hook called"
+check plugin_test_1.err "two_file_test_2.syms: claim file hook called"
+check plugin_test_1.err "two_file_test_1.syms: _Z4f13iv: PREVAILING_DEF_IRONLY"
+check plugin_test_1.err "two_file_test_1.syms: _Z2t2v: PREVAILING_DEF_REG"
+check plugin_test_1.err "two_file_test_1.syms: v2: RESOLVED_IR"
+check plugin_test_1.err "two_file_test_1.syms: t17data: RESOLVED_IR"
+check plugin_test_1.err "two_file_test_2.syms: _Z4f13iv: PREEMPTED_IR"
+check plugin_test_1.err "cleanup hook called"
+
+exit 0
diff --git a/gold/testsuite/plugin_test_2.sh b/gold/testsuite/plugin_test_2.sh
new file mode 100755
index 00000000000..41865acff28
--- /dev/null
+++ b/gold/testsuite/plugin_test_2.sh
@@ -0,0 +1,54 @@
+#!/bin/sh
+
+# plugin_test_2.sh -- a test case for the plugin API.
+
+# Copyright 2008 Free Software Foundation, Inc.
+# Written by Cary Coutant <ccoutant@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 plugin_test_1.c, a simple plug-in library that
+# exercises the basic interfaces and prints out version numbers and
+# options passed to the plugin.
+
+check()
+{
+ if ! grep -q "$2" "$1"
+ then
+ echo "Did not find expected output in $1:"
+ echo " $2"
+ echo ""
+ echo "Actual output below:"
+ cat "$1"
+ exit 1
+ fi
+}
+
+check plugin_test_2.err "API version:"
+check plugin_test_2.err "gold version:"
+check plugin_test_2.err "two_file_test_main.o: claim file hook called"
+check plugin_test_2.err "two_file_test_1.syms: claim file hook called"
+check plugin_test_2.err "two_file_test_1b.syms: claim file hook called"
+check plugin_test_2.err "two_file_shared_2.so: claim file hook called"
+check plugin_test_2.err "two_file_test_1.syms: _Z4f13iv: PREVAILING_DEF_REG"
+check plugin_test_2.err "two_file_test_1.syms: _Z2t2v: PREVAILING_DEF_REG"
+check plugin_test_2.err "two_file_test_1.syms: v2: RESOLVED_DYN"
+check plugin_test_2.err "two_file_test_1.syms: t17data: RESOLVED_DYN"
+check plugin_test_2.err "cleanup hook called"
+
+exit 0
diff --git a/include/ChangeLog b/include/ChangeLog
index ece1aae367f..adcc2b776cd 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,3 +1,8 @@
+2008-09-18 Cary Coutant <ccoutant@google.com>
+
+ Add plugin functionality for link-time optimization (LTO).
+ * plugin-api.h: New file.
+
2008-09-09 Jason Merrill <jason@redhat.com>
* demangle.h (enum demangle_component_type): Add
diff --git a/include/plugin-api.h b/include/plugin-api.h
new file mode 100644
index 00000000000..9863086317c
--- /dev/null
+++ b/include/plugin-api.h
@@ -0,0 +1,242 @@
+/* plugin-api.h -- External linker plugin API. */
+
+/* Copyright 2008 Free Software Foundation, Inc.
+ Written by Cary Coutant <ccoutant@google.com>.
+
+ This file is part of 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. */
+
+/* This file defines the interface for writing a linker plugin, which is
+ described at < http://gcc.gnu.org/wiki/whopr/driver >. */
+
+#ifndef PLUGIN_API_H
+#define PLUGIN_API_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Status code returned by most API routines. */
+
+enum ld_plugin_status
+{
+ LDPS_OK = 0,
+ LDPS_NO_SYMS, // Attempt to get symbols that haven't been added.
+ LDPS_ERR,
+ /* Additional Error codes TBD. */
+};
+
+/* The version of the API specification. */
+
+enum ld_plugin_api_version
+{
+ LD_PLUGIN_API_VERSION = 1,
+};
+
+/* The type of output file being generated by the linker. */
+
+enum ld_plugin_output_file_type
+{
+ LDPO_REL,
+ LDPO_EXEC,
+ LDPO_DYN,
+};
+
+/* An input file managed by the plugin library. */
+
+struct ld_plugin_input_file
+{
+ const char *name;
+ int fd;
+ off_t offset;
+ off_t filesize;
+ void *handle;
+};
+
+/* A symbol belonging to an input file managed by the plugin library. */
+
+struct ld_plugin_symbol
+{
+ char *name;
+ char *version;
+ int def;
+ int visibility;
+ uint64_t size;
+ char *comdat_key;
+ int resolution;
+};
+
+/* Whether the symbol is a definition, reference, or common, weak or not. */
+
+enum ld_plugin_symbol_kind
+{
+ LDPK_DEF,
+ LDPK_WEAKDEF,
+ LDPK_UNDEF,
+ LDPK_WEAKUNDEF,
+ LDPK_COMMON,
+};
+
+/* The visibility of the symbol. */
+
+enum ld_plugin_symbol_visibility
+{
+ LDPV_DEFAULT,
+ LDPV_PROTECTED,
+ LDPV_INTERNAL,
+ LDPV_HIDDEN,
+};
+
+/* How a symbol is resolved. */
+
+enum ld_plugin_symbol_resolution
+{
+ LDPR_UNKNOWN = 0,
+ LDPR_UNDEF,
+ LDPR_PREVAILING_DEF,
+ LDPR_PREVAILING_DEF_IRONLY,
+ LDPR_PREEMPTED_REG,
+ LDPR_PREEMPTED_IR,
+ LDPR_RESOLVED_IR,
+ LDPR_RESOLVED_EXEC,
+ LDPR_RESOLVED_DYN,
+};
+
+/* The plugin library's "claim file" handler. */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_claim_file_handler) (
+ const struct ld_plugin_input_file *file, int *claimed);
+
+/* The plugin library's "all symbols read" handler. */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_all_symbols_read_handler) (void);
+
+/* The plugin library's cleanup handler. */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_cleanup_handler) (void);
+
+/* The linker's interface for registering the "claim file" handler. */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_register_claim_file) (ld_plugin_claim_file_handler handler);
+
+/* The linker's interface for registering the "all symbols read" handler. */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_register_all_symbols_read) (
+ ld_plugin_all_symbols_read_handler handler);
+
+/* The linker's interface for registering the cleanup handler. */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_register_cleanup) (ld_plugin_cleanup_handler handler);
+
+/* The linker's interface for adding symbols from a claimed input file. */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_add_symbols) (void *handle, int nsyms,
+ const struct ld_plugin_symbol *syms);
+
+/* The linker's interface for retrieving symbol resolution information. */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_get_symbols) (const void *handle, int nsyms,
+ struct ld_plugin_symbol *syms);
+
+/* The linker's interface for adding a compiled input file. */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_add_input_file) (char *pathname);
+
+/* The linker's interface for issuing a warning or error message. */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_message) (int level, char *format, ...);
+
+enum ld_plugin_level
+{
+ LDPL_INFO,
+ LDPL_WARNING,
+ LDPL_ERROR,
+ LDPL_FATAL,
+};
+
+/* Values for the tv_tag field of the transfer vector. */
+
+enum ld_plugin_tag
+{
+ LDPT_NULL = 0,
+ LDPT_API_VERSION,
+ LDPT_GOLD_VERSION,
+ LDPT_LINKER_OUTPUT,
+ LDPT_OPTION,
+ LDPT_REGISTER_CLAIM_FILE_HOOK,
+ LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK,
+ LDPT_REGISTER_CLEANUP_HOOK,
+ LDPT_ADD_SYMBOLS,
+ LDPT_GET_SYMBOLS,
+ LDPT_ADD_INPUT_FILE,
+ LDPT_MESSAGE,
+};
+
+/* The plugin transfer vector. */
+
+struct ld_plugin_tv
+{
+ enum ld_plugin_tag tv_tag;
+ union
+ {
+ int tv_val;
+ const char *tv_string;
+ ld_plugin_register_claim_file tv_register_claim_file;
+ ld_plugin_register_all_symbols_read tv_register_all_symbols_read;
+ ld_plugin_register_cleanup tv_register_cleanup;
+ ld_plugin_add_symbols tv_add_symbols;
+ ld_plugin_get_symbols tv_get_symbols;
+ ld_plugin_add_input_file tv_add_input_file;
+ ld_plugin_message tv_message;
+ } tv_u;
+};
+
+/* The plugin library's "onload" entry point. */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_onload) (struct ld_plugin_tv *tv);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* !defined(PLUGIN_API_H) */