From: Cary Coutant Date: Fri, 19 Sep 2008 22:54:57 +0000 (+0000) Subject: Add plugin functionality for link-time optimization (LTO). X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=89fc34211be8b1d74b83e4e2b18cfa4b4cf65ba9;p=binutils-gdb.git 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. --- 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 + + 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 * 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(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 #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(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 . + +// 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 +#include +#include +#include +#include +#include + +#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 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 + (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(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(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 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 +Sized_pluginobj::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 +void +Sized_pluginobj::do_read_symbols(Read_symbols_data*) +{ + gold_unreachable(); +} + +// Lay out the input sections. Not used for plugin objects. + +template +void +Sized_pluginobj::do_layout(Symbol_table*, Layout*, + Read_symbols_data*) +{ + gold_unreachable(); +} + +// Add the symbols to the symbol table. + +template +void +Sized_pluginobj::do_add_symbols(Symbol_table*, + Read_symbols_data*) +{ + gold_unreachable(); +} + +template +void +Sized_pluginobj::do_add_symbols(Symbol_table* symtab, + Layout* layout) +{ + const int sym_size = elfcpp::Elf_sizes::sym_size; + unsigned char symbuf[sym_size]; + elfcpp::Sym sym(symbuf); + elfcpp::Sym_write osym(symbuf); + + typedef typename elfcpp::Elf_types::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(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(this, name, ver, &sym); + } +} + +// Get the size of a section. Not used for plugin objects. + +template +uint64_t +Sized_pluginobj::do_section_size(unsigned int) +{ + gold_unreachable(); + return 0; +} + +// Get the name of a section. Not used for plugin objects. + +template +std::string +Sized_pluginobj::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 +Object::Location +Sized_pluginobj::do_section_contents(unsigned int) +{ + Location loc(0, 0); + + gold_unreachable(); + return loc; +} + +// Return section flags. Not used for plugin objects. + +template +uint64_t +Sized_pluginobj::do_section_flags(unsigned int) +{ + gold_unreachable(); + return 0; +} + +// Return section address. Not used for plugin objects. + +template +uint64_t +Sized_pluginobj::do_section_address(unsigned int) +{ + gold_unreachable(); + return 0; +} + +// Return section type. Not used for plugin objects. + +template +unsigned int +Sized_pluginobj::do_section_type(unsigned int) +{ + gold_unreachable(); + return 0; +} + +// Return the section link field. Not used for plugin objects. + +template +unsigned int +Sized_pluginobj::do_section_link(unsigned int) +{ + gold_unreachable(); + return 0; +} + +// Return the section link field. Not used for plugin objects. + +template +unsigned int +Sized_pluginobj::do_section_info(unsigned int) +{ + gold_unreachable(); + return 0; +} + +// Return the section alignment. Not used for plugin objects. + +template +uint64_t +Sized_pluginobj::do_section_addralign(unsigned int) +{ + gold_unreachable(); + return 0; +} + +// Return the Xindex structure to use. Not used for plugin objects. + +template +Xindex* +Sized_pluginobj::do_initialize_xindex() +{ + gold_unreachable(); + return NULL; +} + +// Get symbol counts. Not used for plugin objects. + +template +void +Sized_pluginobj::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(reinterpret_cast(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(reinterpret_cast(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(¶meters->target()); + else + target = const_cast(¶meters->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 . + +// 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 +#include + +#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_list; + typedef std::vector 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 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 Comdat_map; + Comdat_map comdat_map_; +}; + +// A plugin object, size-specific version. + +template +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* 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(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 +Symbol* +Symbol_table::add_from_pluginobj( + Sized_pluginobj* obj, + const char* name, + const char* ver, + elfcpp::Sym* 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* 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 @@ -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 @@ -2701,6 +2778,46 @@ Symbol_table::add_from_relobj<64, true>( size_t* defined); #endif +#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 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 class Sized_relobj; +template +class Sized_pluginobj; class Dynobj; template 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::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 + Symbol* + add_from_pluginobj(Sized_pluginobj* obj, + const char* name, const char* ver, + elfcpp::Sym* 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 . + + 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 +#include +#include +#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 . + +# 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 . + +# 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 + + Add plugin functionality for link-time optimization (LTO). + * plugin-api.h: New file. + 2008-09-09 Jason Merrill * 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 . + + 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 +#include + +#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) */