From 5a6f7e2db556f93765b75baf2d1ee1509225410d Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 30 Nov 2006 23:52:50 +0000 Subject: Added a testsuite. More support for COPY relocations. --- gold/Makefile.am | 24 +- gold/Makefile.in | 91 ++++--- gold/configure | 87 ++++++- gold/configure.ac | 3 +- gold/fileread.cc | 81 ++++-- gold/fileread.h | 32 ++- gold/gold.cc | 49 +--- gold/gold.h | 3 +- gold/i386.cc | 119 ++++++++- gold/layout.cc | 4 +- gold/main.cc | 57 +++++ gold/object.h | 56 ++-- gold/output.cc | 24 +- gold/output.h | 177 +++++++++++-- gold/po/gold.pot | 56 ++-- gold/readsyms.cc | 2 +- gold/reloc.cc | 175 +++++++++++-- gold/reloc.h | 95 ++++++- gold/target.h | 11 + gold/testsuite/Makefile.am | 22 ++ gold/testsuite/Makefile.in | 521 ++++++++++++++++++++++++++++++++++++++ gold/testsuite/object_unittest.cc | 41 +++ gold/testsuite/test.cc | 78 ++++++ gold/testsuite/test.h | 121 +++++++++ gold/testsuite/testfile.cc | 261 +++++++++++++++++++ gold/testsuite/testfile.h | 20 ++ gold/testsuite/testmain.cc | 18 ++ 27 files changed, 1988 insertions(+), 240 deletions(-) create mode 100644 gold/main.cc create mode 100644 gold/testsuite/Makefile.am create mode 100644 gold/testsuite/Makefile.in create mode 100644 gold/testsuite/object_unittest.cc create mode 100644 gold/testsuite/test.cc create mode 100644 gold/testsuite/test.h create mode 100644 gold/testsuite/testfile.cc create mode 100644 gold/testsuite/testfile.h create mode 100644 gold/testsuite/testmain.cc diff --git a/gold/Makefile.am b/gold/Makefile.am index f76ee5b..02a6da1 100644 --- a/gold/Makefile.am +++ b/gold/Makefile.am @@ -2,7 +2,7 @@ AUTOMAKE_OPTIONS = -SUBDIRS = po +SUBDIRS = po testsuite tooldir = $(exec_prefix)/$(target_alias) @@ -18,6 +18,7 @@ INCLUDES = -D_GNU_SOURCE \ YFLAGS = -d noinst_PROGRAMS = ld-new +noinst_LIBRARIES = libgold.a CCFILES = \ archive.cc \ @@ -74,19 +75,18 @@ YFILES = \ EXTRA_DIST = yyscript.c yyscript.h -POTFILES= $(CCFILES) $(HFILES) $(TARGETFILES) - -po/POTFILES.in: @MAINT@ Makefile - for f in $(POTFILES); do echo $$f; done | LC_COLLATE= sort > tmp \ - && mv tmp $(srcdir)/po/POTFILES.in +libgold_a_SOURCES = $(CCFILES) $(HFILES) $(YFILES) -ld_new_SOURCES = $(CCFILES) $(HFILES) $(TARGETFILES) $(YFILES) -ld_new_DEPENDENCIES = $(LIBINTL_DEP) -ld_new_LDADD = $(LIBINTL) +ld_new_SOURCES = main.cc $(TARGETFILES) +ld_new_DEPENDENCIES = libgold.a $(LIBINTL_DEP) +ld_new_LDADD = libgold.a $(LIBINTL) # Use an explicit dependency for the bison generated header file. script.$(OBJEXT): yyscript.h +# We have to build libgold.a before we run the tests. +check: libgold.a + .PHONY: install-exec-local install-exec-local: ld-new$(EXEEXT) @@ -102,3 +102,9 @@ install-exec-local: ld-new$(EXEEXT) # We want install to imply install-info as per GNU standards, despite # the cygnus option. install-data-local: install-info + +POTFILES= $(CCFILES) $(HFILES) $(TARGETFILES) + +po/POTFILES.in: @MAINT@ Makefile + for f in $(POTFILES); do echo $$f; done | LC_COLLATE= sort > tmp \ + && mv tmp $(srcdir)/po/POTFILES.in diff --git a/gold/Makefile.in b/gold/Makefile.in index 560f481..36994c3 100644 --- a/gold/Makefile.in +++ b/gold/Makefile.in @@ -16,6 +16,7 @@ # Process this file with automake to generate Makefile.in + srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ @@ -62,7 +63,11 @@ am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs CONFIG_HEADER = config.h CONFIG_CLEAN_FILES = po/Makefile.in -PROGRAMS = $(noinst_PROGRAMS) +LIBRARIES = $(noinst_LIBRARIES) +AR = ar +ARFLAGS = cru +libgold_a_AR = $(AR) $(ARFLAGS) +libgold_a_LIBADD = am__objects_1 = archive.$(OBJEXT) common.$(OBJEXT) defstd.$(OBJEXT) \ dirsearch.$(OBJEXT) dynobj.$(OBJEXT) fileread.$(OBJEXT) \ gold.$(OBJEXT) gold-threads.$(OBJEXT) layout.$(OBJEXT) \ @@ -71,10 +76,13 @@ am__objects_1 = archive.$(OBJEXT) common.$(OBJEXT) defstd.$(OBJEXT) \ script.$(OBJEXT) symtab.$(OBJEXT) stringpool.$(OBJEXT) \ target-select.$(OBJEXT) workqueue.$(OBJEXT) am__objects_2 = -am__objects_3 = i386.$(OBJEXT) -am__objects_4 = yyscript.$(OBJEXT) -am_ld_new_OBJECTS = $(am__objects_1) $(am__objects_2) $(am__objects_3) \ - $(am__objects_4) +am__objects_3 = yyscript.$(OBJEXT) +am_libgold_a_OBJECTS = $(am__objects_1) $(am__objects_2) \ + $(am__objects_3) +libgold_a_OBJECTS = $(am_libgold_a_OBJECTS) +PROGRAMS = $(noinst_PROGRAMS) +am__objects_4 = i386.$(OBJEXT) +am_ld_new_OBJECTS = main.$(OBJEXT) $(am__objects_4) ld_new_OBJECTS = $(am_ld_new_OBJECTS) am__DEPENDENCIES_1 = DEFAULT_INCLUDES = -I. -I$(srcdir) -I. @@ -90,8 +98,8 @@ CXXLD = $(CXX) CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ -o $@ YACCCOMPILE = $(YACC) $(YFLAGS) $(AM_YFLAGS) -SOURCES = $(ld_new_SOURCES) -DIST_SOURCES = $(ld_new_SOURCES) +SOURCES = $(libgold_a_SOURCES) $(ld_new_SOURCES) +DIST_SOURCES = $(libgold_a_SOURCES) $(ld_new_SOURCES) RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ html-recursive info-recursive install-data-recursive \ install-exec-recursive install-info-recursive \ @@ -171,6 +179,7 @@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSUB = @POSUB@ +RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ @@ -182,6 +191,7 @@ XGETTEXT = @XGETTEXT@ YACC = @YACC@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ +ac_ct_RANLIB = @ac_ct_RANLIB@ ac_ct_STRIP = @ac_ct_STRIP@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ @@ -225,7 +235,7 @@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ AUTOMAKE_OPTIONS = -SUBDIRS = po +SUBDIRS = po testsuite tooldir = $(exec_prefix)/$(target_alias) ACLOCAL_AMFLAGS = -I ../bfd -I ../config AM_CXXFLAGS = $(WARN_CXXFLAGS) $(LFS_CXXFLAGS) @@ -235,6 +245,7 @@ INCLUDES = -D_GNU_SOURCE \ @INCINTL@ YFLAGS = -d +noinst_LIBRARIES = libgold.a CCFILES = \ archive.cc \ common.cc \ @@ -289,10 +300,11 @@ YFILES = \ yyscript.y EXTRA_DIST = yyscript.c yyscript.h +libgold_a_SOURCES = $(CCFILES) $(HFILES) $(YFILES) +ld_new_SOURCES = main.cc $(TARGETFILES) +ld_new_DEPENDENCIES = libgold.a $(LIBINTL_DEP) +ld_new_LDADD = libgold.a $(LIBINTL) POTFILES = $(CCFILES) $(HFILES) $(TARGETFILES) -ld_new_SOURCES = $(CCFILES) $(HFILES) $(TARGETFILES) $(YFILES) -ld_new_DEPENDENCIES = $(LIBINTL_DEP) -ld_new_LDADD = $(LIBINTL) all: config.h $(MAKE) $(AM_MAKEFLAGS) all-recursive @@ -351,13 +363,20 @@ distclean-hdr: po/Makefile.in: $(top_builddir)/config.status $(top_srcdir)/po/Make-in cd $(top_builddir) && $(SHELL) ./config.status $@ -clean-noinstPROGRAMS: - -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) yyscript.h: yyscript.c @if test ! -f $@; then \ rm -f yyscript.c; \ $(MAKE) yyscript.c; \ else :; fi +libgold.a: $(libgold_a_OBJECTS) $(libgold_a_DEPENDENCIES) + -rm -f libgold.a + $(libgold_a_AR) libgold.a $(libgold_a_OBJECTS) $(libgold_a_LIBADD) + $(RANLIB) libgold.a + +clean-noinstPROGRAMS: + -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) ld-new$(EXEEXT): $(ld_new_OBJECTS) $(ld_new_DEPENDENCIES) @rm -f ld-new$(EXEEXT) $(CXXLINK) $(ld_new_LDFLAGS) $(ld_new_OBJECTS) $(ld_new_LDADD) $(LIBS) @@ -378,6 +397,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gold.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/i386.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/layout.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/object.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/options.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/output.Po@am__quote@ @@ -717,7 +737,7 @@ distcleancheck: distclean exit 1; } >&2 check-am: all-am check: check-recursive -all-am: Makefile $(PROGRAMS) config.h +all-am: Makefile $(LIBRARIES) $(PROGRAMS) config.h installdirs: installdirs-recursive installdirs-am: install: install-recursive @@ -748,7 +768,8 @@ maintainer-clean-generic: -rm -f yyscript.h clean: clean-recursive -clean-am: clean-generic clean-noinstPROGRAMS mostlyclean-am +clean-am: clean-generic clean-noinstLIBRARIES clean-noinstPROGRAMS \ + mostlyclean-am distclean: distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) @@ -801,29 +822,29 @@ uninstall-am: uninstall-info-am uninstall-info: uninstall-info-recursive .PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am am--refresh check \ - check-am clean clean-generic clean-noinstPROGRAMS \ - clean-recursive ctags ctags-recursive dist dist-all dist-bzip2 \ - dist-gzip dist-shar dist-tarZ dist-zip distcheck distclean \ - distclean-compile distclean-generic distclean-hdr \ - distclean-recursive distclean-tags distcleancheck distdir \ - distuninstallcheck dvi dvi-am html html-am info info-am \ - install install-am install-data install-data-am \ - install-data-local install-exec install-exec-am \ - install-exec-local install-info install-info-am install-man \ - install-strip installcheck installcheck-am installdirs \ - installdirs-am maintainer-clean maintainer-clean-generic \ - maintainer-clean-recursive mostlyclean mostlyclean-compile \ - mostlyclean-generic mostlyclean-recursive pdf pdf-am ps ps-am \ - tags tags-recursive uninstall uninstall-am uninstall-info-am + check-am clean clean-generic clean-noinstLIBRARIES \ + clean-noinstPROGRAMS clean-recursive ctags ctags-recursive \ + dist dist-all dist-bzip2 dist-gzip dist-shar dist-tarZ \ + dist-zip distcheck distclean distclean-compile \ + distclean-generic distclean-hdr distclean-recursive \ + distclean-tags distcleancheck distdir distuninstallcheck dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-data-local install-exec \ + install-exec-am install-exec-local install-info \ + install-info-am install-man install-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic maintainer-clean-recursive \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-recursive pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am uninstall-info-am -po/POTFILES.in: @MAINT@ Makefile - for f in $(POTFILES); do echo $$f; done | LC_COLLATE= sort > tmp \ - && mv tmp $(srcdir)/po/POTFILES.in - # Use an explicit dependency for the bison generated header file. script.$(OBJEXT): yyscript.h +# We have to build libgold.a before we run the tests. +check: libgold.a + .PHONY: install-exec-local install-exec-local: ld-new$(EXEEXT) @@ -839,6 +860,10 @@ install-exec-local: ld-new$(EXEEXT) # We want install to imply install-info as per GNU standards, despite # the cygnus option. install-data-local: install-info + +po/POTFILES.in: @MAINT@ Makefile + for f in $(POTFILES); do echo $$f; done | LC_COLLATE= sort > tmp \ + && mv tmp $(srcdir)/po/POTFILES.in # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: diff --git a/gold/configure b/gold/configure index 8be7e91..5d69594 100755 --- a/gold/configure +++ b/gold/configure @@ -309,7 +309,7 @@ ac_includes_default="\ # include #endif" -ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar 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 USE_NLS LIBINTL LIBINTL_DEP INCINTL XGETTEXT GMSGFMT POSUB CATALOGS DATADIRNAME INSTOBJEXT GENCAT CATOBJEXT MKINSTALLDIRS MSGFMT MSGMERGE WARN_CFLAGS NO_WERROR WARN_CXXFLAGS LFS_CXXFLAGS CXXCPP EGREP MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT LIBOBJS 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 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 USE_NLS LIBINTL LIBINTL_DEP INCINTL XGETTEXT GMSGFMT POSUB CATALOGS DATADIRNAME INSTOBJEXT GENCAT CATOBJEXT MKINSTALLDIRS MSGFMT MSGMERGE WARN_CFLAGS NO_WERROR WARN_CXXFLAGS LFS_CXXFLAGS CXXCPP EGREP MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT LIBOBJS LTLIBOBJS' ac_subst_files='' # Initialize some variables set by options. @@ -3450,6 +3450,86 @@ fi done test -n "$YACC" || YACC="yacc" +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + echo "$as_me:$LINENO: result: $RANLIB" >&5 +echo "${ECHO_T}$RANLIB" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":" +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5 +echo "${ECHO_T}$ac_ct_RANLIB" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + RANLIB=$ac_ct_RANLIB +else + RANLIB="$ac_cv_prog_RANLIB" +fi + # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: @@ -5070,7 +5150,7 @@ fi - ac_config_files="$ac_config_files Makefile po/Makefile.in:po/Make-in" + ac_config_files="$ac_config_files Makefile testsuite/Makefile po/Makefile.in:po/Make-in" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure @@ -5642,6 +5722,7 @@ do case "$ac_config_target" in # Handling of arguments. "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "testsuite/Makefile" ) CONFIG_FILES="$CONFIG_FILES testsuite/Makefile" ;; "po/Makefile.in" ) CONFIG_FILES="$CONFIG_FILES po/Makefile.in:po/Make-in" ;; "depfiles" ) CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "default-1" ) CONFIG_COMMANDS="$CONFIG_COMMANDS default-1" ;; @@ -5788,6 +5869,8 @@ s,@CXXDEPMODE@,$CXXDEPMODE,;t t s,@am__fastdepCXX_TRUE@,$am__fastdepCXX_TRUE,;t t s,@am__fastdepCXX_FALSE@,$am__fastdepCXX_FALSE,;t t s,@YACC@,$YACC,;t t +s,@RANLIB@,$RANLIB,;t t +s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t s,@USE_NLS@,$USE_NLS,;t t s,@LIBINTL@,$LIBINTL,;t t s,@LIBINTL_DEP@,$LIBINTL_DEP,;t t diff --git a/gold/configure.ac b/gold/configure.ac index 10e0db9..5cbaf2c 100644 --- a/gold/configure.ac +++ b/gold/configure.ac @@ -13,6 +13,7 @@ AM_CONFIG_HEADER(config.h:config.in) AC_PROG_CC AC_PROG_CXX AC_PROG_YACC +AC_PROG_RANLIB AC_PROG_INSTALL ZW_GNU_GETTEXT_SISTER_DIR AM_PO_SUBDIRS @@ -48,4 +49,4 @@ AC_LANG_POP(C++) AM_MAINTAINER_MODE -AC_OUTPUT(Makefile po/Makefile.in:po/Make-in) +AC_OUTPUT(Makefile testsuite/Makefile po/Makefile.in:po/Make-in) diff --git a/gold/fileread.cc b/gold/fileread.cc index e96476c..1a14202 100644 --- a/gold/fileread.cc +++ b/gold/fileread.cc @@ -60,6 +60,8 @@ File_read::~File_read() this->clear_views(true); } +// Open the file. + bool File_read::open(const std::string& name) { @@ -72,11 +74,20 @@ File_read::open(const std::string& name) return this->descriptor_ >= 0; } -int -File_read::get_descriptor() +// Open the file for testing purposes. + +bool +File_read::open(const std::string& name, const unsigned char* contents, + off_t contents_size) { - gold_assert(this->lock_count_ > 0); - return this->descriptor_; + gold_assert(this->lock_count_ == 0 + && this->descriptor_ < 0 + && this->name_.empty()); + this->name_ = name; + this->contents_ = contents; + this->contents_size_ = contents_size; + ++this->lock_count_; + return true; } void @@ -121,23 +132,37 @@ off_t File_read::do_read(off_t start, off_t size, void* p, off_t* pbytes) { gold_assert(this->lock_count_ > 0); - int o = this->descriptor_; - if (lseek(o, start, SEEK_SET) < 0) + off_t bytes; + if (this->contents_ == NULL) { - fprintf(stderr, _("%s: %s: lseek to %lld failed: %s"), - program_name, this->filename().c_str(), - static_cast(start), - strerror(errno)); - gold_exit(false); - } + int o = this->descriptor_; - off_t bytes = ::read(o, p, size); - if (bytes < 0) + if (lseek(o, start, SEEK_SET) < 0) + { + fprintf(stderr, _("%s: %s: lseek to %lld failed: %s"), + program_name, this->filename().c_str(), + static_cast(start), + strerror(errno)); + gold_exit(false); + } + + bytes = ::read(o, p, size); + if (bytes < 0) + { + fprintf(stderr, _("%s: %s: read failed: %s\n"), + program_name, this->filename().c_str(), strerror(errno)); + gold_exit(false); + } + } + else { - fprintf(stderr, _("%s: %s: read failed: %s\n"), - program_name, this->filename().c_str(), strerror(errno)); - gold_exit(false); + bytes = this->contents_size_ - start; + if (bytes < 0) + bytes = 0; + else if (bytes > size) + bytes = size; + memcpy(p, this->contents_ + start, bytes); } if (pbytes != NULL) @@ -302,16 +327,30 @@ File_view::~File_view() // Class Input_file. +// Create a file for testing. + +Input_file::Input_file(const char* name, const unsigned char* contents, + off_t size) + : file_() +{ + this->input_argument_ = + new Input_file_argument(name, false, Position_dependent_options()); + bool ok = file_.open(name, contents, size); + gold_assert(ok); +} + +// Open the file. + void Input_file::open(const General_options& options, const Dirsearch& dirpath) { std::string name; - if (!this->input_argument_.is_lib()) - name = this->input_argument_.name(); + if (!this->input_argument_->is_lib()) + name = this->input_argument_->name(); else { std::string n1("lib"); - n1 += this->input_argument_.name(); + n1 += this->input_argument_->name(); std::string n2; if (options.is_static()) n1 += ".a"; @@ -324,7 +363,7 @@ Input_file::open(const General_options& options, const Dirsearch& dirpath) if (name.empty()) { fprintf(stderr, _("%s: cannot find %s\n"), program_name, - this->input_argument_.name()); + this->input_argument_->name()); gold_exit(false); } } diff --git a/gold/fileread.h b/gold/fileread.h index 6e49324..178e7f3 100644 --- a/gold/fileread.h +++ b/gold/fileread.h @@ -25,23 +25,27 @@ class File_read { public: File_read() - : name_(), descriptor_(-1), lock_count_(0) + : name_(), descriptor_(-1), lock_count_(0), views_(), + saved_views_(), contents_(NULL), contents_size_(0) { } + ~File_read(); // Open a file. bool open(const std::string& name); + // Pretend to open the file, but provide the file contents. No + // actual file system activity will occur. This is used for + // testing. + bool + open(const std::string& name, const unsigned char* contents, off_t size); + // Return the file name. const std::string& filename() const { return this->name_; } - // Return the file descriptor. - int - get_descriptor(); - // Lock the file for access within a particular Task::run execution. // This means that the descriptor can not be closed. This routine // may only be called from the main thread. @@ -169,6 +173,10 @@ class File_read // List of views which were locked but had to be removed from views_ // because they were not large enough. Saved_views saved_views_; + // Specified file contents. Used only for testing purposes. + const unsigned char* contents_; + // Specified file size. Used only for testing purposes. + off_t contents_size_; }; // A view of file data that persists even when the file is unlocked. @@ -209,17 +217,23 @@ class File_view class Input_file { public: - Input_file(const Input_file_argument& input_argument) - : input_argument_(input_argument) + Input_file(const Input_file_argument* input_argument) + : input_argument_(input_argument), file_() { } + // Create an input file with the contents already provided. This is + // only used for testing. With this path, don't call the open + // method. + Input_file(const char* name, const unsigned char* contents, off_t size); + + // Open the file. void open(const General_options&, const Dirsearch&); // Return the name given by the user. const char* name() const - { return this->input_argument_.name(); } + { return this->input_argument_->name(); } // Return the file name. const std::string& @@ -234,7 +248,7 @@ class Input_file Input_file(const Input_file&); Input_file& operator=(const Input_file&); - const Input_file_argument& input_argument_; + const Input_file_argument* input_argument_; File_read file_; }; diff --git a/gold/gold.cc b/gold/gold.cc index 7c8ed8f..5051a13 100644 --- a/gold/gold.cc +++ b/gold/gold.cc @@ -1,4 +1,4 @@ -// ld.c -- linker main function +// gold.cc -- main linker functions #include "gold.h" @@ -234,50 +234,3 @@ queue_final_tasks(const General_options& options, } } // End namespace gold. - -using namespace gold; - -int -main(int argc, char** argv) -{ -#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES) - setlocale (LC_MESSAGES, ""); -#endif -#if defined (HAVE_SETLOCALE) - setlocale (LC_CTYPE, ""); -#endif - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); - - gold::program_name = argv[0]; - - // Handle the command line options. - gold::Command_line command_line; - command_line.process(argc - 1, argv + 1); - - // The work queue. - gold::Workqueue workqueue(command_line.options()); - - // The list of input objects. - Input_objects input_objects; - - // The symbol table. - Symbol_table symtab; - - // The layout object. - Layout layout(command_line.options()); - - // Get the search path from the -L options. - Dirsearch search_path; - search_path.add(&workqueue, command_line.options().search_path()); - - // Queue up the first set of tasks. - queue_initial_tasks(command_line.options(), search_path, - command_line, &workqueue, &input_objects, - &symtab, &layout); - - // Run the main task processing loop. - workqueue.process(); - - gold::gold_exit(true); -} diff --git a/gold/gold.h b/gold/gold.h index 78c106f..e4cd786 100644 --- a/gold/gold.h +++ b/gold/gold.h @@ -137,6 +137,7 @@ namespace gold { class General_options; +class Command_line; class Input_argument_list; class Dirsearch; class Input_objects; @@ -180,7 +181,7 @@ extern void do_gold_unreachable(const char*, int, const char*) extern void queue_initial_tasks(const General_options&, const Dirsearch&, - const Input_argument_list&, + const Command_line&, Workqueue*, Input_objects*, Symbol_table*, diff --git a/gold/i386.cc b/gold/i386.cc index 488da79..4cf90e9 100644 --- a/gold/i386.cc +++ b/gold/i386.cc @@ -27,9 +27,12 @@ class Output_data_plt_i386; class Target_i386 : public Sized_target<32, false> { public: + typedef Output_data_reloc Reloc_section; + Target_i386() : Sized_target<32, false>(&i386_info), - got_(NULL), plt_(NULL), got_plt_(NULL) + got_(NULL), plt_(NULL), got_plt_(NULL), rel_dyn_(NULL), + copy_relocs_(NULL), dynbss_(NULL) { } // Scan the relocations to look for symbol adjustments. @@ -46,6 +49,10 @@ class Target_i386 : public Sized_target<32, false> const unsigned char* plocal_symbols, Symbol** global_symbols); + // Finalize the sections. + void + do_finalize_sections(Layout*); + // Relocate a section. void relocate_section(const Relocate_info<32, false>*, @@ -170,9 +177,14 @@ class Target_i386 : public Sized_target<32, false> return this->plt_; } + // Get the dynamic reloc section, creating it if necessary. + Reloc_section* + rel_dyn_section(Layout*); + // Copy a relocation against a global symbol. void - copy_reloc(const General_options*, Sized_relobj<32, false>*, unsigned int, + copy_reloc(const General_options*, Symbol_table*, Layout*, + Sized_relobj<32, false>*, unsigned int, Symbol*, const elfcpp::Rel<32, false>&); // Information about this specific target which we pass to the @@ -185,6 +197,12 @@ class Target_i386 : public Sized_target<32, false> Output_data_plt_i386* plt_; // The GOT PLT section. Output_data_space* got_plt_; + // The dynamic reloc section. + Reloc_section* rel_dyn_; + // Relocs saved to avoid a COPY reloc. + Copy_relocs<32, false>* copy_relocs_; + // Space for variables copied with a COPY reloc. + Output_data_space* dynbss_; }; const Target::Target_info Target_i386::i386_info = @@ -238,6 +256,21 @@ Target_i386::got_section(const General_options* options, Symbol_table* symtab, return this->got_; } +// Get the dynamic reloc section, creating it if necessary. + +Target_i386::Reloc_section* +Target_i386::rel_dyn_section(Layout* layout) +{ + if (this->rel_dyn_ == NULL) + { + gold_assert(layout != NULL); + this->rel_dyn_ = new Reloc_section(); + layout->add_output_section_data(".rel.dyn", elfcpp::SHT_REL, + elfcpp::SHF_ALLOC, this->rel_dyn_); + } + return this->rel_dyn_; +} + // A class to handle the PLT data. class Output_data_plt_i386 : public Output_section_data @@ -493,18 +526,70 @@ Target_i386::make_plt_entry(const General_options* options, void Target_i386::copy_reloc(const General_options* options, + Symbol_table* symtab, + Layout* layout, Sized_relobj<32, false>* object, unsigned int data_shndx, Symbol* gsym, - const elfcpp::Rel<32, false>&) + const elfcpp::Rel<32, false>& rel) { - if (!Relocate_functions<32, false>::need_copy_reloc(options, object, - data_shndx, gsym)) + Sized_symbol<32>* ssym; + ssym = symtab->get_sized_symbol SELECT_SIZE_NAME(32) (gsym + SELECT_SIZE(32)); + + if (!Copy_relocs<32, false>::need_copy_reloc(options, object, + data_shndx, ssym)) { // So far we do not need a COPY reloc. Save this relocation. - // If it turns out that we never a COPY reloc for this symbol, - // then we emit the relocation. + // If it turns out that we never need a COPY reloc for this + // symbol, then we will emit the relocation. + if (this->copy_relocs_ == NULL) + this->copy_relocs_ = new Copy_relocs<32, false>(); + this->copy_relocs_->save(ssym, object, data_shndx, rel); } + else + { + // Allocate space for this symbol in the .bss section. + + elfcpp::Elf_types<32>::Elf_WXword symsize = ssym->symsize(); + + // There is no defined way to determine the required alignment + // of the symbol. We pick the alignment based on the size. We + // set an arbitrary maximum of 256. + unsigned int align; + for (align = 1; align < 512; align <<= 1) + if ((symsize & align) != 0) + break; + if (this->dynbss_ == NULL) + { + this->dynbss_ = new Output_data_space(align); + layout->add_output_section_data(".bss", + elfcpp::SHT_NOBITS, + (elfcpp::SHF_ALLOC + | elfcpp::SHF_WRITE), + this->dynbss_); + } + + Output_data_space* dynbss = this->dynbss_; + + if (align > dynbss->addralign()) + dynbss->set_space_alignment(align); + + off_t dynbss_size = dynbss->data_size(); + dynbss_size = align_address(dynbss_size, align); + off_t offset = dynbss_size; + dynbss->set_space_size(dynbss_size + symsize); + + // Define the symbol in the .dynbss section. + symtab->define_in_output_data(this, ssym->name(), dynbss, offset, + symsize, ssym->type(), ssym->binding(), + ssym->visibility(), ssym->nonvis(), + false, false); + + // Add the COPY reloc. + Reloc_section* rel_dyn = this->rel_dyn_section(layout); + rel_dyn->add_global(ssym, elfcpp::R_386_COPY, dynbss, offset); + } } // Optimize the TLS relocation type based on what we know about the @@ -715,7 +800,8 @@ Target_i386::Scan::global(const General_options& options, if (gsym->type() == elfcpp::STT_FUNC) target->make_plt_entry(&options, symtab, layout, gsym); else - target->copy_reloc(&options, object, data_shndx, gsym, reloc); + target->copy_reloc(&options, symtab, layout, object, data_shndx, + gsym, reloc); } break; @@ -854,6 +940,23 @@ Target_i386::scan_relocs(const General_options& options, global_symbols); } +// Finalize the sections. This is where we emit any relocs we saved +// in an attempt to avoid generating extra COPY relocs. + +void +Target_i386::do_finalize_sections(Layout* layout) +{ + if (this->copy_relocs_ == NULL) + return; + if (this->copy_relocs_->any_to_emit()) + { + Reloc_section* rel_dyn = this->rel_dyn_section(layout); + this->copy_relocs_->emit(rel_dyn); + } + delete this->copy_relocs_; + this->copy_relocs_ = NULL; +} + // Perform a relocation. inline bool diff --git a/gold/layout.cc b/gold/layout.cc index 97917b0..0de42c2 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -383,9 +383,11 @@ Layout::find_first_load_seg() off_t Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab) { - const Target* const target = input_objects->target(); + Target* const target = input_objects->target(); const int size = target->get_size(); + target->finalize_sections(this); + Output_segment* phdr_seg = NULL; if (input_objects->any_dynamic()) { diff --git a/gold/main.cc b/gold/main.cc new file mode 100644 index 0000000..ea65c2d --- /dev/null +++ b/gold/main.cc @@ -0,0 +1,57 @@ +// main.cc -- gold main function. + +#include "gold.h" + +#include "options.h" +#include "dirsearch.h" +#include "workqueue.h" +#include "object.h" +#include "symtab.h" +#include "layout.h" + +using namespace gold; + +int +main(int argc, char** argv) +{ +#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES) + setlocale (LC_MESSAGES, ""); +#endif +#if defined (HAVE_SETLOCALE) + setlocale (LC_CTYPE, ""); +#endif + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + program_name = argv[0]; + + // Handle the command line options. + Command_line command_line; + command_line.process(argc - 1, argv + 1); + + // The work queue. + Workqueue workqueue(command_line.options()); + + // The list of input objects. + Input_objects input_objects; + + // The symbol table. + Symbol_table symtab; + + // The layout object. + Layout layout(command_line.options()); + + // Get the search path from the -L options. + Dirsearch search_path; + search_path.add(&workqueue, command_line.options().search_path()); + + // Queue up the first set of tasks. + queue_initial_tasks(command_line.options(), search_path, + command_line, &workqueue, &input_objects, + &symtab, &layout); + + // Run the main task processing loop. + workqueue.process(); + + gold_exit(true); +} diff --git a/gold/object.h b/gold/object.h index cd2bc8d..b823599 100644 --- a/gold/object.h +++ b/gold/object.h @@ -140,22 +140,10 @@ class Object Sized_target* sized_target(ACCEPT_SIZE_ENDIAN_ONLY); - // Read the symbol information. - void - read_symbols(Read_symbols_data* sd) - { return this->do_read_symbols(sd); } - - // Pass sections which should be included in the link to the Layout - // object, and record where the sections go in the output file. - void - layout(const General_options& options, Symbol_table* symtab, - Layout* layout, Read_symbols_data* sd) - { this->do_layout(options, symtab, layout, sd); } - - // Add symbol information to the global symbol table. - void - add_symbols(Symbol_table* symtab, Read_symbols_data* sd) - { this->do_add_symbols(symtab, sd); } + // Get the number of sections. + unsigned int + shnum() const + { return this->shnum_; } // Return a view of the contents of a section. Set *PLEN to the // size. @@ -173,6 +161,23 @@ class Object section_flags(unsigned int shndx) { return this->do_section_flags(shndx); } + // Read the symbol information. + void + read_symbols(Read_symbols_data* sd) + { return this->do_read_symbols(sd); } + + // Pass sections which should be included in the link to the Layout + // object, and record where the sections go in the output file. + void + layout(const General_options& options, Symbol_table* symtab, + Layout* layout, Read_symbols_data* sd) + { this->do_layout(options, symtab, layout, sd); } + + // Add symbol information to the global symbol table. + void + add_symbols(Symbol_table* symtab, Read_symbols_data* sd) + { this->do_add_symbols(symtab, sd); } + // Functions and types for the elfcpp::Elf_file interface. This // permit us to use Object as the File template parameter for // elfcpp::Elf_file. @@ -280,11 +285,6 @@ class Object set_target(int machine, int size, bool big_endian, int osabi, int abiversion); - // Get the number of sections. - unsigned int - shnum() const - { return this->shnum_; } - // Set the number of sections. void set_shnum(int shnum) @@ -373,17 +373,17 @@ class Relobj : public Object // Return whether an input section is being included in the link. bool - is_section_included(unsigned int shnum) const + is_section_included(unsigned int shndx) const { - gold_assert(shnum < this->map_to_output_.size()); - return this->map_to_output_[shnum].output_section != NULL; + gold_assert(shndx < this->map_to_output_.size()); + return this->map_to_output_[shndx].output_section != NULL; } // Given a section index, return the corresponding Output_section // (which will be NULL if the section is not included in the link) // and set *POFF to the offset within that section. inline Output_section* - output_section(unsigned int shnum, off_t* poff); + output_section(unsigned int shndx, off_t* poff); // Set the offset of an input section within its output section. void @@ -437,10 +437,10 @@ class Relobj : public Object // Implement Object::output_section inline for efficiency. inline Output_section* -Relobj::output_section(unsigned int shnum, off_t* poff) +Relobj::output_section(unsigned int shndx, off_t* poff) { - gold_assert(shnum < this->map_to_output_.size()); - const Map_to_output& mo(this->map_to_output_[shnum]); + gold_assert(shndx < this->map_to_output_.size()); + const Map_to_output& mo(this->map_to_output_[shndx]); *poff = mo.offset; return mo.output_section; } diff --git a/gold/output.cc b/gold/output.cc index e4720df..2dbf576 100644 --- a/gold/output.cc +++ b/gold/output.cc @@ -415,19 +415,19 @@ Output_reloc::get_symbol_index() gold_unreachable(); case GSYM_CODE: - if (this->u_.gsym == NULL) + if (this->u1_.gsym == NULL) index = 0; else if (dynamic) - index = this->u_.gsym->dynsym_index(); + index = this->u1_.gsym->dynsym_index(); else - index = this->u_.gsym->symtab_index(); + index = this->u1_.gsym->symtab_index(); break; case SECTION_CODE: if (dynamic) - index = this->u_.os->dynsym_index(); + index = this->u1_.os->dynsym_index(); else - index = this->u_.os->symtab_index(); + index = this->u1_.os->symtab_index(); break; default: @@ -439,7 +439,7 @@ Output_reloc::get_symbol_index() gold_unreachable(); } else - index = this->u_.object->symtab_index(this->local_sym_index_); + index = this->u1_.relobj->symtab_index(this->local_sym_index_); break; } gold_assert(index != -1U); @@ -456,8 +456,16 @@ Output_reloc::write_rel( Write_rel* wr) const { Address address = this->address_; - if (this->od_ != NULL) - address += this->od_->address(); + if (this->shndx_ != INVALID_CODE) + { + off_t off; + Output_section* os = this->u2_.relobj->output_section(this->shndx_, + &off); + gold_assert(os != NULL); + address += os->address() + off; + } + else if (this->u2_.od != NULL) + address += this->u2_.od->address(); wr->put_r_offset(address); wr->put_r_info(elfcpp::elf_r_info(this->get_symbol_index(), this->type_)); diff --git a/gold/output.h b/gold/output.h index c7d835d..6e575ba 100644 --- a/gold/output.h +++ b/gold/output.h @@ -323,6 +323,11 @@ class Output_section_data : public Output_data unsigned int do_out_shndx() const; + // Set the alignment. + void + set_addralign(uint64_t addralign) + { this->addralign_ = addralign; } + private: // The output section for this section. const Output_section* output_section_; @@ -402,6 +407,11 @@ class Output_data_space : public Output_section_data set_space_size(off_t space_size) { this->set_data_size(space_size); } + // Set the alignment. + void + set_space_alignment(uint64_t align) + { this->set_addralign(align); } + // Write out the data--this must be handled elsewhere. void do_write(Output_file*) @@ -457,30 +467,77 @@ class Output_reloc { } // A reloc against a global symbol. + Output_reloc(Symbol* gsym, unsigned int type, Output_data* od, Address address) - : local_sym_index_(GSYM_CODE), type_(type), od_(od), address_(address) - { this->u_.gsym = gsym; } + : address_(address), local_sym_index_(GSYM_CODE), type_(type), + shndx_(INVALID_CODE) + { + this->u1_.gsym = gsym; + this->u2_.od = od; + } + + Output_reloc(Symbol* gsym, unsigned int type, Relobj* relobj, + unsigned int shndx, Address address) + : address_(address), local_sym_index_(GSYM_CODE), type_(type), + shndx_(shndx) + { + gold_assert(shndx != INVALID_CODE); + this->u1_.gsym = gsym; + this->u2_.relobj = relobj; + } // A reloc against a local symbol. - Output_reloc(Sized_relobj* object, + + Output_reloc(Sized_relobj* relobj, unsigned int local_sym_index, unsigned int type, Output_data* od, Address address) - : local_sym_index_(local_sym_index), type_(type), od_(od), - address_(address) + : address_(address), local_sym_index_(local_sym_index), type_(type), + shndx_(INVALID_CODE) { gold_assert(local_sym_index != GSYM_CODE && local_sym_index != INVALID_CODE); - this->u_.object = object; + this->u1_.relobj = relobj; + this->u2_.od = od; + } + + Output_reloc(Sized_relobj* relobj, + unsigned int local_sym_index, + unsigned int type, + unsigned int shndx, + Address address) + : address_(address), local_sym_index_(local_sym_index), type_(type), + shndx_(shndx) + { + gold_assert(local_sym_index != GSYM_CODE + && local_sym_index != INVALID_CODE); + gold_assert(shndx != INVALID_CODE); + this->u1_.relobj = relobj; + this->u2_.relobj = relobj; } // A reloc against the STT_SECTION symbol of an output section. + Output_reloc(Output_section* os, unsigned int type, Output_data* od, Address address) - : local_sym_index_(SECTION_CODE), type_(type), od_(od), address_(address) - { this->u_.os = os; } + : address_(address), local_sym_index_(SECTION_CODE), type_(type), + shndx_(INVALID_CODE) + { + this->u1_.os = os; + this->u2_.od = od; + } + + Output_reloc(Output_section* os, unsigned int type, Relobj* relobj, + unsigned int shndx, Address address) + : address_(address), local_sym_index_(SECTION_CODE), type_(type), + shndx_(shndx) + { + gold_assert(shndx != INVALID_CODE); + this->u1_.os = os; + this->u2_.relobj = relobj; + } // Write the reloc entry to an output view. void @@ -513,24 +570,34 @@ class Output_reloc // relocation against a local symbol in a dynamic object; that // doesn't make sense. And our callers will always be // templatized, so we use Sized_relobj here. - Sized_relobj* object; + Sized_relobj* relobj; // For a global symbol, the symbol. If this is NULL, it indicates // a relocation against the undefined 0 symbol. Symbol* gsym; // For a relocation against an output section, the output section. Output_section* os; - } u_; + } u1_; + union + { + // If shndx_ is not INVALID CODE, the object which holds the input + // section being used to specify the reloc address. + Relobj* relobj; + // If shndx_ is INVALID_CODE, the output data being used to + // specify the reloc address. This may be NULL if the reloc + // address is absolute. + Output_data* od; + } u2_; + // The address offset within the input section or the Output_data. + Address address_; // For a local symbol, the local symbol index. This is GSYM_CODE // for a global symbol, or INVALID_CODE for an uninitialized value. unsigned int local_sym_index_; // The reloc type--a processor specific code. unsigned int type_; - // If this is not NULL, then the relocation is against the contents - // of this output data. - Output_data* od_; - // The reloc address--if od_ is not NULL, this is the offset from - // the start of od_. - Address address_; + // If the reloc address is an input section in an object, the + // section index. This is INVALID_CODE if the reloc address is + // specified in some other way. + unsigned int shndx_; }; // The SHT_RELA version of Output_reloc<>. This is just derived from @@ -549,25 +616,48 @@ class Output_reloc { } // A reloc against a global symbol. + Output_reloc(Symbol* gsym, unsigned int type, Output_data* od, Address address, Addend addend) : rel_(gsym, type, od, address), addend_(addend) { } + Output_reloc(Symbol* gsym, unsigned int type, Relobj* relobj, + unsigned int shndx, Address address, Addend addend) + : rel_(gsym, type, relobj, shndx, address), addend_(addend) + { } + // A reloc against a local symbol. - Output_reloc(Sized_relobj* object, + + Output_reloc(Sized_relobj* relobj, unsigned int local_sym_index, unsigned int type, Output_data* od, Address address, Addend addend) - : rel_(object, local_sym_index, type, od, address), addend_(addend) + : rel_(relobj, local_sym_index, type, od, address), addend_(addend) + { } + + Output_reloc(Sized_relobj* relobj, + unsigned int local_sym_index, + unsigned int type, + unsigned int shndx, + Address address, + Addend addend) + : rel_(relobj, local_sym_index, type, shndx, address), + addend_(addend) { } // A reloc against the STT_SECTION symbol of an output section. + Output_reloc(Output_section* os, unsigned int type, Output_data* od, Address address, Addend addend) : rel_(os, type, od, address), addend_(addend) { } + Output_reloc(Output_section* os, unsigned int type, Relobj* relobj, + unsigned int shndx, Address address, Addend addend) + : rel_(os, type, relobj, shndx, address), addend_(addend) + { } + // Write the reloc entry to an output view. void write(unsigned char* pov) const; @@ -643,22 +733,43 @@ class Output_data_reloc { } // Add a reloc against a global symbol. + void add_global(Symbol* gsym, unsigned int type, Output_data* od, Address address) { this->add(Output_reloc_type(gsym, type, od, address)); } + void + add_global(Symbol* gsym, unsigned int type, Relobj* relobj, + unsigned int shndx, Address address) + { this->add(Output_reloc_type(gsym, type, relobj, shndx, address)); } + // Add a reloc against a local symbol. + void - add_local(Sized_relobj* object, + add_local(Sized_relobj* relobj, unsigned int local_sym_index, unsigned int type, Output_data* od, Address address) - { this->add(Output_reloc_type(object, local_sym_index, type, od, address)); } + { this->add(Output_reloc_type(relobj, local_sym_index, type, od, address)); } + + void + add_local(Sized_relobj* relobj, + unsigned int local_sym_index, unsigned int type, + unsigned int shndx, Address address) + { this->add(Output_reloc_type(relobj, local_sym_index, type, shndx, + address)); } + // A reloc against the STT_SECTION symbol of an output section. + void add_output_section(Output_section* os, unsigned int type, Output_data* od, Address address) { this->add(Output_reloc_type(os, type, od, address)); } + + void + add_output_section(Output_section* os, unsigned int type, + Relobj* relobj, unsigned int shndx, Address address) + { this->add(Output_reloc_type(os, type, relobj, shndx, address)); } }; // The SHT_RELA version of Output_data_reloc. @@ -681,26 +792,48 @@ class Output_data_reloc { } // Add a reloc against a global symbol. + void add_global(Symbol* gsym, unsigned int type, Output_data* od, Address address, Addend addend) { this->add(Output_reloc_type(gsym, type, od, address, addend)); } + void + add_global(Symbol* gsym, unsigned int type, Relobj* relobj, + unsigned int shndx, Address address, Addend addend) + { this->add(Output_reloc_type(gsym, type, relobj, shndx, address, addend)); } + // Add a reloc against a local symbol. + void - add_local(Sized_relobj* object, + add_local(Sized_relobj* relobj, unsigned int local_sym_index, unsigned int type, Output_data* od, Address address, Addend addend) { - this->add(Output_reloc_type(object, local_sym_index, type, od, address, + this->add(Output_reloc_type(relobj, local_sym_index, type, od, address, + addend)); + } + + void + add_local(Sized_relobj* relobj, + unsigned int local_sym_index, unsigned int type, + unsigned int shndx, Address address, Addend addend) + { + this->add(Output_reloc_type(relobj, local_sym_index, type, shndx, address, addend)); } // A reloc against the STT_SECTION symbol of an output section. + void add_output_section(Output_section* os, unsigned int type, Output_data* od, Address address, Addend addend) { this->add(Output_reloc_type(os, type, od, address, addend)); } + + void + add_output_section(Output_section* os, unsigned int type, Relobj* relobj, + unsigned int shndx, Address address, Addend addend) + { this->add(Output_reloc_type(os, type, relobj, shndx, address, addend)); } }; // Output_data_got is used to manage a GOT. Each entry in the GOT is diff --git a/gold/po/gold.pot b/gold/po/gold.pot index 5663031..4a852a1 100644 --- a/gold/po/gold.pot +++ b/gold/po/gold.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2006-11-29 09:53-0800\n" +"POT-Creation-Date: 2006-11-30 15:37-0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -161,27 +161,27 @@ msgstr "" msgid "%s: warning: close(%s) failed: %s" msgstr "" -#: fileread.cc:128 +#: fileread.cc:143 #, c-format msgid "%s: %s: lseek to %lld failed: %s" msgstr "" -#: fileread.cc:138 +#: fileread.cc:153 #, c-format msgid "%s: %s: read failed: %s\n" msgstr "" -#: fileread.cc:148 fileread.cc:231 +#: fileread.cc:173 fileread.cc:256 #, c-format msgid "%s: %s: file too short: read only %lld of %lld bytes at %lld\n" msgstr "" -#: fileread.cc:326 +#: fileread.cc:365 #, c-format msgid "%s: cannot find %s\n" msgstr "" -#: fileread.cc:334 +#: fileread.cc:373 #, c-format msgid "%s: cannot open %s: %s\n" msgstr "" @@ -235,57 +235,57 @@ msgid "pthread_cond_signal failed" msgstr "" #. FIXME: This needs to specify the location somehow. -#: i386.cc:93 +#: i386.cc:100 #, c-format msgid "%s: missing expected TLS relocation\n" msgstr "" -#: i386.cc:617 i386.cc:757 i386.cc:961 +#: i386.cc:702 i386.cc:843 i386.cc:1064 #, c-format msgid "%s: %s: unexpected reloc %u in object file\n" msgstr "" -#: i386.cc:653 i386.cc:672 +#: i386.cc:738 i386.cc:757 #, c-format msgid "%s: %s: unsupported reloc %u against local symbol\n" msgstr "" -#: i386.cc:793 i386.cc:814 +#: i386.cc:879 i386.cc:900 #, c-format msgid "%s: %s: unsupported reloc %u against global symbol %s\n" msgstr "" -#: i386.cc:837 +#: i386.cc:923 #, c-format msgid "%s: %s: unsupported RELA reloc section\n" msgstr "" -#: i386.cc:877 +#: i386.cc:980 #, c-format msgid "%s: %s: missing expected TLS relocation\n" msgstr "" -#: i386.cc:993 i386.cc:1068 i386.cc:1079 +#: i386.cc:1096 i386.cc:1171 i386.cc:1182 #, c-format msgid "%s: %s: unsupported reloc %u\n" msgstr "" -#: i386.cc:1020 +#: i386.cc:1123 #, c-format msgid "%s: %s: TLS reloc but no TLS segment\n" msgstr "" -#: i386.cc:1053 +#: i386.cc:1156 #, c-format msgid "%s: %s: unsupported reloc type %u\n" msgstr "" -#: i386.cc:1262 +#: i386.cc:1365 #, c-format msgid "%s: %s: TLS relocation out of range\n" msgstr "" -#: i386.cc:1280 +#: i386.cc:1383 #, c-format msgid "%s: %s: TLS relocation against invalid instruction\n" msgstr "" @@ -496,37 +496,37 @@ msgstr "" msgid "%s: -%c: %s\n" msgstr "" -#: output.cc:809 +#: output.cc:817 #, c-format msgid "%s: %s: invalid alignment %lu for section \"%s\"\n" msgstr "" -#: output.cc:1308 +#: output.cc:1316 #, c-format msgid "%s: %s: open: %s\n" msgstr "" -#: output.cc:1317 +#: output.cc:1325 #, c-format msgid "%s: %s: lseek: %s\n" msgstr "" -#: output.cc:1324 +#: output.cc:1332 #, c-format msgid "%s: %s: write: %s\n" msgstr "" -#: output.cc:1334 +#: output.cc:1342 #, c-format msgid "%s: %s: mmap: %s\n" msgstr "" -#: output.cc:1348 +#: output.cc:1356 #, c-format msgid "%s: %s: munmap: %s\n" msgstr "" -#: output.cc:1356 +#: output.cc:1364 #, c-format msgid "%s: %s: close: %s\n" msgstr "" @@ -547,22 +547,22 @@ msgstr "" msgid "%s: %s: not an object or archive\n" msgstr "" -#: reloc.cc:168 reloc.cc:409 +#: reloc.cc:169 reloc.cc:410 #, c-format msgid "%s: %s: relocation section %u has bad info %u\n" msgstr "" -#: reloc.cc:187 reloc.cc:426 +#: reloc.cc:188 reloc.cc:427 #, c-format msgid "%s: %s: relocation section %u uses unexpected symbol table %u\n" msgstr "" -#: reloc.cc:203 reloc.cc:445 +#: reloc.cc:204 reloc.cc:446 #, c-format msgid "%s: %s: unexpected entsize for reloc section %u: %lu != %u" msgstr "" -#: reloc.cc:214 reloc.cc:456 +#: reloc.cc:215 reloc.cc:457 #, c-format msgid "%s: %s: reloc section %u size %lu uneven" msgstr "" diff --git a/gold/readsyms.cc b/gold/readsyms.cc index 2b200ba..ba3e85e 100644 --- a/gold/readsyms.cc +++ b/gold/readsyms.cc @@ -61,7 +61,7 @@ Read_symbols::run(Workqueue* workqueue) return; } - Input_file* input_file = new Input_file(this->input_argument_->file()); + Input_file* input_file = new Input_file(&this->input_argument_->file()); input_file->open(this->options_, this->dirpath_); // Read enough of the file to pick up the entire ELF header. diff --git a/gold/reloc.cc b/gold/reloc.cc index 35f262e..915656c 100644 --- a/gold/reloc.cc +++ b/gold/reloc.cc @@ -4,6 +4,7 @@ #include "workqueue.h" #include "object.h" +#include "symtab.h" #include "output.h" #include "reloc.h" @@ -471,21 +472,64 @@ Sized_relobj::relocate_sections( } } -// Relocate_functions functions. +// Copy_relocs::Copy_reloc_entry methods. + +// Return whether we should emit this reloc. We should emit it if the +// symbol is still defined in a dynamic object. If we should not emit +// it, we clear it, to save ourselves the test next time. + +template +bool +Copy_relocs::Copy_reloc_entry::should_emit() +{ + if (this->sym_ == NULL) + return false; + if (this->sym_->is_defined_in_dynobj()) + return true; + this->sym_ = NULL; + return false; +} + +// Emit a reloc into a SHT_REL section. + +template +void +Copy_relocs::Copy_reloc_entry::emit( + Output_data_reloc* reloc_data) +{ + reloc_data->add_global(this->sym_, this->reloc_type_, this->relobj_, + this->shndx_, this->address_); +} + +// Emit a reloc into a SHT_RELA section. + +template +void +Copy_relocs::Copy_reloc_entry::emit( + Output_data_reloc* reloc_data) +{ + reloc_data->add_global(this->sym_, this->reloc_type_, this->relobj_, + this->shndx_, this->address_, this->addend_); +} + +// Copy_relocs methods. // Return whether we need a COPY reloc for a relocation against GSYM. // The relocation is being applied to section SHNDX in OBJECT. template bool -Relocate_functions::need_copy_reloc( +Copy_relocs::need_copy_reloc( const General_options*, Relobj* object, unsigned int shndx, - Symbol*) + Sized_symbol* sym) { // FIXME: Handle -z nocopyrelocs. + if (sym->symsize() == 0) + return false; + // If this is a readonly section, then we need a COPY reloc. // Otherwise we can use a dynamic reloc. if ((object->section_flags(shndx) & elfcpp::SHF_WRITE) == 0) @@ -494,6 +538,71 @@ Relocate_functions::need_copy_reloc( return false; } +// Save a Rel reloc. + +template +void +Copy_relocs::save( + Symbol* sym, + Relobj* relobj, + unsigned int shndx, + const elfcpp::Rel& rel) +{ + unsigned int reloc_type = elfcpp::elf_r_type(rel.get_r_info()); + this->entries_.push_back(Copy_reloc_entry(sym, reloc_type, relobj, shndx, + rel.get_r_offset(), 0)); +} + +// Save a Rela reloc. + +template +void +Copy_relocs::save( + Symbol* sym, + Relobj* relobj, + unsigned int shndx, + const elfcpp::Rela& rela) +{ + unsigned int reloc_type = elfcpp::elf_r_type(rela.get_r_info()); + this->entries_.push_back(Copy_reloc_entry(sym, reloc_type, relobj, shndx, + rela.get_r_offset(), + rela.get_r_addend())); +} + +// Return whether there are any relocs to emit. We don't want to emit +// a reloc if the symbol is no longer defined in a dynamic object. + +template +bool +Copy_relocs::any_to_emit() +{ + for (typename Copy_reloc_entries::iterator p = this->entries_.begin(); + p != this->entries_.end(); + ++p) + { + if (p->should_emit()) + return true; + } + return false; +} + +// Emit relocs. + +template +template +void +Copy_relocs::emit( + Output_data_reloc* reloc_data) +{ + for (typename Copy_reloc_entries::iterator p = this->entries_.begin(); + p != this->entries_.end(); + ++p) + { + if (p->should_emit()) + p->emit(reloc_data); + } +} + // Instantiate the templates we need. We could use the configure // script to restrict this to only the ones for implemented targets. @@ -570,27 +679,55 @@ Sized_relobj<64, true>::do_relocate(const General_options& options, Output_file* of); template -bool -Relocate_functions<32, false>::need_copy_reloc(const General_options*, - Relobj*, unsigned int, - Symbol*); +class Copy_relocs<32, false>; template -bool -Relocate_functions<32, true>::need_copy_reloc(const General_options*, - Relobj*, unsigned int, - Symbol*); +class Copy_relocs<32, true>; template -bool -Relocate_functions<64, false>::need_copy_reloc(const General_options*, - Relobj*, unsigned int, - Symbol*); +class Copy_relocs<64, false>; template -bool -Relocate_functions<64, true>::need_copy_reloc(const General_options*, - Relobj*, unsigned int, - Symbol*); +class Copy_relocs<64, true>; + +template +void +Copy_relocs<32, false>::emit( + Output_data_reloc*); + +template +void +Copy_relocs<32, true>::emit( + Output_data_reloc*); + +template +void +Copy_relocs<64, false>::emit( + Output_data_reloc*); + +template +void +Copy_relocs<64, true>::emit( + Output_data_reloc*); + +template +void +Copy_relocs<32, false>::emit( + Output_data_reloc*); + +template +void +Copy_relocs<32, true>::emit( + Output_data_reloc*); + +template +void +Copy_relocs<64, false>::emit( + Output_data_reloc*); + +template +void +Copy_relocs<64, true>::emit( + Output_data_reloc*); } // End namespace gold. diff --git a/gold/reloc.h b/gold/reloc.h index 7829440..1edaa57 100644 --- a/gold/reloc.h +++ b/gold/reloc.h @@ -17,6 +17,12 @@ class Stringpool; class Symbol; class Layout; +template +class Sized_symbol; + +template +class Output_data_reloc; + // A class to read the relocations for an object file, and then queue // up a task to see if they require any GOT/PLT/COPY relocations in // the symbol table. @@ -229,12 +235,99 @@ public: { This::template pcrel<64>(view, value, address); } +}; + +// We try to avoid COPY relocations when possible. A COPY relocation +// may be required when an executable refers to a variable defined in +// a shared library. COPY relocations are problematic because they +// tie the executable to the exact size of the variable in the shared +// library. We can avoid them if all the references to the variable +// are in a writeable section. In that case we can simply use dynamic +// relocations. However, when scanning relocs, we don't know when we +// see the relocation whether we will be forced to use a COPY +// relocation or not. So we have to save the relocation during the +// reloc scanning, and then emit it as a dynamic relocation if +// necessary. This class implements that. It is used by the target +// specific code. + +template +class Copy_relocs +{ + public: + Copy_relocs() + : entries_() + { } // Return whether we need a COPY reloc for a reloc against GSYM, // which is being applied to section SHNDX in OBJECT. static bool need_copy_reloc(const General_options*, Relobj* object, unsigned int shndx, - Symbol* gsym); + Sized_symbol* gsym); + + // Save a Rel against SYM for possible emission later. SHNDX is the + // index of the section to which the reloc is being applied. + void + save(Symbol* sym, Relobj*, unsigned int shndx, + const elfcpp::Rel&); + + // Save a Rela against SYM for possible emission later. + void + save(Symbol* sym, Relobj*, unsigned int shndx, + const elfcpp::Rela&); + + // Return whether there are any relocs to emit. This also discards + // entries which need not be emitted. + bool + any_to_emit(); + + // Emit relocs for each symbol which did not get a COPY reloc (i.e., + // is still defined in the dynamic object). + template + void + emit(Output_data_reloc*); + + private: + typedef typename elfcpp::Elf_types::Elf_Addr Address; + typedef typename elfcpp::Elf_types::Elf_Addr Addend; + + // This POD class holds the entries we are saving. + class Copy_reloc_entry + { + public: + Copy_reloc_entry(Symbol* sym, unsigned int reloc_type, + Relobj* relobj, unsigned int shndx, + Address address, Addend addend) + : sym_(sym), reloc_type_(reloc_type), relobj_(relobj), + shndx_(shndx), address_(address), addend_(addend) + { } + + // Return whether we should emit this reloc. If we should not + // emit, we clear it. + bool + should_emit(); + + // Emit this reloc. + + void + emit(Output_data_reloc*); + + void + emit(Output_data_reloc*); + + private: + Symbol* sym_; + unsigned int reloc_type_; + Relobj* relobj_; + unsigned int shndx_; + Address address_; + Addend addend_; + }; + + // A list of relocs to be saved. + typedef std::vector Copy_reloc_entries; + + // The list of relocs we are saving. + Copy_reloc_entries entries_; }; } // End namespace gold. diff --git a/gold/target.h b/gold/target.h index 039b97d..a031c40 100644 --- a/gold/target.h +++ b/gold/target.h @@ -83,6 +83,12 @@ class Target common_pagesize() const { return this->pti_->common_pagesize; } + // This is called to tell the target to complete any sections it is + // handling. After this all sections must have their final size. + void + finalize_sections(Layout* layout) + { return this->do_finalize_sections(layout); } + protected: // This struct holds the constant information for a child class. We // use a struct to avoid the overhead of virtual function calls for @@ -113,6 +119,11 @@ class Target : pti_(pti) { } + // Virtual function which may be implemented by the child class. + virtual void + do_finalize_sections(Layout*) + { } + private: Target(const Target&); Target& operator=(const Target&); diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am new file mode 100644 index 0000000..122be70 --- /dev/null +++ b/gold/testsuite/Makefile.am @@ -0,0 +1,22 @@ +# Process this file with automake to generate Makefile.in + +AUTOMAKE_OPTIONS = + +AM_CXXFLAGS = $(WARN_CXXFLAGS) $(LFS_CXXFLAGS) + +INCLUDES = -D_GNU_SOURCE \ + -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../../include \ + -I$(srcdir)/../../elfcpp \ + -DLOCALEDIR="\"$(datadir)/locale\"" \ + @INCINTL@ + +TESTS = object_unittest + +check_LIBRARIES = libgoldtest.a +libgoldtest_a_SOURCES = test.cc testmain.cc testfile.cc + +LDADD = libgoldtest.a ../libgold.a + +check_PROGRAMS = object_unittest + +object_unittest_SOURCES = object_unittest.cc diff --git a/gold/testsuite/Makefile.in b/gold/testsuite/Makefile.in new file mode 100644 index 0000000..4967af6 --- /dev/null +++ b/gold/testsuite/Makefile.in @@ -0,0 +1,521 @@ +# Makefile.in generated by automake 1.9.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Process this file with automake to generate Makefile.in +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +check_PROGRAMS = object_unittest$(EXEEXT) +subdir = testsuite +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/../config/depstand.m4 \ + $(top_srcdir)/../config/lead-dot.m4 \ + $(top_srcdir)/../config/progtest.m4 \ + $(top_srcdir)/../config/po.m4 $(top_srcdir)/../config/nls.m4 \ + $(top_srcdir)/../config/gettext-sister.m4 \ + $(top_srcdir)/../bfd/warning.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +libgoldtest_a_AR = $(AR) $(ARFLAGS) +libgoldtest_a_LIBADD = +am_libgoldtest_a_OBJECTS = test.$(OBJEXT) testmain.$(OBJEXT) \ + testfile.$(OBJEXT) +libgoldtest_a_OBJECTS = $(am_libgoldtest_a_OBJECTS) +am_object_unittest_OBJECTS = object_unittest.$(OBJEXT) +object_unittest_OBJECTS = $(am_object_unittest_OBJECTS) +object_unittest_LDADD = $(LDADD) +object_unittest_DEPENDENCIES = libgoldtest.a ../libgold.a +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/../depcomp +am__depfiles_maybe = depfiles +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ + -o $@ +SOURCES = $(libgoldtest_a_SOURCES) $(object_unittest_SOURCES) +DIST_SOURCES = $(libgoldtest_a_SOURCES) $(object_unittest_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CATALOGS = @CATALOGS@ +CATOBJEXT = @CATOBJEXT@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DATADIRNAME = @DATADIRNAME@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +GENCAT = @GENCAT@ +GMSGFMT = @GMSGFMT@ +INCINTL = @INCINTL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INSTOBJEXT = @INSTOBJEXT@ +LDFLAGS = @LDFLAGS@ +LFS_CXXFLAGS = @LFS_CXXFLAGS@ +LIBINTL = @LIBINTL@ +LIBINTL_DEP = @LIBINTL_DEP@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ +MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ +MAKEINFO = @MAKEINFO@ +MKINSTALLDIRS = @MKINSTALLDIRS@ +MSGFMT = @MSGFMT@ +MSGMERGE = @MSGMERGE@ +NO_WERROR = @NO_WERROR@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSUB = @POSUB@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +WARN_CFLAGS = @WARN_CFLAGS@ +WARN_CXXFLAGS = @WARN_CXXFLAGS@ +XGETTEXT = @XGETTEXT@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +AUTOMAKE_OPTIONS = +AM_CXXFLAGS = $(WARN_CXXFLAGS) $(LFS_CXXFLAGS) +INCLUDES = -D_GNU_SOURCE \ + -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../../include \ + -I$(srcdir)/../../elfcpp \ + -DLOCALEDIR="\"$(datadir)/locale\"" \ + @INCINTL@ + +TESTS = object_unittest +check_LIBRARIES = libgoldtest.a +libgoldtest_a_SOURCES = test.cc testmain.cc testfile.cc +LDADD = libgoldtest.a ../libgold.a +object_unittest_SOURCES = object_unittest.cc +all: all-am + +.SUFFIXES: +.SUFFIXES: .cc .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign testsuite/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign testsuite/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-checkLIBRARIES: + -test -z "$(check_LIBRARIES)" || rm -f $(check_LIBRARIES) +libgoldtest.a: $(libgoldtest_a_OBJECTS) $(libgoldtest_a_DEPENDENCIES) + -rm -f libgoldtest.a + $(libgoldtest_a_AR) libgoldtest.a $(libgoldtest_a_OBJECTS) $(libgoldtest_a_LIBADD) + $(RANLIB) libgoldtest.a + +clean-checkPROGRAMS: + -test -z "$(check_PROGRAMS)" || rm -f $(check_PROGRAMS) +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) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/object_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testfile.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testmain.Po@am__quote@ + +.cc.o: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cc.obj: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` +uninstall-info-am: + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list='$(TESTS)'; \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *" $$tst "*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + echo "XPASS: $$tst"; \ + ;; \ + *) \ + echo "PASS: $$tst"; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *" $$tst "*) \ + xfail=`expr $$xfail + 1`; \ + echo "XFAIL: $$tst"; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + echo "FAIL: $$tst"; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + echo "SKIP: $$tst"; \ + fi; \ + done; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="All $$all tests passed"; \ + else \ + banner="All $$all tests behaved as expected ($$xfail expected failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all tests failed"; \ + else \ + banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + skipped="($$skip tests were not run)"; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + echo "$$dashes"; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_LIBRARIES) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-checkLIBRARIES clean-checkPROGRAMS clean-generic \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am + +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-checkLIBRARIES clean-checkPROGRAMS clean-generic ctags \ + distclean distclean-compile distclean-generic distclean-tags \ + distdir dvi dvi-am html html-am info info-am install \ + install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-info-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/gold/testsuite/object_unittest.cc b/gold/testsuite/object_unittest.cc new file mode 100644 index 0000000..c15237d --- /dev/null +++ b/gold/testsuite/object_unittest.cc @@ -0,0 +1,41 @@ +// object_unittest.cc -- test Object, Relobj, etc. + +#include "gold.h" + +#include "object.h" + +#include "test.h" +#include "testfile.h" + +namespace gold_testsuite +{ + +using namespace gold; + +// Test basic Object functionality. + +bool +Object_test(Test_report*) +{ + Input_file input_file("test.o", test_file_1, test_file_1_size); + Object* object = make_elf_object("test.o", &input_file, 0, + test_file_1, test_file_1_size); + CHECK(object->name() == "test.o"); + CHECK(!object->is_dynamic()); + CHECK(object->target() == target_test_pointer); + CHECK(object->is_locked()); + object->unlock(); + CHECK(!object->is_locked()); + object->lock(); + CHECK(object->shnum() == 5); + CHECK(object->section_name(0).empty()); + CHECK(object->section_name(1) == ".test"); + CHECK(object->section_flags(0) == 0); + CHECK(object->section_flags(1) == elfcpp::SHF_ALLOC); + object->unlock(); + return true; +} + +Register_test object_register("Object", Object_test); + +} // End namespace gold_testsuite. diff --git a/gold/testsuite/test.cc b/gold/testsuite/test.cc new file mode 100644 index 0000000..37a4ada --- /dev/null +++ b/gold/testsuite/test.cc @@ -0,0 +1,78 @@ +// test.cc -- simplistic test framework for gold. + +#include "gold.h" + +#include + +#include "test.h" + +namespace gold_testsuite +{ + +// Test_framework methods. + +// The current test being run. + +Test_report* Test_framework::current_report; + +// Run a test. + +void +Test_framework::run(const char *name, bool (*pfn)(Test_report*)) +{ + this->testname_ = name; + this->current_fail_ = false; + + Test_report tr(this); + Test_framework::current_report = &tr; + + if ((*pfn)(&tr) && !this->current_fail_) + { + printf("PASS: %s\n", name); + ++this->passes_; + } + else + { + printf("FAIL: %s\n", name); + ++this->failures_; + } + + Test_framework::current_report = NULL; + this->testname_ = NULL; +} + +// Let a test report an error. + +void +Test_framework::error(const char* message) +{ + printf("ERROR: %s: %s\n", this->testname_, message); + this->fail(); +} + +// Register_test methods. + +// Linked list of all registered tests. + +Register_test* Register_test::all_tests; + +// Register a test. + +Register_test::Register_test(const char* name, bool (*pfn)(Test_report*)) + : name_(name), pfn_(pfn), next_(Register_test::all_tests) +{ + Register_test::all_tests = this; +} + +// Run all registered tests. + +void +Register_test::run_tests(Test_framework* tf) +{ + for (Register_test* p = Register_test::all_tests; + p != NULL; + p = p->next_) + tf->run(p->name_, p->pfn_); +} + +} // End namespace gold_testsuite. diff --git a/gold/testsuite/test.h b/gold/testsuite/test.h new file mode 100644 index 0000000..e0556e2 --- /dev/null +++ b/gold/testsuite/test.h @@ -0,0 +1,121 @@ +// test.h -- simplistic test framework for gold unittests -*- C++ -*- + +#ifndef GOLD_TESTSUITE_TEST_H +#define GOLD_TESTSUITE_TEST_H + +namespace gold_testsuite +{ + +class Test_report; + +// This class handles basic test framework functionality. + +class Test_framework +{ + public: + Test_framework() + : testname_(NULL), current_fail_(0), passes_(0), failures_(0) + { } + + // Return number of failures. + unsigned int + failures() const + { return this->failures_; } + + // Run a test. + void + run(const char* name, bool (*pfn)(Test_report*)); + + // Get the current Test_report. This is used by the test support + // macros. + static Test_report* + report() + { return Test_framework::current_report; } + + private: + friend class Test_report; + + // Cause the current test to fail. + void + fail() + { ++this->current_fail_ = true; } + + // Report an error from the current test. + void + error(const char* message); + + // Current Test_report. This is a static variable valid while a + // test is being run. + static Test_report* current_report; + + // Current test being run. + const char* testname_; + // Whether the current test is failing. + bool current_fail_; + // Total number of passeed tests. + unsigned int passes_; + // Total number of failed tests. + unsigned int failures_; +}; + +// An instance of this class is passed to each test function. + +class Test_report +{ +public: + Test_report(Test_framework* tf) + : tf_(tf) + { } + + // Mark the test as failing. + void + fail() + { this->tf_->fail(); } + + // Report an error. + void + error(const char* message) + { this->tf_->error(message); } + +private: + Test_framework* tf_; +}; + +// This class registers a test function so that the testsuite runs it. + +class Register_test +{ + public: + Register_test(const char* name, bool (*pfn)(Test_report*)); + + // Run all registered tests. + static void + run_tests(Test_framework*); + + private: + // Linked list of all tests. + static Register_test* all_tests; + + // Test name. + const char* name_; + // Function to call. It should return true if the test passes, + // false if it fails. + bool (*pfn_)(Test_report*); + // Next test in linked list. + Register_test* next_; +}; + +} // End namespace gold_testsuite. + +// These macros are for convenient use in tests. + +// Check that a condition is true. If it is false, report a failure. + +#define CHECK(cond) \ + ((cond) ? 0 : (::gold_testsuite::Test_framework::report()->fail(), 0)) + +// Report an error during a test. + +#define ERROR(msg) (::gold_testsuite::Test_framework::report()->error(msg)) + +#endif // !defined(GOLD_TESTSUITE_TEST_H) diff --git a/gold/testsuite/testfile.cc b/gold/testsuite/testfile.cc new file mode 100644 index 0000000..bfe3c9d --- /dev/null +++ b/gold/testsuite/testfile.cc @@ -0,0 +1,261 @@ +// testfile.cc -- Dummy ELF objects for testing purposes. + +#include "gold.h" + +#include "target.h" +#include "target-select.h" + +#include "test.h" +#include "testfile.h" + +namespace gold_testsuite +{ + +using namespace gold; + +// A Target used for testing purposes. + +class Target_test : public Sized_target<32, false> +{ + public: + Target_test() + : Sized_target<32, false>(&test_target_info) + { } + + void + scan_relocs(const General_options&, Symbol_table*, Layout*, + Sized_relobj<32, false>*, unsigned int, unsigned int, + const unsigned char*, size_t, size_t, const unsigned char*, + Symbol**) + { ERROR("call to Target_test::scan_relocs"); } + + void + relocate_section(const Relocate_info<32, false>*, unsigned int, + const unsigned char*, size_t, unsigned char*, + elfcpp::Elf_types<32>::Elf_Addr, off_t) + { ERROR("call to Target_test::relocate_section"); } + + static const Target::Target_info test_target_info; +}; + +const Target::Target_info Target_test::test_target_info = +{ + 32, // size + false, // is_big_endian + static_cast(0xffff), // machine_code + false, // has_make_symbol + false, // has_resolve + "/dummy", // dynamic_linker + 0x08000000, // text_segment_address + 0x1000, // abi_pagesize + 0x1000 // common_pagesize +}; + +// The single test target. + +Target_test target_test; + +// A pointer to the test target. This is used in CHECKs. + +Target* target_test_pointer = &target_test; + +// Select the test target. + +class Target_selector_test : public Target_selector +{ + public: + Target_selector_test() + : Target_selector(0xffff, 32, false) + { } + + Target* + recognize(int, int, int) + { return &target_test; } +}; + +// Register the test target selector. + +Target_selector_test target_selector_test; + +// A simple ELF object with one empty section, named ".test" and one +// globally visible symbol named "test". + +const unsigned char test_file_1[] = +{ + // Ehdr + // EI_MAG[0-3] + 0x7f, 'E', 'L', 'F', + // EI_CLASS: 32 bit. + 1, + // EI_DATA: little endian + 1, + // EI_VERSION + 1, + // EI_OSABI + 0, + // EI_ABIVERSION + 0, + // EI_PAD + 0, 0, 0, 0, 0, 0, 0, + // e_type: ET_REL + 1, 0, + // e_machine: a magic value used for testing. + 0xff, 0xff, + // e_version + 1, 0, 0, 0, + // e_entry + 0, 0, 0, 0, + // e_phoff + 0, 0, 0, 0, + // e_shoff: starts right after file header + 52, 0, 0, 0, + // e_flags + 0, 0, 0, 0, + // e_ehsize + 52, 0, + // e_phentsize + 32, 0, + // e_phnum + 0, 0, + // e_shentsize + 40, 0, + // e_shnum: dummy, .test, .symtab, .strtab, .shstrtab + 5, 0, + // e_shstrndx + 4, 0, + + // Offset 52 + // Shdr 0: dummy entry + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + + // Offset 92 + // Shdr 1: .test + // sh_name: after initial null + 1, 0, 0, 0, + // sh_type: SHT_PROGBITS + 1, 0, 0, 0, + // sh_flags: SHF_ALLOC + 2, 0, 0, 0, + // sh_addr + 0, 0, 0, 0, + // sh_offset: after file header + 5 section headers + 252, 0, 0, 0, + // sh_size + 0, 0, 0, 0, + // sh_link + 0, 0, 0, 0, + // sh_info + 0, 0, 0, 0, + // sh_addralign + 1, 0, 0, 0, + // sh_entsize + 0, 0, 0, 0, + + // Offset 132 + // Shdr 2: .symtab + // sh_name: 1 null byte + ".test\0" + 7, 0, 0, 0, + // sh_type: SHT_SYMTAB + 2, 0, 0, 0, + // sh_flags + 0, 0, 0, 0, + // sh_addr + 0, 0, 0, 0, + // sh_offset: after file header + 5 section headers + empty section + 252, 0, 0, 0, + // sh_size: two symbols: dummy symbol + test symbol + 32, 0, 0, 0, + // sh_link: to .strtab + 3, 0, 0, 0, + // sh_info: one local symbol, the dummy symbol + 1, 0, 0, 0, + // sh_addralign + 4, 0, 0, 0, + // sh_entsize: size of symbol + 16, 0, 0, 0, + + // Offset 172 + // Shdr 3: .strtab + // sh_name: 1 null byte + ".test\0" + ".symtab\0" + 15, 0, 0, 0, + // sh_type: SHT_STRTAB + 3, 0, 0, 0, + // sh_flags + 0, 0, 0, 0, + // sh_addr + 0, 0, 0, 0, + // sh_offset: after .symtab section. 284 == 0x11c + 0x1c, 0x1, 0, 0, + // sh_size: 1 null byte + "test\0" + 6, 0, 0, 0, + // sh_link + 0, 0, 0, 0, + // sh_info + 0, 0, 0, 0, + // sh_addralign + 1, 0, 0, 0, + // sh_entsize + 0, 0, 0, 0, + + // Offset 212 + // Shdr 4: .shstrtab + // sh_name: 1 null byte + ".test\0" + ".symtab\0" + ".strtab\0" + 23, 0, 0, 0, + // sh_type: SHT_STRTAB + 3, 0, 0, 0, + // sh_flags + 0, 0, 0, 0, + // sh_addr + 0, 0, 0, 0, + // sh_offset: after .strtab section. 290 == 0x122 + 0x22, 0x1, 0, 0, + // sh_size: all section names + 33, 0, 0, 0, + // sh_link + 0, 0, 0, 0, + // sh_info + 0, 0, 0, 0, + // sh_addralign + 1, 0, 0, 0, + // sh_entsize + 0, 0, 0, 0, + + // Offset 252 + // Contents of .symtab section + // Symbol 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + // Offset 268 + // Symbol 1 + // st_name + 1, 0, 0, 0, + // st_value + 0, 0, 0, 0, + // st_size + 0, 0, 0, 0, + // st_info: STT_NOTYPE, STB_GLOBAL + 0x10, + // st_other + 0, + // st_shndx: In .test + 1, 0, + + // Offset 284 + // Contents of .strtab section + '\0', + 't', 'e', 's', 't', '\0', + + // Offset 290 + // Contents of .shstrtab section + '\0', + '.', 't', 'e', 's', 't', '\0', + '.', 's', 'y', 'm', 't', 'a', 'b', '\0', + '.', 's', 't', 'r', 't', 'a', 'b', '\0', + '.', 's', 'h', 's', 't', 'r', 't', 'a', 'b', '\0' +}; + +const unsigned int test_file_1_size = sizeof test_file_1; + +} // End namespace gold_testsuite. diff --git a/gold/testsuite/testfile.h b/gold/testsuite/testfile.h new file mode 100644 index 0000000..c123107 --- /dev/null +++ b/gold/testsuite/testfile.h @@ -0,0 +1,20 @@ +// testfile.h -- test input files -*- C++ -*- + +#ifndef GOLD_TESTSUITE_TESTFILE_H +#define GOLD_TESTSUITE_TESTFILE_H + +namespace gold +{ +class Target; +} + +namespace gold_testsuite +{ + +extern gold::Target* target_test_pointer; +extern const unsigned char test_file_1[]; +extern const unsigned int test_file_1_size; + +}; // End namespace gold_testsuite. + +#endif // !defined(GOLD_TESTSUITE_TESTFILE_H) diff --git a/gold/testsuite/testmain.cc b/gold/testsuite/testmain.cc new file mode 100644 index 0000000..eb46b72 --- /dev/null +++ b/gold/testsuite/testmain.cc @@ -0,0 +1,18 @@ +// testmain.cc -- main function for simplisitic gold test framework. + +#include "gold.h" + +#include "test.h" + +using namespace gold_testsuite; + +int +main(int, char** argv) +{ + gold::program_name = argv[0]; + + Test_framework tf; + Register_test::run_tests(&tf); + + exit(tf.failures()); +} -- cgit v1.1