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:
Cary Coutant 2008-09-19 22:54:57 +00:00
parent 14fc49fb15
commit 89fc34211b
30 changed files with 2923 additions and 81 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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
View 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*>(&parameters->target());
else
target = const_cast<Target*>(&parameters->default_target());
if (target->get_size() == 32)
{
#ifdef HAVE_TARGET_32_BIG
if (target->is_big_endian())
obj = new Sized_pluginobj<32, true>(input_file->filename(),
input_file, offset);
#endif
#ifdef HAVE_TARGET_32_LITTLE
else
obj = new Sized_pluginobj<32, false>(input_file->filename(),
input_file, offset);
#endif
}
else if (target->get_size() == 64)
{
#ifdef HAVE_TARGET_64_BIG
if (target->is_big_endian())
obj = new Sized_pluginobj<64, true>(input_file->filename(),
input_file, offset);
#endif
#ifdef HAVE_TARGET_64_LITTLE
else
obj = new Sized_pluginobj<64, false>(input_file->filename(),
input_file, offset);
#endif
}
gold_assert(obj != NULL);
obj->set_target(target);
return obj;
}
} // End namespace gold.

457
gold/plugin.h Normal file
View 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)

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

View file

@ -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
View 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) */