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.
This commit is contained in:
parent
14fc49fb15
commit
89fc34211b
30 changed files with 2923 additions and 81 deletions
|
@ -1,3 +1,88 @@
|
|||
2008-09-19 Cary Coutant <ccoutant@google.com>
|
||||
|
||||
Add plugin functionality for link-time optimization (LTO).
|
||||
* configure.ac (plugins): Add --enable-plugins option.
|
||||
* configure: Regenerate.
|
||||
* config.in: Regenerate.
|
||||
* Makefile.am (LIBDL): New variable.
|
||||
(CCFILES): Add plugin.cc.
|
||||
(HFILES): Add plugin.h.
|
||||
(ldadd_var): Add LIBDL.
|
||||
* Makefile.in: Regenerate.
|
||||
|
||||
* archive.cc: Include "plugin.h".
|
||||
(Archive::setup): Don't preread archive symbols when using a plugin.
|
||||
(Archive::get_file_and_offset): Add memsize parameter. Change callers.
|
||||
(Archive::get_elf_object_for_member): Call plugin hooks for claiming
|
||||
files.
|
||||
(Archive::include_member): Add symbols from plugin objects.
|
||||
* archive.h (Archive::get_file_and_offset): Add memsize parameter.
|
||||
* descriptors.cc (Descriptors::open): Check for file descriptors
|
||||
abandoned by plugins.
|
||||
(Descriptors::claim_for_plugin): New function.
|
||||
* descriptors.h (Descriptors::claim_for_plugin): New function.
|
||||
(Open_descriptor::is_claimed): New field.
|
||||
(claim_descriptor_for_plugin): New function.
|
||||
* fileread.cc (File_read::claim_for_plugin): New function.
|
||||
* fileread.h (File_read::claim_for_plugin): New function.
|
||||
(File_read::descriptor): New function.
|
||||
* gold.cc: Include "plugin.h".
|
||||
(queue_initial_tasks): Add task to call plugin hooks for generating
|
||||
new object files.
|
||||
* main.cc: Include "plugin.h".
|
||||
(main): Load plugin libraries.
|
||||
* object.h (Pluginobj): Declare.
|
||||
(Object::pluginobj): New function.
|
||||
(Object::do_pluginobj): New function.
|
||||
(Object::set_target): New function.
|
||||
* options.cc: Include "plugin.h".
|
||||
(General_options::parse_plugin): New function.
|
||||
(General_options::General_options): Initialize plugins_ field.
|
||||
(General_options::add_plugin): New function.
|
||||
* options.h (Plugin_manager): Declare.
|
||||
(General_options): Add --plugin option.
|
||||
(General_options::has_plugins): New function.
|
||||
(General_options::plugins): New function.
|
||||
(General_options::add_plugin): New function.
|
||||
(General_options::plugins_): New field.
|
||||
* plugin.cc: New file.
|
||||
* plugin.h: New file.
|
||||
* readsyms.cc: Include "plugin.h".
|
||||
(Read_symbols::do_read_symbols): Check for archive before checking
|
||||
for ELF file. Call plugin hooks to claim files.
|
||||
* resolve.cc (Symbol_table::resolve): Record when symbol is referenced
|
||||
from a real object file; force override when processing replacement
|
||||
files.
|
||||
* symtab.cc (Symbol::init_fields): Initialize in_real_elf_ field.
|
||||
(Symbol::init_base_object): Likewise.
|
||||
(Symbol::init_base_output_data): Likewise.
|
||||
(Symbol::init_base_output_segment): Likewise.
|
||||
(Symbol::init_base_constant): Likewise.
|
||||
(Symbol::init_base_undefined): Likewise.
|
||||
(Symbol::output_section): Assert that object is not a plugin.
|
||||
(Symbol_table::add_from_pluginobj): New function.
|
||||
(Symbol_table::sized_finalize_symbol): Treat symbols from plugins as
|
||||
undefined.
|
||||
(Symbol_table::sized_write_globals): Likewise.
|
||||
(Symbol_table::add_from_pluginobj): Instantiate template.
|
||||
* symtab.h (Sized_pluginobj): Declare.
|
||||
(Symbol::in_real_elf): New function.
|
||||
(Symbol::set_in_real_elf): New function.
|
||||
(Symbol::in_real_elf_): New field.
|
||||
(Symbol_table::add_from_pluginobj): New function.
|
||||
|
||||
* testsuite/Makefile.am (AM_CFLAGS): New variable.
|
||||
(LIBDL): New variable.
|
||||
(LDADD): Add LIBDL.
|
||||
(check_PROGRAMS): Add plugin_test_1 and plugin_test_2.
|
||||
(check_SCRIPTS): Add plugin_test_1.sh and plugin_test_2.sh.
|
||||
(check_DATA): Add plugin_test_1.err and plugin_test_2.err.
|
||||
(MOSTLYCLEANFILES): Likewise.
|
||||
* testsuite/Makefile.in: Regenerate.
|
||||
* testsuite/plugin_test.c: New file.
|
||||
* testsuite/plugin_test_1.sh: New file.
|
||||
* testsuite/plugin_test_2.sh: New file.
|
||||
|
||||
2008-09-16 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* target-reloc.h (relocate_section): Check whether a symbol is
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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@
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "symtab.h"
|
||||
#include "object.h"
|
||||
#include "archive.h"
|
||||
#include "plugin.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
@ -126,6 +127,9 @@ Archive::setup(Input_objects* input_objects)
|
|||
&& parameters->options().preread_archive_symbols());
|
||||
#ifndef ENABLE_THREADS
|
||||
preread_syms = false;
|
||||
#else
|
||||
if (parameters->options().has_plugins())
|
||||
preread_syms = false;
|
||||
#endif
|
||||
if (preread_syms)
|
||||
this->read_all_symbols(input_objects);
|
||||
|
@ -439,11 +443,11 @@ Archive::end()
|
|||
bool
|
||||
Archive::get_file_and_offset(off_t off, Input_objects* input_objects,
|
||||
Input_file** input_file, off_t* memoff,
|
||||
std::string* member_name)
|
||||
off_t* memsize, std::string* member_name)
|
||||
{
|
||||
off_t nested_off;
|
||||
|
||||
this->read_header(off, false, member_name, &nested_off);
|
||||
*memsize = this->read_header(off, false, member_name, &nested_off);
|
||||
|
||||
*input_file = this->input_file_;
|
||||
*memoff = off + static_cast<off_t>(sizeof(Archive_header));
|
||||
|
@ -488,8 +492,8 @@ Archive::get_file_and_offset(off_t off, Input_objects* input_objects,
|
|||
this->nested_archives_.insert(std::make_pair(*member_name, arch));
|
||||
gold_assert(ins.second);
|
||||
}
|
||||
return arch->get_file_and_offset(nested_off, input_objects,
|
||||
input_file, memoff, member_name);
|
||||
return arch->get_file_and_offset(nested_off, input_objects, input_file,
|
||||
memoff, memsize, member_name);
|
||||
}
|
||||
|
||||
// This is an external member of a thin archive. Open the
|
||||
|
@ -503,6 +507,7 @@ Archive::get_file_and_offset(off_t off, Input_objects* input_objects,
|
|||
return false;
|
||||
|
||||
*memoff = 0;
|
||||
*memsize = (*input_file)->file().filesize();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -515,11 +520,26 @@ Archive::get_elf_object_for_member(off_t off, Input_objects* input_objects)
|
|||
std::string member_name;
|
||||
Input_file* input_file;
|
||||
off_t memoff;
|
||||
off_t memsize;
|
||||
|
||||
if (!this->get_file_and_offset(off, input_objects, &input_file, &memoff,
|
||||
&member_name))
|
||||
&memsize, &member_name))
|
||||
return NULL;
|
||||
|
||||
if (parameters->options().has_plugins())
|
||||
{
|
||||
Object* obj = parameters->options().plugins()->claim_file(input_file,
|
||||
memoff,
|
||||
memsize);
|
||||
if (obj != NULL)
|
||||
{
|
||||
// The input file was claimed by a plugin, and its symbols
|
||||
// have been provided by the plugin.
|
||||
input_file->file().claim_for_plugin();
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
off_t filesize = input_file->file().filesize();
|
||||
int read_size = elfcpp::Elf_sizes<64>::ehdr_size;
|
||||
if (filesize - memoff < read_size)
|
||||
|
@ -753,6 +773,13 @@ Archive::include_member(Symbol_table* symtab, Layout* layout,
|
|||
if (mapfile != NULL)
|
||||
mapfile->report_include_archive_member(obj->name(), sym, why);
|
||||
|
||||
Pluginobj* pluginobj = obj->pluginobj();
|
||||
if (pluginobj != NULL)
|
||||
{
|
||||
pluginobj->add_symbols(symtab, layout);
|
||||
return;
|
||||
}
|
||||
|
||||
if (input_objects->add_object(obj))
|
||||
{
|
||||
Read_symbols_data sd;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
41
gold/configure
vendored
41
gold/configure
vendored
|
@ -309,7 +309,7 @@ ac_includes_default="\
|
|||
# include <unistd.h>
|
||||
#endif"
|
||||
|
||||
ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar THREADS_TRUE THREADS_FALSE TARGETOBJS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE YACC RANLIB ac_ct_RANLIB LN_S USE_NLS LIBINTL LIBINTL_DEP INCINTL XGETTEXT GMSGFMT POSUB CATALOGS DATADIRNAME INSTOBJEXT GENCAT CATOBJEXT MKINSTALLDIRS MSGFMT MSGMERGE NATIVE_LINKER_TRUE NATIVE_LINKER_FALSE GCC_TRUE GCC_FALSE FN_PTRS_IN_SO_WITHOUT_PIC_TRUE FN_PTRS_IN_SO_WITHOUT_PIC_FALSE TLS_TRUE TLS_FALSE STATIC_TLS_TRUE STATIC_TLS_FALSE OMP_SUPPORT_TRUE OMP_SUPPORT_FALSE TLS_GNU2_DIALECT_TRUE TLS_GNU2_DIALECT_FALSE TLS_DESCRIPTORS_TRUE TLS_DESCRIPTORS_FALSE CONSTRUCTOR_PRIORITY_TRUE CONSTRUCTOR_PRIORITY_FALSE RANDOM_SEED_CFLAGS WARN_CFLAGS NO_WERROR WARN_CXXFLAGS LFS_CFLAGS LIBOBJS CPP EGREP HAVE_ZLIB_TRUE HAVE_ZLIB_FALSE CXXCPP MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT LTLIBOBJS'
|
||||
ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar THREADS_TRUE THREADS_FALSE PLUGINS_TRUE PLUGINS_FALSE TARGETOBJS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE YACC RANLIB ac_ct_RANLIB LN_S USE_NLS LIBINTL LIBINTL_DEP INCINTL XGETTEXT GMSGFMT POSUB CATALOGS DATADIRNAME INSTOBJEXT GENCAT CATOBJEXT MKINSTALLDIRS MSGFMT MSGMERGE NATIVE_LINKER_TRUE NATIVE_LINKER_FALSE GCC_TRUE GCC_FALSE FN_PTRS_IN_SO_WITHOUT_PIC_TRUE FN_PTRS_IN_SO_WITHOUT_PIC_FALSE TLS_TRUE TLS_FALSE STATIC_TLS_TRUE STATIC_TLS_FALSE OMP_SUPPORT_TRUE OMP_SUPPORT_FALSE TLS_GNU2_DIALECT_TRUE TLS_GNU2_DIALECT_FALSE TLS_DESCRIPTORS_TRUE TLS_DESCRIPTORS_FALSE CONSTRUCTOR_PRIORITY_TRUE CONSTRUCTOR_PRIORITY_FALSE RANDOM_SEED_CFLAGS WARN_CFLAGS NO_WERROR WARN_CXXFLAGS LFS_CFLAGS LIBOBJS CPP EGREP HAVE_ZLIB_TRUE HAVE_ZLIB_FALSE CXXCPP MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT LTLIBOBJS'
|
||||
ac_subst_files=''
|
||||
ac_pwd=`pwd`
|
||||
|
||||
|
@ -866,6 +866,7 @@ Optional Features:
|
|||
--disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
|
||||
--enable-FEATURE[=ARG] include FEATURE [ARG=yes]
|
||||
--enable-threads multi-threaded linking
|
||||
--enable-plugins linker plugins
|
||||
--enable-targets alternative target configurations
|
||||
--disable-dependency-tracking speeds up one-time build
|
||||
--enable-dependency-tracking do not reject slow dependency extractors
|
||||
|
@ -1959,6 +1960,35 @@ else
|
|||
fi
|
||||
|
||||
|
||||
# Check whether --enable-plugins or --disable-plugins was given.
|
||||
if test "${enable_plugins+set}" = set; then
|
||||
enableval="$enable_plugins"
|
||||
case "${enableval}" in
|
||||
yes | "") plugins=yes ;;
|
||||
no) plugins=no ;;
|
||||
*) plugins=yes ;;
|
||||
esac
|
||||
else
|
||||
plugins=no
|
||||
fi;
|
||||
if test "$plugins" = "yes"; then
|
||||
|
||||
cat >>confdefs.h <<\_ACEOF
|
||||
#define ENABLE_PLUGINS 1
|
||||
_ACEOF
|
||||
|
||||
fi
|
||||
|
||||
|
||||
if test "$plugins" = "yes"; then
|
||||
PLUGINS_TRUE=
|
||||
PLUGINS_FALSE='#'
|
||||
else
|
||||
PLUGINS_TRUE='#'
|
||||
PLUGINS_FALSE=
|
||||
fi
|
||||
|
||||
|
||||
# Check whether --enable-targets or --disable-targets was given.
|
||||
if test "${enable_targets+set}" = set; then
|
||||
enableval="$enable_targets"
|
||||
|
@ -6720,6 +6750,13 @@ echo "$as_me: error: conditional \"THREADS\" was never defined.
|
|||
Usually this means the macro was only invoked conditionally." >&2;}
|
||||
{ (exit 1); exit 1; }; }
|
||||
fi
|
||||
if test -z "${PLUGINS_TRUE}" && test -z "${PLUGINS_FALSE}"; then
|
||||
{ { echo "$as_me:$LINENO: error: conditional \"PLUGINS\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." >&5
|
||||
echo "$as_me: error: conditional \"PLUGINS\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." >&2;}
|
||||
{ (exit 1); exit 1; }; }
|
||||
fi
|
||||
if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
|
||||
{ { echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." >&5
|
||||
|
@ -7396,6 +7433,8 @@ s,@am__tar@,$am__tar,;t t
|
|||
s,@am__untar@,$am__untar,;t t
|
||||
s,@THREADS_TRUE@,$THREADS_TRUE,;t t
|
||||
s,@THREADS_FALSE@,$THREADS_FALSE,;t t
|
||||
s,@PLUGINS_TRUE@,$PLUGINS_TRUE,;t t
|
||||
s,@PLUGINS_FALSE@,$PLUGINS_FALSE,;t t
|
||||
s,@TARGETOBJS@,$TARGETOBJS,;t t
|
||||
s,@CC@,$CC,;t t
|
||||
s,@CFLAGS@,$CFLAGS,;t t
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -115,7 +115,9 @@ Descriptors::open(int descriptor, const char* name, int flags, int mode)
|
|||
pod->inuse = true;
|
||||
pod->is_write = (flags & O_ACCMODE) != O_RDONLY;
|
||||
|
||||
++this->current_;
|
||||
if (!pod->is_claimed)
|
||||
++this->current_;
|
||||
pod->is_claimed = false;
|
||||
if (this->current_ >= this->limit_)
|
||||
this->close_some_descriptor();
|
||||
|
||||
|
@ -166,6 +168,24 @@ Descriptors::release(int descriptor, bool permanent)
|
|||
}
|
||||
}
|
||||
|
||||
// Claim the file descriptor DESCRIPTOR for a plugin. This effectively
|
||||
// removes the descriptor from the pool of linker-managed descriptors,
|
||||
// as the plugin will assume responsibility for closing it.
|
||||
// The IS_CLAIMED flag allows us to recognize when a file descriptor
|
||||
// has been reused after being closed by the plugin.
|
||||
|
||||
void
|
||||
Descriptors::claim_for_plugin(int descriptor)
|
||||
{
|
||||
Hold_lock hl(*this->lock_);
|
||||
|
||||
gold_assert(descriptor >= 0
|
||||
&& (static_cast<size_t>(descriptor)
|
||||
< this->open_descriptors_.size()));
|
||||
Open_descriptor* pod = &this->open_descriptors_[descriptor];
|
||||
pod->is_claimed = true;
|
||||
}
|
||||
|
||||
// Close some descriptor. The lock is held when this is called. We
|
||||
// close the descriptor on the top of the free stack. Note that this
|
||||
// is the opposite of an LRU algorithm--we close the most recently
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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&);
|
||||
|
|
11
gold/gold.cc
11
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,
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
968
gold/plugin.cc
Normal file
968
gold/plugin.cc
Normal file
|
@ -0,0 +1,968 @@
|
|||
// plugin.c -- plugin manager for gold -*- C++ -*-
|
||||
|
||||
// Copyright 2008 Free Software Foundation, Inc.
|
||||
// Written by Cary Coutant <ccoutant@google.com>.
|
||||
|
||||
// This file is part of gold.
|
||||
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
||||
// MA 02110-1301, USA.
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdarg>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "gold.h"
|
||||
#include "parameters.h"
|
||||
#include "errors.h"
|
||||
#include "fileread.h"
|
||||
#include "layout.h"
|
||||
#include "options.h"
|
||||
#include "plugin.h"
|
||||
#include "target.h"
|
||||
#include "readsyms.h"
|
||||
#include "symtab.h"
|
||||
#include "elfcpp.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
#ifdef ENABLE_PLUGINS
|
||||
|
||||
// The linker's exported interfaces.
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
static enum ld_plugin_status
|
||||
register_claim_file(ld_plugin_claim_file_handler handler);
|
||||
|
||||
static enum ld_plugin_status
|
||||
register_all_symbols_read(ld_plugin_all_symbols_read_handler handler);
|
||||
|
||||
static enum ld_plugin_status
|
||||
register_cleanup(ld_plugin_cleanup_handler handler);
|
||||
|
||||
static enum ld_plugin_status
|
||||
add_symbols(void *handle, int nsyms, const struct ld_plugin_symbol *syms);
|
||||
|
||||
static enum ld_plugin_status
|
||||
get_symbols(const void *handle, int nsyms, struct ld_plugin_symbol *syms);
|
||||
|
||||
static enum ld_plugin_status
|
||||
add_input_file(char *pathname);
|
||||
|
||||
static enum ld_plugin_status
|
||||
message(int level, char *format, ...);
|
||||
|
||||
};
|
||||
|
||||
#endif // ENABLE_PLUGINS
|
||||
|
||||
static Pluginobj* make_sized_plugin_object(Input_file* input_file,
|
||||
off_t offset);
|
||||
|
||||
// Plugin methods.
|
||||
|
||||
// Load one plugin library.
|
||||
|
||||
void
|
||||
Plugin::load()
|
||||
{
|
||||
#ifdef ENABLE_PLUGINS
|
||||
std::string filename;
|
||||
std::vector<std::string> args;
|
||||
|
||||
// Parse the filename and arguments, each separated by commas.
|
||||
// FIXME: Temporarily allowing semicolon as an argument separator
|
||||
// so args can be passed through gcc's -Wl,... option, which
|
||||
// breaks arguments at the commas.
|
||||
const char* p = this->args_;
|
||||
int n = strcspn(p, ",;");
|
||||
filename.assign(p, n);
|
||||
p += n;
|
||||
while (*p == ',' || *p == ';')
|
||||
{
|
||||
++p;
|
||||
n = strcspn(p, ",;");
|
||||
args.push_back(std::string(p, n));
|
||||
p += n;
|
||||
}
|
||||
|
||||
// Load the plugin library.
|
||||
// FIXME: Look for the library in standard locations.
|
||||
this->handle_ = dlopen(filename.c_str(), RTLD_NOW);
|
||||
if (this->handle_ == NULL)
|
||||
{
|
||||
gold_error(_("%s: could not load plugin library"), filename.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the plugin's onload entry point.
|
||||
ld_plugin_onload onload = reinterpret_cast<ld_plugin_onload>
|
||||
(dlsym(this->handle_, "onload"));
|
||||
if (onload == NULL)
|
||||
{
|
||||
gold_error(_("%s: could not find onload entry point"), filename.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the linker's version number.
|
||||
const char* ver = get_version_string();
|
||||
int major = 0;
|
||||
int minor = 0;
|
||||
sscanf(ver, "%d.%d", &major, &minor);
|
||||
|
||||
// Allocate and populate a transfer vector.
|
||||
const int tv_fixed_size = 11;
|
||||
int tv_size = args.size() + tv_fixed_size;
|
||||
ld_plugin_tv *tv = new ld_plugin_tv[tv_size];
|
||||
|
||||
int i = 0;
|
||||
tv[i].tv_tag = LDPT_API_VERSION;
|
||||
tv[i].tv_u.tv_val = LD_PLUGIN_API_VERSION;
|
||||
|
||||
++i;
|
||||
tv[i].tv_tag = LDPT_GOLD_VERSION;
|
||||
tv[i].tv_u.tv_val = major * 100 + minor;
|
||||
|
||||
++i;
|
||||
tv[i].tv_tag = LDPT_LINKER_OUTPUT;
|
||||
if (parameters->options().relocatable())
|
||||
tv[i].tv_u.tv_val = LDPO_REL;
|
||||
else if (parameters->options().shared())
|
||||
tv[i].tv_u.tv_val = LDPO_DYN;
|
||||
else
|
||||
tv[i].tv_u.tv_val = LDPO_EXEC;
|
||||
|
||||
for (unsigned int j = 0; j < args.size(); ++j)
|
||||
{
|
||||
++i;
|
||||
tv[i].tv_tag = LDPT_OPTION;
|
||||
tv[i].tv_u.tv_string = args[j].c_str();
|
||||
}
|
||||
|
||||
++i;
|
||||
tv[i].tv_tag = LDPT_REGISTER_CLAIM_FILE_HOOK;
|
||||
tv[i].tv_u.tv_register_claim_file = register_claim_file;
|
||||
|
||||
++i;
|
||||
tv[i].tv_tag = LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK;
|
||||
tv[i].tv_u.tv_register_all_symbols_read = register_all_symbols_read;
|
||||
|
||||
++i;
|
||||
tv[i].tv_tag = LDPT_REGISTER_CLEANUP_HOOK;
|
||||
tv[i].tv_u.tv_register_cleanup = register_cleanup;
|
||||
|
||||
++i;
|
||||
tv[i].tv_tag = LDPT_ADD_SYMBOLS;
|
||||
tv[i].tv_u.tv_add_symbols = add_symbols;
|
||||
|
||||
++i;
|
||||
tv[i].tv_tag = LDPT_GET_SYMBOLS;
|
||||
tv[i].tv_u.tv_get_symbols = get_symbols;
|
||||
|
||||
++i;
|
||||
tv[i].tv_tag = LDPT_ADD_INPUT_FILE;
|
||||
tv[i].tv_u.tv_add_input_file = add_input_file;
|
||||
|
||||
++i;
|
||||
tv[i].tv_tag = LDPT_MESSAGE;
|
||||
tv[i].tv_u.tv_message = message;
|
||||
|
||||
++i;
|
||||
tv[i].tv_tag = LDPT_NULL;
|
||||
tv[i].tv_u.tv_val = 0;
|
||||
|
||||
gold_assert(i == tv_size - 1);
|
||||
|
||||
// Call the onload entry point.
|
||||
(*onload)(tv);
|
||||
|
||||
delete tv;
|
||||
#endif // ENABLE_PLUGINS
|
||||
}
|
||||
|
||||
// Call the plugin claim-file handler.
|
||||
|
||||
inline bool
|
||||
Plugin::claim_file(struct ld_plugin_input_file *plugin_input_file)
|
||||
{
|
||||
int claimed = 0;
|
||||
|
||||
if (this->claim_file_handler_ != NULL)
|
||||
{
|
||||
(*this->claim_file_handler_)(plugin_input_file, &claimed);
|
||||
if (claimed)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Call the all-symbols-read handler.
|
||||
|
||||
inline void
|
||||
Plugin::all_symbols_read()
|
||||
{
|
||||
if (this->all_symbols_read_handler_ != NULL)
|
||||
(*this->all_symbols_read_handler_)();
|
||||
}
|
||||
|
||||
// Call the cleanup handler.
|
||||
|
||||
inline void
|
||||
Plugin::cleanup()
|
||||
{
|
||||
if (this->cleanup_handler_ != NULL)
|
||||
(*this->cleanup_handler_)();
|
||||
}
|
||||
|
||||
// Plugin_manager methods.
|
||||
|
||||
Plugin_manager::~Plugin_manager()
|
||||
{
|
||||
for (Plugin_list::iterator p = this->plugins_.begin();
|
||||
p != this->plugins_.end();
|
||||
++p)
|
||||
delete *p;
|
||||
this->plugins_.clear();
|
||||
for (Object_list::iterator obj = this->objects_.begin();
|
||||
obj != this->objects_.end();
|
||||
++obj)
|
||||
delete *obj;
|
||||
this->objects_.clear();
|
||||
}
|
||||
|
||||
// Load all plugin libraries.
|
||||
|
||||
void
|
||||
Plugin_manager::load_plugins()
|
||||
{
|
||||
for (this->current_ = this->plugins_.begin();
|
||||
this->current_ != this->plugins_.end();
|
||||
++this->current_)
|
||||
(*this->current_)->load();
|
||||
}
|
||||
|
||||
// Call the plugin claim-file handlers in turn to see if any claim the file.
|
||||
|
||||
Pluginobj*
|
||||
Plugin_manager::claim_file(Input_file* input_file, off_t offset,
|
||||
off_t filesize)
|
||||
{
|
||||
if (this->in_replacement_phase_)
|
||||
return NULL;
|
||||
|
||||
unsigned int handle = this->objects_.size();
|
||||
this->input_file_ = input_file;
|
||||
this->plugin_input_file_.name = input_file->filename().c_str();
|
||||
this->plugin_input_file_.fd = input_file->file().descriptor();
|
||||
this->plugin_input_file_.offset = offset;
|
||||
this->plugin_input_file_.filesize = filesize;
|
||||
this->plugin_input_file_.handle = reinterpret_cast<void*>(handle);
|
||||
|
||||
for (this->current_ = this->plugins_.begin();
|
||||
this->current_ != this->plugins_.end();
|
||||
++this->current_)
|
||||
{
|
||||
if ((*this->current_)->claim_file(&this->plugin_input_file_))
|
||||
{
|
||||
if (this->objects_.size() <= handle)
|
||||
{
|
||||
gold_error(_("%s: plugin claimed the file "
|
||||
"but did not provide any symbols"),
|
||||
this->plugin_input_file_.name);
|
||||
return NULL;
|
||||
}
|
||||
return this->objects_[handle];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Call the all-symbols-read handlers.
|
||||
|
||||
void
|
||||
Plugin_manager::all_symbols_read(Workqueue* workqueue,
|
||||
Input_objects* input_objects,
|
||||
Symbol_table* symtab, Layout* layout,
|
||||
Dirsearch* dirpath, Mapfile* mapfile,
|
||||
Task_token** last_blocker)
|
||||
{
|
||||
this->in_replacement_phase_ = true;
|
||||
this->workqueue_ = workqueue;
|
||||
this->input_objects_ = input_objects;
|
||||
this->symtab_ = symtab;
|
||||
this->layout_ = layout;
|
||||
this->dirpath_ = dirpath;
|
||||
this->mapfile_ = mapfile;
|
||||
this->this_blocker_ = NULL;
|
||||
|
||||
for (this->current_ = this->plugins_.begin();
|
||||
this->current_ != this->plugins_.end();
|
||||
++this->current_)
|
||||
(*this->current_)->all_symbols_read();
|
||||
|
||||
*last_blocker = this->this_blocker_;
|
||||
}
|
||||
|
||||
// Call the cleanup handlers.
|
||||
|
||||
void
|
||||
Plugin_manager::cleanup()
|
||||
{
|
||||
for (this->current_ = this->plugins_.begin();
|
||||
this->current_ != this->plugins_.end();
|
||||
++this->current_)
|
||||
(*this->current_)->cleanup();
|
||||
}
|
||||
|
||||
// Make a new Pluginobj object. This is called when the plugin calls
|
||||
// the add_symbols API.
|
||||
|
||||
Pluginobj*
|
||||
Plugin_manager::make_plugin_object(unsigned int handle)
|
||||
{
|
||||
// Make sure we aren't asked to make an object for the same handle twice.
|
||||
if (this->objects_.size() != handle)
|
||||
return NULL;
|
||||
|
||||
Pluginobj* obj = make_sized_plugin_object(this->input_file_,
|
||||
this->plugin_input_file_.offset);
|
||||
this->objects_.push_back(obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
// Add a new input file.
|
||||
|
||||
ld_plugin_status
|
||||
Plugin_manager::add_input_file(char *pathname)
|
||||
{
|
||||
Input_file_argument file(pathname, false, "", false, this->options_);
|
||||
Input_argument* input_argument = new Input_argument(file);
|
||||
Task_token* next_blocker = new Task_token(true);
|
||||
next_blocker->add_blocker();
|
||||
this->workqueue_->queue_soon(new Read_symbols(this->options_,
|
||||
this->input_objects_,
|
||||
this->symtab_,
|
||||
this->layout_,
|
||||
this->dirpath_,
|
||||
this->mapfile_,
|
||||
input_argument,
|
||||
NULL,
|
||||
this->this_blocker_,
|
||||
next_blocker));
|
||||
this->this_blocker_ = next_blocker;
|
||||
return LDPS_OK;
|
||||
}
|
||||
|
||||
// Class Pluginobj.
|
||||
|
||||
Pluginobj::Pluginobj(const std::string& name, Input_file* input_file,
|
||||
off_t offset)
|
||||
: Object(name, input_file, false, offset),
|
||||
nsyms_(0), syms_(NULL), symbols_(), comdat_map_()
|
||||
{
|
||||
}
|
||||
|
||||
// Get symbol resolution info.
|
||||
|
||||
ld_plugin_status
|
||||
Pluginobj::get_symbol_resolution_info(int nsyms, ld_plugin_symbol* syms) const
|
||||
{
|
||||
if (this->nsyms_ == 0)
|
||||
return LDPS_NO_SYMS;
|
||||
for (int i = 0; i < nsyms; i++)
|
||||
{
|
||||
ld_plugin_symbol* isym = &syms[i];
|
||||
Symbol* lsym = this->symbols_[i];
|
||||
ld_plugin_symbol_resolution res = LDPR_UNKNOWN;
|
||||
|
||||
if (lsym->is_undefined())
|
||||
// The symbol remains undefined.
|
||||
res = LDPR_UNDEF;
|
||||
else if (isym->def == LDPK_UNDEF
|
||||
|| isym->def == LDPK_WEAKUNDEF
|
||||
|| isym->def == LDPK_COMMON)
|
||||
{
|
||||
// The original symbol was undefined or common.
|
||||
if (lsym->source() != Symbol::FROM_OBJECT)
|
||||
res = LDPR_RESOLVED_EXEC;
|
||||
else if (lsym->object()->pluginobj() != NULL)
|
||||
res = LDPR_RESOLVED_IR;
|
||||
else if (lsym->object()->is_dynamic())
|
||||
res = LDPR_RESOLVED_DYN;
|
||||
else
|
||||
res = LDPR_RESOLVED_EXEC;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The original symbol was a definition.
|
||||
if (lsym->source() != Symbol::FROM_OBJECT)
|
||||
res = LDPR_PREEMPTED_REG;
|
||||
else if (lsym->object() == static_cast<const Object*>(this))
|
||||
res = (lsym->in_real_elf()
|
||||
? LDPR_PREVAILING_DEF
|
||||
: LDPR_PREVAILING_DEF_IRONLY);
|
||||
else
|
||||
res = (lsym->object()->pluginobj() != NULL
|
||||
? LDPR_PREEMPTED_IR
|
||||
: LDPR_PREEMPTED_REG);
|
||||
}
|
||||
isym->resolution = res;
|
||||
}
|
||||
return LDPS_OK;
|
||||
}
|
||||
|
||||
// Return TRUE if the comdat group with key COMDAT_KEY from this object
|
||||
// should be kept.
|
||||
|
||||
bool
|
||||
Pluginobj::include_comdat_group(std::string comdat_key, Layout* layout)
|
||||
{
|
||||
std::pair<Comdat_map::iterator, bool> ins =
|
||||
this->comdat_map_.insert(std::make_pair(comdat_key, false));
|
||||
|
||||
// If this is the first time we've seen this comdat key, ask the
|
||||
// layout object whether it should be included.
|
||||
if (ins.second)
|
||||
ins.first->second = layout->add_comdat(NULL, 1, comdat_key, true);
|
||||
|
||||
return ins.first->second;
|
||||
}
|
||||
|
||||
// Class Sized_pluginobj.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
Sized_pluginobj<size, big_endian>::Sized_pluginobj(
|
||||
const std::string& name,
|
||||
Input_file* input_file,
|
||||
off_t offset)
|
||||
: Pluginobj(name, input_file, offset)
|
||||
{
|
||||
}
|
||||
|
||||
// Read the symbols. Not used for plugin objects.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
Sized_pluginobj<size, big_endian>::do_read_symbols(Read_symbols_data*)
|
||||
{
|
||||
gold_unreachable();
|
||||
}
|
||||
|
||||
// Lay out the input sections. Not used for plugin objects.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
Sized_pluginobj<size, big_endian>::do_layout(Symbol_table*, Layout*,
|
||||
Read_symbols_data*)
|
||||
{
|
||||
gold_unreachable();
|
||||
}
|
||||
|
||||
// Add the symbols to the symbol table.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
Sized_pluginobj<size, big_endian>::do_add_symbols(Symbol_table*,
|
||||
Read_symbols_data*)
|
||||
{
|
||||
gold_unreachable();
|
||||
}
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
Sized_pluginobj<size, big_endian>::do_add_symbols(Symbol_table* symtab,
|
||||
Layout* layout)
|
||||
{
|
||||
const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
|
||||
unsigned char symbuf[sym_size];
|
||||
elfcpp::Sym<size, big_endian> sym(symbuf);
|
||||
elfcpp::Sym_write<size, big_endian> osym(symbuf);
|
||||
|
||||
typedef typename elfcpp::Elf_types<size>::Elf_WXword Elf_size_type;
|
||||
|
||||
this->symbols_.resize(this->nsyms_);
|
||||
|
||||
for (int i = 0; i < this->nsyms_; ++i)
|
||||
{
|
||||
const struct ld_plugin_symbol *isym = &this->syms_[i];
|
||||
const char* name = isym->name;
|
||||
const char* ver = isym->version;
|
||||
elfcpp::Elf_Half shndx;
|
||||
elfcpp::STB bind;
|
||||
elfcpp::STV vis;
|
||||
|
||||
if (name != NULL && name[0] == '\0')
|
||||
name = NULL;
|
||||
if (ver != NULL && ver[0] == '\0')
|
||||
ver = NULL;
|
||||
|
||||
switch (isym->def)
|
||||
{
|
||||
case LDPK_WEAKDEF:
|
||||
case LDPK_WEAKUNDEF:
|
||||
bind = elfcpp::STB_WEAK;
|
||||
break;
|
||||
case LDPK_DEF:
|
||||
case LDPK_UNDEF:
|
||||
case LDPK_COMMON:
|
||||
default:
|
||||
bind = elfcpp::STB_GLOBAL;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (isym->def)
|
||||
{
|
||||
case LDPK_DEF:
|
||||
case LDPK_WEAKDEF:
|
||||
shndx = elfcpp::SHN_ABS;
|
||||
break;
|
||||
case LDPK_COMMON:
|
||||
shndx = elfcpp::SHN_COMMON;
|
||||
break;
|
||||
case LDPK_UNDEF:
|
||||
case LDPK_WEAKUNDEF:
|
||||
default:
|
||||
shndx = elfcpp::SHN_UNDEF;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (isym->visibility)
|
||||
{
|
||||
case LDPV_PROTECTED:
|
||||
vis = elfcpp::STV_DEFAULT;
|
||||
break;
|
||||
case LDPV_INTERNAL:
|
||||
vis = elfcpp::STV_DEFAULT;
|
||||
break;
|
||||
case LDPV_HIDDEN:
|
||||
vis = elfcpp::STV_DEFAULT;
|
||||
break;
|
||||
case LDPV_DEFAULT:
|
||||
default:
|
||||
vis = elfcpp::STV_DEFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
if (isym->comdat_key != NULL
|
||||
&& isym->comdat_key[0] != '\0'
|
||||
&& !this->include_comdat_group(isym->comdat_key, layout))
|
||||
shndx = elfcpp::SHN_UNDEF;
|
||||
|
||||
osym.put_st_name(0);
|
||||
osym.put_st_value(0);
|
||||
osym.put_st_size(static_cast<Elf_size_type>(isym->size));
|
||||
osym.put_st_info(bind, elfcpp::STT_NOTYPE);
|
||||
osym.put_st_other(vis, 0);
|
||||
osym.put_st_shndx(shndx);
|
||||
|
||||
this->symbols_[i] =
|
||||
symtab->add_from_pluginobj<size, big_endian>(this, name, ver, &sym);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the size of a section. Not used for plugin objects.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
uint64_t
|
||||
Sized_pluginobj<size, big_endian>::do_section_size(unsigned int)
|
||||
{
|
||||
gold_unreachable();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get the name of a section. Not used for plugin objects.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
std::string
|
||||
Sized_pluginobj<size, big_endian>::do_section_name(unsigned int)
|
||||
{
|
||||
gold_unreachable();
|
||||
return std::string();
|
||||
}
|
||||
|
||||
// Return a view of the contents of a section. Not used for plugin objects.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
Object::Location
|
||||
Sized_pluginobj<size, big_endian>::do_section_contents(unsigned int)
|
||||
{
|
||||
Location loc(0, 0);
|
||||
|
||||
gold_unreachable();
|
||||
return loc;
|
||||
}
|
||||
|
||||
// Return section flags. Not used for plugin objects.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
uint64_t
|
||||
Sized_pluginobj<size, big_endian>::do_section_flags(unsigned int)
|
||||
{
|
||||
gold_unreachable();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Return section address. Not used for plugin objects.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
uint64_t
|
||||
Sized_pluginobj<size, big_endian>::do_section_address(unsigned int)
|
||||
{
|
||||
gold_unreachable();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Return section type. Not used for plugin objects.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
unsigned int
|
||||
Sized_pluginobj<size, big_endian>::do_section_type(unsigned int)
|
||||
{
|
||||
gold_unreachable();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Return the section link field. Not used for plugin objects.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
unsigned int
|
||||
Sized_pluginobj<size, big_endian>::do_section_link(unsigned int)
|
||||
{
|
||||
gold_unreachable();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Return the section link field. Not used for plugin objects.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
unsigned int
|
||||
Sized_pluginobj<size, big_endian>::do_section_info(unsigned int)
|
||||
{
|
||||
gold_unreachable();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Return the section alignment. Not used for plugin objects.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
uint64_t
|
||||
Sized_pluginobj<size, big_endian>::do_section_addralign(unsigned int)
|
||||
{
|
||||
gold_unreachable();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Return the Xindex structure to use. Not used for plugin objects.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
Xindex*
|
||||
Sized_pluginobj<size, big_endian>::do_initialize_xindex()
|
||||
{
|
||||
gold_unreachable();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Get symbol counts. Not used for plugin objects.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
Sized_pluginobj<size, big_endian>::do_get_global_symbol_counts(const Symbol_table*,
|
||||
size_t*, size_t*) const
|
||||
{
|
||||
gold_unreachable();
|
||||
}
|
||||
|
||||
// Class Add_plugin_symbols.
|
||||
|
||||
Add_plugin_symbols::~Add_plugin_symbols()
|
||||
{
|
||||
if (this->this_blocker_ != NULL)
|
||||
delete this->this_blocker_;
|
||||
// next_blocker_ is deleted by the task associated with the next
|
||||
// input file.
|
||||
}
|
||||
|
||||
// We are blocked by this_blocker_. We block next_blocker_. We also
|
||||
// lock the file.
|
||||
|
||||
Task_token*
|
||||
Add_plugin_symbols::is_runnable()
|
||||
{
|
||||
if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
|
||||
return this->this_blocker_;
|
||||
if (this->obj_->is_locked())
|
||||
return this->obj_->token();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
Add_plugin_symbols::locks(Task_locker* tl)
|
||||
{
|
||||
tl->add(this, this->next_blocker_);
|
||||
tl->add(this, this->obj_->token());
|
||||
}
|
||||
|
||||
// Add the symbols in the object to the symbol table.
|
||||
|
||||
void
|
||||
Add_plugin_symbols::run(Workqueue*)
|
||||
{
|
||||
this->obj_->add_symbols(this->symtab_, this->layout_);
|
||||
}
|
||||
|
||||
// Class Plugin_cleanup. This task calls the plugin cleanup hooks once all
|
||||
// replacement files have been added.
|
||||
|
||||
class Plugin_cleanup : public Task
|
||||
{
|
||||
public:
|
||||
Plugin_cleanup(Task_token* this_blocker, Task_token* next_blocker)
|
||||
: this_blocker_(this_blocker), next_blocker_(next_blocker)
|
||||
{ }
|
||||
|
||||
~Plugin_cleanup()
|
||||
{
|
||||
if (this->this_blocker_ != NULL)
|
||||
delete this->this_blocker_;
|
||||
}
|
||||
|
||||
Task_token*
|
||||
is_runnable()
|
||||
{
|
||||
if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
|
||||
return this->this_blocker_;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
locks(Task_locker* tl)
|
||||
{ tl->add(this, this->next_blocker_); }
|
||||
|
||||
void
|
||||
run(Workqueue*)
|
||||
{ parameters->options().plugins()->cleanup(); }
|
||||
|
||||
std::string
|
||||
get_name() const
|
||||
{ return "Plugin_cleanup"; }
|
||||
|
||||
private:
|
||||
Task_token* this_blocker_;
|
||||
Task_token* next_blocker_;
|
||||
};
|
||||
|
||||
// Class Plugin_hook.
|
||||
|
||||
Plugin_hook::~Plugin_hook()
|
||||
{
|
||||
}
|
||||
|
||||
// Return whether a Plugin_hook task is runnable.
|
||||
|
||||
Task_token*
|
||||
Plugin_hook::is_runnable()
|
||||
{
|
||||
if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
|
||||
return this->this_blocker_;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Return a Task_locker for a Plugin_hook task. We don't need any
|
||||
// locks here.
|
||||
|
||||
void
|
||||
Plugin_hook::locks(Task_locker*)
|
||||
{
|
||||
}
|
||||
|
||||
// Run a Plugin_hook task.
|
||||
|
||||
void
|
||||
Plugin_hook::run(Workqueue* workqueue)
|
||||
{
|
||||
this->do_plugin_hook(workqueue);
|
||||
}
|
||||
|
||||
// Run the "all symbols read" plugin hook.
|
||||
|
||||
void
|
||||
Plugin_hook::do_plugin_hook(Workqueue* workqueue)
|
||||
{
|
||||
gold_assert(this->options_.has_plugins());
|
||||
this->options_.plugins()->all_symbols_read(workqueue,
|
||||
this->input_objects_,
|
||||
this->symtab_,
|
||||
this->layout_,
|
||||
this->dirpath_,
|
||||
this->mapfile_,
|
||||
&this->this_blocker_);
|
||||
workqueue->queue_soon(new Plugin_cleanup(this->this_blocker_,
|
||||
this->next_blocker_));
|
||||
}
|
||||
|
||||
// The C interface routines called by the plugins.
|
||||
|
||||
#ifdef ENABLE_PLUGINS
|
||||
|
||||
// Register a claim-file handler.
|
||||
|
||||
static enum ld_plugin_status
|
||||
register_claim_file(ld_plugin_claim_file_handler handler)
|
||||
{
|
||||
gold_assert(parameters->options().has_plugins());
|
||||
parameters->options().plugins()->set_claim_file_handler(handler);
|
||||
return LDPS_OK;
|
||||
}
|
||||
|
||||
// Register an all-symbols-read handler.
|
||||
|
||||
static enum ld_plugin_status
|
||||
register_all_symbols_read(ld_plugin_all_symbols_read_handler handler)
|
||||
{
|
||||
gold_assert(parameters->options().has_plugins());
|
||||
parameters->options().plugins()->set_all_symbols_read_handler(handler);
|
||||
return LDPS_OK;
|
||||
}
|
||||
|
||||
// Register a cleanup handler.
|
||||
|
||||
static enum ld_plugin_status
|
||||
register_cleanup(ld_plugin_cleanup_handler handler)
|
||||
{
|
||||
gold_assert(parameters->options().has_plugins());
|
||||
parameters->options().plugins()->set_cleanup_handler(handler);
|
||||
return LDPS_OK;
|
||||
}
|
||||
|
||||
// Add symbols from a plugin-claimed input file.
|
||||
|
||||
static enum ld_plugin_status
|
||||
add_symbols(void* handle, int nsyms, const ld_plugin_symbol *syms)
|
||||
{
|
||||
gold_assert(parameters->options().has_plugins());
|
||||
Pluginobj* obj = parameters->options().plugins()->make_plugin_object(
|
||||
static_cast<unsigned int>(reinterpret_cast<intptr_t>(handle)));
|
||||
if (obj == NULL)
|
||||
return LDPS_ERR;
|
||||
obj->store_incoming_symbols(nsyms, syms);
|
||||
return LDPS_OK;
|
||||
}
|
||||
|
||||
// Get the symbol resolution info for a plugin-claimed input file.
|
||||
|
||||
static enum ld_plugin_status
|
||||
get_symbols(const void * handle, int nsyms, ld_plugin_symbol* syms)
|
||||
{
|
||||
gold_assert(parameters->options().has_plugins());
|
||||
Pluginobj* obj = parameters->options().plugins()->object(
|
||||
static_cast<unsigned int>(reinterpret_cast<intptr_t>(handle)));
|
||||
if (obj == NULL)
|
||||
return LDPS_ERR;
|
||||
return obj->get_symbol_resolution_info(nsyms, syms);
|
||||
}
|
||||
|
||||
// Add a new (real) input file generated by a plugin.
|
||||
|
||||
static enum ld_plugin_status
|
||||
add_input_file(char *pathname)
|
||||
{
|
||||
gold_assert(parameters->options().has_plugins());
|
||||
return parameters->options().plugins()->add_input_file(pathname);
|
||||
}
|
||||
|
||||
// Issue a diagnostic message from a plugin.
|
||||
|
||||
static enum ld_plugin_status
|
||||
message(int level, char * format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
|
||||
switch (level)
|
||||
{
|
||||
case LDPL_INFO:
|
||||
parameters->errors()->info(format, args);
|
||||
break;
|
||||
case LDPL_WARNING:
|
||||
parameters->errors()->warning(format, args);
|
||||
break;
|
||||
case LDPL_ERROR:
|
||||
default:
|
||||
parameters->errors()->error(format, args);
|
||||
break;
|
||||
case LDPL_FATAL:
|
||||
parameters->errors()->fatal(format, args);
|
||||
break;
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
return LDPS_OK;
|
||||
}
|
||||
|
||||
#endif // ENABLE_PLUGINS
|
||||
|
||||
// Allocate a Pluginobj object of the appropriate size and endianness.
|
||||
|
||||
static Pluginobj*
|
||||
make_sized_plugin_object(Input_file* input_file, off_t offset)
|
||||
{
|
||||
Target* target;
|
||||
Pluginobj* obj = NULL;
|
||||
|
||||
if (parameters->target_valid())
|
||||
target = const_cast<Target*>(¶meters->target());
|
||||
else
|
||||
target = const_cast<Target*>(¶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.
|
457
gold/plugin.h
Normal file
457
gold/plugin.h
Normal file
|
@ -0,0 +1,457 @@
|
|||
// plugin.h -- plugin manager for gold -*- C++ -*-
|
||||
|
||||
// Copyright 2008 Free Software Foundation, Inc.
|
||||
// Written by Cary Coutant <ccoutant@google.com>.
|
||||
|
||||
// This file is part of gold.
|
||||
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
||||
// MA 02110-1301, USA.
|
||||
|
||||
#ifndef GOLD_PLUGIN_H
|
||||
#define GOLD_PLUGIN_H
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
#include "object.h"
|
||||
#include "plugin-api.h"
|
||||
#include "workqueue.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
class General_options;
|
||||
class Input_file;
|
||||
class Input_objects;
|
||||
class Symbol_table;
|
||||
class Layout;
|
||||
class Dirsearch;
|
||||
class Mapfile;
|
||||
class Task_token;
|
||||
class Pluginobj;
|
||||
|
||||
// This class represents a single plugin library.
|
||||
|
||||
class Plugin
|
||||
{
|
||||
public:
|
||||
Plugin(const char* args)
|
||||
: handle_(NULL),
|
||||
args_(args),
|
||||
claim_file_handler_(NULL),
|
||||
all_symbols_read_handler_(NULL),
|
||||
cleanup_handler_(NULL)
|
||||
{ }
|
||||
|
||||
~Plugin()
|
||||
{ }
|
||||
|
||||
// Load the library and call its entry point.
|
||||
void
|
||||
load();
|
||||
|
||||
// Call the claim-file handler.
|
||||
bool
|
||||
claim_file(struct ld_plugin_input_file *plugin_input_file);
|
||||
|
||||
// Call the all-symbols-read handler.
|
||||
void
|
||||
all_symbols_read();
|
||||
|
||||
// Call the cleanup handler.
|
||||
void
|
||||
cleanup();
|
||||
|
||||
// Register a claim-file handler.
|
||||
void
|
||||
set_claim_file_handler(ld_plugin_claim_file_handler handler)
|
||||
{ this->claim_file_handler_ = handler; }
|
||||
|
||||
// Register an all-symbols-read handler.
|
||||
void
|
||||
set_all_symbols_read_handler(ld_plugin_all_symbols_read_handler handler)
|
||||
{ this->all_symbols_read_handler_ = handler; }
|
||||
|
||||
// Register a claim-file handler.
|
||||
void
|
||||
set_cleanup_handler(ld_plugin_cleanup_handler handler)
|
||||
{ this->cleanup_handler_ = handler; }
|
||||
|
||||
private:
|
||||
Plugin(const Plugin&);
|
||||
Plugin& operator=(const Plugin&);
|
||||
|
||||
// The shared library handle returned by dlopen.
|
||||
void* handle_;
|
||||
// The argument string given to --plugin.
|
||||
const char* args_;
|
||||
// The plugin's event handlers.
|
||||
ld_plugin_claim_file_handler claim_file_handler_;
|
||||
ld_plugin_all_symbols_read_handler all_symbols_read_handler_;
|
||||
ld_plugin_cleanup_handler cleanup_handler_;
|
||||
};
|
||||
|
||||
// A manager class for plugins.
|
||||
|
||||
class Plugin_manager
|
||||
{
|
||||
public:
|
||||
Plugin_manager(const General_options& options)
|
||||
: plugins_(), in_replacement_phase_(false), options_(options),
|
||||
workqueue_(NULL), input_objects_(NULL), symtab_(NULL), layout_(NULL),
|
||||
dirpath_(NULL), mapfile_(NULL), this_blocker_(NULL)
|
||||
{ this->current_ = plugins_.end(); }
|
||||
|
||||
~Plugin_manager();
|
||||
|
||||
// Add a plugin library.
|
||||
void
|
||||
add_plugin(const char* args)
|
||||
{ this->plugins_.push_back(new Plugin(args)); }
|
||||
|
||||
// Load all plugin libraries.
|
||||
void
|
||||
load_plugins();
|
||||
|
||||
// Call the plugin claim-file handlers in turn to see if any claim the file.
|
||||
Pluginobj*
|
||||
claim_file(Input_file *input_file, off_t offset, off_t filesize);
|
||||
|
||||
// Call the all-symbols-read handlers.
|
||||
void
|
||||
all_symbols_read(Workqueue* workqueue, Input_objects* input_objects,
|
||||
Symbol_table* symtab, Layout* layout, Dirsearch* dirpath,
|
||||
Mapfile* mapfile, Task_token** last_blocker);
|
||||
|
||||
// Call the cleanup handlers.
|
||||
void
|
||||
cleanup();
|
||||
|
||||
// Register a claim-file handler.
|
||||
void
|
||||
set_claim_file_handler(ld_plugin_claim_file_handler handler)
|
||||
{
|
||||
gold_assert(this->current_ != plugins_.end());
|
||||
(*this->current_)->set_claim_file_handler(handler);
|
||||
}
|
||||
|
||||
// Register an all-symbols-read handler.
|
||||
void
|
||||
set_all_symbols_read_handler(ld_plugin_all_symbols_read_handler handler)
|
||||
{
|
||||
gold_assert(this->current_ != plugins_.end());
|
||||
(*this->current_)->set_all_symbols_read_handler(handler);
|
||||
}
|
||||
|
||||
// Register a claim-file handler.
|
||||
void
|
||||
set_cleanup_handler(ld_plugin_cleanup_handler handler)
|
||||
{
|
||||
gold_assert(this->current_ != plugins_.end());
|
||||
(*this->current_)->set_cleanup_handler(handler);
|
||||
}
|
||||
|
||||
// Make a new Pluginobj object. This is called when the plugin calls
|
||||
// the add_symbols API.
|
||||
Pluginobj*
|
||||
make_plugin_object(unsigned int handle);
|
||||
|
||||
// Return the Pluginobj associated with the given HANDLE.
|
||||
Pluginobj*
|
||||
object(unsigned int handle) const
|
||||
{
|
||||
if (handle >= this->objects_.size())
|
||||
return NULL;
|
||||
return this->objects_[handle];
|
||||
}
|
||||
|
||||
// Add a new input file.
|
||||
ld_plugin_status
|
||||
add_input_file(char *pathname);
|
||||
|
||||
// Return TRUE if we are in the replacement phase.
|
||||
bool
|
||||
in_replacement_phase() const
|
||||
{ return this->in_replacement_phase_; }
|
||||
|
||||
private:
|
||||
Plugin_manager(const Plugin_manager&);
|
||||
Plugin_manager& operator=(const Plugin_manager&);
|
||||
|
||||
typedef std::list<Plugin*> Plugin_list;
|
||||
typedef std::vector<Pluginobj*> Object_list;
|
||||
|
||||
// The list of plugin libraries.
|
||||
Plugin_list plugins_;
|
||||
// A pointer to the current plugin. Used while loading plugins.
|
||||
Plugin_list::iterator current_;
|
||||
|
||||
// The list of plugin objects. The index of an item in this list
|
||||
// serves as the "handle" that we pass to the plugins.
|
||||
Object_list objects_;
|
||||
|
||||
// The file currently up for claim by the plugins.
|
||||
Input_file* input_file_;
|
||||
struct ld_plugin_input_file plugin_input_file_;
|
||||
|
||||
// TRUE after the all symbols read event; indicates that we are
|
||||
// processing replacement files whose symbols should replace the
|
||||
// placeholder symbols from the Pluginobj objects.
|
||||
bool in_replacement_phase_;
|
||||
|
||||
const General_options& options_;
|
||||
Workqueue* workqueue_;
|
||||
Input_objects* input_objects_;
|
||||
Symbol_table* symtab_;
|
||||
Layout* layout_;
|
||||
Dirsearch* dirpath_;
|
||||
Mapfile* mapfile_;
|
||||
Task_token* this_blocker_;
|
||||
};
|
||||
|
||||
|
||||
// An object file claimed by a plugin. This is an abstract base class.
|
||||
// The implementation is the template class Sized_pluginobj.
|
||||
|
||||
class Pluginobj : public Object
|
||||
{
|
||||
public:
|
||||
|
||||
typedef std::vector<Symbol*> Symbols;
|
||||
|
||||
Pluginobj(const std::string& name, Input_file* input_file, off_t offset);
|
||||
|
||||
// Fill in the symbol resolution status for the given plugin symbols.
|
||||
ld_plugin_status
|
||||
get_symbol_resolution_info(int nsyms, ld_plugin_symbol* syms) const;
|
||||
|
||||
// Add symbol information to the global symbol table.
|
||||
void
|
||||
add_symbols(Symbol_table* symtab, Layout* layout)
|
||||
{ this->do_add_symbols(symtab, layout); }
|
||||
|
||||
// Store the incoming symbols from the plugin for later processing.
|
||||
void
|
||||
store_incoming_symbols(int nsyms, const struct ld_plugin_symbol* syms)
|
||||
{
|
||||
this->nsyms_ = nsyms;
|
||||
this->syms_ = syms;
|
||||
}
|
||||
|
||||
// Return TRUE if the comdat group with key COMDAT_KEY from this object
|
||||
// should be kept.
|
||||
bool
|
||||
include_comdat_group(std::string comdat_key, Layout* layout);
|
||||
|
||||
protected:
|
||||
// Return TRUE if this is an object claimed by a plugin.
|
||||
virtual Pluginobj*
|
||||
do_pluginobj()
|
||||
{ return this; }
|
||||
|
||||
// Add symbol information to the global symbol table--implemented by
|
||||
// child class.
|
||||
virtual void
|
||||
do_add_symbols(Symbol_table*, Layout*) = 0;
|
||||
|
||||
// The number of symbols provided by the plugin.
|
||||
int nsyms_;
|
||||
|
||||
// The symbols provided by the plugin.
|
||||
const struct ld_plugin_symbol* syms_;
|
||||
|
||||
// The entries in the symbol table for the external symbols.
|
||||
Symbols symbols_;
|
||||
|
||||
private:
|
||||
// Map a comdat key symbol to a boolean indicating whether the comdat
|
||||
// group in this object with that key should be kept.
|
||||
typedef Unordered_map<std::string, bool> Comdat_map;
|
||||
Comdat_map comdat_map_;
|
||||
};
|
||||
|
||||
// A plugin object, size-specific version.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
class Sized_pluginobj : public Pluginobj
|
||||
{
|
||||
public:
|
||||
Sized_pluginobj(const std::string& name, Input_file* input_file,
|
||||
off_t offset);
|
||||
|
||||
// Read the symbols.
|
||||
void
|
||||
do_read_symbols(Read_symbols_data*);
|
||||
|
||||
// Lay out the input sections.
|
||||
void
|
||||
do_layout(Symbol_table*, Layout*, Read_symbols_data*);
|
||||
|
||||
// Add the symbols to the symbol table.
|
||||
void
|
||||
do_add_symbols(Symbol_table*, Read_symbols_data*);
|
||||
|
||||
void
|
||||
do_add_symbols(Symbol_table*, Layout*);
|
||||
|
||||
// Get the size of a section.
|
||||
uint64_t
|
||||
do_section_size(unsigned int shndx);
|
||||
|
||||
// Get the name of a section.
|
||||
std::string
|
||||
do_section_name(unsigned int shndx);
|
||||
|
||||
// Return a view of the contents of a section.
|
||||
Object::Location
|
||||
do_section_contents(unsigned int shndx);
|
||||
|
||||
// Return section flags.
|
||||
uint64_t
|
||||
do_section_flags(unsigned int shndx);
|
||||
|
||||
// Return section address.
|
||||
uint64_t
|
||||
do_section_address(unsigned int shndx);
|
||||
|
||||
// Return section type.
|
||||
unsigned int
|
||||
do_section_type(unsigned int shndx);
|
||||
|
||||
// Return the section link field.
|
||||
unsigned int
|
||||
do_section_link(unsigned int shndx);
|
||||
|
||||
// Return the section link field.
|
||||
unsigned int
|
||||
do_section_info(unsigned int shndx);
|
||||
|
||||
// Return the section alignment.
|
||||
uint64_t
|
||||
do_section_addralign(unsigned int shndx);
|
||||
|
||||
// Return the Xindex structure to use.
|
||||
Xindex*
|
||||
do_initialize_xindex();
|
||||
|
||||
// Get symbol counts.
|
||||
void
|
||||
do_get_global_symbol_counts(const Symbol_table*, size_t*, size_t*) const;
|
||||
|
||||
// Add placeholder symbols from a claimed file.
|
||||
ld_plugin_status
|
||||
add_symbols_from_plugin(int nsyms, const ld_plugin_symbol* syms);
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
// This Task handles adding the symbols to the symbol table. These
|
||||
// tasks must be run in the same order as the arguments appear on the
|
||||
// command line.
|
||||
|
||||
class Add_plugin_symbols : public Task
|
||||
{
|
||||
public:
|
||||
// THIS_BLOCKER is used to prevent this task from running before the
|
||||
// one for the previous input file. NEXT_BLOCKER is used to prevent
|
||||
// the next task from running.
|
||||
Add_plugin_symbols(Symbol_table* symtab,
|
||||
Layout* layout,
|
||||
Pluginobj* obj,
|
||||
Task_token* this_blocker,
|
||||
Task_token* next_blocker)
|
||||
: symtab_(symtab), layout_(layout), obj_(obj),
|
||||
this_blocker_(this_blocker), next_blocker_(next_blocker)
|
||||
{ }
|
||||
|
||||
~Add_plugin_symbols();
|
||||
|
||||
// The standard Task methods.
|
||||
|
||||
Task_token*
|
||||
is_runnable();
|
||||
|
||||
void
|
||||
locks(Task_locker*);
|
||||
|
||||
void
|
||||
run(Workqueue*);
|
||||
|
||||
std::string
|
||||
get_name() const
|
||||
{ return "Add_plugin_symbols " + this->obj_->name(); }
|
||||
|
||||
private:
|
||||
Symbol_table* symtab_;
|
||||
Layout* layout_;
|
||||
Pluginobj* obj_;
|
||||
Task_token* this_blocker_;
|
||||
Task_token* next_blocker_;
|
||||
};
|
||||
|
||||
// This Task handles handles the "all symbols read" event hook.
|
||||
// The plugin may add additional input files at this time, which must
|
||||
// be queued for reading.
|
||||
|
||||
class Plugin_hook : public Task
|
||||
{
|
||||
public:
|
||||
Plugin_hook(const General_options& options, Input_objects* input_objects,
|
||||
Symbol_table* symtab, Layout* layout, Dirsearch* dirpath,
|
||||
Mapfile* mapfile, Task_token* this_blocker,
|
||||
Task_token* next_blocker)
|
||||
: options_(options), input_objects_(input_objects), symtab_(symtab),
|
||||
layout_(layout), dirpath_(dirpath), mapfile_(mapfile),
|
||||
this_blocker_(this_blocker), next_blocker_(next_blocker)
|
||||
{ }
|
||||
|
||||
~Plugin_hook();
|
||||
|
||||
// The standard Task methods.
|
||||
|
||||
Task_token*
|
||||
is_runnable();
|
||||
|
||||
void
|
||||
locks(Task_locker*);
|
||||
|
||||
void
|
||||
run(Workqueue*);
|
||||
|
||||
std::string
|
||||
get_name() const
|
||||
{ return "Plugin_hook"; }
|
||||
|
||||
private:
|
||||
// Call the plugin hook.
|
||||
void
|
||||
do_plugin_hook(Workqueue*);
|
||||
|
||||
const General_options& options_;
|
||||
Input_objects* input_objects_;
|
||||
Symbol_table* symtab_;
|
||||
Layout* layout_;
|
||||
Dirsearch* dirpath_;
|
||||
Mapfile* mapfile_;
|
||||
Task_token* this_blocker_;
|
||||
Task_token* next_blocker_;
|
||||
};
|
||||
|
||||
} // End namespace gold.
|
||||
|
||||
#endif // !defined(GOLD_PLUGIN_H)
|
|
@ -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
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "target.h"
|
||||
#include "object.h"
|
||||
#include "symtab.h"
|
||||
#include "plugin.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
@ -240,6 +241,24 @@ Symbol_table::resolve(Sized_symbol<size>* to,
|
|||
to->set_in_dyn();
|
||||
}
|
||||
|
||||
// Record if we've seen this symbol in a real ELF object (i.e., the
|
||||
// symbol is referenced from outside the world known to the plugin).
|
||||
if (object->pluginobj() == NULL)
|
||||
to->set_in_real_elf();
|
||||
|
||||
// If we're processing replacement files, allow new symbols to override
|
||||
// the placeholders from the plugin objects.
|
||||
if (to->source() == Symbol::FROM_OBJECT)
|
||||
{
|
||||
Pluginobj* obj = to->object()->pluginobj();
|
||||
if (obj != NULL
|
||||
&& parameters->options().plugins()->in_replacement_phase())
|
||||
{
|
||||
this->override(to, sym, st_shndx, is_ordinary, object, version);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int frombits = symbol_to_bits(sym.get_st_bind(),
|
||||
object->is_dynamic(),
|
||||
st_shndx, is_ordinary,
|
||||
|
|
117
gold/symtab.cc
117
gold/symtab.cc
|
@ -37,6 +37,7 @@
|
|||
#include "target.h"
|
||||
#include "workqueue.h"
|
||||
#include "symtab.h"
|
||||
#include "plugin.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
@ -73,6 +74,7 @@ Symbol::init_fields(const char* name, const char* version,
|
|||
this->is_copied_from_dynobj_ = false;
|
||||
this->is_forced_local_ = false;
|
||||
this->is_ordinary_shndx_ = false;
|
||||
this->in_real_elf_ = false;
|
||||
}
|
||||
|
||||
// Return the demangled version of the symbol's name, but only
|
||||
|
@ -117,6 +119,7 @@ Symbol::init_base_object(const char* name, const char* version, Object* object,
|
|||
this->source_ = FROM_OBJECT;
|
||||
this->in_reg_ = !object->is_dynamic();
|
||||
this->in_dyn_ = object->is_dynamic();
|
||||
this->in_real_elf_ = object->pluginobj() == NULL;
|
||||
}
|
||||
|
||||
// Initialize the fields in the base class Symbol for a symbol defined
|
||||
|
@ -133,6 +136,7 @@ Symbol::init_base_output_data(const char* name, const char* version,
|
|||
this->u_.in_output_data.offset_is_from_end = offset_is_from_end;
|
||||
this->source_ = IN_OUTPUT_DATA;
|
||||
this->in_reg_ = true;
|
||||
this->in_real_elf_ = true;
|
||||
}
|
||||
|
||||
// Initialize the fields in the base class Symbol for a symbol defined
|
||||
|
@ -150,6 +154,7 @@ Symbol::init_base_output_segment(const char* name, const char* version,
|
|||
this->u_.in_output_segment.offset_base = offset_base;
|
||||
this->source_ = IN_OUTPUT_SEGMENT;
|
||||
this->in_reg_ = true;
|
||||
this->in_real_elf_ = true;
|
||||
}
|
||||
|
||||
// Initialize the fields in the base class Symbol for a symbol defined
|
||||
|
@ -163,6 +168,7 @@ Symbol::init_base_constant(const char* name, const char* version,
|
|||
this->init_fields(name, version, type, binding, visibility, nonvis);
|
||||
this->source_ = IS_CONSTANT;
|
||||
this->in_reg_ = true;
|
||||
this->in_real_elf_ = true;
|
||||
}
|
||||
|
||||
// Initialize the fields in the base class Symbol for an undefined
|
||||
|
@ -177,6 +183,7 @@ Symbol::init_base_undefined(const char* name, const char* version,
|
|||
this->dynsym_index_ = -1U;
|
||||
this->source_ = IS_UNDEFINED;
|
||||
this->in_reg_ = true;
|
||||
this->in_real_elf_ = true;
|
||||
}
|
||||
|
||||
// Allocate a common symbol in the base.
|
||||
|
@ -357,6 +364,7 @@ Symbol::output_section() const
|
|||
if (shndx != elfcpp::SHN_UNDEF && this->is_ordinary_shndx_)
|
||||
{
|
||||
gold_assert(!this->u_.from_object.object->is_dynamic());
|
||||
gold_assert(this->u_.from_object.object->pluginobj() == NULL);
|
||||
Relobj* relobj = static_cast<Relobj*>(this->u_.from_object.object);
|
||||
return relobj->output_section(shndx);
|
||||
}
|
||||
|
@ -973,6 +981,68 @@ Symbol_table::add_from_relobj(
|
|||
}
|
||||
}
|
||||
|
||||
// Add a symbol from a plugin-claimed file.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
Symbol*
|
||||
Symbol_table::add_from_pluginobj(
|
||||
Sized_pluginobj<size, big_endian>* obj,
|
||||
const char* name,
|
||||
const char* ver,
|
||||
elfcpp::Sym<size, big_endian>* sym)
|
||||
{
|
||||
unsigned int st_shndx = sym->get_st_shndx();
|
||||
|
||||
Stringpool::Key ver_key = 0;
|
||||
bool def = false;
|
||||
bool local = false;
|
||||
|
||||
if (ver != NULL)
|
||||
{
|
||||
ver = this->namepool_.add(ver, true, &ver_key);
|
||||
}
|
||||
// We don't want to assign a version to an undefined symbol,
|
||||
// even if it is listed in the version script. FIXME: What
|
||||
// about a common symbol?
|
||||
else
|
||||
{
|
||||
if (!this->version_script_.empty()
|
||||
&& st_shndx != elfcpp::SHN_UNDEF)
|
||||
{
|
||||
// The symbol name did not have a version, but the
|
||||
// version script may assign a version anyway.
|
||||
std::string version;
|
||||
if (this->version_script_.get_symbol_version(name, &version))
|
||||
{
|
||||
// The version can be empty if the version script is
|
||||
// only used to force some symbols to be local.
|
||||
if (!version.empty())
|
||||
{
|
||||
ver = this->namepool_.add_with_length(version.c_str(),
|
||||
version.length(),
|
||||
true,
|
||||
&ver_key);
|
||||
def = true;
|
||||
}
|
||||
}
|
||||
else if (this->version_script_.symbol_is_local(name))
|
||||
local = true;
|
||||
}
|
||||
}
|
||||
|
||||
Stringpool::Key name_key;
|
||||
name = this->namepool_.add(name, true, &name_key);
|
||||
|
||||
Sized_symbol<size>* res;
|
||||
res = this->add_from_object(obj, name, name_key, ver, ver_key,
|
||||
def, *sym, st_shndx, true, st_shndx);
|
||||
|
||||
if (local)
|
||||
this->force_local(res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// Add all the symbols in a dynamic object to the hash table.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
|
@ -2043,6 +2113,11 @@ Symbol_table::sized_finalize_symbol(Symbol* unsized_sym)
|
|||
value = 0;
|
||||
shndx = elfcpp::SHN_UNDEF;
|
||||
}
|
||||
else if (symobj->pluginobj() != NULL)
|
||||
{
|
||||
value = 0;
|
||||
shndx = elfcpp::SHN_UNDEF;
|
||||
}
|
||||
else if (shndx == elfcpp::SHN_UNDEF)
|
||||
value = 0;
|
||||
else if (!is_ordinary
|
||||
|
@ -2261,6 +2336,8 @@ Symbol_table::sized_write_globals(const Input_objects* input_objects,
|
|||
dynsym_value = target.dynsym_value(sym);
|
||||
shndx = elfcpp::SHN_UNDEF;
|
||||
}
|
||||
else if (symobj->pluginobj() != NULL)
|
||||
shndx = elfcpp::SHN_UNDEF;
|
||||
else if (in_shndx == elfcpp::SHN_UNDEF
|
||||
|| (!is_ordinary
|
||||
&& (in_shndx == elfcpp::SHN_ABS
|
||||
|
@ -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
|
||||
|
|
|
@ -43,6 +43,8 @@ class Object;
|
|||
class Relobj;
|
||||
template<int size, bool big_endian>
|
||||
class Sized_relobj;
|
||||
template<int size, bool big_endian>
|
||||
class Sized_pluginobj;
|
||||
class Dynobj;
|
||||
template<int size, bool big_endian>
|
||||
class Sized_dynobj;
|
||||
|
@ -273,6 +275,18 @@ class Symbol
|
|||
set_in_dyn()
|
||||
{ this->in_dyn_ = true; }
|
||||
|
||||
// Return whether this symbol has been seen in a real ELF object.
|
||||
// (IN_REG will return TRUE if the symbol has been seen in either
|
||||
// a real ELF object or an object claimed by a plugin.)
|
||||
bool
|
||||
in_real_elf() const
|
||||
{ return this->in_real_elf_; }
|
||||
|
||||
// Mark this symbol as having been seen in a real ELF object.
|
||||
void
|
||||
set_in_real_elf()
|
||||
{ this->in_real_elf_ = true; }
|
||||
|
||||
// Return the index of this symbol in the output file symbol table.
|
||||
// A value of -1U means that this symbol is not going into the
|
||||
// output file. This starts out as zero, and is set to a non-zero
|
||||
|
@ -871,8 +885,10 @@ class Symbol
|
|||
bool is_forced_local_ : 1;
|
||||
// True if the field u_.from_object.shndx is an ordinary section
|
||||
// index, not one of the special codes from SHN_LORESERVE to
|
||||
// SHN_HIRESERVE.
|
||||
// SHN_HIRESERVE (bit 31).
|
||||
bool is_ordinary_shndx_ : 1;
|
||||
// True if we've seen this symbol in a real ELF object.
|
||||
bool in_real_elf_ : 1;
|
||||
};
|
||||
|
||||
// The parts of a symbol which are size specific. Using a template
|
||||
|
@ -1139,6 +1155,14 @@ class Symbol_table
|
|||
typename Sized_relobj<size, big_endian>::Symbols*,
|
||||
size_t* defined);
|
||||
|
||||
// Add one external symbol from the plugin object OBJ to the symbol table.
|
||||
// Returns a pointer to the resolved symbol in the symbol table.
|
||||
template<int size, bool big_endian>
|
||||
Symbol*
|
||||
add_from_pluginobj(Sized_pluginobj<size, big_endian>* obj,
|
||||
const char* name, const char* ver,
|
||||
elfcpp::Sym<size, big_endian>* sym);
|
||||
|
||||
// Add COUNT dynamic symbols from the dynamic object DYNOBJ to the
|
||||
// symbol table. SYMS is the symbols. SYM_NAMES is their names.
|
||||
// SYM_NAME_SIZE is the size of SYM_NAMES. The other parameters are
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
427
gold/testsuite/plugin_test.c
Normal file
427
gold/testsuite/plugin_test.c
Normal file
|
@ -0,0 +1,427 @@
|
|||
/* test_plugin.c -- simple linker plugin test
|
||||
|
||||
Copyright 2008 Free Software Foundation, Inc.
|
||||
Written by Cary Coutant <ccoutant@google.com>.
|
||||
|
||||
This file is part of gold.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
||||
MA 02110-1301, USA. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "plugin-api.h"
|
||||
|
||||
struct claimed_file
|
||||
{
|
||||
const char* name;
|
||||
void* handle;
|
||||
int nsyms;
|
||||
struct ld_plugin_symbol* syms;
|
||||
struct claimed_file* next;
|
||||
};
|
||||
|
||||
static struct claimed_file* first_claimed_file = NULL;
|
||||
static struct claimed_file* last_claimed_file = NULL;
|
||||
|
||||
static ld_plugin_register_claim_file register_claim_file_hook = NULL;
|
||||
static ld_plugin_register_all_symbols_read register_all_symbols_read_hook = NULL;
|
||||
static ld_plugin_register_cleanup register_cleanup_hook = NULL;
|
||||
static ld_plugin_add_symbols add_symbols = NULL;
|
||||
static ld_plugin_get_symbols get_symbols = NULL;
|
||||
static ld_plugin_add_input_file add_input_file = NULL;
|
||||
static ld_plugin_message message = NULL;
|
||||
|
||||
#define MAXOPTS 10
|
||||
|
||||
static const char *opts[MAXOPTS];
|
||||
static int nopts = 0;
|
||||
|
||||
enum ld_plugin_status onload(struct ld_plugin_tv *tv);
|
||||
enum ld_plugin_status claim_file_hook(const struct ld_plugin_input_file *file,
|
||||
int *claimed);
|
||||
enum ld_plugin_status all_symbols_read_hook(void);
|
||||
enum ld_plugin_status cleanup_hook(void);
|
||||
|
||||
enum ld_plugin_status
|
||||
onload(struct ld_plugin_tv *tv)
|
||||
{
|
||||
struct ld_plugin_tv *entry;
|
||||
int api_version = 0;
|
||||
int gold_version = 0;
|
||||
int i;
|
||||
|
||||
for (entry = tv; entry->tv_tag != LDPT_NULL; ++entry)
|
||||
{
|
||||
switch (entry->tv_tag)
|
||||
{
|
||||
case LDPT_API_VERSION:
|
||||
api_version = entry->tv_u.tv_val;
|
||||
break;
|
||||
case LDPT_GOLD_VERSION:
|
||||
gold_version = entry->tv_u.tv_val;
|
||||
break;
|
||||
case LDPT_LINKER_OUTPUT:
|
||||
break;
|
||||
case LDPT_OPTION:
|
||||
if (nopts < MAXOPTS)
|
||||
opts[nopts++] = entry->tv_u.tv_string;
|
||||
break;
|
||||
case LDPT_REGISTER_CLAIM_FILE_HOOK:
|
||||
register_claim_file_hook = entry->tv_u.tv_register_claim_file;
|
||||
break;
|
||||
case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK:
|
||||
register_all_symbols_read_hook =
|
||||
entry->tv_u.tv_register_all_symbols_read;
|
||||
break;
|
||||
case LDPT_REGISTER_CLEANUP_HOOK:
|
||||
register_cleanup_hook = entry->tv_u.tv_register_cleanup;
|
||||
break;
|
||||
case LDPT_ADD_SYMBOLS:
|
||||
add_symbols = entry->tv_u.tv_add_symbols;
|
||||
break;
|
||||
case LDPT_GET_SYMBOLS:
|
||||
get_symbols = entry->tv_u.tv_get_symbols;
|
||||
break;
|
||||
case LDPT_ADD_INPUT_FILE:
|
||||
add_input_file = entry->tv_u.tv_add_input_file;
|
||||
break;
|
||||
case LDPT_MESSAGE:
|
||||
message = entry->tv_u.tv_message;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (message == NULL)
|
||||
{
|
||||
fprintf(stderr, "tv_message interface missing\n");
|
||||
return LDPS_ERR;
|
||||
}
|
||||
|
||||
if (register_claim_file_hook == NULL)
|
||||
{
|
||||
fprintf(stderr, "tv_register_claim_file_hook interface missing\n");
|
||||
return LDPS_ERR;
|
||||
}
|
||||
|
||||
if (register_all_symbols_read_hook == NULL)
|
||||
{
|
||||
fprintf(stderr, "tv_register_all_symbols_read_hook interface missing\n");
|
||||
return LDPS_ERR;
|
||||
}
|
||||
|
||||
if (register_cleanup_hook == NULL)
|
||||
{
|
||||
fprintf(stderr, "tv_register_cleanup_hook interface missing\n");
|
||||
return LDPS_ERR;
|
||||
}
|
||||
|
||||
(*message)(LDPL_INFO, "API version: %d", api_version);
|
||||
(*message)(LDPL_INFO, "gold version: %d", gold_version);
|
||||
|
||||
for (i = 0; i < nopts; ++i)
|
||||
(*message)(LDPL_INFO, "option: %s", opts[i]);
|
||||
|
||||
if ((*register_claim_file_hook)(claim_file_hook) != LDPS_OK)
|
||||
{
|
||||
(*message)(LDPL_ERROR, "error registering claim file hook");
|
||||
return LDPS_ERR;
|
||||
}
|
||||
|
||||
if ((*register_all_symbols_read_hook)(all_symbols_read_hook) != LDPS_OK)
|
||||
{
|
||||
(*message)(LDPL_ERROR, "error registering all symbols read hook");
|
||||
return LDPS_ERR;
|
||||
}
|
||||
|
||||
if ((*register_cleanup_hook)(cleanup_hook) != LDPS_OK)
|
||||
{
|
||||
(*message)(LDPL_ERROR, "error registering cleanup hook");
|
||||
return LDPS_ERR;
|
||||
}
|
||||
|
||||
return LDPS_OK;
|
||||
}
|
||||
|
||||
enum ld_plugin_status
|
||||
claim_file_hook (const struct ld_plugin_input_file* file, int* claimed)
|
||||
{
|
||||
int len;
|
||||
char buf[160];
|
||||
struct claimed_file* claimed_file;
|
||||
struct ld_plugin_symbol* syms;
|
||||
int nsyms = 0;
|
||||
int maxsyms = 0;
|
||||
FILE* irfile;
|
||||
char *p;
|
||||
char *pbind;
|
||||
char *pvis;
|
||||
char *psect;
|
||||
int weak;
|
||||
int def;
|
||||
int vis;
|
||||
int size;
|
||||
char* name;
|
||||
int is_comdat;
|
||||
int i;
|
||||
|
||||
(*message)(LDPL_INFO,
|
||||
"%s: claim file hook called (offset = %ld, size = %ld)",
|
||||
file->name, (long)file->offset, (long)file->filesize);
|
||||
|
||||
/* Look for the beginning of output from readelf -s. */
|
||||
irfile = fdopen(file->fd, "r");
|
||||
(void)fseek(irfile, file->offset, SEEK_SET);
|
||||
len = fread(buf, 1, 13, irfile);
|
||||
if (len < 13 || strncmp(buf, "\nSymbol table", 13) != 0)
|
||||
return LDPS_OK;
|
||||
|
||||
/* Skip the two header lines. */
|
||||
(void) fgets(buf, sizeof(buf), irfile);
|
||||
(void) fgets(buf, sizeof(buf), irfile);
|
||||
|
||||
if (add_symbols == NULL)
|
||||
{
|
||||
fprintf(stderr, "tv_add_symbols interface missing\n");
|
||||
return LDPS_ERR;
|
||||
}
|
||||
|
||||
/* Parse the output from readelf. The columns are:
|
||||
Index Value Size Type Binding Visibility Section Name. */
|
||||
syms = (struct ld_plugin_symbol*)malloc(sizeof(struct ld_plugin_symbol) * 8);
|
||||
if (syms == NULL)
|
||||
return LDPS_ERR;
|
||||
maxsyms = 8;
|
||||
while (fgets(buf, sizeof(buf), irfile) != NULL)
|
||||
{
|
||||
p = buf;
|
||||
p += strspn(p, " ");
|
||||
|
||||
/* Index field. */
|
||||
p += strcspn(p, " ");
|
||||
p += strspn(p, " ");
|
||||
|
||||
/* Value field. */
|
||||
p += strcspn(p, " ");
|
||||
p += strspn(p, " ");
|
||||
|
||||
/* Size field. */
|
||||
size = atoi(p);
|
||||
p += strcspn(p, " ");
|
||||
p += strspn(p, " ");
|
||||
|
||||
/* Type field. */
|
||||
p += strcspn(p, " ");
|
||||
p += strspn(p, " ");
|
||||
|
||||
/* Binding field. */
|
||||
pbind = p;
|
||||
p += strcspn(p, " ");
|
||||
p += strspn(p, " ");
|
||||
|
||||
/* Visibility field. */
|
||||
pvis = p;
|
||||
p += strcspn(p, " ");
|
||||
p += strspn(p, " ");
|
||||
|
||||
/* Section field. */
|
||||
psect = p;
|
||||
p += strcspn(p, " ");
|
||||
p += strspn(p, " ");
|
||||
|
||||
/* Name field. */
|
||||
/* FIXME: Look for version. */
|
||||
len = strlen(p);
|
||||
if (p[len-1] == '\n')
|
||||
p[--len] = '\0';
|
||||
name = malloc(len + 1);
|
||||
strncpy(name, p, len + 1);
|
||||
|
||||
/* Ignore local symbols. */
|
||||
if (strncmp(pbind, "LOCAL", 5) == 0)
|
||||
continue;
|
||||
|
||||
weak = strncmp(pbind, "WEAK", 4) == 0;
|
||||
if (strncmp(psect, "UND", 3) == 0)
|
||||
def = weak ? LDPK_WEAKUNDEF : LDPK_UNDEF;
|
||||
else if (strncmp(psect, "COM", 3) == 0)
|
||||
def = LDPK_COMMON;
|
||||
else
|
||||
def = weak ? LDPK_WEAKDEF : LDPK_DEF;
|
||||
|
||||
if (strncmp(pvis, "INTERNAL", 8) == 0)
|
||||
vis = LDPV_INTERNAL;
|
||||
else if (strncmp(pvis, "HIDDEN", 6) == 0)
|
||||
vis = LDPV_HIDDEN;
|
||||
else if (strncmp(pvis, "PROTECTED", 9) == 0)
|
||||
vis = LDPV_PROTECTED;
|
||||
else
|
||||
vis = LDPV_DEFAULT;
|
||||
|
||||
/* If the symbol is listed in the options list, special-case
|
||||
it as a comdat symbol. */
|
||||
is_comdat = 0;
|
||||
for (i = 0; i < nopts; ++i)
|
||||
{
|
||||
if (name != NULL && strcmp(name, opts[i]) == 0)
|
||||
{
|
||||
is_comdat = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nsyms >= maxsyms)
|
||||
{
|
||||
syms = (struct ld_plugin_symbol*)
|
||||
realloc(syms, sizeof(struct ld_plugin_symbol) * maxsyms * 2);
|
||||
if (syms == NULL)
|
||||
return LDPS_ERR;
|
||||
maxsyms *= 2;
|
||||
}
|
||||
|
||||
syms[nsyms].name = name;
|
||||
syms[nsyms].version = NULL;
|
||||
syms[nsyms].def = def;
|
||||
syms[nsyms].visibility = vis;
|
||||
syms[nsyms].size = size;
|
||||
syms[nsyms].comdat_key = is_comdat ? name : NULL;
|
||||
syms[nsyms].resolution = LDPR_UNKNOWN;
|
||||
++nsyms;
|
||||
}
|
||||
|
||||
claimed_file = (struct claimed_file*) malloc(sizeof(struct claimed_file));
|
||||
if (claimed_file == NULL)
|
||||
return LDPS_ERR;
|
||||
|
||||
claimed_file->name = file->name;
|
||||
claimed_file->handle = file->handle;
|
||||
claimed_file->nsyms = nsyms;
|
||||
claimed_file->syms = syms;
|
||||
claimed_file->next = NULL;
|
||||
if (last_claimed_file == NULL)
|
||||
first_claimed_file = claimed_file;
|
||||
else
|
||||
last_claimed_file->next = claimed_file;
|
||||
last_claimed_file = claimed_file;
|
||||
|
||||
(*add_symbols)(file->handle, nsyms, syms);
|
||||
|
||||
*claimed = 1;
|
||||
return LDPS_OK;
|
||||
}
|
||||
|
||||
enum ld_plugin_status
|
||||
all_symbols_read_hook(void)
|
||||
{
|
||||
int i;
|
||||
const char* res;
|
||||
struct claimed_file* claimed_file;
|
||||
char buf[160];
|
||||
char *p;
|
||||
|
||||
(*message)(LDPL_INFO, "all symbols read hook called");
|
||||
|
||||
if (get_symbols == NULL)
|
||||
{
|
||||
fprintf(stderr, "tv_get_symbols interface missing\n");
|
||||
return LDPS_ERR;
|
||||
}
|
||||
|
||||
for (claimed_file = first_claimed_file;
|
||||
claimed_file != NULL;
|
||||
claimed_file = claimed_file->next)
|
||||
{
|
||||
(*get_symbols)(claimed_file->handle, claimed_file->nsyms,
|
||||
claimed_file->syms);
|
||||
for (i = 0; i < claimed_file->nsyms; ++i)
|
||||
{
|
||||
switch (claimed_file->syms[i].resolution)
|
||||
{
|
||||
case LDPR_UNKNOWN:
|
||||
res = "UNKNOWN";
|
||||
break;
|
||||
case LDPR_UNDEF:
|
||||
res = "UNDEF";
|
||||
break;
|
||||
case LDPR_PREVAILING_DEF:
|
||||
res = "PREVAILING_DEF_REG";
|
||||
break;
|
||||
case LDPR_PREVAILING_DEF_IRONLY:
|
||||
res = "PREVAILING_DEF_IRONLY";
|
||||
break;
|
||||
case LDPR_PREEMPTED_REG:
|
||||
res = "PREEMPTED_REG";
|
||||
break;
|
||||
case LDPR_PREEMPTED_IR:
|
||||
res = "PREEMPTED_IR";
|
||||
break;
|
||||
case LDPR_RESOLVED_IR:
|
||||
res = "RESOLVED_IR";
|
||||
break;
|
||||
case LDPR_RESOLVED_EXEC:
|
||||
res = "RESOLVED_EXEC";
|
||||
break;
|
||||
case LDPR_RESOLVED_DYN:
|
||||
res = "RESOLVED_DYN";
|
||||
break;
|
||||
default:
|
||||
res = "?";
|
||||
break;
|
||||
}
|
||||
(*message)(LDPL_INFO, "%s: %s: %s", claimed_file->name,
|
||||
claimed_file->syms[i].name, res);
|
||||
}
|
||||
}
|
||||
|
||||
if (add_input_file == NULL)
|
||||
{
|
||||
fprintf(stderr, "tv_add_input_file interface missing\n");
|
||||
return LDPS_ERR;
|
||||
}
|
||||
|
||||
for (claimed_file = first_claimed_file;
|
||||
claimed_file != NULL;
|
||||
claimed_file = claimed_file->next)
|
||||
{
|
||||
if (strlen(claimed_file->name) >= sizeof(buf))
|
||||
{
|
||||
(*message)(LDPL_FATAL, "%s: filename too long", claimed_file->name);
|
||||
return LDPS_ERR;
|
||||
}
|
||||
strcpy(buf, claimed_file->name);
|
||||
p = strrchr(buf, '.');
|
||||
if (p == NULL || strcmp(p, ".syms") != 0)
|
||||
{
|
||||
(*message)(LDPL_FATAL, "%s: filename must have '.syms' suffix",
|
||||
claimed_file->name);
|
||||
return LDPS_ERR;
|
||||
}
|
||||
p[1] = 'o';
|
||||
p[2] = '\0';
|
||||
(*add_input_file)(buf);
|
||||
}
|
||||
|
||||
return LDPS_OK;
|
||||
}
|
||||
|
||||
enum ld_plugin_status
|
||||
cleanup_hook(void)
|
||||
{
|
||||
(*message)(LDPL_INFO, "cleanup hook called");
|
||||
return LDPS_OK;
|
||||
}
|
56
gold/testsuite/plugin_test_1.sh
Executable file
56
gold/testsuite/plugin_test_1.sh
Executable file
|
@ -0,0 +1,56 @@
|
|||
#!/bin/sh
|
||||
|
||||
# plugin_test_1.sh -- a test case for the plugin API.
|
||||
|
||||
# Copyright 2008 Free Software Foundation, Inc.
|
||||
# Written by Cary Coutant <ccoutant@google.com>.
|
||||
|
||||
# This file is part of gold.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
||||
# MA 02110-1301, USA.
|
||||
|
||||
# This file goes with plugin_test_1.c, a simple plug-in library that
|
||||
# exercises the basic interfaces and prints out version numbers and
|
||||
# options passed to the plugin.
|
||||
|
||||
check()
|
||||
{
|
||||
if ! grep -q "$2" "$1"
|
||||
then
|
||||
echo "Did not find expected output in $1:"
|
||||
echo " $2"
|
||||
echo ""
|
||||
echo "Actual output below:"
|
||||
cat "$1"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
check plugin_test_1.err "API version:"
|
||||
check plugin_test_1.err "gold version:"
|
||||
check plugin_test_1.err "option: _Z4f13iv"
|
||||
check plugin_test_1.err "two_file_test_main.o: claim file hook called"
|
||||
check plugin_test_1.err "two_file_test_1.syms: claim file hook called"
|
||||
check plugin_test_1.err "two_file_test_1b.syms: claim file hook called"
|
||||
check plugin_test_1.err "two_file_test_2.syms: claim file hook called"
|
||||
check plugin_test_1.err "two_file_test_1.syms: _Z4f13iv: PREVAILING_DEF_IRONLY"
|
||||
check plugin_test_1.err "two_file_test_1.syms: _Z2t2v: PREVAILING_DEF_REG"
|
||||
check plugin_test_1.err "two_file_test_1.syms: v2: RESOLVED_IR"
|
||||
check plugin_test_1.err "two_file_test_1.syms: t17data: RESOLVED_IR"
|
||||
check plugin_test_1.err "two_file_test_2.syms: _Z4f13iv: PREEMPTED_IR"
|
||||
check plugin_test_1.err "cleanup hook called"
|
||||
|
||||
exit 0
|
54
gold/testsuite/plugin_test_2.sh
Executable file
54
gold/testsuite/plugin_test_2.sh
Executable file
|
@ -0,0 +1,54 @@
|
|||
#!/bin/sh
|
||||
|
||||
# plugin_test_2.sh -- a test case for the plugin API.
|
||||
|
||||
# Copyright 2008 Free Software Foundation, Inc.
|
||||
# Written by Cary Coutant <ccoutant@google.com>.
|
||||
|
||||
# This file is part of gold.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
||||
# MA 02110-1301, USA.
|
||||
|
||||
# This file goes with plugin_test_1.c, a simple plug-in library that
|
||||
# exercises the basic interfaces and prints out version numbers and
|
||||
# options passed to the plugin.
|
||||
|
||||
check()
|
||||
{
|
||||
if ! grep -q "$2" "$1"
|
||||
then
|
||||
echo "Did not find expected output in $1:"
|
||||
echo " $2"
|
||||
echo ""
|
||||
echo "Actual output below:"
|
||||
cat "$1"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
check plugin_test_2.err "API version:"
|
||||
check plugin_test_2.err "gold version:"
|
||||
check plugin_test_2.err "two_file_test_main.o: claim file hook called"
|
||||
check plugin_test_2.err "two_file_test_1.syms: claim file hook called"
|
||||
check plugin_test_2.err "two_file_test_1b.syms: claim file hook called"
|
||||
check plugin_test_2.err "two_file_shared_2.so: claim file hook called"
|
||||
check plugin_test_2.err "two_file_test_1.syms: _Z4f13iv: PREVAILING_DEF_REG"
|
||||
check plugin_test_2.err "two_file_test_1.syms: _Z2t2v: PREVAILING_DEF_REG"
|
||||
check plugin_test_2.err "two_file_test_1.syms: v2: RESOLVED_DYN"
|
||||
check plugin_test_2.err "two_file_test_1.syms: t17data: RESOLVED_DYN"
|
||||
check plugin_test_2.err "cleanup hook called"
|
||||
|
||||
exit 0
|
|
@ -1,3 +1,8 @@
|
|||
2008-09-18 Cary Coutant <ccoutant@google.com>
|
||||
|
||||
Add plugin functionality for link-time optimization (LTO).
|
||||
* plugin-api.h: New file.
|
||||
|
||||
2008-09-09 Jason Merrill <jason@redhat.com>
|
||||
|
||||
* demangle.h (enum demangle_component_type): Add
|
||||
|
|
242
include/plugin-api.h
Normal file
242
include/plugin-api.h
Normal file
|
@ -0,0 +1,242 @@
|
|||
/* plugin-api.h -- External linker plugin API. */
|
||||
|
||||
/* Copyright 2008 Free Software Foundation, Inc.
|
||||
Written by Cary Coutant <ccoutant@google.com>.
|
||||
|
||||
This file is part of binutils.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
||||
MA 02110-1301, USA. */
|
||||
|
||||
/* This file defines the interface for writing a linker plugin, which is
|
||||
described at < http://gcc.gnu.org/wiki/whopr/driver >. */
|
||||
|
||||
#ifndef PLUGIN_API_H
|
||||
#define PLUGIN_API_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* Status code returned by most API routines. */
|
||||
|
||||
enum ld_plugin_status
|
||||
{
|
||||
LDPS_OK = 0,
|
||||
LDPS_NO_SYMS, // Attempt to get symbols that haven't been added.
|
||||
LDPS_ERR,
|
||||
/* Additional Error codes TBD. */
|
||||
};
|
||||
|
||||
/* The version of the API specification. */
|
||||
|
||||
enum ld_plugin_api_version
|
||||
{
|
||||
LD_PLUGIN_API_VERSION = 1,
|
||||
};
|
||||
|
||||
/* The type of output file being generated by the linker. */
|
||||
|
||||
enum ld_plugin_output_file_type
|
||||
{
|
||||
LDPO_REL,
|
||||
LDPO_EXEC,
|
||||
LDPO_DYN,
|
||||
};
|
||||
|
||||
/* An input file managed by the plugin library. */
|
||||
|
||||
struct ld_plugin_input_file
|
||||
{
|
||||
const char *name;
|
||||
int fd;
|
||||
off_t offset;
|
||||
off_t filesize;
|
||||
void *handle;
|
||||
};
|
||||
|
||||
/* A symbol belonging to an input file managed by the plugin library. */
|
||||
|
||||
struct ld_plugin_symbol
|
||||
{
|
||||
char *name;
|
||||
char *version;
|
||||
int def;
|
||||
int visibility;
|
||||
uint64_t size;
|
||||
char *comdat_key;
|
||||
int resolution;
|
||||
};
|
||||
|
||||
/* Whether the symbol is a definition, reference, or common, weak or not. */
|
||||
|
||||
enum ld_plugin_symbol_kind
|
||||
{
|
||||
LDPK_DEF,
|
||||
LDPK_WEAKDEF,
|
||||
LDPK_UNDEF,
|
||||
LDPK_WEAKUNDEF,
|
||||
LDPK_COMMON,
|
||||
};
|
||||
|
||||
/* The visibility of the symbol. */
|
||||
|
||||
enum ld_plugin_symbol_visibility
|
||||
{
|
||||
LDPV_DEFAULT,
|
||||
LDPV_PROTECTED,
|
||||
LDPV_INTERNAL,
|
||||
LDPV_HIDDEN,
|
||||
};
|
||||
|
||||
/* How a symbol is resolved. */
|
||||
|
||||
enum ld_plugin_symbol_resolution
|
||||
{
|
||||
LDPR_UNKNOWN = 0,
|
||||
LDPR_UNDEF,
|
||||
LDPR_PREVAILING_DEF,
|
||||
LDPR_PREVAILING_DEF_IRONLY,
|
||||
LDPR_PREEMPTED_REG,
|
||||
LDPR_PREEMPTED_IR,
|
||||
LDPR_RESOLVED_IR,
|
||||
LDPR_RESOLVED_EXEC,
|
||||
LDPR_RESOLVED_DYN,
|
||||
};
|
||||
|
||||
/* The plugin library's "claim file" handler. */
|
||||
|
||||
typedef
|
||||
enum ld_plugin_status
|
||||
(*ld_plugin_claim_file_handler) (
|
||||
const struct ld_plugin_input_file *file, int *claimed);
|
||||
|
||||
/* The plugin library's "all symbols read" handler. */
|
||||
|
||||
typedef
|
||||
enum ld_plugin_status
|
||||
(*ld_plugin_all_symbols_read_handler) (void);
|
||||
|
||||
/* The plugin library's cleanup handler. */
|
||||
|
||||
typedef
|
||||
enum ld_plugin_status
|
||||
(*ld_plugin_cleanup_handler) (void);
|
||||
|
||||
/* The linker's interface for registering the "claim file" handler. */
|
||||
|
||||
typedef
|
||||
enum ld_plugin_status
|
||||
(*ld_plugin_register_claim_file) (ld_plugin_claim_file_handler handler);
|
||||
|
||||
/* The linker's interface for registering the "all symbols read" handler. */
|
||||
|
||||
typedef
|
||||
enum ld_plugin_status
|
||||
(*ld_plugin_register_all_symbols_read) (
|
||||
ld_plugin_all_symbols_read_handler handler);
|
||||
|
||||
/* The linker's interface for registering the cleanup handler. */
|
||||
|
||||
typedef
|
||||
enum ld_plugin_status
|
||||
(*ld_plugin_register_cleanup) (ld_plugin_cleanup_handler handler);
|
||||
|
||||
/* The linker's interface for adding symbols from a claimed input file. */
|
||||
|
||||
typedef
|
||||
enum ld_plugin_status
|
||||
(*ld_plugin_add_symbols) (void *handle, int nsyms,
|
||||
const struct ld_plugin_symbol *syms);
|
||||
|
||||
/* The linker's interface for retrieving symbol resolution information. */
|
||||
|
||||
typedef
|
||||
enum ld_plugin_status
|
||||
(*ld_plugin_get_symbols) (const void *handle, int nsyms,
|
||||
struct ld_plugin_symbol *syms);
|
||||
|
||||
/* The linker's interface for adding a compiled input file. */
|
||||
|
||||
typedef
|
||||
enum ld_plugin_status
|
||||
(*ld_plugin_add_input_file) (char *pathname);
|
||||
|
||||
/* The linker's interface for issuing a warning or error message. */
|
||||
|
||||
typedef
|
||||
enum ld_plugin_status
|
||||
(*ld_plugin_message) (int level, char *format, ...);
|
||||
|
||||
enum ld_plugin_level
|
||||
{
|
||||
LDPL_INFO,
|
||||
LDPL_WARNING,
|
||||
LDPL_ERROR,
|
||||
LDPL_FATAL,
|
||||
};
|
||||
|
||||
/* Values for the tv_tag field of the transfer vector. */
|
||||
|
||||
enum ld_plugin_tag
|
||||
{
|
||||
LDPT_NULL = 0,
|
||||
LDPT_API_VERSION,
|
||||
LDPT_GOLD_VERSION,
|
||||
LDPT_LINKER_OUTPUT,
|
||||
LDPT_OPTION,
|
||||
LDPT_REGISTER_CLAIM_FILE_HOOK,
|
||||
LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK,
|
||||
LDPT_REGISTER_CLEANUP_HOOK,
|
||||
LDPT_ADD_SYMBOLS,
|
||||
LDPT_GET_SYMBOLS,
|
||||
LDPT_ADD_INPUT_FILE,
|
||||
LDPT_MESSAGE,
|
||||
};
|
||||
|
||||
/* The plugin transfer vector. */
|
||||
|
||||
struct ld_plugin_tv
|
||||
{
|
||||
enum ld_plugin_tag tv_tag;
|
||||
union
|
||||
{
|
||||
int tv_val;
|
||||
const char *tv_string;
|
||||
ld_plugin_register_claim_file tv_register_claim_file;
|
||||
ld_plugin_register_all_symbols_read tv_register_all_symbols_read;
|
||||
ld_plugin_register_cleanup tv_register_cleanup;
|
||||
ld_plugin_add_symbols tv_add_symbols;
|
||||
ld_plugin_get_symbols tv_get_symbols;
|
||||
ld_plugin_add_input_file tv_add_input_file;
|
||||
ld_plugin_message tv_message;
|
||||
} tv_u;
|
||||
};
|
||||
|
||||
/* The plugin library's "onload" entry point. */
|
||||
|
||||
typedef
|
||||
enum ld_plugin_status
|
||||
(*ld_plugin_onload) (struct ld_plugin_tv *tv);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* !defined(PLUGIN_API_H) */
|
Loading…
Reference in a new issue