aboutsummaryrefslogtreecommitdiff
path: root/gold
diff options
context:
space:
mode:
Diffstat (limited to 'gold')
-rw-r--r--gold/Makefile.am112
-rw-r--r--gold/Makefile.in873
-rw-r--r--gold/README18
-rw-r--r--gold/aclocal.m4877
-rw-r--r--gold/archive.cc368
-rw-r--r--gold/archive.h162
-rw-r--r--gold/common.cc210
-rw-r--r--gold/common.h49
-rw-r--r--gold/config.in75
-rwxr-xr-xgold/configure6715
-rw-r--r--gold/configure.ac52
-rw-r--r--gold/defstd.cc239
-rw-r--r--gold/defstd.h16
-rw-r--r--gold/dirsearch.cc236
-rw-r--r--gold/dirsearch.h57
-rw-r--r--gold/dynobj.cc1647
-rw-r--r--gold/dynobj.h494
-rw-r--r--gold/fileread.cc379
-rw-r--r--gold/fileread.h257
-rw-r--r--gold/gold-threads.cc228
-rw-r--r--gold/gold-threads.h101
-rw-r--r--gold/gold.cc239
-rw-r--r--gold/gold.h214
-rw-r--r--gold/i386.cc1517
-rw-r--r--gold/layout.cc1440
-rw-r--r--gold/layout.h430
-rw-r--r--gold/main.cc57
-rw-r--r--gold/merge.cc333
-rw-r--r--gold/merge.h226
-rw-r--r--gold/object.cc973
-rw-r--r--gold/object.h820
-rw-r--r--gold/options.cc579
-rw-r--r--gold/options.h394
-rw-r--r--gold/output.cc1670
-rw-r--r--gold/output.h1801
-rw-r--r--gold/po/Make-in256
-rw-r--r--gold/po/POTFILES.in46
-rw-r--r--gold/po/gold.pot654
-rw-r--r--gold/readsyms.cc313
-rw-r--r--gold/readsyms.h194
-rw-r--r--gold/reloc-types.h36
-rw-r--r--gold/reloc.cc738
-rw-r--r--gold/reloc.h409
-rw-r--r--gold/resolve.cc560
-rw-r--r--gold/script-c.h53
-rw-r--r--gold/script.cc1193
-rw-r--r--gold/script.h39
-rw-r--r--gold/stringpool.cc386
-rw-r--r--gold/stringpool.h167
-rw-r--r--gold/strtab.h73
-rw-r--r--gold/symtab.cc1567
-rw-r--r--gold/symtab.h1050
-rw-r--r--gold/target-reloc.h193
-rw-r--r--gold/target-select.cc52
-rw-r--r--gold/target-select.h69
-rw-r--r--gold/target.h210
-rw-r--r--gold/testsuite/Makefile.am22
-rw-r--r--gold/testsuite/Makefile.in521
-rw-r--r--gold/testsuite/object_unittest.cc41
-rw-r--r--gold/testsuite/test.cc78
-rw-r--r--gold/testsuite/test.h121
-rw-r--r--gold/testsuite/testfile.cc261
-rw-r--r--gold/testsuite/testfile.h20
-rw-r--r--gold/testsuite/testmain.cc18
-rw-r--r--gold/workqueue.cc404
-rw-r--r--gold/workqueue.h419
-rw-r--r--gold/yyscript.y168
67 files changed, 34189 insertions, 0 deletions
diff --git a/gold/Makefile.am b/gold/Makefile.am
new file mode 100644
index 000000000000..a411127df94d
--- /dev/null
+++ b/gold/Makefile.am
@@ -0,0 +1,112 @@
+# Process this file with automake to generate Makefile.in
+
+AUTOMAKE_OPTIONS =
+
+SUBDIRS = po testsuite
+
+tooldir = $(exec_prefix)/$(target_alias)
+
+ACLOCAL_AMFLAGS = -I ../bfd -I ../config
+
+AM_CXXFLAGS = $(WARN_CXXFLAGS) $(LFS_CXXFLAGS)
+
+INCLUDES = -D_GNU_SOURCE \
+ -I$(srcdir) -I$(srcdir)/../include -I$(srcdir)/../elfcpp \
+ -DLOCALEDIR="\"$(datadir)/locale\"" \
+ @INCINTL@
+
+YFLAGS = -d
+
+noinst_PROGRAMS = ld-new
+noinst_LIBRARIES = libgold.a
+
+CCFILES = \
+ archive.cc \
+ common.cc \
+ defstd.cc \
+ dirsearch.cc \
+ dynobj.cc \
+ fileread.cc \
+ gold.cc \
+ gold-threads.cc \
+ layout.cc \
+ merge.cc \
+ object.cc \
+ options.cc \
+ output.cc \
+ readsyms.cc \
+ reloc.cc \
+ resolve.cc \
+ script.cc \
+ symtab.cc \
+ stringpool.cc \
+ target-select.cc \
+ workqueue.cc
+
+HFILES = \
+ archive.h \
+ common.h \
+ defstd.h \
+ dirsearch.h \
+ dynobj.h \
+ fileread.h \
+ gold.h \
+ gold-threads.h \
+ layout.h \
+ merge.h \
+ object.h \
+ options.h \
+ output.h \
+ readsyms.h \
+ reloc.h \
+ reloc-types.h \
+ script.h \
+ script-c.h \
+ stringpool.h \
+ symtab.h \
+ target.h \
+ target-reloc.h \
+ target-select.h \
+ workqueue.h
+
+TARGETFILES = \
+ i386.cc
+
+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)
+
+# 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)
+ $(mkinstalldirs) $(DESTDIR)$(bindir) $(DESTDIR)$(tooldir)/bin
+ n=`echo ld | sed '$(transform)'; \
+ $(INSTALL_PROGRAM) ld-new$(EXEEXT) $(DESTDIR)$(bindir)/$${n}$(EXEEXT); \
+ if test "$(bindir)" != "$(tooldir)/bin"; then \
+ rm -f $(DESTDIR)$(tooldir)/bin/ld$(EXEEXT); \
+ ln $(DESTDIR)$(bindir)/$${n}$(EXEEXT) $(DESTDIR)$(tooldir)/bin/ld$(EXEEXT) >/dev/null 2>/dev/null \
+ || $(INSTALL_PROGRAM) ld-new$(EXEEXT) $(DESTDIR)$(tooldir)/bin/ld$(EXEEXT); \
+ fi
+
+# 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
new file mode 100644
index 000000000000..884b1a52c888
--- /dev/null
+++ b/gold/Makefile.in
@@ -0,0 +1,873 @@
+# 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@
+noinst_PROGRAMS = ld-new$(EXEEXT)
+DIST_COMMON = README $(am__configure_deps) $(srcdir)/../config.guess \
+ $(srcdir)/../config.sub $(srcdir)/../depcomp \
+ $(srcdir)/../install-sh $(srcdir)/../missing \
+ $(srcdir)/../mkinstalldirs $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in $(srcdir)/config.in \
+ $(top_srcdir)/configure $(top_srcdir)/po/Make-in yyscript.c \
+ yyscript.h
+subdir = .
+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)
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+ configure.lineno configure.status.lineno
+mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES = po/Makefile.in
+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) \
+ merge.$(OBJEXT) object.$(OBJEXT) options.$(OBJEXT) \
+ output.$(OBJEXT) readsyms.$(OBJEXT) reloc.$(OBJEXT) \
+ resolve.$(OBJEXT) script.$(OBJEXT) symtab.$(OBJEXT) \
+ stringpool.$(OBJEXT) target-select.$(OBJEXT) \
+ workqueue.$(OBJEXT)
+am__objects_2 =
+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.
+depcomp = $(SHELL) $(top_srcdir)/../depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \
+ -o $@
+YACCCOMPILE = $(YACC) $(YFLAGS) $(AM_YFLAGS)
+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 \
+ install-recursive installcheck-recursive installdirs-recursive \
+ pdf-recursive ps-recursive uninstall-info-recursive \
+ uninstall-recursive
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+am__remove_distdir = \
+ { test ! -d $(distdir) \
+ || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \
+ && rm -fr $(distdir); }; }
+DIST_ARCHIVES = $(distdir).tar.gz
+GZIP_ENV = --best
+distuninstallcheck_listfiles = find . -type f -print
+distcleancheck_listfiles = find . -type f -print
+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 =
+SUBDIRS = po testsuite
+tooldir = $(exec_prefix)/$(target_alias)
+ACLOCAL_AMFLAGS = -I ../bfd -I ../config
+AM_CXXFLAGS = $(WARN_CXXFLAGS) $(LFS_CXXFLAGS)
+INCLUDES = -D_GNU_SOURCE \
+ -I$(srcdir) -I$(srcdir)/../include -I$(srcdir)/../elfcpp \
+ -DLOCALEDIR="\"$(datadir)/locale\"" \
+ @INCINTL@
+
+YFLAGS = -d
+noinst_LIBRARIES = libgold.a
+CCFILES = \
+ archive.cc \
+ common.cc \
+ defstd.cc \
+ dirsearch.cc \
+ dynobj.cc \
+ fileread.cc \
+ gold.cc \
+ gold-threads.cc \
+ layout.cc \
+ merge.cc \
+ object.cc \
+ options.cc \
+ output.cc \
+ readsyms.cc \
+ reloc.cc \
+ resolve.cc \
+ script.cc \
+ symtab.cc \
+ stringpool.cc \
+ target-select.cc \
+ workqueue.cc
+
+HFILES = \
+ archive.h \
+ common.h \
+ defstd.h \
+ dirsearch.h \
+ dynobj.h \
+ fileread.h \
+ gold.h \
+ gold-threads.h \
+ layout.h \
+ merge.h \
+ object.h \
+ options.h \
+ output.h \
+ readsyms.h \
+ reloc.h \
+ reloc-types.h \
+ script.h \
+ script-c.h \
+ stringpool.h \
+ symtab.h \
+ target.h \
+ target-reloc.h \
+ target-select.h \
+ workqueue.h
+
+TARGETFILES = \
+ i386.cc
+
+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)
+all: config.h
+ $(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .c .cc .o .obj .y
+am--refresh:
+ @:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign '; \
+ cd $(srcdir) && $(AUTOMAKE) --foreign \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --foreign Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ echo ' $(SHELL) ./config.status'; \
+ $(SHELL) ./config.status;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ $(SHELL) ./config.status --recheck
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(srcdir) && $(AUTOCONF)
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+
+config.h: stamp-h1
+ @if test ! -f $@; then \
+ rm -f stamp-h1; \
+ $(MAKE) stamp-h1; \
+ else :; fi
+
+stamp-h1: $(srcdir)/config.in $(top_builddir)/config.status
+ @rm -f stamp-h1
+ cd $(top_builddir) && $(SHELL) ./config.status config.h
+$(srcdir)/config.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_srcdir) && $(AUTOHEADER)
+ rm -f stamp-h1
+ touch $@
+
+distclean-hdr:
+ -rm -f config.h stamp-h1
+po/Makefile.in: $(top_builddir)/config.status $(top_srcdir)/po/Make-in
+ cd $(top_builddir) && $(SHELL) ./config.status $@
+
+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)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/archive.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/defstd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dirsearch.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dynobj.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fileread.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gold-threads.Po@am__quote@
+@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)/merge.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@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/readsyms.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reloc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resolve.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stringpool.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/symtab.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/target-select.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/workqueue.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/yyscript.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.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) '$<'`
+
+.y.c:
+ $(YACCCOMPILE) $<
+ if test -f y.tab.h; then \
+ to=`echo "$*_H" | sed \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' \
+ -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'`; \
+ sed -e "/^#/!b" -e "s/Y_TAB_H/$$to/g" -e "s|y\.tab\.h|$*.h|" \
+ y.tab.h >$*.ht; \
+ rm -f y.tab.h; \
+ if cmp -s $*.ht $*.h; then \
+ rm -f $*.ht ;\
+ else \
+ mv $*.ht $*.h; \
+ fi; \
+ fi
+ if test -f y.output; then \
+ mv y.output $*.output; \
+ fi
+ sed '/^#/ s|y\.tab\.c|$@|' y.tab.c >$@t && mv $@t $@
+ rm -f y.tab.c
+uninstall-info-am:
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+ @failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+ @failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ rev=''; for subdir in $$list; do \
+ if test "$$subdir" = "."; then :; else \
+ rev="$$subdir $$rev"; \
+ fi; \
+ done; \
+ rev="$$rev ."; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+ctags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+ done
+
+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: tags-recursive $(HEADERS) $(SOURCES) config.in $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS) config.in $(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: ctags-recursive $(HEADERS) $(SOURCES) config.in $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) config.in $(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
+
+distdir: $(DISTFILES)
+ $(am__remove_distdir)
+ mkdir $(distdir)
+ $(mkdir_p) $(distdir)/.. $(distdir)/../bfd $(distdir)/../config $(distdir)/po
+ @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
+ list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -d "$(distdir)/$$subdir" \
+ || $(mkdir_p) "$(distdir)/$$subdir" \
+ || exit 1; \
+ distdir=`$(am__cd) $(distdir) && pwd`; \
+ top_distdir=`$(am__cd) $(top_distdir) && pwd`; \
+ (cd $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$top_distdir" \
+ distdir="$$distdir/$$subdir" \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+ -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \
+ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \
+ || chmod -R a+r $(distdir)
+dist-gzip: distdir
+ tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+ $(am__remove_distdir)
+
+dist-bzip2: distdir
+ tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2
+ $(am__remove_distdir)
+
+dist-tarZ: distdir
+ tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
+ $(am__remove_distdir)
+
+dist-shar: distdir
+ shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
+ $(am__remove_distdir)
+
+dist-zip: distdir
+ -rm -f $(distdir).zip
+ zip -rq $(distdir).zip $(distdir)
+ $(am__remove_distdir)
+
+dist dist-all: distdir
+ tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+ $(am__remove_distdir)
+
+# This target untars the dist file and tries a VPATH configuration. Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+ case '$(DIST_ARCHIVES)' in \
+ *.tar.gz*) \
+ GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\
+ *.tar.bz2*) \
+ bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\
+ *.tar.Z*) \
+ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
+ *.shar.gz*) \
+ GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\
+ *.zip*) \
+ unzip $(distdir).zip ;;\
+ esac
+ chmod -R a-w $(distdir); chmod a+w $(distdir)
+ mkdir $(distdir)/_build
+ mkdir $(distdir)/_inst
+ chmod a-w $(distdir)
+ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
+ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
+ && cd $(distdir)/_build \
+ && ../configure --srcdir=.. --prefix="$$dc_install_base" \
+ $(DISTCHECK_CONFIGURE_FLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) dvi \
+ && $(MAKE) $(AM_MAKEFLAGS) check \
+ && $(MAKE) $(AM_MAKEFLAGS) install \
+ && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+ && $(MAKE) $(AM_MAKEFLAGS) uninstall \
+ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
+ distuninstallcheck \
+ && chmod -R a-w "$$dc_install_base" \
+ && ({ \
+ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
+ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
+ } || { rm -rf "$$dc_destdir"; exit 1; }) \
+ && rm -rf "$$dc_destdir" \
+ && $(MAKE) $(AM_MAKEFLAGS) dist \
+ && rm -rf $(DIST_ARCHIVES) \
+ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck
+ $(am__remove_distdir)
+ @(echo "$(distdir) archives ready for distribution: "; \
+ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
+ sed -e '1{h;s/./=/g;p;x;}' -e '$${p;x;}'
+distuninstallcheck:
+ @cd $(distuninstallcheck_dir) \
+ && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \
+ || { echo "ERROR: files left after uninstall:" ; \
+ if test -n "$(DESTDIR)"; then \
+ echo " (check DESTDIR support)"; \
+ fi ; \
+ $(distuninstallcheck_listfiles) ; \
+ exit 1; } >&2
+distcleancheck: distclean
+ @if test '$(srcdir)' = . ; then \
+ echo "ERROR: distcleancheck can only run from a VPATH build" ; \
+ exit 1 ; \
+ fi
+ @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
+ || { echo "ERROR: files left in build directory after distclean:" ; \
+ $(distcleancheck_listfiles) ; \
+ exit 1; } >&2
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(LIBRARIES) $(PROGRAMS) config.h
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+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."
+ -rm -f yyscript.c
+ -rm -f yyscript.h
+clean: clean-recursive
+
+clean-am: clean-generic clean-noinstLIBRARIES clean-noinstPROGRAMS \
+ mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-hdr distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-data-local
+
+install-exec-am: install-exec-local
+
+install-info: install-info-recursive
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -rf $(top_srcdir)/autom4te.cache
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+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-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
+
+
+# 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)
+ $(mkinstalldirs) $(DESTDIR)$(bindir) $(DESTDIR)$(tooldir)/bin
+ n=`echo ld | sed '$(transform)'; \
+ $(INSTALL_PROGRAM) ld-new$(EXEEXT) $(DESTDIR)$(bindir)/$${n}$(EXEEXT); \
+ if test "$(bindir)" != "$(tooldir)/bin"; then \
+ rm -f $(DESTDIR)$(tooldir)/bin/ld$(EXEEXT); \
+ ln $(DESTDIR)$(bindir)/$${n}$(EXEEXT) $(DESTDIR)$(tooldir)/bin/ld$(EXEEXT) >/dev/null 2>/dev/null \
+ || $(INSTALL_PROGRAM) ld-new$(EXEEXT) $(DESTDIR)$(tooldir)/bin/ld$(EXEEXT); \
+ fi
+
+# 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/README b/gold/README
new file mode 100644
index 000000000000..aa318f2daa8e
--- /dev/null
+++ b/gold/README
@@ -0,0 +1,18 @@
+gold is an ELF linker. It is intended to have complete support for
+ELF and to run as fast as possible on modern systems.
+
+It is written in C++. It is (intended to be) a GNU program, and
+therefore follows the GNU formatting standards as modified for C++.
+Source documents in order of precedence:
+ http://www.gnu.org/prep/standards/
+ http://gcc.gnu.org/onlinedocs/libstdc++/17_intro/C++STYLE
+ http://www.zembu.com/eng/procs/c++style.html
+
+The linker is intended to have complete support for cross-compilation,
+which still supporting the normal case of native linking as fast as
+possible. This makes the code more complex.
+
+Many functions are actually templates whose parameter is the ELF file
+class (e.g., 32 bits or 64 bits). The code is the same, but we don't
+want to pay the execution time cost of always using 64-bit integers if
+the target is 32 bits.
diff --git a/gold/aclocal.m4 b/gold/aclocal.m4
new file mode 100644
index 000000000000..4438a34308e6
--- /dev/null
+++ b/gold/aclocal.m4
@@ -0,0 +1,877 @@
+# generated automatically by aclocal 1.9.6 -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+# 2005 Free Software Foundation, Inc.
+# This file 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.
+
+# Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
+#
+# This file 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.
+
+# AM_AUTOMAKE_VERSION(VERSION)
+# ----------------------------
+# Automake X.Y traces this macro to ensure aclocal.m4 has been
+# generated from the m4 files accompanying Automake X.Y.
+AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version="1.9"])
+
+# AM_SET_CURRENT_AUTOMAKE_VERSION
+# -------------------------------
+# Call AM_AUTOMAKE_VERSION so it can be traced.
+# This function is AC_REQUIREd by AC_INIT_AUTOMAKE.
+AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+ [AM_AUTOMAKE_VERSION([1.9.6])])
+
+# AM_AUX_DIR_EXPAND -*- Autoconf -*-
+
+# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
+#
+# This file 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.
+
+# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
+# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to
+# `$srcdir', `$srcdir/..', or `$srcdir/../..'.
+#
+# Of course, Automake must honor this variable whenever it calls a
+# tool from the auxiliary directory. The problem is that $srcdir (and
+# therefore $ac_aux_dir as well) can be either absolute or relative,
+# depending on how configure is run. This is pretty annoying, since
+# it makes $ac_aux_dir quite unusable in subdirectories: in the top
+# source directory, any form will work fine, but in subdirectories a
+# relative path needs to be adjusted first.
+#
+# $ac_aux_dir/missing
+# fails when called from a subdirectory if $ac_aux_dir is relative
+# $top_srcdir/$ac_aux_dir/missing
+# fails if $ac_aux_dir is absolute,
+# fails when called from a subdirectory in a VPATH build with
+# a relative $ac_aux_dir
+#
+# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
+# are both prefixed by $srcdir. In an in-source build this is usually
+# harmless because $srcdir is `.', but things will broke when you
+# start a VPATH build or use an absolute $srcdir.
+#
+# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
+# iff we strip the leading $srcdir from $ac_aux_dir. That would be:
+# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
+# and then we would define $MISSING as
+# MISSING="\${SHELL} $am_aux_dir/missing"
+# This will work as long as MISSING is not called from configure, because
+# unfortunately $(top_srcdir) has no meaning in configure.
+# However there are other variables, like CC, which are often used in
+# configure, and could therefore not use this "fixed" $ac_aux_dir.
+#
+# Another solution, used here, is to always expand $ac_aux_dir to an
+# absolute PATH. The drawback is that using absolute paths prevent a
+# configured tree to be moved without reconfiguration.
+
+AC_DEFUN([AM_AUX_DIR_EXPAND],
+[dnl Rely on autoconf to set up CDPATH properly.
+AC_PREREQ([2.50])dnl
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+])
+
+# AM_CONDITIONAL -*- Autoconf -*-
+
+# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005
+# Free Software Foundation, Inc.
+#
+# This file 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.
+
+# serial 7
+
+# AM_CONDITIONAL(NAME, SHELL-CONDITION)
+# -------------------------------------
+# Define a conditional.
+AC_DEFUN([AM_CONDITIONAL],
+[AC_PREREQ(2.52)dnl
+ ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])],
+ [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
+AC_SUBST([$1_TRUE])
+AC_SUBST([$1_FALSE])
+if $2; then
+ $1_TRUE=
+ $1_FALSE='#'
+else
+ $1_TRUE='#'
+ $1_FALSE=
+fi
+AC_CONFIG_COMMANDS_PRE(
+[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
+ AC_MSG_ERROR([[conditional "$1" was never defined.
+Usually this means the macro was only invoked conditionally.]])
+fi])])
+
+
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
+# Free Software Foundation, Inc.
+#
+# This file 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.
+
+# serial 8
+
+# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be
+# written in clear, in which case automake, when reading aclocal.m4,
+# will think it sees a *use*, and therefore will trigger all it's
+# C support machinery. Also note that it means that autoscan, seeing
+# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
+
+
+# _AM_DEPENDENCIES(NAME)
+# ----------------------
+# See how the compiler implements dependency checking.
+# NAME is "CC", "CXX", "GCJ", or "OBJC".
+# We try a few techniques and use that to set a single cache variable.
+#
+# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
+# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
+# dependency, and given that the user is not expected to run this macro,
+# just rely on AC_PROG_CC.
+AC_DEFUN([_AM_DEPENDENCIES],
+[AC_REQUIRE([AM_SET_DEPDIR])dnl
+AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
+AC_REQUIRE([AM_MAKE_INCLUDE])dnl
+AC_REQUIRE([AM_DEP_TRACK])dnl
+
+ifelse([$1], CC, [depcc="$CC" am_compiler_list=],
+ [$1], CXX, [depcc="$CXX" am_compiler_list=],
+ [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
+ [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'],
+ [depcc="$$1" am_compiler_list=])
+
+AC_CACHE_CHECK([dependency style of $depcc],
+ [am_cv_$1_dependencies_compiler_type],
+[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named `D' -- because `-MD' means `put the output
+ # in D'.
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_$1_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
+ fi
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+ # Solaris 8's {/usr,}/bin/sh.
+ touch sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ case $depmode in
+ nosideeffect)
+ # after this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ none) break ;;
+ esac
+ # We check with `-c' and `-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle `-M -o', and we need to detect this.
+ if depmode=$depmode \
+ source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_$1_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_$1_dependencies_compiler_type=none
+fi
+])
+AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
+AM_CONDITIONAL([am__fastdep$1], [
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_$1_dependencies_compiler_type" = gcc3])
+])
+
+
+# AM_SET_DEPDIR
+# -------------
+# Choose a directory name for dependency files.
+# This macro is AC_REQUIREd in _AM_DEPENDENCIES
+AC_DEFUN([AM_SET_DEPDIR],
+[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
+])
+
+
+# AM_DEP_TRACK
+# ------------
+AC_DEFUN([AM_DEP_TRACK],
+[AC_ARG_ENABLE(dependency-tracking,
+[ --disable-dependency-tracking speeds up one-time build
+ --enable-dependency-tracking do not reject slow dependency extractors])
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+fi
+AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
+AC_SUBST([AMDEPBACKSLASH])
+])
+
+# Generate code to set up dependency tracking. -*- Autoconf -*-
+
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
+# Free Software Foundation, Inc.
+#
+# This file 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.
+
+#serial 3
+
+# _AM_OUTPUT_DEPENDENCY_COMMANDS
+# ------------------------------
+AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
+[for mf in $CONFIG_FILES; do
+ # Strip MF so we end up with the name of the file.
+ mf=`echo "$mf" | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile or not.
+ # We used to match only the files named `Makefile.in', but
+ # some people rename them; so instead we look at the file content.
+ # Grep'ing the first line is not enough: some people post-process
+ # each Makefile.in and add a new line on top of each file to say so.
+ # So let's grep whole file.
+ if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then
+ dirpart=`AS_DIRNAME("$mf")`
+ else
+ continue
+ fi
+ # Extract the definition of DEPDIR, am__include, and am__quote
+ # from the Makefile without running `make'.
+ DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+ test -z "$DEPDIR" && continue
+ am__include=`sed -n 's/^am__include = //p' < "$mf"`
+ test -z "am__include" && continue
+ am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+ # When using ansi2knr, U may be empty or an underscore; expand it
+ U=`sed -n 's/^U = //p' < "$mf"`
+ # Find all dependency output files, they are included files with
+ # $(DEPDIR) in their names. We invoke sed twice because it is the
+ # simplest approach to changing $(DEPDIR) to its actual value in the
+ # expansion.
+ for file in `sed -n "
+ s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
+ # Make sure the directory exists.
+ test -f "$dirpart/$file" && continue
+ fdir=`AS_DIRNAME(["$file"])`
+ AS_MKDIR_P([$dirpart/$fdir])
+ # echo "creating $dirpart/$file"
+ echo '# dummy' > "$dirpart/$file"
+ done
+done
+])# _AM_OUTPUT_DEPENDENCY_COMMANDS
+
+
+# AM_OUTPUT_DEPENDENCY_COMMANDS
+# -----------------------------
+# This macro should only be invoked once -- use via AC_REQUIRE.
+#
+# This code is only required when automatic dependency tracking
+# is enabled. FIXME. This creates each `.P' file that we will
+# need in order to bootstrap the dependency handling code.
+AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
+[AC_CONFIG_COMMANDS([depfiles],
+ [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
+ [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
+])
+
+# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005
+# Free Software Foundation, Inc.
+#
+# This file 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.
+
+# serial 8
+
+# AM_CONFIG_HEADER is obsolete. It has been replaced by AC_CONFIG_HEADERS.
+AU_DEFUN([AM_CONFIG_HEADER], [AC_CONFIG_HEADERS($@)])
+
+# Do all the work for Automake. -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+# Free Software Foundation, Inc.
+#
+# This file 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.
+
+# serial 12
+
+# This macro actually does too much. Some checks are only needed if
+# your package does certain things. But this isn't really a big deal.
+
+# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
+# AM_INIT_AUTOMAKE([OPTIONS])
+# -----------------------------------------------
+# The call with PACKAGE and VERSION arguments is the old style
+# call (pre autoconf-2.50), which is being phased out. PACKAGE
+# and VERSION should now be passed to AC_INIT and removed from
+# the call to AM_INIT_AUTOMAKE.
+# We support both call styles for the transition. After
+# the next Automake release, Autoconf can make the AC_INIT
+# arguments mandatory, and then we can depend on a new Autoconf
+# release and drop the old call support.
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[AC_PREREQ([2.58])dnl
+dnl Autoconf wants to disallow AM_ names. We explicitly allow
+dnl the ones we care about.
+m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
+AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
+AC_REQUIRE([AC_PROG_INSTALL])dnl
+# test to see if srcdir already configured
+if test "`cd $srcdir && pwd`" != "`pwd`" &&
+ test -f $srcdir/config.status; then
+ AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+ if (cygpath --version) >/dev/null 2>/dev/null; then
+ CYGPATH_W='cygpath -w'
+ else
+ CYGPATH_W=echo
+ fi
+fi
+AC_SUBST([CYGPATH_W])
+
+# Define the identity of the package.
+dnl Distinguish between old-style and new-style calls.
+m4_ifval([$2],
+[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
+ AC_SUBST([PACKAGE], [$1])dnl
+ AC_SUBST([VERSION], [$2])],
+[_AM_SET_OPTIONS([$1])dnl
+ AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
+ AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
+
+_AM_IF_OPTION([no-define],,
+[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
+ AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl
+
+# Some tools Automake needs.
+AC_REQUIRE([AM_SANITY_CHECK])dnl
+AC_REQUIRE([AC_ARG_PROGRAM])dnl
+AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version})
+AM_MISSING_PROG(AUTOCONF, autoconf)
+AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version})
+AM_MISSING_PROG(AUTOHEADER, autoheader)
+AM_MISSING_PROG(MAKEINFO, makeinfo)
+AM_PROG_INSTALL_SH
+AM_PROG_INSTALL_STRIP
+AC_REQUIRE([AM_PROG_MKDIR_P])dnl
+# We need awk for the "check" target. The system "awk" is bad on
+# some platforms.
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
+ [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
+ [_AM_PROG_TAR([v7])])])
+_AM_IF_OPTION([no-dependencies],,
+[AC_PROVIDE_IFELSE([AC_PROG_CC],
+ [_AM_DEPENDENCIES(CC)],
+ [define([AC_PROG_CC],
+ defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_CXX],
+ [_AM_DEPENDENCIES(CXX)],
+ [define([AC_PROG_CXX],
+ defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl
+])
+])
+
+
+# When config.status generates a header, we must update the stamp-h file.
+# This file resides in the same directory as the config header
+# that is generated. The stamp files are numbered to have different names.
+
+# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
+# loop where config.status creates the headers, so we can generate
+# our stamp files there.
+AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
+[# Compute $1's index in $config_headers.
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+ case $_am_header in
+ $1 | $1:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+done
+echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count])
+
+# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
+#
+# This file 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.
+
+# AM_PROG_INSTALL_SH
+# ------------------
+# Define $install_sh.
+AC_DEFUN([AM_PROG_INSTALL_SH],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+install_sh=${install_sh-"$am_aux_dir/install-sh"}
+AC_SUBST(install_sh)])
+
+# Add --enable-maintainer-mode option to configure. -*- Autoconf -*-
+# From Jim Meyering
+
+# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005
+# Free Software Foundation, Inc.
+#
+# This file 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.
+
+# serial 4
+
+AC_DEFUN([AM_MAINTAINER_MODE],
+[AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
+ dnl maintainer-mode is disabled by default
+ AC_ARG_ENABLE(maintainer-mode,
+[ --enable-maintainer-mode enable make rules and dependencies not useful
+ (and sometimes confusing) to the casual installer],
+ USE_MAINTAINER_MODE=$enableval,
+ USE_MAINTAINER_MODE=no)
+ AC_MSG_RESULT([$USE_MAINTAINER_MODE])
+ AM_CONDITIONAL(MAINTAINER_MODE, [test $USE_MAINTAINER_MODE = yes])
+ MAINT=$MAINTAINER_MODE_TRUE
+ AC_SUBST(MAINT)dnl
+]
+)
+
+AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE])
+
+# Check to see how 'make' treats includes. -*- Autoconf -*-
+
+# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
+#
+# This file 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.
+
+# serial 3
+
+# AM_MAKE_INCLUDE()
+# -----------------
+# Check to see how make treats includes.
+AC_DEFUN([AM_MAKE_INCLUDE],
+[am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+ @echo done
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+AC_MSG_CHECKING([for style of include used by $am_make])
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# We grep out `Entering directory' and `Leaving directory'
+# messages which can occur if `w' ends up in MAKEFLAGS.
+# In particular we don't look at `^make:' because GNU make might
+# be invoked under some other name (usually "gmake"), in which
+# case it prints its new name instead of `make'.
+if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then
+ am__include=include
+ am__quote=
+ _am_result=GNU
+fi
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+ echo '.include "confinc"' > confmf
+ if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then
+ am__include=.include
+ am__quote="\""
+ _am_result=BSD
+ fi
+fi
+AC_SUBST([am__include])
+AC_SUBST([am__quote])
+AC_MSG_RESULT([$_am_result])
+rm -f confinc confmf
+])
+
+# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
+
+# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2005
+# Free Software Foundation, Inc.
+#
+# This file 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.
+
+# serial 4
+
+# AM_MISSING_PROG(NAME, PROGRAM)
+# ------------------------------
+AC_DEFUN([AM_MISSING_PROG],
+[AC_REQUIRE([AM_MISSING_HAS_RUN])
+$1=${$1-"${am_missing_run}$2"}
+AC_SUBST($1)])
+
+
+# AM_MISSING_HAS_RUN
+# ------------------
+# Define MISSING if not defined so far and test if it supports --run.
+# If it does, set am_missing_run to use it, otherwise, to nothing.
+AC_DEFUN([AM_MISSING_HAS_RUN],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing"
+# Use eval to expand $SHELL
+if eval "$MISSING --run true"; then
+ am_missing_run="$MISSING --run "
+else
+ am_missing_run=
+ AC_MSG_WARN([`missing' script is too old or missing])
+fi
+])
+
+# Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+#
+# This file 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.
+
+# AM_PROG_MKDIR_P
+# ---------------
+# Check whether `mkdir -p' is supported, fallback to mkinstalldirs otherwise.
+#
+# Automake 1.8 used `mkdir -m 0755 -p --' to ensure that directories
+# created by `make install' are always world readable, even if the
+# installer happens to have an overly restrictive umask (e.g. 077).
+# This was a mistake. There are at least two reasons why we must not
+# use `-m 0755':
+# - it causes special bits like SGID to be ignored,
+# - it may be too restrictive (some setups expect 775 directories).
+#
+# Do not use -m 0755 and let people choose whatever they expect by
+# setting umask.
+#
+# We cannot accept any implementation of `mkdir' that recognizes `-p'.
+# Some implementations (such as Solaris 8's) are not thread-safe: if a
+# parallel make tries to run `mkdir -p a/b' and `mkdir -p a/c'
+# concurrently, both version can detect that a/ is missing, but only
+# one can create it and the other will error out. Consequently we
+# restrict ourselves to GNU make (using the --version option ensures
+# this.)
+AC_DEFUN([AM_PROG_MKDIR_P],
+[if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then
+ # We used to keeping the `.' as first argument, in order to
+ # allow $(mkdir_p) to be used without argument. As in
+ # $(mkdir_p) $(somedir)
+ # where $(somedir) is conditionally defined. However this is wrong
+ # for two reasons:
+ # 1. if the package is installed by a user who cannot write `.'
+ # make install will fail,
+ # 2. the above comment should most certainly read
+ # $(mkdir_p) $(DESTDIR)$(somedir)
+ # so it does not work when $(somedir) is undefined and
+ # $(DESTDIR) is not.
+ # To support the latter case, we have to write
+ # test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir),
+ # so the `.' trick is pointless.
+ mkdir_p='mkdir -p --'
+else
+ # On NextStep and OpenStep, the `mkdir' command does not
+ # recognize any option. It will interpret all options as
+ # directories to create, and then abort because `.' already
+ # exists.
+ for d in ./-p ./--version;
+ do
+ test -d $d && rmdir $d
+ done
+ # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists.
+ if test -f "$ac_aux_dir/mkinstalldirs"; then
+ mkdir_p='$(mkinstalldirs)'
+ else
+ mkdir_p='$(install_sh) -d'
+ fi
+fi
+AC_SUBST([mkdir_p])])
+
+# Helper functions for option handling. -*- Autoconf -*-
+
+# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
+#
+# This file 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.
+
+# serial 3
+
+# _AM_MANGLE_OPTION(NAME)
+# -----------------------
+AC_DEFUN([_AM_MANGLE_OPTION],
+[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
+
+# _AM_SET_OPTION(NAME)
+# ------------------------------
+# Set option NAME. Presently that only means defining a flag for this option.
+AC_DEFUN([_AM_SET_OPTION],
+[m4_define(_AM_MANGLE_OPTION([$1]), 1)])
+
+# _AM_SET_OPTIONS(OPTIONS)
+# ----------------------------------
+# OPTIONS is a space-separated list of Automake options.
+AC_DEFUN([_AM_SET_OPTIONS],
+[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
+
+# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
+# -------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+AC_DEFUN([_AM_IF_OPTION],
+[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
+
+# Check to make sure that the build environment is sane. -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005
+# Free Software Foundation, Inc.
+#
+# This file 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.
+
+# serial 4
+
+# AM_SANITY_CHECK
+# ---------------
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Just in case
+sleep 1
+echo timestamp > conftest.file
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null`
+ if test "$[*]" = "X"; then
+ # -L didn't work.
+ set X `ls -t $srcdir/configure conftest.file`
+ fi
+ rm -f conftest.file
+ if test "$[*]" != "X $srcdir/configure conftest.file" \
+ && test "$[*]" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
+alias in your environment])
+ fi
+
+ test "$[2]" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+AC_MSG_RESULT(yes)])
+
+# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
+#
+# This file 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.
+
+# AM_PROG_INSTALL_STRIP
+# ---------------------
+# One issue with vendor `install' (even GNU) is that you can't
+# specify the program used to strip binaries. This is especially
+# annoying in cross-compiling environments, where the build's strip
+# is unlikely to handle the host's binaries.
+# Fortunately install-sh will honor a STRIPPROG variable, so we
+# always use install-sh in `make install-strip', and initialize
+# STRIPPROG with the value of the STRIP variable (set by the user).
+AC_DEFUN([AM_PROG_INSTALL_STRIP],
+[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+# Installed binaries are usually stripped using `strip' when the user
+# run `make install-strip'. However `strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the `STRIP' environment variable to overrule this program.
+dnl Don't test for $cross_compiling = yes, because it might be `maybe'.
+if test "$cross_compiling" != no; then
+ AC_CHECK_TOOL([STRIP], [strip], :)
+fi
+INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s"
+AC_SUBST([INSTALL_STRIP_PROGRAM])])
+
+# Check how to create a tarball. -*- Autoconf -*-
+
+# Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+#
+# This file 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.
+
+# serial 2
+
+# _AM_PROG_TAR(FORMAT)
+# --------------------
+# Check how to create a tarball in format FORMAT.
+# FORMAT should be one of `v7', `ustar', or `pax'.
+#
+# Substitute a variable $(am__tar) that is a command
+# writing to stdout a FORMAT-tarball containing the directory
+# $tardir.
+# tardir=directory && $(am__tar) > result.tar
+#
+# Substitute a variable $(am__untar) that extract such
+# a tarball read from stdin.
+# $(am__untar) < result.tar
+AC_DEFUN([_AM_PROG_TAR],
+[# Always define AMTAR for backward compatibility.
+AM_MISSING_PROG([AMTAR], [tar])
+m4_if([$1], [v7],
+ [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'],
+ [m4_case([$1], [ustar],, [pax],,
+ [m4_fatal([Unknown tar format])])
+AC_MSG_CHECKING([how to create a $1 tar archive])
+# Loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
+_am_tools=${am_cv_prog_tar_$1-$_am_tools}
+# Do not fold the above two line into one, because Tru64 sh and
+# Solaris sh will not grok spaces in the rhs of `-'.
+for _am_tool in $_am_tools
+do
+ case $_am_tool in
+ gnutar)
+ for _am_tar in tar gnutar gtar;
+ do
+ AM_RUN_LOG([$_am_tar --version]) && break
+ done
+ am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
+ am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
+ am__untar="$_am_tar -xf -"
+ ;;
+ plaintar)
+ # Must skip GNU tar: if it does not support --format= it doesn't create
+ # ustar tarball either.
+ (tar --version) >/dev/null 2>&1 && continue
+ am__tar='tar chf - "$$tardir"'
+ am__tar_='tar chf - "$tardir"'
+ am__untar='tar xf -'
+ ;;
+ pax)
+ am__tar='pax -L -x $1 -w "$$tardir"'
+ am__tar_='pax -L -x $1 -w "$tardir"'
+ am__untar='pax -r'
+ ;;
+ cpio)
+ am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
+ am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
+ am__untar='cpio -i -H $1 -d'
+ ;;
+ none)
+ am__tar=false
+ am__tar_=false
+ am__untar=false
+ ;;
+ esac
+
+ # If the value was cached, stop now. We just wanted to have am__tar
+ # and am__untar set.
+ test -n "${am_cv_prog_tar_$1}" && break
+
+ # tar/untar a dummy directory, and stop if the command works
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ echo GrepMe > conftest.dir/file
+ AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
+ rm -rf conftest.dir
+ if test -s conftest.tar; then
+ AM_RUN_LOG([$am__untar <conftest.tar])
+ grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+ fi
+done
+rm -rf conftest.dir
+
+AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
+AC_MSG_RESULT([$am_cv_prog_tar_$1])])
+AC_SUBST([am__tar])
+AC_SUBST([am__untar])
+]) # _AM_PROG_TAR
+
+m4_include([../config/depstand.m4])
+m4_include([../config/lead-dot.m4])
+m4_include([../config/progtest.m4])
+m4_include([../config/po.m4])
+m4_include([../config/nls.m4])
+m4_include([../config/gettext-sister.m4])
+m4_include([../bfd/warning.m4])
diff --git a/gold/archive.cc b/gold/archive.cc
new file mode 100644
index 000000000000..d0854036a672
--- /dev/null
+++ b/gold/archive.cc
@@ -0,0 +1,368 @@
+// archive.cc -- archive support for gold
+
+#include "gold.h"
+
+#include <cerrno>
+#include <cstring>
+#include <climits>
+#include <vector>
+
+#include "elfcpp.h"
+#include "fileread.h"
+#include "readsyms.h"
+#include "symtab.h"
+#include "object.h"
+#include "archive.h"
+
+namespace gold
+{
+
+// The header of an entry in the archive. This is all readable text,
+// padded with spaces where necesary. If the contents of an archive
+// are all text file, the entire archive is readable.
+
+struct Archive::Archive_header
+{
+ // The entry name.
+ char ar_name[16];
+ // The file modification time.
+ char ar_date[12];
+ // The user's UID in decimal.
+ char ar_uid[6];
+ // The user's GID in decimal.
+ char ar_gid[6];
+ // The file mode in octal.
+ char ar_mode[8];
+ // The file size in decimal.
+ char ar_size[10];
+ // The final magic code.
+ char ar_fmag[2];
+};
+
+// Archive methods.
+
+const char Archive::armag[sarmag] =
+{
+ '!', '<', 'a', 'r', 'c', 'h', '>', '\n'
+};
+
+const char Archive::arfmag[2] = { '`', '\n' };
+
+// Set up the archive: read the symbol map and the extended name
+// table.
+
+void
+Archive::setup()
+{
+ // The first member of the archive should be the symbol table.
+ std::string armap_name;
+ off_t armap_size = this->read_header(sarmag, &armap_name);
+ if (!armap_name.empty())
+ {
+ fprintf(stderr, _("%s: %s: no archive symbol table (run ranlib)\n"),
+ program_name, this->name().c_str());
+ gold_exit(false);
+ }
+
+ // Read in the entire armap.
+ const unsigned char* p = this->get_view(sarmag + sizeof(Archive_header),
+ armap_size);
+
+ // Numbers in the armap are always big-endian.
+ const elfcpp::Elf_Word* pword = reinterpret_cast<const elfcpp::Elf_Word*>(p);
+ unsigned int nsyms = elfcpp::Swap<32, true>::readval(pword);
+ ++pword;
+
+ // Note that the addition is in units of sizeof(elfcpp::Elf_Word).
+ const char* pnames = reinterpret_cast<const char*>(pword + nsyms);
+
+ this->armap_.resize(nsyms);
+
+ for (unsigned int i = 0; i < nsyms; ++i)
+ {
+ this->armap_[i].name = pnames;
+ this->armap_[i].offset = elfcpp::Swap<32, true>::readval(pword);
+ pnames += strlen(pnames) + 1;
+ ++pword;
+ }
+
+ if (reinterpret_cast<const unsigned char*>(pnames) - p > armap_size)
+ {
+ fprintf(stderr, _("%s: %s: bad archive symbol table names\n"),
+ program_name, this->name().c_str());
+ gold_exit(false);
+ }
+
+ // See if there is an extended name table.
+ off_t off = sarmag + sizeof(Archive_header) + armap_size;
+ if ((off & 1) != 0)
+ ++off;
+ std::string xname;
+ off_t extended_size = this->read_header(off, &xname);
+ if (xname == "/")
+ {
+ p = this->get_view(off + sizeof(Archive_header), extended_size);
+ const char* px = reinterpret_cast<const char*>(p);
+ this->extended_names_.assign(px, extended_size);
+ }
+
+ // This array keeps track of which symbols are for archive elements
+ // which we have already included in the link.
+ this->seen_.resize(nsyms);
+
+ // Opening the file locked it. Unlock it now.
+ this->input_file_->file().unlock();
+}
+
+// Read the header of an archive member at OFF. Fail if something
+// goes wrong. Return the size of the member. Set *PNAME to the name
+// of the member.
+
+off_t
+Archive::read_header(off_t off, std::string* pname)
+{
+ const unsigned char* p = this->get_view(off, sizeof(Archive_header));
+ const Archive_header* hdr = reinterpret_cast<const Archive_header*>(p);
+
+ if (memcmp(hdr->ar_fmag, arfmag, sizeof arfmag) != 0)
+ {
+ fprintf(stderr, _("%s; %s: malformed archive header at %ld\n"),
+ program_name, this->name().c_str(),
+ static_cast<long>(off));
+ gold_exit(false);
+ }
+
+ const int size_string_size = sizeof hdr->ar_size;
+ char size_string[size_string_size + 1];
+ memcpy(size_string, hdr->ar_size, size_string_size);
+ char* ps = size_string + size_string_size;
+ while (ps[-1] == ' ')
+ --ps;
+ *ps = '\0';
+
+ errno = 0;
+ char* end;
+ off_t member_size = strtol(size_string, &end, 10);
+ if (*end != '\0'
+ || member_size < 0
+ || (member_size == LONG_MAX && errno == ERANGE))
+ {
+ fprintf(stderr, _("%s: %s: malformed archive header size at %ld\n"),
+ program_name, this->name().c_str(),
+ static_cast<long>(off));
+ gold_exit(false);
+ }
+
+ if (hdr->ar_name[0] != '/')
+ {
+ const char* name_end = strchr(hdr->ar_name, '/');
+ if (name_end == NULL
+ || name_end - hdr->ar_name >= static_cast<int>(sizeof hdr->ar_name))
+ {
+ fprintf(stderr, _("%s: %s: malformed archive header name at %ld\n"),
+ program_name, this->name().c_str(),
+ static_cast<long>(off));
+ gold_exit(false);
+ }
+ pname->assign(hdr->ar_name, name_end - hdr->ar_name);
+ }
+ else if (hdr->ar_name[1] == ' ')
+ {
+ // This is the symbol table.
+ pname->clear();
+ }
+ else if (hdr->ar_name[1] == '/')
+ {
+ // This is the extended name table.
+ pname->assign(1, '/');
+ }
+ else
+ {
+ errno = 0;
+ long x = strtol(hdr->ar_name + 1, &end, 10);
+ if (*end != ' '
+ || x < 0
+ || (x == LONG_MAX && errno == ERANGE)
+ || static_cast<size_t>(x) >= this->extended_names_.size())
+ {
+ fprintf(stderr, _("%s: %s: bad extended name index at %ld\n"),
+ program_name, this->name().c_str(),
+ static_cast<long>(off));
+ gold_exit(false);
+ }
+
+ const char* name = this->extended_names_.data() + x;
+ const char* name_end = strchr(name, '/');
+ if (static_cast<size_t>(name_end - name) > this->extended_names_.size()
+ || name_end[1] != '\n')
+ {
+ fprintf(stderr, _("%s: %s: bad extended name entry at header %ld\n"),
+ program_name, this->name().c_str(),
+ static_cast<long>(off));
+ gold_exit(false);
+ }
+ pname->assign(name, name_end - name);
+ }
+
+ return member_size;
+}
+
+// Select members from the archive and add them to the link. We walk
+// through the elements in the archive map, and look each one up in
+// the symbol table. If it exists as a strong undefined symbol, we
+// pull in the corresponding element. We have to do this in a loop,
+// since pulling in one element may create new undefined symbols which
+// may be satisfied by other objects in the archive.
+
+void
+Archive::add_symbols(const General_options& options, Symbol_table* symtab,
+ Layout* layout, Input_objects* input_objects)
+{
+ const size_t armap_size = this->armap_.size();
+
+ bool added_new_object;
+ do
+ {
+ added_new_object = false;
+ off_t last = -1;
+ for (size_t i = 0; i < armap_size; ++i)
+ {
+ if (this->seen_[i])
+ continue;
+ if (this->armap_[i].offset == last)
+ {
+ this->seen_[i] = true;
+ continue;
+ }
+
+ Symbol* sym = symtab->lookup(this->armap_[i].name);
+ if (sym == NULL)
+ continue;
+ else if (!sym->is_undefined())
+ {
+ this->seen_[i] = true;
+ continue;
+ }
+ else if (sym->binding() == elfcpp::STB_WEAK)
+ continue;
+
+ // We want to include this object in the link.
+ last = this->armap_[i].offset;
+ this->include_member(options, symtab, layout, input_objects, last);
+ this->seen_[i] = true;
+ added_new_object = true;
+ }
+ }
+ while (added_new_object);
+}
+
+// Include an archive member in the link. OFF is the file offset of
+// the member header.
+
+void
+Archive::include_member(const General_options& options, Symbol_table* symtab,
+ Layout* layout, Input_objects* input_objects,
+ off_t off)
+{
+ std::string n;
+ this->read_header(off, &n);
+
+ size_t memoff = off + sizeof(Archive_header);
+
+ // Read enough of the file to pick up the entire ELF header.
+ int ehdr_size = elfcpp::Elf_sizes<64>::ehdr_size;
+ off_t bytes;
+ const unsigned char* p = this->input_file_->file().get_view(memoff,
+ ehdr_size,
+ &bytes);
+ if (bytes < 4)
+ {
+ fprintf(stderr, _("%s: %s: member at %ld is not an ELF object"),
+ program_name, this->name().c_str(),
+ static_cast<long>(off));
+ gold_exit(false);
+ }
+
+ static unsigned char elfmagic[4] =
+ {
+ elfcpp::ELFMAG0, elfcpp::ELFMAG1,
+ elfcpp::ELFMAG2, elfcpp::ELFMAG3
+ };
+ if (memcmp(p, elfmagic, 4) != 0)
+ {
+ fprintf(stderr, _("%s: %s: member at %ld is not an ELF object"),
+ program_name, this->name().c_str(),
+ static_cast<long>(off));
+ gold_exit(false);
+ }
+
+ Object* obj = make_elf_object((std::string(this->input_file_->filename())
+ + "(" + n + ")"),
+ this->input_file_, memoff, p, bytes);
+
+ input_objects->add_object(obj);
+
+ Read_symbols_data sd;
+ obj->read_symbols(&sd);
+ obj->layout(options, symtab, layout, &sd);
+ obj->add_symbols(symtab, &sd);
+}
+
+// Add_archive_symbols methods.
+
+Add_archive_symbols::~Add_archive_symbols()
+{
+ if (this->this_blocker_ != NULL)
+ delete this->this_blocker_;
+ // next_blocker_ is deleted by the task associated with the next
+ // input file.
+}
+
+// Return whether we can add the archive symbols. We are blocked by
+// this_blocker_. We block next_blocker_. We also lock the file.
+
+Task::Is_runnable_type
+Add_archive_symbols::is_runnable(Workqueue*)
+{
+ if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
+ return IS_BLOCKED;
+ return IS_RUNNABLE;
+}
+
+class Add_archive_symbols::Add_archive_symbols_locker : public Task_locker
+{
+ public:
+ Add_archive_symbols_locker(Task_token& token, Workqueue* workqueue,
+ File_read& file)
+ : blocker_(token, workqueue), filelock_(file)
+ { }
+
+ private:
+ Task_locker_block blocker_;
+ Task_locker_obj<File_read> filelock_;
+};
+
+Task_locker*
+Add_archive_symbols::locks(Workqueue* workqueue)
+{
+ return new Add_archive_symbols_locker(*this->next_blocker_,
+ workqueue,
+ this->archive_->file());
+}
+
+void
+Add_archive_symbols::run(Workqueue*)
+{
+ this->archive_->add_symbols(this->options_, this->symtab_, this->layout_,
+ this->input_objects_);
+
+ if (this->input_group_ != NULL)
+ this->input_group_->add_archive(this->archive_);
+ else
+ {
+ // We no longer need to know about this archive.
+ delete this->archive_;
+ }
+}
+
+} // End namespace gold.
diff --git a/gold/archive.h b/gold/archive.h
new file mode 100644
index 000000000000..193a9e2de820
--- /dev/null
+++ b/gold/archive.h
@@ -0,0 +1,162 @@
+// archive.h -- archive support for gold -*- C++ -*-
+
+#ifndef GOLD_ARCHIVE_H
+#define GOLD_ARCHIVE_H
+
+#include <string>
+#include <vector>
+
+#include "workqueue.h"
+
+namespace gold
+{
+
+class General_options;
+class Input_file;
+class Input_objects;
+class Input_group;
+class Layout;
+class Symbol_table;
+
+// This class represents an archive--generally a libNAME.a file.
+// Archives have a symbol table and a list of objects.
+
+class Archive
+{
+ public:
+ Archive(const std::string& name, Input_file* input_file)
+ : name_(name), input_file_(input_file), armap_(), extended_names_()
+ { }
+
+ // The length of the magic string at the start of an archive.
+ static const int sarmag = 8;
+
+ // The magic string at the start of an archive.
+ static const char armag[sarmag];
+
+ // The string expected at the end of an archive member header.
+ static const char arfmag[2];
+
+ // The name of the object.
+ const std::string&
+ name() const
+ { return this->name_; }
+
+ // Set up the archive: read the symbol map.
+ void
+ setup();
+
+ // Get a reference to the underlying file.
+ File_read&
+ file()
+ { return this->input_file_->file(); }
+
+ // Lock the underlying file.
+ void
+ lock()
+ { this->input_file_->file().lock(); }
+
+ // Unlock the underlying file.
+ void
+ unlock()
+ { this->input_file_->file().unlock(); }
+
+ // Return whether the underlying file is locked.
+ bool
+ is_locked() const
+ { return this->input_file_->file().is_locked(); }
+
+ // Select members from the archive as needed and add them to the
+ // link.
+ void
+ add_symbols(const General_options&, Symbol_table*, Layout*, Input_objects*);
+
+ private:
+ Archive(const Archive&);
+ Archive& operator=(const Archive&);
+
+ struct Archive_header;
+
+ // Get a view into the underlying file.
+ const unsigned char*
+ get_view(off_t start, off_t size)
+ { return this->input_file_->file().get_view(start, size); }
+
+ // Read an archive member header at OFF. Return the size of the
+ // member, and set *PNAME to the name.
+ off_t
+ read_header(off_t off, std::string* pname);
+
+ // Include an archive member in the link.
+ void
+ include_member(const General_options&, Symbol_table*, Layout*,
+ Input_objects*, off_t off);
+
+ // An entry in the archive map of symbols to object files.
+ struct Armap_entry
+ {
+ // The symbol name.
+ const char* name;
+ // The offset to the file.
+ off_t offset;
+ };
+
+ // Name of object as printed to user.
+ std::string name_;
+ // For reading the file.
+ Input_file* input_file_;
+ // The archive map.
+ std::vector<Armap_entry> armap_;
+ // The extended name table.
+ std::string extended_names_;
+ // Track which symbols in the archive map are for elements which
+ // have already been included in the link.
+ std::vector<bool> seen_;
+};
+
+// This class is used to read an archive and pick out the desired
+// elements and add them to the link.
+
+class Add_archive_symbols : public Task
+{
+ public:
+ Add_archive_symbols(const General_options& options, Symbol_table* symtab,
+ Layout* layout, Input_objects* input_objects,
+ Archive* archive, Input_group* input_group,
+ Task_token* this_blocker,
+ Task_token* next_blocker)
+ : options_(options), symtab_(symtab), layout_(layout),
+ input_objects_(input_objects), archive_(archive),
+ input_group_(input_group), this_blocker_(this_blocker),
+ next_blocker_(next_blocker)
+ { }
+
+ ~Add_archive_symbols();
+
+ // The standard Task methods.
+
+ Is_runnable_type
+ is_runnable(Workqueue*);
+
+ Task_locker*
+ locks(Workqueue*);
+
+ void
+ run(Workqueue*);
+
+ private:
+ class Add_archive_symbols_locker;
+
+ const General_options& options_;
+ Symbol_table* symtab_;
+ Layout* layout_;
+ Input_objects* input_objects_;
+ Archive* archive_;
+ Input_group* input_group_;
+ Task_token* this_blocker_;
+ Task_token* next_blocker_;
+};
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_ARCHIVE_H)
diff --git a/gold/common.cc b/gold/common.cc
new file mode 100644
index 000000000000..e83219c901f0
--- /dev/null
+++ b/gold/common.cc
@@ -0,0 +1,210 @@
+// common.cc -- handle common symbols for gold
+
+#include "gold.h"
+
+#include <algorithm>
+
+#include "workqueue.h"
+#include "layout.h"
+#include "output.h"
+#include "symtab.h"
+#include "common.h"
+
+namespace gold
+{
+
+// Allocate_commons_task methods.
+
+// This task allocates the common symbols. We need a lock on the
+// symbol table.
+
+Task::Is_runnable_type
+Allocate_commons_task::is_runnable(Workqueue*)
+{
+ if (!this->symtab_lock_->is_writable())
+ return IS_LOCKED;
+ return IS_RUNNABLE;
+}
+
+// Return the locks we hold: one on the symbol table, and one blocker.
+
+class Allocate_commons_task::Allocate_commons_locker : public Task_locker
+{
+ public:
+ Allocate_commons_locker(Task_token& symtab_lock, Task* task,
+ Task_token& blocker, Workqueue* workqueue)
+ : symtab_locker_(symtab_lock, task),
+ blocker_(blocker, workqueue)
+ { }
+
+ private:
+ Task_locker_write symtab_locker_;
+ Task_locker_block blocker_;
+};
+
+Task_locker*
+Allocate_commons_task::locks(Workqueue* workqueue)
+{
+ return new Allocate_commons_locker(*this->symtab_lock_, this,
+ *this->blocker_, workqueue);
+}
+
+// Allocate the common symbols.
+
+void
+Allocate_commons_task::run(Workqueue*)
+{
+ this->symtab_->allocate_commons(this->options_, this->layout_);
+}
+
+// This class is used to sort the common symbol by size. We put the
+// larger common symbols first.
+
+template<int size>
+class Sort_commons
+{
+ public:
+ Sort_commons(const Symbol_table* symtab)
+ : symtab_(symtab)
+ { }
+
+ bool operator()(const Symbol* a, const Symbol* b) const;
+
+ private:
+ const Symbol_table* symtab_;
+};
+
+template<int size>
+bool
+Sort_commons<size>::operator()(const Symbol* pa, const Symbol* pb) const
+{
+ if (pa == NULL)
+ return false;
+ if (pb == NULL)
+ return true;
+
+ const Symbol_table* symtab = this->symtab_;
+ const Sized_symbol<size>* psa;
+ psa = symtab->get_sized_symbol SELECT_SIZE_NAME(size) (pa
+ SELECT_SIZE(size));
+ const Sized_symbol<size>* psb;
+ psb = symtab->get_sized_symbol SELECT_SIZE_NAME(size) (pb
+ SELECT_SIZE(size));
+
+ typename Sized_symbol<size>::Size_type sa = psa->symsize();
+ typename Sized_symbol<size>::Size_type sb = psb->symsize();
+ if (sa < sb)
+ return false;
+ else if (sb > sa)
+ return true;
+
+ // When the symbols are the same size, we sort them by alignment.
+ typename Sized_symbol<size>::Value_type va = psa->value();
+ typename Sized_symbol<size>::Value_type vb = psb->value();
+ if (va < vb)
+ return false;
+ else if (vb > va)
+ return true;
+
+ // Otherwise we stabilize the sort by sorting by name.
+ return strcmp(psa->name(), psb->name()) < 0;
+}
+
+// Allocate the common symbols.
+
+void
+Symbol_table::allocate_commons(const General_options& options, Layout* layout)
+{
+ if (this->get_size() == 32)
+ this->do_allocate_commons<32>(options, layout);
+ else if (this->get_size() == 64)
+ this->do_allocate_commons<64>(options, layout);
+ else
+ gold_unreachable();
+}
+
+// Allocated the common symbols, sized version.
+
+template<int size>
+void
+Symbol_table::do_allocate_commons(const General_options&,
+ Layout* layout)
+{
+ typedef typename Sized_symbol<size>::Value_type Value_type;
+ typedef typename Sized_symbol<size>::Size_type Size_type;
+
+ // We've kept a list of all the common symbols. But the symbol may
+ // have been resolved to a defined symbol by now. And it may be a
+ // forwarder. First remove all non-common symbols.
+ bool any = false;
+ uint64_t addralign = 0;
+ for (Commons_type::iterator p = this->commons_.begin();
+ p != this->commons_.end();
+ ++p)
+ {
+ Symbol* sym = *p;
+ if (sym->is_forwarder())
+ {
+ sym = this->resolve_forwards(sym);
+ *p = sym;
+ }
+ if (!sym->is_common())
+ *p = NULL;
+ else
+ {
+ any = true;
+ Sized_symbol<size>* ssym;
+ ssym = this->get_sized_symbol SELECT_SIZE_NAME(size) (
+ sym
+ SELECT_SIZE(size));
+ if (ssym->value() > addralign)
+ addralign = ssym->value();
+ }
+ }
+ if (!any)
+ return;
+
+ // Sort the common symbols by size, so that they pack better into
+ // memory.
+ std::sort(this->commons_.begin(), this->commons_.end(),
+ Sort_commons<size>(this));
+
+ // Place them in a newly allocated .bss section.
+
+ Output_data_space *poc = new Output_data_space(addralign);
+
+ layout->add_output_section_data(".bss", elfcpp::SHT_NOBITS,
+ elfcpp::SHF_WRITE | elfcpp::SHF_ALLOC,
+ poc);
+
+ // Allocate them all.
+
+ off_t off = 0;
+ for (Commons_type::iterator p = this->commons_.begin();
+ p != this->commons_.end();
+ ++p)
+ {
+ Symbol* sym = *p;
+ if (sym == NULL)
+ break;
+
+ Sized_symbol<size>* ssym;
+ ssym = this->get_sized_symbol SELECT_SIZE_NAME(size) (sym
+ SELECT_SIZE(size));
+
+ off = align_address(off, ssym->value());
+
+ Size_type symsize = ssym->symsize();
+ ssym->init(ssym->name(), poc, off, symsize, ssym->type(),
+ ssym->binding(), ssym->visibility(), ssym->nonvis(),
+ false);
+
+ off += symsize;
+ }
+
+ poc->set_space_size(off);
+
+ this->commons_.clear();
+}
+
+} // End namespace gold.
diff --git a/gold/common.h b/gold/common.h
new file mode 100644
index 000000000000..75237a6a5c52
--- /dev/null
+++ b/gold/common.h
@@ -0,0 +1,49 @@
+// common.h -- handle common symbols for gold -*- C++ -*-
+
+#ifndef GOLD_COMMON_H
+#define GOLD_COMMON_H
+
+#include "workqueue.h"
+
+namespace gold
+{
+
+class General_options;
+class Symbol_table;
+
+// This task is used to allocate the common symbols.
+
+class Allocate_commons_task : public Task
+{
+ public:
+ Allocate_commons_task(const General_options& options, Symbol_table* symtab,
+ Layout* layout, Task_token* symtab_lock,
+ Task_token* blocker)
+ : options_(options), symtab_(symtab), layout_(layout),
+ symtab_lock_(symtab_lock), blocker_(blocker)
+ { }
+
+ // The standard Task methods.
+
+ Is_runnable_type
+ is_runnable(Workqueue*);
+
+ Task_locker*
+ locks(Workqueue*);
+
+ void
+ run(Workqueue*);
+
+ private:
+ class Allocate_commons_locker;
+
+ const General_options& options_;
+ Symbol_table* symtab_;
+ Layout* layout_;
+ Task_token* symtab_lock_;
+ Task_token* blocker_;
+};
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_COMMON_H)
diff --git a/gold/config.in b/gold/config.in
new file mode 100644
index 000000000000..1d40c66bac36
--- /dev/null
+++ b/gold/config.in
@@ -0,0 +1,75 @@
+/* config.in. Generated from configure.ac by autoheader. */
+
+/* Define to 1 if translation of program messages to the user's native
+ language is requested. */
+#undef ENABLE_NLS
+
+/* Define to 1 if you have the <ext/hash_map> header file. */
+#undef HAVE_EXT_HASH_MAP
+
+/* Define to 1 if you have the <ext/hash_set> header file. */
+#undef HAVE_EXT_HASH_SET
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Whether the C++ compiler can call a template member with no arguments */
+#undef HAVE_MEMBER_TEMPLATE_SPECIFICATIONS
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <tr1/unordered_map> header file. */
+#undef HAVE_TR1_UNORDERED_MAP
+
+/* Define to 1 if you have the <tr1/unordered_set> header file. */
+#undef HAVE_TR1_UNORDERED_SET
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Version number of package */
+#undef VERSION
+
+/* Define to 1 if your processor stores words with the most significant byte
+ first (like Motorola and SPARC, unlike Intel and VAX). */
+#undef WORDS_BIGENDIAN
diff --git a/gold/configure b/gold/configure
new file mode 100755
index 000000000000..5d69594d33fb
--- /dev/null
+++ b/gold/configure
@@ -0,0 +1,6715 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.59.
+#
+# Copyright (C) 2003 Free Software Foundation, Inc.
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## --------------------- ##
+## M4sh Initialization. ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
+fi
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+ LC_TELEPHONE LC_TIME
+do
+ if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+ eval $as_var=C; export $as_var
+ else
+ $as_unset $as_var
+ fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)$' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+ /^X\/\(\/\/\)$/{ s//\1/; q; }
+ /^X\/\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+
+
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" || {
+ # Find who we are. Look in the path if we contain no path at all
+ # relative or not.
+ case $0 in
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+
+ ;;
+ esac
+ # We did not find ourselves, most probably we were run as `sh COMMAND'
+ # in which case we are not to be found in the path.
+ if test "x$as_myself" = x; then
+ as_myself=$0
+ fi
+ if test ! -f "$as_myself"; then
+ { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2
+ { (exit 1); exit 1; }; }
+ fi
+ case $CONFIG_SHELL in
+ '')
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for as_base in sh bash ksh sh5; do
+ case $as_dir in
+ /*)
+ if ("$as_dir/$as_base" -c '
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then
+ $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+ $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+ CONFIG_SHELL=$as_dir/$as_base
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+ fi;;
+ esac
+ done
+done
+;;
+ esac
+
+ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+ # uniformly replaced by the line number. The first 'sed' inserts a
+ # line-number line before each line; the second 'sed' does the real
+ # work. The second script uses 'N' to pair each line-number line
+ # with the numbered line, and appends trailing '-' during
+ # substitution so that $LINENO is not a special case at line end.
+ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+ # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-)
+ sed '=' <$as_myself |
+ sed '
+ N
+ s,$,-,
+ : loop
+ s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+ t loop
+ s,-$,,
+ s,^['$as_cr_digits']*\n,,
+ ' >$as_me.lineno &&
+ chmod +x $as_me.lineno ||
+ { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+ { (exit 1); exit 1; }; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensible to this).
+ . ./$as_me.lineno
+ # Exit status is that of the last command.
+ exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+ *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T=' ' ;;
+ *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+ *) ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ # We could just check for DJGPP; but this test a) works b) is more generic
+ # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+ if test -f conf$$.exe; then
+ # Don't use ln at all; we don't have any links
+ as_ln_s='cp -p'
+ else
+ as_ln_s='ln -s'
+ fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p=:
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_executable_p="test -f"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" $as_nl"
+
+# CDPATH.
+$as_unset CDPATH
+
+
+# Name of the host.
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+exec 6>&1
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_config_libobj_dir=.
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Maximum number of lines to put in a shell here document.
+# This variable seems obsolete. It should probably be removed, and
+# only ac_max_sed_lines should be used.
+: ${ac_max_here_lines=38}
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+
+ac_unique_file="gold.cc"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# if HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#if HAVE_STRING_H
+# if !STDC_HEADERS && HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+# include <stdint.h>
+# endif
+#endif
+#if HAVE_UNISTD_H
+# 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 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.
+ac_init_help=
+ac_init_version=false
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+ac_prev=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'`
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_option in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ eval "enable_$ac_feature=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_$ac_feature='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_$ac_package='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package | sed 's/-/_/g'`
+ eval "with_$ac_package=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) { echo "$as_me: error: unrecognized option: $ac_option
+Try \`$0 --help' for more information." >&2
+ { (exit 1); exit 1; }; }
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+ { (exit 1); exit 1; }; }
+ ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`
+ eval "$ac_envvar='$ac_optarg'"
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ { echo "$as_me: error: missing argument to $ac_option" >&2
+ { (exit 1); exit 1; }; }
+fi
+
+# Be sure to have absolute paths.
+for ac_var in exec_prefix prefix
+do
+ eval ac_val=$`echo $ac_var`
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* | NONE | '' ) ;;
+ *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# Be sure to have absolute paths.
+for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \
+ localstatedir libdir includedir oldincludedir infodir mandir
+do
+ eval ac_val=$`echo $ac_var`
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) ;;
+ *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+ If a cross compiler is detected then cross compile mode will be used." >&2
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_confdir=`(dirname "$0") 2>/dev/null ||
+$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$0" : 'X\(//\)[^/]' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$0" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2
+ { (exit 1); exit 1; }; }
+ else
+ { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
+ { (exit 1); exit 1; }; }
+ fi
+fi
+(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null ||
+ { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2
+ { (exit 1); exit 1; }; }
+srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'`
+ac_env_build_alias_set=${build_alias+set}
+ac_env_build_alias_value=$build_alias
+ac_cv_env_build_alias_set=${build_alias+set}
+ac_cv_env_build_alias_value=$build_alias
+ac_env_host_alias_set=${host_alias+set}
+ac_env_host_alias_value=$host_alias
+ac_cv_env_host_alias_set=${host_alias+set}
+ac_cv_env_host_alias_value=$host_alias
+ac_env_target_alias_set=${target_alias+set}
+ac_env_target_alias_value=$target_alias
+ac_cv_env_target_alias_set=${target_alias+set}
+ac_cv_env_target_alias_value=$target_alias
+ac_env_CC_set=${CC+set}
+ac_env_CC_value=$CC
+ac_cv_env_CC_set=${CC+set}
+ac_cv_env_CC_value=$CC
+ac_env_CFLAGS_set=${CFLAGS+set}
+ac_env_CFLAGS_value=$CFLAGS
+ac_cv_env_CFLAGS_set=${CFLAGS+set}
+ac_cv_env_CFLAGS_value=$CFLAGS
+ac_env_LDFLAGS_set=${LDFLAGS+set}
+ac_env_LDFLAGS_value=$LDFLAGS
+ac_cv_env_LDFLAGS_set=${LDFLAGS+set}
+ac_cv_env_LDFLAGS_value=$LDFLAGS
+ac_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_env_CPPFLAGS_value=$CPPFLAGS
+ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_cv_env_CPPFLAGS_value=$CPPFLAGS
+ac_env_CXX_set=${CXX+set}
+ac_env_CXX_value=$CXX
+ac_cv_env_CXX_set=${CXX+set}
+ac_cv_env_CXX_value=$CXX
+ac_env_CXXFLAGS_set=${CXXFLAGS+set}
+ac_env_CXXFLAGS_value=$CXXFLAGS
+ac_cv_env_CXXFLAGS_set=${CXXFLAGS+set}
+ac_cv_env_CXXFLAGS_value=$CXXFLAGS
+ac_env_CXXCPP_set=${CXXCPP+set}
+ac_env_CXXCPP_value=$CXXCPP
+ac_cv_env_CXXCPP_set=${CXXCPP+set}
+ac_cv_env_CXXCPP_value=$CXXCPP
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+_ACEOF
+
+ cat <<_ACEOF
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --infodir=DIR info documentation [PREFIX/info]
+ --mandir=DIR man documentation [PREFIX/man]
+_ACEOF
+
+ cat <<\_ACEOF
+
+Program names:
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM run sed PROGRAM on installed program names
+
+System types:
+ --build=BUILD configure for building on BUILD [guessed]
+ --host=HOST cross-compile to build programs to run on HOST [BUILD]
+ --target=TARGET configure for building compilers for TARGET [HOST]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Features:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --disable-dependency-tracking speeds up one-time build
+ --enable-dependency-tracking do not reject slow dependency extractors
+ --disable-nls do not use Native Language Support
+ --enable-werror treat compile warnings as errors
+ --enable-build-warnings enable build-time compiler warnings
+ --enable-maintainer-mode enable make rules and dependencies not useful
+ (and sometimes confusing) to the casual installer
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ CPPFLAGS C/C++ preprocessor flags, e.g. -I<include dir> if you have
+ headers in a nonstandard directory <include dir>
+ CXX C++ compiler command
+ CXXFLAGS C++ compiler flags
+ CXXCPP C++ preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+_ACEOF
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ ac_popdir=`pwd`
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d $ac_dir || continue
+ ac_builddir=.
+
+if test "$ac_dir" != .; then
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+ ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+ .) # No --srcdir option. We are building in place.
+ ac_srcdir=.
+ if test -z "$ac_top_builddir"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+
+# Do not use `cd foo && pwd` to compute absolute paths, because
+# the directories may not exist.
+case `pwd` in
+.) ac_abs_builddir="$ac_dir";;
+*)
+ case "$ac_dir" in
+ .) ac_abs_builddir=`pwd`;;
+ [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";;
+ *) ac_abs_builddir=`pwd`/"$ac_dir";;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_builddir=${ac_top_builddir}.;;
+*)
+ case ${ac_top_builddir}. in
+ .) ac_abs_top_builddir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;;
+ *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_srcdir=$ac_srcdir;;
+*)
+ case $ac_srcdir in
+ .) ac_abs_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;;
+ *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_srcdir=$ac_top_srcdir;;
+*)
+ case $ac_top_srcdir in
+ .) ac_abs_top_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;;
+ *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;;
+ esac;;
+esac
+
+ cd $ac_dir
+ # Check for guested configure; otherwise get Cygnus style configure.
+ if test -f $ac_srcdir/configure.gnu; then
+ echo
+ $SHELL $ac_srcdir/configure.gnu --help=recursive
+ elif test -f $ac_srcdir/configure; then
+ echo
+ $SHELL $ac_srcdir/configure --help=recursive
+ elif test -f $ac_srcdir/configure.ac ||
+ test -f $ac_srcdir/configure.in; then
+ echo
+ $ac_configure --help
+ else
+ echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi
+ cd $ac_popdir
+ done
+fi
+
+test -n "$ac_init_help" && exit 0
+if $ac_init_version; then
+ cat <<\_ACEOF
+
+Copyright (C) 2003 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit 0
+fi
+exec 5>config.log
+cat >&5 <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.59. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+hostinfo = `(hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ echo "PATH: $as_dir"
+done
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_sep=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+ ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;;
+ 2)
+ ac_configure_args1="$ac_configure_args1 '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'"
+ # Get rid of the leading space.
+ ac_sep=" "
+ ;;
+ esac
+ done
+done
+$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; }
+$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; }
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Be sure not to use single quotes in there, as some shells,
+# such as our DU 5.0 friend, will then `close' the trap.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ cat <<\_ASBOX
+## ---------------- ##
+## Cache variables. ##
+## ---------------- ##
+_ASBOX
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+{
+ (set) 2>&1 |
+ case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ sed -n \
+ "s/'"'"'/'"'"'\\\\'"'"''"'"'/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p"
+ ;;
+ *)
+ sed -n \
+ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+ ;;
+ esac;
+}
+ echo
+
+ cat <<\_ASBOX
+## ----------------- ##
+## Output variables. ##
+## ----------------- ##
+_ASBOX
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=$`echo $ac_var`
+ echo "$ac_var='"'"'$ac_val'"'"'"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ cat <<\_ASBOX
+## ------------- ##
+## Output files. ##
+## ------------- ##
+_ASBOX
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=$`echo $ac_var`
+ echo "$ac_var='"'"'$ac_val'"'"'"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ cat <<\_ASBOX
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+_ASBOX
+ echo
+ sed "/^$/d" confdefs.h | sort
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ echo "$as_me: caught signal $ac_signal"
+ echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core &&
+ rm -rf conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+ ' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo >confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5
+echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special
+ # files actually), so we avoid doing that.
+ if test -f "$cache_file"; then
+ { echo "$as_me:$LINENO: loading cache $cache_file" >&5
+echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . $cache_file;;
+ *) . ./$cache_file;;
+ esac
+ fi
+else
+ { echo "$as_me:$LINENO: creating cache $cache_file" >&5
+echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in `(set) 2>&1 |
+ sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val="\$ac_cv_env_${ac_var}_value"
+ eval ac_new_val="\$ac_env_${ac_var}_value"
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
+echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ { echo "$as_me:$LINENO: former value: $ac_old_val" >&5
+echo "$as_me: former value: $ac_old_val" >&2;}
+ { echo "$as_me:$LINENO: current value: $ac_new_val" >&5
+echo "$as_me: current value: $ac_new_val" >&2;}
+ ac_cache_corrupted=:
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+ ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
+echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
+echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+ if test -f $ac_dir/install-sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f $ac_dir/install.sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ elif test -f $ac_dir/shtool; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/shtool install -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5
+echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"
+ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure.
+
+# Make sure we can run config.sub.
+$ac_config_sub sun4 >/dev/null 2>&1 ||
+ { { echo "$as_me:$LINENO: error: cannot run $ac_config_sub" >&5
+echo "$as_me: error: cannot run $ac_config_sub" >&2;}
+ { (exit 1); exit 1; }; }
+
+echo "$as_me:$LINENO: checking build system type" >&5
+echo $ECHO_N "checking build system type... $ECHO_C" >&6
+if test "${ac_cv_build+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_build_alias=$build_alias
+test -z "$ac_cv_build_alias" &&
+ ac_cv_build_alias=`$ac_config_guess`
+test -z "$ac_cv_build_alias" &&
+ { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5
+echo "$as_me: error: cannot guess build type; you must specify one" >&2;}
+ { (exit 1); exit 1; }; }
+ac_cv_build=`$ac_config_sub $ac_cv_build_alias` ||
+ { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_build_alias failed" >&5
+echo "$as_me: error: $ac_config_sub $ac_cv_build_alias failed" >&2;}
+ { (exit 1); exit 1; }; }
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_build" >&5
+echo "${ECHO_T}$ac_cv_build" >&6
+build=$ac_cv_build
+build_cpu=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+build_vendor=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+build_os=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+
+echo "$as_me:$LINENO: checking host system type" >&5
+echo $ECHO_N "checking host system type... $ECHO_C" >&6
+if test "${ac_cv_host+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_host_alias=$host_alias
+test -z "$ac_cv_host_alias" &&
+ ac_cv_host_alias=$ac_cv_build_alias
+ac_cv_host=`$ac_config_sub $ac_cv_host_alias` ||
+ { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_host_alias failed" >&5
+echo "$as_me: error: $ac_config_sub $ac_cv_host_alias failed" >&2;}
+ { (exit 1); exit 1; }; }
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_host" >&5
+echo "${ECHO_T}$ac_cv_host" >&6
+host=$ac_cv_host
+host_cpu=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+
+echo "$as_me:$LINENO: checking target system type" >&5
+echo $ECHO_N "checking target system type... $ECHO_C" >&6
+if test "${ac_cv_target+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_target_alias=$target_alias
+test "x$ac_cv_target_alias" = "x" &&
+ ac_cv_target_alias=$ac_cv_host_alias
+ac_cv_target=`$ac_config_sub $ac_cv_target_alias` ||
+ { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_target_alias failed" >&5
+echo "$as_me: error: $ac_config_sub $ac_cv_target_alias failed" >&2;}
+ { (exit 1); exit 1; }; }
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_target" >&5
+echo "${ECHO_T}$ac_cv_target" >&6
+target=$ac_cv_target
+target_cpu=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+target_vendor=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+target_os=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+
+# The aliases save the names the user supplied, while $host etc.
+# will get canonicalized.
+test -n "$target_alias" &&
+ test "$program_prefix$program_suffix$program_transform_name" = \
+ NONENONEs,x,x, &&
+ program_prefix=${target_alias}-
+
+am__api_version="1.9"
+# 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:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5
+echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in
+ ./ | .// | /cC/* | \
+ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+ ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \
+ /usr/ucb/* ) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+ if test $ac_prog = install &&
+ grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ elif test $ac_prog = install &&
+ grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # program-specific install script used by HP pwplus--don't use.
+ :
+ else
+ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+ break 3
+ fi
+ fi
+ done
+ done
+ ;;
+esac
+done
+
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL=$ac_cv_path_install
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL=$ac_install_sh
+ fi
+fi
+echo "$as_me:$LINENO: result: $INSTALL" >&5
+echo "${ECHO_T}$INSTALL" >&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo "$as_me:$LINENO: checking whether build environment is sane" >&5
+echo $ECHO_N "checking whether build environment is sane... $ECHO_C" >&6
+# Just in case
+sleep 1
+echo timestamp > conftest.file
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null`
+ if test "$*" = "X"; then
+ # -L didn't work.
+ set X `ls -t $srcdir/configure conftest.file`
+ fi
+ rm -f conftest.file
+ if test "$*" != "X $srcdir/configure conftest.file" \
+ && test "$*" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ { { echo "$as_me:$LINENO: error: ls -t appears to fail. Make sure there is not a broken
+alias in your environment" >&5
+echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken
+alias in your environment" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+
+ test "$2" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ { { echo "$as_me:$LINENO: error: newly created file is older than distributed files!
+Check your system clock" >&5
+echo "$as_me: error: newly created file is older than distributed files!
+Check your system clock" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+test "$program_prefix" != NONE &&
+ program_transform_name="s,^,$program_prefix,;$program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+ program_transform_name="s,\$,$program_suffix,;$program_transform_name"
+# Double any \ or $. echo might interpret backslashes.
+# By default was `s,x,x', remove it if useless.
+cat <<\_ACEOF >conftest.sed
+s/[\\$]/&&/g;s/;s,x,x,$//
+_ACEOF
+program_transform_name=`echo $program_transform_name | sed -f conftest.sed`
+rm conftest.sed
+
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+
+test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing"
+# Use eval to expand $SHELL
+if eval "$MISSING --run true"; then
+ am_missing_run="$MISSING --run "
+else
+ am_missing_run=
+ { echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5
+echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;}
+fi
+
+if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then
+ # We used to keeping the `.' as first argument, in order to
+ # allow $(mkdir_p) to be used without argument. As in
+ # $(mkdir_p) $(somedir)
+ # where $(somedir) is conditionally defined. However this is wrong
+ # for two reasons:
+ # 1. if the package is installed by a user who cannot write `.'
+ # make install will fail,
+ # 2. the above comment should most certainly read
+ # $(mkdir_p) $(DESTDIR)$(somedir)
+ # so it does not work when $(somedir) is undefined and
+ # $(DESTDIR) is not.
+ # To support the latter case, we have to write
+ # test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir),
+ # so the `.' trick is pointless.
+ mkdir_p='mkdir -p --'
+else
+ # On NextStep and OpenStep, the `mkdir' command does not
+ # recognize any option. It will interpret all options as
+ # directories to create, and then abort because `.' already
+ # exists.
+ for d in ./-p ./--version;
+ do
+ test -d $d && rmdir $d
+ done
+ # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists.
+ if test -f "$ac_aux_dir/mkinstalldirs"; then
+ mkdir_p='$(mkinstalldirs)'
+ else
+ mkdir_p='$(install_sh) -d'
+ fi
+fi
+
+for ac_prog in gawk mawk nawk awk
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; 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_AWK+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$AWK"; then
+ ac_cv_prog_AWK="$AWK" # 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_AWK="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+ echo "$as_me:$LINENO: result: $AWK" >&5
+echo "${ECHO_T}$AWK" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$AWK" && break
+done
+
+echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,:./+-,___p_,'`
+if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.make <<\_ACEOF
+all:
+ @echo 'ac_maketemp="$(MAKE)"'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+ eval ac_cv_prog_make_${ac_make}_set=yes
+else
+ eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftest.make
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ SET_MAKE=
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+ am__leading_dot=.
+else
+ am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+
+# test to see if srcdir already configured
+if test "`cd $srcdir && pwd`" != "`pwd`" &&
+ test -f $srcdir/config.status; then
+ { { echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5
+echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+ if (cygpath --version) >/dev/null 2>/dev/null; then
+ CYGPATH_W='cygpath -w'
+ else
+ CYGPATH_W=echo
+ fi
+fi
+
+
+# Define the identity of the package.
+ PACKAGE=gold
+ VERSION=0.1
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE "$PACKAGE"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define VERSION "$VERSION"
+_ACEOF
+
+# Some tools Automake needs.
+
+ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"}
+
+
+AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"}
+
+
+AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"}
+
+
+AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}
+
+
+MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
+
+install_sh=${install_sh-"$am_aux_dir/install-sh"}
+
+# Installed binaries are usually stripped using `strip' when the user
+# run `make install-strip'. However `strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the `STRIP' environment variable to overrule this program.
+if test "$cross_compiling" != no; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; 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_STRIP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$STRIP"; then
+ ac_cv_prog_STRIP="$STRIP" # 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_STRIP="${ac_tool_prefix}strip"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+ echo "$as_me:$LINENO: result: $STRIP" >&5
+echo "${ECHO_T}$STRIP" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+ ac_ct_STRIP=$STRIP
+ # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; 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_STRIP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_STRIP"; then
+ ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # 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_STRIP="strip"
+ 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_STRIP" && ac_cv_prog_ac_ct_STRIP=":"
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+ echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5
+echo "${ECHO_T}$ac_ct_STRIP" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ STRIP=$ac_ct_STRIP
+else
+ STRIP="$ac_cv_prog_STRIP"
+fi
+
+fi
+INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s"
+
+# We need awk for the "check" target. The system "awk" is bad on
+# some platforms.
+# Always define AMTAR for backward compatibility.
+
+AMTAR=${AMTAR-"${am_missing_run}tar"}
+
+am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'
+
+
+
+
+
+
+ ac_config_headers="$ac_config_headers config.h:config.in"
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; 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_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # 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_CC="${ac_tool_prefix}gcc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; 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_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # 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_CC="gcc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ CC=$ac_ct_CC
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; 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_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # 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_CC="${ac_tool_prefix}cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; 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_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # 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_CC="cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ CC=$ac_ct_CC
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; 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_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+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
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; 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_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # 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_CC="$ac_tool_prefix$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; 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_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # 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_CC="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$ac_ct_CC" && break
+done
+
+ CC=$ac_ct_CC
+fi
+
+fi
+
+
+test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&5
+echo "$as_me: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+
+# Provide some information about the compiler.
+echo "$as_me:$LINENO:" \
+ "checking for C compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
+ (eval $ac_compiler --version </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5
+ (eval $ac_compiler -v </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5
+ (eval $ac_compiler -V </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+echo "$as_me:$LINENO: checking for C compiler default output file name" >&5
+echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6
+ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5
+ (eval $ac_link_default) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # Find the output, starting from the most likely. This scheme is
+# not robust to junk in `.', hence go to wildcards (a.*) only as a last
+# resort.
+
+# Be careful to initialize this variable, since it used to be cached.
+# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile.
+ac_cv_exeext=
+# b.out is created by i960 compilers.
+for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj )
+ ;;
+ conftest.$ac_ext )
+ # This is the source file.
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ # FIXME: I believe we export ac_cv_exeext for Libtool,
+ # but it would be cool to find out if it's true. Does anybody
+ # maintain Libtool? --akim.
+ export ac_cv_exeext
+ break;;
+ * )
+ break;;
+ esac
+done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: C compiler cannot create executables
+See \`config.log' for more details." >&5
+echo "$as_me: error: C compiler cannot create executables
+See \`config.log' for more details." >&2;}
+ { (exit 77); exit 77; }; }
+fi
+
+ac_exeext=$ac_cv_exeext
+echo "$as_me:$LINENO: result: $ac_file" >&5
+echo "${ECHO_T}$ac_file" >&6
+
+# Check the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:$LINENO: checking whether the C compiler works" >&5
+echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6
+# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
+# If not cross compiling, check that we can run a simple program.
+if test "$cross_compiling" != yes; then
+ if { ac_try='./$ac_file'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { echo "$as_me:$LINENO: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ fi
+fi
+echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+rm -f a.out a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+# Check the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:$LINENO: checking whether we are cross compiling" >&5
+echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6
+echo "$as_me:$LINENO: result: $cross_compiling" >&5
+echo "${ECHO_T}$cross_compiling" >&6
+
+echo "$as_me:$LINENO: checking for suffix of executables" >&5
+echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ export ac_cv_exeext
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest$ac_cv_exeext
+echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5
+echo "${ECHO_T}$ac_cv_exeext" >&6
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+echo "$as_me:$LINENO: checking for suffix of object files" >&5
+echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6
+if test "${ac_cv_objext+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_objext" >&5
+echo "${ECHO_T}$ac_cv_objext" >&6
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_compiler_gnu=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_compiler_gnu=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6
+GCC=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+CFLAGS="-g"
+echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_g+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_cc_g=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_prog_cc_g=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_g" >&6
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5
+echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_prog_cc_stdc=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std1 is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std1. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX -qlanglvl=ansi
+# Ultrix and OSF/1 -std1
+# HP-UX 10.20 and later -Ae
+# HP-UX older versions -Aa -D_HPUX_SOURCE
+# SVR4 -Xc -D__EXTENSIONS__
+for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_cc_stdc=$ac_arg
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext
+done
+rm -f conftest.$ac_ext conftest.$ac_objext
+CC=$ac_save_CC
+
+fi
+
+case "x$ac_cv_prog_cc_stdc" in
+ x|xno)
+ echo "$as_me:$LINENO: result: none needed" >&5
+echo "${ECHO_T}none needed" >&6 ;;
+ *)
+ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6
+ CC="$CC $ac_cv_prog_cc_stdc" ;;
+esac
+
+# Some people use a C++ compiler to compile C. Since we use `exit',
+# in C++ we need to declare it. In case someone uses the same compiler
+# for both compiling C and C++ we need to have the C++ compiler decide
+# the declaration of exit, since it's the most demanding environment.
+cat >conftest.$ac_ext <<_ACEOF
+#ifndef __cplusplus
+ choke me
+#endif
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ for ac_declaration in \
+ '' \
+ 'extern "C" void std::exit (int) throw (); using std::exit;' \
+ 'extern "C" void std::exit (int); using std::exit;' \
+ 'extern "C" void exit (int) throw ();' \
+ 'extern "C" void exit (int);' \
+ 'void exit (int);'
+do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_declaration
+#include <stdlib.h>
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+continue
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_declaration
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+rm -f conftest*
+if test -n "$ac_declaration"; then
+ echo '#ifdef __cplusplus' >>confdefs.h
+ echo $ac_declaration >>confdefs.h
+ echo '#endif' >>confdefs.h
+fi
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+DEPDIR="${am__leading_dot}deps"
+
+ ac_config_commands="$ac_config_commands depfiles"
+
+
+am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+ @echo done
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5
+echo $ECHO_N "checking for style of include used by $am_make... $ECHO_C" >&6
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# We grep out `Entering directory' and `Leaving directory'
+# messages which can occur if `w' ends up in MAKEFLAGS.
+# In particular we don't look at `^make:' because GNU make might
+# be invoked under some other name (usually "gmake"), in which
+# case it prints its new name instead of `make'.
+if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then
+ am__include=include
+ am__quote=
+ _am_result=GNU
+fi
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+ echo '.include "confinc"' > confmf
+ if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then
+ am__include=.include
+ am__quote="\""
+ _am_result=BSD
+ fi
+fi
+
+
+echo "$as_me:$LINENO: result: $_am_result" >&5
+echo "${ECHO_T}$_am_result" >&6
+rm -f confinc confmf
+
+# Check whether --enable-dependency-tracking or --disable-dependency-tracking was given.
+if test "${enable_dependency_tracking+set}" = set; then
+ enableval="$enable_dependency_tracking"
+
+fi;
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+fi
+
+
+if test "x$enable_dependency_tracking" != xno; then
+ AMDEP_TRUE=
+ AMDEP_FALSE='#'
+else
+ AMDEP_TRUE='#'
+ AMDEP_FALSE=
+fi
+
+
+
+
+depcc="$CC" am_compiler_list=
+
+echo "$as_me:$LINENO: checking dependency style of $depcc" >&5
+echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6
+if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named `D' -- because `-MD' means `put the output
+ # in D'.
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_CC_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+ fi
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+ # Solaris 8's {/usr,}/bin/sh.
+ touch sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ case $depmode in
+ nosideeffect)
+ # after this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ none) break ;;
+ esac
+ # We check with `-c' and `-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle `-M -o', and we need to detect this.
+ if depmode=$depmode \
+ source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_CC_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5
+echo "${ECHO_T}$am_cv_CC_dependencies_compiler_type" >&6
+CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+
+
+if
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+ am__fastdepCC_TRUE=
+ am__fastdepCC_FALSE='#'
+else
+ am__fastdepCC_TRUE='#'
+ am__fastdepCC_FALSE=
+fi
+
+
+ac_ext=cc
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl FCC KCC RCC xlC_r xlC
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; 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_CXX+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CXX"; then
+ ac_cv_prog_CXX="$CXX" # 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_CXX="$ac_tool_prefix$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CXX=$ac_cv_prog_CXX
+if test -n "$CXX"; then
+ echo "$as_me:$LINENO: result: $CXX" >&5
+echo "${ECHO_T}$CXX" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$CXX" && break
+ done
+fi
+if test -z "$CXX"; then
+ ac_ct_CXX=$CXX
+ for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl FCC KCC RCC xlC_r xlC
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; 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_CXX+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CXX"; then
+ ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # 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_CXX="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CXX=$ac_cv_prog_ac_ct_CXX
+if test -n "$ac_ct_CXX"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5
+echo "${ECHO_T}$ac_ct_CXX" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$ac_ct_CXX" && break
+done
+test -n "$ac_ct_CXX" || ac_ct_CXX="g++"
+
+ CXX=$ac_ct_CXX
+fi
+
+
+# Provide some information about the compiler.
+echo "$as_me:$LINENO:" \
+ "checking for C++ compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
+ (eval $ac_compiler --version </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5
+ (eval $ac_compiler -v </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5
+ (eval $ac_compiler -V </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+
+echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C++ compiler... $ECHO_C" >&6
+if test "${ac_cv_cxx_compiler_gnu+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_compiler_gnu=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_compiler_gnu=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_cxx_compiler_gnu=$ac_compiler_gnu
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_cxx_compiler_gnu" >&6
+GXX=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CXXFLAGS=${CXXFLAGS+set}
+ac_save_CXXFLAGS=$CXXFLAGS
+CXXFLAGS="-g"
+echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5
+echo $ECHO_N "checking whether $CXX accepts -g... $ECHO_C" >&6
+if test "${ac_cv_prog_cxx_g+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_cxx_g=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_prog_cxx_g=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cxx_g" >&6
+if test "$ac_test_CXXFLAGS" = set; then
+ CXXFLAGS=$ac_save_CXXFLAGS
+elif test $ac_cv_prog_cxx_g = yes; then
+ if test "$GXX" = yes; then
+ CXXFLAGS="-g -O2"
+ else
+ CXXFLAGS="-g"
+ fi
+else
+ if test "$GXX" = yes; then
+ CXXFLAGS="-O2"
+ else
+ CXXFLAGS=
+ fi
+fi
+for ac_declaration in \
+ '' \
+ 'extern "C" void std::exit (int) throw (); using std::exit;' \
+ 'extern "C" void std::exit (int); using std::exit;' \
+ 'extern "C" void exit (int) throw ();' \
+ 'extern "C" void exit (int);' \
+ 'void exit (int);'
+do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_declaration
+#include <stdlib.h>
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+continue
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_declaration
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+rm -f conftest*
+if test -n "$ac_declaration"; then
+ echo '#ifdef __cplusplus' >>confdefs.h
+ echo $ac_declaration >>confdefs.h
+ echo '#endif' >>confdefs.h
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+depcc="$CXX" am_compiler_list=
+
+echo "$as_me:$LINENO: checking dependency style of $depcc" >&5
+echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6
+if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named `D' -- because `-MD' means `put the output
+ # in D'.
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_CXX_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+ fi
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+ # Solaris 8's {/usr,}/bin/sh.
+ touch sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ case $depmode in
+ nosideeffect)
+ # after this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ none) break ;;
+ esac
+ # We check with `-c' and `-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle `-M -o', and we need to detect this.
+ if depmode=$depmode \
+ source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_CXX_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_CXX_dependencies_compiler_type=none
+fi
+
+fi
+echo "$as_me:$LINENO: result: $am_cv_CXX_dependencies_compiler_type" >&5
+echo "${ECHO_T}$am_cv_CXX_dependencies_compiler_type" >&6
+CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type
+
+
+
+if
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then
+ am__fastdepCXX_TRUE=
+ am__fastdepCXX_FALSE='#'
+else
+ am__fastdepCXX_TRUE='#'
+ am__fastdepCXX_FALSE=
+fi
+
+
+for ac_prog in 'bison -y' byacc
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; 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_YACC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$YACC"; then
+ ac_cv_prog_YACC="$YACC" # 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_YACC="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+YACC=$ac_cv_prog_YACC
+if test -n "$YACC"; then
+ echo "$as_me:$LINENO: result: $YACC" >&5
+echo "${ECHO_T}$YACC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$YACC" && break
+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:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5
+echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in
+ ./ | .// | /cC/* | \
+ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+ ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \
+ /usr/ucb/* ) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+ if test $ac_prog = install &&
+ grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ elif test $ac_prog = install &&
+ grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # program-specific install script used by HP pwplus--don't use.
+ :
+ else
+ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+ break 3
+ fi
+ fi
+ done
+ done
+ ;;
+esac
+done
+
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL=$ac_cv_path_install
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL=$ac_install_sh
+ fi
+fi
+echo "$as_me:$LINENO: result: $INSTALL" >&5
+echo "${ECHO_T}$INSTALL" >&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+# If we haven't got the data from the intl directory,
+# assume NLS is disabled.
+USE_NLS=no
+LIBINTL=
+LIBINTL_DEP=
+INCINTL=
+XGETTEXT=
+GMSGFMT=
+POSUB=
+
+if test -f ../intl/config.intl; then
+ . ../intl/config.intl
+fi
+echo "$as_me:$LINENO: checking whether NLS is requested" >&5
+echo $ECHO_N "checking whether NLS is requested... $ECHO_C" >&6
+if test x"$USE_NLS" != xyes; then
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+else
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+cat >>confdefs.h <<\_ACEOF
+#define ENABLE_NLS 1
+_ACEOF
+
+
+ echo "$as_me:$LINENO: checking for catalogs to be installed" >&5
+echo $ECHO_N "checking for catalogs to be installed... $ECHO_C" >&6
+ # Look for .po and .gmo files in the source directory.
+ CATALOGS=
+ XLINGUAS=
+ for cat in $srcdir/po/*.gmo $srcdir/po/*.po; do
+ # If there aren't any .gmo files the shell will give us the
+ # literal string "../path/to/srcdir/po/*.gmo" which has to be
+ # weeded out.
+ case "$cat" in *\**)
+ continue;;
+ esac
+ # The quadruple backslash is collapsed to a double backslash
+ # by the backticks, then collapsed again by the double quotes,
+ # leaving us with one backslash in the sed expression (right
+ # before the dot that mustn't act as a wildcard).
+ cat=`echo $cat | sed -e "s!$srcdir/po/!!" -e "s!\\\\.po!.gmo!"`
+ lang=`echo $cat | sed -e "s!\\\\.gmo!!"`
+ # The user is allowed to set LINGUAS to a list of languages to
+ # install catalogs for. If it's empty that means "all of them."
+ if test "x$LINGUAS" = x; then
+ CATALOGS="$CATALOGS $cat"
+ XLINGUAS="$XLINGUAS $lang"
+ else
+ case "$LINGUAS" in *$lang*)
+ CATALOGS="$CATALOGS $cat"
+ XLINGUAS="$XLINGUAS $lang"
+ ;;
+ esac
+ fi
+ done
+ LINGUAS="$XLINGUAS"
+ echo "$as_me:$LINENO: result: $LINGUAS" >&5
+echo "${ECHO_T}$LINGUAS" >&6
+
+
+ DATADIRNAME=share
+
+ INSTOBJEXT=.mo
+
+ GENCAT=gencat
+
+ CATOBJEXT=.gmo
+
+fi
+
+ MKINSTALLDIRS=
+ if test -n "$ac_aux_dir"; then
+ case "$ac_aux_dir" in
+ /*) MKINSTALLDIRS="$ac_aux_dir/mkinstalldirs" ;;
+ *) MKINSTALLDIRS="\$(top_builddir)/$ac_aux_dir/mkinstalldirs" ;;
+ esac
+ fi
+ if test -z "$MKINSTALLDIRS"; then
+ MKINSTALLDIRS="\$(top_srcdir)/mkinstalldirs"
+ fi
+
+
+
+ echo "$as_me:$LINENO: checking whether NLS is requested" >&5
+echo $ECHO_N "checking whether NLS is requested... $ECHO_C" >&6
+ # Check whether --enable-nls or --disable-nls was given.
+if test "${enable_nls+set}" = set; then
+ enableval="$enable_nls"
+ USE_NLS=$enableval
+else
+ USE_NLS=yes
+fi;
+ echo "$as_me:$LINENO: result: $USE_NLS" >&5
+echo "${ECHO_T}$USE_NLS" >&6
+
+
+
+
+
+
+# Prepare PATH_SEPARATOR.
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+
+# Find out how to test for executable files. Don't use a zero-byte file,
+# as systems may use methods other than mode bits to determine executability.
+cat >conf$$.file <<_ASEOF
+#! /bin/sh
+exit 0
+_ASEOF
+chmod +x conf$$.file
+if test -x conf$$.file >/dev/null 2>&1; then
+ ac_executable_p="test -x"
+else
+ ac_executable_p="test -f"
+fi
+rm -f conf$$.file
+
+# Extract the first word of "msgfmt", so it can be a program name with args.
+set dummy msgfmt; 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_path_MSGFMT+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case "$MSGFMT" in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_MSGFMT="$MSGFMT" # Let the user override the test with a path.
+ ;;
+ *)
+ ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS="$ac_save_IFS"
+ test -z "$ac_dir" && ac_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then
+ if $ac_dir/$ac_word --statistics /dev/null >/dev/null 2>&1 &&
+ (if $ac_dir/$ac_word --statistics /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi); then
+ ac_cv_path_MSGFMT="$ac_dir/$ac_word$ac_exec_ext"
+ break 2
+ fi
+ fi
+ done
+ done
+ IFS="$ac_save_IFS"
+ test -z "$ac_cv_path_MSGFMT" && ac_cv_path_MSGFMT=":"
+ ;;
+esac
+fi
+MSGFMT="$ac_cv_path_MSGFMT"
+if test "$MSGFMT" != ":"; then
+ echo "$as_me:$LINENO: result: $MSGFMT" >&5
+echo "${ECHO_T}$MSGFMT" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ # Extract the first word of "gmsgfmt", so it can be a program name with args.
+set dummy gmsgfmt; 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_path_GMSGFMT+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $GMSGFMT in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_GMSGFMT="$GMSGFMT" # Let the user override the test with a path.
+ ;;
+ *)
+ 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_path_GMSGFMT="$as_dir/$ac_word$ac_exec_ext"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ test -z "$ac_cv_path_GMSGFMT" && ac_cv_path_GMSGFMT="$MSGFMT"
+ ;;
+esac
+fi
+GMSGFMT=$ac_cv_path_GMSGFMT
+
+if test -n "$GMSGFMT"; then
+ echo "$as_me:$LINENO: result: $GMSGFMT" >&5
+echo "${ECHO_T}$GMSGFMT" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+
+
+# Prepare PATH_SEPARATOR.
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+
+# Find out how to test for executable files. Don't use a zero-byte file,
+# as systems may use methods other than mode bits to determine executability.
+cat >conf$$.file <<_ASEOF
+#! /bin/sh
+exit 0
+_ASEOF
+chmod +x conf$$.file
+if test -x conf$$.file >/dev/null 2>&1; then
+ ac_executable_p="test -x"
+else
+ ac_executable_p="test -f"
+fi
+rm -f conf$$.file
+
+# Extract the first word of "xgettext", so it can be a program name with args.
+set dummy xgettext; 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_path_XGETTEXT+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case "$XGETTEXT" in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_XGETTEXT="$XGETTEXT" # Let the user override the test with a path.
+ ;;
+ *)
+ ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS="$ac_save_IFS"
+ test -z "$ac_dir" && ac_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then
+ if $ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null >/dev/null 2>&1 &&
+ (if $ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi); then
+ ac_cv_path_XGETTEXT="$ac_dir/$ac_word$ac_exec_ext"
+ break 2
+ fi
+ fi
+ done
+ done
+ IFS="$ac_save_IFS"
+ test -z "$ac_cv_path_XGETTEXT" && ac_cv_path_XGETTEXT=":"
+ ;;
+esac
+fi
+XGETTEXT="$ac_cv_path_XGETTEXT"
+if test "$XGETTEXT" != ":"; then
+ echo "$as_me:$LINENO: result: $XGETTEXT" >&5
+echo "${ECHO_T}$XGETTEXT" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ rm -f messages.po
+
+
+# Prepare PATH_SEPARATOR.
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+
+# Find out how to test for executable files. Don't use a zero-byte file,
+# as systems may use methods other than mode bits to determine executability.
+cat >conf$$.file <<_ASEOF
+#! /bin/sh
+exit 0
+_ASEOF
+chmod +x conf$$.file
+if test -x conf$$.file >/dev/null 2>&1; then
+ ac_executable_p="test -x"
+else
+ ac_executable_p="test -f"
+fi
+rm -f conf$$.file
+
+# Extract the first word of "msgmerge", so it can be a program name with args.
+set dummy msgmerge; 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_path_MSGMERGE+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case "$MSGMERGE" in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_MSGMERGE="$MSGMERGE" # Let the user override the test with a path.
+ ;;
+ *)
+ ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS="$ac_save_IFS"
+ test -z "$ac_dir" && ac_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then
+ if $ac_dir/$ac_word --update -q /dev/null /dev/null >/dev/null 2>&1; then
+ ac_cv_path_MSGMERGE="$ac_dir/$ac_word$ac_exec_ext"
+ break 2
+ fi
+ fi
+ done
+ done
+ IFS="$ac_save_IFS"
+ test -z "$ac_cv_path_MSGMERGE" && ac_cv_path_MSGMERGE=":"
+ ;;
+esac
+fi
+MSGMERGE="$ac_cv_path_MSGMERGE"
+if test "$MSGMERGE" != ":"; then
+ echo "$as_me:$LINENO: result: $MSGMERGE" >&5
+echo "${ECHO_T}$MSGMERGE" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+
+ if test "$GMSGFMT" != ":"; then
+ if $GMSGFMT --statistics /dev/null >/dev/null 2>&1 &&
+ (if $GMSGFMT --statistics /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi); then
+ : ;
+ else
+ GMSGFMT=`echo "$GMSGFMT" | sed -e 's,^.*/,,'`
+ echo "$as_me:$LINENO: result: found $GMSGFMT program is not GNU msgfmt; ignore it" >&5
+echo "${ECHO_T}found $GMSGFMT program is not GNU msgfmt; ignore it" >&6
+ GMSGFMT=":"
+ fi
+ fi
+
+ if test "$XGETTEXT" != ":"; then
+ if $XGETTEXT --omit-header --copyright-holder= --msgid-bugs-address= /dev/null >/dev/null 2>&1 &&
+ (if $XGETTEXT --omit-header --copyright-holder= --msgid-bugs-address= /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi); then
+ : ;
+ else
+ echo "$as_me:$LINENO: result: found xgettext program is not GNU xgettext; ignore it" >&5
+echo "${ECHO_T}found xgettext program is not GNU xgettext; ignore it" >&6
+ XGETTEXT=":"
+ fi
+ rm -f messages.po
+ fi
+
+ ac_config_commands="$ac_config_commands default-1"
+
+
+
+
+echo "$as_me:$LINENO: checking whether byte ordering is bigendian" >&5
+echo $ECHO_N "checking whether byte ordering is bigendian... $ECHO_C" >&6
+if test "${ac_cv_c_bigendian+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # See if sys/param.h defines the BYTE_ORDER macro.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <sys/param.h>
+
+int
+main ()
+{
+#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN
+ bogus endian macros
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ # It does; now see whether it defined to BIG_ENDIAN or not.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <sys/param.h>
+
+int
+main ()
+{
+#if BYTE_ORDER != BIG_ENDIAN
+ not big endian
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_c_bigendian=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_c_bigendian=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+# It does not; compile a test program.
+if test "$cross_compiling" = yes; then
+ # try to guess the endianness by grepping values into an object file
+ ac_cv_c_bigendian=unknown
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+short ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
+short ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
+void _ascii () { char *s = (char *) ascii_mm; s = (char *) ascii_ii; }
+short ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
+short ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
+void _ebcdic () { char *s = (char *) ebcdic_mm; s = (char *) ebcdic_ii; }
+int
+main ()
+{
+ _ascii (); _ebcdic ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ if grep BIGenDianSyS conftest.$ac_objext >/dev/null ; then
+ ac_cv_c_bigendian=yes
+fi
+if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then
+ if test "$ac_cv_c_bigendian" = unknown; then
+ ac_cv_c_bigendian=no
+ else
+ # finding both strings is unlikely to happen, but who knows?
+ ac_cv_c_bigendian=unknown
+ fi
+fi
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+int
+main ()
+{
+ /* Are we little or big endian? From Harbison&Steele. */
+ union
+ {
+ long l;
+ char c[sizeof (long)];
+ } u;
+ u.l = 1;
+ exit (u.c[sizeof (long) - 1] == 1);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_c_bigendian=no
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_c_bigendian=yes
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_bigendian" >&5
+echo "${ECHO_T}$ac_cv_c_bigendian" >&6
+case $ac_cv_c_bigendian in
+ yes)
+
+cat >>confdefs.h <<\_ACEOF
+#define WORDS_BIGENDIAN 1
+_ACEOF
+ ;;
+ no)
+ ;;
+ *)
+ { { echo "$as_me:$LINENO: error: unknown endianness
+presetting ac_cv_c_bigendian=no (or yes) will help" >&5
+echo "$as_me: error: unknown endianness
+presetting ac_cv_c_bigendian=no (or yes) will help" >&2;}
+ { (exit 1); exit 1; }; } ;;
+esac
+
+
+
+
+
+GCC_WARN_CFLAGS="-W -Wall -Wstrict-prototypes -Wmissing-prototypes"
+
+# Check whether --enable-werror or --disable-werror was given.
+if test "${enable_werror+set}" = set; then
+ enableval="$enable_werror"
+ case "${enableval}" in
+ yes | y) ERROR_ON_WARNING="yes" ;;
+ no | n) ERROR_ON_WARNING="no" ;;
+ *) { { echo "$as_me:$LINENO: error: bad value ${enableval} for --enable-werror" >&5
+echo "$as_me: error: bad value ${enableval} for --enable-werror" >&2;}
+ { (exit 1); exit 1; }; } ;;
+ esac
+fi;
+
+# Enable -Werror by default when using gcc
+if test "${GCC}" = yes -a -z "${ERROR_ON_WARNING}" ; then
+ ERROR_ON_WARNING=yes
+fi
+
+NO_WERROR=
+if test "${ERROR_ON_WARNING}" = yes ; then
+ GCC_WARN_CFLAGS="$GCC_WARN_CFLAGS -Werror"
+ NO_WERROR="-Wno-error"
+fi
+
+if test "${GCC}" = yes ; then
+ WARN_CFLAGS="${GCC_WARN_CFLAGS}"
+fi
+
+# Check whether --enable-build-warnings or --disable-build-warnings was given.
+if test "${enable_build_warnings+set}" = set; then
+ enableval="$enable_build_warnings"
+ case "${enableval}" in
+ yes) WARN_CFLAGS="${GCC_WARN_CFLAGS}";;
+ no) if test "${GCC}" = yes ; then
+ WARN_CFLAGS="-w"
+ fi;;
+ ,*) t=`echo "${enableval}" | sed -e "s/,/ /g"`
+ WARN_CFLAGS="${GCC_WARN_CFLAGS} ${t}";;
+ *,) t=`echo "${enableval}" | sed -e "s/,/ /g"`
+ WARN_CFLAGS="${t} ${GCC_WARN_CFLAGS}";;
+ *) WARN_CFLAGS=`echo "${enableval}" | sed -e "s/,/ /g"`;;
+esac
+fi;
+
+if test x"$silent" != x"yes" && test x"$WARN_CFLAGS" != x""; then
+ echo "Setting warning flags = $WARN_CFLAGS" 6>&1
+fi
+
+
+
+
+
+WARN_CXXFLAGS=`echo ${WARN_CFLAGS} | sed -e 's/-Wstrict-prototypes//' -e 's/-Wmissing-prototypes//'`
+
+
+LFS_CXXFLAGS="-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64"
+
+
+ac_ext=cc
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+
+
+ac_ext=cc
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+echo "$as_me:$LINENO: checking how to run the C++ preprocessor" >&5
+echo $ECHO_N "checking how to run the C++ preprocessor... $ECHO_C" >&6
+if test -z "$CXXCPP"; then
+ if test "${ac_cv_prog_CXXCPP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # Double quotes because CXXCPP needs to be expanded
+ for CXXCPP in "$CXX -E" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_cxx_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_cxx_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether non-existent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_cxx_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ break
+fi
+
+ done
+ ac_cv_prog_CXXCPP=$CXXCPP
+
+fi
+ CXXCPP=$ac_cv_prog_CXXCPP
+else
+ ac_cv_prog_CXXCPP=$CXXCPP
+fi
+echo "$as_me:$LINENO: result: $CXXCPP" >&5
+echo "${ECHO_T}$CXXCPP" >&6
+ac_preproc_ok=false
+for ac_cxx_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_cxx_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether non-existent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_cxx_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ :
+else
+ { { echo "$as_me:$LINENO: error: C++ preprocessor \"$CXXCPP\" fails sanity check
+See \`config.log' for more details." >&5
+echo "$as_me: error: C++ preprocessor \"$CXXCPP\" fails sanity check
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+ac_ext=cc
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+
+echo "$as_me:$LINENO: checking for egrep" >&5
+echo $ECHO_N "checking for egrep... $ECHO_C" >&6
+if test "${ac_cv_prog_egrep+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if echo a | (grep -E '(a|b)') >/dev/null 2>&1
+ then ac_cv_prog_egrep='grep -E'
+ else ac_cv_prog_egrep='egrep'
+ fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5
+echo "${ECHO_T}$ac_cv_prog_egrep" >&6
+ EGREP=$ac_cv_prog_egrep
+
+
+echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6
+if test "${ac_cv_header_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_header_stdc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_header_stdc=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then
+ :
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ctype.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ exit(2);
+ exit (0);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+echo "${ECHO_T}$ac_cv_header_stdc" >&6
+if test $ac_cv_header_stdc = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define STDC_HEADERS 1
+_ACEOF
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+
+
+
+
+
+
+
+
+
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+ inttypes.h stdint.h unistd.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_Header=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_Header=no"
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+
+for ac_header in tr1/unordered_set tr1/unordered_map
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_cxx_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_cxx_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------------ ##
+## Report this to the AC_PACKAGE_NAME lists. ##
+## ------------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+for ac_header in ext/hash_map ext/hash_set
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_cxx_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_cxx_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------------ ##
+## Report this to the AC_PACKAGE_NAME lists. ##
+## ------------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+cat >conftest.$ac_ext <<_ACEOF
+
+class c { public: template<int i> void fn(); };
+template<int i> void foo(c cv) { cv.fn<i>(); }
+template void foo<1>(c cv);
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_MEMBER_TEMPLATE_SPECIFICATIONS
+_ACEOF
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+echo "$as_me:$LINENO: checking whether to enable maintainer-specific portions of Makefiles" >&5
+echo $ECHO_N "checking whether to enable maintainer-specific portions of Makefiles... $ECHO_C" >&6
+ # Check whether --enable-maintainer-mode or --disable-maintainer-mode was given.
+if test "${enable_maintainer_mode+set}" = set; then
+ enableval="$enable_maintainer_mode"
+ USE_MAINTAINER_MODE=$enableval
+else
+ USE_MAINTAINER_MODE=no
+fi;
+ echo "$as_me:$LINENO: result: $USE_MAINTAINER_MODE" >&5
+echo "${ECHO_T}$USE_MAINTAINER_MODE" >&6
+
+
+if test $USE_MAINTAINER_MODE = yes; then
+ MAINTAINER_MODE_TRUE=
+ MAINTAINER_MODE_FALSE='#'
+else
+ MAINTAINER_MODE_TRUE='#'
+ MAINTAINER_MODE_FALSE=
+fi
+
+ MAINT=$MAINTAINER_MODE_TRUE
+
+
+
+ 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
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+{
+ (set) 2>&1 |
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n \
+ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+ ;;
+ esac;
+} |
+ sed '
+ t clear
+ : clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ : end' >>confcache
+if diff $cache_file confcache >/dev/null 2>&1; then :; else
+ if test -w $cache_file; then
+ test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file"
+ cat confcache >$cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=/{
+s/:*\$(srcdir):*/:/;
+s/:*\${srcdir}:*/:/;
+s/:*@srcdir@:*/:/;
+s/^\([^=]*=[ ]*\):*/\1/;
+s/:*$//;
+s/^[^=]*=[ ]*$//;
+}'
+fi
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_i=`echo "$ac_i" |
+ sed 's/\$U\././;s/\.o$//;s/\.obj$//'`
+ # 2. Add them.
+ ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext"
+ ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+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
+echo "$as_me: error: conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCXX\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"am__fastdepCXX\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"MAINTAINER_MODE\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"MAINTAINER_MODE\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+: ${CONFIG_STATUS=./config.status}
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
+echo "$as_me: creating $CONFIG_STATUS" >&6;}
+cat >$CONFIG_STATUS <<_ACEOF
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+SHELL=\${CONFIG_SHELL-$SHELL}
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+## --------------------- ##
+## M4sh Initialization. ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
+fi
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+ LC_TELEPHONE LC_TIME
+do
+ if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+ eval $as_var=C; export $as_var
+ else
+ $as_unset $as_var
+ fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)$' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+ /^X\/\(\/\/\)$/{ s//\1/; q; }
+ /^X\/\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+
+
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" || {
+ # Find who we are. Look in the path if we contain no path at all
+ # relative or not.
+ case $0 in
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+
+ ;;
+ esac
+ # We did not find ourselves, most probably we were run as `sh COMMAND'
+ # in which case we are not to be found in the path.
+ if test "x$as_myself" = x; then
+ as_myself=$0
+ fi
+ if test ! -f "$as_myself"; then
+ { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5
+echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ case $CONFIG_SHELL in
+ '')
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for as_base in sh bash ksh sh5; do
+ case $as_dir in
+ /*)
+ if ("$as_dir/$as_base" -c '
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then
+ $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+ $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+ CONFIG_SHELL=$as_dir/$as_base
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+ fi;;
+ esac
+ done
+done
+;;
+ esac
+
+ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+ # uniformly replaced by the line number. The first 'sed' inserts a
+ # line-number line before each line; the second 'sed' does the real
+ # work. The second script uses 'N' to pair each line-number line
+ # with the numbered line, and appends trailing '-' during
+ # substitution so that $LINENO is not a special case at line end.
+ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+ # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-)
+ sed '=' <$as_myself |
+ sed '
+ N
+ s,$,-,
+ : loop
+ s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+ t loop
+ s,-$,,
+ s,^['$as_cr_digits']*\n,,
+ ' >$as_me.lineno &&
+ chmod +x $as_me.lineno ||
+ { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5
+echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;}
+ { (exit 1); exit 1; }; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensible to this).
+ . ./$as_me.lineno
+ # Exit status is that of the last command.
+ exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+ *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T=' ' ;;
+ *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+ *) ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ # We could just check for DJGPP; but this test a) works b) is more generic
+ # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+ if test -f conf$$.exe; then
+ # Don't use ln at all; we don't have any links
+ as_ln_s='cp -p'
+ else
+ as_ln_s='ln -s'
+ fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p=:
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_executable_p="test -f"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" $as_nl"
+
+# CDPATH.
+$as_unset CDPATH
+
+exec 6>&1
+
+# Open the log real soon, to keep \$[0] and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling. Logging --version etc. is OK.
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+} >&5
+cat >&5 <<_CSEOF
+
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.59. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+_CSEOF
+echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5
+echo >&5
+_ACEOF
+
+# Files that config.status was made for.
+if test -n "$ac_config_files"; then
+ echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_headers"; then
+ echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_links"; then
+ echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_commands"; then
+ echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+ac_cs_usage="\
+\`$as_me' instantiates files from templates according to the
+current configuration.
+
+Usage: $0 [OPTIONS] [FILE]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number, then exit
+ -q, --quiet do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Configuration commands:
+$config_commands
+
+Report bugs to <bug-autoconf@gnu.org>."
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.59,
+ with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright (C) 2003 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+srcdir=$srcdir
+INSTALL="$INSTALL"
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# If no file are specified by the user, then we need to provide default
+# value. By we need to know if files were specified by the user.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=*)
+ ac_option=`expr "x$1" : 'x\([^=]*\)='`
+ ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ -*)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ *) # This is not an option, so the user has probably given explicit
+ # arguments.
+ ac_option=$1
+ ac_need_defaults=false;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --vers* | -V )
+ echo "$ac_cs_version"; exit 0 ;;
+ --he | --h)
+ # Conflict between --help and --header
+ { { echo "$as_me:$LINENO: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&2;}
+ { (exit 1); exit 1; }; };;
+ --help | --hel | -h )
+ echo "$ac_cs_usage"; exit 0 ;;
+ --debug | --d* | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ CONFIG_FILES="$CONFIG_FILES $ac_optarg"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg"
+ ac_need_defaults=false;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&2;}
+ { (exit 1); exit 1; }; } ;;
+
+ *) ac_config_targets="$ac_config_targets $1" ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+if \$ac_cs_recheck; then
+ echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6
+ exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+fi
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+#
+# INIT-COMMANDS section.
+#
+
+AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"
+# Capture the value of obsolete ALL_LINGUAS because we need it to compute
+ # POFILES, GMOFILES, UPDATEPOFILES, DUMMYPOFILES, CATALOGS. But hide it
+ # from automake.
+ eval 'OBSOLETE_ALL_LINGUAS''="$ALL_LINGUAS"'
+ # Capture the value of LINGUAS because we need it to compute CATALOGS.
+ LINGUAS="${LINGUAS-%UNSET%}"
+
+
+_ACEOF
+
+
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_config_target in $ac_config_targets
+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" ;;
+ "config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS config.h:config.in" ;;
+ *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
+echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+ test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason to put it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Create a temporary directory, and hook for its removal unless debugging.
+$debug ||
+{
+ trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0
+ trap '{ (exit 1); exit 1; }' 1 2 13 15
+}
+
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` &&
+ test -n "$tmp" && test -d "$tmp"
+} ||
+{
+ tmp=./confstat$$-$RANDOM
+ (umask 077 && mkdir $tmp)
+} ||
+{
+ echo "$me: cannot create a temporary directory in ." >&2
+ { (exit 1); exit 1; }
+}
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+
+#
+# CONFIG_FILES section.
+#
+
+# No need to generate the scripts if there are no CONFIG_FILES.
+# This happens for instance when ./config.status config.h
+if test -n "\$CONFIG_FILES"; then
+ # Protect against being on the right side of a sed subst in config.status.
+ sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g;
+ s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF
+s,@SHELL@,$SHELL,;t t
+s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t
+s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t
+s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t
+s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t
+s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t
+s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t
+s,@exec_prefix@,$exec_prefix,;t t
+s,@prefix@,$prefix,;t t
+s,@program_transform_name@,$program_transform_name,;t t
+s,@bindir@,$bindir,;t t
+s,@sbindir@,$sbindir,;t t
+s,@libexecdir@,$libexecdir,;t t
+s,@datadir@,$datadir,;t t
+s,@sysconfdir@,$sysconfdir,;t t
+s,@sharedstatedir@,$sharedstatedir,;t t
+s,@localstatedir@,$localstatedir,;t t
+s,@libdir@,$libdir,;t t
+s,@includedir@,$includedir,;t t
+s,@oldincludedir@,$oldincludedir,;t t
+s,@infodir@,$infodir,;t t
+s,@mandir@,$mandir,;t t
+s,@build_alias@,$build_alias,;t t
+s,@host_alias@,$host_alias,;t t
+s,@target_alias@,$target_alias,;t t
+s,@DEFS@,$DEFS,;t t
+s,@ECHO_C@,$ECHO_C,;t t
+s,@ECHO_N@,$ECHO_N,;t t
+s,@ECHO_T@,$ECHO_T,;t t
+s,@LIBS@,$LIBS,;t t
+s,@build@,$build,;t t
+s,@build_cpu@,$build_cpu,;t t
+s,@build_vendor@,$build_vendor,;t t
+s,@build_os@,$build_os,;t t
+s,@host@,$host,;t t
+s,@host_cpu@,$host_cpu,;t t
+s,@host_vendor@,$host_vendor,;t t
+s,@host_os@,$host_os,;t t
+s,@target@,$target,;t t
+s,@target_cpu@,$target_cpu,;t t
+s,@target_vendor@,$target_vendor,;t t
+s,@target_os@,$target_os,;t t
+s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t
+s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t
+s,@INSTALL_DATA@,$INSTALL_DATA,;t t
+s,@CYGPATH_W@,$CYGPATH_W,;t t
+s,@PACKAGE@,$PACKAGE,;t t
+s,@VERSION@,$VERSION,;t t
+s,@ACLOCAL@,$ACLOCAL,;t t
+s,@AUTOCONF@,$AUTOCONF,;t t
+s,@AUTOMAKE@,$AUTOMAKE,;t t
+s,@AUTOHEADER@,$AUTOHEADER,;t t
+s,@MAKEINFO@,$MAKEINFO,;t t
+s,@install_sh@,$install_sh,;t t
+s,@STRIP@,$STRIP,;t t
+s,@ac_ct_STRIP@,$ac_ct_STRIP,;t t
+s,@INSTALL_STRIP_PROGRAM@,$INSTALL_STRIP_PROGRAM,;t t
+s,@mkdir_p@,$mkdir_p,;t t
+s,@AWK@,$AWK,;t t
+s,@SET_MAKE@,$SET_MAKE,;t t
+s,@am__leading_dot@,$am__leading_dot,;t t
+s,@AMTAR@,$AMTAR,;t t
+s,@am__tar@,$am__tar,;t t
+s,@am__untar@,$am__untar,;t t
+s,@CC@,$CC,;t t
+s,@CFLAGS@,$CFLAGS,;t t
+s,@LDFLAGS@,$LDFLAGS,;t t
+s,@CPPFLAGS@,$CPPFLAGS,;t t
+s,@ac_ct_CC@,$ac_ct_CC,;t t
+s,@EXEEXT@,$EXEEXT,;t t
+s,@OBJEXT@,$OBJEXT,;t t
+s,@DEPDIR@,$DEPDIR,;t t
+s,@am__include@,$am__include,;t t
+s,@am__quote@,$am__quote,;t t
+s,@AMDEP_TRUE@,$AMDEP_TRUE,;t t
+s,@AMDEP_FALSE@,$AMDEP_FALSE,;t t
+s,@AMDEPBACKSLASH@,$AMDEPBACKSLASH,;t t
+s,@CCDEPMODE@,$CCDEPMODE,;t t
+s,@am__fastdepCC_TRUE@,$am__fastdepCC_TRUE,;t t
+s,@am__fastdepCC_FALSE@,$am__fastdepCC_FALSE,;t t
+s,@CXX@,$CXX,;t t
+s,@CXXFLAGS@,$CXXFLAGS,;t t
+s,@ac_ct_CXX@,$ac_ct_CXX,;t t
+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
+s,@INCINTL@,$INCINTL,;t t
+s,@XGETTEXT@,$XGETTEXT,;t t
+s,@GMSGFMT@,$GMSGFMT,;t t
+s,@POSUB@,$POSUB,;t t
+s,@CATALOGS@,$CATALOGS,;t t
+s,@DATADIRNAME@,$DATADIRNAME,;t t
+s,@INSTOBJEXT@,$INSTOBJEXT,;t t
+s,@GENCAT@,$GENCAT,;t t
+s,@CATOBJEXT@,$CATOBJEXT,;t t
+s,@MKINSTALLDIRS@,$MKINSTALLDIRS,;t t
+s,@MSGFMT@,$MSGFMT,;t t
+s,@MSGMERGE@,$MSGMERGE,;t t
+s,@WARN_CFLAGS@,$WARN_CFLAGS,;t t
+s,@NO_WERROR@,$NO_WERROR,;t t
+s,@WARN_CXXFLAGS@,$WARN_CXXFLAGS,;t t
+s,@LFS_CXXFLAGS@,$LFS_CXXFLAGS,;t t
+s,@CXXCPP@,$CXXCPP,;t t
+s,@EGREP@,$EGREP,;t t
+s,@MAINTAINER_MODE_TRUE@,$MAINTAINER_MODE_TRUE,;t t
+s,@MAINTAINER_MODE_FALSE@,$MAINTAINER_MODE_FALSE,;t t
+s,@MAINT@,$MAINT,;t t
+s,@LIBOBJS@,$LIBOBJS,;t t
+s,@LTLIBOBJS@,$LTLIBOBJS,;t t
+CEOF
+
+_ACEOF
+
+ cat >>$CONFIG_STATUS <<\_ACEOF
+ # Split the substitutions into bite-sized pieces for seds with
+ # small command number limits, like on Digital OSF/1 and HP-UX.
+ ac_max_sed_lines=48
+ ac_sed_frag=1 # Number of current file.
+ ac_beg=1 # First line for current file.
+ ac_end=$ac_max_sed_lines # Line after last line for current file.
+ ac_more_lines=:
+ ac_sed_cmds=
+ while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+ else
+ sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+ fi
+ if test ! -s $tmp/subs.frag; then
+ ac_more_lines=false
+ else
+ # The purpose of the label and of the branching condition is to
+ # speed up the sed processing (if there are no `@' at all, there
+ # is no need to browse any of the substitutions).
+ # These are the two extra sed commands mentioned above.
+ (echo ':t
+ /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed"
+ fi
+ ac_sed_frag=`expr $ac_sed_frag + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_lines`
+ fi
+ done
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+ fi
+fi # test -n "$CONFIG_FILES"
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case $ac_file in
+ - | *:- | *:-:* ) # input from stdin
+ cat >$tmp/stdin
+ ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ * ) ac_file_in=$ac_file.in ;;
+ esac
+
+ # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories.
+ ac_dir=`(dirname "$ac_file") 2>/dev/null ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ { if $as_mkdir_p; then
+ mkdir -p "$ac_dir"
+ else
+ as_dir="$ac_dir"
+ as_dirs=
+ while test ! -d "$as_dir"; do
+ as_dirs="$as_dir $as_dirs"
+ as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ done
+ test ! -n "$as_dirs" || mkdir $as_dirs
+ fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
+ { (exit 1); exit 1; }; }; }
+
+ ac_builddir=.
+
+if test "$ac_dir" != .; then
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+ ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+ .) # No --srcdir option. We are building in place.
+ ac_srcdir=.
+ if test -z "$ac_top_builddir"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+
+# Do not use `cd foo && pwd` to compute absolute paths, because
+# the directories may not exist.
+case `pwd` in
+.) ac_abs_builddir="$ac_dir";;
+*)
+ case "$ac_dir" in
+ .) ac_abs_builddir=`pwd`;;
+ [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";;
+ *) ac_abs_builddir=`pwd`/"$ac_dir";;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_builddir=${ac_top_builddir}.;;
+*)
+ case ${ac_top_builddir}. in
+ .) ac_abs_top_builddir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;;
+ *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_srcdir=$ac_srcdir;;
+*)
+ case $ac_srcdir in
+ .) ac_abs_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;;
+ *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_srcdir=$ac_top_srcdir;;
+*)
+ case $ac_top_srcdir in
+ .) ac_abs_top_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;;
+ *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;;
+ esac;;
+esac
+
+
+ case $INSTALL in
+ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+ *) ac_INSTALL=$ac_top_builddir$INSTALL ;;
+ esac
+
+ if test x"$ac_file" != x-; then
+ { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+ rm -f "$ac_file"
+ fi
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ if test x"$ac_file" = x-; then
+ configure_input=
+ else
+ configure_input="$ac_file. "
+ fi
+ configure_input=$configure_input"Generated from `echo $ac_file_in |
+ sed 's,.*/,,'` by configure."
+
+ # First look for the input files in the build tree, otherwise in the
+ # src tree.
+ ac_file_inputs=`IFS=:
+ for f in $ac_file_in; do
+ case $f in
+ -) echo $tmp/stdin ;;
+ [\\/$]*)
+ # Absolute (can't be DOS-style, as IFS=:)
+ test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ echo "$f";;
+ *) # Relative
+ if test -f "$f"; then
+ # Build tree
+ echo "$f"
+ elif test -f "$srcdir/$f"; then
+ # Source tree
+ echo "$srcdir/$f"
+ else
+ # /dev/null tree
+ { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ fi;;
+ esac
+ done` || { (exit 1); exit 1; }
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+ sed "$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s,@configure_input@,$configure_input,;t t
+s,@srcdir@,$ac_srcdir,;t t
+s,@abs_srcdir@,$ac_abs_srcdir,;t t
+s,@top_srcdir@,$ac_top_srcdir,;t t
+s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t
+s,@builddir@,$ac_builddir,;t t
+s,@abs_builddir@,$ac_abs_builddir,;t t
+s,@top_builddir@,$ac_top_builddir,;t t
+s,@abs_top_builddir@,$ac_abs_top_builddir,;t t
+s,@INSTALL@,$ac_INSTALL,;t t
+" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out
+ rm -f $tmp/stdin
+ if test x"$ac_file" != x-; then
+ mv $tmp/out $ac_file
+ else
+ cat $tmp/out
+ rm -f $tmp/out
+ fi
+
+done
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+#
+# CONFIG_HEADER section.
+#
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s,^\([ ]*\)#\([ ]*define[ ][ ]*\)'
+ac_dB='[ ].*$,\1#\2'
+ac_dC=' '
+ac_dD=',;t'
+# ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_uA='s,^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_uB='$,\1#\2define\3'
+ac_uC=' '
+ac_uD=',;t'
+
+for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case $ac_file in
+ - | *:- | *:-:* ) # input from stdin
+ cat >$tmp/stdin
+ ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ * ) ac_file_in=$ac_file.in ;;
+ esac
+
+ test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+
+ # First look for the input files in the build tree, otherwise in the
+ # src tree.
+ ac_file_inputs=`IFS=:
+ for f in $ac_file_in; do
+ case $f in
+ -) echo $tmp/stdin ;;
+ [\\/$]*)
+ # Absolute (can't be DOS-style, as IFS=:)
+ test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ # Do quote $f, to prevent DOS paths from being IFS'd.
+ echo "$f";;
+ *) # Relative
+ if test -f "$f"; then
+ # Build tree
+ echo "$f"
+ elif test -f "$srcdir/$f"; then
+ # Source tree
+ echo "$srcdir/$f"
+ else
+ # /dev/null tree
+ { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ fi;;
+ esac
+ done` || { (exit 1); exit 1; }
+ # Remove the trailing spaces.
+ sed 's/[ ]*$//' $ac_file_inputs >$tmp/in
+
+_ACEOF
+
+# Transform confdefs.h into two sed scripts, `conftest.defines' and
+# `conftest.undefs', that substitutes the proper values into
+# config.h.in to produce config.h. The first handles `#define'
+# templates, and the second `#undef' templates.
+# And first: Protect against being on the right side of a sed subst in
+# config.status. Protect against being in an unquoted here document
+# in config.status.
+rm -f conftest.defines conftest.undefs
+# Using a here document instead of a string reduces the quoting nightmare.
+# Putting comments in sed scripts is not portable.
+#
+# `end' is used to avoid that the second main sed command (meant for
+# 0-ary CPP macros) applies to n-ary macro definitions.
+# See the Autoconf documentation for `clear'.
+cat >confdef2sed.sed <<\_ACEOF
+s/[\\&,]/\\&/g
+s,[\\$`],\\&,g
+t clear
+: clear
+s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*\)\(([^)]*)\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp
+t end
+s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp
+: end
+_ACEOF
+# If some macros were called several times there might be several times
+# the same #defines, which is useless. Nevertheless, we may not want to
+# sort them, since we want the *last* AC-DEFINE to be honored.
+uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines
+sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs
+rm -f confdef2sed.sed
+
+# This sed command replaces #undef with comments. This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >>conftest.undefs <<\_ACEOF
+s,^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */,
+_ACEOF
+
+# Break up conftest.defines because some shells have a limit on the size
+# of here documents, and old seds have small limits too (100 cmds).
+echo ' # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS
+echo ' if grep "^[ ]*#[ ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS
+echo ' # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS
+echo ' :' >>$CONFIG_STATUS
+rm -f conftest.tail
+while grep . conftest.defines >/dev/null
+do
+ # Write a limited-size here document to $tmp/defines.sed.
+ echo ' cat >$tmp/defines.sed <<CEOF' >>$CONFIG_STATUS
+ # Speed up: don't consider the non `#define' lines.
+ echo '/^[ ]*#[ ]*define/!b' >>$CONFIG_STATUS
+ # Work around the forget-to-reset-the-flag bug.
+ echo 't clr' >>$CONFIG_STATUS
+ echo ': clr' >>$CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS
+ echo 'CEOF
+ sed -f $tmp/defines.sed $tmp/in >$tmp/out
+ rm -f $tmp/in
+ mv $tmp/out $tmp/in
+' >>$CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail
+ rm -f conftest.defines
+ mv conftest.tail conftest.defines
+done
+rm -f conftest.defines
+echo ' fi # grep' >>$CONFIG_STATUS
+echo >>$CONFIG_STATUS
+
+# Break up conftest.undefs because some shells have a limit on the size
+# of here documents, and old seds have small limits too (100 cmds).
+echo ' # Handle all the #undef templates' >>$CONFIG_STATUS
+rm -f conftest.tail
+while grep . conftest.undefs >/dev/null
+do
+ # Write a limited-size here document to $tmp/undefs.sed.
+ echo ' cat >$tmp/undefs.sed <<CEOF' >>$CONFIG_STATUS
+ # Speed up: don't consider the non `#undef'
+ echo '/^[ ]*#[ ]*undef/!b' >>$CONFIG_STATUS
+ # Work around the forget-to-reset-the-flag bug.
+ echo 't clr' >>$CONFIG_STATUS
+ echo ': clr' >>$CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS
+ echo 'CEOF
+ sed -f $tmp/undefs.sed $tmp/in >$tmp/out
+ rm -f $tmp/in
+ mv $tmp/out $tmp/in
+' >>$CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail
+ rm -f conftest.undefs
+ mv conftest.tail conftest.undefs
+done
+rm -f conftest.undefs
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ if test x"$ac_file" = x-; then
+ echo "/* Generated by configure. */" >$tmp/config.h
+ else
+ echo "/* $ac_file. Generated by configure. */" >$tmp/config.h
+ fi
+ cat $tmp/in >>$tmp/config.h
+ rm -f $tmp/in
+ if test x"$ac_file" != x-; then
+ if diff $ac_file $tmp/config.h >/dev/null 2>&1; then
+ { echo "$as_me:$LINENO: $ac_file is unchanged" >&5
+echo "$as_me: $ac_file is unchanged" >&6;}
+ else
+ ac_dir=`(dirname "$ac_file") 2>/dev/null ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ { if $as_mkdir_p; then
+ mkdir -p "$ac_dir"
+ else
+ as_dir="$ac_dir"
+ as_dirs=
+ while test ! -d "$as_dir"; do
+ as_dirs="$as_dir $as_dirs"
+ as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ done
+ test ! -n "$as_dirs" || mkdir $as_dirs
+ fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
+ { (exit 1); exit 1; }; }; }
+
+ rm -f $ac_file
+ mv $tmp/config.h $ac_file
+ fi
+ else
+ cat $tmp/config.h
+ rm -f $tmp/config.h
+ fi
+# Compute $ac_file's index in $config_headers.
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+ case $_am_header in
+ $ac_file | $ac_file:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+done
+echo "timestamp for $ac_file" >`(dirname $ac_file) 2>/dev/null ||
+$as_expr X$ac_file : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X$ac_file : 'X\(//\)[^/]' \| \
+ X$ac_file : 'X\(//\)$' \| \
+ X$ac_file : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X$ac_file |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`/stamp-h$_am_stamp_count
+done
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+#
+# CONFIG_COMMANDS section.
+#
+for ac_file in : $CONFIG_COMMANDS; do test "x$ac_file" = x: && continue
+ ac_dest=`echo "$ac_file" | sed 's,:.*,,'`
+ ac_source=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_dir=`(dirname "$ac_dest") 2>/dev/null ||
+$as_expr X"$ac_dest" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_dest" : 'X\(//\)[^/]' \| \
+ X"$ac_dest" : 'X\(//\)$' \| \
+ X"$ac_dest" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$ac_dest" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ { if $as_mkdir_p; then
+ mkdir -p "$ac_dir"
+ else
+ as_dir="$ac_dir"
+ as_dirs=
+ while test ! -d "$as_dir"; do
+ as_dirs="$as_dir $as_dirs"
+ as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ done
+ test ! -n "$as_dirs" || mkdir $as_dirs
+ fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
+ { (exit 1); exit 1; }; }; }
+
+ ac_builddir=.
+
+if test "$ac_dir" != .; then
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+ ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+ .) # No --srcdir option. We are building in place.
+ ac_srcdir=.
+ if test -z "$ac_top_builddir"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+
+# Do not use `cd foo && pwd` to compute absolute paths, because
+# the directories may not exist.
+case `pwd` in
+.) ac_abs_builddir="$ac_dir";;
+*)
+ case "$ac_dir" in
+ .) ac_abs_builddir=`pwd`;;
+ [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";;
+ *) ac_abs_builddir=`pwd`/"$ac_dir";;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_builddir=${ac_top_builddir}.;;
+*)
+ case ${ac_top_builddir}. in
+ .) ac_abs_top_builddir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;;
+ *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_srcdir=$ac_srcdir;;
+*)
+ case $ac_srcdir in
+ .) ac_abs_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;;
+ *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_srcdir=$ac_top_srcdir;;
+*)
+ case $ac_top_srcdir in
+ .) ac_abs_top_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;;
+ *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;;
+ esac;;
+esac
+
+
+ { echo "$as_me:$LINENO: executing $ac_dest commands" >&5
+echo "$as_me: executing $ac_dest commands" >&6;}
+ case $ac_dest in
+ depfiles ) test x"$AMDEP_TRUE" != x"" || for mf in $CONFIG_FILES; do
+ # Strip MF so we end up with the name of the file.
+ mf=`echo "$mf" | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile or not.
+ # We used to match only the files named `Makefile.in', but
+ # some people rename them; so instead we look at the file content.
+ # Grep'ing the first line is not enough: some people post-process
+ # each Makefile.in and add a new line on top of each file to say so.
+ # So let's grep whole file.
+ if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then
+ dirpart=`(dirname "$mf") 2>/dev/null ||
+$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$mf" : 'X\(//\)[^/]' \| \
+ X"$mf" : 'X\(//\)$' \| \
+ X"$mf" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$mf" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ else
+ continue
+ fi
+ # Extract the definition of DEPDIR, am__include, and am__quote
+ # from the Makefile without running `make'.
+ DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+ test -z "$DEPDIR" && continue
+ am__include=`sed -n 's/^am__include = //p' < "$mf"`
+ test -z "am__include" && continue
+ am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+ # When using ansi2knr, U may be empty or an underscore; expand it
+ U=`sed -n 's/^U = //p' < "$mf"`
+ # Find all dependency output files, they are included files with
+ # $(DEPDIR) in their names. We invoke sed twice because it is the
+ # simplest approach to changing $(DEPDIR) to its actual value in the
+ # expansion.
+ for file in `sed -n "
+ s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
+ # Make sure the directory exists.
+ test -f "$dirpart/$file" && continue
+ fdir=`(dirname "$file") 2>/dev/null ||
+$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$file" : 'X\(//\)[^/]' \| \
+ X"$file" : 'X\(//\)$' \| \
+ X"$file" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ { if $as_mkdir_p; then
+ mkdir -p $dirpart/$fdir
+ else
+ as_dir=$dirpart/$fdir
+ as_dirs=
+ while test ! -d "$as_dir"; do
+ as_dirs="$as_dir $as_dirs"
+ as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ done
+ test ! -n "$as_dirs" || mkdir $as_dirs
+ fi || { { echo "$as_me:$LINENO: error: cannot create directory $dirpart/$fdir" >&5
+echo "$as_me: error: cannot create directory $dirpart/$fdir" >&2;}
+ { (exit 1); exit 1; }; }; }
+
+ # echo "creating $dirpart/$file"
+ echo '# dummy' > "$dirpart/$file"
+ done
+done
+ ;;
+ default-1 )
+ for ac_file in $CONFIG_FILES; do
+ # Support "outfile[:infile[:infile...]]"
+ case "$ac_file" in
+ *:*) ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ esac
+ # PO directories have a Makefile.in generated from Makefile.in.in.
+ case "$ac_file" in */Makefile.in)
+ # Adjust a relative srcdir.
+ ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'`
+ ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`"
+ ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'`
+ # In autoconf-2.13 it is called $ac_given_srcdir.
+ # In autoconf-2.50 it is called $srcdir.
+ test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir"
+ case "$ac_given_srcdir" in
+ .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;;
+ /*) top_srcdir="$ac_given_srcdir" ;;
+ *) top_srcdir="$ac_dots$ac_given_srcdir" ;;
+ esac
+ if test -f "$ac_given_srcdir/$ac_dir/POTFILES.in"; then
+ rm -f "$ac_dir/POTFILES"
+ test -n "$as_me" && echo "$as_me: creating $ac_dir/POTFILES" || echo "creating $ac_dir/POTFILES"
+ cat "$ac_given_srcdir/$ac_dir/POTFILES.in" | sed -e "/^#/d" -e "/^[ ]*\$/d" -e "s,.*, $top_srcdir/& \\\\," | sed -e "\$s/\(.*\) \\\\/\1/" > "$ac_dir/POTFILES"
+ POMAKEFILEDEPS="POTFILES.in"
+ # ALL_LINGUAS, POFILES, GMOFILES, UPDATEPOFILES, DUMMYPOFILES depend
+ # on $ac_dir but don't depend on user-specified configuration
+ # parameters.
+ if test -f "$ac_given_srcdir/$ac_dir/LINGUAS"; then
+ # The LINGUAS file contains the set of available languages.
+ if test -n "$OBSOLETE_ALL_LINGUAS"; then
+ test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete"
+ fi
+ ALL_LINGUAS_=`sed -e "/^#/d" "$ac_given_srcdir/$ac_dir/LINGUAS"`
+ # Hide the ALL_LINGUAS assigment from automake.
+ eval 'ALL_LINGUAS''=$ALL_LINGUAS_'
+ POMAKEFILEDEPS="$POMAKEFILEDEPS LINGUAS"
+ else
+ # The set of available languages was given in configure.in.
+ eval 'ALL_LINGUAS''=$OBSOLETE_ALL_LINGUAS'
+ fi
+ case "$ac_given_srcdir" in
+ .) srcdirpre= ;;
+ *) srcdirpre='$(srcdir)/' ;;
+ esac
+ POFILES=
+ GMOFILES=
+ UPDATEPOFILES=
+ DUMMYPOFILES=
+ for lang in $ALL_LINGUAS; do
+ POFILES="$POFILES $srcdirpre$lang.po"
+ GMOFILES="$GMOFILES $srcdirpre$lang.gmo"
+ UPDATEPOFILES="$UPDATEPOFILES $lang.po-update"
+ DUMMYPOFILES="$DUMMYPOFILES $lang.nop"
+ done
+ # CATALOGS depends on both $ac_dir and the user's LINGUAS
+ # environment variable.
+ INST_LINGUAS=
+ if test -n "$ALL_LINGUAS"; then
+ for presentlang in $ALL_LINGUAS; do
+ useit=no
+ if test "%UNSET%" != "$LINGUAS"; then
+ desiredlanguages="$LINGUAS"
+ else
+ desiredlanguages="$ALL_LINGUAS"
+ fi
+ for desiredlang in $desiredlanguages; do
+ # Use the presentlang catalog if desiredlang is
+ # a. equal to presentlang, or
+ # b. a variant of presentlang (because in this case,
+ # presentlang can be used as a fallback for messages
+ # which are not translated in the desiredlang catalog).
+ case "$desiredlang" in
+ "$presentlang"*) useit=yes;;
+ esac
+ done
+ if test $useit = yes; then
+ INST_LINGUAS="$INST_LINGUAS $presentlang"
+ fi
+ done
+ fi
+ CATALOGS=
+ if test -n "$INST_LINGUAS"; then
+ for lang in $INST_LINGUAS; do
+ CATALOGS="$CATALOGS $lang.gmo"
+ done
+ fi
+ test -n "$as_me" && echo "$as_me: creating $ac_dir/Makefile" || echo "creating $ac_dir/Makefile"
+ sed -e "/^POTFILES =/r $ac_dir/POTFILES" -e "/^# Makevars/r $ac_given_srcdir/$ac_dir/Makevars" -e "s|@POFILES@|$POFILES|g" -e "s|@GMOFILES@|$GMOFILES|g" -e "s|@UPDATEPOFILES@|$UPDATEPOFILES|g" -e "s|@DUMMYPOFILES@|$DUMMYPOFILES|g" -e "s|@CATALOGS@|$CATALOGS|g" -e "s|@POMAKEFILEDEPS@|$POMAKEFILEDEPS|g" "$ac_dir/Makefile.in" > "$ac_dir/Makefile"
+ for f in "$ac_given_srcdir/$ac_dir"/Rules-*; do
+ if test -f "$f"; then
+ case "$f" in
+ *.orig | *.bak | *~) ;;
+ *) cat "$f" >> "$ac_dir/Makefile" ;;
+ esac
+ fi
+ done
+ fi
+ ;;
+ esac
+ done ;;
+ esac
+done
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+{ (exit 0); exit 0; }
+_ACEOF
+chmod +x $CONFIG_STATUS
+ac_clean_files=$ac_clean_files_save
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || { (exit 1); exit 1; }
+fi
+
diff --git a/gold/configure.ac b/gold/configure.ac
new file mode 100644
index 000000000000..5cbaf2c455d9
--- /dev/null
+++ b/gold/configure.ac
@@ -0,0 +1,52 @@
+dnl Process this file with autoconf to produce a configure script.
+
+AC_PREREQ(2.59)
+AC_INIT
+AC_CONFIG_SRCDIR([gold.cc])
+
+AC_CANONICAL_TARGET
+
+AM_INIT_AUTOMAKE(gold, 0.1)
+
+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
+
+AC_C_BIGENDIAN
+
+AC_EXEEXT
+
+AM_BINUTILS_WARNINGS
+
+WARN_CXXFLAGS=`echo ${WARN_CFLAGS} | sed -e 's/-Wstrict-prototypes//' -e 's/-Wmissing-prototypes//'`
+AC_SUBST(WARN_CXXFLAGS)
+
+dnl Force support for large files by default. This may need to be
+dnl host dependent. If build == host, we can check getconf LFS_CFLAGS.
+LFS_CXXFLAGS="-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64"
+AC_SUBST(LFS_CXXFLAGS)
+
+AC_LANG_PUSH(C++)
+
+AC_CHECK_HEADERS(tr1/unordered_set tr1/unordered_map)
+AC_CHECK_HEADERS(ext/hash_map ext/hash_set)
+
+dnl Test whether the compiler can specify a member templates to call.
+AC_COMPILE_IFELSE([
+class c { public: template<int i> void fn(); };
+template<int i> void foo(c cv) { cv.fn<i>(); }
+template void foo<1>(c cv);],
+[AC_DEFINE(HAVE_MEMBER_TEMPLATE_SPECIFICATIONS, [],
+ [Whether the C++ compiler can call a template member with no arguments])])
+
+AC_LANG_POP(C++)
+
+AM_MAINTAINER_MODE
+
+AC_OUTPUT(Makefile testsuite/Makefile po/Makefile.in:po/Make-in)
diff --git a/gold/defstd.cc b/gold/defstd.cc
new file mode 100644
index 000000000000..50a977a3b907
--- /dev/null
+++ b/gold/defstd.cc
@@ -0,0 +1,239 @@
+// defstd.cc -- define standard symbols for gold.
+
+#include "gold.h"
+
+#include "symtab.h"
+#include "defstd.h"
+
+// This is a simple file which defines the standard symbols like
+// "_end".
+
+namespace
+{
+
+using namespace gold;
+
+const Define_symbol_in_section in_section[] =
+{
+ {
+ "__preinit_array_start", // name
+ ".preinit_array", // output_section
+ 0, // value
+ 0, // size
+ elfcpp::STT_NOTYPE, // type
+ elfcpp::STB_GLOBAL, // binding
+ elfcpp::STV_HIDDEN, // visibility
+ 0, // nonvis
+ false, // offset_is_from_end
+ true // only_if_ref
+ },
+ {
+ "__preinit_array_end", // name
+ ".preinit_array", // output_section
+ 0, // value
+ 0, // size
+ elfcpp::STT_NOTYPE, // type
+ elfcpp::STB_GLOBAL, // binding
+ elfcpp::STV_HIDDEN, // visibility
+ 0, // nonvis
+ true, // offset_is_from_end
+ true // only_if_ref
+ },
+ {
+ "__init_array_start", // name
+ ".init_array", // output_section
+ 0, // value
+ 0, // size
+ elfcpp::STT_NOTYPE, // type
+ elfcpp::STB_GLOBAL, // binding
+ elfcpp::STV_HIDDEN, // visibility
+ 0, // nonvis
+ false, // offset_is_from_end
+ true // only_if_ref
+ },
+ {
+ "__init_array_end", // name
+ ".init_array", // output_section
+ 0, // value
+ 0, // size
+ elfcpp::STT_NOTYPE, // type
+ elfcpp::STB_GLOBAL, // binding
+ elfcpp::STV_HIDDEN, // visibility
+ 0, // nonvis
+ true, // offset_is_from_end
+ true // only_if_ref
+ },
+ {
+ "__fini_array_start", // name
+ ".fini_array", // output_section
+ 0, // value
+ 0, // size
+ elfcpp::STT_NOTYPE, // type
+ elfcpp::STB_GLOBAL, // binding
+ elfcpp::STV_HIDDEN, // visibility
+ 0, // nonvis
+ false, // offset_is_from_end
+ true // only_if_ref
+ },
+ {
+ "__fini_array_end", // name
+ ".fini_array", // output_section
+ 0, // value
+ 0, // size
+ elfcpp::STT_NOTYPE, // type
+ elfcpp::STB_GLOBAL, // binding
+ elfcpp::STV_HIDDEN, // visibility
+ 0, // nonvis
+ true, // offset_is_from_end
+ true // only_if_ref
+ }
+};
+
+const int in_section_count = sizeof in_section / sizeof in_section[0];
+
+const Define_symbol_in_segment in_segment[] =
+{
+ {
+ "__executable_start", // name
+ elfcpp::PT_LOAD, // segment_type
+ elfcpp::PF(0), // segment_flags_set
+ elfcpp::PF(0), // segment_flags_clear
+ 0, // value
+ 0, // size
+ elfcpp::STT_NOTYPE, // type
+ elfcpp::STB_GLOBAL, // binding
+ elfcpp::STV_DEFAULT, // visibility
+ 0, // nonvis
+ Symbol::SEGMENT_START, // offset_from_base
+ true // only_if_ref
+ },
+ {
+ "etext", // name
+ elfcpp::PT_LOAD, // segment_type
+ elfcpp::PF_X, // segment_flags_set
+ elfcpp::PF_W, // segment_flags_clear
+ 0, // value
+ 0, // size
+ elfcpp::STT_NOTYPE, // type
+ elfcpp::STB_GLOBAL, // binding
+ elfcpp::STV_DEFAULT, // visibility
+ 0, // nonvis
+ Symbol::SEGMENT_END, // offset_from_base
+ true // only_if_ref
+ },
+ {
+ "_etext", // name
+ elfcpp::PT_LOAD, // segment_type
+ elfcpp::PF_X, // segment_flags_set
+ elfcpp::PF_W, // segment_flags_clear
+ 0, // value
+ 0, // size
+ elfcpp::STT_NOTYPE, // type
+ elfcpp::STB_GLOBAL, // binding
+ elfcpp::STV_DEFAULT, // visibility
+ 0, // nonvis
+ Symbol::SEGMENT_END, // offset_from_base
+ true // only_if_ref
+ },
+ {
+ "__etext", // name
+ elfcpp::PT_LOAD, // segment_type
+ elfcpp::PF_X, // segment_flags_set
+ elfcpp::PF_W, // segment_flags_clear
+ 0, // value
+ 0, // size
+ elfcpp::STT_NOTYPE, // type
+ elfcpp::STB_GLOBAL, // binding
+ elfcpp::STV_DEFAULT, // visibility
+ 0, // nonvis
+ Symbol::SEGMENT_END, // offset_from_base
+ true // only_if_ref
+ },
+ {
+ "_edata", // name
+ elfcpp::PT_LOAD, // segment_type
+ elfcpp::PF_X, // segment_flags_set
+ elfcpp::PF(0), // segment_flags_clear
+ 0, // value
+ 0, // size
+ elfcpp::STT_NOTYPE, // type
+ elfcpp::STB_GLOBAL, // binding
+ elfcpp::STV_DEFAULT, // visibility
+ 0, // nonvis
+ Symbol::SEGMENT_BSS, // offset_from_base
+ false // only_if_ref
+ },
+ {
+ "edata", // name
+ elfcpp::PT_LOAD, // segment_type
+ elfcpp::PF_X, // segment_flags_set
+ elfcpp::PF(0), // segment_flags_clear
+ 0, // value
+ 0, // size
+ elfcpp::STT_NOTYPE, // type
+ elfcpp::STB_GLOBAL, // binding
+ elfcpp::STV_DEFAULT, // visibility
+ 0, // nonvis
+ Symbol::SEGMENT_BSS, // offset_from_base
+ true // only_if_ref
+ },
+ {
+ "__bss_start", // name
+ elfcpp::PT_LOAD, // segment_type
+ elfcpp::PF_X, // segment_flags_set
+ elfcpp::PF(0), // segment_flags_clear
+ 0, // value
+ 0, // size
+ elfcpp::STT_NOTYPE, // type
+ elfcpp::STB_GLOBAL, // binding
+ elfcpp::STV_DEFAULT, // visibility
+ 0, // nonvis
+ Symbol::SEGMENT_BSS, // offset_from_base
+ false // only_if_ref
+ },
+ {
+ "_end", // name
+ elfcpp::PT_LOAD, // segment_type
+ elfcpp::PF_X, // segment_flags_set
+ elfcpp::PF(0), // segment_flags_clear
+ 0, // value
+ 0, // size
+ elfcpp::STT_NOTYPE, // type
+ elfcpp::STB_GLOBAL, // binding
+ elfcpp::STV_DEFAULT, // visibility
+ 0, // nonvis
+ Symbol::SEGMENT_START, // offset_from_base
+ false // only_if_ref
+ },
+ {
+ "end", // name
+ elfcpp::PT_LOAD, // segment_type
+ elfcpp::PF_X, // segment_flags_set
+ elfcpp::PF(0), // segment_flags_clear
+ 0, // value
+ 0, // size
+ elfcpp::STT_NOTYPE, // type
+ elfcpp::STB_GLOBAL, // binding
+ elfcpp::STV_DEFAULT, // visibility
+ 0, // nonvis
+ Symbol::SEGMENT_START, // offset_from_base
+ false // only_if_ref
+ }
+};
+
+const int in_segment_count = sizeof in_segment / sizeof in_segment[0];
+
+} // End anonymous namespace.
+
+namespace gold
+{
+
+void
+define_standard_symbols(Symbol_table* symtab, const Layout* layout,
+ Target* target)
+{
+ symtab->define_symbols(layout, target, in_section_count, in_section);
+ symtab->define_symbols(layout, target, in_segment_count, in_segment);
+}
+
+} // End namespace gold.
diff --git a/gold/defstd.h b/gold/defstd.h
new file mode 100644
index 000000000000..f578b49d76f2
--- /dev/null
+++ b/gold/defstd.h
@@ -0,0 +1,16 @@
+// defstd.h -- define standard symbols for gold -*- C++ -*-
+
+#ifndef GOLD_DEFSTD_H
+#define GOLD_DEFSTD_H
+
+#include "symtab.h"
+
+namespace gold
+{
+
+extern void
+define_standard_symbols(Symbol_table*, const Layout*, Target*);
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_DEFSTD_H)
diff --git a/gold/dirsearch.cc b/gold/dirsearch.cc
new file mode 100644
index 000000000000..d1298d81757d
--- /dev/null
+++ b/gold/dirsearch.cc
@@ -0,0 +1,236 @@
+// dirsearch.cc -- directory searching for gold
+
+#include "gold.h"
+
+#include <cerrno>
+#include <sys/types.h>
+#include <dirent.h>
+
+#include "gold-threads.h"
+#include "dirsearch.h"
+
+namespace
+{
+
+// Read all the files in a directory.
+
+class Dir_cache
+{
+ public:
+ Dir_cache(const char* dirname)
+ : dirname_(dirname), files_()
+ { }
+
+ // Read the files in the directory.
+ void read_files();
+
+ // Return whether a file (a base name) is present in the directory.
+ bool find(const std::string&) const;
+
+ private:
+ // We can not copy this class.
+ Dir_cache(const Dir_cache&);
+ Dir_cache& operator=(const Dir_cache&);
+
+ const char* dirname_;
+ Unordered_set<std::string> files_;
+};
+
+void
+Dir_cache::read_files()
+{
+ DIR* d = opendir(this->dirname_);
+ if (d == NULL)
+ {
+ // We ignore directories which do not exist.
+ if (errno == ENOENT)
+ return;
+
+ char *s = NULL;
+ if (asprintf(&s, _("can not read directory %s"), this->dirname_) < 0)
+ gold::gold_nomem();
+ gold::gold_fatal(s, true);
+ }
+
+ dirent* de;
+ while ((de = readdir(d)) != NULL)
+ this->files_.insert(std::string(de->d_name));
+
+ if (closedir(d) != 0)
+ gold::gold_fatal("closedir failed", true);
+}
+
+bool
+Dir_cache::find(const std::string& basename) const
+{
+ return this->files_.find(basename) != this->files_.end();
+}
+
+// A mapping from directory names to caches. A lock permits
+// concurrent update. There is no lock for read operations--some
+// other mechanism must be used to prevent reads from conflicting with
+// writes.
+
+class Dir_caches
+{
+ public:
+ Dir_caches()
+ : lock_(), caches_()
+ { }
+
+ ~Dir_caches();
+
+ // Add a cache for a directory.
+ void add(const char*);
+
+ // Look up a directory in the cache. This much be locked against
+ // calls to Add.
+ Dir_cache* lookup(const char*) const;
+
+ private:
+ // We can not copy this class.
+ Dir_caches(const Dir_caches&);
+ Dir_caches& operator=(const Dir_caches&);
+
+ typedef Unordered_map<const char*, Dir_cache*> Cache_hash;
+
+ gold::Lock lock_;
+ Cache_hash caches_;
+};
+
+Dir_caches::~Dir_caches()
+{
+ for (Cache_hash::iterator p = this->caches_.begin();
+ p != this->caches_.end();
+ ++p)
+ delete p->second;
+}
+
+void
+Dir_caches::add(const char* dirname)
+{
+ {
+ gold::Hold_lock hl(this->lock_);
+ if (this->lookup(dirname) != NULL)
+ return;
+ }
+
+ Dir_cache* cache = new Dir_cache(dirname);
+
+ cache->read_files();
+
+ {
+ gold::Hold_lock hl(this->lock_);
+
+ std::pair<const char*, Dir_cache*> v(dirname, cache);
+ std::pair<Cache_hash::iterator, bool> p = this->caches_.insert(v);
+ gold_assert(p.second);
+ }
+}
+
+Dir_cache*
+Dir_caches::lookup(const char* dirname) const
+{
+ Cache_hash::const_iterator p = this->caches_.find(dirname);
+ if (p == this->caches_.end())
+ return NULL;
+ return p->second;
+}
+
+// The caches.
+
+Dir_caches caches;
+
+// A Task to read the directory.
+
+class Dir_cache_task : public gold::Task
+{
+ public:
+ Dir_cache_task(const char* dir, gold::Task_token& token)
+ : dir_(dir), token_(token)
+ { }
+
+ Is_runnable_type is_runnable(gold::Workqueue*);
+
+ gold::Task_locker* locks(gold::Workqueue*);
+
+ void run(gold::Workqueue*);
+
+ private:
+ const char* dir_;
+ gold::Task_token& token_;
+};
+
+// We can always run the task to read the directory.
+
+gold::Task::Is_runnable_type
+Dir_cache_task::is_runnable(gold::Workqueue*)
+{
+ return IS_RUNNABLE;
+}
+
+// Return the locks to hold. We use a blocker lock to prevent file
+// lookups from starting until the directory contents have been read.
+
+gold::Task_locker*
+Dir_cache_task::locks(gold::Workqueue* workqueue)
+{
+ return new gold::Task_locker_block(this->token_, workqueue);
+}
+
+// Run the task--read the directory contents.
+
+void
+Dir_cache_task::run(gold::Workqueue*)
+{
+ caches.add(this->dir_);
+}
+
+}
+
+namespace gold
+{
+
+Dirsearch::Dirsearch()
+ : directories_(), token_()
+{
+}
+
+void
+Dirsearch::add(Workqueue* workqueue, const char* d)
+{
+ this->directories_.push_back(d);
+ this->token_.add_blocker();
+ workqueue->queue(new Dir_cache_task(d, this->token_));
+}
+
+void
+Dirsearch::add(Workqueue* workqueue, const General_options::Dir_list& list)
+{
+ for (General_options::Dir_list::const_iterator p = list.begin();
+ p != list.end();
+ ++p)
+ this->add(workqueue, *p);
+}
+
+std::string
+Dirsearch::find(const std::string& n1, const std::string& n2) const
+{
+ gold_assert(!this->token_.is_blocked());
+
+ for (std::list<const char*>::const_iterator p = this->directories_.begin();
+ p != this->directories_.end();
+ ++p)
+ {
+ Dir_cache* pdc = caches.lookup(*p);
+ gold_assert(pdc != NULL);
+ if (pdc->find(n1))
+ return std::string(*p) + '/' + n1;
+ if (!n2.empty() && pdc->find(n2))
+ return std::string(*p) + '/' + n2;
+ }
+
+ return std::string();
+}
+
+} // End namespace gold.
diff --git a/gold/dirsearch.h b/gold/dirsearch.h
new file mode 100644
index 000000000000..8b6ba59bf583
--- /dev/null
+++ b/gold/dirsearch.h
@@ -0,0 +1,57 @@
+// dirsearch.h -- directory searching for gold -*- C++ -*-
+
+#ifndef GOLD_DIRSEARCH_H
+#define GOLD_DIRSEARCH_H
+
+#include <string>
+#include <list>
+
+#include "workqueue.h"
+
+namespace gold
+{
+
+class General_options;
+
+// A simple interface to manage directories to be searched for
+// libraries.
+
+class Dirsearch
+{
+ public:
+ Dirsearch();
+
+ // Add a directory to the search path.
+ void
+ add(Workqueue*, const char*);
+
+ // Add a list of directories to the search path.
+ void
+ add(Workqueue*, const General_options::Dir_list&);
+
+ // Search for a file, giving one or two names to search for (the
+ // second one may be empty). Return a full path name for the file,
+ // or the empty string if it could not be found. This may only be
+ // called if the token is not blocked.
+ std::string
+ find(const std::string&, const std::string& n2 = std::string()) const;
+
+ // Return a reference to the blocker token which controls access.
+ const Task_token&
+ token() const
+ { return this->token_; }
+
+ private:
+ // We can not copy this class.
+ Dirsearch(const Dirsearch&);
+ Dirsearch& operator=(const Dirsearch&);
+
+ // Directories to search.
+ std::list<const char*> directories_;
+ // Blocker token to control access from tasks.
+ Task_token token_;
+};
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_DIRSEARCH_H)
diff --git a/gold/dynobj.cc b/gold/dynobj.cc
new file mode 100644
index 000000000000..1bd5a85e4392
--- /dev/null
+++ b/gold/dynobj.cc
@@ -0,0 +1,1647 @@
+// dynobj.cc -- dynamic object support for gold
+
+#include "gold.h"
+
+#include <vector>
+#include <cstring>
+
+#include "elfcpp.h"
+#include "symtab.h"
+#include "dynobj.h"
+
+namespace gold
+{
+
+// Class Dynobj.
+
+// Return the string to use in a DT_NEEDED entry.
+
+const char*
+Dynobj::soname() const
+{
+ if (!this->soname_.empty())
+ return this->soname_.c_str();
+ return this->name().c_str();
+}
+
+// Class Sized_dynobj.
+
+template<int size, bool big_endian>
+Sized_dynobj<size, big_endian>::Sized_dynobj(
+ const std::string& name,
+ Input_file* input_file,
+ off_t offset,
+ const elfcpp::Ehdr<size, big_endian>& ehdr)
+ : Dynobj(name, input_file, offset),
+ elf_file_(this, ehdr)
+{
+}
+
+// Set up the object.
+
+template<int size, bool big_endian>
+void
+Sized_dynobj<size, big_endian>::setup(
+ const elfcpp::Ehdr<size, big_endian>& ehdr)
+{
+ this->set_target(ehdr.get_e_machine(), size, big_endian,
+ ehdr.get_e_ident()[elfcpp::EI_OSABI],
+ ehdr.get_e_ident()[elfcpp::EI_ABIVERSION]);
+
+ const unsigned int shnum = this->elf_file_.shnum();
+ this->set_shnum(shnum);
+}
+
+// Find the SHT_DYNSYM section and the various version sections, and
+// the dynamic section, given the section headers.
+
+template<int size, bool big_endian>
+void
+Sized_dynobj<size, big_endian>::find_dynsym_sections(
+ const unsigned char* pshdrs,
+ unsigned int* pdynsym_shndx,
+ unsigned int* pversym_shndx,
+ unsigned int* pverdef_shndx,
+ unsigned int* pverneed_shndx,
+ unsigned int* pdynamic_shndx)
+{
+ *pdynsym_shndx = -1U;
+ *pversym_shndx = -1U;
+ *pverdef_shndx = -1U;
+ *pverneed_shndx = -1U;
+ *pdynamic_shndx = -1U;
+
+ const unsigned int shnum = this->shnum();
+ const unsigned char* p = pshdrs;
+ for (unsigned int i = 0; i < shnum; ++i, p += This::shdr_size)
+ {
+ typename This::Shdr shdr(p);
+
+ unsigned int* pi;
+ switch (shdr.get_sh_type())
+ {
+ case elfcpp::SHT_DYNSYM:
+ pi = pdynsym_shndx;
+ break;
+ case elfcpp::SHT_GNU_versym:
+ pi = pversym_shndx;
+ break;
+ case elfcpp::SHT_GNU_verdef:
+ pi = pverdef_shndx;
+ break;
+ case elfcpp::SHT_GNU_verneed:
+ pi = pverneed_shndx;
+ break;
+ case elfcpp::SHT_DYNAMIC:
+ pi = pdynamic_shndx;
+ break;
+ default:
+ pi = NULL;
+ break;
+ }
+
+ if (pi == NULL)
+ continue;
+
+ if (*pi != -1U)
+ {
+ fprintf(stderr,
+ _("%s: %s: unexpected duplicate type %u section: %u, %u\n"),
+ program_name, this->name().c_str(), shdr.get_sh_type(),
+ *pi, i);
+ gold_exit(false);
+ }
+
+ *pi = i;
+ }
+}
+
+// Read the contents of section SHNDX. PSHDRS points to the section
+// headers. TYPE is the expected section type. LINK is the expected
+// section link. Store the data in *VIEW and *VIEW_SIZE. The
+// section's sh_info field is stored in *VIEW_INFO.
+
+template<int size, bool big_endian>
+void
+Sized_dynobj<size, big_endian>::read_dynsym_section(
+ const unsigned char* pshdrs,
+ unsigned int shndx,
+ elfcpp::SHT type,
+ unsigned int link,
+ File_view** view,
+ off_t* view_size,
+ unsigned int* view_info)
+{
+ if (shndx == -1U)
+ {
+ *view = NULL;
+ *view_size = 0;
+ *view_info = 0;
+ return;
+ }
+
+ typename This::Shdr shdr(pshdrs + shndx * This::shdr_size);
+
+ gold_assert(shdr.get_sh_type() == type);
+
+ if (shdr.get_sh_link() != link)
+ {
+ fprintf(stderr,
+ _("%s: %s: unexpected link in section %u header: %u != %u\n"),
+ program_name, this->name().c_str(), shndx,
+ shdr.get_sh_link(), link);
+ gold_exit(false);
+ }
+
+ *view = this->get_lasting_view(shdr.get_sh_offset(), shdr.get_sh_size());
+ *view_size = shdr.get_sh_size();
+ *view_info = shdr.get_sh_info();
+}
+
+// Set the soname field if this shared object has a DT_SONAME tag.
+// PSHDRS points to the section headers. DYNAMIC_SHNDX is the section
+// index of the SHT_DYNAMIC section. STRTAB_SHNDX, STRTAB, and
+// STRTAB_SIZE are the section index and contents of a string table
+// which may be the one associated with the SHT_DYNAMIC section.
+
+template<int size, bool big_endian>
+void
+Sized_dynobj<size, big_endian>::set_soname(const unsigned char* pshdrs,
+ unsigned int dynamic_shndx,
+ unsigned int strtab_shndx,
+ const unsigned char* strtabu,
+ off_t strtab_size)
+{
+ typename This::Shdr dynamicshdr(pshdrs + dynamic_shndx * This::shdr_size);
+ gold_assert(dynamicshdr.get_sh_type() == elfcpp::SHT_DYNAMIC);
+
+ const off_t dynamic_size = dynamicshdr.get_sh_size();
+ const unsigned char* pdynamic = this->get_view(dynamicshdr.get_sh_offset(),
+ dynamic_size);
+
+ const unsigned int link = dynamicshdr.get_sh_link();
+ if (link != strtab_shndx)
+ {
+ if (link >= this->shnum())
+ {
+ fprintf(stderr,
+ _("%s: %s: DYNAMIC section %u link out of range: %u\n"),
+ program_name, this->name().c_str(),
+ dynamic_shndx, link);
+ gold_exit(false);
+ }
+
+ typename This::Shdr strtabshdr(pshdrs + link * This::shdr_size);
+ if (strtabshdr.get_sh_type() != elfcpp::SHT_STRTAB)
+ {
+ fprintf(stderr,
+ _("%s: %s: DYNAMIC section %u link %u is not a strtab\n"),
+ program_name, this->name().c_str(),
+ dynamic_shndx, link);
+ gold_exit(false);
+ }
+
+ strtab_size = strtabshdr.get_sh_size();
+ strtabu = this->get_view(strtabshdr.get_sh_offset(), strtab_size);
+ }
+
+ for (const unsigned char* p = pdynamic;
+ p < pdynamic + dynamic_size;
+ p += This::dyn_size)
+ {
+ typename This::Dyn dyn(p);
+
+ if (dyn.get_d_tag() == elfcpp::DT_SONAME)
+ {
+ off_t val = dyn.get_d_val();
+ if (val >= strtab_size)
+ {
+ fprintf(stderr,
+ _("%s: %s: DT_SONAME value out of range: "
+ "%lld >= %lld\n"),
+ program_name, this->name().c_str(),
+ static_cast<long long>(val),
+ static_cast<long long>(strtab_size));
+ gold_exit(false);
+ }
+
+ const char* strtab = reinterpret_cast<const char*>(strtabu);
+ this->set_soname_string(strtab + val);
+ return;
+ }
+
+ if (dyn.get_d_tag() == elfcpp::DT_NULL)
+ return;
+ }
+
+ fprintf(stderr, _("%s: %s: missing DT_NULL in dynamic segment\n"),
+ program_name, this->name().c_str());
+ gold_exit(false);
+}
+
+// Read the symbols and sections from a dynamic object. We read the
+// dynamic symbols, not the normal symbols.
+
+template<int size, bool big_endian>
+void
+Sized_dynobj<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
+{
+ this->read_section_data(&this->elf_file_, sd);
+
+ const unsigned char* const pshdrs = sd->section_headers->data();
+
+ unsigned int dynsym_shndx;
+ unsigned int versym_shndx;
+ unsigned int verdef_shndx;
+ unsigned int verneed_shndx;
+ unsigned int dynamic_shndx;
+ this->find_dynsym_sections(pshdrs, &dynsym_shndx, &versym_shndx,
+ &verdef_shndx, &verneed_shndx, &dynamic_shndx);
+
+ unsigned int strtab_shndx = -1U;
+
+ if (dynsym_shndx == -1U)
+ {
+ sd->symbols = NULL;
+ sd->symbols_size = 0;
+ sd->symbol_names = NULL;
+ sd->symbol_names_size = 0;
+ }
+ else
+ {
+ // Get the dynamic symbols.
+ typename This::Shdr dynsymshdr(pshdrs + dynsym_shndx * This::shdr_size);
+ gold_assert(dynsymshdr.get_sh_type() == elfcpp::SHT_DYNSYM);
+
+ sd->symbols = this->get_lasting_view(dynsymshdr.get_sh_offset(),
+ dynsymshdr.get_sh_size());
+ sd->symbols_size = dynsymshdr.get_sh_size();
+
+ // Get the symbol names.
+ strtab_shndx = dynsymshdr.get_sh_link();
+ if (strtab_shndx >= this->shnum())
+ {
+ fprintf(stderr,
+ _("%s: %s: invalid dynamic symbol table name index: %u\n"),
+ program_name, this->name().c_str(), strtab_shndx);
+ gold_exit(false);
+ }
+ typename This::Shdr strtabshdr(pshdrs + strtab_shndx * This::shdr_size);
+ if (strtabshdr.get_sh_type() != elfcpp::SHT_STRTAB)
+ {
+ fprintf(stderr,
+ _("%s: %s: dynamic symbol table name section "
+ "has wrong type: %u\n"),
+ program_name, this->name().c_str(),
+ static_cast<unsigned int>(strtabshdr.get_sh_type()));
+ gold_exit(false);
+ }
+
+ sd->symbol_names = this->get_lasting_view(strtabshdr.get_sh_offset(),
+ strtabshdr.get_sh_size());
+ sd->symbol_names_size = strtabshdr.get_sh_size();
+
+ // Get the version information.
+
+ unsigned int dummy;
+ this->read_dynsym_section(pshdrs, versym_shndx, elfcpp::SHT_GNU_versym,
+ dynsym_shndx, &sd->versym, &sd->versym_size,
+ &dummy);
+
+ // We require that the version definition and need section link
+ // to the same string table as the dynamic symbol table. This
+ // is not a technical requirement, but it always happens in
+ // practice. We could change this if necessary.
+
+ this->read_dynsym_section(pshdrs, verdef_shndx, elfcpp::SHT_GNU_verdef,
+ strtab_shndx, &sd->verdef, &sd->verdef_size,
+ &sd->verdef_info);
+
+ this->read_dynsym_section(pshdrs, verneed_shndx, elfcpp::SHT_GNU_verneed,
+ strtab_shndx, &sd->verneed, &sd->verneed_size,
+ &sd->verneed_info);
+ }
+
+ // Read the SHT_DYNAMIC section to find whether this shared object
+ // has a DT_SONAME tag. This doesn't really have anything to do
+ // with reading the symbols, but this is a convenient place to do
+ // it.
+ if (dynamic_shndx != -1U)
+ this->set_soname(pshdrs, dynamic_shndx, strtab_shndx,
+ (sd->symbol_names == NULL
+ ? NULL
+ : sd->symbol_names->data()),
+ sd->symbol_names_size);
+}
+
+// Lay out the input sections for a dynamic object. We don't want to
+// include sections from a dynamic object, so all that we actually do
+// here is check for .gnu.warning sections.
+
+template<int size, bool big_endian>
+void
+Sized_dynobj<size, big_endian>::do_layout(const General_options&,
+ Symbol_table* symtab,
+ Layout*,
+ Read_symbols_data* sd)
+{
+ const unsigned int shnum = this->shnum();
+ if (shnum == 0)
+ return;
+
+ // Get the section headers.
+ const unsigned char* pshdrs = sd->section_headers->data();
+
+ // Get the section names.
+ const unsigned char* pnamesu = sd->section_names->data();
+ const char* pnames = reinterpret_cast<const char*>(pnamesu);
+
+ // Skip the first, dummy, section.
+ pshdrs += This::shdr_size;
+ for (unsigned int i = 1; i < shnum; ++i, pshdrs += This::shdr_size)
+ {
+ typename This::Shdr shdr(pshdrs);
+
+ if (shdr.get_sh_name() >= sd->section_names_size)
+ {
+ fprintf(stderr,
+ _("%s: %s: bad section name offset for section %u: %lu\n"),
+ program_name, this->name().c_str(), i,
+ static_cast<unsigned long>(shdr.get_sh_name()));
+ gold_exit(false);
+ }
+
+ const char* name = pnames + shdr.get_sh_name();
+
+ this->handle_gnu_warning_section(name, i, symtab);
+ }
+
+ delete sd->section_headers;
+ sd->section_headers = NULL;
+ delete sd->section_names;
+ sd->section_names = NULL;
+}
+
+// Add an entry to the vector mapping version numbers to version
+// strings.
+
+template<int size, bool big_endian>
+void
+Sized_dynobj<size, big_endian>::set_version_map(
+ Version_map* version_map,
+ unsigned int ndx,
+ const char* name) const
+{
+ if (ndx >= version_map->size())
+ version_map->resize(ndx + 1);
+ if ((*version_map)[ndx] != NULL)
+ {
+ fprintf(stderr, _("%s: %s: duplicate definition for version %u\n"),
+ program_name, this->name().c_str(), ndx);
+ gold_exit(false);
+ }
+ (*version_map)[ndx] = name;
+}
+
+// Add mappings for the version definitions to VERSION_MAP.
+
+template<int size, bool big_endian>
+void
+Sized_dynobj<size, big_endian>::make_verdef_map(
+ Read_symbols_data* sd,
+ Version_map* version_map) const
+{
+ if (sd->verdef == NULL)
+ return;
+
+ const char* names = reinterpret_cast<const char*>(sd->symbol_names->data());
+ off_t names_size = sd->symbol_names_size;
+
+ const unsigned char* pverdef = sd->verdef->data();
+ off_t verdef_size = sd->verdef_size;
+ const unsigned int count = sd->verdef_info;
+
+ const unsigned char* p = pverdef;
+ for (unsigned int i = 0; i < count; ++i)
+ {
+ elfcpp::Verdef<size, big_endian> verdef(p);
+
+ if (verdef.get_vd_version() != elfcpp::VER_DEF_CURRENT)
+ {
+ fprintf(stderr, _("%s: %s: unexpected verdef version %u\n"),
+ program_name, this->name().c_str(), verdef.get_vd_version());
+ gold_exit(false);
+ }
+
+ const unsigned int vd_ndx = verdef.get_vd_ndx();
+
+ // The GNU linker clears the VERSYM_HIDDEN bit. I'm not
+ // sure why.
+
+ // The first Verdaux holds the name of this version. Subsequent
+ // ones are versions that this one depends upon, which we don't
+ // care about here.
+ const unsigned int vd_cnt = verdef.get_vd_cnt();
+ if (vd_cnt < 1)
+ {
+ fprintf(stderr, _("%s: %s: verdef vd_cnt field too small: %u\n"),
+ program_name, this->name().c_str(), vd_cnt);
+ gold_exit(false);
+ }
+
+ const unsigned int vd_aux = verdef.get_vd_aux();
+ if ((p - pverdef) + vd_aux >= verdef_size)
+ {
+ fprintf(stderr,
+ _("%s: %s: verdef vd_aux field out of range: %u\n"),
+ program_name, this->name().c_str(), vd_aux);
+ gold_exit(false);
+ }
+
+ const unsigned char* pvda = p + vd_aux;
+ elfcpp::Verdaux<size, big_endian> verdaux(pvda);
+
+ const unsigned int vda_name = verdaux.get_vda_name();
+ if (vda_name >= names_size)
+ {
+ fprintf(stderr,
+ _("%s: %s: verdaux vda_name field out of range: %u\n"),
+ program_name, this->name().c_str(), vda_name);
+ gold_exit(false);
+ }
+
+ this->set_version_map(version_map, vd_ndx, names + vda_name);
+
+ const unsigned int vd_next = verdef.get_vd_next();
+ if ((p - pverdef) + vd_next >= verdef_size)
+ {
+ fprintf(stderr,
+ _("%s: %s: verdef vd_next field out of range: %u\n"),
+ program_name, this->name().c_str(), vd_next);
+ gold_exit(false);
+ }
+
+ p += vd_next;
+ }
+}
+
+// Add mappings for the required versions to VERSION_MAP.
+
+template<int size, bool big_endian>
+void
+Sized_dynobj<size, big_endian>::make_verneed_map(
+ Read_symbols_data* sd,
+ Version_map* version_map) const
+{
+ if (sd->verneed == NULL)
+ return;
+
+ const char* names = reinterpret_cast<const char*>(sd->symbol_names->data());
+ off_t names_size = sd->symbol_names_size;
+
+ const unsigned char* pverneed = sd->verneed->data();
+ const off_t verneed_size = sd->verneed_size;
+ const unsigned int count = sd->verneed_info;
+
+ const unsigned char* p = pverneed;
+ for (unsigned int i = 0; i < count; ++i)
+ {
+ elfcpp::Verneed<size, big_endian> verneed(p);
+
+ if (verneed.get_vn_version() != elfcpp::VER_NEED_CURRENT)
+ {
+ fprintf(stderr, _("%s: %s: unexpected verneed version %u\n"),
+ program_name, this->name().c_str(),
+ verneed.get_vn_version());
+ gold_exit(false);
+ }
+
+ const unsigned int vn_aux = verneed.get_vn_aux();
+
+ if ((p - pverneed) + vn_aux >= verneed_size)
+ {
+ fprintf(stderr,
+ _("%s: %s: verneed vn_aux field out of range: %u\n"),
+ program_name, this->name().c_str(), vn_aux);
+ gold_exit(false);
+ }
+
+ const unsigned int vn_cnt = verneed.get_vn_cnt();
+ const unsigned char* pvna = p + vn_aux;
+ for (unsigned int j = 0; j < vn_cnt; ++j)
+ {
+ elfcpp::Vernaux<size, big_endian> vernaux(pvna);
+
+ const unsigned int vna_name = vernaux.get_vna_name();
+ if (vna_name >= names_size)
+ {
+ fprintf(stderr,
+ _("%s: %s: vernaux vna_name field "
+ "out of range: %u\n"),
+ program_name, this->name().c_str(), vna_name);
+ gold_exit(false);
+ }
+
+ this->set_version_map(version_map, vernaux.get_vna_other(),
+ names + vna_name);
+
+ const unsigned int vna_next = vernaux.get_vna_next();
+ if ((pvna - pverneed) + vna_next >= verneed_size)
+ {
+ fprintf(stderr,
+ _("%s: %s: verneed vna_next field "
+ "out of range: %u\n"),
+ program_name, this->name().c_str(), vna_next);
+ gold_exit(false);
+ }
+
+ pvna += vna_next;
+ }
+
+ const unsigned int vn_next = verneed.get_vn_next();
+ if ((p - pverneed) + vn_next >= verneed_size)
+ {
+ fprintf(stderr,
+ _("%s: %s: verneed vn_next field out of range: %u\n"),
+ program_name, this->name().c_str(), vn_next);
+ gold_exit(false);
+ }
+
+ p += vn_next;
+ }
+}
+
+// Create a vector mapping version numbers to version strings.
+
+template<int size, bool big_endian>
+void
+Sized_dynobj<size, big_endian>::make_version_map(
+ Read_symbols_data* sd,
+ Version_map* version_map) const
+{
+ if (sd->verdef == NULL && sd->verneed == NULL)
+ return;
+
+ // A guess at the maximum version number we will see. If this is
+ // wrong we will be less efficient but still correct.
+ version_map->reserve(sd->verdef_info + sd->verneed_info * 10);
+
+ this->make_verdef_map(sd, version_map);
+ this->make_verneed_map(sd, version_map);
+}
+
+// Add the dynamic symbols to the symbol table.
+
+template<int size, bool big_endian>
+void
+Sized_dynobj<size, big_endian>::do_add_symbols(Symbol_table* symtab,
+ Read_symbols_data* sd)
+{
+ if (sd->symbols == NULL)
+ {
+ gold_assert(sd->symbol_names == NULL);
+ gold_assert(sd->versym == NULL && sd->verdef == NULL
+ && sd->verneed == NULL);
+ return;
+ }
+
+ const int sym_size = This::sym_size;
+ const size_t symcount = sd->symbols_size / sym_size;
+ if (symcount * sym_size != sd->symbols_size)
+ {
+ fprintf(stderr,
+ _("%s: %s: size of dynamic symbols is not "
+ "multiple of symbol size\n"),
+ program_name, this->name().c_str());
+ gold_exit(false);
+ }
+
+ Version_map version_map;
+ this->make_version_map(sd, &version_map);
+
+ const char* sym_names =
+ reinterpret_cast<const char*>(sd->symbol_names->data());
+ symtab->add_from_dynobj(this, sd->symbols->data(), symcount,
+ sym_names, sd->symbol_names_size,
+ (sd->versym == NULL
+ ? NULL
+ : sd->versym->data()),
+ sd->versym_size,
+ &version_map);
+
+ delete sd->symbols;
+ sd->symbols = NULL;
+ delete sd->symbol_names;
+ sd->symbol_names = NULL;
+ if (sd->versym != NULL)
+ {
+ delete sd->versym;
+ sd->versym = NULL;
+ }
+ if (sd->verdef != NULL)
+ {
+ delete sd->verdef;
+ sd->verdef = NULL;
+ }
+ if (sd->verneed != NULL)
+ {
+ delete sd->verneed;
+ sd->verneed = NULL;
+ }
+}
+
+// Given a vector of hash codes, compute the number of hash buckets to
+// use.
+
+unsigned int
+Dynobj::compute_bucket_count(const std::vector<uint32_t>& hashcodes,
+ bool for_gnu_hash_table)
+{
+ // FIXME: Implement optional hash table optimization.
+
+ // Array used to determine the number of hash table buckets to use
+ // based on the number of symbols there are. If there are fewer
+ // than 3 symbols we use 1 bucket, fewer than 17 symbols we use 3
+ // buckets, fewer than 37 we use 17 buckets, and so forth. We never
+ // use more than 32771 buckets. This is straight from the old GNU
+ // linker.
+ static const unsigned int buckets[] =
+ {
+ 1, 3, 17, 37, 67, 97, 131, 197, 263, 521, 1031, 2053, 4099, 8209,
+ 16411, 32771
+ };
+ const int buckets_count = sizeof buckets / sizeof buckets[0];
+
+ unsigned int symcount = hashcodes.size();
+ unsigned int ret = 1;
+ for (int i = 0; i < buckets_count; ++i)
+ {
+ if (symcount < buckets[i])
+ break;
+ ret = buckets[i];
+ }
+
+ if (for_gnu_hash_table && ret < 2)
+ ret = 2;
+
+ return ret;
+}
+
+// The standard ELF hash function. This hash function must not
+// change, as the dynamic linker uses it also.
+
+uint32_t
+Dynobj::elf_hash(const char* name)
+{
+ const unsigned char* nameu = reinterpret_cast<const unsigned char*>(name);
+ uint32_t h = 0;
+ unsigned char c;
+ while ((c = *nameu++) != '\0')
+ {
+ h = (h << 4) + c;
+ uint32_t g = h & 0xf0000000;
+ if (g != 0)
+ {
+ h ^= g >> 24;
+ // The ELF ABI says h &= ~g, but using xor is equivalent in
+ // this case (since g was set from h) and may save one
+ // instruction.
+ h ^= g;
+ }
+ }
+ return h;
+}
+
+// Create a standard ELF hash table, setting *PPHASH and *PHASHLEN.
+// DYNSYMS is a vector with all the global dynamic symbols.
+// LOCAL_DYNSYM_COUNT is the number of local symbols in the dynamic
+// symbol table.
+
+void
+Dynobj::create_elf_hash_table(const Target* target,
+ const std::vector<Symbol*>& dynsyms,
+ unsigned int local_dynsym_count,
+ unsigned char** pphash,
+ unsigned int* phashlen)
+{
+ unsigned int dynsym_count = dynsyms.size();
+
+ // Get the hash values for all the symbols.
+ std::vector<uint32_t> dynsym_hashvals(dynsym_count);
+ for (unsigned int i = 0; i < dynsym_count; ++i)
+ dynsym_hashvals[i] = Dynobj::elf_hash(dynsyms[i]->name());
+
+ const unsigned int bucketcount =
+ Dynobj::compute_bucket_count(dynsym_hashvals, false);
+
+ std::vector<uint32_t> bucket(bucketcount);
+ std::vector<uint32_t> chain(local_dynsym_count + dynsym_count);
+
+ for (unsigned int i = 0; i < dynsym_count; ++i)
+ {
+ unsigned int dynsym_index = dynsyms[i]->dynsym_index();
+ unsigned int bucketpos = dynsym_hashvals[i] % bucketcount;
+ chain[dynsym_index] = bucket[bucketpos];
+ bucket[bucketpos] = dynsym_index;
+ }
+
+ unsigned int hashlen = ((2
+ + bucketcount
+ + local_dynsym_count
+ + dynsym_count)
+ * 4);
+ unsigned char* phash = new unsigned char[hashlen];
+
+ if (target->is_big_endian())
+ Dynobj::sized_create_elf_hash_table<true>(bucket, chain, phash, hashlen);
+ else
+ Dynobj::sized_create_elf_hash_table<false>(bucket, chain, phash, hashlen);
+
+ *pphash = phash;
+ *phashlen = hashlen;
+}
+
+// Fill in an ELF hash table.
+
+template<bool big_endian>
+void
+Dynobj::sized_create_elf_hash_table(const std::vector<uint32_t>& bucket,
+ const std::vector<uint32_t>& chain,
+ unsigned char* phash,
+ unsigned int hashlen)
+{
+ unsigned char* p = phash;
+
+ const unsigned int bucketcount = bucket.size();
+ const unsigned int chaincount = chain.size();
+
+ elfcpp::Swap<32, big_endian>::writeval(p, bucketcount);
+ p += 4;
+ elfcpp::Swap<32, big_endian>::writeval(p, chaincount);
+ p += 4;
+
+ for (unsigned int i = 0; i < bucketcount; ++i)
+ {
+ elfcpp::Swap<32, big_endian>::writeval(p, bucket[i]);
+ p += 4;
+ }
+
+ for (unsigned int i = 0; i < chaincount; ++i)
+ {
+ elfcpp::Swap<32, big_endian>::writeval(p, chain[i]);
+ p += 4;
+ }
+
+ gold_assert(static_cast<unsigned int>(p - phash) == hashlen);
+}
+
+// The hash function used for the GNU hash table. This hash function
+// must not change, as the dynamic linker uses it also.
+
+uint32_t
+Dynobj::gnu_hash(const char* name)
+{
+ const unsigned char* nameu = reinterpret_cast<const unsigned char*>(name);
+ uint32_t h = 5381;
+ unsigned char c;
+ while ((c = *nameu++) != '\0')
+ h = (h << 5) + h + c;
+ return h;
+}
+
+// Create a GNU hash table, setting *PPHASH and *PHASHLEN. GNU hash
+// tables are an extension to ELF which are recognized by the GNU
+// dynamic linker. They are referenced using dynamic tag DT_GNU_HASH.
+// TARGET is the target. DYNSYMS is a vector with all the global
+// symbols which will be going into the dynamic symbol table.
+// LOCAL_DYNSYM_COUNT is the number of local symbols in the dynamic
+// symbol table.
+
+void
+Dynobj::create_gnu_hash_table(const Target* target,
+ const std::vector<Symbol*>& dynsyms,
+ unsigned int local_dynsym_count,
+ unsigned char** pphash,
+ unsigned int* phashlen)
+{
+ const unsigned int count = dynsyms.size();
+
+ // Sort the dynamic symbols into two vectors. Symbols which we do
+ // not want to put into the hash table we store into
+ // UNHASHED_DYNSYMS. Symbols which we do want to store we put into
+ // HASHED_DYNSYMS. DYNSYM_HASHVALS is parallel to HASHED_DYNSYMS,
+ // and records the hash codes.
+
+ std::vector<Symbol*> unhashed_dynsyms;
+ unhashed_dynsyms.reserve(count);
+
+ std::vector<Symbol*> hashed_dynsyms;
+ hashed_dynsyms.reserve(count);
+
+ std::vector<uint32_t> dynsym_hashvals;
+ dynsym_hashvals.reserve(count);
+
+ for (unsigned int i = 0; i < count; ++i)
+ {
+ Symbol* sym = dynsyms[i];
+
+ // FIXME: Should put on unhashed_dynsyms if the symbol is
+ // hidden.
+ if (sym->is_undefined())
+ unhashed_dynsyms.push_back(sym);
+ else
+ {
+ hashed_dynsyms.push_back(sym);
+ dynsym_hashvals.push_back(Dynobj::gnu_hash(sym->name()));
+ }
+ }
+
+ // Put the unhashed symbols at the start of the global portion of
+ // the dynamic symbol table.
+ const unsigned int unhashed_count = unhashed_dynsyms.size();
+ unsigned int unhashed_dynsym_index = local_dynsym_count;
+ for (unsigned int i = 0; i < unhashed_count; ++i)
+ {
+ unhashed_dynsyms[i]->set_dynsym_index(unhashed_dynsym_index);
+ ++unhashed_dynsym_index;
+ }
+
+ // For the actual data generation we call out to a templatized
+ // function.
+ int size = target->get_size();
+ bool big_endian = target->is_big_endian();
+ if (size == 32)
+ {
+ if (big_endian)
+ Dynobj::sized_create_gnu_hash_table<32, true>(hashed_dynsyms,
+ dynsym_hashvals,
+ unhashed_dynsym_index,
+ pphash,
+ phashlen);
+ else
+ Dynobj::sized_create_gnu_hash_table<32, false>(hashed_dynsyms,
+ dynsym_hashvals,
+ unhashed_dynsym_index,
+ pphash,
+ phashlen);
+ }
+ else if (size == 64)
+ {
+ if (big_endian)
+ Dynobj::sized_create_gnu_hash_table<64, true>(hashed_dynsyms,
+ dynsym_hashvals,
+ unhashed_dynsym_index,
+ pphash,
+ phashlen);
+ else
+ Dynobj::sized_create_gnu_hash_table<64, false>(hashed_dynsyms,
+ dynsym_hashvals,
+ unhashed_dynsym_index,
+ pphash,
+ phashlen);
+ }
+ else
+ gold_unreachable();
+}
+
+// Create the actual data for a GNU hash table. This is just a copy
+// of the code from the old GNU linker.
+
+template<int size, bool big_endian>
+void
+Dynobj::sized_create_gnu_hash_table(
+ const std::vector<Symbol*>& hashed_dynsyms,
+ const std::vector<uint32_t>& dynsym_hashvals,
+ unsigned int unhashed_dynsym_count,
+ unsigned char** pphash,
+ unsigned int* phashlen)
+{
+ if (hashed_dynsyms.empty())
+ {
+ // Special case for the empty hash table.
+ unsigned int hashlen = 5 * 4 + size / 8;
+ unsigned char* phash = new unsigned char[hashlen];
+ // One empty bucket.
+ elfcpp::Swap<32, big_endian>::writeval(phash, 1);
+ // Symbol index above unhashed symbols.
+ elfcpp::Swap<32, big_endian>::writeval(phash + 4, unhashed_dynsym_count);
+ // One word for bitmask.
+ elfcpp::Swap<32, big_endian>::writeval(phash + 8, 1);
+ // Only bloom filter.
+ elfcpp::Swap<32, big_endian>::writeval(phash + 12, 0);
+ // No valid hashes.
+ elfcpp::Swap<size, big_endian>::writeval(phash + 16, 0);
+ // No hashes in only bucket.
+ elfcpp::Swap<32, big_endian>::writeval(phash + 16 + size / 8, 0);
+
+ *phashlen = hashlen;
+ *pphash = phash;
+
+ return;
+ }
+
+ const unsigned int bucketcount =
+ Dynobj::compute_bucket_count(dynsym_hashvals, true);
+
+ const unsigned int nsyms = hashed_dynsyms.size();
+
+ uint32_t maskbitslog2 = 1;
+ uint32_t x = nsyms >> 1;
+ while (x != 0)
+ {
+ ++maskbitslog2;
+ x >>= 1;
+ }
+ if (maskbitslog2 < 3)
+ maskbitslog2 = 5;
+ else if (((1U << (maskbitslog2 - 2)) & nsyms) != 0)
+ maskbitslog2 += 3;
+ else
+ maskbitslog2 += 2;
+
+ uint32_t shift1;
+ if (size == 32)
+ shift1 = 5;
+ else
+ {
+ if (maskbitslog2 == 5)
+ maskbitslog2 = 6;
+ shift1 = 6;
+ }
+ uint32_t mask = (1U << shift1) - 1U;
+ uint32_t shift2 = maskbitslog2;
+ uint32_t maskbits = 1U << maskbitslog2;
+ uint32_t maskwords = 1U << (maskbitslog2 - shift1);
+
+ typedef typename elfcpp::Elf_types<size>::Elf_WXword Word;
+ std::vector<Word> bitmask(maskwords);
+ std::vector<uint32_t> counts(bucketcount);
+ std::vector<uint32_t> indx(bucketcount);
+ uint32_t symindx = unhashed_dynsym_count;
+
+ // Count the number of times each hash bucket is used.
+ for (unsigned int i = 0; i < nsyms; ++i)
+ ++counts[dynsym_hashvals[i] % bucketcount];
+
+ unsigned int cnt = symindx;
+ for (unsigned int i = 0; i < bucketcount; ++i)
+ {
+ indx[i] = cnt;
+ cnt += counts[i];
+ }
+
+ unsigned int hashlen = (4 + bucketcount + nsyms) * 4;
+ hashlen += maskbits / 8;
+ unsigned char* phash = new unsigned char[hashlen];
+
+ elfcpp::Swap<32, big_endian>::writeval(phash, bucketcount);
+ elfcpp::Swap<32, big_endian>::writeval(phash + 4, symindx);
+ elfcpp::Swap<32, big_endian>::writeval(phash + 8, maskwords);
+ elfcpp::Swap<32, big_endian>::writeval(phash + 12, shift2);
+
+ unsigned char* p = phash + 16 + maskbits / 8;
+ for (unsigned int i = 0; i < bucketcount; ++i)
+ {
+ if (counts[i] == 0)
+ elfcpp::Swap<32, big_endian>::writeval(p, 0);
+ else
+ elfcpp::Swap<32, big_endian>::writeval(p, indx[i]);
+ p += 4;
+ }
+
+ for (unsigned int i = 0; i < nsyms; ++i)
+ {
+ Symbol* sym = hashed_dynsyms[i];
+ uint32_t hashval = dynsym_hashvals[i];
+
+ unsigned int bucket = hashval % bucketcount;
+ unsigned int val = ((hashval >> shift1)
+ & ((maskbits >> shift1) - 1));
+ bitmask[val] |= (static_cast<Word>(1U)) << (hashval & mask);
+ bitmask[val] |= (static_cast<Word>(1U)) << ((hashval >> shift2) & mask);
+ val = hashval & ~ 1U;
+ if (counts[bucket] == 1)
+ {
+ // Last element terminates the chain.
+ val |= 1;
+ }
+ elfcpp::Swap<32, big_endian>::writeval(p + (indx[bucket] - symindx) * 4,
+ val);
+ --counts[bucket];
+
+ sym->set_dynsym_index(indx[bucket]);
+ ++indx[bucket];
+ }
+
+ p = phash + 16;
+ for (unsigned int i = 0; i < maskwords; ++i)
+ {
+ elfcpp::Swap<size, big_endian>::writeval(p, bitmask[i]);
+ p += size / 8;
+ }
+
+ *phashlen = hashlen;
+ *pphash = phash;
+}
+
+// Verdef methods.
+
+// Write this definition to a buffer for the output section.
+
+template<int size, bool big_endian>
+unsigned char*
+Verdef::write(const Stringpool* dynpool, bool is_last, unsigned char* pb
+ ACCEPT_SIZE_ENDIAN) const
+{
+ const int verdef_size = elfcpp::Elf_sizes<size>::verdef_size;
+ const int verdaux_size = elfcpp::Elf_sizes<size>::verdaux_size;
+
+ elfcpp::Verdef_write<size, big_endian> vd(pb);
+ vd.set_vd_version(elfcpp::VER_DEF_CURRENT);
+ vd.set_vd_flags((this->is_base_ ? elfcpp::VER_FLG_BASE : 0)
+ | (this->is_weak_ ? elfcpp::VER_FLG_WEAK : 0));
+ vd.set_vd_ndx(this->index());
+ vd.set_vd_cnt(1 + this->deps_.size());
+ vd.set_vd_hash(Dynobj::elf_hash(this->name()));
+ vd.set_vd_aux(verdef_size);
+ vd.set_vd_next(is_last
+ ? 0
+ : verdef_size + (1 + this->deps_.size()) * verdaux_size);
+ pb += verdef_size;
+
+ elfcpp::Verdaux_write<size, big_endian> vda(pb);
+ vda.set_vda_name(dynpool->get_offset(this->name()));
+ vda.set_vda_next(this->deps_.empty() ? 0 : verdaux_size);
+ pb += verdaux_size;
+
+ Deps::const_iterator p;
+ unsigned int i;
+ for (p = this->deps_.begin(), i = 0;
+ p != this->deps_.end();
+ ++p, ++i)
+ {
+ elfcpp::Verdaux_write<size, big_endian> vda(pb);
+ vda.set_vda_name(dynpool->get_offset(*p));
+ vda.set_vda_next(i + 1 >= this->deps_.size() ? 0 : verdaux_size);
+ pb += verdaux_size;
+ }
+
+ return pb;
+}
+
+// Verneed methods.
+
+Verneed::~Verneed()
+{
+ for (Need_versions::iterator p = this->need_versions_.begin();
+ p != this->need_versions_.end();
+ ++p)
+ delete *p;
+}
+
+// Add a new version to this file reference.
+
+Verneed_version*
+Verneed::add_name(const char* name)
+{
+ Verneed_version* vv = new Verneed_version(name);
+ this->need_versions_.push_back(vv);
+ return vv;
+}
+
+// Set the version indexes starting at INDEX.
+
+unsigned int
+Verneed::finalize(unsigned int index)
+{
+ for (Need_versions::iterator p = this->need_versions_.begin();
+ p != this->need_versions_.end();
+ ++p)
+ {
+ (*p)->set_index(index);
+ ++index;
+ }
+ return index;
+}
+
+// Write this list of referenced versions to a buffer for the output
+// section.
+
+template<int size, bool big_endian>
+unsigned char*
+Verneed::write(const Stringpool* dynpool, bool is_last,
+ unsigned char* pb ACCEPT_SIZE_ENDIAN) const
+{
+ const int verneed_size = elfcpp::Elf_sizes<size>::verneed_size;
+ const int vernaux_size = elfcpp::Elf_sizes<size>::vernaux_size;
+
+ elfcpp::Verneed_write<size, big_endian> vn(pb);
+ vn.set_vn_version(elfcpp::VER_NEED_CURRENT);
+ vn.set_vn_cnt(this->need_versions_.size());
+ vn.set_vn_file(dynpool->get_offset(this->filename()));
+ vn.set_vn_aux(verneed_size);
+ vn.set_vn_next(is_last
+ ? 0
+ : verneed_size + this->need_versions_.size() * vernaux_size);
+ pb += verneed_size;
+
+ Need_versions::const_iterator p;
+ unsigned int i;
+ for (p = this->need_versions_.begin(), i = 0;
+ p != this->need_versions_.end();
+ ++p, ++i)
+ {
+ elfcpp::Vernaux_write<size, big_endian> vna(pb);
+ vna.set_vna_hash(Dynobj::elf_hash((*p)->version()));
+ // FIXME: We need to sometimes set VER_FLG_WEAK here.
+ vna.set_vna_flags(0);
+ vna.set_vna_other((*p)->index());
+ vna.set_vna_name(dynpool->get_offset((*p)->version()));
+ vna.set_vna_next(i + 1 >= this->need_versions_.size()
+ ? 0
+ : vernaux_size);
+ pb += vernaux_size;
+ }
+
+ return pb;
+}
+
+// Versions methods.
+
+Versions::~Versions()
+{
+ for (Defs::iterator p = this->defs_.begin();
+ p != this->defs_.end();
+ ++p)
+ delete *p;
+
+ for (Needs::iterator p = this->needs_.begin();
+ p != this->needs_.end();
+ ++p)
+ delete *p;
+}
+
+// Record version information for a symbol going into the dynamic
+// symbol table.
+
+void
+Versions::record_version(const General_options* options,
+ Stringpool* dynpool, const Symbol* sym)
+{
+ gold_assert(!this->is_finalized_);
+ gold_assert(sym->version() != NULL);
+
+ Stringpool::Key version_key;
+ const char* version = dynpool->add(sym->version(), &version_key);
+
+ if (!sym->is_from_dynobj())
+ this->add_def(options, sym, version, version_key);
+ else
+ {
+ // This is a version reference.
+
+ Object* object = sym->object();
+ gold_assert(object->is_dynamic());
+ Dynobj* dynobj = static_cast<Dynobj*>(object);
+
+ this->add_need(dynpool, dynobj->soname(), version, version_key);
+ }
+}
+
+// We've found a symbol SYM defined in version VERSION.
+
+void
+Versions::add_def(const General_options* options, const Symbol* sym,
+ const char* version, Stringpool::Key version_key)
+{
+ Key k(version_key, 0);
+ Version_base* const vbnull = NULL;
+ std::pair<Version_table::iterator, bool> ins =
+ this->version_table_.insert(std::make_pair(k, vbnull));
+
+ if (!ins.second)
+ {
+ // We already have an entry for this version.
+ Version_base* vb = ins.first->second;
+
+ // We have now seen a symbol in this version, so it is not
+ // weak.
+ vb->clear_weak();
+
+ // FIXME: When we support version scripts, we will need to
+ // check whether this symbol should be forced local.
+ }
+ else
+ {
+ // If we are creating a shared object, it is an error to
+ // find a definition of a symbol with a version which is not
+ // in the version script.
+ if (options->is_shared())
+ {
+ fprintf(stderr, _("%s: symbol %s has undefined version %s\n"),
+ program_name, sym->name(), version);
+ gold_exit(false);
+ }
+
+ // If this is the first version we are defining, first define
+ // the base version. FIXME: Should use soname here when
+ // creating a shared object.
+ Verdef* vdbase = new Verdef(options->output_file_name(), true, false,
+ true);
+ this->defs_.push_back(vdbase);
+
+ // When creating a regular executable, automatically define
+ // a new version.
+ Verdef* vd = new Verdef(version, false, false, false);
+ this->defs_.push_back(vd);
+ ins.first->second = vd;
+ }
+}
+
+// Add a reference to version NAME in file FILENAME.
+
+void
+Versions::add_need(Stringpool* dynpool, const char* filename, const char* name,
+ Stringpool::Key name_key)
+{
+ Stringpool::Key filename_key;
+ filename = dynpool->add(filename, &filename_key);
+
+ Key k(name_key, filename_key);
+ Version_base* const vbnull = NULL;
+ std::pair<Version_table::iterator, bool> ins =
+ this->version_table_.insert(std::make_pair(k, vbnull));
+
+ if (!ins.second)
+ {
+ // We already have an entry for this filename/version.
+ return;
+ }
+
+ // See whether we already have this filename. We don't expect many
+ // version references, so we just do a linear search. This could be
+ // replaced by a hash table.
+ Verneed* vn = NULL;
+ for (Needs::iterator p = this->needs_.begin();
+ p != this->needs_.end();
+ ++p)
+ {
+ if ((*p)->filename() == filename)
+ {
+ vn = *p;
+ break;
+ }
+ }
+
+ if (vn == NULL)
+ {
+ // We have a new filename.
+ vn = new Verneed(filename);
+ this->needs_.push_back(vn);
+ }
+
+ ins.first->second = vn->add_name(name);
+}
+
+// Set the version indexes. Create a new dynamic version symbol for
+// each new version definition.
+
+unsigned int
+Versions::finalize(const Target* target, Symbol_table* symtab,
+ unsigned int dynsym_index, std::vector<Symbol*>* syms)
+{
+ gold_assert(!this->is_finalized_);
+
+ unsigned int vi = 1;
+
+ for (Defs::iterator p = this->defs_.begin();
+ p != this->defs_.end();
+ ++p)
+ {
+ (*p)->set_index(vi);
+ ++vi;
+
+ // Create a version symbol if necessary.
+ if (!(*p)->is_symbol_created())
+ {
+ Symbol* vsym = symtab->define_as_constant(target, (*p)->name(),
+ (*p)->name(), 0, 0,
+ elfcpp::STT_OBJECT,
+ elfcpp::STB_GLOBAL,
+ elfcpp::STV_DEFAULT, 0,
+ false);
+ vsym->set_needs_dynsym_entry();
+ ++dynsym_index;
+ syms->push_back(vsym);
+ // The name is already in the dynamic pool.
+ }
+ }
+
+ // Index 1 is used for global symbols.
+ if (vi == 1)
+ {
+ gold_assert(this->defs_.empty());
+ vi = 2;
+ }
+
+ for (Needs::iterator p = this->needs_.begin();
+ p != this->needs_.end();
+ ++p)
+ vi = (*p)->finalize(vi);
+
+ this->is_finalized_ = true;
+
+ return dynsym_index;
+}
+
+// Return the version index to use for a symbol. This does two hash
+// table lookups: one in DYNPOOL and one in this->version_table_.
+// Another approach alternative would be store a pointer in SYM, which
+// would increase the size of the symbol table. Or perhaps we could
+// use a hash table from dynamic symbol pointer values to Version_base
+// pointers.
+
+unsigned int
+Versions::version_index(const Stringpool* dynpool, const Symbol* sym) const
+{
+ Stringpool::Key version_key;
+ const char* version = dynpool->find(sym->version(), &version_key);
+ gold_assert(version != NULL);
+
+ Key k;
+ if (!sym->is_from_dynobj())
+ k = Key(version_key, 0);
+ else
+ {
+ Object* object = sym->object();
+ gold_assert(object->is_dynamic());
+ Dynobj* dynobj = static_cast<Dynobj*>(object);
+
+ Stringpool::Key filename_key;
+ const char* filename = dynpool->find(dynobj->soname(), &filename_key);
+ gold_assert(filename != NULL);
+
+ k = Key(version_key, filename_key);
+ }
+
+ Version_table::const_iterator p = this->version_table_.find(k);
+ gold_assert(p != this->version_table_.end());
+
+ return p->second->index();
+}
+
+// Return an allocated buffer holding the contents of the symbol
+// version section.
+
+template<int size, bool big_endian>
+void
+Versions::symbol_section_contents(const Stringpool* dynpool,
+ unsigned int local_symcount,
+ const std::vector<Symbol*>& syms,
+ unsigned char** pp,
+ unsigned int* psize
+ ACCEPT_SIZE_ENDIAN) const
+{
+ gold_assert(this->is_finalized_);
+
+ unsigned int sz = (local_symcount + syms.size()) * 2;
+ unsigned char* pbuf = new unsigned char[sz];
+
+ for (unsigned int i = 0; i < local_symcount; ++i)
+ elfcpp::Swap<16, big_endian>::writeval(pbuf + i * 2,
+ elfcpp::VER_NDX_LOCAL);
+
+ for (std::vector<Symbol*>::const_iterator p = syms.begin();
+ p != syms.end();
+ ++p)
+ {
+ unsigned int version_index;
+ const char* version = (*p)->version();
+ if (version == NULL)
+ version_index = elfcpp::VER_NDX_GLOBAL;
+ else
+ version_index = this->version_index(dynpool, *p);
+ elfcpp::Swap<16, big_endian>::writeval(pbuf + (*p)->dynsym_index() * 2,
+ version_index);
+ }
+
+ *pp = pbuf;
+ *psize = sz;
+}
+
+// Return an allocated buffer holding the contents of the version
+// definition section.
+
+template<int size, bool big_endian>
+void
+Versions::def_section_contents(const Stringpool* dynpool,
+ unsigned char** pp, unsigned int* psize,
+ unsigned int* pentries
+ ACCEPT_SIZE_ENDIAN) const
+{
+ gold_assert(this->is_finalized_);
+ gold_assert(!this->defs_.empty());
+
+ const int verdef_size = elfcpp::Elf_sizes<size>::verdef_size;
+ const int verdaux_size = elfcpp::Elf_sizes<size>::verdaux_size;
+
+ unsigned int sz = 0;
+ for (Defs::const_iterator p = this->defs_.begin();
+ p != this->defs_.end();
+ ++p)
+ {
+ sz += verdef_size + verdaux_size;
+ sz += (*p)->count_dependencies() * verdaux_size;
+ }
+
+ unsigned char* pbuf = new unsigned char[sz];
+
+ unsigned char* pb = pbuf;
+ Defs::const_iterator p;
+ unsigned int i;
+ for (p = this->defs_.begin(), i = 0;
+ p != this->defs_.end();
+ ++p, ++i)
+ pb = (*p)->write SELECT_SIZE_ENDIAN_NAME(size, big_endian)(
+ dynpool, i + 1 >= this->defs_.size(), pb
+ SELECT_SIZE_ENDIAN(size, big_endian));
+
+ gold_assert(static_cast<unsigned int>(pb - pbuf) == sz);
+
+ *pp = pbuf;
+ *psize = sz;
+ *pentries = this->defs_.size();
+}
+
+// Return an allocated buffer holding the contents of the version
+// reference section.
+
+template<int size, bool big_endian>
+void
+Versions::need_section_contents(const Stringpool* dynpool,
+ unsigned char** pp, unsigned int *psize,
+ unsigned int *pentries
+ ACCEPT_SIZE_ENDIAN) const
+{
+ gold_assert(this->is_finalized_);
+ gold_assert(!this->needs_.empty());
+
+ const int verneed_size = elfcpp::Elf_sizes<size>::verneed_size;
+ const int vernaux_size = elfcpp::Elf_sizes<size>::vernaux_size;
+
+ unsigned int sz = 0;
+ for (Needs::const_iterator p = this->needs_.begin();
+ p != this->needs_.end();
+ ++p)
+ {
+ sz += verneed_size;
+ sz += (*p)->count_versions() * vernaux_size;
+ }
+
+ unsigned char* pbuf = new unsigned char[sz];
+
+ unsigned char* pb = pbuf;
+ Needs::const_iterator p;
+ unsigned int i;
+ for (p = this->needs_.begin(), i = 0;
+ p != this->needs_.end();
+ ++p, ++i)
+ pb = (*p)->write SELECT_SIZE_ENDIAN_NAME(size, big_endian)(
+ dynpool, i + 1 >= this->needs_.size(), pb
+ SELECT_SIZE_ENDIAN(size, big_endian));
+
+ gold_assert(static_cast<unsigned int>(pb - pbuf) == sz);
+
+ *pp = pbuf;
+ *psize = sz;
+ *pentries = this->needs_.size();
+}
+
+// Instantiate the templates we need. We could use the configure
+// script to restrict this to only the ones for implemented targets.
+
+template
+class Sized_dynobj<32, false>;
+
+template
+class Sized_dynobj<32, true>;
+
+template
+class Sized_dynobj<64, false>;
+
+template
+class Sized_dynobj<64, true>;
+
+template
+void
+Versions::symbol_section_contents<32, false>(
+ const Stringpool*,
+ unsigned int,
+ const std::vector<Symbol*>&,
+ unsigned char**,
+ unsigned int*
+ ACCEPT_SIZE_ENDIAN_EXPLICIT(32, false)) const;
+
+template
+void
+Versions::symbol_section_contents<32, true>(
+ const Stringpool*,
+ unsigned int,
+ const std::vector<Symbol*>&,
+ unsigned char**,
+ unsigned int*
+ ACCEPT_SIZE_ENDIAN_EXPLICIT(32, true)) const;
+
+template
+void
+Versions::symbol_section_contents<64, false>(
+ const Stringpool*,
+ unsigned int,
+ const std::vector<Symbol*>&,
+ unsigned char**,
+ unsigned int*
+ ACCEPT_SIZE_ENDIAN_EXPLICIT(64, false)) const;
+
+template
+void
+Versions::symbol_section_contents<64, true>(
+ const Stringpool*,
+ unsigned int,
+ const std::vector<Symbol*>&,
+ unsigned char**,
+ unsigned int*
+ ACCEPT_SIZE_ENDIAN_EXPLICIT(64, true)) const;
+
+template
+void
+Versions::def_section_contents<32, false>(
+ const Stringpool*,
+ unsigned char**,
+ unsigned int*,
+ unsigned int*
+ ACCEPT_SIZE_ENDIAN_EXPLICIT(32, false)) const;
+
+template
+void
+Versions::def_section_contents<32, true>(
+ const Stringpool*,
+ unsigned char**,
+ unsigned int*,
+ unsigned int*
+ ACCEPT_SIZE_ENDIAN_EXPLICIT(32, true)) const;
+
+template
+void
+Versions::def_section_contents<64, false>(
+ const Stringpool*,
+ unsigned char**,
+ unsigned int*,
+ unsigned int*
+ ACCEPT_SIZE_ENDIAN_EXPLICIT(64, false)) const;
+
+template
+void
+Versions::def_section_contents<64, true>(
+ const Stringpool*,
+ unsigned char**,
+ unsigned int*,
+ unsigned int*
+ ACCEPT_SIZE_ENDIAN_EXPLICIT(64, true)) const;
+
+template
+void
+Versions::need_section_contents<32, false>(
+ const Stringpool*,
+ unsigned char**,
+ unsigned int*,
+ unsigned int*
+ ACCEPT_SIZE_ENDIAN_EXPLICIT(32, false)) const;
+
+template
+void
+Versions::need_section_contents<32, true>(
+ const Stringpool*,
+ unsigned char**,
+ unsigned int*,
+ unsigned int*
+ ACCEPT_SIZE_ENDIAN_EXPLICIT(32, true)) const;
+
+template
+void
+Versions::need_section_contents<64, false>(
+ const Stringpool*,
+ unsigned char**,
+ unsigned int*,
+ unsigned int*
+ ACCEPT_SIZE_ENDIAN_EXPLICIT(64, false)) const;
+
+template
+void
+Versions::need_section_contents<64, true>(
+ const Stringpool*,
+ unsigned char**,
+ unsigned int*,
+ unsigned int*
+ ACCEPT_SIZE_ENDIAN_EXPLICIT(64, true)) const;
+
+} // End namespace gold.
diff --git a/gold/dynobj.h b/gold/dynobj.h
new file mode 100644
index 000000000000..d63aa6af0b21
--- /dev/null
+++ b/gold/dynobj.h
@@ -0,0 +1,494 @@
+// dynobj.h -- dynamic object support for gold -*- C++ -*-
+
+#ifndef GOLD_DYNOBJ_H
+#define GOLD_DYNOBJ_H
+
+#include <vector>
+
+#include "stringpool.h"
+#include "object.h"
+
+namespace gold
+{
+
+class General_options;
+
+// A dynamic object (ET_DYN). This is an abstract base class itself.
+// The implementations is the template class Sized_dynobj.
+
+class Dynobj : public Object
+{
+ public:
+ Dynobj(const std::string& name, Input_file* input_file, off_t offset = 0)
+ : Object(name, input_file, true, offset), soname_()
+ { }
+
+ // Return the name to use in a DT_NEEDED entry for this object.
+ const char*
+ soname() const;
+
+ // Compute the ELF hash code for a string.
+ static uint32_t
+ elf_hash(const char*);
+
+ // Create a standard ELF hash table, setting *PPHASH and *PHASHLEN.
+ // DYNSYMS is the global dynamic symbols. LOCAL_DYNSYM_COUNT is the
+ // number of local dynamic symbols, which is the index of the first
+ // dynamic gobal symbol.
+ static void
+ create_elf_hash_table(const Target*, const std::vector<Symbol*>& dynsyms,
+ unsigned int local_dynsym_count,
+ unsigned char** pphash,
+ unsigned int* phashlen);
+
+ // Create a GNU hash table, setting *PPHASH and *PHASHLEN. DYNSYMS
+ // is the global dynamic symbols. LOCAL_DYNSYM_COUNT is the number
+ // of local dynamic symbols, which is the index of the first dynamic
+ // gobal symbol.
+ static void
+ create_gnu_hash_table(const Target*, const std::vector<Symbol*>& dynsyms,
+ unsigned int local_dynsym_count,
+ unsigned char** pphash, unsigned int* phashlen);
+
+ protected:
+ // Set the DT_SONAME string.
+ void
+ set_soname_string(const char* s)
+ { this->soname_.assign(s); }
+
+ private:
+ // Compute the GNU hash code for a string.
+ static uint32_t
+ gnu_hash(const char*);
+
+ // Compute the number of hash buckets to use.
+ static unsigned int
+ compute_bucket_count(const std::vector<uint32_t>& hashcodes,
+ bool for_gnu_hash_table);
+
+ // Sized version of create_elf_hash_table.
+ template<bool big_endian>
+ static void
+ sized_create_elf_hash_table(const std::vector<uint32_t>& bucket,
+ const std::vector<uint32_t>& chain,
+ unsigned char* phash,
+ unsigned int hashlen);
+
+ // Sized version of create_gnu_hash_table.
+ template<int size, bool big_endian>
+ static void
+ sized_create_gnu_hash_table(const std::vector<Symbol*>& hashed_dynsyms,
+ const std::vector<uint32_t>& dynsym_hashvals,
+ unsigned int unhashed_dynsym_count,
+ unsigned char** pphash,
+ unsigned int* phashlen);
+
+ // The DT_SONAME name, if any.
+ std::string soname_;
+};
+
+// A dynamic object, size and endian specific version.
+
+template<int size, bool big_endian>
+class Sized_dynobj : public Dynobj
+{
+ public:
+ Sized_dynobj(const std::string& name, Input_file* input_file, off_t offset,
+ const typename elfcpp::Ehdr<size, big_endian>&);
+
+ // Set up the object file based on the ELF header.
+ void
+ setup(const typename elfcpp::Ehdr<size, big_endian>&);
+
+ // Read the symbols.
+ void
+ do_read_symbols(Read_symbols_data*);
+
+ // Lay out the input sections.
+ void
+ do_layout(const General_options&, Symbol_table*, Layout*,
+ Read_symbols_data*);
+
+ // Add the symbols to the symbol table.
+ void
+ do_add_symbols(Symbol_table*, Read_symbols_data*);
+
+ // Get the name of a section.
+ std::string
+ do_section_name(unsigned int shndx)
+ { return this->elf_file_.section_name(shndx); }
+
+ // Return a view of the contents of a section. Set *PLEN to the
+ // size.
+ Object::Location
+ do_section_contents(unsigned int shndx)
+ { return this->elf_file_.section_contents(shndx); }
+
+ // Return section flags.
+ uint64_t
+ do_section_flags(unsigned int shndx)
+ { return this->elf_file_.section_flags(shndx); }
+
+ private:
+ // For convenience.
+ typedef Sized_dynobj<size, big_endian> This;
+ static const int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
+ static const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+ static const int dyn_size = elfcpp::Elf_sizes<size>::dyn_size;
+ typedef elfcpp::Shdr<size, big_endian> Shdr;
+ typedef elfcpp::Dyn<size, big_endian> Dyn;
+
+ // Find the dynamic symbol table and the version sections, given the
+ // section headers.
+ void
+ find_dynsym_sections(const unsigned char* pshdrs,
+ unsigned int* pdynshm_shndx,
+ unsigned int* pversym_shndx,
+ unsigned int* pverdef_shndx,
+ unsigned int* pverneed_shndx,
+ unsigned int* pdynamic_shndx);
+
+ // Read the dynamic symbol section SHNDX.
+ void
+ read_dynsym_section(const unsigned char* pshdrs, unsigned int shndx,
+ elfcpp::SHT type, unsigned int link,
+ File_view** view, off_t* view_size,
+ unsigned int* view_info);
+
+ // Set the SONAME from the SHT_DYNAMIC section at DYNAMIC_SHNDX.
+ // The STRTAB parameters may have the relevant string table.
+ void
+ set_soname(const unsigned char* pshdrs, unsigned int dynamic_shndx,
+ unsigned int strtab_shndx, const unsigned char* strtabu,
+ off_t strtab_size);
+
+ // Mapping from version number to version name.
+ typedef std::vector<const char*> Version_map;
+
+ // Create the version map.
+ void
+ make_version_map(Read_symbols_data* sd, Version_map*) const;
+
+ // Add version definitions to the version map.
+ void
+ make_verdef_map(Read_symbols_data* sd, Version_map*) const;
+
+ // Add version references to the version map.
+ void
+ make_verneed_map(Read_symbols_data* sd, Version_map*) const;
+
+ // Add an entry to the version map.
+ void
+ set_version_map(Version_map*, unsigned int ndx, const char* name) const;
+
+ // General access to the ELF file.
+ elfcpp::Elf_file<size, big_endian, Object> elf_file_;
+};
+
+// A base class for Verdef and Verneed_version which just handles the
+// version index which will be stored in the SHT_GNU_versym section.
+
+class Version_base
+{
+ public:
+ Version_base()
+ : index_(-1U)
+ { }
+
+ virtual
+ ~Version_base()
+ { }
+
+ // Return the version index.
+ unsigned int
+ index() const
+ {
+ gold_assert(this->index_ != -1U);
+ return this->index_;
+ }
+
+ // Set the version index.
+ void
+ set_index(unsigned int index)
+ {
+ gold_assert(this->index_ == -1U);
+ this->index_ = index;
+ }
+
+ // Clear the weak flag in a version definition.
+ virtual void
+ clear_weak() = 0;
+
+ private:
+ Version_base(const Version_base&);
+ Version_base& operator=(const Version_base&);
+
+ // The index of the version definition or reference.
+ unsigned int index_;
+};
+
+// This class handles a version being defined in the file we are
+// generating.
+
+class Verdef : public Version_base
+{
+ public:
+ Verdef(const char* name, bool is_base, bool is_weak, bool is_symbol_created)
+ : name_(name), deps_(), is_base_(is_base), is_weak_(is_weak),
+ is_symbol_created_(is_symbol_created)
+ { }
+
+ // Return the version name.
+ const char*
+ name() const
+ { return this->name_; }
+
+ // Return the number of dependencies.
+ unsigned int
+ count_dependencies() const
+ { return this->deps_.size(); }
+
+ // Add a dependency to this version. The NAME should be
+ // canonicalized in the dynamic Stringpool.
+ void
+ add_dependency(const char* name)
+ { this->deps_.push_back(name); }
+
+ // Return whether this definition is weak.
+ bool
+ is_weak() const
+ { return this->is_weak_; }
+
+ // Clear the weak flag.
+ void
+ clear_weak()
+ { this->is_weak_ = false; }
+
+ // Return whether a version symbol has been created for this
+ // definition.
+ bool
+ is_symbol_created() const
+ { return this->is_symbol_created_; }
+
+ // Write contents to buffer.
+ template<int size, bool big_endian>
+ unsigned char*
+ write(const Stringpool*, bool is_last, unsigned char*
+ ACCEPT_SIZE_ENDIAN) const;
+
+ private:
+ Verdef(const Verdef&);
+ Verdef& operator=(const Verdef&);
+
+ // The type of the list of version dependencies. Each dependency
+ // should be canonicalized in the dynamic Stringpool.
+ typedef std::vector<const char*> Deps;
+
+ // The name of this version. This should be canonicalized in the
+ // dynamic Stringpool.
+ const char* name_;
+ // A list of other versions which this version depends upon.
+ Deps deps_;
+ // Whether this is the base version.
+ bool is_base_;
+ // Whether this version is weak.
+ bool is_weak_;
+ // Whether a version symbol has been created.
+ bool is_symbol_created_;
+};
+
+// A referened version. This will be associated with a filename by
+// Verneed.
+
+class Verneed_version : public Version_base
+{
+ public:
+ Verneed_version(const char* version)
+ : version_(version)
+ { }
+
+ // Return the version name.
+ const char*
+ version() const
+ { return this->version_; }
+
+ // Clear the weak flag. This is invalid for a reference.
+ void
+ clear_weak()
+ { gold_unreachable(); }
+
+ private:
+ Verneed_version(const Verneed_version&);
+ Verneed_version& operator=(const Verneed_version&);
+
+ const char* version_;
+};
+
+// Version references in a single dynamic object.
+
+class Verneed
+{
+ public:
+ Verneed(const char* filename)
+ : filename_(filename), need_versions_()
+ { }
+
+ ~Verneed();
+
+ // Return the file name.
+ const char*
+ filename() const
+ { return this->filename_; }
+
+ // Return the number of versions.
+ unsigned int
+ count_versions() const
+ { return this->need_versions_.size(); }
+
+ // Add a version name. The name should be canonicalized in the
+ // dynamic Stringpool. If the name is already present, this does
+ // nothing.
+ Verneed_version*
+ add_name(const char* name);
+
+ // Set the version indexes, starting at INDEX. Return the updated
+ // INDEX.
+ unsigned int
+ finalize(unsigned int index);
+
+ // Write contents to buffer.
+ template<int size, bool big_endian>
+ unsigned char*
+ write(const Stringpool*, bool is_last, unsigned char*
+ ACCEPT_SIZE_ENDIAN) const;
+
+ private:
+ Verneed(const Verneed&);
+ Verneed& operator=(const Verneed&);
+
+ // The type of the list of version names. Each name should be
+ // canonicalized in the dynamic Stringpool.
+ typedef std::vector<Verneed_version*> Need_versions;
+
+ // The filename of the dynamic object. This should be
+ // canonicalized in the dynamic Stringpool.
+ const char* filename_;
+ // The list of version names.
+ Need_versions need_versions_;
+};
+
+// This class handles version definitions and references which go into
+// the output file.
+
+class Versions
+{
+ public:
+ Versions()
+ : defs_(), needs_(), version_table_(), is_finalized_(false)
+ { }
+
+ ~Versions();
+
+ // SYM is going into the dynamic symbol table and has a version.
+ // Record the appropriate version information.
+ void
+ record_version(const General_options*, Stringpool*, const Symbol* sym);
+
+ // Set the version indexes. DYNSYM_INDEX is the index we should use
+ // for the next dynamic symbol. We add new dynamic symbols to SYMS
+ // and return an updated DYNSYM_INDEX.
+ unsigned int
+ finalize(const Target*, Symbol_table* symtab, unsigned int dynsym_index,
+ std::vector<Symbol*>* syms);
+
+ // Return whether there are any version definitions.
+ bool
+ any_defs() const
+ { return !this->defs_.empty(); }
+
+ // Return whether there are any version references.
+ bool
+ any_needs() const
+ { return !this->needs_.empty(); }
+
+ // Build an allocated buffer holding the contents of the symbol
+ // version section (.gnu.version).
+ template<int size, bool big_endian>
+ void
+ symbol_section_contents(const Stringpool*, unsigned int local_symcount,
+ const std::vector<Symbol*>& syms,
+ unsigned char**, unsigned int*
+ ACCEPT_SIZE_ENDIAN) const;
+
+ // Build an allocated buffer holding the contents of the version
+ // definition section (.gnu.version_d).
+ template<int size, bool big_endian>
+ void
+ def_section_contents(const Stringpool*, unsigned char**,
+ unsigned int* psize, unsigned int* pentries
+ ACCEPT_SIZE_ENDIAN) const;
+
+ // Build an allocated buffer holding the contents of the version
+ // reference section (.gnu.version_r).
+ template<int size, bool big_endian>
+ void
+ need_section_contents(const Stringpool*, unsigned char**,
+ unsigned int* psize, unsigned int* pentries
+ ACCEPT_SIZE_ENDIAN) const;
+
+ private:
+ // The type of the list of version definitions.
+ typedef std::vector<Verdef*> Defs;
+
+ // The type of the list of version references.
+ typedef std::vector<Verneed*> Needs;
+
+ // Handle a symbol SYM defined with version VERSION.
+ void
+ add_def(const General_options*, const Symbol* sym, const char* version,
+ Stringpool::Key);
+
+ // Add a reference to version NAME in file FILENAME.
+ void
+ add_need(Stringpool*, const char* filename, const char* name,
+ Stringpool::Key);
+
+ // Return the version index to use for SYM.
+ unsigned int
+ version_index(const Stringpool*, const Symbol* sym) const;
+
+ // We keep a hash table mapping canonicalized name/version pairs to
+ // a version base.
+ typedef std::pair<Stringpool::Key, Stringpool::Key> Key;
+
+ struct Version_table_hash
+ {
+ size_t
+ operator()(const Key& k) const
+ { return k.first + k.second; }
+ };
+
+ struct Version_table_eq
+ {
+ bool
+ operator()(const Key& k1, const Key& k2) const
+ { return k1.first == k2.first && k1.second == k2.second; }
+ };
+
+ typedef Unordered_map<Key, Version_base*, Version_table_hash,
+ Version_table_eq> Version_table;
+
+ // The version definitions.
+ Defs defs_;
+ // The version references.
+ Needs needs_;
+ // The mapping from a canonicalized version/filename pair to a
+ // version index. The filename may be NULL.
+ Version_table version_table_;
+ // Whether the version indexes have been set.
+ bool is_finalized_;
+};
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_DYNOBJ_H)
diff --git a/gold/fileread.cc b/gold/fileread.cc
new file mode 100644
index 000000000000..1a142022569a
--- /dev/null
+++ b/gold/fileread.cc
@@ -0,0 +1,379 @@
+// fileread.cc -- read files for gold
+
+#include "gold.h"
+
+#include <cstring>
+#include <cerrno>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "options.h"
+#include "dirsearch.h"
+#include "fileread.h"
+
+namespace gold
+{
+
+// Class File_read::View.
+
+File_read::View::~View()
+{
+ gold_assert(!this->is_locked());
+ delete[] this->data_;
+}
+
+void
+File_read::View::lock()
+{
+ ++this->lock_count_;
+}
+
+void
+File_read::View::unlock()
+{
+ gold_assert(this->lock_count_ > 0);
+ --this->lock_count_;
+}
+
+bool
+File_read::View::is_locked()
+{
+ return this->lock_count_ > 0;
+}
+
+// Class File_read.
+
+// The File_read class is designed to support file descriptor caching,
+// but this is not currently implemented.
+
+File_read::~File_read()
+{
+ gold_assert(this->lock_count_ == 0);
+ if (this->descriptor_ >= 0)
+ {
+ if (close(this->descriptor_) < 0)
+ fprintf(stderr, _("%s: warning: close(%s) failed: %s"),
+ program_name, this->name_.c_str(), strerror(errno));
+ this->descriptor_ = -1;
+ }
+ this->name_.clear();
+ this->clear_views(true);
+}
+
+// Open the file.
+
+bool
+File_read::open(const std::string& name)
+{
+ gold_assert(this->lock_count_ == 0
+ && this->descriptor_ < 0
+ && this->name_.empty());
+ this->name_ = name;
+ this->descriptor_ = ::open(this->name_.c_str(), O_RDONLY);
+ ++this->lock_count_;
+ return this->descriptor_ >= 0;
+}
+
+// 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
+ && this->descriptor_ < 0
+ && this->name_.empty());
+ this->name_ = name;
+ this->contents_ = contents;
+ this->contents_size_ = contents_size;
+ ++this->lock_count_;
+ return true;
+}
+
+void
+File_read::lock()
+{
+ ++this->lock_count_;
+}
+
+void
+File_read::unlock()
+{
+ gold_assert(this->lock_count_ > 0);
+ --this->lock_count_;
+}
+
+bool
+File_read::is_locked()
+{
+ return this->lock_count_ > 0;
+}
+
+// See if we have a view which covers the file starting at START for
+// SIZE bytes. Return a pointer to the View if found, NULL if not.
+
+inline File_read::View*
+File_read::find_view(off_t start, off_t size)
+{
+ off_t page = File_read::page_offset(start);
+ Views::iterator p = this->views_.find(page);
+ if (p == this->views_.end())
+ return NULL;
+ if (p->second->size() - (start - page) < size)
+ return NULL;
+ return p->second;
+}
+
+// Read data from the file. Return the number of bytes read. If
+// PBYTES is not NULL, store the number of bytes in *PBYTES, otherwise
+// require that we read exactly the number of bytes requested.
+
+off_t
+File_read::do_read(off_t start, off_t size, void* p, off_t* pbytes)
+{
+ gold_assert(this->lock_count_ > 0);
+
+ off_t bytes;
+ if (this->contents_ == NULL)
+ {
+ int o = this->descriptor_;
+
+ if (lseek(o, start, SEEK_SET) < 0)
+ {
+ fprintf(stderr, _("%s: %s: lseek to %lld failed: %s"),
+ program_name, this->filename().c_str(),
+ static_cast<long long>(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
+ {
+ 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)
+ *pbytes = bytes;
+ else if (bytes != size)
+ {
+ fprintf(stderr,
+ _("%s: %s: file too short: read only %lld of %lld "
+ "bytes at %lld\n"),
+ program_name, this->filename().c_str(),
+ static_cast<long long>(bytes),
+ static_cast<long long>(size),
+ static_cast<long long>(start));
+ gold_exit(false);
+ }
+
+ return bytes;
+}
+
+void
+File_read::read(off_t start, off_t size, void* p, off_t* pbytes)
+{
+ gold_assert(this->lock_count_ > 0);
+
+ File_read::View* pv = this->find_view(start, size);
+ if (pv != NULL)
+ {
+ memcpy(p, pv->data() + (start - pv->start()), size);
+ if (pbytes != NULL)
+ *pbytes = size;
+ return;
+ }
+
+ this->do_read(start, size, p, pbytes);
+}
+
+// Find an existing view or make a new one.
+
+File_read::View*
+File_read::find_or_make_view(off_t start, off_t size, off_t* pbytes)
+{
+ gold_assert(this->lock_count_ > 0);
+
+ off_t poff = File_read::page_offset(start);
+
+ File_read::View* const vnull = NULL;
+ std::pair<Views::iterator, bool> ins =
+ this->views_.insert(std::make_pair(poff, vnull));
+
+ if (!ins.second)
+ {
+ // There was an existing view at this offset.
+ File_read::View* v = ins.first->second;
+ if (v->size() - (start - v->start()) >= size)
+ {
+ if (pbytes != NULL)
+ *pbytes = size;
+ return v;
+ }
+
+ // This view is not large enough.
+ this->saved_views_.push_back(v);
+ }
+
+ // We need to read data from the file.
+
+ off_t psize = File_read::pages(size + (start - poff));
+ unsigned char* p = new unsigned char[psize];
+
+ off_t got_bytes;
+ off_t bytes = this->do_read(poff, psize, p, &got_bytes);
+
+ File_read::View* v = new File_read::View(poff, bytes, p);
+
+ ins.first->second = v;
+
+ if (bytes - (start - poff) >= size)
+ {
+ if (pbytes != NULL)
+ *pbytes = size;
+ return v;
+ }
+
+ if (pbytes != NULL)
+ {
+ *pbytes = bytes - (start - poff);
+ return v;
+ }
+
+ fprintf(stderr,
+ _("%s: %s: file too short: read only %lld of %lld bytes at %lld\n"),
+ program_name, this->filename().c_str(),
+ static_cast<long long>(bytes - (start - poff)),
+ static_cast<long long>(size),
+ static_cast<long long>(start));
+ gold_exit(false);
+}
+
+// This implementation of get_view just reads into a memory buffer,
+// which we store on view_list_. At some point we should support
+// mmap.
+
+const unsigned char*
+File_read::get_view(off_t start, off_t size, off_t* pbytes)
+{
+ gold_assert(this->lock_count_ > 0);
+ File_read::View* pv = this->find_or_make_view(start, size, pbytes);
+ return pv->data() + (start - pv->start());
+}
+
+File_view*
+File_read::get_lasting_view(off_t start, off_t size, off_t* pbytes)
+{
+ gold_assert(this->lock_count_ > 0);
+ File_read::View* pv = this->find_or_make_view(start, size, pbytes);
+ pv->lock();
+ return new File_view(*this, pv, pv->data() + (start - pv->start()));
+}
+
+// Remove all the file views.
+
+void
+File_read::clear_views(bool destroying)
+{
+ for (Views::iterator p = this->views_.begin();
+ p != this->views_.end();
+ ++p)
+ {
+ if (!p->second->is_locked())
+ delete p->second;
+ else
+ {
+ gold_assert(!destroying);
+ this->saved_views_.push_back(p->second);
+ }
+ }
+ this->views_.clear();
+
+ Saved_views::iterator p = this->saved_views_.begin();
+ while (p != this->saved_views_.end())
+ {
+ if (!(*p)->is_locked())
+ {
+ delete *p;
+ p = this->saved_views_.erase(p);
+ }
+ else
+ {
+ gold_assert(!destroying);
+ ++p;
+ }
+ }
+}
+
+// Class File_view.
+
+File_view::~File_view()
+{
+ gold_assert(this->file_.is_locked());
+ this->view_->unlock();
+}
+
+// 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();
+ else
+ {
+ std::string n1("lib");
+ n1 += this->input_argument_->name();
+ std::string n2;
+ if (options.is_static())
+ n1 += ".a";
+ else
+ {
+ n2 = n1 + ".a";
+ n1 += ".so";
+ }
+ name = dirpath.find(n1, n2);
+ if (name.empty())
+ {
+ fprintf(stderr, _("%s: cannot find %s\n"), program_name,
+ this->input_argument_->name());
+ gold_exit(false);
+ }
+ }
+
+ if (!this->file_.open(name))
+ {
+ fprintf(stderr, _("%s: cannot open %s: %s\n"), program_name,
+ name.c_str(), strerror(errno));
+ gold_exit(false);
+ }
+}
+
+} // End namespace gold.
diff --git a/gold/fileread.h b/gold/fileread.h
new file mode 100644
index 000000000000..178e7f355e44
--- /dev/null
+++ b/gold/fileread.h
@@ -0,0 +1,257 @@
+// fileread.h -- read files for gold -*- C++ -*-
+
+// Classes used to read data from binary input files.
+
+#ifndef GOLD_FILEREAD_H
+#define GOLD_FILEREAD_H
+
+#include <list>
+#include <map>
+#include <string>
+
+#include "options.h"
+
+namespace gold
+{
+
+class Dirsearch;
+class File_view;
+
+// File_read manages a file descriptor for a file we are reading. We
+// close file descriptors if we run out of them, so this class reopens
+// the file as needed.
+
+class File_read
+{
+ public:
+ File_read()
+ : 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_; }
+
+ // 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.
+ void
+ lock();
+
+ // Unlock the descriptor, permitting it to be closed if necessary.
+ void
+ unlock();
+
+ // Test whether the object is locked.
+ bool
+ is_locked();
+
+ // Return a view into the file. The pointer will remain valid until
+ // the File_read is unlocked. If PBYTES is NULL, it is an error if
+ // we can not read enough data. Otherwise *PBYTES is set to the
+ // number of bytes read.
+ const unsigned char*
+ get_view(off_t start, off_t size, off_t *pbytes = NULL);
+
+ // Read data from the file into the buffer P. PBYTES is as in
+ // get_view.
+ void
+ read(off_t start, off_t size, void* p, off_t *pbytes = NULL);
+
+ // Return a lasting view into the file. This is allocated with new,
+ // and the caller is responsible for deleting it when done. The
+ // data associated with this view will remain valid until the view
+ // is deleted. PBYTES is handled as with get_view.
+ File_view*
+ get_lasting_view(off_t start, off_t size, off_t *pbytes = NULL);
+
+ private:
+ // This class may not be copied.
+ File_read(const File_read&);
+ File_read& operator=(const File_read&);
+
+ // A view into the file when not using mmap.
+ class View
+ {
+ public:
+ View(off_t start, off_t size, unsigned char* data)
+ : start_(start), size_(size), data_(data), lock_count_(0)
+ { }
+
+ ~View();
+
+ off_t
+ start() const
+ { return this->start_; }
+
+ off_t
+ size() const
+ { return this->size_; }
+
+ unsigned char*
+ data() const
+ { return this->data_; }
+
+ void
+ lock();
+
+ void
+ unlock();
+
+ bool
+ is_locked();
+
+ private:
+ View(const View&);
+ View& operator=(const View&);
+
+ off_t start_;
+ off_t size_;
+ unsigned char* data_;
+ int lock_count_;
+ };
+
+ friend class File_view;
+
+ // Find a view into the file.
+ View*
+ find_view(off_t start, off_t size);
+
+ // Read data from the file into a buffer.
+ off_t
+ do_read(off_t start, off_t size, void* p, off_t* pbytes);
+
+ // Find or make a view into the file.
+ View*
+ find_or_make_view(off_t start, off_t size, off_t* pbytes);
+
+ // Clear the file views.
+ void
+ clear_views(bool);
+
+ // The size of a file page for buffering data.
+ static const off_t page_size = 8192;
+
+ // Given a file offset, return the page offset.
+ static off_t
+ page_offset(off_t file_offset)
+ { return file_offset & ~ (page_size - 1); }
+
+ // Given a file size, return the size to read integral pages.
+ static off_t
+ pages(off_t file_size)
+ { return (file_size + (page_size - 1)) & ~ (page_size - 1); }
+
+ // The type of a mapping from page start to views.
+ typedef std::map<off_t, View*> Views;
+
+ // A simple list of Views.
+ typedef std::list<View*> Saved_views;
+
+ // File name.
+ std::string name_;
+ // File descriptor.
+ int descriptor_;
+ // Number of locks on the file.
+ int lock_count_;
+ // Buffered views into the file.
+ Views views_;
+ // 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.
+// Callers should destroy these when no longer required. These are
+// obtained form File_read::get_lasting_view. They may only be
+// destroyed when the underlying File_read is locked.
+
+class File_view
+{
+ public:
+ // This may only be called when the underlying File_read is locked.
+ ~File_view();
+
+ // Return a pointer to the data associated with this view.
+ const unsigned char*
+ data() const
+ { return this->data_; }
+
+ private:
+ File_view(const File_view&);
+ File_view& operator=(const File_view&);
+
+ friend class File_read;
+
+ // Callers have to get these via File_read::get_lasting_view.
+ File_view(File_read& file, File_read::View* view, const unsigned char* data)
+ : file_(file), view_(view), data_(data)
+ { }
+
+ File_read& file_;
+ File_read::View* view_;
+ const unsigned char* data_;
+};
+
+// All the information we hold for a single input file. This can be
+// an object file, a shared library, or an archive.
+
+class Input_file
+{
+ public:
+ 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 the file name.
+ const std::string&
+ filename() const
+ { return this->file_.filename(); }
+
+ File_read&
+ file()
+ { return this->file_; }
+
+ private:
+ Input_file(const Input_file&);
+ Input_file& operator=(const Input_file&);
+
+ const Input_file_argument* input_argument_;
+ File_read file_;
+};
+
+} // end namespace gold
+
+#endif // !defined(GOLD_FILEREAD_H)
diff --git a/gold/gold-threads.cc b/gold/gold-threads.cc
new file mode 100644
index 000000000000..537373969ada
--- /dev/null
+++ b/gold/gold-threads.cc
@@ -0,0 +1,228 @@
+// gold-threads.cc -- thread support for gold
+
+#include "gold.h"
+
+#ifdef ENABLE_THREADS
+#include <pthread.h>
+#endif
+
+#include "gold-threads.h"
+
+namespace gold
+{
+
+// Class Lock_impl.
+
+class Lock_impl
+{
+ public:
+ Lock_impl();
+ ~Lock_impl();
+
+ void acquire();
+
+ void release();
+
+private:
+ // This class can not be copied.
+ Lock_impl(const Lock_impl&);
+ Lock_impl& operator=(const Lock_impl&);
+
+ friend class Condvar_impl;
+
+#ifdef ENABLE_THREADS
+ pthread_mutex_t mutex_;
+#else
+ bool acquired_;
+#endif
+};
+
+#ifdef ENABLE_THREADS
+
+Lock_impl::Lock_impl()
+{
+ pthread_mutexattr_t attr;
+ if (pthread_mutexattr_init(&attr) != 0)
+ gold_fatal(_("pthead_mutextattr_init failed"), true);
+#ifdef PTHREAD_MUTEXT_ADAPTIVE_NP
+ if (pthread_mutextattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP) != 0)
+ gold_fatal(_("pthread_mutextattr_settype failed"), true);
+#endif
+
+ if (pthread_mutex_init (&this->mutex_, &attr) != 0)
+ gold_fatal(_("pthread_mutex_init failed"), true);
+
+ if (pthread_mutexattr_destroy(&attr) != 0)
+ gold_fatal(_("pthread_mutexattr_destroy failed"), true);
+}
+
+Lock_impl::~Lock_impl()
+{
+ if (pthread_mutex_destroy(&this->mutex_) != 0)
+ gold_fatal(_("pthread_mutex_destroy failed"), true);
+}
+
+void
+Lock_impl::acquire()
+{
+ if (pthread_mutex_lock(&this->mutex_) != 0)
+ gold_fatal(_("pthread_mutex_lock failed"), true);
+}
+
+void
+Lock_impl::release()
+{
+ if (pthread_mutex_unlock(&this->mutex_) != 0)
+ gold_fatal(_("pthread_mutex_unlock failed"), true);
+}
+
+#else // !defined(ENABLE_THREADS)
+
+Lock_impl::Lock_impl()
+ : acquired_(false)
+{
+}
+
+Lock_impl::~Lock_impl()
+{
+ gold_assert(!this->acquired_);
+}
+
+void
+Lock_impl::acquire()
+{
+ gold_assert(!this->acquired_);
+ this->acquired_ = true;
+}
+
+void
+Lock_impl::release()
+{
+ gold_assert(this->acquired_);
+ this->acquired_ = false;
+}
+
+#endif // !defined(ENABLE_THREADS)
+
+// Methods for Lock class.
+
+Lock::Lock()
+{
+ this->lock_ = new Lock_impl;
+}
+
+Lock::~Lock()
+{
+ delete this->lock_;
+}
+
+void
+Lock::acquire()
+{
+ this->lock_->acquire();
+}
+
+void
+Lock::release()
+{
+ this->lock_->release();
+}
+
+// Class Condvar_impl.
+
+class Condvar_impl
+{
+ public:
+ Condvar_impl();
+ ~Condvar_impl();
+
+ void wait(Lock_impl*);
+ void signal();
+
+ private:
+ // This class can not be copied.
+ Condvar_impl(const Condvar_impl&);
+ Condvar_impl& operator=(const Condvar_impl&);
+
+#ifdef ENABLE_THREADS
+ pthread_cond_t cond_;
+#endif
+};
+
+#ifdef ENABLE_THREADS
+
+Condvar_impl::Condvar_impl()
+{
+ if (pthread_cond_init(&this->cond_, NULL) != 0)
+ gold_fatal(_("pthread_cond_init failed"), true);
+}
+
+Condvar_impl::~Condvar_impl()
+{
+ if (pthread_cond_destroy(&this->cond_) != 0)
+ gold_fatal(_("pthread_cond_destroy failed"), true);
+}
+
+void
+Condvar_impl::wait(Lock_impl* li)
+{
+ if (pthread_cond_wait(&this->cond_, &li->mutex_) != 0)
+ gold_fatal(_("pthread_cond_wait failed"), true);
+}
+
+void
+Condvar_impl::signal()
+{
+ if (pthread_cond_signal(&this->cond_) != 0)
+ gold_fatal(_("pthread_cond_signal failed"), true);
+}
+
+#else // !defined(ENABLE_THREADS)
+
+Condvar_impl::Condvar_impl()
+{
+}
+
+Condvar_impl::~Condvar_impl()
+{
+}
+
+void
+Condvar_impl::wait(Lock_impl* li)
+{
+ gold_assert(li->acquired_);
+}
+
+void
+Condvar_impl::signal()
+{
+}
+
+#endif // !defined(ENABLE_THREADS)
+
+// Methods for Condvar class.
+
+Condvar::Condvar(Lock& lock)
+ : lock_(lock)
+{
+ this->condvar_ = new Condvar_impl;
+}
+
+Condvar::~Condvar()
+{
+ delete this->condvar_;
+}
+
+void
+Condvar::wait()
+{
+ this->condvar_->wait(this->lock_.get_impl());
+}
+
+void
+Condvar::signal()
+{
+ this->condvar_->signal();
+}
+
+} // End namespace gold.
diff --git a/gold/gold-threads.h b/gold/gold-threads.h
new file mode 100644
index 000000000000..e2a8388ac136
--- /dev/null
+++ b/gold/gold-threads.h
@@ -0,0 +1,101 @@
+// gold-threads.h -- thread support for gold -*- C++ -*-
+
+// gold can be configured to support threads. If threads are
+// supported, the user can specify at runtime whether or not to
+// support them. This provides an interface to manage locking
+// accordingly.
+
+// Lock
+// A simple lock class.
+
+#ifndef GOLD_THREADS_H
+#define GOLD_THREADS_H
+
+namespace gold
+{
+
+class Lock_impl;
+class Condvar;
+
+// A simple lock class.
+
+class Lock
+{
+ public:
+ Lock();
+ ~Lock();
+
+ // Acquire the lock.
+ void
+ acquire();
+
+ // Release the lock.
+ void
+ release();
+
+ private:
+ // This class can not be copied.
+ Lock(const Lock&);
+ Lock& operator=(const Lock&);
+
+ friend class Condvar;
+ Lock_impl*
+ get_impl() const
+ { return this->lock_; }
+
+ Lock_impl* lock_;
+};
+
+// RAII for Lock.
+
+class Hold_lock
+{
+ public:
+ Hold_lock(Lock& lock)
+ : lock_(lock)
+ { this->lock_.acquire(); }
+
+ ~Hold_lock()
+ { this->lock_.release(); }
+
+ private:
+ // This class can not be copied.
+ Hold_lock(const Hold_lock&);
+ Hold_lock& operator=(const Hold_lock&);
+
+ Lock& lock_;
+};
+
+class Condvar_impl;
+
+// A simple condition variable class. It is always associated with a
+// specific lock.
+
+class Condvar
+{
+ public:
+ Condvar(Lock& lock);
+ ~Condvar();
+
+ // Wait for the condition variable to be signalled. This should
+ // only be called when the lock is held.
+ void
+ wait();
+
+ // Signal the condition variable. This should only be called when
+ // the lock is held.
+ void
+ signal();
+
+ private:
+ // This class can not be copied.
+ Condvar(const Condvar&);
+ Condvar& operator=(const Condvar&);
+
+ Lock& lock_;
+ Condvar_impl* condvar_;
+};
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_THREADS_H)
diff --git a/gold/gold.cc b/gold/gold.cc
new file mode 100644
index 000000000000..e7b7ae2939d7
--- /dev/null
+++ b/gold/gold.cc
@@ -0,0 +1,239 @@
+// gold.cc -- main linker functions
+
+#include "gold.h"
+
+#include <cstdlib>
+#include <cstdio>
+#include <cstring>
+#include <unistd.h>
+
+#include "options.h"
+#include "workqueue.h"
+#include "dirsearch.h"
+#include "readsyms.h"
+#include "symtab.h"
+#include "common.h"
+#include "object.h"
+#include "layout.h"
+#include "reloc.h"
+#include "defstd.h"
+
+namespace gold
+{
+
+const char* program_name;
+
+void
+gold_exit(bool status)
+{
+ exit(status ? EXIT_SUCCESS : EXIT_FAILURE);
+}
+
+void
+gold_fatal(const char* msg, bool perrno)
+{
+ fprintf(stderr, "%s: ", program_name);
+ if (perrno)
+ perror(msg);
+ else
+ fprintf(stderr, "%s\n", msg);
+ gold_exit(false);
+}
+
+void
+gold_nomem()
+{
+ // We are out of memory, so try hard to print a reasonable message.
+ // Note that we don't try to translate this message, since the
+ // translation process itself will require memory.
+ write(2, program_name, strlen(program_name));
+ const char* const s = ": out of memory\n";
+ write(2, s, strlen(s));
+ gold_exit(false);
+}
+
+// Handle an unreachable case.
+
+void
+do_gold_unreachable(const char* filename, int lineno, const char* function)
+{
+ fprintf(stderr, "%s: internal error in %s, at %s:%d\n",
+ program_name, function, filename, lineno);
+ gold_exit(false);
+}
+
+// This class arranges to run the functions done in the middle of the
+// link. It is just a closure.
+
+class Middle_runner : public Task_function_runner
+{
+ public:
+ Middle_runner(const General_options& options,
+ const Input_objects* input_objects,
+ Symbol_table* symtab,
+ Layout* layout)
+ : options_(options), input_objects_(input_objects), symtab_(symtab),
+ layout_(layout)
+ { }
+
+ void
+ run(Workqueue*);
+
+ private:
+ const General_options& options_;
+ const Input_objects* input_objects_;
+ Symbol_table* symtab_;
+ Layout* layout_;
+};
+
+void
+Middle_runner::run(Workqueue* workqueue)
+{
+ queue_middle_tasks(this->options_, this->input_objects_, this->symtab_,
+ this->layout_, workqueue);
+}
+
+// Queue up the initial set of tasks for this link job.
+
+void
+queue_initial_tasks(const General_options& options,
+ const Dirsearch& search_path,
+ const Command_line& cmdline,
+ Workqueue* workqueue, Input_objects* input_objects,
+ Symbol_table* symtab, Layout* layout)
+{
+ if (cmdline.begin() == cmdline.end())
+ gold_fatal(_("no input files"), false);
+
+ // Read the input files. We have to add the symbols to the symbol
+ // table in order. We do this by creating a separate blocker for
+ // each input file. We associate the blocker with the following
+ // input file, to give us a convenient place to delete it.
+ Task_token* this_blocker = NULL;
+ for (Command_line::const_iterator p = cmdline.begin();
+ p != cmdline.end();
+ ++p)
+ {
+ Task_token* next_blocker = new Task_token();
+ next_blocker->add_blocker();
+ workqueue->queue(new Read_symbols(options, input_objects, symtab, layout,
+ search_path, &*p, NULL, this_blocker,
+ next_blocker));
+ this_blocker = next_blocker;
+ }
+
+ workqueue->queue(new Task_function(new Middle_runner(options,
+ input_objects,
+ symtab,
+ layout),
+ this_blocker));
+}
+
+// Queue up the middle set of tasks. These are the tasks which run
+// after all the input objects have been found and all the symbols
+// have been read, but before we lay out the output file.
+
+void
+queue_middle_tasks(const General_options& options,
+ const Input_objects* input_objects,
+ Symbol_table* symtab,
+ Layout* layout,
+ Workqueue* workqueue)
+{
+ // Define some sections and symbols needed for a dynamic link. This
+ // handles some cases we want to see before we read the relocs.
+ layout->create_initial_dynamic_sections(input_objects, symtab);
+
+ // Predefine standard symbols. This should be fast, so we don't
+ // bother to create a task for it.
+ define_standard_symbols(symtab, layout, input_objects->target());
+
+ // Read the relocations of the input files. We do this to find
+ // which symbols are used by relocations which require a GOT and/or
+ // a PLT entry, or a COPY reloc. When we implement garbage
+ // collection we will do it here by reading the relocations in a
+ // breadth first search by references.
+ //
+ // We could also read the relocations during the first pass, and
+ // mark symbols at that time. That is how the old GNU linker works.
+ // Doing that is more complex, since we may later decide to discard
+ // some of the sections, and thus change our minds about the types
+ // of references made to the symbols.
+ Task_token* blocker = new Task_token();
+ Task_token* symtab_lock = new Task_token();
+ for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
+ p != input_objects->relobj_end();
+ ++p)
+ {
+ // We can read and process the relocations in any order. But we
+ // only want one task to write to the symbol table at a time.
+ // So we queue up a task for each object to read the
+ // relocations. That task will in turn queue a task to wait
+ // until it can write to the symbol table.
+ blocker->add_blocker();
+ workqueue->queue(new Read_relocs(options, symtab, layout, *p,
+ symtab_lock, blocker));
+ }
+
+ // Allocate common symbols. This requires write access to the
+ // symbol table, but is independent of the relocation processing.
+ blocker->add_blocker();
+ workqueue->queue(new Allocate_commons_task(options, symtab, layout,
+ symtab_lock, blocker));
+
+ // When all those tasks are complete, we can start laying out the
+ // output file.
+ workqueue->queue(new Task_function(new Layout_task_runner(options,
+ input_objects,
+ symtab,
+ layout),
+ blocker));
+}
+
+// Queue up the final set of tasks. This is called at the end of
+// Layout_task.
+
+void
+queue_final_tasks(const General_options& options,
+ const Input_objects* input_objects,
+ const Symbol_table* symtab,
+ const Layout* layout,
+ Workqueue* workqueue,
+ Output_file* of)
+{
+ // Use a blocker to block the final cleanup task.
+ Task_token* final_blocker = new Task_token();
+
+ // Queue a task for each input object to relocate the sections and
+ // write out the local symbols.
+ for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
+ p != input_objects->relobj_end();
+ ++p)
+ {
+ final_blocker->add_blocker();
+ workqueue->queue(new Relocate_task(options, symtab, layout, *p, of,
+ final_blocker));
+ }
+
+ // Queue a task to write out the symbol table.
+ final_blocker->add_blocker();
+ workqueue->queue(new Write_symbols_task(symtab,
+ input_objects->target(),
+ layout->sympool(),
+ layout->dynpool(),
+ of,
+ final_blocker));
+
+ // Queue a task to write out everything else.
+ final_blocker->add_blocker();
+ workqueue->queue(new Write_data_task(layout, symtab,
+ input_objects->target(),
+ of, final_blocker));
+
+ // Queue a task to close the output file. This will be blocked by
+ // FINAL_BLOCKER.
+ workqueue->queue(new Task_function(new Close_task_runner(of),
+ final_blocker));
+}
+
+} // End namespace gold.
diff --git a/gold/gold.h b/gold/gold.h
new file mode 100644
index 000000000000..288d9eb937bf
--- /dev/null
+++ b/gold/gold.h
@@ -0,0 +1,214 @@
+// gold.h -- general definitions for gold -*- C++ -*-
+
+#ifndef GOLD_GOLD_H
+
+#include "config.h"
+#include "ansidecl.h"
+
+#ifdef ENABLE_NLS
+# include <libintl.h>
+# define _(String) gettext (String)
+# ifdef gettext_noop
+# define N_(String) gettext_noop (String)
+# else
+# define N_(String) (String)
+# endif
+#else
+# define gettext(Msgid) (Msgid)
+# define dgettext(Domainname, Msgid) (Msgid)
+# define dcgettext(Domainname, Msgid, Category) (Msgid)
+# define textdomain(Domainname) while (0) /* nothing */
+# define bindtextdomain(Domainname, Dirname) while (0) /* nothing */
+# define _(String) (String)
+# define N_(String) (String)
+#endif
+
+// Figure out how to get a hash set and a hash map.
+
+#if defined(HAVE_TR1_UNORDERED_SET) && defined(HAVE_TR1_UNORDERED_MAP)
+
+#include <tr1/unordered_set>
+#include <tr1/unordered_map>
+
+// We need a template typedef here.
+
+#define Unordered_set std::tr1::unordered_set
+#define Unordered_map std::tr1::unordered_map
+
+#elif defined(HAVE_EXT_HASH_MAP) && defined(HAVE_EXT_HASH_SET)
+
+#include <ext/hash_map>
+#include <ext/hash_set>
+#include <string>
+
+#define Unordered_set __gnu_cxx::hash_set
+#define Unordered_map __gnu_cxx::hash_map
+
+namespace __gnu_cxx
+{
+
+template<>
+struct hash<std::string>
+{
+ size_t
+ operator()(std::string s) const
+ { return __stl_hash_string(s.c_str()); }
+};
+
+template<typename T>
+struct hash<T*>
+{
+ size_t
+ operator()(T* p) const
+ { return reinterpret_cast<size_t>(p); }
+};
+
+}
+
+#else
+
+// The fallback is to just use set and map.
+
+#include <set>
+#include <map>
+
+#define Unordered_set std::set
+#define Unordered_map std::map
+
+#endif
+
+namespace gold
+{
+// This is a hack to work around a problem with older versions of g++.
+// The problem is that they don't support calling a member template by
+// specifying the template parameters. It works to pass in an
+// argument for argument dependent lookup.
+
+// To use this, the member template method declaration should put
+// ACCEPT_SIZE or ACCEPT_SIZE_ENDIAN after the last parameter. If the
+// method takes no parameters, use ACCEPT_SIZE_ONLY or
+// ACCEPT_SIZE_ENDIAN_ONLY.
+
+// When calling the method, instead of using fn<size>, use fn
+// SELECT_SIZE_NAME or SELECT_SIZE_ENDIAN_NAME. And after the last
+// argument, put SELECT_SIZE(size) or SELECT_SIZE_ENDIAN(size,
+// big_endian). If there is only one argment, use the _ONLY variants.
+
+#ifdef HAVE_MEMBER_TEMPLATE_SPECIFICATIONS
+
+#define SELECT_SIZE_NAME(size) <size>
+#define SELECT_SIZE(size)
+#define SELECT_SIZE_ONLY(size)
+#define ACCEPT_SIZE
+#define ACCEPT_SIZE_ONLY
+#define ACCEPT_SIZE_EXPLICIT(size)
+
+#define SELECT_SIZE_ENDIAN_NAME(size, big_endian) <size, big_endian>
+#define SELECT_SIZE_ENDIAN(size, big_endian)
+#define SELECT_SIZE_ENDIAN_ONLY(size, big_endian)
+#define ACCEPT_SIZE_ENDIAN
+#define ACCEPT_SIZE_ENDIAN_ONLY
+#define ACCEPT_SIZE_ENDIAN_EXPLICIT(size, big_endian)
+
+#else // !defined(HAVE_MEMBER_TEMPLATE_SPECIFICATIONS)
+
+template<int size>
+class Select_size { };
+template<int size, bool big_endian>
+class Select_size_endian { };
+
+#define SELECT_SIZE_NAME(size)
+#define SELECT_SIZE(size) , Select_size<size>()
+#define SELECT_SIZE_ONLY(size) Select_size<size>()
+#define ACCEPT_SIZE , Select_size<size>
+#define ACCEPT_SIZE_ONLY Select_size<size>
+#define ACCEPT_SIZE_EXPLICIT(size) , Select_size<size>
+
+#define SELECT_SIZE_ENDIAN_NAME(size, big_endian)
+#define SELECT_SIZE_ENDIAN(size, big_endian) \
+ , Select_size_endian<size, big_endian>()
+#define SELECT_SIZE_ENDIAN_ONLY(size, big_endian) \
+ Select_size_endian<size, big_endian>()
+#define ACCEPT_SIZE_ENDIAN , Select_size_endian<size, big_endian>
+#define ACCEPT_SIZE_ENDIAN_ONLY Select_size_endian<size, big_endian>
+#define ACCEPT_SIZE_ENDIAN_EXPLICIT(size, big_endian) \
+ , Select_size_endian<size, big_endian>
+
+#endif // !defined(HAVE_MEMBER_TEMPLATE_SPECIFICATIONS)
+
+} // End namespace gold.
+
+namespace gold
+{
+
+class General_options;
+class Command_line;
+class Input_argument_list;
+class Dirsearch;
+class Input_objects;
+class Symbol_table;
+class Layout;
+class Workqueue;
+class Output_file;
+
+// The name of the program as used in error messages.
+extern const char* program_name;
+
+// This function is called to exit the program. Status is true to
+// exit success (0) and false to exit failure (1).
+extern void
+gold_exit(bool status) ATTRIBUTE_NORETURN;
+
+// This function is called to emit an unexpected error message and a
+// newline, and then exit with failure. If PERRNO is true, it reports
+// the error in errno.
+extern void
+gold_fatal(const char* msg, bool perrno) ATTRIBUTE_NORETURN;
+
+// This is function is called in some cases if we run out of memory.
+extern void
+gold_nomem() ATTRIBUTE_NORETURN;
+
+// This macro and function are used in cases which can not arise if
+// the code is written correctly.
+
+#define gold_unreachable() \
+ (gold::do_gold_unreachable(__FILE__, __LINE__, __FUNCTION__))
+
+extern void do_gold_unreachable(const char*, int, const char*)
+ ATTRIBUTE_NORETURN;
+
+// Assertion check.
+
+#define gold_assert(expr) ((void)(!(expr) ? gold_unreachable(), 0 : 0))
+
+// Queue up the first set of tasks.
+extern void
+queue_initial_tasks(const General_options&,
+ const Dirsearch&,
+ const Command_line&,
+ Workqueue*,
+ Input_objects*,
+ Symbol_table*,
+ Layout*);
+
+// Queue up the middle set of tasks.
+extern void
+queue_middle_tasks(const General_options&,
+ const Input_objects*,
+ Symbol_table*,
+ Layout*,
+ Workqueue*);
+
+// Queue up the final set of tasks.
+extern void
+queue_final_tasks(const General_options&,
+ const Input_objects*,
+ const Symbol_table*,
+ const Layout*,
+ Workqueue*,
+ Output_file* of);
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_GOLD_H)
diff --git a/gold/i386.cc b/gold/i386.cc
new file mode 100644
index 000000000000..448453aa3495
--- /dev/null
+++ b/gold/i386.cc
@@ -0,0 +1,1517 @@
+// i386.cc -- i386 target support for gold.
+
+#include "gold.h"
+
+#include <cstring>
+
+#include "elfcpp.h"
+#include "reloc.h"
+#include "i386.h"
+#include "object.h"
+#include "symtab.h"
+#include "layout.h"
+#include "output.h"
+#include "target.h"
+#include "target-reloc.h"
+#include "target-select.h"
+
+namespace
+{
+
+using namespace gold;
+
+class Output_data_plt_i386;
+
+// The i386 target class.
+
+class Target_i386 : public Sized_target<32, false>
+{
+ public:
+ typedef Output_data_reloc<elfcpp::SHT_REL, true, 32, false> Reloc_section;
+
+ Target_i386()
+ : Sized_target<32, false>(&i386_info),
+ got_(NULL), plt_(NULL), got_plt_(NULL), rel_dyn_(NULL),
+ copy_relocs_(NULL), dynbss_(NULL)
+ { }
+
+ // Scan the relocations to look for symbol adjustments.
+ void
+ scan_relocs(const General_options& options,
+ Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj<32, false>* object,
+ unsigned int data_shndx,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ size_t local_symbol_count,
+ const unsigned char* plocal_symbols,
+ Symbol** global_symbols);
+
+ // Finalize the sections.
+ void
+ do_finalize_sections(const General_options*, Layout*);
+
+ // Relocate a section.
+ void
+ relocate_section(const Relocate_info<32, false>*,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ unsigned char* view,
+ elfcpp::Elf_types<32>::Elf_Addr view_address,
+ off_t view_size);
+
+ private:
+ // The class which scans relocations.
+ struct Scan
+ {
+ inline void
+ local(const General_options& options, Symbol_table* symtab,
+ Layout* layout, Target_i386* target,
+ Sized_relobj<32, false>* object,
+ unsigned int data_shndx,
+ const elfcpp::Rel<32, false>& reloc, unsigned int r_type,
+ const elfcpp::Sym<32, false>& lsym);
+
+ inline void
+ global(const General_options& options, Symbol_table* symtab,
+ Layout* layout, Target_i386* target,
+ Sized_relobj<32, false>* object,
+ unsigned int data_shndx,
+ const elfcpp::Rel<32, false>& reloc, unsigned int r_type,
+ Symbol* gsym);
+ };
+
+ // The class which implements relocation.
+ class Relocate
+ {
+ public:
+ Relocate()
+ : skip_call_tls_get_addr_(false)
+ { }
+
+ ~Relocate()
+ {
+ if (this->skip_call_tls_get_addr_)
+ {
+ // FIXME: This needs to specify the location somehow.
+ fprintf(stderr, _("%s: missing expected TLS relocation\n"),
+ program_name);
+ gold_exit(false);
+ }
+ }
+
+ // Do a relocation. Return false if the caller should not issue
+ // any warnings about this relocation.
+ inline bool
+ relocate(const Relocate_info<32, false>*, Target_i386*, size_t relnum,
+ const elfcpp::Rel<32, false>&,
+ unsigned int r_type, const Sized_symbol<32>*,
+ const Symbol_value<32>*,
+ unsigned char*, elfcpp::Elf_types<32>::Elf_Addr,
+ off_t);
+
+ private:
+ // Do a TLS relocation.
+ inline void
+ relocate_tls(const Relocate_info<32, false>*, size_t relnum,
+ const elfcpp::Rel<32, false>&,
+ unsigned int r_type, const Sized_symbol<32>*,
+ const Symbol_value<32>*,
+ unsigned char*, elfcpp::Elf_types<32>::Elf_Addr, off_t);
+
+ // Do a TLS Initial-Exec to Local-Exec transition.
+ static inline void
+ tls_ie_to_le(const Relocate_info<32, false>*, size_t relnum,
+ Output_segment* tls_segment,
+ const elfcpp::Rel<32, false>&, unsigned int r_type,
+ elfcpp::Elf_types<32>::Elf_Addr value,
+ unsigned char* view,
+ off_t view_size);
+
+ // Do a TLS Global-Dynamic to Local-Exec transition.
+ inline void
+ tls_gd_to_le(const Relocate_info<32, false>*, size_t relnum,
+ Output_segment* tls_segment,
+ const elfcpp::Rel<32, false>&, unsigned int r_type,
+ elfcpp::Elf_types<32>::Elf_Addr value,
+ unsigned char* view,
+ off_t view_size);
+
+ // Check the range for a TLS relocation.
+ static inline void
+ check_range(const Relocate_info<32, false>*, size_t relnum,
+ const elfcpp::Rel<32, false>&, off_t, off_t);
+
+ // Check the validity of a TLS relocation. This is like assert.
+ static inline void
+ check_tls(const Relocate_info<32, false>*, size_t relnum,
+ const elfcpp::Rel<32, false>&, bool);
+
+ // This is set if we should skip the next reloc, which should be a
+ // PLT32 reloc against ___tls_get_addr.
+ bool skip_call_tls_get_addr_;
+ };
+
+ // Adjust TLS relocation type based on the options and whether this
+ // is a local symbol.
+ static unsigned int
+ optimize_tls_reloc(const General_options*, bool is_final, int r_type);
+
+ // Get the GOT section, creating it if necessary.
+ Output_data_got<32, false>*
+ got_section(const General_options*, Symbol_table*, Layout*);
+
+ // Create a PLT entry for a global symbol.
+ void
+ make_plt_entry(const General_options* options, Symbol_table*,
+ Layout*, Symbol*);
+
+ // Get the PLT section.
+ Output_data_plt_i386*
+ plt_section() const
+ {
+ gold_assert(this->plt_ != NULL);
+ 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*, 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
+ // general Target structure.
+ static const Target::Target_info i386_info;
+
+ // The GOT section.
+ Output_data_got<32, false>* got_;
+ // The PLT section.
+ 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 =
+{
+ 32, // size
+ false, // is_big_endian
+ elfcpp::EM_386, // machine_code
+ false, // has_make_symbol
+ false, // has_resolve
+ "/usr/lib/libc.so.1", // dynamic_linker
+ 0x08048000, // text_segment_address
+ 0x1000, // abi_pagesize
+ 0x1000 // common_pagesize
+};
+
+// Get the GOT section, creating it if necessary.
+
+Output_data_got<32, false>*
+Target_i386::got_section(const General_options* options, Symbol_table* symtab,
+ Layout* layout)
+{
+ if (this->got_ == NULL)
+ {
+ gold_assert(options != NULL && symtab != NULL && layout != NULL);
+
+ this->got_ = new Output_data_got<32, false>(options);
+
+ layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
+ elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
+ this->got_);
+
+ // The old GNU linker creates a .got.plt section. We just
+ // create another set of data in the .got section. Note that we
+ // always create a PLT if we create a GOT, although the PLT
+ // might be empty.
+ this->got_plt_ = new Output_data_space(4);
+ layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
+ elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
+ this->got_plt_);
+
+ // The first three entries are reserved.
+ this->got_plt_->set_space_size(3 * 4);
+
+ // Define _GLOBAL_OFFSET_TABLE_ at the start of the PLT.
+ symtab->define_in_output_data(this, "_GLOBAL_OFFSET_TABLE_", NULL,
+ this->got_plt_,
+ 0, 0, elfcpp::STT_OBJECT,
+ elfcpp::STB_LOCAL,
+ elfcpp::STV_HIDDEN, 0,
+ false, false);
+ }
+
+ 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
+{
+ public:
+ typedef Output_data_reloc<elfcpp::SHT_REL, true, 32, false> Reloc_section;
+
+ Output_data_plt_i386(Layout*, Output_data_space*, bool is_shared);
+
+ // Add an entry to the PLT.
+ void
+ add_entry(Symbol* gsym);
+
+ // Return the .rel.plt section data.
+ const Reloc_section*
+ rel_plt() const
+ { return this->rel_; }
+
+ protected:
+ void
+ do_adjust_output_section(Output_section* os);
+
+ private:
+ // The size of an entry in the PLT.
+ static const int plt_entry_size = 16;
+
+ // The first entry in the PLT for an executable.
+ static unsigned char exec_first_plt_entry[plt_entry_size];
+
+ // The first entry in the PLT for a shared object.
+ static unsigned char dyn_first_plt_entry[plt_entry_size];
+
+ // Other entries in the PLT for an executable.
+ static unsigned char exec_plt_entry[plt_entry_size];
+
+ // Other entries in the PLT for a shared object.
+ static unsigned char dyn_plt_entry[plt_entry_size];
+
+ // Set the final size.
+ void
+ do_set_address(uint64_t, off_t)
+ { this->set_data_size((this->count_ + 1) * plt_entry_size); }
+
+ // Write out the PLT data.
+ void
+ do_write(Output_file*);
+
+ // The reloc section.
+ Reloc_section* rel_;
+ // The .got.plt section.
+ Output_data_space* got_plt_;
+ // The number of PLT entries.
+ unsigned int count_;
+ // Whether we are generated a shared object.
+ bool is_shared_;
+};
+
+// Create the PLT section. The ordinary .got section is an argument,
+// since we need to refer to the start. We also create our own .got
+// section just for PLT entries.
+
+Output_data_plt_i386::Output_data_plt_i386(Layout* layout,
+ Output_data_space* got_plt,
+ bool is_shared)
+ : Output_section_data(4), got_plt_(got_plt), is_shared_(is_shared)
+{
+ this->rel_ = new Reloc_section();
+ layout->add_output_section_data(".rel.plt", elfcpp::SHT_REL,
+ elfcpp::SHF_ALLOC, this->rel_);
+}
+
+// For some reason
+
+void
+Output_data_plt_i386::do_adjust_output_section(Output_section* os)
+{
+ // UnixWare sets the entsize of .plt to 4, and so does the old GNU
+ // linker, and so do we.
+ os->set_entsize(4);
+}
+
+// Add an entry to the PLT.
+
+void
+Output_data_plt_i386::add_entry(Symbol* gsym)
+{
+ gold_assert(!gsym->has_plt_offset());
+
+ // Note that when setting the PLT offset we skip the initial
+ // reserved PLT entry.
+ gsym->set_plt_offset((this->count_ + 1) * plt_entry_size);
+
+ ++this->count_;
+
+ off_t got_offset = this->got_plt_->data_size();
+
+ // Every PLT entry needs a GOT entry which points back to the PLT
+ // entry (this will be changed by the dynamic linker, normally
+ // lazily when the function is called).
+ this->got_plt_->set_space_size(got_offset + 4);
+
+ // Every PLT entry needs a reloc.
+ gsym->set_needs_dynsym_entry();
+ this->rel_->add_global(gsym, elfcpp::R_386_JUMP_SLOT, this->got_plt_,
+ got_offset);
+
+ // Note that we don't need to save the symbol. The contents of the
+ // PLT are independent of which symbols are used. The symbols only
+ // appear in the relocations.
+}
+
+// The first entry in the PLT for an executable.
+
+unsigned char Output_data_plt_i386::exec_first_plt_entry[plt_entry_size] =
+{
+ 0xff, 0x35, // pushl contents of memory address
+ 0, 0, 0, 0, // replaced with address of .got + 4
+ 0xff, 0x25, // jmp indirect
+ 0, 0, 0, 0, // replaced with address of .got + 8
+ 0, 0, 0, 0 // unused
+};
+
+// The first entry in the PLT for a shared object.
+
+unsigned char Output_data_plt_i386::dyn_first_plt_entry[plt_entry_size] =
+{
+ 0xff, 0xb3, 4, 0, 0, 0, // pushl 4(%ebx)
+ 0xff, 0xa3, 8, 0, 0, 0, // jmp *8(%ebx)
+ 0, 0, 0, 0 // unused
+};
+
+// Subsequent entries in the PLT for an executable.
+
+unsigned char Output_data_plt_i386::exec_plt_entry[plt_entry_size] =
+{
+ 0xff, 0x25, // jmp indirect
+ 0, 0, 0, 0, // replaced with address of symbol in .got
+ 0x68, // pushl immediate
+ 0, 0, 0, 0, // replaced with offset into relocation table
+ 0xe9, // jmp relative
+ 0, 0, 0, 0 // replaced with offset to start of .plt
+};
+
+// Subsequent entries in the PLT for a shared object.
+
+unsigned char Output_data_plt_i386::dyn_plt_entry[plt_entry_size] =
+{
+ 0xff, 0xa3, // jmp *offset(%ebx)
+ 0, 0, 0, 0, // replaced with offset of symbol in .got
+ 0x68, // pushl immediate
+ 0, 0, 0, 0, // replaced with offset into relocation table
+ 0xe9, // jmp relative
+ 0, 0, 0, 0 // replaced with offset to start of .plt
+};
+
+// Write out the PLT. This uses the hand-coded instructions above,
+// and adjusts them as needed. This is all specified by the i386 ELF
+// Processor Supplement.
+
+void
+Output_data_plt_i386::do_write(Output_file* of)
+{
+ const off_t offset = this->offset();
+ const off_t oview_size = this->data_size();
+ unsigned char* const oview = of->get_output_view(offset, oview_size);
+
+ const off_t got_file_offset = this->got_plt_->offset();
+ const off_t got_size = this->got_plt_->data_size();
+ unsigned char* const got_view = of->get_output_view(got_file_offset,
+ got_size);
+
+ unsigned char* pov = oview;
+
+ elfcpp::Elf_types<32>::Elf_Addr plt_address = this->address();
+ elfcpp::Elf_types<32>::Elf_Addr got_address = this->got_plt_->address();
+
+ if (this->is_shared_)
+ memcpy(pov, dyn_first_plt_entry, plt_entry_size);
+ else
+ {
+ memcpy(pov, exec_first_plt_entry, plt_entry_size);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 2, got_address + 4);
+ elfcpp::Swap<32, false>::writeval(pov + 8, got_address + 8);
+ }
+ pov += plt_entry_size;
+
+ unsigned char* got_pov = got_view;
+
+ memset(got_pov, 0, 12);
+ got_pov += 12;
+
+ const int rel_size = elfcpp::Elf_sizes<32>::rel_size;
+
+ unsigned int plt_offset = plt_entry_size;
+ unsigned int plt_rel_offset = 0;
+ unsigned int got_offset = 12;
+ const unsigned int count = this->count_;
+ for (unsigned int i = 0;
+ i < count;
+ ++i,
+ pov += plt_entry_size,
+ got_pov += 4,
+ plt_offset += plt_entry_size,
+ plt_rel_offset += rel_size,
+ got_offset += 4)
+ {
+ // Set and adjust the PLT entry itself.
+
+ if (this->is_shared_)
+ {
+ memcpy(pov, dyn_plt_entry, plt_entry_size);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 2, got_offset);
+ }
+ else
+ {
+ memcpy(pov, exec_plt_entry, plt_entry_size);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 2,
+ (got_address
+ + got_offset));
+ }
+
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 7, plt_rel_offset);
+ elfcpp::Swap<32, false>::writeval(pov + 12,
+ - (plt_offset + plt_entry_size));
+
+ // Set the entry in the GOT.
+ elfcpp::Swap<32, false>::writeval(got_pov, plt_address + plt_offset + 6);
+ }
+
+ gold_assert(pov - oview == oview_size);
+ gold_assert(got_pov - got_view == got_size);
+
+ of->write_output_view(offset, oview_size, oview);
+ of->write_output_view(got_file_offset, got_size, got_view);
+}
+
+// Create a PLT entry for a global symbol.
+
+void
+Target_i386::make_plt_entry(const General_options* options,
+ Symbol_table* symtab, Layout* layout, Symbol* gsym)
+{
+ if (gsym->has_plt_offset())
+ return;
+
+ if (this->plt_ == NULL)
+ {
+ // Create the GOT sections first.
+ this->got_section(options, symtab, layout);
+
+ this->plt_ = new Output_data_plt_i386(layout, this->got_plt_,
+ options->is_shared());
+ layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
+ (elfcpp::SHF_ALLOC
+ | elfcpp::SHF_EXECINSTR),
+ this->plt_);
+ }
+
+ this->plt_->add_entry(gsym);
+}
+
+// Handle a relocation against a non-function symbol defined in a
+// dynamic object. The traditional way to handle this is to generate
+// a COPY relocation to copy the variable at runtime from the shared
+// object into the executable's data segment. However, this is
+// undesirable in general, as if the size of the object changes in the
+// dynamic object, the executable will no longer work correctly. If
+// this relocation is in a writable section, then we can create a
+// dynamic reloc and the dynamic linker will resolve it to the correct
+// address at runtime. However, we do not want do that if the
+// relocation is in a read-only section, as it would prevent the
+// readonly segment from being shared. And if we have to eventually
+// generate a COPY reloc, then any dynamic relocations will be
+// useless. So this means that if this is a writable section, we need
+// to save the relocation until we see whether we have to create a
+// COPY relocation for this symbol for any other relocation.
+
+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>& rel)
+{
+ 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 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(), ssym->version(),
+ dynbss, offset, symsize, ssym->type(),
+ ssym->binding(), ssym->visibility(),
+ ssym->nonvis(), false, false);
+
+ // Add the COPY reloc.
+ ssym->set_needs_dynsym_entry();
+ 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
+// symbol. IS_FINAL is true if the final address of this symbol is
+// known at link time.
+
+unsigned int
+Target_i386::optimize_tls_reloc(const General_options* options,
+ bool is_final,
+ int r_type)
+{
+ // If we are generating a shared library, then we can't do anything
+ // in the linker.
+ if (options->is_shared())
+ return r_type;
+
+ switch (r_type)
+ {
+ case elfcpp::R_386_TLS_GD:
+ case elfcpp::R_386_TLS_GOTDESC:
+ case elfcpp::R_386_TLS_DESC_CALL:
+ // These are Global-Dynamic which permits fully general TLS
+ // access. Since we know that we are generating an executable,
+ // we can convert this to Initial-Exec. If we also know that
+ // this is a local symbol, we can further switch to Local-Exec.
+ if (is_final)
+ return elfcpp::R_386_TLS_LE_32;
+ return elfcpp::R_386_TLS_IE_32;
+
+ case elfcpp::R_386_TLS_LDM:
+ // This is Local-Dynamic, which refers to a local symbol in the
+ // dynamic TLS block. Since we know that we generating an
+ // executable, we can switch to Local-Exec.
+ return elfcpp::R_386_TLS_LE_32;
+
+ case elfcpp::R_386_TLS_LDO_32:
+ // Another type of Local-Dynamic relocation.
+ return elfcpp::R_386_TLS_LE;
+
+ case elfcpp::R_386_TLS_IE:
+ case elfcpp::R_386_TLS_GOTIE:
+ case elfcpp::R_386_TLS_IE_32:
+ // These are Initial-Exec relocs which get the thread offset
+ // from the GOT. If we know that we are linking against the
+ // local symbol, we can switch to Local-Exec, which links the
+ // thread offset into the instruction.
+ if (is_final)
+ return elfcpp::R_386_TLS_LE_32;
+ return r_type;
+
+ case elfcpp::R_386_TLS_LE:
+ case elfcpp::R_386_TLS_LE_32:
+ // When we already have Local-Exec, there is nothing further we
+ // can do.
+ return r_type;
+
+ default:
+ gold_unreachable();
+ }
+}
+
+// Scan a relocation for a local symbol.
+
+inline void
+Target_i386::Scan::local(const General_options& options,
+ Symbol_table* symtab,
+ Layout* layout,
+ Target_i386* target,
+ Sized_relobj<32, false>* object,
+ unsigned int,
+ const elfcpp::Rel<32, false>&,
+ unsigned int r_type,
+ const elfcpp::Sym<32, false>&)
+{
+ switch (r_type)
+ {
+ case elfcpp::R_386_NONE:
+ case elfcpp::R_386_GNU_VTINHERIT:
+ case elfcpp::R_386_GNU_VTENTRY:
+ break;
+
+ case elfcpp::R_386_32:
+ case elfcpp::R_386_16:
+ case elfcpp::R_386_8:
+ // FIXME: If we are generating a shared object we need to copy
+ // this relocation into the object.
+ gold_assert(!options.is_shared());
+ break;
+
+ case elfcpp::R_386_PC32:
+ case elfcpp::R_386_PC16:
+ case elfcpp::R_386_PC8:
+ break;
+
+ case elfcpp::R_386_GOTOFF:
+ case elfcpp::R_386_GOTPC:
+ // We need a GOT section.
+ target->got_section(&options, symtab, layout);
+ break;
+
+ case elfcpp::R_386_COPY:
+ case elfcpp::R_386_GLOB_DAT:
+ case elfcpp::R_386_JUMP_SLOT:
+ case elfcpp::R_386_RELATIVE:
+ case elfcpp::R_386_TLS_TPOFF:
+ case elfcpp::R_386_TLS_DTPMOD32:
+ case elfcpp::R_386_TLS_DTPOFF32:
+ case elfcpp::R_386_TLS_TPOFF32:
+ case elfcpp::R_386_TLS_DESC:
+ fprintf(stderr, _("%s: %s: unexpected reloc %u in object file\n"),
+ program_name, object->name().c_str(), r_type);
+ gold_exit(false);
+ break;
+
+ case elfcpp::R_386_TLS_IE:
+ case elfcpp::R_386_TLS_GOTIE:
+ case elfcpp::R_386_TLS_LE:
+ case elfcpp::R_386_TLS_GD:
+ case elfcpp::R_386_TLS_LDM:
+ case elfcpp::R_386_TLS_LDO_32:
+ case elfcpp::R_386_TLS_IE_32:
+ case elfcpp::R_386_TLS_LE_32:
+ case elfcpp::R_386_TLS_GOTDESC:
+ case elfcpp::R_386_TLS_DESC_CALL:
+ r_type = Target_i386::optimize_tls_reloc(&options,
+ !options.is_shared(),
+ r_type);
+ switch (r_type)
+ {
+ case elfcpp::R_386_TLS_LE:
+ case elfcpp::R_386_TLS_LE_32:
+ // FIXME: If generating a shared object, we need to copy
+ // this relocation into the object.
+ gold_assert(!options.is_shared());
+ break;
+
+ case elfcpp::R_386_TLS_IE:
+ case elfcpp::R_386_TLS_GOTIE:
+ case elfcpp::R_386_TLS_GD:
+ case elfcpp::R_386_TLS_LDM:
+ case elfcpp::R_386_TLS_LDO_32:
+ case elfcpp::R_386_TLS_IE_32:
+ case elfcpp::R_386_TLS_GOTDESC:
+ case elfcpp::R_386_TLS_DESC_CALL:
+ fprintf(stderr,
+ _("%s: %s: unsupported reloc %u against local symbol\n"),
+ program_name, object->name().c_str(), r_type);
+ break;
+ }
+ break;
+
+ case elfcpp::R_386_GOT32:
+ case elfcpp::R_386_PLT32:
+ case elfcpp::R_386_32PLT:
+ case elfcpp::R_386_TLS_GD_32:
+ case elfcpp::R_386_TLS_GD_PUSH:
+ case elfcpp::R_386_TLS_GD_CALL:
+ case elfcpp::R_386_TLS_GD_POP:
+ case elfcpp::R_386_TLS_LDM_32:
+ case elfcpp::R_386_TLS_LDM_PUSH:
+ case elfcpp::R_386_TLS_LDM_CALL:
+ case elfcpp::R_386_TLS_LDM_POP:
+ case elfcpp::R_386_USED_BY_INTEL_200:
+ default:
+ fprintf(stderr, _("%s: %s: unsupported reloc %u against local symbol\n"),
+ program_name, object->name().c_str(), r_type);
+ break;
+ }
+}
+
+// Scan a relocation for a global symbol.
+
+inline void
+Target_i386::Scan::global(const General_options& options,
+ Symbol_table* symtab,
+ Layout* layout,
+ Target_i386* target,
+ Sized_relobj<32, false>* object,
+ unsigned int data_shndx,
+ const elfcpp::Rel<32, false>& reloc,
+ unsigned int r_type,
+ Symbol* gsym)
+{
+ switch (r_type)
+ {
+ case elfcpp::R_386_NONE:
+ case elfcpp::R_386_GNU_VTINHERIT:
+ case elfcpp::R_386_GNU_VTENTRY:
+ break;
+
+ case elfcpp::R_386_32:
+ case elfcpp::R_386_PC32:
+ case elfcpp::R_386_16:
+ case elfcpp::R_386_PC16:
+ case elfcpp::R_386_8:
+ case elfcpp::R_386_PC8:
+ // FIXME: If we are generating a shared object we may need to
+ // copy this relocation into the object. If this symbol is
+ // defined in a shared object, we may need to copy this
+ // relocation in order to avoid a COPY relocation.
+ gold_assert(!options.is_shared());
+
+ if (gsym->is_from_dynobj())
+ {
+ // This symbol is defined in a dynamic object. If it is a
+ // function, we make a PLT entry. Otherwise we need to
+ // either generate a COPY reloc or copy this reloc.
+ if (gsym->type() == elfcpp::STT_FUNC)
+ target->make_plt_entry(&options, symtab, layout, gsym);
+ else
+ target->copy_reloc(&options, symtab, layout, object, data_shndx,
+ gsym, reloc);
+ }
+
+ break;
+
+ case elfcpp::R_386_GOT32:
+ // The symbol requires a GOT entry.
+ if (target->got_section(&options, symtab, layout)->add_global(gsym))
+ {
+ // If this symbol is not fully resolved, we need to add a
+ // dynamic relocation for it.
+ if (!gsym->final_value_is_known(&options))
+ gold_unreachable();
+ }
+ break;
+
+ case elfcpp::R_386_PLT32:
+ // If the symbol is fully resolved, this is just a PC32 reloc.
+ // Otherwise we need a PLT entry.
+ if (gsym->final_value_is_known(&options))
+ break;
+ target->make_plt_entry(&options, symtab, layout, gsym);
+ break;
+
+ case elfcpp::R_386_GOTOFF:
+ case elfcpp::R_386_GOTPC:
+ // We need a GOT section.
+ target->got_section(&options, symtab, layout);
+ break;
+
+ case elfcpp::R_386_COPY:
+ case elfcpp::R_386_GLOB_DAT:
+ case elfcpp::R_386_JUMP_SLOT:
+ case elfcpp::R_386_RELATIVE:
+ case elfcpp::R_386_TLS_TPOFF:
+ case elfcpp::R_386_TLS_DTPMOD32:
+ case elfcpp::R_386_TLS_DTPOFF32:
+ case elfcpp::R_386_TLS_TPOFF32:
+ case elfcpp::R_386_TLS_DESC:
+ fprintf(stderr, _("%s: %s: unexpected reloc %u in object file\n"),
+ program_name, object->name().c_str(), r_type);
+ gold_exit(false);
+ break;
+
+ case elfcpp::R_386_TLS_IE:
+ case elfcpp::R_386_TLS_GOTIE:
+ case elfcpp::R_386_TLS_LE:
+ case elfcpp::R_386_TLS_GD:
+ case elfcpp::R_386_TLS_LDM:
+ case elfcpp::R_386_TLS_LDO_32:
+ case elfcpp::R_386_TLS_IE_32:
+ case elfcpp::R_386_TLS_LE_32:
+ case elfcpp::R_386_TLS_GOTDESC:
+ case elfcpp::R_386_TLS_DESC_CALL:
+ {
+ const bool is_final = gsym->final_value_is_known(&options);
+ r_type = Target_i386::optimize_tls_reloc(&options, is_final, r_type);
+ switch (r_type)
+ {
+ case elfcpp::R_386_TLS_LE:
+ case elfcpp::R_386_TLS_LE_32:
+ // FIXME: If generating a shared object, we need to copy
+ // this relocation into the object.
+ gold_assert(!options.is_shared());
+ break;
+
+ case elfcpp::R_386_TLS_IE:
+ case elfcpp::R_386_TLS_GOTIE:
+ case elfcpp::R_386_TLS_GD:
+ case elfcpp::R_386_TLS_LDM:
+ case elfcpp::R_386_TLS_LDO_32:
+ case elfcpp::R_386_TLS_IE_32:
+ case elfcpp::R_386_TLS_GOTDESC:
+ case elfcpp::R_386_TLS_DESC_CALL:
+ fprintf(stderr,
+ _("%s: %s: unsupported reloc %u "
+ "against global symbol %s\n"),
+ program_name, object->name().c_str(), r_type,
+ gsym->name());
+ break;
+ }
+ }
+ break;
+
+ case elfcpp::R_386_32PLT:
+ case elfcpp::R_386_TLS_GD_32:
+ case elfcpp::R_386_TLS_GD_PUSH:
+ case elfcpp::R_386_TLS_GD_CALL:
+ case elfcpp::R_386_TLS_GD_POP:
+ case elfcpp::R_386_TLS_LDM_32:
+ case elfcpp::R_386_TLS_LDM_PUSH:
+ case elfcpp::R_386_TLS_LDM_CALL:
+ case elfcpp::R_386_TLS_LDM_POP:
+ case elfcpp::R_386_USED_BY_INTEL_200:
+ default:
+ fprintf(stderr,
+ _("%s: %s: unsupported reloc %u against global symbol %s\n"),
+ program_name, object->name().c_str(), r_type, gsym->name());
+ break;
+ }
+}
+
+// Scan relocations for a section.
+
+void
+Target_i386::scan_relocs(const General_options& options,
+ Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj<32, false>* object,
+ unsigned int data_shndx,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ size_t local_symbol_count,
+ const unsigned char* plocal_symbols,
+ Symbol** global_symbols)
+{
+ if (sh_type == elfcpp::SHT_RELA)
+ {
+ fprintf(stderr, _("%s: %s: unsupported RELA reloc section\n"),
+ program_name, object->name().c_str());
+ gold_exit(false);
+ }
+
+ gold::scan_relocs<32, false, Target_i386, elfcpp::SHT_REL,
+ Target_i386::Scan>(
+ options,
+ symtab,
+ layout,
+ this,
+ object,
+ data_shndx,
+ prelocs,
+ reloc_count,
+ local_symbol_count,
+ plocal_symbols,
+ global_symbols);
+}
+
+// Finalize the sections.
+
+void
+Target_i386::do_finalize_sections(const General_options* options,
+ Layout* layout)
+{
+ // Fill in some more dynamic tags.
+ Output_data_dynamic* const odyn = layout->dynamic_data();
+ if (odyn != NULL)
+ {
+ if (this->got_plt_ != NULL)
+ odyn->add_section_address(elfcpp::DT_PLTGOT, this->got_plt_);
+
+ if (this->plt_ != NULL)
+ {
+ const Output_data* od = this->plt_->rel_plt();
+ odyn->add_section_size(elfcpp::DT_PLTRELSZ, od);
+ odyn->add_section_address(elfcpp::DT_JMPREL, od);
+ odyn->add_constant(elfcpp::DT_PLTREL, elfcpp::DT_REL);
+ }
+
+ if (this->rel_dyn_ != NULL)
+ {
+ const Output_data* od = this->rel_dyn_;
+ odyn->add_section_address(elfcpp::DT_REL, od);
+ odyn->add_section_size(elfcpp::DT_RELSZ, od);
+ odyn->add_constant(elfcpp::DT_RELENT,
+ elfcpp::Elf_sizes<32>::rel_size);
+ }
+
+ if (!options->is_shared())
+ {
+ // The value of the DT_DEBUG tag is filled in by the dynamic
+ // linker at run time, and used by the debugger.
+ odyn->add_constant(elfcpp::DT_DEBUG, 0);
+ }
+ }
+
+ // Emit any relocs we saved in an attempt to avoid generating COPY
+ // relocs.
+ 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
+Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
+ Target_i386* target,
+ size_t relnum,
+ const elfcpp::Rel<32, false>& rel,
+ unsigned int r_type,
+ const Sized_symbol<32>* gsym,
+ const Symbol_value<32>* psymval,
+ unsigned char* view,
+ elfcpp::Elf_types<32>::Elf_Addr address,
+ off_t view_size)
+{
+ if (this->skip_call_tls_get_addr_)
+ {
+ if (r_type != elfcpp::R_386_PLT32
+ || gsym == NULL
+ || strcmp(gsym->name(), "___tls_get_addr") != 0)
+ {
+ fprintf(stderr, _("%s: %s: missing expected TLS relocation\n"),
+ program_name,
+ relinfo->location(relnum, rel.get_r_offset()).c_str());
+ gold_exit(false);
+ }
+
+ this->skip_call_tls_get_addr_ = false;
+
+ return false;
+ }
+
+ // Pick the value to use for symbols defined in shared objects.
+ Symbol_value<32> symval;
+ if (gsym != NULL && gsym->is_from_dynobj())
+ {
+ if (!gsym->has_plt_offset())
+ gold_unreachable();
+
+ symval.set_output_value(target->plt_section()->address()
+ + gsym->plt_offset());
+ psymval = &symval;
+ }
+
+ const Sized_relobj<32, false>* object = relinfo->object;
+
+ switch (r_type)
+ {
+ case elfcpp::R_386_NONE:
+ case elfcpp::R_386_GNU_VTINHERIT:
+ case elfcpp::R_386_GNU_VTENTRY:
+ break;
+
+ case elfcpp::R_386_32:
+ Relocate_functions<32, false>::rel32(view, object, psymval);
+ break;
+
+ case elfcpp::R_386_PC32:
+ Relocate_functions<32, false>::pcrel32(view, object, psymval, address);
+ break;
+
+ case elfcpp::R_386_16:
+ Relocate_functions<32, false>::rel16(view, object, psymval);
+ break;
+
+ case elfcpp::R_386_PC16:
+ Relocate_functions<32, false>::pcrel16(view, object, psymval, address);
+ break;
+
+ case elfcpp::R_386_8:
+ Relocate_functions<32, false>::rel8(view, object, psymval);
+ break;
+
+ case elfcpp::R_386_PC8:
+ Relocate_functions<32, false>::pcrel8(view, object, psymval, address);
+ break;
+
+ case elfcpp::R_386_PLT32:
+ gold_assert(gsym->has_plt_offset()
+ || gsym->final_value_is_known(relinfo->options));
+ Relocate_functions<32, false>::pcrel32(view, object, psymval, address);
+ break;
+
+ case elfcpp::R_386_GOT32:
+ // Local GOT offsets not yet supported.
+ gold_assert(gsym);
+ gold_assert(gsym->has_got_offset());
+ Relocate_functions<32, false>::rel32(view, gsym->got_offset());
+ break;
+
+ case elfcpp::R_386_GOTOFF:
+ {
+ elfcpp::Elf_types<32>::Elf_Addr value;
+ value = (psymval->value(object, 0)
+ - target->got_section(NULL, NULL, NULL)->address());
+ Relocate_functions<32, false>::rel32(view, value);
+ }
+ break;
+
+ case elfcpp::R_386_GOTPC:
+ {
+ elfcpp::Elf_types<32>::Elf_Addr value;
+ value = target->got_section(NULL, NULL, NULL)->address();
+ Relocate_functions<32, false>::pcrel32(view, value, address);
+ }
+ break;
+
+ case elfcpp::R_386_COPY:
+ case elfcpp::R_386_GLOB_DAT:
+ case elfcpp::R_386_JUMP_SLOT:
+ case elfcpp::R_386_RELATIVE:
+ case elfcpp::R_386_TLS_TPOFF:
+ case elfcpp::R_386_TLS_DTPMOD32:
+ case elfcpp::R_386_TLS_DTPOFF32:
+ case elfcpp::R_386_TLS_TPOFF32:
+ case elfcpp::R_386_TLS_DESC:
+ fprintf(stderr, _("%s: %s: unexpected reloc %u in object file\n"),
+ program_name,
+ relinfo->location(relnum, rel.get_r_offset()).c_str(),
+ r_type);
+ gold_exit(false);
+ break;
+
+ case elfcpp::R_386_TLS_IE:
+ case elfcpp::R_386_TLS_GOTIE:
+ case elfcpp::R_386_TLS_LE:
+ case elfcpp::R_386_TLS_GD:
+ case elfcpp::R_386_TLS_LDM:
+ case elfcpp::R_386_TLS_LDO_32:
+ case elfcpp::R_386_TLS_IE_32:
+ case elfcpp::R_386_TLS_LE_32:
+ case elfcpp::R_386_TLS_GOTDESC:
+ case elfcpp::R_386_TLS_DESC_CALL:
+ this->relocate_tls(relinfo, relnum, rel, r_type, gsym, psymval, view,
+ address, view_size);
+ break;
+
+ case elfcpp::R_386_32PLT:
+ case elfcpp::R_386_TLS_GD_32:
+ case elfcpp::R_386_TLS_GD_PUSH:
+ case elfcpp::R_386_TLS_GD_CALL:
+ case elfcpp::R_386_TLS_GD_POP:
+ case elfcpp::R_386_TLS_LDM_32:
+ case elfcpp::R_386_TLS_LDM_PUSH:
+ case elfcpp::R_386_TLS_LDM_CALL:
+ case elfcpp::R_386_TLS_LDM_POP:
+ case elfcpp::R_386_USED_BY_INTEL_200:
+ default:
+ fprintf(stderr, _("%s: %s: unsupported reloc %u\n"),
+ program_name,
+ relinfo->location(relnum, rel.get_r_offset()).c_str(),
+ r_type);
+ // gold_exit(false);
+ break;
+ }
+
+ return true;
+}
+
+// Perform a TLS relocation.
+
+inline void
+Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
+ size_t relnum,
+ const elfcpp::Rel<32, false>& rel,
+ unsigned int r_type,
+ const Sized_symbol<32>* gsym,
+ const Symbol_value<32>* psymval,
+ unsigned char* view,
+ elfcpp::Elf_types<32>::Elf_Addr,
+ off_t view_size)
+{
+ Output_segment* tls_segment = relinfo->layout->tls_segment();
+ if (tls_segment == NULL)
+ {
+ fprintf(stderr, _("%s: %s: TLS reloc but no TLS segment\n"),
+ program_name,
+ relinfo->location(relnum, rel.get_r_offset()).c_str());
+ gold_exit(false);
+ }
+
+ elfcpp::Elf_types<32>::Elf_Addr value = psymval->value(relinfo->object, 0);
+
+ const bool is_final = (gsym == NULL
+ ? !relinfo->options->is_shared()
+ : gsym->final_value_is_known(relinfo->options));
+ const unsigned int opt_r_type =
+ Target_i386::optimize_tls_reloc(relinfo->options, is_final, r_type);
+ switch (r_type)
+ {
+ case elfcpp::R_386_TLS_LE_32:
+ value = tls_segment->vaddr() + tls_segment->memsz() - value;
+ Relocate_functions<32, false>::rel32(view, value);
+ break;
+
+ case elfcpp::R_386_TLS_LE:
+ value = value - (tls_segment->vaddr() + tls_segment->memsz());
+ Relocate_functions<32, false>::rel32(view, value);
+ break;
+
+ case elfcpp::R_386_TLS_IE:
+ case elfcpp::R_386_TLS_GOTIE:
+ case elfcpp::R_386_TLS_IE_32:
+ if (opt_r_type == elfcpp::R_386_TLS_LE_32)
+ {
+ Target_i386::Relocate::tls_ie_to_le(relinfo, relnum, tls_segment,
+ rel, r_type, value, view,
+ view_size);
+ break;
+ }
+ fprintf(stderr, _("%s: %s: unsupported reloc type %u\n"),
+ program_name,
+ relinfo->location(relnum, rel.get_r_offset()).c_str(),
+ r_type);
+ // gold_exit(false);
+ break;
+
+ case elfcpp::R_386_TLS_GD:
+ if (opt_r_type == elfcpp::R_386_TLS_LE_32)
+ {
+ this->tls_gd_to_le(relinfo, relnum, tls_segment,
+ rel, r_type, value, view,
+ view_size);
+ break;
+ }
+ fprintf(stderr, _("%s: %s: unsupported reloc %u\n"),
+ program_name,
+ relinfo->location(relnum, rel.get_r_offset()).c_str(),
+ r_type);
+ // gold_exit(false);
+ break;
+
+ case elfcpp::R_386_TLS_LDM:
+ case elfcpp::R_386_TLS_LDO_32:
+ case elfcpp::R_386_TLS_GOTDESC:
+ case elfcpp::R_386_TLS_DESC_CALL:
+ fprintf(stderr, _("%s: %s: unsupported reloc %u\n"),
+ program_name,
+ relinfo->location(relnum, rel.get_r_offset()).c_str(),
+ r_type);
+ // gold_exit(false);
+ break;
+ }
+}
+
+// Do a relocation in which we convert a TLS Initial-Exec to a
+// Local-Exec.
+
+inline void
+Target_i386::Relocate::tls_ie_to_le(const Relocate_info<32, false>* relinfo,
+ size_t relnum,
+ Output_segment* tls_segment,
+ const elfcpp::Rel<32, false>& rel,
+ unsigned int r_type,
+ elfcpp::Elf_types<32>::Elf_Addr value,
+ unsigned char* view,
+ off_t view_size)
+{
+ // We have to actually change the instructions, which means that we
+ // need to examine the opcodes to figure out which instruction we
+ // are looking at.
+ if (r_type == elfcpp::R_386_TLS_IE)
+ {
+ // movl %gs:XX,%eax ==> movl $YY,%eax
+ // movl %gs:XX,%reg ==> movl $YY,%reg
+ // addl %gs:XX,%reg ==> addl $YY,%reg
+ Target_i386::Relocate::check_range(relinfo, relnum, rel, view_size, -1);
+ Target_i386::Relocate::check_range(relinfo, relnum, rel, view_size, 4);
+
+ unsigned char op1 = view[-1];
+ if (op1 == 0xa1)
+ {
+ // movl XX,%eax ==> movl $YY,%eax
+ view[-1] = 0xb8;
+ }
+ else
+ {
+ Target_i386::Relocate::check_range(relinfo, relnum, rel,
+ view_size, -2);
+
+ unsigned char op2 = view[-2];
+ if (op2 == 0x8b)
+ {
+ // movl XX,%reg ==> movl $YY,%reg
+ Target_i386::Relocate::check_tls(relinfo, relnum, rel,
+ (op1 & 0xc7) == 0x05);
+ view[-2] = 0xc7;
+ view[-1] = 0xc0 | ((op1 >> 3) & 7);
+ }
+ else if (op2 == 0x03)
+ {
+ // addl XX,%reg ==> addl $YY,%reg
+ Target_i386::Relocate::check_tls(relinfo, relnum, rel,
+ (op1 & 0xc7) == 0x05);
+ view[-2] = 0x81;
+ view[-1] = 0xc0 | ((op1 >> 3) & 7);
+ }
+ else
+ Target_i386::Relocate::check_tls(relinfo, relnum, rel, 0);
+ }
+ }
+ else
+ {
+ // subl %gs:XX(%reg1),%reg2 ==> subl $YY,%reg2
+ // movl %gs:XX(%reg1),%reg2 ==> movl $YY,%reg2
+ // addl %gs:XX(%reg1),%reg2 ==> addl $YY,$reg2
+ Target_i386::Relocate::check_range(relinfo, relnum, rel, view_size, -2);
+ Target_i386::Relocate::check_range(relinfo, relnum, rel, view_size, 4);
+
+ unsigned char op1 = view[-1];
+ unsigned char op2 = view[-2];
+ Target_i386::Relocate::check_tls(relinfo, relnum, rel,
+ (op1 & 0xc0) == 0x80 && (op1 & 7) != 4);
+ if (op2 == 0x8b)
+ {
+ // movl %gs:XX(%reg1),%reg2 ==> movl $YY,%reg2
+ view[-2] = 0xc7;
+ view[-1] = 0xc0 | ((op1 >> 3) & 7);
+ }
+ else if (op2 == 0x2b)
+ {
+ // subl %gs:XX(%reg1),%reg2 ==> subl $YY,%reg2
+ view[-2] = 0x81;
+ view[-1] = 0xe8 | ((op1 >> 3) & 7);
+ }
+ else if (op2 == 0x03)
+ {
+ // addl %gs:XX(%reg1),%reg2 ==> addl $YY,$reg2
+ view[-2] = 0x81;
+ view[-1] = 0xc0 | ((op1 >> 3) & 7);
+ }
+ else
+ Target_i386::Relocate::check_tls(relinfo, relnum, rel, 0);
+ }
+
+ value = tls_segment->vaddr() + tls_segment->memsz() - value;
+ if (r_type == elfcpp::R_386_TLS_IE || r_type == elfcpp::R_386_TLS_GOTIE)
+ value = - value;
+
+ Relocate_functions<32, false>::rel32(view, value);
+}
+
+// Do a relocation in which we convert a TLS Global-Dynamic to a
+// Local-Exec.
+
+inline void
+Target_i386::Relocate::tls_gd_to_le(const Relocate_info<32, false>* relinfo,
+ size_t relnum,
+ Output_segment* tls_segment,
+ const elfcpp::Rel<32, false>& rel,
+ unsigned int,
+ elfcpp::Elf_types<32>::Elf_Addr value,
+ unsigned char* view,
+ off_t view_size)
+{
+ // leal foo(,%reg,1),%eax; call ___tls_get_addr
+ // ==> movl %gs,0,%eax; subl $foo@tpoff,%eax
+ // leal foo(%reg),%eax; call ___tls_get_addr
+ // ==> movl %gs:0,%eax; subl $foo@tpoff,%eax
+
+ Target_i386::Relocate::check_range(relinfo, relnum, rel, view_size, -2);
+ Target_i386::Relocate::check_range(relinfo, relnum, rel, view_size, 9);
+
+ unsigned char op1 = view[-1];
+ unsigned char op2 = view[-2];
+
+ Target_i386::Relocate::check_tls(relinfo, relnum, rel,
+ op2 == 0x8d || op2 == 0x04);
+ Target_i386::Relocate::check_tls(relinfo, relnum, rel,
+ view[4] == 0xe8);
+
+ int roff = 5;
+
+ if (op2 == 0x04)
+ {
+ Target_i386::Relocate::check_range(relinfo, relnum, rel, view_size, -3);
+ Target_i386::Relocate::check_tls(relinfo, relnum, rel,
+ view[-3] == 0x8d);
+ Target_i386::Relocate::check_tls(relinfo, relnum, rel,
+ ((op1 & 0xc7) == 0x05
+ && op1 != (4 << 3)));
+ memcpy(view - 3, "\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12);
+ }
+ else
+ {
+ Target_i386::Relocate::check_tls(relinfo, relnum, rel,
+ (op1 & 0xf8) == 0x80 && (op1 & 7) != 4);
+ if (rel.get_r_offset() + 9 < view_size && view[9] == 0x90)
+ {
+ // There is a trailing nop. Use the size byte subl.
+ memcpy(view - 2, "\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12);
+ roff = 6;
+ }
+ else
+ {
+ // Use the five byte subl.
+ memcpy(view - 2, "\x65\xa1\0\0\0\0\x2d\0\0\0", 11);
+ }
+ }
+
+ value = tls_segment->vaddr() + tls_segment->memsz() - value;
+ Relocate_functions<32, false>::rel32(view + roff, value);
+
+ // The next reloc should be a PLT32 reloc against __tls_get_addr.
+ // We can skip it.
+ this->skip_call_tls_get_addr_ = true;
+}
+
+// Check the range for a TLS relocation.
+
+inline void
+Target_i386::Relocate::check_range(const Relocate_info<32, false>* relinfo,
+ size_t relnum,
+ const elfcpp::Rel<32, false>& rel,
+ off_t view_size, off_t off)
+{
+ off_t offset = rel.get_r_offset() + off;
+ if (offset < 0 || offset > view_size)
+ {
+ fprintf(stderr, _("%s: %s: TLS relocation out of range\n"),
+ program_name,
+ relinfo->location(relnum, rel.get_r_offset()).c_str());
+ gold_exit(false);
+ }
+}
+
+// Check the validity of a TLS relocation. This is like assert.
+
+inline void
+Target_i386::Relocate::check_tls(const Relocate_info<32, false>* relinfo,
+ size_t relnum,
+ const elfcpp::Rel<32, false>& rel,
+ bool valid)
+{
+ if (!valid)
+ {
+ fprintf(stderr,
+ _("%s: %s: TLS relocation against invalid instruction\n"),
+ program_name,
+ relinfo->location(relnum, rel.get_r_offset()).c_str());
+ gold_exit(false);
+ }
+}
+
+// Relocate section data.
+
+void
+Target_i386::relocate_section(const Relocate_info<32, false>* relinfo,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ unsigned char* view,
+ elfcpp::Elf_types<32>::Elf_Addr address,
+ off_t view_size)
+{
+ gold_assert(sh_type == elfcpp::SHT_REL);
+
+ gold::relocate_section<32, false, Target_i386, elfcpp::SHT_REL,
+ Target_i386::Relocate>(
+ relinfo,
+ this,
+ prelocs,
+ reloc_count,
+ view,
+ address,
+ view_size);
+}
+
+// The selector for i386 object files.
+
+class Target_selector_i386 : public Target_selector
+{
+public:
+ Target_selector_i386()
+ : Target_selector(elfcpp::EM_386, 32, false)
+ { }
+
+ Target*
+ recognize(int machine, int osabi, int abiversion);
+
+ private:
+ Target_i386* target_;
+};
+
+// Recognize an i386 object file when we already know that the machine
+// number is EM_386.
+
+Target*
+Target_selector_i386::recognize(int, int, int)
+{
+ if (this->target_ == NULL)
+ this->target_ = new Target_i386();
+ return this->target_;
+}
+
+Target_selector_i386 target_selector_i386;
+
+} // End anonymous namespace.
diff --git a/gold/layout.cc b/gold/layout.cc
new file mode 100644
index 000000000000..62ba5f30dec9
--- /dev/null
+++ b/gold/layout.cc
@@ -0,0 +1,1440 @@
+// layout.cc -- lay out output file sections for gold
+
+#include "gold.h"
+
+#include <cstring>
+#include <algorithm>
+#include <iostream>
+#include <utility>
+
+#include "output.h"
+#include "symtab.h"
+#include "dynobj.h"
+#include "layout.h"
+
+namespace gold
+{
+
+// Layout_task_runner methods.
+
+// Lay out the sections. This is called after all the input objects
+// have been read.
+
+void
+Layout_task_runner::run(Workqueue* workqueue)
+{
+ off_t file_size = this->layout_->finalize(this->input_objects_,
+ this->symtab_);
+
+ // Now we know the final size of the output file and we know where
+ // each piece of information goes.
+ Output_file* of = new Output_file(this->options_);
+ of->open(file_size);
+
+ // Queue up the final set of tasks.
+ gold::queue_final_tasks(this->options_, this->input_objects_,
+ this->symtab_, this->layout_, workqueue, of);
+}
+
+// Layout methods.
+
+Layout::Layout(const General_options& options)
+ : options_(options), namepool_(), sympool_(), dynpool_(), signatures_(),
+ section_name_map_(), segment_list_(), section_list_(),
+ unattached_section_list_(), special_output_list_(),
+ tls_segment_(NULL), symtab_section_(NULL),
+ dynsym_section_(NULL), dynamic_section_(NULL), dynamic_data_(NULL)
+{
+ // Make space for more than enough segments for a typical file.
+ // This is just for efficiency--it's OK if we wind up needing more.
+ this->segment_list_.reserve(12);
+
+ // We expect three unattached Output_data objects: the file header,
+ // the segment headers, and the section headers.
+ this->special_output_list_.reserve(3);
+}
+
+// Hash a key we use to look up an output section mapping.
+
+size_t
+Layout::Hash_key::operator()(const Layout::Key& k) const
+{
+ return k.first + k.second.first + k.second.second;
+}
+
+// Whether to include this section in the link.
+
+template<int size, bool big_endian>
+bool
+Layout::include_section(Object*, const char*,
+ const elfcpp::Shdr<size, big_endian>& shdr)
+{
+ // Some section types are never linked. Some are only linked when
+ // doing a relocateable link.
+ switch (shdr.get_sh_type())
+ {
+ case elfcpp::SHT_NULL:
+ case elfcpp::SHT_SYMTAB:
+ case elfcpp::SHT_DYNSYM:
+ case elfcpp::SHT_STRTAB:
+ case elfcpp::SHT_HASH:
+ case elfcpp::SHT_DYNAMIC:
+ case elfcpp::SHT_SYMTAB_SHNDX:
+ return false;
+
+ case elfcpp::SHT_RELA:
+ case elfcpp::SHT_REL:
+ case elfcpp::SHT_GROUP:
+ return this->options_.is_relocatable();
+
+ default:
+ // FIXME: Handle stripping debug sections here.
+ return true;
+ }
+}
+
+// Return an output section named NAME, or NULL if there is none.
+
+Output_section*
+Layout::find_output_section(const char* name) const
+{
+ for (Section_name_map::const_iterator p = this->section_name_map_.begin();
+ p != this->section_name_map_.end();
+ ++p)
+ if (strcmp(p->second->name(), name) == 0)
+ return p->second;
+ return NULL;
+}
+
+// Return an output segment of type TYPE, with segment flags SET set
+// and segment flags CLEAR clear. Return NULL if there is none.
+
+Output_segment*
+Layout::find_output_segment(elfcpp::PT type, elfcpp::Elf_Word set,
+ elfcpp::Elf_Word clear) const
+{
+ for (Segment_list::const_iterator p = this->segment_list_.begin();
+ p != this->segment_list_.end();
+ ++p)
+ if (static_cast<elfcpp::PT>((*p)->type()) == type
+ && ((*p)->flags() & set) == set
+ && ((*p)->flags() & clear) == 0)
+ return *p;
+ return NULL;
+}
+
+// Return the output section to use for section NAME with type TYPE
+// and section flags FLAGS.
+
+Output_section*
+Layout::get_output_section(const char* name, Stringpool::Key name_key,
+ elfcpp::Elf_Word type, elfcpp::Elf_Xword flags)
+{
+ // We should ignore some flags.
+ flags &= ~ (elfcpp::SHF_INFO_LINK
+ | elfcpp::SHF_LINK_ORDER
+ | elfcpp::SHF_GROUP
+ | elfcpp::SHF_MERGE
+ | elfcpp::SHF_STRINGS);
+
+ const Key key(name_key, std::make_pair(type, flags));
+ const std::pair<Key, Output_section*> v(key, NULL);
+ std::pair<Section_name_map::iterator, bool> ins(
+ this->section_name_map_.insert(v));
+
+ if (!ins.second)
+ return ins.first->second;
+ else
+ {
+ // This is the first time we've seen this name/type/flags
+ // combination.
+ Output_section* os = this->make_output_section(name, type, flags);
+ ins.first->second = os;
+ return os;
+ }
+}
+
+// Return the output section to use for input section SHNDX, with name
+// NAME, with header HEADER, from object OBJECT. Set *OFF to the
+// offset of this input section without the output section.
+
+template<int size, bool big_endian>
+Output_section*
+Layout::layout(Relobj* object, unsigned int shndx, const char* name,
+ const elfcpp::Shdr<size, big_endian>& shdr, off_t* off)
+{
+ if (!this->include_section(object, name, shdr))
+ return NULL;
+
+ // If we are not doing a relocateable link, choose the name to use
+ // for the output section.
+ size_t len = strlen(name);
+ if (!this->options_.is_relocatable())
+ name = Layout::output_section_name(name, &len);
+
+ // FIXME: Handle SHF_OS_NONCONFORMING here.
+
+ // Canonicalize the section name.
+ Stringpool::Key name_key;
+ name = this->namepool_.add(name, len, &name_key);
+
+ // Find the output section. The output section is selected based on
+ // the section name, type, and flags.
+ Output_section* os = this->get_output_section(name, name_key,
+ shdr.get_sh_type(),
+ shdr.get_sh_flags());
+
+ // FIXME: Handle SHF_LINK_ORDER somewhere.
+
+ *off = os->add_input_section(object, shndx, name, shdr);
+
+ return os;
+}
+
+// Add POSD to an output section using NAME, TYPE, and FLAGS.
+
+void
+Layout::add_output_section_data(const char* name, elfcpp::Elf_Word type,
+ elfcpp::Elf_Xword flags,
+ Output_section_data* posd)
+{
+ // Canonicalize the name.
+ Stringpool::Key name_key;
+ name = this->namepool_.add(name, &name_key);
+
+ Output_section* os = this->get_output_section(name, name_key, type, flags);
+ os->add_output_section_data(posd);
+}
+
+// Map section flags to segment flags.
+
+elfcpp::Elf_Word
+Layout::section_flags_to_segment(elfcpp::Elf_Xword flags)
+{
+ elfcpp::Elf_Word ret = elfcpp::PF_R;
+ if ((flags & elfcpp::SHF_WRITE) != 0)
+ ret |= elfcpp::PF_W;
+ if ((flags & elfcpp::SHF_EXECINSTR) != 0)
+ ret |= elfcpp::PF_X;
+ return ret;
+}
+
+// Make a new Output_section, and attach it to segments as
+// appropriate.
+
+Output_section*
+Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
+ elfcpp::Elf_Xword flags)
+{
+ Output_section* os = new Output_section(name, type, flags);
+ this->section_list_.push_back(os);
+
+ if ((flags & elfcpp::SHF_ALLOC) == 0)
+ this->unattached_section_list_.push_back(os);
+ else
+ {
+ // This output section goes into a PT_LOAD segment.
+
+ elfcpp::Elf_Word seg_flags = Layout::section_flags_to_segment(flags);
+
+ // The only thing we really care about for PT_LOAD segments is
+ // whether or not they are writable, so that is how we search
+ // for them. People who need segments sorted on some other
+ // basis will have to wait until we implement a mechanism for
+ // them to describe the segments they want.
+
+ Segment_list::const_iterator p;
+ for (p = this->segment_list_.begin();
+ p != this->segment_list_.end();
+ ++p)
+ {
+ if ((*p)->type() == elfcpp::PT_LOAD
+ && ((*p)->flags() & elfcpp::PF_W) == (seg_flags & elfcpp::PF_W))
+ {
+ (*p)->add_output_section(os, seg_flags);
+ break;
+ }
+ }
+
+ if (p == this->segment_list_.end())
+ {
+ Output_segment* oseg = new Output_segment(elfcpp::PT_LOAD,
+ seg_flags);
+ this->segment_list_.push_back(oseg);
+ oseg->add_output_section(os, seg_flags);
+ }
+
+ // If we see a loadable SHT_NOTE section, we create a PT_NOTE
+ // segment.
+ if (type == elfcpp::SHT_NOTE)
+ {
+ // See if we already have an equivalent PT_NOTE segment.
+ for (p = this->segment_list_.begin();
+ p != segment_list_.end();
+ ++p)
+ {
+ if ((*p)->type() == elfcpp::PT_NOTE
+ && (((*p)->flags() & elfcpp::PF_W)
+ == (seg_flags & elfcpp::PF_W)))
+ {
+ (*p)->add_output_section(os, seg_flags);
+ break;
+ }
+ }
+
+ if (p == this->segment_list_.end())
+ {
+ Output_segment* oseg = new Output_segment(elfcpp::PT_NOTE,
+ seg_flags);
+ this->segment_list_.push_back(oseg);
+ oseg->add_output_section(os, seg_flags);
+ }
+ }
+
+ // If we see a loadable SHF_TLS section, we create a PT_TLS
+ // segment. There can only be one such segment.
+ if ((flags & elfcpp::SHF_TLS) != 0)
+ {
+ if (this->tls_segment_ == NULL)
+ {
+ this->tls_segment_ = new Output_segment(elfcpp::PT_TLS,
+ seg_flags);
+ this->segment_list_.push_back(this->tls_segment_);
+ }
+ this->tls_segment_->add_output_section(os, seg_flags);
+ }
+ }
+
+ return os;
+}
+
+// Create the dynamic sections which are needed before we read the
+// relocs.
+
+void
+Layout::create_initial_dynamic_sections(const Input_objects* input_objects,
+ Symbol_table* symtab)
+{
+ if (!input_objects->any_dynamic())
+ return;
+
+ const char* dynamic_name = this->namepool_.add(".dynamic", NULL);
+ this->dynamic_section_ = this->make_output_section(dynamic_name,
+ elfcpp::SHT_DYNAMIC,
+ (elfcpp::SHF_ALLOC
+ | elfcpp::SHF_WRITE));
+
+ symtab->define_in_output_data(input_objects->target(), "_DYNAMIC", NULL,
+ this->dynamic_section_, 0, 0,
+ elfcpp::STT_OBJECT, elfcpp::STB_LOCAL,
+ elfcpp::STV_HIDDEN, 0, false, false);
+
+ this->dynamic_data_ = new Output_data_dynamic(input_objects->target(),
+ &this->dynpool_);
+
+ this->dynamic_section_->add_output_section_data(this->dynamic_data_);
+}
+
+// Find the first read-only PT_LOAD segment, creating one if
+// necessary.
+
+Output_segment*
+Layout::find_first_load_seg()
+{
+ for (Segment_list::const_iterator p = this->segment_list_.begin();
+ p != this->segment_list_.end();
+ ++p)
+ {
+ if ((*p)->type() == elfcpp::PT_LOAD
+ && ((*p)->flags() & elfcpp::PF_R) != 0
+ && ((*p)->flags() & elfcpp::PF_W) == 0)
+ return *p;
+ }
+
+ Output_segment* load_seg = new Output_segment(elfcpp::PT_LOAD, elfcpp::PF_R);
+ this->segment_list_.push_back(load_seg);
+ return load_seg;
+}
+
+// Finalize the layout. When this is called, we have created all the
+// output sections and all the output segments which are based on
+// input sections. We have several things to do, and we have to do
+// them in the right order, so that we get the right results correctly
+// and efficiently.
+
+// 1) Finalize the list of output segments and create the segment
+// table header.
+
+// 2) Finalize the dynamic symbol table and associated sections.
+
+// 3) Determine the final file offset of all the output segments.
+
+// 4) Determine the final file offset of all the SHF_ALLOC output
+// sections.
+
+// 5) Create the symbol table sections and the section name table
+// section.
+
+// 6) Finalize the symbol table: set symbol values to their final
+// value and make a final determination of which symbols are going
+// into the output symbol table.
+
+// 7) Create the section table header.
+
+// 8) Determine the final file offset of all the output sections which
+// are not SHF_ALLOC, including the section table header.
+
+// 9) Finalize the ELF file header.
+
+// This function returns the size of the output file.
+
+off_t
+Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
+{
+ Target* const target = input_objects->target();
+ const int size = target->get_size();
+
+ target->finalize_sections(&this->options_, this);
+
+ Output_segment* phdr_seg = NULL;
+ if (input_objects->any_dynamic())
+ {
+ // There was a dynamic object in the link. We need to create
+ // some information for the dynamic linker.
+
+ // Create the PT_PHDR segment which will hold the program
+ // headers.
+ phdr_seg = new Output_segment(elfcpp::PT_PHDR, elfcpp::PF_R);
+ this->segment_list_.push_back(phdr_seg);
+
+ // Create the dynamic symbol table, including the hash table.
+ Output_section* dynstr;
+ std::vector<Symbol*> dynamic_symbols;
+ unsigned int local_dynamic_count;
+ Versions versions;
+ this->create_dynamic_symtab(target, symtab, &dynstr,
+ &local_dynamic_count, &dynamic_symbols,
+ &versions);
+
+ // Create the .interp section to hold the name of the
+ // interpreter, and put it in a PT_INTERP segment.
+ this->create_interp(target);
+
+ // Finish the .dynamic section to hold the dynamic data, and put
+ // it in a PT_DYNAMIC segment.
+ this->finish_dynamic_section(input_objects, symtab);
+
+ // We should have added everything we need to the dynamic string
+ // table.
+ this->dynpool_.set_string_offsets();
+
+ // Create the version sections. We can't do this until the
+ // dynamic string table is complete.
+ this->create_version_sections(target, &versions, local_dynamic_count,
+ dynamic_symbols, dynstr);
+ }
+
+ // FIXME: Handle PT_GNU_STACK.
+
+ Output_segment* load_seg = this->find_first_load_seg();
+
+ // Lay out the segment headers.
+ bool big_endian = target->is_big_endian();
+ Output_segment_headers* segment_headers;
+ segment_headers = new Output_segment_headers(size, big_endian,
+ this->segment_list_);
+ load_seg->add_initial_output_data(segment_headers);
+ this->special_output_list_.push_back(segment_headers);
+ if (phdr_seg != NULL)
+ phdr_seg->add_initial_output_data(segment_headers);
+
+ // Lay out the file header.
+ Output_file_header* file_header;
+ file_header = new Output_file_header(size,
+ big_endian,
+ this->options_,
+ target,
+ symtab,
+ segment_headers);
+ load_seg->add_initial_output_data(file_header);
+ this->special_output_list_.push_back(file_header);
+
+ // We set the output section indexes in set_segment_offsets and
+ // set_section_offsets.
+ unsigned int shndx = 1;
+
+ // Set the file offsets of all the segments, and all the sections
+ // they contain.
+ off_t off = this->set_segment_offsets(target, load_seg, &shndx);
+
+ // Create the symbol table sections.
+ this->create_symtab_sections(size, input_objects, symtab, &off);
+
+ // Create the .shstrtab section.
+ Output_section* shstrtab_section = this->create_shstrtab();
+
+ // Set the file offsets of all the sections not associated with
+ // segments.
+ off = this->set_section_offsets(off, &shndx);
+
+ // Create the section table header.
+ Output_section_headers* oshdrs = this->create_shdrs(size, big_endian, &off);
+
+ file_header->set_section_info(oshdrs, shstrtab_section);
+
+ // Now we know exactly where everything goes in the output file.
+ Output_data::layout_complete();
+
+ return off;
+}
+
+// Return whether SEG1 should be before SEG2 in the output file. This
+// is based entirely on the segment type and flags. When this is
+// called the segment addresses has normally not yet been set.
+
+bool
+Layout::segment_precedes(const Output_segment* seg1,
+ const Output_segment* seg2)
+{
+ elfcpp::Elf_Word type1 = seg1->type();
+ elfcpp::Elf_Word type2 = seg2->type();
+
+ // The single PT_PHDR segment is required to precede any loadable
+ // segment. We simply make it always first.
+ if (type1 == elfcpp::PT_PHDR)
+ {
+ gold_assert(type2 != elfcpp::PT_PHDR);
+ return true;
+ }
+ if (type2 == elfcpp::PT_PHDR)
+ return false;
+
+ // The single PT_INTERP segment is required to precede any loadable
+ // segment. We simply make it always second.
+ if (type1 == elfcpp::PT_INTERP)
+ {
+ gold_assert(type2 != elfcpp::PT_INTERP);
+ return true;
+ }
+ if (type2 == elfcpp::PT_INTERP)
+ return false;
+
+ // We then put PT_LOAD segments before any other segments.
+ if (type1 == elfcpp::PT_LOAD && type2 != elfcpp::PT_LOAD)
+ return true;
+ if (type2 == elfcpp::PT_LOAD && type1 != elfcpp::PT_LOAD)
+ return false;
+
+ // We put the PT_TLS segment last, because that is where the dynamic
+ // linker expects to find it (this is just for efficiency; other
+ // positions would also work correctly).
+ if (type1 == elfcpp::PT_TLS && type2 != elfcpp::PT_TLS)
+ return false;
+ if (type2 == elfcpp::PT_TLS && type1 != elfcpp::PT_TLS)
+ return true;
+
+ const elfcpp::Elf_Word flags1 = seg1->flags();
+ const elfcpp::Elf_Word flags2 = seg2->flags();
+
+ // The order of non-PT_LOAD segments is unimportant. We simply sort
+ // by the numeric segment type and flags values. There should not
+ // be more than one segment with the same type and flags.
+ if (type1 != elfcpp::PT_LOAD)
+ {
+ if (type1 != type2)
+ return type1 < type2;
+ gold_assert(flags1 != flags2);
+ return flags1 < flags2;
+ }
+
+ // We sort PT_LOAD segments based on the flags. Readonly segments
+ // come before writable segments. Then executable segments come
+ // before non-executable segments. Then the unlikely case of a
+ // non-readable segment comes before the normal case of a readable
+ // segment. If there are multiple segments with the same type and
+ // flags, we require that the address be set, and we sort by
+ // virtual address and then physical address.
+ if ((flags1 & elfcpp::PF_W) != (flags2 & elfcpp::PF_W))
+ return (flags1 & elfcpp::PF_W) == 0;
+ if ((flags1 & elfcpp::PF_X) != (flags2 & elfcpp::PF_X))
+ return (flags1 & elfcpp::PF_X) != 0;
+ if ((flags1 & elfcpp::PF_R) != (flags2 & elfcpp::PF_R))
+ return (flags1 & elfcpp::PF_R) == 0;
+
+ uint64_t vaddr1 = seg1->vaddr();
+ uint64_t vaddr2 = seg2->vaddr();
+ if (vaddr1 != vaddr2)
+ return vaddr1 < vaddr2;
+
+ uint64_t paddr1 = seg1->paddr();
+ uint64_t paddr2 = seg2->paddr();
+ gold_assert(paddr1 != paddr2);
+ return paddr1 < paddr2;
+}
+
+// Set the file offsets of all the segments, and all the sections they
+// contain. They have all been created. LOAD_SEG must be be laid out
+// first. Return the offset of the data to follow.
+
+off_t
+Layout::set_segment_offsets(const Target* target, Output_segment* load_seg,
+ unsigned int *pshndx)
+{
+ // Sort them into the final order.
+ std::sort(this->segment_list_.begin(), this->segment_list_.end(),
+ Layout::Compare_segments());
+
+ // Find the PT_LOAD segments, and set their addresses and offsets
+ // and their section's addresses and offsets.
+ uint64_t addr = target->text_segment_address();
+ off_t off = 0;
+ bool was_readonly = false;
+ for (Segment_list::iterator p = this->segment_list_.begin();
+ p != this->segment_list_.end();
+ ++p)
+ {
+ if ((*p)->type() == elfcpp::PT_LOAD)
+ {
+ if (load_seg != NULL && load_seg != *p)
+ gold_unreachable();
+ load_seg = NULL;
+
+ // If the last segment was readonly, and this one is not,
+ // then skip the address forward one page, maintaining the
+ // same position within the page. This lets us store both
+ // segments overlapping on a single page in the file, but
+ // the loader will put them on different pages in memory.
+
+ uint64_t orig_addr = addr;
+ uint64_t orig_off = off;
+
+ uint64_t aligned_addr = addr;
+ uint64_t abi_pagesize = target->abi_pagesize();
+ if (was_readonly && ((*p)->flags() & elfcpp::PF_W) != 0)
+ {
+ uint64_t align = (*p)->addralign();
+
+ addr = align_address(addr, align);
+ aligned_addr = addr;
+ if ((addr & (abi_pagesize - 1)) != 0)
+ addr = addr + abi_pagesize;
+ }
+
+ unsigned int shndx_hold = *pshndx;
+ off = orig_off + ((addr - orig_addr) & (abi_pagesize - 1));
+ uint64_t new_addr = (*p)->set_section_addresses(addr, &off, pshndx);
+
+ // Now that we know the size of this segment, we may be able
+ // to save a page in memory, at the cost of wasting some
+ // file space, by instead aligning to the start of a new
+ // page. Here we use the real machine page size rather than
+ // the ABI mandated page size.
+
+ if (aligned_addr != addr)
+ {
+ uint64_t common_pagesize = target->common_pagesize();
+ uint64_t first_off = (common_pagesize
+ - (aligned_addr
+ & (common_pagesize - 1)));
+ uint64_t last_off = new_addr & (common_pagesize - 1);
+ if (first_off > 0
+ && last_off > 0
+ && ((aligned_addr & ~ (common_pagesize - 1))
+ != (new_addr & ~ (common_pagesize - 1)))
+ && first_off + last_off <= common_pagesize)
+ {
+ *pshndx = shndx_hold;
+ addr = align_address(aligned_addr, common_pagesize);
+ off = orig_off + ((addr - orig_addr) & (abi_pagesize - 1));
+ new_addr = (*p)->set_section_addresses(addr, &off, pshndx);
+ }
+ }
+
+ addr = new_addr;
+
+ if (((*p)->flags() & elfcpp::PF_W) == 0)
+ was_readonly = true;
+ }
+ }
+
+ // Handle the non-PT_LOAD segments, setting their offsets from their
+ // section's offsets.
+ for (Segment_list::iterator p = this->segment_list_.begin();
+ p != this->segment_list_.end();
+ ++p)
+ {
+ if ((*p)->type() != elfcpp::PT_LOAD)
+ (*p)->set_offset();
+ }
+
+ return off;
+}
+
+// Set the file offset of all the sections not associated with a
+// segment.
+
+off_t
+Layout::set_section_offsets(off_t off, unsigned int* pshndx)
+{
+ for (Section_list::iterator p = this->unattached_section_list_.begin();
+ p != this->unattached_section_list_.end();
+ ++p)
+ {
+ (*p)->set_out_shndx(*pshndx);
+ ++*pshndx;
+ if ((*p)->offset() != -1)
+ continue;
+ off = align_address(off, (*p)->addralign());
+ (*p)->set_address(0, off);
+ off += (*p)->data_size();
+ }
+ return off;
+}
+
+// Create the symbol table sections. Here we also set the final
+// values of the symbols. At this point all the loadable sections are
+// fully laid out.
+
+void
+Layout::create_symtab_sections(int size, const Input_objects* input_objects,
+ Symbol_table* symtab,
+ off_t* poff)
+{
+ int symsize;
+ unsigned int align;
+ if (size == 32)
+ {
+ symsize = elfcpp::Elf_sizes<32>::sym_size;
+ align = 4;
+ }
+ else if (size == 64)
+ {
+ symsize = elfcpp::Elf_sizes<64>::sym_size;
+ align = 8;
+ }
+ else
+ gold_unreachable();
+
+ off_t off = *poff;
+ off = align_address(off, align);
+ off_t startoff = off;
+
+ // Save space for the dummy symbol at the start of the section. We
+ // never bother to write this out--it will just be left as zero.
+ off += symsize;
+ unsigned int local_symbol_index = 1;
+
+ // Add STT_SECTION symbols for each Output section which needs one.
+ for (Section_list::iterator p = this->section_list_.begin();
+ p != this->section_list_.end();
+ ++p)
+ {
+ if (!(*p)->needs_symtab_index())
+ (*p)->set_symtab_index(-1U);
+ else
+ {
+ (*p)->set_symtab_index(local_symbol_index);
+ ++local_symbol_index;
+ off += symsize;
+ }
+ }
+
+ for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
+ p != input_objects->relobj_end();
+ ++p)
+ {
+ Task_lock_obj<Object> tlo(**p);
+ unsigned int index = (*p)->finalize_local_symbols(local_symbol_index,
+ off,
+ &this->sympool_);
+ off += (index - local_symbol_index) * symsize;
+ local_symbol_index = index;
+ }
+
+ unsigned int local_symcount = local_symbol_index;
+ gold_assert(local_symcount * symsize == off - startoff);
+
+ off_t dynoff;
+ size_t dyn_global_index;
+ size_t dyncount;
+ if (this->dynsym_section_ == NULL)
+ {
+ dynoff = 0;
+ dyn_global_index = 0;
+ dyncount = 0;
+ }
+ else
+ {
+ dyn_global_index = this->dynsym_section_->info();
+ off_t locsize = dyn_global_index * this->dynsym_section_->entsize();
+ dynoff = this->dynsym_section_->offset() + locsize;
+ dyncount = (this->dynsym_section_->data_size() - locsize) / symsize;
+ gold_assert(dyncount * symsize
+ == this->dynsym_section_->data_size() - locsize);
+ }
+
+ off = symtab->finalize(local_symcount, off, dynoff, dyn_global_index,
+ dyncount, &this->sympool_);
+
+ this->sympool_.set_string_offsets();
+
+ const char* symtab_name = this->namepool_.add(".symtab", NULL);
+ Output_section* osymtab = this->make_output_section(symtab_name,
+ elfcpp::SHT_SYMTAB,
+ 0);
+ this->symtab_section_ = osymtab;
+
+ Output_section_data* pos = new Output_data_space(off - startoff,
+ align);
+ osymtab->add_output_section_data(pos);
+
+ const char* strtab_name = this->namepool_.add(".strtab", NULL);
+ Output_section* ostrtab = this->make_output_section(strtab_name,
+ elfcpp::SHT_STRTAB,
+ 0);
+
+ Output_section_data* pstr = new Output_data_strtab(&this->sympool_);
+ ostrtab->add_output_section_data(pstr);
+
+ osymtab->set_address(0, startoff);
+ osymtab->set_link_section(ostrtab);
+ osymtab->set_info(local_symcount);
+ osymtab->set_entsize(symsize);
+
+ *poff = off;
+}
+
+// Create the .shstrtab section, which holds the names of the
+// sections. At the time this is called, we have created all the
+// output sections except .shstrtab itself.
+
+Output_section*
+Layout::create_shstrtab()
+{
+ // FIXME: We don't need to create a .shstrtab section if we are
+ // stripping everything.
+
+ const char* name = this->namepool_.add(".shstrtab", NULL);
+
+ this->namepool_.set_string_offsets();
+
+ Output_section* os = this->make_output_section(name, elfcpp::SHT_STRTAB, 0);
+
+ Output_section_data* posd = new Output_data_strtab(&this->namepool_);
+ os->add_output_section_data(posd);
+
+ return os;
+}
+
+// Create the section headers. SIZE is 32 or 64. OFF is the file
+// offset.
+
+Output_section_headers*
+Layout::create_shdrs(int size, bool big_endian, off_t* poff)
+{
+ Output_section_headers* oshdrs;
+ oshdrs = new Output_section_headers(size, big_endian, this,
+ &this->segment_list_,
+ &this->unattached_section_list_,
+ &this->namepool_);
+ off_t off = align_address(*poff, oshdrs->addralign());
+ oshdrs->set_address(0, off);
+ off += oshdrs->data_size();
+ *poff = off;
+ this->special_output_list_.push_back(oshdrs);
+ return oshdrs;
+}
+
+// Create the dynamic symbol table.
+
+void
+Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab,
+ Output_section **pdynstr,
+ unsigned int* plocal_dynamic_count,
+ std::vector<Symbol*>* pdynamic_symbols,
+ Versions* pversions)
+{
+ // Count all the symbols in the dynamic symbol table, and set the
+ // dynamic symbol indexes.
+
+ // Skip symbol 0, which is always all zeroes.
+ unsigned int index = 1;
+
+ // Add STT_SECTION symbols for each Output section which needs one.
+ for (Section_list::iterator p = this->section_list_.begin();
+ p != this->section_list_.end();
+ ++p)
+ {
+ if (!(*p)->needs_dynsym_index())
+ (*p)->set_dynsym_index(-1U);
+ else
+ {
+ (*p)->set_dynsym_index(index);
+ ++index;
+ }
+ }
+
+ // FIXME: Some targets apparently require local symbols in the
+ // dynamic symbol table. Here is where we will have to count them,
+ // and set the dynamic symbol indexes, and add the names to
+ // this->dynpool_.
+
+ unsigned int local_symcount = index;
+ *plocal_dynamic_count = local_symcount;
+
+ // FIXME: We have to tell set_dynsym_indexes whether the
+ // -E/--export-dynamic option was used.
+ index = symtab->set_dynsym_indexes(&this->options_, target, index,
+ pdynamic_symbols, &this->dynpool_,
+ pversions);
+
+ int symsize;
+ unsigned int align;
+ const int size = target->get_size();
+ if (size == 32)
+ {
+ symsize = elfcpp::Elf_sizes<32>::sym_size;
+ align = 4;
+ }
+ else if (size == 64)
+ {
+ symsize = elfcpp::Elf_sizes<64>::sym_size;
+ align = 8;
+ }
+ else
+ gold_unreachable();
+
+ // Create the dynamic symbol table section.
+
+ const char* dynsym_name = this->namepool_.add(".dynsym", NULL);
+ Output_section* dynsym = this->make_output_section(dynsym_name,
+ elfcpp::SHT_DYNSYM,
+ elfcpp::SHF_ALLOC);
+
+ Output_section_data* odata = new Output_data_space(index * symsize,
+ align);
+ dynsym->add_output_section_data(odata);
+
+ dynsym->set_info(local_symcount);
+ dynsym->set_entsize(symsize);
+ dynsym->set_addralign(align);
+
+ this->dynsym_section_ = dynsym;
+
+ Output_data_dynamic* const odyn = this->dynamic_data_;
+ odyn->add_section_address(elfcpp::DT_SYMTAB, dynsym);
+ odyn->add_constant(elfcpp::DT_SYMENT, symsize);
+
+ // Create the dynamic string table section.
+
+ const char* dynstr_name = this->namepool_.add(".dynstr", NULL);
+ Output_section* dynstr = this->make_output_section(dynstr_name,
+ elfcpp::SHT_STRTAB,
+ elfcpp::SHF_ALLOC);
+
+ Output_section_data* strdata = new Output_data_strtab(&this->dynpool_);
+ dynstr->add_output_section_data(strdata);
+
+ dynsym->set_link_section(dynstr);
+ this->dynamic_section_->set_link_section(dynstr);
+
+ odyn->add_section_address(elfcpp::DT_STRTAB, dynstr);
+ odyn->add_section_size(elfcpp::DT_STRSZ, dynstr);
+
+ *pdynstr = dynstr;
+
+ // Create the hash tables.
+
+ // FIXME: We need an option to create a GNU hash table.
+
+ unsigned char* phash;
+ unsigned int hashlen;
+ Dynobj::create_elf_hash_table(target, *pdynamic_symbols, local_symcount,
+ &phash, &hashlen);
+
+ const char* hash_name = this->namepool_.add(".hash", NULL);
+ Output_section* hashsec = this->make_output_section(hash_name,
+ elfcpp::SHT_HASH,
+ elfcpp::SHF_ALLOC);
+
+ Output_section_data* hashdata = new Output_data_const_buffer(phash,
+ hashlen,
+ align);
+ hashsec->add_output_section_data(hashdata);
+
+ hashsec->set_link_section(dynsym);
+ hashsec->set_entsize(4);
+
+ odyn->add_section_address(elfcpp::DT_HASH, hashsec);
+}
+
+// Create the version sections.
+
+void
+Layout::create_version_sections(const Target* target, const Versions* versions,
+ unsigned int local_symcount,
+ const std::vector<Symbol*>& dynamic_symbols,
+ const Output_section* dynstr)
+{
+ if (!versions->any_defs() && !versions->any_needs())
+ return;
+
+ if (target->get_size() == 32)
+ {
+ if (target->is_big_endian())
+ this->sized_create_version_sections SELECT_SIZE_ENDIAN_NAME(32, true)(
+ versions, local_symcount, dynamic_symbols, dynstr
+ SELECT_SIZE_ENDIAN(32, true));
+ else
+ this->sized_create_version_sections SELECT_SIZE_ENDIAN_NAME(32, false)(
+ versions, local_symcount, dynamic_symbols, dynstr
+ SELECT_SIZE_ENDIAN(32, false));
+ }
+ else if (target->get_size() == 64)
+ {
+ if (target->is_big_endian())
+ this->sized_create_version_sections SELECT_SIZE_ENDIAN_NAME(64, true)(
+ versions, local_symcount, dynamic_symbols, dynstr
+ SELECT_SIZE_ENDIAN(64, true));
+ else
+ this->sized_create_version_sections SELECT_SIZE_ENDIAN_NAME(64, false)(
+ versions, local_symcount, dynamic_symbols, dynstr
+ SELECT_SIZE_ENDIAN(64, false));
+ }
+ else
+ gold_unreachable();
+}
+
+// Create the version sections, sized version.
+
+template<int size, bool big_endian>
+void
+Layout::sized_create_version_sections(
+ const Versions* versions,
+ unsigned int local_symcount,
+ const std::vector<Symbol*>& dynamic_symbols,
+ const Output_section* dynstr
+ ACCEPT_SIZE_ENDIAN)
+{
+ const char* vname = this->namepool_.add(".gnu.version", NULL);
+ Output_section* vsec = this->make_output_section(vname,
+ elfcpp::SHT_GNU_versym,
+ elfcpp::SHF_ALLOC);
+
+ unsigned char* vbuf;
+ unsigned int vsize;
+ versions->symbol_section_contents SELECT_SIZE_ENDIAN_NAME(size, big_endian)(
+ &this->dynpool_, local_symcount, dynamic_symbols, &vbuf, &vsize
+ SELECT_SIZE_ENDIAN(size, big_endian));
+
+ Output_section_data* vdata = new Output_data_const_buffer(vbuf, vsize, 2);
+
+ vsec->add_output_section_data(vdata);
+ vsec->set_entsize(2);
+ vsec->set_link_section(this->dynsym_section_);
+
+ Output_data_dynamic* const odyn = this->dynamic_data_;
+ odyn->add_section_address(elfcpp::DT_VERSYM, vsec);
+
+ if (versions->any_defs())
+ {
+ const char* vdname = this->namepool_.add(".gnu.version_d", NULL);
+ Output_section *vdsec;
+ vdsec = this->make_output_section(vdname, elfcpp::SHT_GNU_verdef,
+ elfcpp::SHF_ALLOC);
+
+ unsigned char* vdbuf;
+ unsigned int vdsize;
+ unsigned int vdentries;
+ versions->def_section_contents SELECT_SIZE_ENDIAN_NAME(size, big_endian)(
+ &this->dynpool_, &vdbuf, &vdsize, &vdentries
+ SELECT_SIZE_ENDIAN(size, big_endian));
+
+ Output_section_data* vddata = new Output_data_const_buffer(vdbuf,
+ vdsize,
+ 4);
+
+ vdsec->add_output_section_data(vddata);
+ vdsec->set_link_section(dynstr);
+ vdsec->set_info(vdentries);
+
+ odyn->add_section_address(elfcpp::DT_VERDEF, vdsec);
+ odyn->add_constant(elfcpp::DT_VERDEFNUM, vdentries);
+ }
+
+ if (versions->any_needs())
+ {
+ const char* vnname = this->namepool_.add(".gnu.version_r", NULL);
+ Output_section* vnsec;
+ vnsec = this->make_output_section(vnname, elfcpp::SHT_GNU_verneed,
+ elfcpp::SHF_ALLOC);
+
+ unsigned char* vnbuf;
+ unsigned int vnsize;
+ unsigned int vnentries;
+ versions->need_section_contents SELECT_SIZE_ENDIAN_NAME(size, big_endian)
+ (&this->dynpool_, &vnbuf, &vnsize, &vnentries
+ SELECT_SIZE_ENDIAN(size, big_endian));
+
+ Output_section_data* vndata = new Output_data_const_buffer(vnbuf,
+ vnsize,
+ 4);
+
+ vnsec->add_output_section_data(vndata);
+ vnsec->set_link_section(dynstr);
+ vnsec->set_info(vnentries);
+
+ odyn->add_section_address(elfcpp::DT_VERNEED, vnsec);
+ odyn->add_constant(elfcpp::DT_VERNEEDNUM, vnentries);
+ }
+}
+
+// Create the .interp section and PT_INTERP segment.
+
+void
+Layout::create_interp(const Target* target)
+{
+ const char* interp = this->options_.dynamic_linker();
+ if (interp == NULL)
+ {
+ interp = target->dynamic_linker();
+ gold_assert(interp != NULL);
+ }
+
+ size_t len = strlen(interp) + 1;
+
+ Output_section_data* odata = new Output_data_const(interp, len, 1);
+
+ const char* interp_name = this->namepool_.add(".interp", NULL);
+ Output_section* osec = this->make_output_section(interp_name,
+ elfcpp::SHT_PROGBITS,
+ elfcpp::SHF_ALLOC);
+ osec->add_output_section_data(odata);
+
+ Output_segment* oseg = new Output_segment(elfcpp::PT_INTERP, elfcpp::PF_R);
+ this->segment_list_.push_back(oseg);
+ oseg->add_initial_output_section(osec, elfcpp::PF_R);
+}
+
+// Finish the .dynamic section and PT_DYNAMIC segment.
+
+void
+Layout::finish_dynamic_section(const Input_objects* input_objects,
+ const Symbol_table* symtab)
+{
+ Output_segment* oseg = new Output_segment(elfcpp::PT_DYNAMIC,
+ elfcpp::PF_R | elfcpp::PF_W);
+ this->segment_list_.push_back(oseg);
+ oseg->add_initial_output_section(this->dynamic_section_,
+ elfcpp::PF_R | elfcpp::PF_W);
+
+ Output_data_dynamic* const odyn = this->dynamic_data_;
+
+ for (Input_objects::Dynobj_iterator p = input_objects->dynobj_begin();
+ p != input_objects->dynobj_end();
+ ++p)
+ {
+ // FIXME: Handle --as-needed.
+ odyn->add_string(elfcpp::DT_NEEDED, (*p)->soname());
+ }
+
+ // FIXME: Support --init and --fini.
+ Symbol* sym = symtab->lookup("_init");
+ if (sym != NULL && sym->is_defined() && !sym->is_from_dynobj())
+ odyn->add_symbol(elfcpp::DT_INIT, sym);
+
+ sym = symtab->lookup("_fini");
+ if (sym != NULL && sym->is_defined() && !sym->is_from_dynobj())
+ odyn->add_symbol(elfcpp::DT_FINI, sym);
+
+ // FIXME: Support DT_INIT_ARRAY and DT_FINI_ARRAY.
+}
+
+// The mapping of .gnu.linkonce section names to real section names.
+
+#define MAPPING_INIT(f, t) { f, sizeof(f) - 1, t, sizeof(t) - 1 }
+const Layout::Linkonce_mapping Layout::linkonce_mapping[] =
+{
+ MAPPING_INIT("d.rel.ro", ".data.rel.ro"), // Must be before "d".
+ MAPPING_INIT("t", ".text"),
+ MAPPING_INIT("r", ".rodata"),
+ MAPPING_INIT("d", ".data"),
+ MAPPING_INIT("b", ".bss"),
+ MAPPING_INIT("s", ".sdata"),
+ MAPPING_INIT("sb", ".sbss"),
+ MAPPING_INIT("s2", ".sdata2"),
+ MAPPING_INIT("sb2", ".sbss2"),
+ MAPPING_INIT("wi", ".debug_info"),
+ MAPPING_INIT("td", ".tdata"),
+ MAPPING_INIT("tb", ".tbss"),
+ MAPPING_INIT("lr", ".lrodata"),
+ MAPPING_INIT("l", ".ldata"),
+ MAPPING_INIT("lb", ".lbss"),
+};
+#undef MAPPING_INIT
+
+const int Layout::linkonce_mapping_count =
+ sizeof(Layout::linkonce_mapping) / sizeof(Layout::linkonce_mapping[0]);
+
+// Return the name of the output section to use for a .gnu.linkonce
+// section. This is based on the default ELF linker script of the old
+// GNU linker. For example, we map a name like ".gnu.linkonce.t.foo"
+// to ".text". Set *PLEN to the length of the name. *PLEN is
+// initialized to the length of NAME.
+
+const char*
+Layout::linkonce_output_name(const char* name, size_t *plen)
+{
+ const char* s = name + sizeof(".gnu.linkonce") - 1;
+ if (*s != '.')
+ return name;
+ ++s;
+ const Linkonce_mapping* plm = linkonce_mapping;
+ for (int i = 0; i < linkonce_mapping_count; ++i, ++plm)
+ {
+ if (strncmp(s, plm->from, plm->fromlen) == 0 && s[plm->fromlen] == '.')
+ {
+ *plen = plm->tolen;
+ return plm->to;
+ }
+ }
+ return name;
+}
+
+// Choose the output section name to use given an input section name.
+// Set *PLEN to the length of the name. *PLEN is initialized to the
+// length of NAME.
+
+const char*
+Layout::output_section_name(const char* name, size_t* plen)
+{
+ if (Layout::is_linkonce(name))
+ {
+ // .gnu.linkonce sections are laid out as though they were named
+ // for the sections are placed into.
+ return Layout::linkonce_output_name(name, plen);
+ }
+
+ // If the section name has no '.', or only an initial '.', we use
+ // the name unchanged (i.e., ".text" is unchanged).
+
+ // Otherwise, if the section name does not include ".rel", we drop
+ // the last '.' and everything that follows (i.e., ".text.XXX"
+ // becomes ".text").
+
+ // Otherwise, if the section name has zero or one '.' after the
+ // ".rel", we use the name unchanged (i.e., ".rel.text" is
+ // unchanged).
+
+ // Otherwise, we drop the last '.' and everything that follows
+ // (i.e., ".rel.text.XXX" becomes ".rel.text").
+
+ const char* s = name;
+ if (*s == '.')
+ ++s;
+ const char* sdot = strchr(s, '.');
+ if (sdot == NULL)
+ return name;
+
+ const char* srel = strstr(s, ".rel");
+ if (srel == NULL)
+ {
+ *plen = sdot - name;
+ return name;
+ }
+
+ sdot = strchr(srel + 1, '.');
+ if (sdot == NULL)
+ return name;
+ sdot = strchr(sdot + 1, '.');
+ if (sdot == NULL)
+ return name;
+
+ *plen = sdot - name;
+ return name;
+}
+
+// Record the signature of a comdat section, and return whether to
+// include it in the link. If GROUP is true, this is a regular
+// section group. If GROUP is false, this is a group signature
+// derived from the name of a linkonce section. We want linkonce
+// signatures and group signatures to block each other, but we don't
+// want a linkonce signature to block another linkonce signature.
+
+bool
+Layout::add_comdat(const char* signature, bool group)
+{
+ std::string sig(signature);
+ std::pair<Signatures::iterator, bool> ins(
+ this->signatures_.insert(std::make_pair(sig, group)));
+
+ if (ins.second)
+ {
+ // This is the first time we've seen this signature.
+ return true;
+ }
+
+ if (ins.first->second)
+ {
+ // We've already seen a real section group with this signature.
+ return false;
+ }
+ else if (group)
+ {
+ // This is a real section group, and we've already seen a
+ // linkonce section with tihs signature. Record that we've seen
+ // a section group, and don't include this section group.
+ ins.first->second = true;
+ return false;
+ }
+ else
+ {
+ // We've already seen a linkonce section and this is a linkonce
+ // section. These don't block each other--this may be the same
+ // symbol name with different section types.
+ return true;
+ }
+}
+
+// Write out data not associated with a section or the symbol table.
+
+void
+Layout::write_data(const Symbol_table* symtab, const Target* target,
+ Output_file* of) const
+{
+ const Output_section* symtab_section = this->symtab_section_;
+ for (Section_list::const_iterator p = this->section_list_.begin();
+ p != this->section_list_.end();
+ ++p)
+ {
+ if ((*p)->needs_symtab_index())
+ {
+ gold_assert(symtab_section != NULL);
+ unsigned int index = (*p)->symtab_index();
+ gold_assert(index > 0 && index != -1U);
+ off_t off = (symtab_section->offset()
+ + index * symtab_section->entsize());
+ symtab->write_section_symbol(target, *p, of, off);
+ }
+ }
+
+ const Output_section* dynsym_section = this->dynsym_section_;
+ for (Section_list::const_iterator p = this->section_list_.begin();
+ p != this->section_list_.end();
+ ++p)
+ {
+ if ((*p)->needs_dynsym_index())
+ {
+ gold_assert(dynsym_section != NULL);
+ unsigned int index = (*p)->dynsym_index();
+ gold_assert(index > 0 && index != -1U);
+ off_t off = (dynsym_section->offset()
+ + index * dynsym_section->entsize());
+ symtab->write_section_symbol(target, *p, of, off);
+ }
+ }
+
+ // Write out the Output_sections. Most won't have anything to
+ // write, since most of the data will come from input sections which
+ // are handled elsewhere. But some Output_sections do have
+ // Output_data.
+ for (Section_list::const_iterator p = this->section_list_.begin();
+ p != this->section_list_.end();
+ ++p)
+ (*p)->write(of);
+
+ // Write out the Output_data which are not in an Output_section.
+ for (Data_list::const_iterator p = this->special_output_list_.begin();
+ p != this->special_output_list_.end();
+ ++p)
+ (*p)->write(of);
+}
+
+// Write_data_task methods.
+
+// We can always run this task.
+
+Task::Is_runnable_type
+Write_data_task::is_runnable(Workqueue*)
+{
+ return IS_RUNNABLE;
+}
+
+// We need to unlock FINAL_BLOCKER when finished.
+
+Task_locker*
+Write_data_task::locks(Workqueue* workqueue)
+{
+ return new Task_locker_block(*this->final_blocker_, workqueue);
+}
+
+// Run the task--write out the data.
+
+void
+Write_data_task::run(Workqueue*)
+{
+ this->layout_->write_data(this->symtab_, this->target_, this->of_);
+}
+
+// Write_symbols_task methods.
+
+// We can always run this task.
+
+Task::Is_runnable_type
+Write_symbols_task::is_runnable(Workqueue*)
+{
+ return IS_RUNNABLE;
+}
+
+// We need to unlock FINAL_BLOCKER when finished.
+
+Task_locker*
+Write_symbols_task::locks(Workqueue* workqueue)
+{
+ return new Task_locker_block(*this->final_blocker_, workqueue);
+}
+
+// Run the task--write out the symbols.
+
+void
+Write_symbols_task::run(Workqueue*)
+{
+ this->symtab_->write_globals(this->target_, this->sympool_, this->dynpool_,
+ this->of_);
+}
+
+// Close_task_runner methods.
+
+// Run the task--close the file.
+
+void
+Close_task_runner::run(Workqueue*)
+{
+ this->of_->close();
+}
+
+// Instantiate the templates we need. We could use the configure
+// script to restrict this to only the ones for implemented targets.
+
+template
+Output_section*
+Layout::layout<32, false>(Relobj* object, unsigned int shndx, const char* name,
+ const elfcpp::Shdr<32, false>& shdr, off_t*);
+
+template
+Output_section*
+Layout::layout<32, true>(Relobj* object, unsigned int shndx, const char* name,
+ const elfcpp::Shdr<32, true>& shdr, off_t*);
+
+template
+Output_section*
+Layout::layout<64, false>(Relobj* object, unsigned int shndx, const char* name,
+ const elfcpp::Shdr<64, false>& shdr, off_t*);
+
+template
+Output_section*
+Layout::layout<64, true>(Relobj* object, unsigned int shndx, const char* name,
+ const elfcpp::Shdr<64, true>& shdr, off_t*);
+
+
+} // End namespace gold.
diff --git a/gold/layout.h b/gold/layout.h
new file mode 100644
index 000000000000..8b349cc0a4bd
--- /dev/null
+++ b/gold/layout.h
@@ -0,0 +1,430 @@
+// layout.h -- lay out output file sections for gold -*- C++ -*-
+
+#ifndef GOLD_LAYOUT_H
+#define GOLD_LAYOUT_H
+
+#include <list>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "workqueue.h"
+#include "object.h"
+#include "dynobj.h"
+#include "stringpool.h"
+
+namespace gold
+{
+
+class General_options;
+class Input_objects;
+class Symbol_table;
+class Output_section_data;
+class Output_section;
+class Output_section_headers;
+class Output_segment;
+class Output_data;
+class Output_data_dynamic;
+class Target;
+
+// This task function handles mapping the input sections to output
+// sections and laying them out in memory.
+
+class Layout_task_runner : public Task_function_runner
+{
+ public:
+ // OPTIONS is the command line options, INPUT_OBJECTS is the list of
+ // input objects, SYMTAB is the symbol table, LAYOUT is the layout
+ // object.
+ Layout_task_runner(const General_options& options,
+ const Input_objects* input_objects,
+ Symbol_table* symtab,
+ Layout* layout)
+ : options_(options), input_objects_(input_objects), symtab_(symtab),
+ layout_(layout)
+ { }
+
+ // Run the operation.
+ void
+ run(Workqueue*);
+
+ private:
+ Layout_task_runner(const Layout_task_runner&);
+ Layout_task_runner& operator=(const Layout_task_runner&);
+
+ const General_options& options_;
+ const Input_objects* input_objects_;
+ Symbol_table* symtab_;
+ Layout* layout_;
+};
+
+// This class handles the details of laying out input sections.
+
+class Layout
+{
+ public:
+ Layout(const General_options& options);
+
+ // Given an input section SHNDX, named NAME, with data in SHDR, from
+ // the object file OBJECT, return the output section where this
+ // input section should go. Set *OFFSET to the offset within the
+ // output section.
+ template<int size, bool big_endian>
+ Output_section*
+ layout(Relobj *object, unsigned int shndx, const char* name,
+ const elfcpp::Shdr<size, big_endian>& shdr, off_t* offset);
+
+ // Add an Output_section_data to the layout. This is used for
+ // special sections like the GOT section.
+ void
+ add_output_section_data(const char* name, elfcpp::Elf_Word type,
+ elfcpp::Elf_Xword flags,
+ Output_section_data*);
+
+ // Create dynamic sections if necessary.
+ void
+ create_initial_dynamic_sections(const Input_objects*, Symbol_table*);
+
+ // Return the Stringpool used for symbol names.
+ const Stringpool*
+ sympool() const
+ { return &this->sympool_; }
+
+ // Return the Stringpool used for dynamic symbol names and dynamic
+ // tags.
+ const Stringpool*
+ dynpool() const
+ { return &this->dynpool_; }
+
+ // Return whether a section is a .gnu.linkonce section, given the
+ // section name.
+ static inline bool
+ is_linkonce(const char* name)
+ { return strncmp(name, ".gnu.linkonce", sizeof(".gnu.linkonce") - 1) == 0; }
+
+ // Record the signature of a comdat section, and return whether to
+ // include it in the link. The GROUP parameter is true for a
+ // section group signature, false for a signature derived from a
+ // .gnu.linkonce section.
+ bool
+ add_comdat(const char*, bool group);
+
+ // Finalize the layout after all the input sections have been added.
+ off_t
+ finalize(const Input_objects*, Symbol_table*);
+
+ // Return the TLS segment. This will return NULL if there isn't
+ // one.
+ Output_segment*
+ tls_segment() const
+ { return this->tls_segment_; }
+
+ // Return the normal symbol table.
+ Output_section*
+ symtab_section() const
+ {
+ gold_assert(this->symtab_section_ != NULL);
+ return this->symtab_section_;
+ }
+
+ // Return the dynamic symbol table.
+ Output_section*
+ dynsym_section() const
+ {
+ gold_assert(this->dynsym_section_ != NULL);
+ return this->dynsym_section_;
+ }
+
+ // Return the dynamic tags.
+ Output_data_dynamic*
+ dynamic_data() const
+ { return this->dynamic_data_; }
+
+ // Write out data not associated with an input file or the symbol
+ // table.
+ void
+ write_data(const Symbol_table*, const Target*, Output_file*) const;
+
+ // Return an output section named NAME, or NULL if there is none.
+ Output_section*
+ find_output_section(const char* name) const;
+
+ // Return an output segment of type TYPE, with segment flags SET set
+ // and segment flags CLEAR clear. Return NULL if there is none.
+ Output_segment*
+ find_output_segment(elfcpp::PT type, elfcpp::Elf_Word set,
+ elfcpp::Elf_Word clear) const;
+
+ // The list of segments.
+
+ typedef std::vector<Output_segment*> Segment_list;
+
+ // The list of sections not attached to a segment.
+
+ typedef std::vector<Output_section*> Section_list;
+
+ // The list of information to write out which is not attached to
+ // either a section or a segment.
+ typedef std::vector<Output_data*> Data_list;
+
+ private:
+ Layout(const Layout&);
+ Layout& operator=(const Layout&);
+
+ // Mapping from .gnu.linkonce section names to output section names.
+ struct Linkonce_mapping
+ {
+ const char* from;
+ int fromlen;
+ const char* to;
+ int tolen;
+ };
+ static const Linkonce_mapping linkonce_mapping[];
+ static const int linkonce_mapping_count;
+
+ // Find the first read-only PT_LOAD segment, creating one if
+ // necessary.
+ Output_segment*
+ find_first_load_seg();
+
+ // Create the output sections for the symbol table.
+ void
+ create_symtab_sections(int size, const Input_objects*, Symbol_table*,
+ off_t*);
+
+ // Create the .shstrtab section.
+ Output_section*
+ create_shstrtab();
+
+ // Create the section header table.
+ Output_section_headers*
+ create_shdrs(int size, bool big_endian, off_t*);
+
+ // Create the dynamic symbol table.
+ void
+ create_dynamic_symtab(const Target*, Symbol_table*, Output_section** pdynstr,
+ unsigned int* plocal_dynamic_count,
+ std::vector<Symbol*>* pdynamic_symbols,
+ Versions* versions);
+
+ // Finish the .dynamic section and PT_DYNAMIC segment.
+ void
+ finish_dynamic_section(const Input_objects*, const Symbol_table*);
+
+ // Create the .interp section and PT_INTERP segment.
+ void
+ create_interp(const Target* target);
+
+ // Create the version sections.
+ void
+ create_version_sections(const Target*, const Versions*,
+ unsigned int local_symcount,
+ const std::vector<Symbol*>& dynamic_symbols,
+ const Output_section* dynstr);
+
+ template<int size, bool big_endian>
+ void
+ sized_create_version_sections(const Versions* versions,
+ unsigned int local_symcount,
+ const std::vector<Symbol*>& dynamic_symbols,
+ const Output_section* dynstr
+ ACCEPT_SIZE_ENDIAN);
+
+ // Return whether to include this section in the link.
+ template<int size, bool big_endian>
+ bool
+ include_section(Object* object, const char* name,
+ const elfcpp::Shdr<size, big_endian>&);
+
+ // Return the output section name to use given an input section
+ // name. Set *PLEN to the length of the name. *PLEN must be
+ // initialized to the length of NAME.
+ static const char*
+ output_section_name(const char* name, size_t* plen);
+
+ // Return the output section name to use for a linkonce section
+ // name. PLEN is as for output_section_name.
+ static const char*
+ linkonce_output_name(const char* name, size_t* plen);
+
+ // Return the output section for NAME, TYPE and FLAGS.
+ Output_section*
+ get_output_section(const char* name, Stringpool::Key name_key,
+ elfcpp::Elf_Word type, elfcpp::Elf_Xword flags);
+
+ // Create a new Output_section.
+ Output_section*
+ make_output_section(const char* name, elfcpp::Elf_Word type,
+ elfcpp::Elf_Xword flags);
+
+ // Set the final file offsets of all the segments.
+ off_t
+ set_segment_offsets(const Target*, Output_segment*, unsigned int* pshndx);
+
+ // Set the final file offsets and section indexes of all the
+ // sections not associated with a segment.
+ off_t
+ set_section_offsets(off_t, unsigned int *pshndx);
+
+ // Return whether SEG1 comes before SEG2 in the output file.
+ static bool
+ segment_precedes(const Output_segment* seg1, const Output_segment* seg2);
+
+ // Map from section flags to segment flags.
+ static elfcpp::Elf_Word
+ section_flags_to_segment(elfcpp::Elf_Xword flags);
+
+ // A mapping used for group signatures.
+ typedef Unordered_map<std::string, bool> Signatures;
+
+ // Mapping from input section name/type/flags to output section. We
+ // use canonicalized strings here.
+
+ typedef std::pair<Stringpool::Key,
+ std::pair<elfcpp::Elf_Word, elfcpp::Elf_Xword> > Key;
+
+ struct Hash_key
+ {
+ size_t
+ operator()(const Key& k) const;
+ };
+
+ typedef Unordered_map<Key, Output_section*, Hash_key> Section_name_map;
+
+ // A comparison class for segments.
+
+ struct Compare_segments
+ {
+ bool
+ operator()(const Output_segment* seg1, const Output_segment* seg2)
+ { return Layout::segment_precedes(seg1, seg2); }
+ };
+
+ // A reference to the options on the command line.
+ const General_options& options_;
+ // The output section names.
+ Stringpool namepool_;
+ // The output symbol names.
+ Stringpool sympool_;
+ // The dynamic strings, if needed.
+ Stringpool dynpool_;
+ // The list of group sections and linkonce sections which we have seen.
+ Signatures signatures_;
+ // The mapping from input section name/type/flags to output sections.
+ Section_name_map section_name_map_;
+ // The list of output segments.
+ Segment_list segment_list_;
+ // The list of output sections.
+ Section_list section_list_;
+ // The list of output sections which are not attached to any output
+ // segment.
+ Section_list unattached_section_list_;
+ // The list of unattached Output_data objects which require special
+ // handling because they are not Output_sections.
+ Data_list special_output_list_;
+ // A pointer to the PT_TLS segment if there is one.
+ Output_segment* tls_segment_;
+ // The SHT_SYMTAB output section.
+ Output_section* symtab_section_;
+ // The SHT_DYNSYM output section if there is one.
+ Output_section* dynsym_section_;
+ // The SHT_DYNAMIC output section if there is one.
+ Output_section* dynamic_section_;
+ // The dynamic data which goes into dynamic_section_.
+ Output_data_dynamic* dynamic_data_;
+};
+
+// This task handles writing out data which is not part of a section
+// or segment.
+
+class Write_data_task : public Task
+{
+ public:
+ Write_data_task(const Layout* layout, const Symbol_table* symtab,
+ const Target* target, Output_file* of,
+ Task_token* final_blocker)
+ : layout_(layout), symtab_(symtab), target_(target), of_(of),
+ final_blocker_(final_blocker)
+ { }
+
+ // The standard Task methods.
+
+ Is_runnable_type
+ is_runnable(Workqueue*);
+
+ Task_locker*
+ locks(Workqueue*);
+
+ void
+ run(Workqueue*);
+
+ private:
+ const Layout* layout_;
+ const Symbol_table* symtab_;
+ const Target* target_;
+ Output_file* of_;
+ Task_token* final_blocker_;
+};
+
+// This task handles writing out the global symbols.
+
+class Write_symbols_task : public Task
+{
+ public:
+ Write_symbols_task(const Symbol_table* symtab, const Target* target,
+ const Stringpool* sympool, const Stringpool* dynpool,
+ Output_file* of, Task_token* final_blocker)
+ : symtab_(symtab), target_(target), sympool_(sympool), dynpool_(dynpool),
+ of_(of), final_blocker_(final_blocker)
+ { }
+
+ // The standard Task methods.
+
+ Is_runnable_type
+ is_runnable(Workqueue*);
+
+ Task_locker*
+ locks(Workqueue*);
+
+ void
+ run(Workqueue*);
+
+ private:
+ const Symbol_table* symtab_;
+ const Target* target_;
+ const Stringpool* sympool_;
+ const Stringpool* dynpool_;
+ Output_file* of_;
+ Task_token* final_blocker_;
+};
+
+// This task function handles closing the file.
+
+class Close_task_runner : public Task_function_runner
+{
+ public:
+ Close_task_runner(Output_file* of)
+ : of_(of)
+ { }
+
+ // Run the operation.
+ void
+ run(Workqueue*);
+
+ private:
+ Output_file* of_;
+};
+
+// A small helper function to align an address.
+
+inline uint64_t
+align_address(uint64_t address, uint64_t addralign)
+{
+ if (addralign != 0)
+ address = (address + addralign - 1) &~ (addralign - 1);
+ return address;
+}
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_LAYOUT_H)
diff --git a/gold/main.cc b/gold/main.cc
new file mode 100644
index 000000000000..ea65c2da27e1
--- /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/merge.cc b/gold/merge.cc
new file mode 100644
index 000000000000..7af4faa03c92
--- /dev/null
+++ b/gold/merge.cc
@@ -0,0 +1,333 @@
+// merge.cc -- handle section merging for gold
+
+#include "gold.h"
+
+#include <cstdlib>
+
+#include "merge.h"
+
+namespace gold
+{
+
+// Sort the entries in a merge mapping. The key is an input object, a
+// section index in that object, and an offset in that section.
+
+bool
+Output_merge_base::Merge_key_less::operator()(const Merge_key& mk1,
+ const Merge_key& mk2) const
+{
+ // The order of different objects and different sections doesn't
+ // matter. We want to get consistent results across links so we
+ // don't use pointer comparison.
+ if (mk1.object != mk2.object)
+ return mk1.object->name() < mk2.object->name();
+ if (mk1.shndx != mk2.shndx)
+ return mk1.shndx < mk2.shndx;
+ return mk1.offset < mk2.offset;
+}
+
+// Add a mapping from an OFFSET in input section SHNDX in object
+// OBJECT to an OUTPUT_OFFSET in a merged output section. This
+// manages the mapping used to resolve relocations against merged
+// sections.
+
+void
+Output_merge_base::add_mapping(Relobj* object, unsigned int shndx,
+ off_t offset, off_t output_offset)
+{
+ Merge_key mk;
+ mk.object = object;
+ mk.shndx = shndx;
+ mk.offset = offset;
+ std::pair<Merge_map::iterator, bool> ins =
+ this->merge_map_.insert(std::make_pair(mk, output_offset));
+ gold_assert(ins.second);
+}
+
+// Return the output address for an input address. The input address
+// is at offset OFFSET in section SHNDX in OBJECT.
+// OUTPUT_SECTION_ADDRESS is the address of the output section. If we
+// know the address, set *POUTPUT and return true. Otherwise return
+// false.
+
+bool
+Output_merge_base::do_output_address(const Relobj* object, unsigned int shndx,
+ off_t offset,
+ uint64_t output_section_address,
+ uint64_t* poutput) const
+{
+ gold_assert(output_section_address == this->address());
+
+ Merge_key mk;
+ mk.object = object;
+ mk.shndx = shndx;
+ mk.offset = offset;
+ Merge_map::const_iterator p = this->merge_map_.lower_bound(mk);
+
+ // If MK is not in the map, lower_bound returns the next iterator
+ // larger than it.
+ if (p->first.object != object
+ || p->first.shndx != shndx
+ || p->first.offset != offset)
+ {
+ if (p == this->merge_map_.begin())
+ return false;
+ --p;
+ }
+
+ if (p->first.object != object || p->first.shndx != shndx)
+ return false;
+
+ // Any input section is fully mapped: we don't need to know the size
+ // of the range starting at P->FIRST.OFFSET.
+ *poutput = output_section_address + p->second + (offset - p->first.offset);
+ return true;
+}
+
+// Compute the hash code for a fixed-size constant.
+
+size_t
+Output_merge_data::Merge_data_hash::operator()(Merge_data_key k) const
+{
+ const unsigned char* p = this->pomd_->constant(k);
+ uint64_t entsize = this->pomd_->entsize();
+
+ // Fowler/Noll/Vo (FNV) hash (type FNV-1a).
+ if (sizeof(size_t) == 8)
+ {
+ size_t result = static_cast<size_t>(14695981039346656037ULL);
+ for (uint64_t i = 0; i < entsize; ++i)
+ {
+ result &= (size_t) *p++;
+ result *= 1099511628211ULL;
+ }
+ return result;
+ }
+ else
+ {
+ size_t result = 2166136261UL;
+ for (uint64_t i = 0; i < entsize; ++i)
+ {
+ result ^= (size_t) *p++;
+ result *= 16777619UL;
+ }
+ return result;
+ }
+}
+
+// Return whether one hash table key equals another.
+
+bool
+Output_merge_data::Merge_data_eq::operator()(Merge_data_key k1,
+ Merge_data_key k2) const
+{
+ const unsigned char* p1 = this->pomd_->constant(k1);
+ const unsigned char* p2 = this->pomd_->constant(k2);
+ return memcmp(p1, p2, this->pomd_->entsize()) == 0;
+}
+
+// Add a constant to the end of the section contents.
+
+void
+Output_merge_data::add_constant(const unsigned char* p)
+{
+ uint64_t entsize = this->entsize();
+ if (this->len_ + entsize > this->alc_)
+ {
+ if (this->alc_ == 0)
+ this->alc_ = 128 * entsize;
+ else
+ this->alc_ *= 2;
+ this->p_ = static_cast<unsigned char*>(realloc(this->p_, this->alc_));
+ if (this->p_ == NULL)
+ gold_fatal("out of memory", true);
+ }
+
+ memcpy(this->p_ + this->len_, p, entsize);
+ this->len_ += entsize;
+}
+
+// Add the input section SHNDX in OBJECT to a merged output section
+// which holds fixed length constants. Return whether we were able to
+// handle the section; if not, it will be linked as usual without
+// constant merging.
+
+bool
+Output_merge_data::do_add_input_section(Relobj* object, unsigned int shndx)
+{
+ off_t len;
+ const unsigned char* p = object->section_contents(shndx, &len);
+
+ uint64_t entsize = this->entsize();
+
+ if (len % entsize != 0)
+ return false;
+
+ for (off_t i = 0; i < len; i += entsize, p += entsize)
+ {
+ // Add the constant to the section contents. If we find that it
+ // is already in the hash table, we will remove it again.
+ Merge_data_key k = this->len_;
+ this->add_constant(p);
+
+ std::pair<Merge_data_hashtable::iterator, bool> ins =
+ this->hashtable_.insert(k);
+
+ if (!ins.second)
+ {
+ // Key was already present. Remove the copy we just added.
+ this->len_ -= entsize;
+ k = *ins.first;
+ }
+
+ // Record the offset of this constant in the output section.
+ this->add_mapping(object, shndx, i, k);
+ }
+
+ return true;
+}
+
+// Set the final data size in a merged output section with fixed size
+// constants.
+
+void
+Output_merge_data::do_set_address(uint64_t, off_t)
+{
+ // Release the memory we don't need.
+ this->p_ = static_cast<unsigned char*>(realloc(this->p_, this->len_));
+ gold_assert(this->p_ != NULL);
+ this->set_data_size(this->len_);
+}
+
+// Write the data of a merged output section with fixed size constants
+// to the file.
+
+void
+Output_merge_data::do_write(Output_file* of)
+{
+ of->write(this->offset(), this->p_, this->len_);
+}
+
+// Compute a hash code for a Merge_string_key, which is an object, a
+// section index, and an offset.
+
+template<typename Char_type>
+size_t
+Output_merge_string<Char_type>::Merge_string_key_hash::operator()(
+ const Merge_string_key& key) const
+{
+ // This is a very simple minded hash code. Fix it if it we get too
+ // many collisions.
+ const std::string& oname(key.object->name());
+ return oname[0] + oname.length() + key.shndx + key.offset;
+}
+
+// Compare two Merge_string_keys for equality.
+
+template<typename Char_type>
+bool
+Output_merge_string<Char_type>::Merge_string_key_eq::operator()(
+ const Merge_string_key& k1, const Merge_string_key& k2) const
+{
+ return (k1.object == k2.object
+ && k1.shndx == k2.shndx
+ && k1.offset == k2.offset);
+}
+
+// Add an input section to a merged string section.
+
+template<typename Char_type>
+bool
+Output_merge_string<Char_type>::do_add_input_section(Relobj* object,
+ unsigned int shndx)
+{
+ off_t len;
+ const unsigned char* pdata = object->section_contents(shndx, &len);
+
+ const Char_type* p = reinterpret_cast<const Char_type*>(pdata);
+
+ if (len % sizeof(Char_type) != 0)
+ {
+ fprintf(stderr,
+ _("%s: %s: mergeable string section length not multiple of "
+ "character size\n"),
+ program_name, object->name().c_str());
+ gold_exit(false);
+ }
+ len /= sizeof(Char_type);
+
+ off_t i = 0;
+ while (i < len)
+ {
+ off_t plen = 0;
+ for (const Char_type* pl = p; *pl != 0; ++pl)
+ {
+ ++plen;
+ if (i + plen >= len)
+ {
+ fprintf(stderr,
+ _("%s: %s: entry in mergeable string section "
+ "not null terminated\n"),
+ program_name, object->name().c_str());
+ gold_exit(false);
+ }
+ }
+
+ const Char_type* str = this->stringpool_.add(p, NULL);
+
+ Merge_string_key k(object, shndx, i);
+ typename Merge_string_hashtable::value_type v(k, str);
+ bool b = this->hashtable_.insert(v).second;
+ gold_assert(b);
+
+ p += plen + 1;
+ i += plen + 1;
+ }
+
+ return true;
+}
+
+// Set the final data size of a merged string section. This is where
+// we finalize the mappings from the input sections to the output
+// section.
+
+template<typename Char_type>
+void
+Output_merge_string<Char_type>::do_set_address(uint64_t, off_t)
+{
+ this->stringpool_.set_string_offsets();
+
+ for (typename Merge_string_hashtable::const_iterator p =
+ this->hashtable_.begin();
+ p != this->hashtable_.end();
+ ++p)
+ this->add_mapping(p->first.object, p->first.shndx, p->first.offset,
+ this->stringpool_.get_offset(p->second));
+
+ this->set_data_size(this->stringpool_.get_strtab_size());
+
+ // Save some memory.
+ this->hashtable_.clear();
+}
+
+// Write out a merged string section.
+
+template<typename Char_type>
+void
+Output_merge_string<Char_type>::do_write(Output_file* of)
+{
+ this->stringpool_.write(of, this->offset());
+}
+
+// Instantiate the templates we need.
+
+template
+class Output_merge_string<char>;
+
+template
+class Output_merge_string<uint16_t>;
+
+template
+class Output_merge_string<uint32_t>;
+
+} // End namespace gold.
diff --git a/gold/merge.h b/gold/merge.h
new file mode 100644
index 000000000000..dd97bf2d39e2
--- /dev/null
+++ b/gold/merge.h
@@ -0,0 +1,226 @@
+// merge.h -- handle section merging for gold -*- C++ -*-
+
+#ifndef GOLD_MERGE_H
+#define GOLD_MERGE_H
+
+#include <climits>
+
+#include "stringpool.h"
+#include "output.h"
+
+namespace gold
+{
+
+// A general class for SHF_MERGE data, to hold functions shared by
+// fixed-size constant data and string data.
+
+class Output_merge_base : public Output_section_data
+{
+ public:
+ Output_merge_base(uint64_t entsize)
+ : Output_section_data(1), merge_map_(), entsize_(entsize)
+ { }
+
+ // Return the output address for an input address.
+ bool
+ do_output_address(const Relobj* object, unsigned int shndx, off_t offset,
+ uint64_t output_section_address, uint64_t* poutput) const;
+
+ protected:
+ // Return the entry size.
+ uint64_t
+ entsize() const
+ { return this->entsize_; }
+
+ // Add a mapping from an OFFSET in input section SHNDX in object
+ // OBJECT to an OUTPUT_OFFSET in the output section.
+ void
+ add_mapping(Relobj* object, unsigned int shndx, off_t offset,
+ off_t output_offset);
+
+ private:
+ // We build a mapping from OBJECT/SHNDX/OFFSET to an offset in the
+ // output section.
+ struct Merge_key
+ {
+ const Relobj* object;
+ unsigned int shndx;
+ off_t offset;
+ };
+
+ struct Merge_key_less
+ {
+ bool
+ operator()(const Merge_key&, const Merge_key&) const;
+ };
+
+ typedef std::map<Merge_key, off_t, Merge_key_less> Merge_map;
+
+ // A mapping from input object/section/offset to offset in output
+ // section.
+ Merge_map merge_map_;
+
+ // The entry size. For fixed-size constants, this is the size of
+ // the constants. For strings, this is the size of a character.
+ uint64_t entsize_;
+};
+
+// Handle SHF_MERGE sections with fixed-size constant data.
+
+class Output_merge_data : public Output_merge_base
+{
+ public:
+ Output_merge_data(uint64_t entsize)
+ : Output_merge_base(entsize), p_(NULL), len_(0), alc_(0),
+ hashtable_(128, Merge_data_hash(this), Merge_data_eq(this))
+ { }
+
+ // Add an input section.
+ bool
+ do_add_input_section(Relobj* object, unsigned int shndx);
+
+ // Set the final data size.
+ void
+ do_set_address(uint64_t, off_t);
+
+ // Write the data to the file.
+ void
+ do_write(Output_file*);
+
+ private:
+ // We build a hash table of the fixed-size constants. Each constant
+ // is stored as a pointer into the section data we are accumulating.
+
+ // A key in the hash table. This is an offset in the section
+ // contents we are building.
+ typedef off_t Merge_data_key;
+
+ // Compute the hash code. To do this we need a pointer back to the
+ // object holding the data.
+ class Merge_data_hash
+ {
+ public:
+ Merge_data_hash(const Output_merge_data* pomd)
+ : pomd_(pomd)
+ { }
+
+ size_t
+ operator()(Merge_data_key) const;
+
+ private:
+ const Output_merge_data* pomd_;
+ };
+
+ friend class Merge_data_hash;
+
+ // Compare two entries in the hash table for equality. To do this
+ // we need a pointer back to the object holding the data. Note that
+ // we now have a pointer to the object stored in two places in the
+ // hash table. Fixing this would require specializing the hash
+ // table, which would be hard to do portably.
+ class Merge_data_eq
+ {
+ public:
+ Merge_data_eq(const Output_merge_data* pomd)
+ : pomd_(pomd)
+ { }
+
+ bool
+ operator()(Merge_data_key k1, Merge_data_key k2) const;
+
+ private:
+ const Output_merge_data* pomd_;
+ };
+
+ friend class Merge_data_eq;
+
+ // The type of the hash table.
+ typedef Unordered_set<Merge_data_key, Merge_data_hash, Merge_data_eq>
+ Merge_data_hashtable;
+
+ // Given a hash table key, which is just an offset into the section
+ // data, return a pointer to the corresponding constant.
+ const unsigned char*
+ constant(Merge_data_key k) const
+ {
+ gold_assert(k >= 0 && k < this->len_);
+ return this->p_ + k;
+ }
+
+ // Add a constant to the output.
+ void
+ add_constant(const unsigned char*);
+
+ // The accumulated data.
+ unsigned char* p_;
+ // The length of the accumulated data.
+ off_t len_;
+ // The size of the allocated buffer.
+ size_t alc_;
+ // The hash table.
+ Merge_data_hashtable hashtable_;
+};
+
+// Handle SHF_MERGE sections with string data. This is a template
+// based on the type of the characters in the string.
+
+template<typename Char_type>
+class Output_merge_string : public Output_merge_base
+{
+ public:
+ Output_merge_string()
+ : Output_merge_base(sizeof(Char_type)), stringpool_(false), hashtable_()
+ { }
+
+ // Add an input section.
+ bool
+ do_add_input_section(Relobj* object, unsigned int shndx);
+
+ // Set the final data size.
+ void
+ do_set_address(uint64_t, off_t);
+
+ // Write the data to the file.
+ void
+ do_write(Output_file*);
+
+ private:
+ // As we see input sections, we build a mapping from object, section
+ // index and offset to strings.
+ struct Merge_string_key
+ {
+ Relobj* object;
+ unsigned int shndx;
+ off_t offset;
+
+ Merge_string_key(Relobj *objecta, unsigned int shndxa, off_t offseta)
+ : object(objecta), shndx(shndxa), offset(offseta)
+ { }
+ };
+
+ struct Merge_string_key_hash
+ {
+ size_t
+ operator()(const Merge_string_key&) const;
+ };
+
+ struct Merge_string_key_eq
+ {
+ bool
+ operator()(const Merge_string_key&, const Merge_string_key&) const;
+ };
+
+ typedef Unordered_map<Merge_string_key, const Char_type*,
+ Merge_string_key_hash, Merge_string_key_eq>
+ Merge_string_hashtable;
+
+ // As we see the strings, we add them to a Stringpool.
+ Stringpool_template<Char_type> stringpool_;
+ // Map from a location in an input object to an entry in the
+ // Stringpool.
+ Merge_string_hashtable hashtable_;
+};
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_MERGE_H)
diff --git a/gold/object.cc b/gold/object.cc
new file mode 100644
index 000000000000..eb975c6c7345
--- /dev/null
+++ b/gold/object.cc
@@ -0,0 +1,973 @@
+// object.cc -- support for an object file for linking in gold
+
+#include "gold.h"
+
+#include <cerrno>
+#include <cstring>
+#include <cstdarg>
+
+#include "target-select.h"
+#include "layout.h"
+#include "output.h"
+#include "symtab.h"
+#include "object.h"
+#include "dynobj.h"
+
+namespace gold
+{
+
+// Class Object.
+
+// Set the target based on fields in the ELF file header.
+
+void
+Object::set_target(int machine, int size, bool big_endian, int osabi,
+ int abiversion)
+{
+ Target* target = select_target(machine, size, big_endian, osabi, abiversion);
+ if (target == NULL)
+ {
+ fprintf(stderr, _("%s: %s: unsupported ELF machine number %d\n"),
+ program_name, this->name().c_str(), machine);
+ gold_exit(false);
+ }
+ this->target_ = target;
+}
+
+// Report an error for the elfcpp::Elf_file interface.
+
+void
+Object::error(const char* format, ...)
+{
+ va_list args;
+
+ fprintf(stderr, "%s: %s: ", program_name, this->name().c_str());
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+ putc('\n', stderr);
+
+ gold_exit(false);
+}
+
+// Return a view of the contents of a section.
+
+const unsigned char*
+Object::section_contents(unsigned int shndx, off_t* plen)
+{
+ Location loc(this->do_section_contents(shndx));
+ *plen = loc.data_size;
+ return this->get_view(loc.file_offset, loc.data_size);
+}
+
+// Read the section data into SD. This is code common to Sized_relobj
+// and Sized_dynobj, so we put it into Object.
+
+template<int size, bool big_endian>
+void
+Object::read_section_data(elfcpp::Elf_file<size, big_endian, Object>* elf_file,
+ Read_symbols_data* sd)
+{
+ const int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
+
+ // Read the section headers.
+ const off_t shoff = elf_file->shoff();
+ const unsigned int shnum = this->shnum();
+ sd->section_headers = this->get_lasting_view(shoff, shnum * shdr_size);
+
+ // Read the section names.
+ const unsigned char* pshdrs = sd->section_headers->data();
+ const unsigned char* pshdrnames = pshdrs + elf_file->shstrndx() * shdr_size;
+ typename elfcpp::Shdr<size, big_endian> shdrnames(pshdrnames);
+
+ if (shdrnames.get_sh_type() != elfcpp::SHT_STRTAB)
+ {
+ fprintf(stderr,
+ _("%s: %s: section name section has wrong type: %u\n"),
+ program_name, this->name().c_str(),
+ static_cast<unsigned int>(shdrnames.get_sh_type()));
+ gold_exit(false);
+ }
+
+ sd->section_names_size = shdrnames.get_sh_size();
+ sd->section_names = this->get_lasting_view(shdrnames.get_sh_offset(),
+ sd->section_names_size);
+}
+
+// If NAME is the name of a special .gnu.warning section, arrange for
+// the warning to be issued. SHNDX is the section index. Return
+// whether it is a warning section.
+
+bool
+Object::handle_gnu_warning_section(const char* name, unsigned int shndx,
+ Symbol_table* symtab)
+{
+ const char warn_prefix[] = ".gnu.warning.";
+ const int warn_prefix_len = sizeof warn_prefix - 1;
+ if (strncmp(name, warn_prefix, warn_prefix_len) == 0)
+ {
+ symtab->add_warning(name + warn_prefix_len, this, shndx);
+ return true;
+ }
+ return false;
+}
+
+// Class Sized_relobj.
+
+template<int size, bool big_endian>
+Sized_relobj<size, big_endian>::Sized_relobj(
+ const std::string& name,
+ Input_file* input_file,
+ off_t offset,
+ const elfcpp::Ehdr<size, big_endian>& ehdr)
+ : Relobj(name, input_file, offset),
+ elf_file_(this, ehdr),
+ symtab_shndx_(-1U),
+ local_symbol_count_(0),
+ output_local_symbol_count_(0),
+ symbols_(NULL),
+ local_symbol_offset_(0),
+ local_values_()
+{
+}
+
+template<int size, bool big_endian>
+Sized_relobj<size, big_endian>::~Sized_relobj()
+{
+}
+
+// Set up an object file based on the file header. This sets up the
+// target and reads the section information.
+
+template<int size, bool big_endian>
+void
+Sized_relobj<size, big_endian>::setup(
+ const elfcpp::Ehdr<size, big_endian>& ehdr)
+{
+ this->set_target(ehdr.get_e_machine(), size, big_endian,
+ ehdr.get_e_ident()[elfcpp::EI_OSABI],
+ ehdr.get_e_ident()[elfcpp::EI_ABIVERSION]);
+
+ const unsigned int shnum = this->elf_file_.shnum();
+ this->set_shnum(shnum);
+}
+
+// Find the SHT_SYMTAB section, given the section headers. The ELF
+// standard says that maybe in the future there can be more than one
+// SHT_SYMTAB section. Until somebody figures out how that could
+// work, we assume there is only one.
+
+template<int size, bool big_endian>
+void
+Sized_relobj<size, big_endian>::find_symtab(const unsigned char* pshdrs)
+{
+ const unsigned int shnum = this->shnum();
+ this->symtab_shndx_ = 0;
+ if (shnum > 0)
+ {
+ // Look through the sections in reverse order, since gas tends
+ // to put the symbol table at the end.
+ const unsigned char* p = pshdrs + shnum * This::shdr_size;
+ unsigned int i = shnum;
+ while (i > 0)
+ {
+ --i;
+ p -= This::shdr_size;
+ typename This::Shdr shdr(p);
+ if (shdr.get_sh_type() == elfcpp::SHT_SYMTAB)
+ {
+ this->symtab_shndx_ = i;
+ break;
+ }
+ }
+ }
+}
+
+// Read the sections and symbols from an object file.
+
+template<int size, bool big_endian>
+void
+Sized_relobj<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
+{
+ this->read_section_data(&this->elf_file_, sd);
+
+ const unsigned char* const pshdrs = sd->section_headers->data();
+
+ this->find_symtab(pshdrs);
+
+ if (this->symtab_shndx_ == 0)
+ {
+ // No symbol table. Weird but legal.
+ sd->symbols = NULL;
+ sd->symbols_size = 0;
+ sd->symbol_names = NULL;
+ sd->symbol_names_size = 0;
+ return;
+ }
+
+ // Get the symbol table section header.
+ typename This::Shdr symtabshdr(pshdrs
+ + this->symtab_shndx_ * This::shdr_size);
+ gold_assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
+
+ // We only need the external symbols.
+ const int sym_size = This::sym_size;
+ const unsigned int loccount = symtabshdr.get_sh_info();
+ this->local_symbol_count_ = loccount;
+ off_t locsize = loccount * sym_size;
+ off_t extoff = symtabshdr.get_sh_offset() + locsize;
+ off_t extsize = symtabshdr.get_sh_size() - locsize;
+
+ // Read the symbol table.
+ File_view* fvsymtab = this->get_lasting_view(extoff, extsize);
+
+ // Read the section header for the symbol names.
+ unsigned int strtab_shndx = symtabshdr.get_sh_link();
+ if (strtab_shndx >= this->shnum())
+ {
+ fprintf(stderr, _("%s: %s: invalid symbol table name index: %u\n"),
+ program_name, this->name().c_str(), strtab_shndx);
+ gold_exit(false);
+ }
+ typename This::Shdr strtabshdr(pshdrs + strtab_shndx * This::shdr_size);
+ if (strtabshdr.get_sh_type() != elfcpp::SHT_STRTAB)
+ {
+ fprintf(stderr,
+ _("%s: %s: symbol table name section has wrong type: %u\n"),
+ program_name, this->name().c_str(),
+ static_cast<unsigned int>(strtabshdr.get_sh_type()));
+ gold_exit(false);
+ }
+
+ // Read the symbol names.
+ File_view* fvstrtab = this->get_lasting_view(strtabshdr.get_sh_offset(),
+ strtabshdr.get_sh_size());
+
+ sd->symbols = fvsymtab;
+ sd->symbols_size = extsize;
+ sd->symbol_names = fvstrtab;
+ sd->symbol_names_size = strtabshdr.get_sh_size();
+}
+
+// Return whether to include a section group in the link. LAYOUT is
+// used to keep track of which section groups we have already seen.
+// INDEX is the index of the section group and SHDR is the section
+// header. If we do not want to include this group, we set bits in
+// OMIT for each section which should be discarded.
+
+template<int size, bool big_endian>
+bool
+Sized_relobj<size, big_endian>::include_section_group(
+ Layout* layout,
+ unsigned int index,
+ const elfcpp::Shdr<size, big_endian>& shdr,
+ std::vector<bool>* omit)
+{
+ // Read the section contents.
+ const unsigned char* pcon = this->get_view(shdr.get_sh_offset(),
+ shdr.get_sh_size());
+ const elfcpp::Elf_Word* pword =
+ reinterpret_cast<const elfcpp::Elf_Word*>(pcon);
+
+ // The first word contains flags. We only care about COMDAT section
+ // groups. Other section groups are always included in the link
+ // just like ordinary sections.
+ elfcpp::Elf_Word flags = elfcpp::Swap<32, big_endian>::readval(pword);
+ if ((flags & elfcpp::GRP_COMDAT) == 0)
+ return true;
+
+ // Look up the group signature, which is the name of a symbol. This
+ // is a lot of effort to go to to read a string. Why didn't they
+ // just use the name of the SHT_GROUP section as the group
+ // signature?
+
+ // Get the appropriate symbol table header (this will normally be
+ // the single SHT_SYMTAB section, but in principle it need not be).
+ const unsigned int link = shdr.get_sh_link();
+ typename This::Shdr symshdr(this, this->elf_file_.section_header(link));
+
+ // Read the symbol table entry.
+ if (shdr.get_sh_info() >= symshdr.get_sh_size() / This::sym_size)
+ {
+ fprintf(stderr, _("%s: %s: section group %u info %u out of range\n"),
+ program_name, this->name().c_str(), index, shdr.get_sh_info());
+ gold_exit(false);
+ }
+ off_t symoff = symshdr.get_sh_offset() + shdr.get_sh_info() * This::sym_size;
+ const unsigned char* psym = this->get_view(symoff, This::sym_size);
+ elfcpp::Sym<size, big_endian> sym(psym);
+
+ // Read the symbol table names.
+ off_t symnamelen;
+ const unsigned char* psymnamesu;
+ psymnamesu = this->section_contents(symshdr.get_sh_link(), &symnamelen);
+ const char* psymnames = reinterpret_cast<const char*>(psymnamesu);
+
+ // Get the section group signature.
+ if (sym.get_st_name() >= symnamelen)
+ {
+ fprintf(stderr, _("%s: %s: symbol %u name offset %u out of range\n"),
+ program_name, this->name().c_str(), shdr.get_sh_info(),
+ sym.get_st_name());
+ gold_exit(false);
+ }
+
+ const char* signature = psymnames + sym.get_st_name();
+
+ // It seems that some versions of gas will create a section group
+ // associated with a section symbol, and then fail to give a name to
+ // the section symbol. In such a case, use the name of the section.
+ // FIXME.
+ std::string secname;
+ if (signature[0] == '\0' && sym.get_st_type() == elfcpp::STT_SECTION)
+ {
+ secname = this->section_name(sym.get_st_shndx());
+ signature = secname.c_str();
+ }
+
+ // Record this section group, and see whether we've already seen one
+ // with the same signature.
+ if (layout->add_comdat(signature, true))
+ return true;
+
+ // This is a duplicate. We want to discard the sections in this
+ // group.
+ size_t count = shdr.get_sh_size() / sizeof(elfcpp::Elf_Word);
+ for (size_t i = 1; i < count; ++i)
+ {
+ elfcpp::Elf_Word secnum =
+ elfcpp::Swap<32, big_endian>::readval(pword + i);
+ if (secnum >= this->shnum())
+ {
+ fprintf(stderr,
+ _("%s: %s: section %u in section group %u out of range"),
+ program_name, this->name().c_str(), secnum,
+ index);
+ gold_exit(false);
+ }
+ (*omit)[secnum] = true;
+ }
+
+ return false;
+}
+
+// Whether to include a linkonce section in the link. NAME is the
+// name of the section and SHDR is the section header.
+
+// Linkonce sections are a GNU extension implemented in the original
+// GNU linker before section groups were defined. The semantics are
+// that we only include one linkonce section with a given name. The
+// name of a linkonce section is normally .gnu.linkonce.T.SYMNAME,
+// where T is the type of section and SYMNAME is the name of a symbol.
+// In an attempt to make linkonce sections interact well with section
+// groups, we try to identify SYMNAME and use it like a section group
+// signature. We want to block section groups with that signature,
+// but not other linkonce sections with that signature. We also use
+// the full name of the linkonce section as a normal section group
+// signature.
+
+template<int size, bool big_endian>
+bool
+Sized_relobj<size, big_endian>::include_linkonce_section(
+ Layout* layout,
+ const char* name,
+ const elfcpp::Shdr<size, big_endian>&)
+{
+ const char* symname = strrchr(name, '.') + 1;
+ bool include1 = layout->add_comdat(symname, false);
+ bool include2 = layout->add_comdat(name, true);
+ return include1 && include2;
+}
+
+// Lay out the input sections. We walk through the sections and check
+// whether they should be included in the link. If they should, we
+// pass them to the Layout object, which will return an output section
+// and an offset.
+
+template<int size, bool big_endian>
+void
+Sized_relobj<size, big_endian>::do_layout(const General_options& options,
+ Symbol_table* symtab,
+ Layout* layout,
+ Read_symbols_data* sd)
+{
+ const unsigned int shnum = this->shnum();
+ if (shnum == 0)
+ return;
+
+ // Get the section headers.
+ const unsigned char* pshdrs = sd->section_headers->data();
+
+ // Get the section names.
+ const unsigned char* pnamesu = sd->section_names->data();
+ const char* pnames = reinterpret_cast<const char*>(pnamesu);
+
+ std::vector<Map_to_output>& map_sections(this->map_to_output());
+ map_sections.resize(shnum);
+
+ // Keep track of which sections to omit.
+ std::vector<bool> omit(shnum, false);
+
+ // Skip the first, dummy, section.
+ pshdrs += This::shdr_size;
+ for (unsigned int i = 1; i < shnum; ++i, pshdrs += This::shdr_size)
+ {
+ typename This::Shdr shdr(pshdrs);
+
+ if (shdr.get_sh_name() >= sd->section_names_size)
+ {
+ fprintf(stderr,
+ _("%s: %s: bad section name offset for section %u: %lu\n"),
+ program_name, this->name().c_str(), i,
+ static_cast<unsigned long>(shdr.get_sh_name()));
+ gold_exit(false);
+ }
+
+ const char* name = pnames + shdr.get_sh_name();
+
+ if (this->handle_gnu_warning_section(name, i, symtab))
+ {
+ if (!options.is_relocatable())
+ omit[i] = true;
+ }
+
+ bool discard = omit[i];
+ if (!discard)
+ {
+ if (shdr.get_sh_type() == elfcpp::SHT_GROUP)
+ {
+ if (!this->include_section_group(layout, i, shdr, &omit))
+ discard = true;
+ }
+ else if (Layout::is_linkonce(name))
+ {
+ if (!this->include_linkonce_section(layout, name, shdr))
+ discard = true;
+ }
+ }
+
+ if (discard)
+ {
+ // Do not include this section in the link.
+ map_sections[i].output_section = NULL;
+ continue;
+ }
+
+ off_t offset;
+ Output_section* os = layout->layout(this, i, name, shdr, &offset);
+
+ map_sections[i].output_section = os;
+ map_sections[i].offset = offset;
+ }
+
+ delete sd->section_headers;
+ sd->section_headers = NULL;
+ delete sd->section_names;
+ sd->section_names = NULL;
+}
+
+// Add the symbols to the symbol table.
+
+template<int size, bool big_endian>
+void
+Sized_relobj<size, big_endian>::do_add_symbols(Symbol_table* symtab,
+ Read_symbols_data* sd)
+{
+ if (sd->symbols == NULL)
+ {
+ gold_assert(sd->symbol_names == NULL);
+ return;
+ }
+
+ const int sym_size = This::sym_size;
+ size_t symcount = sd->symbols_size / sym_size;
+ if (symcount * sym_size != sd->symbols_size)
+ {
+ fprintf(stderr,
+ _("%s: %s: size of symbols is not multiple of symbol size\n"),
+ program_name, this->name().c_str());
+ gold_exit(false);
+ }
+
+ this->symbols_ = new Symbol*[symcount];
+
+ const char* sym_names =
+ reinterpret_cast<const char*>(sd->symbol_names->data());
+ symtab->add_from_relobj(this, sd->symbols->data(), symcount, sym_names,
+ sd->symbol_names_size, this->symbols_);
+
+ delete sd->symbols;
+ sd->symbols = NULL;
+ delete sd->symbol_names;
+ sd->symbol_names = NULL;
+}
+
+// Finalize the local symbols. Here we record the file offset at
+// which they should be output, we add their names to *POOL, and we
+// add their values to THIS->LOCAL_VALUES_. Return the symbol index.
+// This function is always called from the main thread. The actual
+// output of the local symbols will occur in a separate task.
+
+template<int size, bool big_endian>
+unsigned int
+Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index,
+ off_t off,
+ Stringpool* pool)
+{
+ gold_assert(this->symtab_shndx_ != -1U);
+ if (this->symtab_shndx_ == 0)
+ {
+ // This object has no symbols. Weird but legal.
+ return index;
+ }
+
+ gold_assert(off == static_cast<off_t>(align_address(off, size >> 3)));
+
+ this->local_symbol_offset_ = off;
+
+ // Read the symbol table section header.
+ const unsigned int symtab_shndx = this->symtab_shndx_;
+ typename This::Shdr symtabshdr(this,
+ this->elf_file_.section_header(symtab_shndx));
+ gold_assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
+
+ // Read the local symbols.
+ const int sym_size = This::sym_size;
+ const unsigned int loccount = this->local_symbol_count_;
+ gold_assert(loccount == symtabshdr.get_sh_info());
+ off_t locsize = loccount * sym_size;
+ const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(),
+ locsize);
+
+ this->local_values_.resize(loccount);
+
+ // Read the symbol names.
+ const unsigned int strtab_shndx = symtabshdr.get_sh_link();
+ off_t strtab_size;
+ const unsigned char* pnamesu = this->section_contents(strtab_shndx,
+ &strtab_size);
+ const char* pnames = reinterpret_cast<const char*>(pnamesu);
+
+ // Loop over the local symbols.
+
+ const std::vector<Map_to_output>& mo(this->map_to_output());
+ unsigned int shnum = this->shnum();
+ unsigned int count = 0;
+ // Skip the first, dummy, symbol.
+ psyms += sym_size;
+ for (unsigned int i = 1; i < loccount; ++i, psyms += sym_size)
+ {
+ elfcpp::Sym<size, big_endian> sym(psyms);
+
+ Symbol_value<size>& lv(this->local_values_[i]);
+
+ unsigned int shndx = sym.get_st_shndx();
+ lv.set_input_shndx(shndx);
+
+ if (shndx >= elfcpp::SHN_LORESERVE)
+ {
+ if (shndx == elfcpp::SHN_ABS)
+ lv.set_output_value(sym.get_st_value());
+ else
+ {
+ // FIXME: Handle SHN_XINDEX.
+ fprintf(stderr,
+ _("%s: %s: unknown section index %u "
+ "for local symbol %u\n"),
+ program_name, this->name().c_str(), shndx, i);
+ gold_exit(false);
+ }
+ }
+ else
+ {
+ if (shndx >= shnum)
+ {
+ fprintf(stderr,
+ _("%s: %s: local symbol %u section index %u "
+ "out of range\n"),
+ program_name, this->name().c_str(), i, shndx);
+ gold_exit(false);
+ }
+
+ Output_section* os = mo[shndx].output_section;
+
+ if (os == NULL)
+ {
+ lv.set_output_value(0);
+ lv.set_no_output_symtab_entry();
+ continue;
+ }
+
+ if (mo[shndx].offset == -1)
+ lv.set_input_value(sym.get_st_value());
+ else
+ lv.set_output_value(mo[shndx].output_section->address()
+ + mo[shndx].offset
+ + sym.get_st_value());
+ }
+
+ // Decide whether this symbol should go into the output file.
+
+ if (sym.get_st_type() == elfcpp::STT_SECTION)
+ {
+ lv.set_no_output_symtab_entry();
+ continue;
+ }
+
+ if (sym.get_st_name() >= strtab_size)
+ {
+ fprintf(stderr,
+ _("%s: %s: local symbol %u section name "
+ "out of range: %u >= %u\n"),
+ program_name, this->name().c_str(),
+ i, sym.get_st_name(),
+ static_cast<unsigned int>(strtab_size));
+ gold_exit(false);
+ }
+
+ const char* name = pnames + sym.get_st_name();
+ pool->add(name, NULL);
+ lv.set_output_symtab_index(index);
+ ++index;
+ ++count;
+ }
+
+ this->output_local_symbol_count_ = count;
+
+ return index;
+}
+
+// Return the value of a local symbol defined in input section SHNDX,
+// with value VALUE, adding addend ADDEND. This handles SHF_MERGE
+// sections.
+template<int size, bool big_endian>
+typename elfcpp::Elf_types<size>::Elf_Addr
+Sized_relobj<size, big_endian>::local_value(unsigned int shndx,
+ Address value,
+ Address addend) const
+{
+ const std::vector<Map_to_output>& mo(this->map_to_output());
+ Output_section* os = mo[shndx].output_section;
+ if (os == NULL)
+ return addend;
+ gold_assert(mo[shndx].offset == -1);
+ return os->output_address(this, shndx, value + addend);
+}
+
+// Write out the local symbols.
+
+template<int size, bool big_endian>
+void
+Sized_relobj<size, big_endian>::write_local_symbols(Output_file* of,
+ const Stringpool* sympool)
+{
+ gold_assert(this->symtab_shndx_ != -1U);
+ if (this->symtab_shndx_ == 0)
+ {
+ // This object has no symbols. Weird but legal.
+ return;
+ }
+
+ // Read the symbol table section header.
+ const unsigned int symtab_shndx = this->symtab_shndx_;
+ typename This::Shdr symtabshdr(this,
+ this->elf_file_.section_header(symtab_shndx));
+ gold_assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
+ const unsigned int loccount = this->local_symbol_count_;
+ gold_assert(loccount == symtabshdr.get_sh_info());
+
+ // Read the local symbols.
+ const int sym_size = This::sym_size;
+ off_t locsize = loccount * sym_size;
+ const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(),
+ locsize);
+
+ // Read the symbol names.
+ const unsigned int strtab_shndx = symtabshdr.get_sh_link();
+ off_t strtab_size;
+ const unsigned char* pnamesu = this->section_contents(strtab_shndx,
+ &strtab_size);
+ const char* pnames = reinterpret_cast<const char*>(pnamesu);
+
+ // Get a view into the output file.
+ off_t output_size = this->output_local_symbol_count_ * sym_size;
+ unsigned char* oview = of->get_output_view(this->local_symbol_offset_,
+ output_size);
+
+ const std::vector<Map_to_output>& mo(this->map_to_output());
+
+ gold_assert(this->local_values_.size() == loccount);
+
+ unsigned char* ov = oview;
+ psyms += sym_size;
+ for (unsigned int i = 1; i < loccount; ++i, psyms += sym_size)
+ {
+ elfcpp::Sym<size, big_endian> isym(psyms);
+
+ if (!this->local_values_[i].needs_output_symtab_entry())
+ continue;
+
+ unsigned int st_shndx = isym.get_st_shndx();
+ if (st_shndx < elfcpp::SHN_LORESERVE)
+ {
+ gold_assert(st_shndx < mo.size());
+ if (mo[st_shndx].output_section == NULL)
+ continue;
+ st_shndx = mo[st_shndx].output_section->out_shndx();
+ }
+
+ elfcpp::Sym_write<size, big_endian> osym(ov);
+
+ gold_assert(isym.get_st_name() < strtab_size);
+ const char* name = pnames + isym.get_st_name();
+ osym.put_st_name(sympool->get_offset(name));
+ osym.put_st_value(this->local_values_[i].value(this, 0));
+ osym.put_st_size(isym.get_st_size());
+ osym.put_st_info(isym.get_st_info());
+ osym.put_st_other(isym.get_st_other());
+ osym.put_st_shndx(st_shndx);
+
+ ov += sym_size;
+ }
+
+ gold_assert(ov - oview == output_size);
+
+ of->write_output_view(this->local_symbol_offset_, output_size, oview);
+}
+
+// Input_objects methods.
+
+// Add a regular relocatable object to the list. Return false if this
+// object should be ignored.
+
+bool
+Input_objects::add_object(Object* obj)
+{
+ if (!obj->is_dynamic())
+ this->relobj_list_.push_back(static_cast<Relobj*>(obj));
+ else
+ {
+ // See if this is a duplicate SONAME.
+ Dynobj* dynobj = static_cast<Dynobj*>(obj);
+
+ std::pair<Unordered_set<std::string>::iterator, bool> ins =
+ this->sonames_.insert(dynobj->soname());
+ if (!ins.second)
+ {
+ // We have already seen a dynamic object with this soname.
+ return false;
+ }
+
+ this->dynobj_list_.push_back(dynobj);
+ }
+
+ Target* target = obj->target();
+ if (this->target_ == NULL)
+ this->target_ = target;
+ else if (this->target_ != target)
+ {
+ fprintf(stderr, "%s: %s: incompatible target\n",
+ program_name, obj->name().c_str());
+ gold_exit(false);
+ }
+
+ return true;
+}
+
+// Relocate_info methods.
+
+// Return a string describing the location of a relocation. This is
+// only used in error messages.
+
+template<int size, bool big_endian>
+std::string
+Relocate_info<size, big_endian>::location(size_t relnum, off_t) const
+{
+ std::string ret(this->object->name());
+ ret += ": reloc ";
+ char buf[100];
+ snprintf(buf, sizeof buf, "%zu", relnum);
+ ret += buf;
+ ret += " in reloc section ";
+ snprintf(buf, sizeof buf, "%u", this->reloc_shndx);
+ ret += buf;
+ ret += " (" + this->object->section_name(this->reloc_shndx);
+ ret += ") for section ";
+ snprintf(buf, sizeof buf, "%u", this->data_shndx);
+ ret += buf;
+ ret += " (" + this->object->section_name(this->data_shndx) + ")";
+ return ret;
+}
+
+} // End namespace gold.
+
+namespace
+{
+
+using namespace gold;
+
+// Read an ELF file with the header and return the appropriate
+// instance of Object.
+
+template<int size, bool big_endian>
+Object*
+make_elf_sized_object(const std::string& name, Input_file* input_file,
+ off_t offset, const elfcpp::Ehdr<size, big_endian>& ehdr)
+{
+ int et = ehdr.get_e_type();
+ if (et == elfcpp::ET_REL)
+ {
+ Sized_relobj<size, big_endian>* obj =
+ new Sized_relobj<size, big_endian>(name, input_file, offset, ehdr);
+ obj->setup(ehdr);
+ return obj;
+ }
+ else if (et == elfcpp::ET_DYN)
+ {
+ Sized_dynobj<size, big_endian>* obj =
+ new Sized_dynobj<size, big_endian>(name, input_file, offset, ehdr);
+ obj->setup(ehdr);
+ return obj;
+ }
+ else
+ {
+ fprintf(stderr, _("%s: %s: unsupported ELF file type %d\n"),
+ program_name, name.c_str(), et);
+ gold_exit(false);
+ }
+}
+
+} // End anonymous namespace.
+
+namespace gold
+{
+
+// Read an ELF file and return the appropriate instance of Object.
+
+Object*
+make_elf_object(const std::string& name, Input_file* input_file, off_t offset,
+ const unsigned char* p, off_t bytes)
+{
+ if (bytes < elfcpp::EI_NIDENT)
+ {
+ fprintf(stderr, _("%s: %s: ELF file too short\n"),
+ program_name, name.c_str());
+ gold_exit(false);
+ }
+
+ int v = p[elfcpp::EI_VERSION];
+ if (v != elfcpp::EV_CURRENT)
+ {
+ if (v == elfcpp::EV_NONE)
+ fprintf(stderr, _("%s: %s: invalid ELF version 0\n"),
+ program_name, name.c_str());
+ else
+ fprintf(stderr, _("%s: %s: unsupported ELF version %d\n"),
+ program_name, name.c_str(), v);
+ gold_exit(false);
+ }
+
+ int c = p[elfcpp::EI_CLASS];
+ if (c == elfcpp::ELFCLASSNONE)
+ {
+ fprintf(stderr, _("%s: %s: invalid ELF class 0\n"),
+ program_name, name.c_str());
+ gold_exit(false);
+ }
+ else if (c != elfcpp::ELFCLASS32
+ && c != elfcpp::ELFCLASS64)
+ {
+ fprintf(stderr, _("%s: %s: unsupported ELF class %d\n"),
+ program_name, name.c_str(), c);
+ gold_exit(false);
+ }
+
+ int d = p[elfcpp::EI_DATA];
+ if (d == elfcpp::ELFDATANONE)
+ {
+ fprintf(stderr, _("%s: %s: invalid ELF data encoding\n"),
+ program_name, name.c_str());
+ gold_exit(false);
+ }
+ else if (d != elfcpp::ELFDATA2LSB
+ && d != elfcpp::ELFDATA2MSB)
+ {
+ fprintf(stderr, _("%s: %s: unsupported ELF data encoding %d\n"),
+ program_name, name.c_str(), d);
+ gold_exit(false);
+ }
+
+ bool big_endian = d == elfcpp::ELFDATA2MSB;
+
+ if (c == elfcpp::ELFCLASS32)
+ {
+ if (bytes < elfcpp::Elf_sizes<32>::ehdr_size)
+ {
+ fprintf(stderr, _("%s: %s: ELF file too short\n"),
+ program_name, name.c_str());
+ gold_exit(false);
+ }
+ if (big_endian)
+ {
+ elfcpp::Ehdr<32, true> ehdr(p);
+ return make_elf_sized_object<32, true>(name, input_file,
+ offset, ehdr);
+ }
+ else
+ {
+ elfcpp::Ehdr<32, false> ehdr(p);
+ return make_elf_sized_object<32, false>(name, input_file,
+ offset, ehdr);
+ }
+ }
+ else
+ {
+ if (bytes < elfcpp::Elf_sizes<32>::ehdr_size)
+ {
+ fprintf(stderr, _("%s: %s: ELF file too short\n"),
+ program_name, name.c_str());
+ gold_exit(false);
+ }
+ if (big_endian)
+ {
+ elfcpp::Ehdr<64, true> ehdr(p);
+ return make_elf_sized_object<64, true>(name, input_file,
+ offset, ehdr);
+ }
+ else
+ {
+ elfcpp::Ehdr<64, false> ehdr(p);
+ return make_elf_sized_object<64, false>(name, input_file,
+ offset, ehdr);
+ }
+ }
+}
+
+// Instantiate the templates we need. We could use the configure
+// script to restrict this to only the ones for implemented targets.
+
+template
+class Sized_relobj<32, false>;
+
+template
+class Sized_relobj<32, true>;
+
+template
+class Sized_relobj<64, false>;
+
+template
+class Sized_relobj<64, true>;
+
+template
+struct Relocate_info<32, false>;
+
+template
+struct Relocate_info<32, true>;
+
+template
+struct Relocate_info<64, false>;
+
+template
+struct Relocate_info<64, true>;
+
+} // End namespace gold.
diff --git a/gold/object.h b/gold/object.h
new file mode 100644
index 000000000000..2027f8e97dff
--- /dev/null
+++ b/gold/object.h
@@ -0,0 +1,820 @@
+// object.h -- support for an object file for linking in gold -*- C++ -*-
+
+#ifndef GOLD_OBJECT_H
+#define GOLD_OBJECT_H
+
+#include <string>
+#include <vector>
+
+#include "elfcpp.h"
+#include "elfcpp_file.h"
+#include "fileread.h"
+#include "target.h"
+
+namespace gold
+{
+
+class General_options;
+class Layout;
+class Output_section;
+class Output_file;
+class Dynobj;
+
+template<typename Stringpool_char>
+class Stringpool_template;
+
+// Data to pass from read_symbols() to add_symbols().
+
+struct Read_symbols_data
+{
+ // Section headers.
+ File_view* section_headers;
+ // Section names.
+ File_view* section_names;
+ // Size of section name data in bytes.
+ off_t section_names_size;
+ // Symbol data.
+ File_view* symbols;
+ // Size of symbol data in bytes.
+ off_t symbols_size;
+ // Symbol names.
+ File_view* symbol_names;
+ // Size of symbol name data in bytes.
+ off_t symbol_names_size;
+
+ // Version information. This is only used on dynamic objects.
+ // Version symbol data (from SHT_GNU_versym section).
+ File_view* versym;
+ off_t versym_size;
+ // Version definition data (from SHT_GNU_verdef section).
+ File_view* verdef;
+ off_t verdef_size;
+ unsigned int verdef_info;
+ // Needed version data (from SHT_GNU_verneed section).
+ File_view* verneed;
+ off_t verneed_size;
+ unsigned int verneed_info;
+};
+
+// Data about a single relocation section. This is read in
+// read_relocs and processed in scan_relocs.
+
+struct Section_relocs
+{
+ // Index of reloc section.
+ unsigned int reloc_shndx;
+ // Index of section that relocs apply to.
+ unsigned int data_shndx;
+ // Contents of reloc section.
+ File_view* contents;
+ // Reloc section type.
+ unsigned int sh_type;
+ // Number of reloc entries.
+ size_t reloc_count;
+};
+
+// Relocations in an object file. This is read in read_relocs and
+// processed in scan_relocs.
+
+struct Read_relocs_data
+{
+ typedef std::vector<Section_relocs> Relocs_list;
+ // The relocations.
+ Relocs_list relocs;
+ // The local symbols.
+ File_view* local_symbols;
+};
+
+// Object is an abstract base class which represents either a 32-bit
+// or a 64-bit input object. This can be a regular object file
+// (ET_REL) or a shared object (ET_DYN).
+
+class Object
+{
+ public:
+ // NAME is the name of the object as we would report it to the user
+ // (e.g., libfoo.a(bar.o) if this is in an archive. INPUT_FILE is
+ // used to read the file. OFFSET is the offset within the input
+ // file--0 for a .o or .so file, something else for a .a file.
+ Object(const std::string& name, Input_file* input_file, bool is_dynamic,
+ off_t offset = 0)
+ : name_(name), input_file_(input_file), offset_(offset), shnum_(-1U),
+ is_dynamic_(is_dynamic), target_(NULL)
+ { }
+
+ virtual ~Object()
+ { }
+
+ // Return the name of the object as we would report it to the tuser.
+ const std::string&
+ name() const
+ { return this->name_; }
+
+ // Return whether this is a dynamic object.
+ bool
+ is_dynamic() const
+ { return this->is_dynamic_; }
+
+ // Return the target structure associated with this object.
+ Target*
+ target() const
+ { return this->target_; }
+
+ // Lock the underlying file.
+ void
+ lock()
+ { this->input_file_->file().lock(); }
+
+ // Unlock the underlying file.
+ void
+ unlock()
+ { this->input_file_->file().unlock(); }
+
+ // Return whether the underlying file is locked.
+ bool
+ is_locked() const
+ { return this->input_file_->file().is_locked(); }
+
+ // Return the sized target structure associated with this object.
+ // This is like the target method but it returns a pointer of
+ // appropriate checked type.
+ template<int size, bool big_endian>
+ Sized_target<size, big_endian>*
+ sized_target(ACCEPT_SIZE_ENDIAN_ONLY);
+
+ // 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.
+ const unsigned char*
+ section_contents(unsigned int shndx, off_t* plen);
+
+ // Return the name of a section given a section index. This is only
+ // used for error messages.
+ std::string
+ section_name(unsigned int shndx)
+ { return this->do_section_name(shndx); }
+
+ // Return the section flags given a section index.
+ uint64_t
+ 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.
+
+ // The View class is returned by view. It must support a single
+ // method, data(). This is trivial, because get_view does what we
+ // need.
+ class View
+ {
+ public:
+ View(const unsigned char* p)
+ : p_(p)
+ { }
+
+ const unsigned char*
+ data() const
+ { return this->p_; }
+
+ private:
+ const unsigned char* p_;
+ };
+
+ // Return a View.
+ View
+ view(off_t file_offset, off_t data_size)
+ { return View(this->get_view(file_offset, data_size)); }
+
+ // Report an error.
+ void
+ error(const char* format, ...) ATTRIBUTE_PRINTF_2;
+
+ // A location in the file.
+ struct Location
+ {
+ off_t file_offset;
+ off_t data_size;
+
+ Location(off_t fo, off_t ds)
+ : file_offset(fo), data_size(ds)
+ { }
+ };
+
+ // Get a View given a Location.
+ View view(Location loc)
+ { return View(this->get_view(loc.file_offset, loc.data_size)); }
+
+ protected:
+ // Read the symbols--implemented by child class.
+ virtual void
+ do_read_symbols(Read_symbols_data*) = 0;
+
+ // Lay out sections--implemented by child class.
+ virtual void
+ do_layout(const General_options&, Symbol_table*, Layout*,
+ Read_symbols_data*) = 0;
+
+ // Add symbol information to the global symbol table--implemented by
+ // child class.
+ virtual void
+ do_add_symbols(Symbol_table*, Read_symbols_data*) = 0;
+
+ // Return the location of the contents of a section. Implemented by
+ // child class.
+ virtual Location
+ do_section_contents(unsigned int shndx) = 0;
+
+ // Get the name of a section--implemented by child class.
+ virtual std::string
+ do_section_name(unsigned int shndx) = 0;
+
+ // Get section flags--implemented by child class.
+ virtual uint64_t
+ do_section_flags(unsigned int shndx) = 0;
+
+ // Get the file.
+ Input_file*
+ input_file() const
+ { return this->input_file_; }
+
+ // Get the offset into the file.
+ off_t
+ offset() const
+ { return this->offset_; }
+
+ // Get a view into the underlying file.
+ const unsigned char*
+ get_view(off_t start, off_t size)
+ { return this->input_file_->file().get_view(start + this->offset_, size); }
+
+ // Get a lasting view into the underlying file.
+ File_view*
+ get_lasting_view(off_t start, off_t size)
+ {
+ return this->input_file_->file().get_lasting_view(start + this->offset_,
+ size);
+ }
+
+ // Read data from the underlying file.
+ void
+ read(off_t start, off_t size, void* p)
+ { this->input_file_->file().read(start + this->offset_, size, p); }
+
+ // Set the target.
+ void
+ set_target(int machine, int size, bool big_endian, int osabi,
+ int abiversion);
+
+ // Set the number of sections.
+ void
+ set_shnum(int shnum)
+ { this->shnum_ = shnum; }
+
+ // Functions used by both Sized_relobj and Sized_dynobj.
+
+ // Read the section data into a Read_symbols_data object.
+ template<int size, bool big_endian>
+ void
+ read_section_data(elfcpp::Elf_file<size, big_endian, Object>*,
+ Read_symbols_data*);
+
+ // If NAME is the name of a special .gnu.warning section, arrange
+ // for the warning to be issued. SHNDX is the section index.
+ // Return whether it is a warning section.
+ bool
+ handle_gnu_warning_section(const char* name, unsigned int shndx,
+ Symbol_table*);
+
+ private:
+ // This class may not be copied.
+ Object(const Object&);
+ Object& operator=(const Object&);
+
+ // Name of object as printed to user.
+ std::string name_;
+ // For reading the file.
+ Input_file* input_file_;
+ // Offset within the file--0 for an object file, non-0 for an
+ // archive.
+ off_t offset_;
+ // Number of input sections.
+ unsigned int shnum_;
+ // Whether this is a dynamic object.
+ bool is_dynamic_;
+ // Target functions--may be NULL if the target is not known.
+ Target* target_;
+};
+
+// Implement sized_target inline for efficiency. This approach breaks
+// static type checking, but is made safe using asserts.
+
+template<int size, bool big_endian>
+inline Sized_target<size, big_endian>*
+Object::sized_target(ACCEPT_SIZE_ENDIAN_ONLY)
+{
+ gold_assert(this->target_->get_size() == size);
+ gold_assert(this->target_->is_big_endian() ? big_endian : !big_endian);
+ return static_cast<Sized_target<size, big_endian>*>(this->target_);
+}
+
+// A regular object (ET_REL). This is an abstract base class itself.
+// The implementation is the template class Sized_relobj.
+
+class Relobj : public Object
+{
+ public:
+ Relobj(const std::string& name, Input_file* input_file, off_t offset = 0)
+ : Object(name, input_file, false, offset)
+ { }
+
+ // Read the relocs.
+ void
+ read_relocs(Read_relocs_data* rd)
+ { return this->do_read_relocs(rd); }
+
+ // Scan the relocs and adjust the symbol table.
+ void
+ scan_relocs(const General_options& options, Symbol_table* symtab,
+ Layout* layout, Read_relocs_data* rd)
+ { return this->do_scan_relocs(options, symtab, layout, rd); }
+
+ // Initial local symbol processing: set the offset where local
+ // symbol information will be stored; add local symbol names to
+ // *POOL; return the new local symbol index.
+ unsigned int
+ finalize_local_symbols(unsigned int index, off_t off,
+ Stringpool_template<char>* pool)
+ { return this->do_finalize_local_symbols(index, off, pool); }
+
+ // Relocate the input sections and write out the local symbols.
+ void
+ relocate(const General_options& options, const Symbol_table* symtab,
+ const Layout* layout, Output_file* of)
+ { return this->do_relocate(options, symtab, layout, of); }
+
+ // Return whether an input section is being included in the link.
+ bool
+ is_section_included(unsigned int shndx) const
+ {
+ 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 shndx, off_t* poff) const;
+
+ // Set the offset of an input section within its output section.
+ void
+ set_section_offset(unsigned int shndx, off_t off)
+ {
+ gold_assert(shndx < this->map_to_output_.size());
+ this->map_to_output_[shndx].offset = off;
+ }
+
+ protected:
+ // What we need to know to map an input section to an output
+ // section. We keep an array of these, one for each input section,
+ // indexed by the input section number.
+ struct Map_to_output
+ {
+ // The output section. This is NULL if the input section is to be
+ // discarded.
+ Output_section* output_section;
+ // The offset within the output section. This is -1 if the
+ // section requires special handling.
+ off_t offset;
+ };
+
+ // Read the relocs--implemented by child class.
+ virtual void
+ do_read_relocs(Read_relocs_data*) = 0;
+
+ // Scan the relocs--implemented by child class.
+ virtual void
+ do_scan_relocs(const General_options&, Symbol_table*, Layout*,
+ Read_relocs_data*) = 0;
+
+ // Finalize local symbols--implemented by child class.
+ virtual unsigned int
+ do_finalize_local_symbols(unsigned int, off_t,
+ Stringpool_template<char>*) = 0;
+
+ // Relocate the input sections and write out the local
+ // symbols--implemented by child class.
+ virtual void
+ do_relocate(const General_options& options, const Symbol_table* symtab,
+ const Layout*, Output_file* of) = 0;
+
+ // Return the vector mapping input sections to output sections.
+ std::vector<Map_to_output>&
+ map_to_output()
+ { return this->map_to_output_; }
+
+ const std::vector<Map_to_output>&
+ map_to_output() const
+ { return this->map_to_output_; }
+
+ private:
+ // Mapping from input sections to output section.
+ std::vector<Map_to_output> map_to_output_;
+};
+
+// Implement Object::output_section inline for efficiency.
+inline Output_section*
+Relobj::output_section(unsigned int shndx, off_t* poff) const
+{
+ 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;
+}
+
+// This POD class is holds the value of a symbol. This is used for
+// local symbols, and for all symbols during relocation processing.
+// In order to process relocs we need to be able to handle SHF_MERGE
+// sections correctly.
+
+template<int size>
+class Symbol_value
+{
+ public:
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Value;
+
+ Symbol_value()
+ : output_symtab_index_(0), input_shndx_(0), needs_output_address_(false),
+ value_(0)
+ { }
+
+ // Get the value of this symbol. OBJECT is the object in which this
+ // symbol is defined, and ADDEND is an addend to add to the value.
+ template<bool big_endian>
+ Value
+ value(const Sized_relobj<size, big_endian>* object, Value addend) const
+ {
+ if (!this->needs_output_address_)
+ return this->value_ + addend;
+ return object->local_value(this->input_shndx_, this->value_, addend);
+ }
+
+ // Set the value of this symbol in the output symbol table.
+ void
+ set_output_value(Value value)
+ {
+ this->value_ = value;
+ this->needs_output_address_ = false;
+ }
+
+ // If this symbol is mapped to an output section which requires
+ // special handling to determine the output value, we store the
+ // value of the symbol in the input file. This is used for
+ // SHF_MERGE sections.
+ void
+ set_input_value(Value value)
+ {
+ this->value_ = value;
+ this->needs_output_address_ = true;
+ }
+
+ // Return whether this symbol should go into the output symbol
+ // table.
+ bool
+ needs_output_symtab_entry() const
+ {
+ gold_assert(this->output_symtab_index_ != 0);
+ return this->output_symtab_index_ != -1U;
+ }
+
+ // Return the index in the output symbol table.
+ unsigned int
+ output_symtab_index() const
+ {
+ gold_assert(this->output_symtab_index_ != 0);
+ return this->output_symtab_index_;
+ }
+
+ // Set the index in the output symbol table.
+ void
+ set_output_symtab_index(unsigned int i)
+ {
+ gold_assert(this->output_symtab_index_ == 0);
+ this->output_symtab_index_ = i;
+ }
+
+ // Record that this symbol should not go into the output symbol
+ // table.
+ void
+ set_no_output_symtab_entry()
+ {
+ gold_assert(this->output_symtab_index_ == 0);
+ this->output_symtab_index_ = -1U;
+ }
+
+ // Set the index of the input section in the input file.
+ void
+ set_input_shndx(unsigned int i)
+ { this->input_shndx_ = i; }
+
+ private:
+ // The index of this local symbol in the output symbol table. This
+ // will be -1 if the symbol should not go into the symbol table.
+ unsigned int output_symtab_index_;
+ // The section index in the input file in which this symbol is
+ // defined.
+ unsigned int input_shndx_ : 31;
+ // Whether getting the value of this symbol requires calling an
+ // Output_section method. For example, this will be true of a
+ // STT_SECTION symbol in a SHF_MERGE section.
+ bool needs_output_address_ : 1;
+ // The value of the symbol. If !needs_output_address_, this is the
+ // value in the output file. If needs_output_address_, this is the
+ // value in the input file.
+ Value value_;
+};
+
+// A regular object file. This is size and endian specific.
+
+template<int size, bool big_endian>
+class Sized_relobj : public Relobj
+{
+ public:
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+ typedef std::vector<Symbol_value<size> > Local_values;
+
+ Sized_relobj(const std::string& name, Input_file* input_file, off_t offset,
+ const typename elfcpp::Ehdr<size, big_endian>&);
+
+ ~Sized_relobj();
+
+ // Set up the object file based on the ELF header.
+ void
+ setup(const typename elfcpp::Ehdr<size, big_endian>&);
+
+ // Return the index of local symbol SYM in the ordinary symbol
+ // table. A value of -1U means that the symbol is not being output.
+ unsigned int
+ symtab_index(unsigned int sym) const
+ {
+ gold_assert(sym < this->local_values_.size());
+ return this->local_values_[sym].output_symtab_index();
+ }
+
+ // Read the symbols.
+ void
+ do_read_symbols(Read_symbols_data*);
+
+ // Lay out the input sections.
+ void
+ do_layout(const General_options&, Symbol_table*, Layout*,
+ Read_symbols_data*);
+
+ // Add the symbols to the symbol table.
+ void
+ do_add_symbols(Symbol_table*, Read_symbols_data*);
+
+ // Read the relocs.
+ void
+ do_read_relocs(Read_relocs_data*);
+
+ // Scan the relocs and adjust the symbol table.
+ void
+ do_scan_relocs(const General_options&, Symbol_table*, Layout*,
+ Read_relocs_data*);
+
+ // Finalize the local symbols.
+ unsigned int
+ do_finalize_local_symbols(unsigned int, off_t,
+ Stringpool_template<char>*);
+
+ // Relocate the input sections and write out the local symbols.
+ void
+ do_relocate(const General_options& options, const Symbol_table* symtab,
+ const Layout*, Output_file* of);
+
+ // Get the name of a section.
+ std::string
+ do_section_name(unsigned int shndx)
+ { return this->elf_file_.section_name(shndx); }
+
+ // Return the location of the contents of a section.
+ Object::Location
+ do_section_contents(unsigned int shndx)
+ { return this->elf_file_.section_contents(shndx); }
+
+ // Return section flags.
+ uint64_t
+ do_section_flags(unsigned int shndx)
+ { return this->elf_file_.section_flags(shndx); }
+
+ // Return the appropriate Sized_target structure.
+ Sized_target<size, big_endian>*
+ sized_target()
+ {
+ return this->Object::sized_target
+ SELECT_SIZE_ENDIAN_NAME(size, big_endian) (
+ SELECT_SIZE_ENDIAN_ONLY(size, big_endian));
+ }
+
+ // Return the value of a local symbol define in input section SHNDX,
+ // with value VALUE, adding addend ADDEND. This handles SHF_MERGE
+ // sections.
+ Address
+ local_value(unsigned int shndx, Address value, Address addend) const;
+
+ private:
+ // For convenience.
+ typedef Sized_relobj<size, big_endian> This;
+ static const int ehdr_size = elfcpp::Elf_sizes<size>::ehdr_size;
+ static const int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
+ static const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+ typedef elfcpp::Shdr<size, big_endian> Shdr;
+
+ // Find the SHT_SYMTAB section, given the section headers.
+ void
+ find_symtab(const unsigned char* pshdrs);
+
+ // Whether to include a section group in the link.
+ bool
+ include_section_group(Layout*, unsigned int,
+ const elfcpp::Shdr<size, big_endian>&,
+ std::vector<bool>*);
+
+ // Whether to include a linkonce section in the link.
+ bool
+ include_linkonce_section(Layout*, const char*,
+ const elfcpp::Shdr<size, big_endian>&);
+
+ // Views and sizes when relocating.
+ struct View_size
+ {
+ unsigned char* view;
+ typename elfcpp::Elf_types<size>::Elf_Addr address;
+ off_t offset;
+ off_t view_size;
+ };
+
+ typedef std::vector<View_size> Views;
+
+ // Write section data to the output file. Record the views and
+ // sizes in VIEWS for use when relocating.
+ void
+ write_sections(const unsigned char* pshdrs, Output_file*, Views*);
+
+ // Relocate the sections in the output file.
+ void
+ relocate_sections(const General_options& options, const Symbol_table*,
+ const Layout*, const unsigned char* pshdrs, Views*);
+
+ // Write out the local symbols.
+ void
+ write_local_symbols(Output_file*,
+ const Stringpool_template<char>*);
+
+ // General access to the ELF file.
+ elfcpp::Elf_file<size, big_endian, Object> elf_file_;
+ // Index of SHT_SYMTAB section.
+ unsigned int symtab_shndx_;
+ // The number of local symbols.
+ unsigned int local_symbol_count_;
+ // The number of local symbols which go into the output file.
+ unsigned int output_local_symbol_count_;
+ // The entries in the symbol table for the external symbols.
+ Symbol** symbols_;
+ // File offset for local symbols.
+ off_t local_symbol_offset_;
+ // Values of local symbols.
+ Local_values local_values_;
+};
+
+// A class to manage the list of all objects.
+
+class Input_objects
+{
+ public:
+ Input_objects()
+ : relobj_list_(), dynobj_list_(), target_(NULL), sonames_()
+ { }
+
+ // The type of the list of input relocateable objects.
+ typedef std::vector<Relobj*> Relobj_list;
+ typedef Relobj_list::const_iterator Relobj_iterator;
+
+ // The type of the list of input dynamic objects.
+ typedef std::vector<Dynobj*> Dynobj_list;
+ typedef Dynobj_list::const_iterator Dynobj_iterator;
+
+ // Add an object to the list. Return true if all is well, or false
+ // if this object should be ignored.
+ bool
+ add_object(Object*);
+
+ // Get the target we should use for the output file.
+ Target*
+ target() const
+ { return this->target_; }
+
+ // Iterate over all regular objects.
+
+ Relobj_iterator
+ relobj_begin() const
+ { return this->relobj_list_.begin(); }
+
+ Relobj_iterator
+ relobj_end() const
+ { return this->relobj_list_.end(); }
+
+ // Iterate over all dynamic objects.
+
+ Dynobj_iterator
+ dynobj_begin() const
+ { return this->dynobj_list_.begin(); }
+
+ Dynobj_iterator
+ dynobj_end() const
+ { return this->dynobj_list_.end(); }
+
+ // Return whether we have seen any dynamic objects.
+ bool
+ any_dynamic() const
+ { return !this->dynobj_list_.empty(); }
+
+ private:
+ Input_objects(const Input_objects&);
+ Input_objects& operator=(const Input_objects&);
+
+ // The list of ordinary objects included in the link.
+ Relobj_list relobj_list_;
+ // The list of dynamic objects included in the link.
+ Dynobj_list dynobj_list_;
+ // The target.
+ Target* target_;
+ // SONAMEs that we have seen.
+ Unordered_set<std::string> sonames_;
+};
+
+// Some of the information we pass to the relocation routines. We
+// group this together to avoid passing a dozen different arguments.
+
+template<int size, bool big_endian>
+struct Relocate_info
+{
+ // Command line options.
+ const General_options* options;
+ // Symbol table.
+ const Symbol_table* symtab;
+ // Layout.
+ const Layout* layout;
+ // Object being relocated.
+ Sized_relobj<size, big_endian>* object;
+ // Number of local symbols.
+ unsigned int local_symbol_count;
+ // Values of local symbols.
+ const typename Sized_relobj<size, big_endian>::Local_values* local_values;
+ // Global symbols.
+ const Symbol* const * symbols;
+ // Section index of relocation section.
+ unsigned int reloc_shndx;
+ // Section index of section being relocated.
+ unsigned int data_shndx;
+
+ // Return a string showing the location of a relocation. This is
+ // only used for error messages.
+ std::string
+ location(size_t relnum, off_t reloffset) const;
+};
+
+// Return an Object appropriate for the input file. P is BYTES long,
+// and holds the ELF header.
+
+extern Object*
+make_elf_object(const std::string& name, Input_file*,
+ off_t offset, const unsigned char* p,
+ off_t bytes);
+
+} // end namespace gold
+
+#endif // !defined(GOLD_OBJECT_H)
diff --git a/gold/options.cc b/gold/options.cc
new file mode 100644
index 000000000000..b8339e8a6253
--- /dev/null
+++ b/gold/options.cc
@@ -0,0 +1,579 @@
+// options.c -- handle command line options for gold
+
+#include <iostream>
+
+#include "gold.h"
+#include "options.h"
+
+namespace gold
+{
+
+// The information we keep for a single command line option.
+
+struct options::One_option
+{
+ // The single character option name, or '\0' if this is only a long
+ // option.
+ char short_option;
+
+ // The long option name, or NULL if this is only a short option.
+ const char* long_option;
+
+ // Description of the option for --help output, or NULL if there is none.
+ const char* doc;
+
+ // How to print the option name in --help output, or NULL to use the
+ // default.
+ const char* help_output;
+
+ // Long option dash control. This is ignored if long_option is
+ // NULL.
+ enum
+ {
+ // Long option normally takes one dash; two dashes are also
+ // accepted.
+ ONE_DASH,
+ // Long option normally takes two dashes; one dash is also
+ // accepted.
+ TWO_DASHES,
+ // Long option always takes two dashes.
+ EXACTLY_TWO_DASHES
+ } dash;
+
+ // Function for special handling, or NULL. Returns the number of
+ // arguments to skip. This will normally be at least 1, but it may
+ // be 0 if this function changes *argv. ARG points to the location
+ // in *ARGV where the option starts, which may be helpful for a
+ // short option.
+ int (*special)(int argc, char** argv, char *arg, Command_line*);
+
+ // If this is a position independent option which does not take an
+ // argument, this is the member function to call to record it.
+ void (General_options::*general_noarg)();
+
+ // If this is a position independent function which takes an
+ // argument, this is the member function to call to record it.
+ void (General_options::*general_arg)(const char*);
+
+ // If this is a position dependent option which does not take an
+ // argument, this is the member function to call to record it.
+ void (Position_dependent_options::*dependent_noarg)();
+
+ // If this is a position dependent option which takes an argument,
+ // this is the member function to record it.
+ void (Position_dependent_options::*dependent_arg)(const char*);
+
+ // Return whether this option takes an argument.
+ bool
+ takes_argument() const
+ { return this->general_arg != NULL || this->dependent_arg != NULL; }
+};
+
+class options::Command_line_options
+{
+ public:
+ static const One_option options[];
+ static const int options_size;
+};
+
+} // End namespace gold.
+
+namespace
+{
+
+// Handle the special -l option, which adds an input file.
+
+int
+library(int argc, char** argv, char* arg, gold::Command_line* cmdline)
+{
+ return cmdline->process_l_option(argc, argv, arg);
+}
+
+// Handle the special --start-group option.
+
+int
+start_group(int, char**, char* arg, gold::Command_line* cmdline)
+{
+ cmdline->start_group(arg);
+ return 1;
+}
+
+// Handle the special --end-group option.
+
+int
+end_group(int, char**, char* arg, gold::Command_line* cmdline)
+{
+ cmdline->end_group(arg);
+ return 1;
+}
+
+// Report usage information for ld --help, and exit.
+
+int
+help(int, char**, char*, gold::Command_line*)
+{
+ printf(_("Usage: %s [options] file...\nOptions:\n"), gold::program_name);
+
+ const int options_size = gold::options::Command_line_options::options_size;
+ const gold::options::One_option* options =
+ gold::options::Command_line_options::options;
+ for (int i = 0; i < options_size; ++i)
+ {
+ if (options[i].doc == NULL)
+ continue;
+
+ printf(" ");
+ int len = 2;
+ bool comma = false;
+
+ int j = i;
+ do
+ {
+ if (options[j].help_output != NULL)
+ {
+ if (comma)
+ {
+ printf(", ");
+ len += 2;
+ }
+ printf(options[j].help_output);
+ len += std::strlen(options[i].help_output);
+ }
+ else
+ {
+ if (options[j].short_option != '\0')
+ {
+ if (comma)
+ {
+ printf(", ");
+ len += 2;
+ }
+ printf("-%c", options[j].short_option);
+ len += 2;
+ }
+
+ if (options[j].long_option != NULL)
+ {
+ if (comma)
+ {
+ printf(", ");
+ len += 2;
+ }
+ if (options[j].dash == gold::options::One_option::ONE_DASH)
+ {
+ printf("-");
+ ++len;
+ }
+ else
+ {
+ printf("--");
+ len += 2;
+ }
+ printf("%s", options[j].long_option);
+ len += std::strlen(options[j].long_option);
+ }
+ }
+ ++j;
+ }
+ while (j < options_size && options[j].doc == NULL);
+
+ if (len > 30)
+ {
+ printf("\n");
+ len = 0;
+ }
+ for (; len < 30; ++len)
+ std::putchar(' ');
+
+ std::puts(options[i].doc);
+ }
+
+ gold::gold_exit(true);
+
+ return 0;
+}
+
+} // End anonymous namespace.
+
+namespace gold
+{
+
+// Helper macros used to specify the options. We could also do this
+// using constructors, but then g++ would generate code to initialize
+// the array. We want the array to be initialized statically so that
+// we get better startup time.
+
+#define GENERAL_NOARG(short_option, long_option, doc, help, dash, func) \
+ { short_option, long_option, doc, help, options::One_option::dash, \
+ NULL, func, NULL, NULL, NULL }
+#define GENERAL_ARG(short_option, long_option, doc, help, dash, func) \
+ { short_option, long_option, doc, help, options::One_option::dash, \
+ NULL, NULL, func, NULL, NULL }
+#define POSDEP_NOARG(short_option, long_option, doc, help, dash, func) \
+ { short_option, long_option, doc, help, options::One_option::dash, \
+ NULL, NULL, NULL, func, NULL }
+#define POSDEP_ARG(short_option, long_option, doc, help, dash, func) \
+ { short_option, long_option, doc, help, options::One_option::dash, \
+ NULL, NULL, NULL, NULL, func }
+#define SPECIAL(short_option, long_option, doc, help, dash, func) \
+ { short_option, long_option, doc, help, options::One_option::dash, \
+ func, NULL, NULL, NULL, NULL }
+
+// Here is the actual list of options which we accept.
+
+const options::One_option
+options::Command_line_options::options[] =
+{
+ SPECIAL('l', "library", N_("Search for library LIBNAME"),
+ N_("-lLIBNAME --library LIBNAME"), TWO_DASHES,
+ &library),
+ SPECIAL('(', "start-group", N_("Start a library search group"), NULL,
+ TWO_DASHES, &start_group),
+ SPECIAL(')', "end-group", N_("End a library search group"), NULL,
+ TWO_DASHES, &end_group),
+ GENERAL_ARG('I', "dynamic-linker", N_("Set dynamic linker path"),
+ N_("-I PROGRAM, --dynamic-linker PROGRAM"), TWO_DASHES,
+ &General_options::set_dynamic_linker),
+ GENERAL_ARG('L', "library-path", N_("Add directory to search path"),
+ N_("-L DIR, --library-path DIR"), TWO_DASHES,
+ &General_options::add_to_search_path),
+ GENERAL_ARG('m', NULL, N_("Ignored for compatibility"), NULL, ONE_DASH,
+ &General_options::ignore),
+ GENERAL_ARG('o', "output", N_("Set output file name"),
+ N_("-o FILE, --output FILE"), TWO_DASHES,
+ &General_options::set_output_file_name),
+ GENERAL_NOARG('r', NULL, N_("Generate relocatable output"), NULL,
+ ONE_DASH, &General_options::set_relocatable),
+ GENERAL_NOARG('\0', "shared", N_("Generate shared library"),
+ NULL, ONE_DASH, &General_options::set_shared),
+ GENERAL_NOARG('\0', "static", N_("Do not link against shared libraries"),
+ NULL, ONE_DASH, &General_options::set_static),
+ POSDEP_NOARG('\0', "as-needed",
+ N_("Only set DT_NEEDED for following dynamic libs if used"),
+ NULL, TWO_DASHES, &Position_dependent_options::set_as_needed),
+ POSDEP_NOARG('\0', "no-as-needed",
+ N_("Always DT_NEEDED for following dynamic libs (default)"),
+ NULL, TWO_DASHES, &Position_dependent_options::clear_as_needed),
+ SPECIAL('\0', "help", N_("Report usage information"), NULL,
+ TWO_DASHES, &help)
+};
+
+const int options::Command_line_options::options_size =
+ sizeof (options) / sizeof (options[0]);
+
+// The default values for the general options.
+
+General_options::General_options()
+ : dynamic_linker_(NULL),
+ search_path_(),
+ output_file_name_("a.out"),
+ is_relocatable_(false),
+ is_shared_(false),
+ is_static_(false)
+{
+}
+
+// The default values for the position dependent options.
+
+Position_dependent_options::Position_dependent_options()
+ : do_static_search_(false)
+{
+}
+
+// Input_arguments methods.
+
+// Add a file to the list.
+
+void
+Input_arguments::add_file(const Input_file_argument& file)
+{
+ if (!this->in_group_)
+ this->input_argument_list_.push_back(Input_argument(file));
+ else
+ {
+ gold_assert(!this->input_argument_list_.empty());
+ gold_assert(this->input_argument_list_.back().is_group());
+ this->input_argument_list_.back().group()->add_file(file);
+ }
+}
+
+// Start a group.
+
+void
+Input_arguments::start_group()
+{
+ gold_assert(!this->in_group_);
+ Input_file_group* group = new Input_file_group();
+ this->input_argument_list_.push_back(Input_argument(group));
+ this->in_group_ = true;
+}
+
+// End a group.
+
+void
+Input_arguments::end_group()
+{
+ gold_assert(this->in_group_);
+ this->in_group_ = false;
+}
+
+// Command_line options.
+
+Command_line::Command_line()
+ : options_(), position_options_(), inputs_()
+{
+}
+
+// Process the command line options.
+
+void
+Command_line::process(int argc, char** argv)
+{
+ const int options_size = options::Command_line_options::options_size;
+ const options::One_option* options =
+ options::Command_line_options::options;
+ bool no_more_options = false;
+ int i = 0;
+ while (i < argc)
+ {
+ if (argv[i][0] != '-' || no_more_options)
+ {
+ this->add_file(argv[i], false);
+ ++i;
+ continue;
+ }
+
+ // Option starting with '-'.
+ int dashes = 1;
+ if (argv[i][1] == '-')
+ {
+ dashes = 2;
+ if (argv[i][2] == '\0')
+ {
+ no_more_options = true;
+ continue;
+ }
+ }
+
+ // Look for a long option match.
+ char* opt = argv[i] + dashes;
+ char first = opt[0];
+ int skiparg = 0;
+ char* arg = strchr(opt, '=');
+ if (arg != NULL)
+ *arg = '\0';
+ else if (i + 1 < argc)
+ {
+ arg = argv[i + 1];
+ skiparg = 1;
+ }
+
+ int j;
+ for (j = 0; j < options_size; ++j)
+ {
+ if (options[j].long_option != NULL
+ && (dashes == 2
+ || (options[j].dash
+ != options::One_option::EXACTLY_TWO_DASHES))
+ && first == options[j].long_option[0]
+ && strcmp(opt, options[j].long_option) == 0)
+ {
+ if (options[j].special)
+ i += options[j].special(argc - 1, argv + i, opt, this);
+ else
+ {
+ if (!options[j].takes_argument())
+ {
+ arg = NULL;
+ skiparg = 0;
+ }
+ else
+ {
+ if (arg == NULL)
+ this->usage(_("missing argument"), argv[i]);
+ }
+ this->apply_option(options[j], arg);
+ i += skiparg + 1;
+ }
+ break;
+ }
+ }
+ if (j < options_size)
+ continue;
+
+ // If we saw two dashes, we need to see a long option.
+ if (dashes == 2)
+ this->usage(_("unknown option"), argv[i]);
+
+ // Look for a short option match. There may be more than one
+ // short option in a given argument.
+ bool done = false;
+ char* s = argv[i] + 1;
+ ++i;
+ while (*s != '\0' && !done)
+ {
+ char opt = *s;
+ int j;
+ for (j = 0; j < options_size; ++j)
+ {
+ if (options[j].short_option == opt)
+ {
+ if (options[j].special)
+ {
+ // Undo the argument skip done above.
+ --i;
+ i += options[j].special(argc - i, argv + i, s, this);
+ done = true;
+ }
+ else
+ {
+ arg = NULL;
+ if (options[j].takes_argument())
+ {
+ if (s[1] != '\0')
+ {
+ arg = s + 1;
+ done = true;
+ }
+ else if (i < argc)
+ {
+ arg = argv[i];
+ ++i;
+ }
+ else
+ this->usage(_("missing argument"), opt);
+ }
+ this->apply_option(options[j], arg);
+ }
+ break;
+ }
+ }
+
+ if (j >= options_size)
+ this->usage(_("unknown option"), *s);
+
+ ++s;
+ }
+ }
+
+ if (this->inputs_.in_group())
+ {
+ fprintf(stderr, _("%s: missing group end"), program_name);
+ this->usage();
+ }
+
+ // FIXME: We should only do this when configured in native mode.
+ this->options_.add_to_search_path("/lib");
+ this->options_.add_to_search_path("/usr/lib");
+}
+
+// Apply a command line option.
+
+void
+Command_line::apply_option(const options::One_option& opt,
+ const char* arg)
+{
+ if (arg == NULL)
+ {
+ if (opt.general_noarg)
+ (this->options_.*(opt.general_noarg))();
+ else if (opt.dependent_noarg)
+ (this->position_options_.*(opt.dependent_noarg))();
+ else
+ gold_unreachable();
+ }
+ else
+ {
+ if (opt.general_arg)
+ (this->options_.*(opt.general_arg))(arg);
+ else if (opt.dependent_arg)
+ (this->position_options_.*(opt.dependent_arg))(arg);
+ else
+ gold_unreachable();
+ }
+}
+
+// Add an input file or library.
+
+void
+Command_line::add_file(const char* name, bool is_lib)
+{
+ Input_file_argument file(name, is_lib, this->position_options_);
+ this->inputs_.add_file(file);
+}
+
+// Handle the -l option, which requires special treatment.
+
+int
+Command_line::process_l_option(int argc, char** argv, char* arg)
+{
+ int ret;
+ const char* libname;
+ if (arg[1] != '\0')
+ {
+ ret = 1;
+ libname = arg + 1;
+ }
+ else if (argc > 1)
+ {
+ ret = 2;
+ libname = argv[argc + 1];
+ }
+ else
+ this->usage(_("missing argument"), arg);
+
+ this->add_file(libname, true);
+
+ return ret;
+}
+
+// Handle the --start-group option.
+
+void
+Command_line::start_group(const char* arg)
+{
+ if (this->inputs_.in_group())
+ this->usage(_("may not nest groups"), arg);
+ this->inputs_.start_group();
+}
+
+// Handle the --end-group option.
+
+void
+Command_line::end_group(const char* arg)
+{
+ if (!this->inputs_.in_group())
+ this->usage(_("group end without group start"), arg);
+ this->inputs_.end_group();
+}
+
+// Report a usage error. */
+
+void
+Command_line::usage()
+{
+ fprintf(stderr,
+ _("%s: use the --help option for usage information\n"),
+ program_name);
+ gold_exit(false);
+}
+
+void
+Command_line::usage(const char* msg, const char *opt)
+{
+ fprintf(stderr,
+ _("%s: %s: %s\n"),
+ program_name, opt, msg);
+ this->usage();
+}
+
+void
+Command_line::usage(const char* msg, char opt)
+{
+ fprintf(stderr,
+ _("%s: -%c: %s\n"),
+ program_name, opt, msg);
+ this->usage();
+}
+
+} // End namespace gold.
diff --git a/gold/options.h b/gold/options.h
new file mode 100644
index 000000000000..56907c058ead
--- /dev/null
+++ b/gold/options.h
@@ -0,0 +1,394 @@
+// options.h -- handle command line options for gold -*- C++ -*-
+
+// Command_line
+// Holds everything we get from the command line.
+// General_options (from Command_line::options())
+// Options which are not position dependent.
+// Input_argument (from Command_line::inputs())
+// The list of input files, including -l options.
+// Position_dependent_options (from Input_argument::options())
+// Position dependent options which apply to this argument.
+
+#ifndef GOLD_OPTIONS_H
+#define GOLD_OPTIONS_H
+
+#include <list>
+#include <string>
+#include <vector>
+
+namespace gold
+{
+
+class Command_line;
+class Input_file_group;
+
+namespace options {
+
+class Command_line_options;
+struct One_option;
+
+} // End namespace gold::options.
+
+// The position independent options which apply to the whole link.
+// There are a lot of them.
+
+class General_options
+{
+ public:
+ General_options();
+
+ // -I: dynamic linker name.
+ const char*
+ dynamic_linker() const
+ { return this->dynamic_linker_; }
+
+ // -L: Library search path.
+ typedef std::list<const char*> Dir_list;
+
+ const Dir_list&
+ search_path() const
+ { return this->search_path_; }
+
+ // -o: Output file name.
+ const char*
+ output_file_name() const
+ { return this->output_file_name_; }
+
+ // -r: Whether we are doing a relocatable link.
+ bool
+ is_relocatable() const
+ { return this->is_relocatable_; }
+
+ // --shared: Whether generating a shared object.
+ bool
+ is_shared() const
+ { return this->is_shared_; }
+
+ // --static: Whether doing a static link.
+ bool
+ is_static() const
+ { return this->is_static_; }
+
+ private:
+ // Don't copy this structure.
+ General_options(const General_options&);
+ General_options& operator=(const General_options&);
+
+ friend class Command_line;
+ friend class options::Command_line_options;
+
+ void
+ set_dynamic_linker(const char* arg)
+ { this->dynamic_linker_ = arg; }
+
+ void
+ add_to_search_path(const char* arg)
+ { this->search_path_.push_back(arg); }
+
+ void
+ set_output_file_name(const char* arg)
+ { this->output_file_name_ = arg; }
+
+ void
+ set_relocatable()
+ { this->is_relocatable_ = true; }
+
+ void
+ set_shared()
+ { this->is_shared_ = true; }
+
+ void
+ set_static()
+ { this->is_static_ = true; }
+
+ void
+ ignore(const char*)
+ { }
+
+ const char* dynamic_linker_;
+ Dir_list search_path_;
+ const char* output_file_name_;
+ bool is_relocatable_;
+ bool is_shared_;
+ bool is_static_;
+};
+
+// The current state of the position dependent options.
+
+class Position_dependent_options
+{
+ public:
+ Position_dependent_options();
+
+ // -Bstatic: Whether we are searching for a static archive rather
+ // than a shared object.
+ bool
+ do_static_search() const
+ { return this->do_static_search_; }
+
+ // --as-needed: Whether to add a DT_NEEDED argument only if the
+ // dynamic object is used.
+ bool
+ as_needed() const
+ { return this->as_needed_; }
+
+ void
+ set_static_search()
+ { this->do_static_search_ = true; }
+
+ void
+ set_dynamic_search()
+ { this->do_static_search_ = false; }
+
+ void
+ set_as_needed()
+ { this->as_needed_ = true; }
+
+ void
+ clear_as_needed()
+ { this->as_needed_ = false; }
+
+ private:
+ bool do_static_search_;
+ bool as_needed_;
+};
+
+// A single file or library argument from the command line.
+
+class Input_file_argument
+{
+ public:
+ Input_file_argument()
+ : name_(), is_lib_(false), options_()
+ { }
+
+ Input_file_argument(const char* name, bool is_lib,
+ const Position_dependent_options& options)
+ : name_(name), is_lib_(is_lib), options_(options)
+ { }
+
+ const char*
+ name() const
+ { return this->name_.c_str(); }
+
+ const Position_dependent_options&
+ options() const
+ { return this->options_; }
+
+ bool
+ is_lib() const
+ { return this->is_lib_; }
+
+ private:
+ // We use std::string, not const char*, here for convenience when
+ // using script files, so that we do not have to preserve the string
+ // in that case.
+ std::string name_;
+ bool is_lib_;
+ Position_dependent_options options_;
+};
+
+// A file or library, or a group, from the command line.
+
+class Input_argument
+{
+ public:
+ // Create a file or library argument.
+ explicit Input_argument(Input_file_argument file)
+ : is_file_(true), file_(file), group_(NULL)
+ { }
+
+ // Create a group argument.
+ explicit Input_argument(Input_file_group* group)
+ : is_file_(false), group_(group)
+ { }
+
+ // Return whether this is a file.
+ bool
+ is_file() const
+ { return this->is_file_; }
+
+ // Return whether this is a group.
+ bool
+ is_group() const
+ { return !this->is_file_; }
+
+ // Return the information about the file.
+ const Input_file_argument&
+ file() const
+ {
+ gold_assert(this->is_file_);
+ return this->file_;
+ }
+
+ // Return the information about the group.
+ const Input_file_group*
+ group() const
+ {
+ gold_assert(!this->is_file_);
+ return this->group_;
+ }
+
+ Input_file_group*
+ group()
+ {
+ gold_assert(!this->is_file_);
+ return this->group_;
+ }
+
+ private:
+ bool is_file_;
+ Input_file_argument file_;
+ Input_file_group* group_;
+};
+
+// A group from the command line. This is a set of arguments within
+// --start-group ... --end-group.
+
+class Input_file_group
+{
+ public:
+ typedef std::vector<Input_argument> Files;
+ typedef Files::const_iterator const_iterator;
+
+ Input_file_group()
+ : files_()
+ { }
+
+ // Add a file to the end of the group.
+ void
+ add_file(const Input_file_argument& arg)
+ { this->files_.push_back(Input_argument(arg)); }
+
+ // Iterators to iterate over the group contents.
+
+ const_iterator
+ begin() const
+ { return this->files_.begin(); }
+
+ const_iterator
+ end() const
+ { return this->files_.end(); }
+
+ private:
+ Files files_;
+};
+
+// A list of files from the command line or a script.
+
+class Input_arguments
+{
+ public:
+ typedef std::vector<Input_argument> Input_argument_list;
+ typedef Input_argument_list::const_iterator const_iterator;
+
+ Input_arguments()
+ : input_argument_list_(), in_group_(false)
+ { }
+
+ // Add a file.
+ void
+ add_file(const Input_file_argument& arg);
+
+ // Start a group (the --start-group option).
+ void
+ start_group();
+
+ // End a group (the --end-group option).
+ void
+ end_group();
+
+ // Return whether we are currently in a group.
+ bool
+ in_group() const
+ { return this->in_group_; }
+
+ // Iterators to iterate over the list of input files.
+
+ const_iterator
+ begin() const
+ { return this->input_argument_list_.begin(); }
+
+ const_iterator
+ end() const
+ { return this->input_argument_list_.end(); }
+
+ // Return whether the list is empty.
+ bool
+ empty() const
+ { return this->input_argument_list_.empty(); }
+
+ private:
+ Input_argument_list input_argument_list_;
+ bool in_group_;
+};
+
+// All the information read from the command line.
+
+class Command_line
+{
+ public:
+ typedef Input_arguments::const_iterator const_iterator;
+
+ Command_line();
+
+ // Process the command line options. This will exit with an
+ // appropriate error message if an unrecognized option is seen.
+ void
+ process(int argc, char** argv);
+
+ // Handle a -l option.
+ int
+ process_l_option(int, char**, char*);
+
+ // Handle a --start-group option.
+ void
+ start_group(const char* arg);
+
+ // Handle a --end-group option.
+ void
+ end_group(const char* arg);
+
+ // Get the general options.
+ const General_options&
+ options() const
+ { return this->options_; }
+
+ // Iterators to iterate over the list of input files.
+
+ const_iterator
+ begin() const
+ { return this->inputs_.begin(); }
+
+ const_iterator
+ end() const
+ { return this->inputs_.end(); }
+
+ private:
+ Command_line(const Command_line&);
+ Command_line& operator=(const Command_line&);
+
+ // Report usage error.
+ void
+ usage() ATTRIBUTE_NORETURN;
+ void
+ usage(const char* msg, const char* opt) ATTRIBUTE_NORETURN;
+ void
+ usage(const char* msg, char opt) ATTRIBUTE_NORETURN;
+
+ // Apply a command line option.
+ void
+ apply_option(const gold::options::One_option&, const char*);
+
+ // Add a file.
+ void
+ add_file(const char* name, bool is_lib);
+
+ General_options options_;
+ Position_dependent_options position_options_;
+ Input_arguments inputs_;
+};
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_OPTIONS_H)
diff --git a/gold/output.cc b/gold/output.cc
new file mode 100644
index 000000000000..2a7400def77c
--- /dev/null
+++ b/gold/output.cc
@@ -0,0 +1,1670 @@
+// output.cc -- manage the output file for gold
+
+#include "gold.h"
+
+#include <cstdlib>
+#include <cerrno>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <algorithm>
+
+#include "object.h"
+#include "symtab.h"
+#include "reloc.h"
+#include "merge.h"
+#include "output.h"
+
+namespace gold
+{
+
+// Output_data variables.
+
+bool Output_data::sizes_are_fixed;
+
+// Output_data methods.
+
+Output_data::~Output_data()
+{
+}
+
+// Set the address and offset.
+
+void
+Output_data::set_address(uint64_t addr, off_t off)
+{
+ this->address_ = addr;
+ this->offset_ = off;
+
+ // Let the child class know.
+ this->do_set_address(addr, off);
+}
+
+// Return the default alignment for a size--32 or 64.
+
+uint64_t
+Output_data::default_alignment(int size)
+{
+ if (size == 32)
+ return 4;
+ else if (size == 64)
+ return 8;
+ else
+ gold_unreachable();
+}
+
+// Output_section_header methods. This currently assumes that the
+// segment and section lists are complete at construction time.
+
+Output_section_headers::Output_section_headers(
+ int size,
+ bool big_endian,
+ const Layout* layout,
+ const Layout::Segment_list* segment_list,
+ const Layout::Section_list* unattached_section_list,
+ const Stringpool* secnamepool)
+ : size_(size),
+ big_endian_(big_endian),
+ layout_(layout),
+ segment_list_(segment_list),
+ unattached_section_list_(unattached_section_list),
+ secnamepool_(secnamepool)
+{
+ // Count all the sections. Start with 1 for the null section.
+ off_t count = 1;
+ for (Layout::Segment_list::const_iterator p = segment_list->begin();
+ p != segment_list->end();
+ ++p)
+ if ((*p)->type() == elfcpp::PT_LOAD)
+ count += (*p)->output_section_count();
+ count += unattached_section_list->size();
+
+ int shdr_size;
+ if (size == 32)
+ shdr_size = elfcpp::Elf_sizes<32>::shdr_size;
+ else if (size == 64)
+ shdr_size = elfcpp::Elf_sizes<64>::shdr_size;
+ else
+ gold_unreachable();
+
+ this->set_data_size(count * shdr_size);
+}
+
+// Write out the section headers.
+
+void
+Output_section_headers::do_write(Output_file* of)
+{
+ if (this->size_ == 32)
+ {
+ if (this->big_endian_)
+ this->do_sized_write<32, true>(of);
+ else
+ this->do_sized_write<32, false>(of);
+ }
+ else if (this->size_ == 64)
+ {
+ if (this->big_endian_)
+ this->do_sized_write<64, true>(of);
+ else
+ this->do_sized_write<64, false>(of);
+ }
+ else
+ gold_unreachable();
+}
+
+template<int size, bool big_endian>
+void
+Output_section_headers::do_sized_write(Output_file* of)
+{
+ off_t all_shdrs_size = this->data_size();
+ unsigned char* view = of->get_output_view(this->offset(), all_shdrs_size);
+
+ const int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
+ unsigned char* v = view;
+
+ {
+ typename elfcpp::Shdr_write<size, big_endian> oshdr(v);
+ oshdr.put_sh_name(0);
+ oshdr.put_sh_type(elfcpp::SHT_NULL);
+ oshdr.put_sh_flags(0);
+ oshdr.put_sh_addr(0);
+ oshdr.put_sh_offset(0);
+ oshdr.put_sh_size(0);
+ oshdr.put_sh_link(0);
+ oshdr.put_sh_info(0);
+ oshdr.put_sh_addralign(0);
+ oshdr.put_sh_entsize(0);
+ }
+
+ v += shdr_size;
+
+ unsigned shndx = 1;
+ for (Layout::Segment_list::const_iterator p = this->segment_list_->begin();
+ p != this->segment_list_->end();
+ ++p)
+ v = (*p)->write_section_headers SELECT_SIZE_ENDIAN_NAME(size, big_endian) (
+ this->layout_, this->secnamepool_, v, &shndx
+ SELECT_SIZE_ENDIAN(size, big_endian));
+ for (Layout::Section_list::const_iterator p =
+ this->unattached_section_list_->begin();
+ p != this->unattached_section_list_->end();
+ ++p)
+ {
+ gold_assert(shndx == (*p)->out_shndx());
+ elfcpp::Shdr_write<size, big_endian> oshdr(v);
+ (*p)->write_header(this->layout_, this->secnamepool_, &oshdr);
+ v += shdr_size;
+ ++shndx;
+ }
+
+ of->write_output_view(this->offset(), all_shdrs_size, view);
+}
+
+// Output_segment_header methods.
+
+Output_segment_headers::Output_segment_headers(
+ int size,
+ bool big_endian,
+ const Layout::Segment_list& segment_list)
+ : size_(size), big_endian_(big_endian), segment_list_(segment_list)
+{
+ int phdr_size;
+ if (size == 32)
+ phdr_size = elfcpp::Elf_sizes<32>::phdr_size;
+ else if (size == 64)
+ phdr_size = elfcpp::Elf_sizes<64>::phdr_size;
+ else
+ gold_unreachable();
+
+ this->set_data_size(segment_list.size() * phdr_size);
+}
+
+void
+Output_segment_headers::do_write(Output_file* of)
+{
+ if (this->size_ == 32)
+ {
+ if (this->big_endian_)
+ this->do_sized_write<32, true>(of);
+ else
+ this->do_sized_write<32, false>(of);
+ }
+ else if (this->size_ == 64)
+ {
+ if (this->big_endian_)
+ this->do_sized_write<64, true>(of);
+ else
+ this->do_sized_write<64, false>(of);
+ }
+ else
+ gold_unreachable();
+}
+
+template<int size, bool big_endian>
+void
+Output_segment_headers::do_sized_write(Output_file* of)
+{
+ const int phdr_size = elfcpp::Elf_sizes<size>::phdr_size;
+ off_t all_phdrs_size = this->segment_list_.size() * phdr_size;
+ unsigned char* view = of->get_output_view(this->offset(),
+ all_phdrs_size);
+ unsigned char* v = view;
+ for (Layout::Segment_list::const_iterator p = this->segment_list_.begin();
+ p != this->segment_list_.end();
+ ++p)
+ {
+ elfcpp::Phdr_write<size, big_endian> ophdr(v);
+ (*p)->write_header(&ophdr);
+ v += phdr_size;
+ }
+
+ of->write_output_view(this->offset(), all_phdrs_size, view);
+}
+
+// Output_file_header methods.
+
+Output_file_header::Output_file_header(int size,
+ bool big_endian,
+ const General_options& options,
+ const Target* target,
+ const Symbol_table* symtab,
+ const Output_segment_headers* osh)
+ : size_(size),
+ big_endian_(big_endian),
+ options_(options),
+ target_(target),
+ symtab_(symtab),
+ segment_header_(osh),
+ section_header_(NULL),
+ shstrtab_(NULL)
+{
+ int ehdr_size;
+ if (size == 32)
+ ehdr_size = elfcpp::Elf_sizes<32>::ehdr_size;
+ else if (size == 64)
+ ehdr_size = elfcpp::Elf_sizes<64>::ehdr_size;
+ else
+ gold_unreachable();
+
+ this->set_data_size(ehdr_size);
+}
+
+// Set the section table information for a file header.
+
+void
+Output_file_header::set_section_info(const Output_section_headers* shdrs,
+ const Output_section* shstrtab)
+{
+ this->section_header_ = shdrs;
+ this->shstrtab_ = shstrtab;
+}
+
+// Write out the file header.
+
+void
+Output_file_header::do_write(Output_file* of)
+{
+ if (this->size_ == 32)
+ {
+ if (this->big_endian_)
+ this->do_sized_write<32, true>(of);
+ else
+ this->do_sized_write<32, false>(of);
+ }
+ else if (this->size_ == 64)
+ {
+ if (this->big_endian_)
+ this->do_sized_write<64, true>(of);
+ else
+ this->do_sized_write<64, false>(of);
+ }
+ else
+ gold_unreachable();
+}
+
+// Write out the file header with appropriate size and endianess.
+
+template<int size, bool big_endian>
+void
+Output_file_header::do_sized_write(Output_file* of)
+{
+ gold_assert(this->offset() == 0);
+
+ int ehdr_size = elfcpp::Elf_sizes<size>::ehdr_size;
+ unsigned char* view = of->get_output_view(0, ehdr_size);
+ elfcpp::Ehdr_write<size, big_endian> oehdr(view);
+
+ unsigned char e_ident[elfcpp::EI_NIDENT];
+ memset(e_ident, 0, elfcpp::EI_NIDENT);
+ e_ident[elfcpp::EI_MAG0] = elfcpp::ELFMAG0;
+ e_ident[elfcpp::EI_MAG1] = elfcpp::ELFMAG1;
+ e_ident[elfcpp::EI_MAG2] = elfcpp::ELFMAG2;
+ e_ident[elfcpp::EI_MAG3] = elfcpp::ELFMAG3;
+ if (size == 32)
+ e_ident[elfcpp::EI_CLASS] = elfcpp::ELFCLASS32;
+ else if (size == 64)
+ e_ident[elfcpp::EI_CLASS] = elfcpp::ELFCLASS64;
+ else
+ gold_unreachable();
+ e_ident[elfcpp::EI_DATA] = (big_endian
+ ? elfcpp::ELFDATA2MSB
+ : elfcpp::ELFDATA2LSB);
+ e_ident[elfcpp::EI_VERSION] = elfcpp::EV_CURRENT;
+ // FIXME: Some targets may need to set EI_OSABI and EI_ABIVERSION.
+ oehdr.put_e_ident(e_ident);
+
+ elfcpp::ET e_type;
+ // FIXME: ET_DYN.
+ if (this->options_.is_relocatable())
+ e_type = elfcpp::ET_REL;
+ else
+ e_type = elfcpp::ET_EXEC;
+ oehdr.put_e_type(e_type);
+
+ oehdr.put_e_machine(this->target_->machine_code());
+ oehdr.put_e_version(elfcpp::EV_CURRENT);
+
+ // FIXME: Need to support -e, and target specific entry symbol.
+ Symbol* sym = this->symtab_->lookup("_start");
+ typename Sized_symbol<size>::Value_type v;
+ if (sym == NULL)
+ v = 0;
+ else
+ {
+ Sized_symbol<size>* ssym;
+ ssym = this->symtab_->get_sized_symbol SELECT_SIZE_NAME(size) (
+ sym SELECT_SIZE(size));
+ v = ssym->value();
+ }
+ oehdr.put_e_entry(v);
+
+ oehdr.put_e_phoff(this->segment_header_->offset());
+ oehdr.put_e_shoff(this->section_header_->offset());
+
+ // FIXME: The target needs to set the flags.
+ oehdr.put_e_flags(0);
+
+ oehdr.put_e_ehsize(elfcpp::Elf_sizes<size>::ehdr_size);
+ oehdr.put_e_phentsize(elfcpp::Elf_sizes<size>::phdr_size);
+ oehdr.put_e_phnum(this->segment_header_->data_size()
+ / elfcpp::Elf_sizes<size>::phdr_size);
+ oehdr.put_e_shentsize(elfcpp::Elf_sizes<size>::shdr_size);
+ oehdr.put_e_shnum(this->section_header_->data_size()
+ / elfcpp::Elf_sizes<size>::shdr_size);
+ oehdr.put_e_shstrndx(this->shstrtab_->out_shndx());
+
+ of->write_output_view(0, ehdr_size, view);
+}
+
+// Output_data_const methods.
+
+void
+Output_data_const::do_write(Output_file* of)
+{
+ of->write(this->offset(), this->data_.data(), this->data_.size());
+}
+
+// Output_data_const_buffer methods.
+
+void
+Output_data_const_buffer::do_write(Output_file* of)
+{
+ of->write(this->offset(), this->p_, this->data_size());
+}
+
+// Output_section_data methods.
+
+// Record the output section, and set the entry size and such.
+
+void
+Output_section_data::set_output_section(Output_section* os)
+{
+ gold_assert(this->output_section_ == NULL);
+ this->output_section_ = os;
+ this->do_adjust_output_section(os);
+}
+
+// Return the section index of the output section.
+
+unsigned int
+Output_section_data::do_out_shndx() const
+{
+ gold_assert(this->output_section_ != NULL);
+ return this->output_section_->out_shndx();
+}
+
+// Output_data_strtab methods.
+
+// Set the address. We don't actually care about the address, but we
+// do set our final size.
+
+void
+Output_data_strtab::do_set_address(uint64_t, off_t)
+{
+ this->strtab_->set_string_offsets();
+ this->set_data_size(this->strtab_->get_strtab_size());
+}
+
+// Write out a string table.
+
+void
+Output_data_strtab::do_write(Output_file* of)
+{
+ this->strtab_->write(of, this->offset());
+}
+
+// Output_reloc methods.
+
+// Get the symbol index of a relocation.
+
+template<bool dynamic, int size, bool big_endian>
+unsigned int
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::get_symbol_index()
+ const
+{
+ unsigned int index;
+ switch (this->local_sym_index_)
+ {
+ case INVALID_CODE:
+ gold_unreachable();
+
+ case GSYM_CODE:
+ if (this->u1_.gsym == NULL)
+ index = 0;
+ else if (dynamic)
+ index = this->u1_.gsym->dynsym_index();
+ else
+ index = this->u1_.gsym->symtab_index();
+ break;
+
+ case SECTION_CODE:
+ if (dynamic)
+ index = this->u1_.os->dynsym_index();
+ else
+ index = this->u1_.os->symtab_index();
+ break;
+
+ default:
+ if (dynamic)
+ {
+ // FIXME: It seems that some targets may need to generate
+ // dynamic relocations against local symbols for some
+ // reasons. This will have to be addressed at some point.
+ gold_unreachable();
+ }
+ else
+ index = this->u1_.relobj->symtab_index(this->local_sym_index_);
+ break;
+ }
+ gold_assert(index != -1U);
+ return index;
+}
+
+// Write out the offset and info fields of a Rel or Rela relocation
+// entry.
+
+template<bool dynamic, int size, bool big_endian>
+template<typename Write_rel>
+void
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::write_rel(
+ Write_rel* wr) const
+{
+ Address address = this->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<size>(this->get_symbol_index(),
+ this->type_));
+}
+
+// Write out a Rel relocation.
+
+template<bool dynamic, int size, bool big_endian>
+void
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::write(
+ unsigned char* pov) const
+{
+ elfcpp::Rel_write<size, big_endian> orel(pov);
+ this->write_rel(&orel);
+}
+
+// Write out a Rela relocation.
+
+template<bool dynamic, int size, bool big_endian>
+void
+Output_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>::write(
+ unsigned char* pov) const
+{
+ elfcpp::Rela_write<size, big_endian> orel(pov);
+ this->rel_.write_rel(&orel);
+ orel.put_r_addend(this->addend_);
+}
+
+// Output_data_reloc_base methods.
+
+// Adjust the output section.
+
+template<int sh_type, bool dynamic, int size, bool big_endian>
+void
+Output_data_reloc_base<sh_type, dynamic, size, big_endian>
+ ::do_adjust_output_section(Output_section* os)
+{
+ if (sh_type == elfcpp::SHT_REL)
+ os->set_entsize(elfcpp::Elf_sizes<size>::rel_size);
+ else if (sh_type == elfcpp::SHT_RELA)
+ os->set_entsize(elfcpp::Elf_sizes<size>::rela_size);
+ else
+ gold_unreachable();
+ if (dynamic)
+ os->set_should_link_to_dynsym();
+ else
+ os->set_should_link_to_symtab();
+}
+
+// Write out relocation data.
+
+template<int sh_type, bool dynamic, int size, bool big_endian>
+void
+Output_data_reloc_base<sh_type, dynamic, size, big_endian>::do_write(
+ Output_file* of)
+{
+ const off_t off = this->offset();
+ const off_t oview_size = this->data_size();
+ unsigned char* const oview = of->get_output_view(off, oview_size);
+
+ unsigned char* pov = oview;
+ for (typename Relocs::const_iterator p = this->relocs_.begin();
+ p != this->relocs_.end();
+ ++p)
+ {
+ p->write(pov);
+ pov += reloc_size;
+ }
+
+ gold_assert(pov - oview == oview_size);
+
+ of->write_output_view(off, oview_size, oview);
+
+ // We no longer need the relocation entries.
+ this->relocs_.clear();
+}
+
+// Output_data_got::Got_entry methods.
+
+// Write out the entry.
+
+template<int size, bool big_endian>
+void
+Output_data_got<size, big_endian>::Got_entry::write(
+ const General_options* options,
+ unsigned char* pov) const
+{
+ Valtype val = 0;
+
+ switch (this->local_sym_index_)
+ {
+ case GSYM_CODE:
+ {
+ Symbol* gsym = this->u_.gsym;
+
+ // If the symbol is resolved locally, we need to write out its
+ // value. Otherwise we just write zero. The target code is
+ // responsible for creating a relocation entry to fill in the
+ // value at runtime.
+ if (gsym->final_value_is_known(options))
+ {
+ Sized_symbol<size>* sgsym;
+ // This cast is a bit ugly. We don't want to put a
+ // virtual method in Symbol, because we want Symbol to be
+ // as small as possible.
+ sgsym = static_cast<Sized_symbol<size>*>(gsym);
+ val = sgsym->value();
+ }
+ }
+ break;
+
+ case CONSTANT_CODE:
+ val = this->u_.constant;
+ break;
+
+ default:
+ gold_unreachable();
+ }
+
+ elfcpp::Swap<size, big_endian>::writeval(pov, val);
+}
+
+// Output_data_got methods.
+
+// Add an entry for a global symbol to the GOT. This returns true if
+// this is a new GOT entry, false if the symbol already had a GOT
+// entry.
+
+template<int size, bool big_endian>
+bool
+Output_data_got<size, big_endian>::add_global(Symbol* gsym)
+{
+ if (gsym->has_got_offset())
+ return false;
+
+ this->entries_.push_back(Got_entry(gsym));
+ this->set_got_size();
+ gsym->set_got_offset(this->last_got_offset());
+ return true;
+}
+
+// Write out the GOT.
+
+template<int size, bool big_endian>
+void
+Output_data_got<size, big_endian>::do_write(Output_file* of)
+{
+ const int add = size / 8;
+
+ const off_t off = this->offset();
+ const off_t oview_size = this->data_size();
+ unsigned char* const oview = of->get_output_view(off, oview_size);
+
+ unsigned char* pov = oview;
+ for (typename Got_entries::const_iterator p = this->entries_.begin();
+ p != this->entries_.end();
+ ++p)
+ {
+ p->write(this->options_, pov);
+ pov += add;
+ }
+
+ gold_assert(pov - oview == oview_size);
+
+ of->write_output_view(off, oview_size, oview);
+
+ // We no longer need the GOT entries.
+ this->entries_.clear();
+}
+
+// Output_data_dynamic::Dynamic_entry methods.
+
+// Write out the entry.
+
+template<int size, bool big_endian>
+void
+Output_data_dynamic::Dynamic_entry::write(
+ unsigned char* pov,
+ const Stringpool* pool
+ ACCEPT_SIZE_ENDIAN) const
+{
+ typename elfcpp::Elf_types<size>::Elf_WXword val;
+ switch (this->classification_)
+ {
+ case DYNAMIC_NUMBER:
+ val = this->u_.val;
+ break;
+
+ case DYNAMIC_SECTION_ADDRESS:
+ val = this->u_.od->address();
+ break;
+
+ case DYNAMIC_SECTION_SIZE:
+ val = this->u_.od->data_size();
+ break;
+
+ case DYNAMIC_SYMBOL:
+ {
+ const Sized_symbol<size>* s =
+ static_cast<const Sized_symbol<size>*>(this->u_.sym);
+ val = s->value();
+ }
+ break;
+
+ case DYNAMIC_STRING:
+ val = pool->get_offset(this->u_.str);
+ break;
+
+ default:
+ gold_unreachable();
+ }
+
+ elfcpp::Dyn_write<size, big_endian> dw(pov);
+ dw.put_d_tag(this->tag_);
+ dw.put_d_val(val);
+}
+
+// Output_data_dynamic methods.
+
+// Adjust the output section to set the entry size.
+
+void
+Output_data_dynamic::do_adjust_output_section(Output_section* os)
+{
+ if (this->target_->get_size() == 32)
+ os->set_entsize(elfcpp::Elf_sizes<32>::dyn_size);
+ else if (this->target_->get_size() == 64)
+ os->set_entsize(elfcpp::Elf_sizes<64>::dyn_size);
+ else
+ gold_unreachable();
+}
+
+// Set the final data size.
+
+void
+Output_data_dynamic::do_set_address(uint64_t, off_t)
+{
+ // Add the terminating entry.
+ this->add_constant(elfcpp::DT_NULL, 0);
+
+ int dyn_size;
+ if (this->target_->get_size() == 32)
+ dyn_size = elfcpp::Elf_sizes<32>::dyn_size;
+ else if (this->target_->get_size() == 64)
+ dyn_size = elfcpp::Elf_sizes<64>::dyn_size;
+ else
+ gold_unreachable();
+ this->set_data_size(this->entries_.size() * dyn_size);
+}
+
+// Write out the dynamic entries.
+
+void
+Output_data_dynamic::do_write(Output_file* of)
+{
+ if (this->target_->get_size() == 32)
+ {
+ if (this->target_->is_big_endian())
+ this->sized_write<32, true>(of);
+ else
+ this->sized_write<32, false>(of);
+ }
+ else if (this->target_->get_size() == 64)
+ {
+ if (this->target_->is_big_endian())
+ this->sized_write<64, true>(of);
+ else
+ this->sized_write<64, false>(of);
+ }
+ else
+ gold_unreachable();
+}
+
+template<int size, bool big_endian>
+void
+Output_data_dynamic::sized_write(Output_file* of)
+{
+ const int dyn_size = elfcpp::Elf_sizes<size>::dyn_size;
+
+ const off_t offset = this->offset();
+ const off_t oview_size = this->data_size();
+ unsigned char* const oview = of->get_output_view(offset, oview_size);
+
+ unsigned char* pov = oview;
+ for (typename Dynamic_entries::const_iterator p = this->entries_.begin();
+ p != this->entries_.end();
+ ++p)
+ {
+ p->write SELECT_SIZE_ENDIAN_NAME(size, big_endian)(
+ pov, this->pool_ SELECT_SIZE_ENDIAN(size, big_endian));
+ pov += dyn_size;
+ }
+
+ gold_assert(pov - oview == oview_size);
+
+ of->write_output_view(offset, oview_size, oview);
+
+ // We no longer need the dynamic entries.
+ this->entries_.clear();
+}
+
+// Output_section::Input_section methods.
+
+// Return the data size. For an input section we store the size here.
+// For an Output_section_data, we have to ask it for the size.
+
+off_t
+Output_section::Input_section::data_size() const
+{
+ if (this->is_input_section())
+ return this->u1_.data_size;
+ else
+ return this->u2_.posd->data_size();
+}
+
+// Set the address and file offset.
+
+void
+Output_section::Input_section::set_address(uint64_t addr, off_t off,
+ off_t secoff)
+{
+ if (this->is_input_section())
+ this->u2_.object->set_section_offset(this->shndx_, off - secoff);
+ else
+ this->u2_.posd->set_address(addr, off);
+}
+
+// Try to turn an input address into an output address.
+
+bool
+Output_section::Input_section::output_address(const Relobj* object,
+ unsigned int shndx,
+ off_t offset,
+ uint64_t output_section_address,
+ uint64_t *poutput) const
+{
+ if (!this->is_input_section())
+ return this->u2_.posd->output_address(object, shndx, offset,
+ output_section_address, poutput);
+ else
+ {
+ if (this->u2_.object != object)
+ return false;
+ off_t output_offset;
+ Output_section* os = object->output_section(shndx, &output_offset);
+ gold_assert(os != NULL);
+ *poutput = output_section_address + output_offset + offset;
+ return true;
+ }
+}
+
+// Write out the data. We don't have to do anything for an input
+// section--they are handled via Object::relocate--but this is where
+// we write out the data for an Output_section_data.
+
+void
+Output_section::Input_section::write(Output_file* of)
+{
+ if (!this->is_input_section())
+ this->u2_.posd->write(of);
+}
+
+// Output_section methods.
+
+// Construct an Output_section. NAME will point into a Stringpool.
+
+Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
+ elfcpp::Elf_Xword flags)
+ : name_(name),
+ addralign_(0),
+ entsize_(0),
+ link_section_(NULL),
+ link_(0),
+ info_section_(NULL),
+ info_(0),
+ type_(type),
+ flags_(flags),
+ out_shndx_(0),
+ symtab_index_(0),
+ dynsym_index_(0),
+ input_sections_(),
+ first_input_offset_(0),
+ needs_symtab_index_(false),
+ needs_dynsym_index_(false),
+ should_link_to_symtab_(false),
+ should_link_to_dynsym_(false)
+{
+}
+
+Output_section::~Output_section()
+{
+}
+
+// Set the entry size.
+
+void
+Output_section::set_entsize(uint64_t v)
+{
+ if (this->entsize_ == 0)
+ this->entsize_ = v;
+ else
+ gold_assert(this->entsize_ == v);
+}
+
+// Add the input section SHNDX, with header SHDR, named SECNAME, in
+// OBJECT, to the Output_section. Return the offset of the input
+// section within the output section. We don't always keep track of
+// input sections for an Output_section. Instead, each Object keeps
+// track of the Output_section for each of its input sections.
+
+template<int size, bool big_endian>
+off_t
+Output_section::add_input_section(Relobj* object, unsigned int shndx,
+ const char* secname,
+ const elfcpp::Shdr<size, big_endian>& shdr)
+{
+ elfcpp::Elf_Xword addralign = shdr.get_sh_addralign();
+ if ((addralign & (addralign - 1)) != 0)
+ {
+ fprintf(stderr, _("%s: %s: invalid alignment %lu for section \"%s\"\n"),
+ program_name, object->name().c_str(),
+ static_cast<unsigned long>(addralign), secname);
+ gold_exit(false);
+ }
+
+ if (addralign > this->addralign_)
+ this->addralign_ = addralign;
+
+ // If this is a SHF_MERGE section, we pass all the input sections to
+ // a Output_data_merge.
+ if ((shdr.get_sh_flags() & elfcpp::SHF_MERGE) != 0)
+ {
+ if (this->add_merge_input_section(object, shndx, shdr.get_sh_flags(),
+ shdr.get_sh_entsize(),
+ addralign))
+ {
+ // Tell the relocation routines that they need to call the
+ // output_address method to determine the final address.
+ return -1;
+ }
+ }
+
+ off_t ssize = this->data_size();
+ ssize = align_address(ssize, addralign);
+ this->set_data_size(ssize + shdr.get_sh_size());
+
+ // We need to keep track of this section if we are already keeping
+ // track of sections, or if we are relaxing. FIXME: Add test for
+ // relaxing.
+ if (! this->input_sections_.empty())
+ this->input_sections_.push_back(Input_section(object, shndx,
+ shdr.get_sh_size(),
+ addralign));
+
+ return ssize;
+}
+
+// Add arbitrary data to an output section.
+
+void
+Output_section::add_output_section_data(Output_section_data* posd)
+{
+ Input_section inp(posd);
+ this->add_output_section_data(&inp);
+}
+
+// Add arbitrary data to an output section by Input_section.
+
+void
+Output_section::add_output_section_data(Input_section* inp)
+{
+ if (this->input_sections_.empty())
+ this->first_input_offset_ = this->data_size();
+
+ this->input_sections_.push_back(*inp);
+
+ uint64_t addralign = inp->addralign();
+ if (addralign > this->addralign_)
+ this->addralign_ = addralign;
+
+ inp->set_output_section(this);
+}
+
+// Add a merge section to an output section.
+
+void
+Output_section::add_output_merge_section(Output_section_data* posd,
+ bool is_string, uint64_t entsize)
+{
+ Input_section inp(posd, is_string, entsize);
+ this->add_output_section_data(&inp);
+}
+
+// Add an input section to a SHF_MERGE section.
+
+bool
+Output_section::add_merge_input_section(Relobj* object, unsigned int shndx,
+ uint64_t flags, uint64_t entsize,
+ uint64_t addralign)
+{
+ // We only merge constants if the alignment is not more than the
+ // entry size. This could be handled, but it's unusual.
+ if (addralign > entsize)
+ return false;
+
+ bool is_string = (flags & elfcpp::SHF_STRINGS) != 0;
+ Input_section_list::iterator p;
+ for (p = this->input_sections_.begin();
+ p != this->input_sections_.end();
+ ++p)
+ if (p->is_merge_section(is_string, entsize))
+ break;
+
+ // We handle the actual constant merging in Output_merge_data or
+ // Output_merge_string_data.
+ if (p != this->input_sections_.end())
+ p->add_input_section(object, shndx);
+ else
+ {
+ Output_section_data* posd;
+ if (!is_string)
+ posd = new Output_merge_data(entsize);
+ else if (entsize == 1)
+ posd = new Output_merge_string<char>();
+ else if (entsize == 2)
+ posd = new Output_merge_string<uint16_t>();
+ else if (entsize == 4)
+ posd = new Output_merge_string<uint32_t>();
+ else
+ return false;
+
+ this->add_output_merge_section(posd, is_string, entsize);
+ posd->add_input_section(object, shndx);
+ }
+
+ return true;
+}
+
+// Return the output virtual address of OFFSET relative to the start
+// of input section SHNDX in object OBJECT.
+
+uint64_t
+Output_section::output_address(const Relobj* object, unsigned int shndx,
+ off_t offset) const
+{
+ uint64_t addr = this->address() + this->first_input_offset_;
+ for (Input_section_list::const_iterator p = this->input_sections_.begin();
+ p != this->input_sections_.end();
+ ++p)
+ {
+ addr = align_address(addr, p->addralign());
+ uint64_t output;
+ if (p->output_address(object, shndx, offset, addr, &output))
+ return output;
+ addr += p->data_size();
+ }
+
+ // If we get here, it means that we don't know the mapping for this
+ // input section. This might happen in principle if
+ // add_input_section were called before add_output_section_data.
+ // But it should never actually happen.
+
+ gold_unreachable();
+}
+
+// Set the address of an Output_section. This is where we handle
+// setting the addresses of any Output_section_data objects.
+
+void
+Output_section::do_set_address(uint64_t address, off_t startoff)
+{
+ if (this->input_sections_.empty())
+ return;
+
+ off_t off = startoff + this->first_input_offset_;
+ for (Input_section_list::iterator p = this->input_sections_.begin();
+ p != this->input_sections_.end();
+ ++p)
+ {
+ off = align_address(off, p->addralign());
+ p->set_address(address + (off - startoff), off, startoff);
+ off += p->data_size();
+ }
+
+ this->set_data_size(off - startoff);
+}
+
+// Write the section header to *OSHDR.
+
+template<int size, bool big_endian>
+void
+Output_section::write_header(const Layout* layout,
+ const Stringpool* secnamepool,
+ elfcpp::Shdr_write<size, big_endian>* oshdr) const
+{
+ oshdr->put_sh_name(secnamepool->get_offset(this->name_));
+ oshdr->put_sh_type(this->type_);
+ oshdr->put_sh_flags(this->flags_);
+ oshdr->put_sh_addr(this->address());
+ oshdr->put_sh_offset(this->offset());
+ oshdr->put_sh_size(this->data_size());
+ if (this->link_section_ != NULL)
+ oshdr->put_sh_link(this->link_section_->out_shndx());
+ else if (this->should_link_to_symtab_)
+ oshdr->put_sh_link(layout->symtab_section()->out_shndx());
+ else if (this->should_link_to_dynsym_)
+ oshdr->put_sh_link(layout->dynsym_section()->out_shndx());
+ else
+ oshdr->put_sh_link(this->link_);
+ if (this->info_section_ != NULL)
+ oshdr->put_sh_info(this->info_section_->out_shndx());
+ else
+ oshdr->put_sh_info(this->info_);
+ oshdr->put_sh_addralign(this->addralign_);
+ oshdr->put_sh_entsize(this->entsize_);
+}
+
+// Write out the data. For input sections the data is written out by
+// Object::relocate, but we have to handle Output_section_data objects
+// here.
+
+void
+Output_section::do_write(Output_file* of)
+{
+ for (Input_section_list::iterator p = this->input_sections_.begin();
+ p != this->input_sections_.end();
+ ++p)
+ p->write(of);
+}
+
+// Output segment methods.
+
+Output_segment::Output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags)
+ : output_data_(),
+ output_bss_(),
+ vaddr_(0),
+ paddr_(0),
+ memsz_(0),
+ align_(0),
+ offset_(0),
+ filesz_(0),
+ type_(type),
+ flags_(flags),
+ is_align_known_(false)
+{
+}
+
+// Add an Output_section to an Output_segment.
+
+void
+Output_segment::add_output_section(Output_section* os,
+ elfcpp::Elf_Word seg_flags,
+ bool front)
+{
+ gold_assert((os->flags() & elfcpp::SHF_ALLOC) != 0);
+ gold_assert(!this->is_align_known_);
+
+ // Update the segment flags.
+ this->flags_ |= seg_flags;
+
+ Output_segment::Output_data_list* pdl;
+ if (os->type() == elfcpp::SHT_NOBITS)
+ pdl = &this->output_bss_;
+ else
+ pdl = &this->output_data_;
+
+ // So that PT_NOTE segments will work correctly, we need to ensure
+ // that all SHT_NOTE sections are adjacent. This will normally
+ // happen automatically, because all the SHT_NOTE input sections
+ // will wind up in the same output section. However, it is possible
+ // for multiple SHT_NOTE input sections to have different section
+ // flags, and thus be in different output sections, but for the
+ // different section flags to map into the same segment flags and
+ // thus the same output segment.
+
+ // Note that while there may be many input sections in an output
+ // section, there are normally only a few output sections in an
+ // output segment. This loop is expected to be fast.
+
+ if (os->type() == elfcpp::SHT_NOTE && !pdl->empty())
+ {
+ Output_segment::Output_data_list::iterator p = pdl->end();
+ do
+ {
+ --p;
+ if ((*p)->is_section_type(elfcpp::SHT_NOTE))
+ {
+ // We don't worry about the FRONT parameter.
+ ++p;
+ pdl->insert(p, os);
+ return;
+ }
+ }
+ while (p != pdl->begin());
+ }
+
+ // Similarly, so that PT_TLS segments will work, we need to group
+ // SHF_TLS sections. An SHF_TLS/SHT_NOBITS section is a special
+ // case: we group the SHF_TLS/SHT_NOBITS sections right after the
+ // SHF_TLS/SHT_PROGBITS sections. This lets us set up PT_TLS
+ // correctly.
+ if ((os->flags() & elfcpp::SHF_TLS) != 0 && !this->output_data_.empty())
+ {
+ pdl = &this->output_data_;
+ bool nobits = os->type() == elfcpp::SHT_NOBITS;
+ bool sawtls = false;
+ Output_segment::Output_data_list::iterator p = pdl->end();
+ do
+ {
+ --p;
+ bool insert;
+ if ((*p)->is_section_flag_set(elfcpp::SHF_TLS))
+ {
+ sawtls = true;
+ // Put a NOBITS section after the first TLS section.
+ // But a PROGBITS section after the first TLS/PROGBITS
+ // section.
+ insert = nobits || !(*p)->is_section_type(elfcpp::SHT_NOBITS);
+ }
+ else
+ {
+ // If we've gone past the TLS sections, but we've seen a
+ // TLS section, then we need to insert this section now.
+ insert = sawtls;
+ }
+
+ if (insert)
+ {
+ // We don't worry about the FRONT parameter.
+ ++p;
+ pdl->insert(p, os);
+ return;
+ }
+ }
+ while (p != pdl->begin());
+
+ // There are no TLS sections yet; put this one at the requested
+ // location in the section list.
+ }
+
+ if (front)
+ pdl->push_front(os);
+ else
+ pdl->push_back(os);
+}
+
+// Add an Output_data (which is not an Output_section) to the start of
+// a segment.
+
+void
+Output_segment::add_initial_output_data(Output_data* od)
+{
+ gold_assert(!this->is_align_known_);
+ this->output_data_.push_front(od);
+}
+
+// Return the maximum alignment of the Output_data in Output_segment.
+// Once we compute this, we prohibit new sections from being added.
+
+uint64_t
+Output_segment::addralign()
+{
+ if (!this->is_align_known_)
+ {
+ uint64_t addralign;
+
+ addralign = Output_segment::maximum_alignment(&this->output_data_);
+ if (addralign > this->align_)
+ this->align_ = addralign;
+
+ addralign = Output_segment::maximum_alignment(&this->output_bss_);
+ if (addralign > this->align_)
+ this->align_ = addralign;
+
+ this->is_align_known_ = true;
+ }
+
+ return this->align_;
+}
+
+// Return the maximum alignment of a list of Output_data.
+
+uint64_t
+Output_segment::maximum_alignment(const Output_data_list* pdl)
+{
+ uint64_t ret = 0;
+ for (Output_data_list::const_iterator p = pdl->begin();
+ p != pdl->end();
+ ++p)
+ {
+ uint64_t addralign = (*p)->addralign();
+ if (addralign > ret)
+ ret = addralign;
+ }
+ return ret;
+}
+
+// Set the section addresses for an Output_segment. ADDR is the
+// address and *POFF is the file offset. Set the section indexes
+// starting with *PSHNDX. Return the address of the immediately
+// following segment. Update *POFF and *PSHNDX.
+
+uint64_t
+Output_segment::set_section_addresses(uint64_t addr, off_t* poff,
+ unsigned int* pshndx)
+{
+ gold_assert(this->type_ == elfcpp::PT_LOAD);
+
+ this->vaddr_ = addr;
+ this->paddr_ = addr;
+
+ off_t orig_off = *poff;
+ this->offset_ = orig_off;
+
+ *poff = align_address(*poff, this->addralign());
+
+ addr = this->set_section_list_addresses(&this->output_data_, addr, poff,
+ pshndx);
+ this->filesz_ = *poff - orig_off;
+
+ off_t off = *poff;
+
+ uint64_t ret = this->set_section_list_addresses(&this->output_bss_, addr,
+ poff, pshndx);
+ this->memsz_ = *poff - orig_off;
+
+ // Ignore the file offset adjustments made by the BSS Output_data
+ // objects.
+ *poff = off;
+
+ return ret;
+}
+
+// Set the addresses and file offsets in a list of Output_data
+// structures.
+
+uint64_t
+Output_segment::set_section_list_addresses(Output_data_list* pdl,
+ uint64_t addr, off_t* poff,
+ unsigned int* pshndx)
+{
+ off_t startoff = *poff;
+
+ off_t off = startoff;
+ for (Output_data_list::iterator p = pdl->begin();
+ p != pdl->end();
+ ++p)
+ {
+ off = align_address(off, (*p)->addralign());
+ (*p)->set_address(addr + (off - startoff), off);
+
+ // Unless this is a PT_TLS segment, we want to ignore the size
+ // of a SHF_TLS/SHT_NOBITS section. Such a section does not
+ // affect the size of a PT_LOAD segment.
+ if (this->type_ == elfcpp::PT_TLS
+ || !(*p)->is_section_flag_set(elfcpp::SHF_TLS)
+ || !(*p)->is_section_type(elfcpp::SHT_NOBITS))
+ off += (*p)->data_size();
+
+ if ((*p)->is_section())
+ {
+ (*p)->set_out_shndx(*pshndx);
+ ++*pshndx;
+ }
+ }
+
+ *poff = off;
+ return addr + (off - startoff);
+}
+
+// For a non-PT_LOAD segment, set the offset from the sections, if
+// any.
+
+void
+Output_segment::set_offset()
+{
+ gold_assert(this->type_ != elfcpp::PT_LOAD);
+
+ if (this->output_data_.empty() && this->output_bss_.empty())
+ {
+ this->vaddr_ = 0;
+ this->paddr_ = 0;
+ this->memsz_ = 0;
+ this->align_ = 0;
+ this->offset_ = 0;
+ this->filesz_ = 0;
+ return;
+ }
+
+ const Output_data* first;
+ if (this->output_data_.empty())
+ first = this->output_bss_.front();
+ else
+ first = this->output_data_.front();
+ this->vaddr_ = first->address();
+ this->paddr_ = this->vaddr_;
+ this->offset_ = first->offset();
+
+ if (this->output_data_.empty())
+ this->filesz_ = 0;
+ else
+ {
+ const Output_data* last_data = this->output_data_.back();
+ this->filesz_ = (last_data->address()
+ + last_data->data_size()
+ - this->vaddr_);
+ }
+
+ const Output_data* last;
+ if (this->output_bss_.empty())
+ last = this->output_data_.back();
+ else
+ last = this->output_bss_.back();
+ this->memsz_ = (last->address()
+ + last->data_size()
+ - this->vaddr_);
+}
+
+// Return the number of Output_sections in an Output_segment.
+
+unsigned int
+Output_segment::output_section_count() const
+{
+ return (this->output_section_count_list(&this->output_data_)
+ + this->output_section_count_list(&this->output_bss_));
+}
+
+// Return the number of Output_sections in an Output_data_list.
+
+unsigned int
+Output_segment::output_section_count_list(const Output_data_list* pdl) const
+{
+ unsigned int count = 0;
+ for (Output_data_list::const_iterator p = pdl->begin();
+ p != pdl->end();
+ ++p)
+ {
+ if ((*p)->is_section())
+ ++count;
+ }
+ return count;
+}
+
+// Write the segment data into *OPHDR.
+
+template<int size, bool big_endian>
+void
+Output_segment::write_header(elfcpp::Phdr_write<size, big_endian>* ophdr)
+{
+ ophdr->put_p_type(this->type_);
+ ophdr->put_p_offset(this->offset_);
+ ophdr->put_p_vaddr(this->vaddr_);
+ ophdr->put_p_paddr(this->paddr_);
+ ophdr->put_p_filesz(this->filesz_);
+ ophdr->put_p_memsz(this->memsz_);
+ ophdr->put_p_flags(this->flags_);
+ ophdr->put_p_align(this->addralign());
+}
+
+// Write the section headers into V.
+
+template<int size, bool big_endian>
+unsigned char*
+Output_segment::write_section_headers(const Layout* layout,
+ const Stringpool* secnamepool,
+ unsigned char* v,
+ unsigned int *pshndx
+ ACCEPT_SIZE_ENDIAN) const
+{
+ // Every section that is attached to a segment must be attached to a
+ // PT_LOAD segment, so we only write out section headers for PT_LOAD
+ // segments.
+ if (this->type_ != elfcpp::PT_LOAD)
+ return v;
+
+ v = this->write_section_headers_list
+ SELECT_SIZE_ENDIAN_NAME(size, big_endian) (
+ layout, secnamepool, &this->output_data_, v, pshndx
+ SELECT_SIZE_ENDIAN(size, big_endian));
+ v = this->write_section_headers_list
+ SELECT_SIZE_ENDIAN_NAME(size, big_endian) (
+ layout, secnamepool, &this->output_bss_, v, pshndx
+ SELECT_SIZE_ENDIAN(size, big_endian));
+ return v;
+}
+
+template<int size, bool big_endian>
+unsigned char*
+Output_segment::write_section_headers_list(const Layout* layout,
+ const Stringpool* secnamepool,
+ const Output_data_list* pdl,
+ unsigned char* v,
+ unsigned int* pshndx
+ ACCEPT_SIZE_ENDIAN) const
+{
+ const int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
+ for (Output_data_list::const_iterator p = pdl->begin();
+ p != pdl->end();
+ ++p)
+ {
+ if ((*p)->is_section())
+ {
+ const Output_section* ps = static_cast<const Output_section*>(*p);
+ gold_assert(*pshndx == ps->out_shndx());
+ elfcpp::Shdr_write<size, big_endian> oshdr(v);
+ ps->write_header(layout, secnamepool, &oshdr);
+ v += shdr_size;
+ ++*pshndx;
+ }
+ }
+ return v;
+}
+
+// Output_file methods.
+
+Output_file::Output_file(const General_options& options)
+ : options_(options),
+ name_(options.output_file_name()),
+ o_(-1),
+ file_size_(0),
+ base_(NULL)
+{
+}
+
+// Open the output file.
+
+void
+Output_file::open(off_t file_size)
+{
+ this->file_size_ = file_size;
+
+ int mode = this->options_.is_relocatable() ? 0666 : 0777;
+ int o = ::open(this->name_, O_RDWR | O_CREAT | O_TRUNC, mode);
+ if (o < 0)
+ {
+ fprintf(stderr, _("%s: %s: open: %s\n"),
+ program_name, this->name_, strerror(errno));
+ gold_exit(false);
+ }
+ this->o_ = o;
+
+ // Write out one byte to make the file the right size.
+ if (::lseek(o, file_size - 1, SEEK_SET) < 0)
+ {
+ fprintf(stderr, _("%s: %s: lseek: %s\n"),
+ program_name, this->name_, strerror(errno));
+ gold_exit(false);
+ }
+ char b = 0;
+ if (::write(o, &b, 1) != 1)
+ {
+ fprintf(stderr, _("%s: %s: write: %s\n"),
+ program_name, this->name_, strerror(errno));
+ gold_exit(false);
+ }
+
+ // Map the file into memory.
+ void* base = ::mmap(NULL, file_size, PROT_READ | PROT_WRITE,
+ MAP_SHARED, o, 0);
+ if (base == MAP_FAILED)
+ {
+ fprintf(stderr, _("%s: %s: mmap: %s\n"),
+ program_name, this->name_, strerror(errno));
+ gold_exit(false);
+ }
+ this->base_ = static_cast<unsigned char*>(base);
+}
+
+// Close the output file.
+
+void
+Output_file::close()
+{
+ if (::munmap(this->base_, this->file_size_) < 0)
+ {
+ fprintf(stderr, _("%s: %s: munmap: %s\n"),
+ program_name, this->name_, strerror(errno));
+ gold_exit(false);
+ }
+ this->base_ = NULL;
+
+ if (::close(this->o_) < 0)
+ {
+ fprintf(stderr, _("%s: %s: close: %s\n"),
+ program_name, this->name_, strerror(errno));
+ gold_exit(false);
+ }
+ this->o_ = -1;
+}
+
+// Instantiate the templates we need. We could use the configure
+// script to restrict this to only the ones for implemented targets.
+
+template
+off_t
+Output_section::add_input_section<32, false>(
+ Relobj* object,
+ unsigned int shndx,
+ const char* secname,
+ const elfcpp::Shdr<32, false>& shdr);
+
+template
+off_t
+Output_section::add_input_section<32, true>(
+ Relobj* object,
+ unsigned int shndx,
+ const char* secname,
+ const elfcpp::Shdr<32, true>& shdr);
+
+template
+off_t
+Output_section::add_input_section<64, false>(
+ Relobj* object,
+ unsigned int shndx,
+ const char* secname,
+ const elfcpp::Shdr<64, false>& shdr);
+
+template
+off_t
+Output_section::add_input_section<64, true>(
+ Relobj* object,
+ unsigned int shndx,
+ const char* secname,
+ const elfcpp::Shdr<64, true>& shdr);
+
+template
+class Output_data_reloc<elfcpp::SHT_REL, false, 32, false>;
+
+template
+class Output_data_reloc<elfcpp::SHT_REL, false, 32, true>;
+
+template
+class Output_data_reloc<elfcpp::SHT_REL, false, 64, false>;
+
+template
+class Output_data_reloc<elfcpp::SHT_REL, false, 64, true>;
+
+template
+class Output_data_reloc<elfcpp::SHT_REL, true, 32, false>;
+
+template
+class Output_data_reloc<elfcpp::SHT_REL, true, 32, true>;
+
+template
+class Output_data_reloc<elfcpp::SHT_REL, true, 64, false>;
+
+template
+class Output_data_reloc<elfcpp::SHT_REL, true, 64, true>;
+
+template
+class Output_data_reloc<elfcpp::SHT_RELA, false, 32, false>;
+
+template
+class Output_data_reloc<elfcpp::SHT_RELA, false, 32, true>;
+
+template
+class Output_data_reloc<elfcpp::SHT_RELA, false, 64, false>;
+
+template
+class Output_data_reloc<elfcpp::SHT_RELA, false, 64, true>;
+
+template
+class Output_data_reloc<elfcpp::SHT_RELA, true, 32, false>;
+
+template
+class Output_data_reloc<elfcpp::SHT_RELA, true, 32, true>;
+
+template
+class Output_data_reloc<elfcpp::SHT_RELA, true, 64, false>;
+
+template
+class Output_data_reloc<elfcpp::SHT_RELA, true, 64, true>;
+
+template
+class Output_data_got<32, false>;
+
+template
+class Output_data_got<32, true>;
+
+template
+class Output_data_got<64, false>;
+
+template
+class Output_data_got<64, true>;
+
+} // End namespace gold.
+
diff --git a/gold/output.h b/gold/output.h
new file mode 100644
index 000000000000..7ed53ff06d77
--- /dev/null
+++ b/gold/output.h
@@ -0,0 +1,1801 @@
+// output.h -- manage the output file for gold -*- C++ -*-
+
+#ifndef GOLD_OUTPUT_H
+#define GOLD_OUTPUT_H
+
+#include <list>
+#include <vector>
+
+#include "elfcpp.h"
+#include "layout.h"
+#include "reloc-types.h"
+
+namespace gold
+{
+
+class General_options;
+class Object;
+class Symbol;
+class Output_file;
+class Output_section;
+class Target;
+template<int size, bool big_endian>
+class Sized_target;
+template<int size, bool big_endian>
+class Sized_relobj;
+
+// An abtract class for data which has to go into the output file.
+
+class Output_data
+{
+ public:
+ explicit Output_data(off_t data_size = 0)
+ : address_(0), data_size_(data_size), offset_(-1)
+ { }
+
+ virtual
+ ~Output_data();
+
+ // Return the address. This is only valid after Layout::finalize is
+ // finished.
+ uint64_t
+ address() const
+ { return this->address_; }
+
+ // Return the size of the data. This must be valid after
+ // Layout::finalize calls set_address, but need not be valid before
+ // then.
+ off_t
+ data_size() const
+ { return this->data_size_; }
+
+ // Return the file offset. This is only valid after
+ // Layout::finalize is finished.
+ off_t
+ offset() const
+ { return this->offset_; }
+
+ // Return the required alignment.
+ uint64_t
+ addralign() const
+ { return this->do_addralign(); }
+
+ // Return whether this is an Output_section.
+ bool
+ is_section() const
+ { return this->do_is_section(); }
+
+ // Return whether this is an Output_section of the specified type.
+ bool
+ is_section_type(elfcpp::Elf_Word stt) const
+ { return this->do_is_section_type(stt); }
+
+ // Return whether this is an Output_section with the specified flag
+ // set.
+ bool
+ is_section_flag_set(elfcpp::Elf_Xword shf) const
+ { return this->do_is_section_flag_set(shf); }
+
+ // Return the output section index, if there is an output section.
+ unsigned int
+ out_shndx() const
+ { return this->do_out_shndx(); }
+
+ // Set the output section index, if this is an output section.
+ void
+ set_out_shndx(unsigned int shndx)
+ { this->do_set_out_shndx(shndx); }
+
+ // Set the address and file offset of this data. This is called
+ // during Layout::finalize.
+ void
+ set_address(uint64_t addr, off_t off);
+
+ // Write the data to the output file. This is called after
+ // Layout::finalize is complete.
+ void
+ write(Output_file* file)
+ { this->do_write(file); }
+
+ // This is called by Layout::finalize to note that all sizes must
+ // now be fixed.
+ static void
+ layout_complete()
+ { Output_data::sizes_are_fixed = true; }
+
+ protected:
+ // Functions that child classes may or in some cases must implement.
+
+ // Write the data to the output file.
+ virtual void
+ do_write(Output_file*) = 0;
+
+ // Return the required alignment.
+ virtual uint64_t
+ do_addralign() const = 0;
+
+ // Return whether this is an Output_section.
+ virtual bool
+ do_is_section() const
+ { return false; }
+
+ // Return whether this is an Output_section of the specified type.
+ // This only needs to be implement by Output_section.
+ virtual bool
+ do_is_section_type(elfcpp::Elf_Word) const
+ { return false; }
+
+ // Return whether this is an Output_section with the specific flag
+ // set. This only needs to be implemented by Output_section.
+ virtual bool
+ do_is_section_flag_set(elfcpp::Elf_Xword) const
+ { return false; }
+
+ // Return the output section index, if there is an output section.
+ virtual unsigned int
+ do_out_shndx() const
+ { gold_unreachable(); }
+
+ // Set the output section index, if this is an output section.
+ virtual void
+ do_set_out_shndx(unsigned int)
+ { gold_unreachable(); }
+
+ // Set the address and file offset of the data. This only needs to
+ // be implemented if the child needs to know. The child class can
+ // set its size in this call.
+ virtual void
+ do_set_address(uint64_t, off_t)
+ { }
+
+ // Functions that child classes may call.
+
+ // Set the size of the data.
+ void
+ set_data_size(off_t data_size)
+ {
+ gold_assert(!Output_data::sizes_are_fixed);
+ this->data_size_ = data_size;
+ }
+
+ // Return default alignment for a size--32 or 64.
+ static uint64_t
+ default_alignment(int size);
+
+ private:
+ Output_data(const Output_data&);
+ Output_data& operator=(const Output_data&);
+
+ // This is used for verification, to make sure that we don't try to
+ // change any sizes after we set the section addresses.
+ static bool sizes_are_fixed;
+
+ // Memory address in file (not always meaningful).
+ uint64_t address_;
+ // Size of data in file.
+ off_t data_size_;
+ // Offset within file.
+ off_t offset_;
+};
+
+// Output the section headers.
+
+class Output_section_headers : public Output_data
+{
+ public:
+ Output_section_headers(int size,
+ bool big_endian,
+ const Layout*,
+ const Layout::Segment_list*,
+ const Layout::Section_list*,
+ const Stringpool*);
+
+ // Write the data to the file.
+ void
+ do_write(Output_file*);
+
+ // Return the required alignment.
+ uint64_t
+ do_addralign() const
+ { return Output_data::default_alignment(this->size_); }
+
+ private:
+ // Write the data to the file with the right size and endianness.
+ template<int size, bool big_endian>
+ void
+ do_sized_write(Output_file*);
+
+ int size_;
+ bool big_endian_;
+ const Layout* layout_;
+ const Layout::Segment_list* segment_list_;
+ const Layout::Section_list* unattached_section_list_;
+ const Stringpool* secnamepool_;
+};
+
+// Output the segment headers.
+
+class Output_segment_headers : public Output_data
+{
+ public:
+ Output_segment_headers(int size, bool big_endian,
+ const Layout::Segment_list& segment_list);
+
+ // Write the data to the file.
+ void
+ do_write(Output_file*);
+
+ // Return the required alignment.
+ uint64_t
+ do_addralign() const
+ { return Output_data::default_alignment(this->size_); }
+
+ private:
+ // Write the data to the file with the right size and endianness.
+ template<int size, bool big_endian>
+ void
+ do_sized_write(Output_file*);
+
+ int size_;
+ bool big_endian_;
+ const Layout::Segment_list& segment_list_;
+};
+
+// Output the ELF file header.
+
+class Output_file_header : public Output_data
+{
+ public:
+ Output_file_header(int size,
+ bool big_endian,
+ const General_options&,
+ const Target*,
+ const Symbol_table*,
+ const Output_segment_headers*);
+
+ // Add information about the section headers. We lay out the ELF
+ // file header before we create the section headers.
+ void set_section_info(const Output_section_headers*,
+ const Output_section* shstrtab);
+
+ // Write the data to the file.
+ void
+ do_write(Output_file*);
+
+ // Return the required alignment.
+ uint64_t
+ do_addralign() const
+ { return Output_data::default_alignment(this->size_); }
+
+ // Set the address and offset--we only implement this for error
+ // checking.
+ void
+ do_set_address(uint64_t, off_t off) const
+ { gold_assert(off == 0); }
+
+ private:
+ // Write the data to the file with the right size and endianness.
+ template<int size, bool big_endian>
+ void
+ do_sized_write(Output_file*);
+
+ int size_;
+ bool big_endian_;
+ const General_options& options_;
+ const Target* target_;
+ const Symbol_table* symtab_;
+ const Output_segment_headers* segment_header_;
+ const Output_section_headers* section_header_;
+ const Output_section* shstrtab_;
+};
+
+// Output sections are mainly comprised of input sections. However,
+// there are cases where we have data to write out which is not in an
+// input section. Output_section_data is used in such cases. This is
+// an abstract base class.
+
+class Output_section_data : public Output_data
+{
+ public:
+ Output_section_data(off_t data_size, uint64_t addralign)
+ : Output_data(data_size), output_section_(NULL), addralign_(addralign)
+ { }
+
+ Output_section_data(uint64_t addralign)
+ : Output_data(0), output_section_(NULL), addralign_(addralign)
+ { }
+
+ // Return the output section.
+ const Output_section*
+ output_section() const
+ { return this->output_section_; }
+
+ // Record the output section.
+ void
+ set_output_section(Output_section* os);
+
+ // Add an input section, for SHF_MERGE sections. This returns true
+ // if the section was handled.
+ bool
+ add_input_section(Relobj* object, unsigned int shndx)
+ { return this->do_add_input_section(object, shndx); }
+
+ // Given an input OBJECT, an input section index SHNDX within that
+ // object, and an OFFSET relative to the start of that input
+ // section, return whether or not the output address is known.
+ // OUTPUT_SECTION_ADDRESS is the address of the output section which
+ // this is a part of. If this function returns true, it sets
+ // *POUTPUT to the output address.
+ virtual bool
+ output_address(const Relobj* object, unsigned int shndx, off_t offset,
+ uint64_t output_section_address, uint64_t *poutput) const
+ {
+ return this->do_output_address(object, shndx, offset,
+ output_section_address, poutput);
+ }
+
+ protected:
+ // The child class must implement do_write.
+
+ // The child class may implement specific adjustments to the output
+ // section.
+ virtual void
+ do_adjust_output_section(Output_section*)
+ { }
+
+ // May be implemented by child class. Return true if the section
+ // was handled.
+ virtual bool
+ do_add_input_section(Relobj*, unsigned int)
+ { gold_unreachable(); }
+
+ // The child class may implement output_address.
+ virtual bool
+ do_output_address(const Relobj*, unsigned int, off_t, uint64_t,
+ uint64_t*) const
+ { return false; }
+
+ // Return the required alignment.
+ uint64_t
+ do_addralign() const
+ { return this->addralign_; }
+
+ // Return the section index of the output section.
+ 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_;
+ // The required alignment.
+ uint64_t addralign_;
+};
+
+// A simple case of Output_data in which we have constant data to
+// output.
+
+class Output_data_const : public Output_section_data
+{
+ public:
+ Output_data_const(const std::string& data, uint64_t addralign)
+ : Output_section_data(data.size(), addralign), data_(data)
+ { }
+
+ Output_data_const(const char* p, off_t len, uint64_t addralign)
+ : Output_section_data(len, addralign), data_(p, len)
+ { }
+
+ Output_data_const(const unsigned char* p, off_t len, uint64_t addralign)
+ : Output_section_data(len, addralign),
+ data_(reinterpret_cast<const char*>(p), len)
+ { }
+
+ // Add more data.
+ void
+ add_data(const std::string& add)
+ {
+ this->data_.append(add);
+ this->set_data_size(this->data_.size());
+ }
+
+ // Write the data to the output file.
+ void
+ do_write(Output_file*);
+
+ private:
+ std::string data_;
+};
+
+// Another version of Output_data with constant data, in which the
+// buffer is allocated by the caller.
+
+class Output_data_const_buffer : public Output_section_data
+{
+ public:
+ Output_data_const_buffer(const unsigned char* p, off_t len,
+ uint64_t addralign)
+ : Output_section_data(len, addralign), p_(p)
+ { }
+
+ // Write the data the output file.
+ void
+ do_write(Output_file*);
+
+ private:
+ const unsigned char* p_;
+};
+
+// A place holder for data written out via some other mechanism.
+
+class Output_data_space : public Output_section_data
+{
+ public:
+ Output_data_space(off_t data_size, uint64_t addralign)
+ : Output_section_data(data_size, addralign)
+ { }
+
+ explicit Output_data_space(uint64_t addralign)
+ : Output_section_data(addralign)
+ { }
+
+ // Set the size.
+ void
+ 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*)
+ { }
+};
+
+// A string table which goes into an output section.
+
+class Output_data_strtab : public Output_section_data
+{
+ public:
+ Output_data_strtab(Stringpool* strtab)
+ : Output_section_data(1), strtab_(strtab)
+ { }
+
+ // This is called to set the address and file offset. Here we make
+ // sure that the Stringpool is finalized.
+ void
+ do_set_address(uint64_t, off_t);
+
+ // Write out the data.
+ void
+ do_write(Output_file*);
+
+ private:
+ Stringpool* strtab_;
+};
+
+// This POD class is used to represent a single reloc in the output
+// file. This could be a private class within Output_data_reloc, but
+// the templatization is complex enough that I broke it out into a
+// separate class. The class is templatized on either elfcpp::SHT_REL
+// or elfcpp::SHT_RELA, and also on whether this is a dynamic
+// relocation or an ordinary relocation.
+
+// A relocation can be against a global symbol, a local symbol, an
+// output section, or the undefined symbol at index 0. We represent
+// the latter by using a NULL global symbol.
+
+template<int sh_type, bool dynamic, int size, bool big_endian>
+class Output_reloc;
+
+template<bool dynamic, int size, bool big_endian>
+class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
+{
+ public:
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+
+ // An uninitialized entry. We need this because we want to put
+ // instances of this class into an STL container.
+ Output_reloc()
+ : local_sym_index_(INVALID_CODE)
+ { }
+
+ // A reloc against a global symbol.
+
+ Output_reloc(Symbol* gsym, unsigned int type, Output_data* od,
+ Address address)
+ : 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<size, big_endian>* relobj,
+ unsigned int local_sym_index,
+ unsigned int type,
+ Output_data* 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->u1_.relobj = relobj;
+ this->u2_.od = od;
+ }
+
+ Output_reloc(Sized_relobj<size, big_endian>* 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)
+ : 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
+ write(unsigned char* pov) const;
+
+ // Write the offset and info fields to Write_rel.
+ template<typename Write_rel>
+ void write_rel(Write_rel*) const;
+
+ private:
+ // Return the symbol index. We can't do a double template
+ // specialization, so we do a secondary template here.
+ unsigned int
+ get_symbol_index() const;
+
+ // Codes for local_sym_index_.
+ enum
+ {
+ // Global symbol.
+ GSYM_CODE = -1U,
+ // Output section.
+ SECTION_CODE = -2U,
+ // Invalid uninitialized entry.
+ INVALID_CODE = -3U
+ };
+
+ union
+ {
+ // For a local symbol, the object. We will never generate a
+ // 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<size, big_endian>* 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;
+ } 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 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
+// the SHT_REL version of Output_reloc, but it adds an addend.
+
+template<bool dynamic, int size, bool big_endian>
+class Output_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
+{
+ public:
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Addend;
+
+ // An uninitialized entry.
+ Output_reloc()
+ : rel_()
+ { }
+
+ // 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<size, big_endian>* relobj,
+ unsigned int local_sym_index,
+ unsigned int type, Output_data* od, Address address,
+ Addend addend)
+ : rel_(relobj, local_sym_index, type, od, address), addend_(addend)
+ { }
+
+ Output_reloc(Sized_relobj<size, big_endian>* 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;
+
+ private:
+ // The basic reloc.
+ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian> rel_;
+ // The addend.
+ Addend addend_;
+};
+
+// Output_data_reloc is used to manage a section containing relocs.
+// SH_TYPE is either elfcpp::SHT_REL or elfcpp::SHT_RELA. DYNAMIC
+// indicates whether this is a dynamic relocation or a normal
+// relocation. Output_data_reloc_base is a base class.
+// Output_data_reloc is the real class, which we specialize based on
+// the reloc type.
+
+template<int sh_type, bool dynamic, int size, bool big_endian>
+class Output_data_reloc_base : public Output_section_data
+{
+ public:
+ typedef Output_reloc<sh_type, dynamic, size, big_endian> Output_reloc_type;
+ typedef typename Output_reloc_type::Address Address;
+ static const int reloc_size =
+ Reloc_types<sh_type, size, big_endian>::reloc_size;
+
+ // Construct the section.
+ Output_data_reloc_base()
+ : Output_section_data(Output_data::default_alignment(size))
+ { }
+
+ // Write out the data.
+ void
+ do_write(Output_file*);
+
+ protected:
+ // Set the entry size and the link.
+ void
+ do_adjust_output_section(Output_section *os);
+
+ // Add a relocation entry.
+ void
+ add(const Output_reloc_type& reloc)
+ {
+ this->relocs_.push_back(reloc);
+ this->set_data_size(this->relocs_.size() * reloc_size);
+ }
+
+ private:
+ typedef std::vector<Output_reloc_type> Relocs;
+
+ Relocs relocs_;
+};
+
+// The class which callers actually create.
+
+template<int sh_type, bool dynamic, int size, bool big_endian>
+class Output_data_reloc;
+
+// The SHT_REL version of Output_data_reloc.
+
+template<bool dynamic, int size, bool big_endian>
+class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
+ : public Output_data_reloc_base<elfcpp::SHT_REL, dynamic, size, big_endian>
+{
+ private:
+ typedef Output_data_reloc_base<elfcpp::SHT_REL, dynamic, size,
+ big_endian> Base;
+
+ public:
+ typedef typename Base::Output_reloc_type Output_reloc_type;
+ typedef typename Output_reloc_type::Address Address;
+
+ Output_data_reloc()
+ : Output_data_reloc_base<elfcpp::SHT_REL, dynamic, size, big_endian>()
+ { }
+
+ // 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<size, big_endian>* relobj,
+ unsigned int local_sym_index, unsigned int type,
+ Output_data* od, Address address)
+ { this->add(Output_reloc_type(relobj, local_sym_index, type, od, address)); }
+
+ void
+ add_local(Sized_relobj<size, big_endian>* 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.
+
+template<bool dynamic, int size, bool big_endian>
+class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
+ : public Output_data_reloc_base<elfcpp::SHT_RELA, dynamic, size, big_endian>
+{
+ private:
+ typedef Output_data_reloc_base<elfcpp::SHT_RELA, dynamic, size,
+ big_endian> Base;
+
+ public:
+ typedef typename Base::Output_reloc_type Output_reloc_type;
+ typedef typename Output_reloc_type::Address Address;
+ typedef typename Output_reloc_type::Addend Addend;
+
+ Output_data_reloc()
+ : Output_data_reloc_base<elfcpp::SHT_RELA, dynamic, size, big_endian>()
+ { }
+
+ // 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<size, big_endian>* relobj,
+ unsigned int local_sym_index, unsigned int type,
+ Output_data* od, Address address, Addend addend)
+ {
+ this->add(Output_reloc_type(relobj, local_sym_index, type, od, address,
+ addend));
+ }
+
+ void
+ add_local(Sized_relobj<size, big_endian>* 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
+// for one symbol--either a global symbol or a local symbol in an
+// object. The target specific code adds entries to the GOT as
+// needed.
+
+template<int size, bool big_endian>
+class Output_data_got : public Output_section_data
+{
+ public:
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Valtype;
+
+ Output_data_got(const General_options* options)
+ : Output_section_data(Output_data::default_alignment(size)),
+ options_(options), entries_()
+ { }
+
+ // Add an entry for a global symbol to the GOT. Return true if this
+ // is a new GOT entry, false if the symbol was already in the GOT.
+ bool
+ add_global(Symbol* gsym);
+
+ // Add an entry for a local symbol to the GOT. This returns the
+ // offset of the new entry from the start of the GOT.
+ unsigned int
+ add_local(Object* object, unsigned int sym_index)
+ {
+ this->entries_.push_back(Got_entry(object, sym_index));
+ this->set_got_size();
+ return this->last_got_offset();
+ }
+
+ // Add a constant to the GOT. This returns the offset of the new
+ // entry from the start of the GOT.
+ unsigned int
+ add_constant(Valtype constant)
+ {
+ this->entries_.push_back(Got_entry(constant));
+ this->set_got_size();
+ return this->last_got_offset();
+ }
+
+ // Write out the GOT table.
+ void
+ do_write(Output_file*);
+
+ private:
+ // This POD class holds a single GOT entry.
+ class Got_entry
+ {
+ public:
+ // Create a zero entry.
+ Got_entry()
+ : local_sym_index_(CONSTANT_CODE)
+ { this->u_.constant = 0; }
+
+ // Create a global symbol entry.
+ explicit Got_entry(Symbol* gsym)
+ : local_sym_index_(GSYM_CODE)
+ { this->u_.gsym = gsym; }
+
+ // Create a local symbol entry.
+ Got_entry(Object* object, unsigned int local_sym_index)
+ : local_sym_index_(local_sym_index)
+ {
+ gold_assert(local_sym_index != GSYM_CODE
+ && local_sym_index != CONSTANT_CODE);
+ this->u_.object = object;
+ }
+
+ // Create a constant entry. The constant is a host value--it will
+ // be swapped, if necessary, when it is written out.
+ explicit Got_entry(Valtype constant)
+ : local_sym_index_(CONSTANT_CODE)
+ { this->u_.constant = constant; }
+
+ // Write the GOT entry to an output view.
+ void
+ write(const General_options*, unsigned char* pov) const;
+
+ private:
+ enum
+ {
+ GSYM_CODE = -1U,
+ CONSTANT_CODE = -2U
+ };
+
+ union
+ {
+ // For a local symbol, the object.
+ Object* object;
+ // For a global symbol, the symbol.
+ Symbol* gsym;
+ // For a constant, the constant.
+ Valtype constant;
+ } u_;
+ // For a local symbol, the local symbol index. This is GSYM_CODE
+ // for a global symbol, or CONSTANT_CODE for a constant.
+ unsigned int local_sym_index_;
+ };
+
+ typedef std::vector<Got_entry> Got_entries;
+
+ // Return the offset into the GOT of GOT entry I.
+ unsigned int
+ got_offset(unsigned int i) const
+ { return i * (size / 8); }
+
+ // Return the offset into the GOT of the last entry added.
+ unsigned int
+ last_got_offset() const
+ { return this->got_offset(this->entries_.size() - 1); }
+
+ // Set the size of the section.
+ void
+ set_got_size()
+ { this->set_data_size(this->got_offset(this->entries_.size())); }
+
+ // Options.
+ const General_options* options_;
+ // The list of GOT entries.
+ Got_entries entries_;
+};
+
+// Output_data_dynamic is used to hold the data in SHT_DYNAMIC
+// section.
+
+class Output_data_dynamic : public Output_section_data
+{
+ public:
+ Output_data_dynamic(const Target* target, Stringpool* pool)
+ : Output_section_data(Output_data::default_alignment(target->get_size())),
+ target_(target), entries_(), pool_(pool)
+ { }
+
+ // Add a new dynamic entry with a fixed numeric value.
+ void
+ add_constant(elfcpp::DT tag, unsigned int val)
+ { this->add_entry(Dynamic_entry(tag, val)); }
+
+ // Add a new dynamic entry with the address of output data.
+ void
+ add_section_address(elfcpp::DT tag, const Output_data* od)
+ { this->add_entry(Dynamic_entry(tag, od, false)); }
+
+ // Add a new dynamic entry with the size of output data.
+ void
+ add_section_size(elfcpp::DT tag, const Output_data* od)
+ { this->add_entry(Dynamic_entry(tag, od, true)); }
+
+ // Add a new dynamic entry with the address of a symbol.
+ void
+ add_symbol(elfcpp::DT tag, const Symbol* sym)
+ { this->add_entry(Dynamic_entry(tag, sym)); }
+
+ // Add a new dynamic entry with a string.
+ void
+ add_string(elfcpp::DT tag, const char* str)
+ { this->add_entry(Dynamic_entry(tag, this->pool_->add(str, NULL))); }
+
+ // Set the final data size.
+ void
+ do_set_address(uint64_t, off_t);
+
+ // Write out the dynamic entries.
+ void
+ do_write(Output_file*);
+
+ protected:
+ // Adjust the output section to set the entry size.
+ void
+ do_adjust_output_section(Output_section*);
+
+ private:
+ // This POD class holds a single dynamic entry.
+ class Dynamic_entry
+ {
+ public:
+ // Create an entry with a fixed numeric value.
+ Dynamic_entry(elfcpp::DT tag, unsigned int val)
+ : tag_(tag), classification_(DYNAMIC_NUMBER)
+ { this->u_.val = val; }
+
+ // Create an entry with the size or address of a section.
+ Dynamic_entry(elfcpp::DT tag, const Output_data* od, bool section_size)
+ : tag_(tag),
+ classification_(section_size
+ ? DYNAMIC_SECTION_SIZE
+ : DYNAMIC_SECTION_ADDRESS)
+ { this->u_.od = od; }
+
+ // Create an entry with the address of a symbol.
+ Dynamic_entry(elfcpp::DT tag, const Symbol* sym)
+ : tag_(tag), classification_(DYNAMIC_SYMBOL)
+ { this->u_.sym = sym; }
+
+ // Create an entry with a string.
+ Dynamic_entry(elfcpp::DT tag, const char* str)
+ : tag_(tag), classification_(DYNAMIC_STRING)
+ { this->u_.str = str; }
+
+ // Write the dynamic entry to an output view.
+ template<int size, bool big_endian>
+ void
+ write(unsigned char* pov, const Stringpool* ACCEPT_SIZE_ENDIAN) const;
+
+ private:
+ enum Classification
+ {
+ // Number.
+ DYNAMIC_NUMBER,
+ // Section address.
+ DYNAMIC_SECTION_ADDRESS,
+ // Section size.
+ DYNAMIC_SECTION_SIZE,
+ // Symbol adress.
+ DYNAMIC_SYMBOL,
+ // String.
+ DYNAMIC_STRING
+ };
+
+ union
+ {
+ // For DYNAMIC_NUMBER.
+ unsigned int val;
+ // For DYNAMIC_SECTION_ADDRESS and DYNAMIC_SECTION_SIZE.
+ const Output_data* od;
+ // For DYNAMIC_SYMBOL.
+ const Symbol* sym;
+ // For DYNAMIC_STRING.
+ const char* str;
+ } u_;
+ // The dynamic tag.
+ elfcpp::DT tag_;
+ // The type of entry.
+ Classification classification_;
+ };
+
+ // Add an entry to the list.
+ void
+ add_entry(const Dynamic_entry& entry)
+ { this->entries_.push_back(entry); }
+
+ // Sized version of write function.
+ template<int size, bool big_endian>
+ void
+ sized_write(Output_file* of);
+
+ // The type of the list of entries.
+ typedef std::vector<Dynamic_entry> Dynamic_entries;
+
+ // The target.
+ const Target* target_;
+ // The entries.
+ Dynamic_entries entries_;
+ // The pool used for strings.
+ Stringpool* pool_;
+};
+
+// An output section. We don't expect to have too many output
+// sections, so we don't bother to do a template on the size.
+
+class Output_section : public Output_data
+{
+ public:
+ // Create an output section, giving the name, type, and flags.
+ Output_section(const char* name, elfcpp::Elf_Word, elfcpp::Elf_Xword);
+ virtual ~Output_section();
+
+ // Add a new input section SHNDX, named NAME, with header SHDR, from
+ // object OBJECT. Return the offset within the output section.
+ template<int size, bool big_endian>
+ off_t
+ add_input_section(Relobj* object, unsigned int shndx, const char *name,
+ const elfcpp::Shdr<size, big_endian>& shdr);
+
+ // Add generated data POSD to this output section.
+ void
+ add_output_section_data(Output_section_data* posd);
+
+ // Return the section name.
+ const char*
+ name() const
+ { return this->name_; }
+
+ // Return the section type.
+ elfcpp::Elf_Word
+ type() const
+ { return this->type_; }
+
+ // Return the section flags.
+ elfcpp::Elf_Xword
+ flags() const
+ { return this->flags_; }
+
+ // Return the section index in the output file.
+ unsigned int
+ do_out_shndx() const
+ { return this->out_shndx_; }
+
+ // Set the output section index.
+ void
+ do_set_out_shndx(unsigned int shndx)
+ { this->out_shndx_ = shndx; }
+
+ // Return the entsize field.
+ uint64_t
+ entsize() const
+ { return this->entsize_; }
+
+ // Set the entsize field.
+ void
+ set_entsize(uint64_t v);
+
+ // Set the link field to the output section index of a section.
+ void
+ set_link_section(const Output_data* od)
+ {
+ gold_assert(this->link_ == 0
+ && !this->should_link_to_symtab_
+ && !this->should_link_to_dynsym_);
+ this->link_section_ = od;
+ }
+
+ // Set the link field to a constant.
+ void
+ set_link(unsigned int v)
+ {
+ gold_assert(this->link_section_ == NULL
+ && !this->should_link_to_symtab_
+ && !this->should_link_to_dynsym_);
+ this->link_ = v;
+ }
+
+ // Record that this section should link to the normal symbol table.
+ void
+ set_should_link_to_symtab()
+ {
+ gold_assert(this->link_section_ == NULL
+ && this->link_ == 0
+ && !this->should_link_to_dynsym_);
+ this->should_link_to_symtab_ = true;
+ }
+
+ // Record that this section should link to the dynamic symbol table.
+ void
+ set_should_link_to_dynsym()
+ {
+ gold_assert(this->link_section_ == NULL
+ && this->link_ == 0
+ && !this->should_link_to_symtab_);
+ this->should_link_to_dynsym_ = true;
+ }
+
+ // Return the info field.
+ unsigned int
+ info() const
+ {
+ gold_assert(this->info_section_ == NULL);
+ return this->info_;
+ }
+
+ // Set the info field to the output section index of a section.
+ void
+ set_info_section(const Output_data* od)
+ {
+ gold_assert(this->info_ == 0);
+ this->info_section_ = od;
+ }
+
+ // Set the info field to a constant.
+ void
+ set_info(unsigned int v)
+ {
+ gold_assert(this->info_section_ == NULL);
+ this->info_ = v;
+ }
+
+ // Set the addralign field.
+ void
+ set_addralign(uint64_t v)
+ { this->addralign_ = v; }
+
+ // Indicate that we need a symtab index.
+ void
+ set_needs_symtab_index()
+ { this->needs_symtab_index_ = true; }
+
+ // Return whether we need a symtab index.
+ bool
+ needs_symtab_index() const
+ { return this->needs_symtab_index_; }
+
+ // Get the symtab index.
+ unsigned int
+ symtab_index() const
+ {
+ gold_assert(this->symtab_index_ != 0);
+ return this->symtab_index_;
+ }
+
+ // Set the symtab index.
+ void
+ set_symtab_index(unsigned int index)
+ {
+ gold_assert(index != 0);
+ this->symtab_index_ = index;
+ }
+
+ // Indicate that we need a dynsym index.
+ void
+ set_needs_dynsym_index()
+ { this->needs_dynsym_index_ = true; }
+
+ // Return whether we need a dynsym index.
+ bool
+ needs_dynsym_index() const
+ { return this->needs_dynsym_index_; }
+
+ // Get the dynsym index.
+ unsigned int
+ dynsym_index() const
+ {
+ gold_assert(this->dynsym_index_ != 0);
+ return this->dynsym_index_;
+ }
+
+ // Set the dynsym index.
+ void
+ set_dynsym_index(unsigned int index)
+ {
+ gold_assert(index != 0);
+ this->dynsym_index_ = index;
+ }
+
+ // Return the output virtual address of OFFSET relative to the start
+ // of input section SHNDX in object OBJECT.
+ uint64_t
+ output_address(const Relobj* object, unsigned int shndx,
+ off_t offset) const;
+
+ // Set the address of the Output_section. For a typical
+ // Output_section, there is nothing to do, but if there are any
+ // Output_section_data objects we need to set the final addresses
+ // here.
+ void
+ do_set_address(uint64_t, off_t);
+
+ // Write the data to the file. For a typical Output_section, this
+ // does nothing: the data is written out by calling Object::Relocate
+ // on each input object. But if there are any Output_section_data
+ // objects we do need to write them out here.
+ void
+ do_write(Output_file*);
+
+ // Return the address alignment--function required by parent class.
+ uint64_t
+ do_addralign() const
+ { return this->addralign_; }
+
+ // Return whether this is an Output_section.
+ bool
+ do_is_section() const
+ { return true; }
+
+ // Return whether this is a section of the specified type.
+ bool
+ do_is_section_type(elfcpp::Elf_Word type) const
+ { return this->type_ == type; }
+
+ // Return whether the specified section flag is set.
+ bool
+ do_is_section_flag_set(elfcpp::Elf_Xword flag) const
+ { return (this->flags_ & flag) != 0; }
+
+ // Write the section header into *OPHDR.
+ template<int size, bool big_endian>
+ void
+ write_header(const Layout*, const Stringpool*,
+ elfcpp::Shdr_write<size, big_endian>*) const;
+
+ private:
+ // In some cases we need to keep a list of the input sections
+ // associated with this output section. We only need the list if we
+ // might have to change the offsets of the input section within the
+ // output section after we add the input section. The ordinary
+ // input sections will be written out when we process the object
+ // file, and as such we don't need to track them here. We do need
+ // to track Output_section_data objects here. We store instances of
+ // this structure in a std::vector, so it must be a POD. There can
+ // be many instances of this structure, so we use a union to save
+ // some space.
+ class Input_section
+ {
+ public:
+ Input_section()
+ : shndx_(0), p2align_(0)
+ {
+ this->u1_.data_size = 0;
+ this->u2_.object = NULL;
+ }
+
+ // For an ordinary input section.
+ Input_section(Relobj* object, unsigned int shndx, off_t data_size,
+ uint64_t addralign)
+ : shndx_(shndx),
+ p2align_(ffsll(static_cast<long long>(addralign)))
+ {
+ gold_assert(shndx != OUTPUT_SECTION_CODE
+ && shndx != MERGE_DATA_SECTION_CODE
+ && shndx != MERGE_STRING_SECTION_CODE);
+ this->u1_.data_size = data_size;
+ this->u2_.object = object;
+ }
+
+ // For a non-merge output section.
+ Input_section(Output_section_data* posd)
+ : shndx_(OUTPUT_SECTION_CODE),
+ p2align_(ffsll(static_cast<long long>(posd->addralign())))
+ {
+ this->u1_.data_size = 0;
+ this->u2_.posd = posd;
+ }
+
+ // For a merge section.
+ Input_section(Output_section_data* posd, bool is_string, uint64_t entsize)
+ : shndx_(is_string
+ ? MERGE_STRING_SECTION_CODE
+ : MERGE_DATA_SECTION_CODE),
+ p2align_(ffsll(static_cast<long long>(posd->addralign())))
+ {
+ this->u1_.entsize = entsize;
+ this->u2_.posd = posd;
+ }
+
+ // The required alignment.
+ uint64_t
+ addralign() const
+ {
+ return (this->p2align_ == 0
+ ? 0
+ : static_cast<uint64_t>(1) << (this->p2align_ - 1));
+ }
+
+ // Return the required size.
+ off_t
+ data_size() const;
+
+ // Return whether this is a merge section which matches the
+ // parameters.
+ bool
+ is_merge_section(bool is_string, uint64_t entsize) const
+ {
+ return (this->shndx_ == (is_string
+ ? MERGE_STRING_SECTION_CODE
+ : MERGE_DATA_SECTION_CODE)
+ && this->u1_.entsize == entsize);
+ }
+
+ // Set the output section.
+ void
+ set_output_section(Output_section* os)
+ {
+ gold_assert(!this->is_input_section());
+ this->u2_.posd->set_output_section(os);
+ }
+
+ // Set the address and file offset. This is called during
+ // Layout::finalize. SECOFF is the file offset of the enclosing
+ // section.
+ void
+ set_address(uint64_t addr, off_t off, off_t secoff);
+
+ // Add an input section, for SHF_MERGE sections.
+ bool
+ add_input_section(Relobj* object, unsigned int shndx)
+ {
+ gold_assert(this->shndx_ == MERGE_DATA_SECTION_CODE
+ || this->shndx_ == MERGE_STRING_SECTION_CODE);
+ return this->u2_.posd->add_input_section(object, shndx);
+ }
+
+ // Given an input OBJECT, an input section index SHNDX within that
+ // object, and an OFFSET relative to the start of that input
+ // section, return whether or not the output address is known.
+ // OUTPUT_SECTION_ADDRESS is the address of the output section
+ // which this is a part of. If this function returns true, it
+ // sets *POUTPUT to the output address.
+ bool
+ output_address(const Relobj* object, unsigned int shndx, off_t offset,
+ uint64_t output_section_address, uint64_t *poutput) const;
+
+ // Write out the data. This does nothing for an input section.
+ void
+ write(Output_file*);
+
+ private:
+ // Code values which appear in shndx_. If the value is not one of
+ // these codes, it is the input section index in the object file.
+ enum
+ {
+ // An Output_section_data.
+ OUTPUT_SECTION_CODE = -1U,
+ // An Output_section_data for an SHF_MERGE section with
+ // SHF_STRINGS not set.
+ MERGE_DATA_SECTION_CODE = -2U,
+ // An Output_section_data for an SHF_MERGE section with
+ // SHF_STRINGS set.
+ MERGE_STRING_SECTION_CODE = -3U
+ };
+
+ // Whether this is an input section.
+ bool
+ is_input_section() const
+ {
+ return (this->shndx_ != OUTPUT_SECTION_CODE
+ && this->shndx_ != MERGE_DATA_SECTION_CODE
+ && this->shndx_ != MERGE_STRING_SECTION_CODE);
+ }
+
+ // For an ordinary input section, this is the section index in the
+ // input file. For an Output_section_data, this is
+ // OUTPUT_SECTION_CODE or MERGE_DATA_SECTION_CODE or
+ // MERGE_STRING_SECTION_CODE.
+ unsigned int shndx_;
+ // The required alignment, stored as a power of 2.
+ unsigned int p2align_;
+ union
+ {
+ // For an ordinary input section, the section size.
+ off_t data_size;
+ // For OUTPUT_SECTION_CODE, this is not used. For
+ // MERGE_DATA_SECTION_CODE or MERGE_STRING_SECTION_CODE, the
+ // entity size.
+ uint64_t entsize;
+ } u1_;
+ union
+ {
+ // For an ordinary input section, the object which holds the
+ // input section.
+ Relobj* object;
+ // For OUTPUT_SECTION_CODE or MERGE_DATA_SECTION_CODE or
+ // MERGE_STRING_SECTION_CODE, the data.
+ Output_section_data* posd;
+ } u2_;
+ };
+
+ typedef std::vector<Input_section> Input_section_list;
+
+ // Add a new output section by Input_section.
+ void
+ add_output_section_data(Input_section*);
+
+ // Add an SHF_MERGE input section. Returns true if the section was
+ // handled.
+ bool
+ add_merge_input_section(Relobj* object, unsigned int shndx, uint64_t flags,
+ uint64_t entsize, uint64_t addralign);
+
+ // Add an output SHF_MERGE section POSD to this output section.
+ // IS_STRING indicates whether it is a SHF_STRINGS section, and
+ // ENTSIZE is the entity size. This returns the entry added to
+ // input_sections_.
+ void
+ add_output_merge_section(Output_section_data* posd, bool is_string,
+ uint64_t entsize);
+
+ // Most of these fields are only valid after layout.
+
+ // The name of the section. This will point into a Stringpool.
+ const char* name_;
+ // The section address is in the parent class.
+ // The section alignment.
+ uint64_t addralign_;
+ // The section entry size.
+ uint64_t entsize_;
+ // The file offset is in the parent class.
+ // Set the section link field to the index of this section.
+ const Output_data* link_section_;
+ // If link_section_ is NULL, this is the link field.
+ unsigned int link_;
+ // Set the section info field to the index of this section.
+ const Output_data* info_section_;
+ // If info_section_ is NULL, this is the section info field.
+ unsigned int info_;
+ // The section type.
+ elfcpp::Elf_Word type_;
+ // The section flags.
+ elfcpp::Elf_Xword flags_;
+ // The section index.
+ unsigned int out_shndx_;
+ // If there is a STT_SECTION for this output section in the normal
+ // symbol table, this is the symbol index. This starts out as zero.
+ // It is initialized in Layout::finalize() to be the index, or -1U
+ // if there isn't one.
+ unsigned int symtab_index_;
+ // If there is a STT_SECTION for this output section in the dynamic
+ // symbol table, this is the symbol index. This starts out as zero.
+ // It is initialized in Layout::finalize() to be the index, or -1U
+ // if there isn't one.
+ unsigned int dynsym_index_;
+ // The input sections. This will be empty in cases where we don't
+ // need to keep track of them.
+ Input_section_list input_sections_;
+ // The offset of the first entry in input_sections_.
+ off_t first_input_offset_;
+ // Whether this output section needs a STT_SECTION symbol in the
+ // normal symbol table. This will be true if there is a relocation
+ // which needs it.
+ bool needs_symtab_index_ : 1;
+ // Whether this output section needs a STT_SECTION symbol in the
+ // dynamic symbol table. This will be true if there is a dynamic
+ // relocation which needs it.
+ bool needs_dynsym_index_ : 1;
+ // Whether the link field of this output section should point to the
+ // normal symbol table.
+ bool should_link_to_symtab_ : 1;
+ // Whether the link field of this output section should point to the
+ // dynamic symbol table.
+ bool should_link_to_dynsym_ : 1;
+};
+
+// An output segment. PT_LOAD segments are built from collections of
+// output sections. Other segments typically point within PT_LOAD
+// segments, and are built directly as needed.
+
+class Output_segment
+{
+ public:
+ // Create an output segment, specifying the type and flags.
+ Output_segment(elfcpp::Elf_Word, elfcpp::Elf_Word);
+
+ // Return the virtual address.
+ uint64_t
+ vaddr() const
+ { return this->vaddr_; }
+
+ // Return the physical address.
+ uint64_t
+ paddr() const
+ { return this->paddr_; }
+
+ // Return the segment type.
+ elfcpp::Elf_Word
+ type() const
+ { return this->type_; }
+
+ // Return the segment flags.
+ elfcpp::Elf_Word
+ flags() const
+ { return this->flags_; }
+
+ // Return the memory size.
+ uint64_t
+ memsz() const
+ { return this->memsz_; }
+
+ // Return the file size.
+ off_t
+ filesz() const
+ { return this->filesz_; }
+
+ // Return the maximum alignment of the Output_data.
+ uint64_t
+ addralign();
+
+ // Add an Output_section to this segment.
+ void
+ add_output_section(Output_section* os, elfcpp::Elf_Word seg_flags)
+ { this->add_output_section(os, seg_flags, false); }
+
+ // Add an Output_section to the start of this segment.
+ void
+ add_initial_output_section(Output_section* os, elfcpp::Elf_Word seg_flags)
+ { this->add_output_section(os, seg_flags, true); }
+
+ // Add an Output_data (which is not an Output_section) to the start
+ // of this segment.
+ void
+ add_initial_output_data(Output_data*);
+
+ // Set the address of the segment to ADDR and the offset to *POFF
+ // (aligned if necessary), and set the addresses and offsets of all
+ // contained output sections accordingly. Set the section indexes
+ // of all contained output sections starting with *PSHNDX. Return
+ // the address of the immediately following segment. Update *POFF
+ // and *PSHNDX. This should only be called for a PT_LOAD segment.
+ uint64_t
+ set_section_addresses(uint64_t addr, off_t* poff, unsigned int* pshndx);
+
+ // Set the offset of this segment based on the section. This should
+ // only be called for a non-PT_LOAD segment.
+ void
+ set_offset();
+
+ // Return the number of output sections.
+ unsigned int
+ output_section_count() const;
+
+ // Write the segment header into *OPHDR.
+ template<int size, bool big_endian>
+ void
+ write_header(elfcpp::Phdr_write<size, big_endian>*);
+
+ // Write the section headers of associated sections into V.
+ template<int size, bool big_endian>
+ unsigned char*
+ write_section_headers(const Layout*, const Stringpool*, unsigned char* v,
+ unsigned int* pshndx ACCEPT_SIZE_ENDIAN) const;
+
+ private:
+ Output_segment(const Output_segment&);
+ Output_segment& operator=(const Output_segment&);
+
+ typedef std::list<Output_data*> Output_data_list;
+
+ // Add an Output_section to this segment, specifying front or back.
+ void
+ add_output_section(Output_section*, elfcpp::Elf_Word seg_flags,
+ bool front);
+
+ // Find the maximum alignment in an Output_data_list.
+ static uint64_t
+ maximum_alignment(const Output_data_list*);
+
+ // Set the section addresses in an Output_data_list.
+ uint64_t
+ set_section_list_addresses(Output_data_list*, uint64_t addr, off_t* poff,
+ unsigned int* pshndx);
+
+ // Return the number of Output_sections in an Output_data_list.
+ unsigned int
+ output_section_count_list(const Output_data_list*) const;
+
+ // Write the section headers in the list into V.
+ template<int size, bool big_endian>
+ unsigned char*
+ write_section_headers_list(const Layout*, const Stringpool*,
+ const Output_data_list*, unsigned char* v,
+ unsigned int* pshdx ACCEPT_SIZE_ENDIAN) const;
+
+ // The list of output data with contents attached to this segment.
+ Output_data_list output_data_;
+ // The list of output data without contents attached to this segment.
+ Output_data_list output_bss_;
+ // The segment virtual address.
+ uint64_t vaddr_;
+ // The segment physical address.
+ uint64_t paddr_;
+ // The size of the segment in memory.
+ uint64_t memsz_;
+ // The segment alignment.
+ uint64_t align_;
+ // The offset of the segment data within the file.
+ off_t offset_;
+ // The size of the segment data in the file.
+ off_t filesz_;
+ // The segment type;
+ elfcpp::Elf_Word type_;
+ // The segment flags.
+ elfcpp::Elf_Word flags_;
+ // Whether we have set align_.
+ bool is_align_known_;
+};
+
+// This class represents the output file.
+
+class Output_file
+{
+ public:
+ Output_file(const General_options& options);
+
+ // Open the output file. FILE_SIZE is the final size of the file.
+ void
+ open(off_t file_size);
+
+ // Close the output file and make sure there are no error.
+ void
+ close();
+
+ // We currently always use mmap which makes the view handling quite
+ // simple. In the future we may support other approaches.
+
+ // Write data to the output file.
+ void
+ write(off_t offset, const void* data, off_t len)
+ { memcpy(this->base_ + offset, data, len); }
+
+ // Get a buffer to use to write to the file, given the offset into
+ // the file and the size.
+ unsigned char*
+ get_output_view(off_t start, off_t size)
+ {
+ gold_assert(start >= 0 && size >= 0 && start + size <= this->file_size_);
+ return this->base_ + start;
+ }
+
+ // VIEW must have been returned by get_output_view. Write the
+ // buffer to the file, passing in the offset and the size.
+ void
+ write_output_view(off_t, off_t, unsigned char*)
+ { }
+
+ private:
+ // General options.
+ const General_options& options_;
+ // File name.
+ const char* name_;
+ // File descriptor.
+ int o_;
+ // File size.
+ off_t file_size_;
+ // Base of file mapped into memory.
+ unsigned char* base_;
+};
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_OUTPUT_H)
diff --git a/gold/po/Make-in b/gold/po/Make-in
new file mode 100644
index 000000000000..88ce78fa6e46
--- /dev/null
+++ b/gold/po/Make-in
@@ -0,0 +1,256 @@
+# Makefile for program source directory in GNU NLS utilities package.
+# Copyright (C) 1995, 1996, 1997 by Ulrich Drepper <drepper@gnu.ai.mit.edu>
+# Copyright 2003, 2006 Free Software Foundation, Inc.
+#
+# This file may be copied and used freely without restrictions. It can
+# be used in projects which are not available under the GNU Public License
+# but which still want to provide support for the GNU gettext functionality.
+# Please note that the actual code is *not* freely available.
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+
+SHELL = /bin/sh
+@SET_MAKE@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+top_builddir = @top_builddir@
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+datadir = $(prefix)/@DATADIRNAME@
+localedir = $(datadir)/locale
+gnulocaledir = $(prefix)/share/locale
+gettextsrcdir = $(prefix)/share/gettext/po
+subdir = po
+
+DESTDIR =
+
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+
+CC = @CC@
+GENCAT = @GENCAT@
+GMSGFMT = PATH=../src:$$PATH @GMSGFMT@
+MSGFMT = @MSGFMT@
+XGETTEXT = PATH=../src:$$PATH @XGETTEXT@
+MSGMERGE = PATH=../src:$$PATH msgmerge
+
+DEFS = @DEFS@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+
+INCLUDES = -I.. -I$(top_srcdir)/intl
+
+COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) $(XCFLAGS)
+
+SOURCES = cat-id-tbl.c
+POFILES = @POFILES@
+GMOFILES = @GMOFILES@
+DISTFILES = ChangeLog Makefile.in.in POTFILES.in $(PACKAGE).pot \
+stamp-cat-id $(POFILES) $(GMOFILES) $(SOURCES)
+
+POTFILES = \
+
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+INSTOBJEXT = @INSTOBJEXT@
+
+.SUFFIXES:
+.SUFFIXES: .c .o .po .pox .gmo .mo .msg .cat
+
+.c.o:
+ $(COMPILE) $<
+
+.po.pox:
+ $(MAKE) $(PACKAGE).pot
+ $(MSGMERGE) $< $(srcdir)/$(PACKAGE).pot -o $*.pox
+
+.po.mo:
+ $(MSGFMT) -o $@ $<
+
+.po.gmo:
+ file=$(srcdir)/`echo $* | sed 's,.*/,,'`.gmo \
+ && rm -f $$file && $(GMSGFMT) -o $$file $<
+
+.po.cat:
+ sed -f ../intl/po2msg.sed < $< > $*.msg \
+ && rm -f $@ && $(GENCAT) $@ $*.msg
+
+
+all: all-@USE_NLS@
+
+all-yes: $(CATALOGS) @MAINT@ $(PACKAGE).pot
+all-no:
+
+$(srcdir)/$(PACKAGE).pot: $(POTFILES)
+ $(XGETTEXT) --default-domain=$(PACKAGE) --directory=$(top_srcdir) \
+ --add-comments --keyword=_ --keyword=N_ \
+ --files-from=$(srcdir)/POTFILES.in
+ rm -f $(srcdir)/$(PACKAGE).pot
+ mv $(PACKAGE).po $(srcdir)/$(PACKAGE).pot
+
+$(srcdir)/cat-id-tbl.c: stamp-cat-id; @:
+$(srcdir)/stamp-cat-id: $(PACKAGE).pot
+ rm -f cat-id-tbl.tmp
+ sed -f ../intl/po2tbl.sed $(srcdir)/$(PACKAGE).pot \
+ | sed -e "s/@PACKAGE NAME@/$(PACKAGE)/" > cat-id-tbl.tmp
+ if cmp -s cat-id-tbl.tmp $(srcdir)/cat-id-tbl.c; then \
+ rm cat-id-tbl.tmp; \
+ else \
+ echo cat-id-tbl.c changed; \
+ rm -f $(srcdir)/cat-id-tbl.c; \
+ mv cat-id-tbl.tmp $(srcdir)/cat-id-tbl.c; \
+ fi
+ cd $(srcdir) && rm -f stamp-cat-id && echo timestamp > stamp-cat-id
+
+
+install: install-exec install-data
+install-exec:
+install-info:
+install-html:
+install-data: install-data-@USE_NLS@
+install-data-no: all
+install-data-yes: all
+ if test -r $(MKINSTALLDIRS); then \
+ $(MKINSTALLDIRS) $(DESTDIR)$(datadir); \
+ else \
+ $(top_srcdir)/mkinstalldirs $(DESTDIR)$(datadir); \
+ fi
+ @catalogs='$(CATALOGS)'; \
+ for cat in $$catalogs; do \
+ cat=`basename $$cat`; \
+ case "$$cat" in \
+ *.gmo) destdir=$(gnulocaledir);; \
+ *) destdir=$(localedir);; \
+ esac; \
+ lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \
+ dir=$(DESTDIR)$$destdir/$$lang/LC_MESSAGES; \
+ if test -r $(MKINSTALLDIRS); then \
+ $(MKINSTALLDIRS) $$dir; \
+ else \
+ $(top_srcdir)/mkinstalldirs $$dir; \
+ fi; \
+ if test -r $$cat; then \
+ $(INSTALL_DATA) $$cat $$dir/$(PACKAGE)$(INSTOBJEXT); \
+ echo "installing $$cat as $$dir/$(PACKAGE)$(INSTOBJEXT)"; \
+ else \
+ $(INSTALL_DATA) $(srcdir)/$$cat $$dir/$(PACKAGE)$(INSTOBJEXT); \
+ echo "installing $(srcdir)/$$cat as" \
+ "$$dir/$(PACKAGE)$(INSTOBJEXT)"; \
+ fi; \
+ if test -r $$cat.m; then \
+ $(INSTALL_DATA) $$cat.m $$dir/$(PACKAGE)$(INSTOBJEXT).m; \
+ echo "installing $$cat.m as $$dir/$(PACKAGE)$(INSTOBJEXT).m"; \
+ else \
+ if test -r $(srcdir)/$$cat.m ; then \
+ $(INSTALL_DATA) $(srcdir)/$$cat.m \
+ $$dir/$(PACKAGE)$(INSTOBJEXT).m; \
+ echo "installing $(srcdir)/$$cat as" \
+ "$$dir/$(PACKAGE)$(INSTOBJEXT).m"; \
+ else \
+ true; \
+ fi; \
+ fi; \
+ done
+ if test "$(PACKAGE)" = "gettext"; then \
+ if test -r $(MKINSTALLDIRS); then \
+ $(MKINSTALLDIRS) $(DESTDIR)$(gettextsrcdir); \
+ else \
+ $(top_srcdir)/mkinstalldirs $(DESTDIR)$(gettextsrcdir); \
+ fi; \
+ $(INSTALL_DATA) $(srcdir)/Makefile.in.in \
+ $(DESTDIR)$(gettextsrcdir)/Makefile.in.in; \
+ else \
+ : ; \
+ fi
+
+# Define this as empty until I found a useful application.
+installcheck:
+
+uninstall:
+ catalogs='$(CATALOGS)'; \
+ for cat in $$catalogs; do \
+ cat=`basename $$cat`; \
+ lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \
+ rm -f $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(PACKAGE)$(INSTOBJEXT); \
+ rm -f $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(PACKAGE)$(INSTOBJEXT).m; \
+ rm -f $(DESTDIR)$(gnulocaledir)/$$lang/LC_MESSAGES/$(PACKAGE)$(INSTOBJEXT); \
+ rm -f $(DESTDIR)$(gnulocaledir)/$$lang/LC_MESSAGES/$(PACKAGE)$(INSTOBJEXT).m; \
+ done
+ rm -f $(DESTDIR)$(gettextsrcdir)/po-Makefile.in.in
+
+check: all
+
+cat-id-tbl.o: ../intl/libgettext.h
+
+html dvi pdf ps info tags TAGS ID:
+
+mostlyclean:
+ rm -f core core.* *.pox $(PACKAGE).po *.old.po cat-id-tbl.tmp
+ rm -fr *.o
+
+clean: mostlyclean
+
+distclean: clean
+ rm -f Makefile Makefile.in POTFILES *.mo *.msg *.cat *.cat.m
+
+maintainer-clean: distclean
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+ rm -f $(GMOFILES)
+
+distdir = ../$(PACKAGE)-$(VERSION)/$(subdir)
+dist distdir: update-po $(DISTFILES)
+ dists="$(DISTFILES)"; \
+ for file in $$dists; do \
+ ln $(srcdir)/$$file $(distdir) 2> /dev/null \
+ || cp -p $(srcdir)/$$file $(distdir); \
+ done
+
+update-po: Makefile
+ $(MAKE) $(PACKAGE).pot
+ PATH=`pwd`/../src:$$PATH; \
+ cd $(srcdir); \
+ catalogs='$(CATALOGS)'; \
+ for cat in $$catalogs; do \
+ cat=`basename $$cat`; \
+ lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \
+ mv $$lang.po $$lang.old.po; \
+ echo "$$lang:"; \
+ if $(MSGMERGE) $$lang.old.po $(PACKAGE).pot -o $$lang.po; then \
+ rm -f $$lang.old.po; \
+ else \
+ echo "msgmerge for $$cat failed!"; \
+ rm -f $$lang.po; \
+ mv $$lang.old.po $$lang.po; \
+ fi; \
+ done
+
+POTFILES: POTFILES.in
+ ( if test 'x$(srcdir)' != 'x.'; then \
+ posrcprefix='$(top_srcdir)/'; \
+ else \
+ posrcprefix="../"; \
+ fi; \
+ rm -f $@-t $@ \
+ && (sed -e '/^#/d' -e '/^[ ]*$$/d' \
+ -e "s@.*@ $$posrcprefix& \\\\@" < $(srcdir)/$@.in \
+ | sed -e '$$s/\\$$//') > $@-t \
+ && chmod a-w $@-t \
+ && mv $@-t $@ )
+
+POTFILES.in: @MAINT@ ../Makefile
+ cd .. && $(MAKE) po/POTFILES.in
+
+Makefile: Make-in ../config.status POTFILES
+ cd .. \
+ && CONFIG_FILES=$(subdir)/Makefile.in:$(subdir)/Make-in \
+ CONFIG_HEADERS= $(SHELL) ./config.status
+
+# Tell versions [3.59,3.63) of GNU make not to export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/gold/po/POTFILES.in b/gold/po/POTFILES.in
new file mode 100644
index 000000000000..0c4145af71a7
--- /dev/null
+++ b/gold/po/POTFILES.in
@@ -0,0 +1,46 @@
+archive.cc
+archive.h
+common.cc
+common.h
+defstd.cc
+defstd.h
+dirsearch.cc
+dirsearch.h
+dynobj.cc
+dynobj.h
+fileread.cc
+fileread.h
+gold.cc
+gold.h
+gold-threads.cc
+gold-threads.h
+i386.cc
+layout.cc
+layout.h
+merge.cc
+merge.h
+object.cc
+object.h
+options.cc
+options.h
+output.cc
+output.h
+readsyms.cc
+readsyms.h
+reloc.cc
+reloc.h
+reloc-types.h
+resolve.cc
+script.cc
+script-c.h
+script.h
+stringpool.cc
+stringpool.h
+symtab.cc
+symtab.h
+target.h
+target-reloc.h
+target-select.cc
+target-select.h
+workqueue.cc
+workqueue.h
diff --git a/gold/po/gold.pot b/gold/po/gold.pot
new file mode 100644
index 000000000000..79d0628dc44f
--- /dev/null
+++ b/gold/po/gold.pot
@@ -0,0 +1,654 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2007-05-16 10:40-0700\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: archive.cc:62
+#, c-format
+msgid "%s: %s: no archive symbol table (run ranlib)\n"
+msgstr ""
+
+#: archive.cc:91
+#, c-format
+msgid "%s: %s: bad archive symbol table names\n"
+msgstr ""
+
+#: archive.cc:129
+#, c-format
+msgid "%s; %s: malformed archive header at %ld\n"
+msgstr ""
+
+#: archive.cc:150
+#, c-format
+msgid "%s: %s: malformed archive header size at %ld\n"
+msgstr ""
+
+#: archive.cc:162
+#, c-format
+msgid "%s: %s: malformed archive header name at %ld\n"
+msgstr ""
+
+#: archive.cc:188
+#, c-format
+msgid "%s: %s: bad extended name index at %ld\n"
+msgstr ""
+
+#: archive.cc:199
+#, c-format
+msgid "%s: %s: bad extended name entry at header %ld\n"
+msgstr ""
+
+#: archive.cc:280 archive.cc:293
+#, c-format
+msgid "%s: %s: member at %ld is not an ELF object"
+msgstr ""
+
+#: dirsearch.cc:50
+#, c-format
+msgid "can not read directory %s"
+msgstr ""
+
+#: dynobj.cc:109
+#, c-format
+msgid "%s: %s: unexpected duplicate type %u section: %u, %u\n"
+msgstr ""
+
+#: dynobj.cc:150
+#, c-format
+msgid "%s: %s: unexpected link in section %u header: %u != %u\n"
+msgstr ""
+
+#: dynobj.cc:188
+#, c-format
+msgid "%s: %s: DYNAMIC section %u link out of range: %u\n"
+msgstr ""
+
+#: dynobj.cc:198
+#, c-format
+msgid "%s: %s: DYNAMIC section %u link %u is not a strtab\n"
+msgstr ""
+
+#: dynobj.cc:220
+#, c-format
+msgid "%s: %s: DT_SONAME value out of range: %lld >= %lld\n"
+msgstr ""
+
+#: dynobj.cc:237
+#, c-format
+msgid "%s: %s: missing DT_NULL in dynamic segment\n"
+msgstr ""
+
+#: dynobj.cc:285
+#, c-format
+msgid "%s: %s: invalid dynamic symbol table name index: %u\n"
+msgstr ""
+
+#: dynobj.cc:293
+#, c-format
+msgid "%s: %s: dynamic symbol table name section has wrong type: %u\n"
+msgstr ""
+
+#: dynobj.cc:368 object.cc:420
+#, c-format
+msgid "%s: %s: bad section name offset for section %u: %lu\n"
+msgstr ""
+
+#: dynobj.cc:399
+#, c-format
+msgid "%s: %s: duplicate definition for version %u\n"
+msgstr ""
+
+#: dynobj.cc:431
+#, c-format
+msgid "%s: %s: unexpected verdef version %u\n"
+msgstr ""
+
+#: dynobj.cc:447
+#, c-format
+msgid "%s: %s: verdef vd_cnt field too small: %u\n"
+msgstr ""
+
+#: dynobj.cc:456
+#, c-format
+msgid "%s: %s: verdef vd_aux field out of range: %u\n"
+msgstr ""
+
+#: dynobj.cc:468
+#, c-format
+msgid "%s: %s: verdaux vda_name field out of range: %u\n"
+msgstr ""
+
+#: dynobj.cc:479
+#, c-format
+msgid "%s: %s: verdef vd_next field out of range: %u\n"
+msgstr ""
+
+#: dynobj.cc:513
+#, c-format
+msgid "%s: %s: unexpected verneed version %u\n"
+msgstr ""
+
+#: dynobj.cc:524
+#, c-format
+msgid "%s: %s: verneed vn_aux field out of range: %u\n"
+msgstr ""
+
+#: dynobj.cc:539
+#, c-format
+msgid "%s: %s: vernaux vna_name field out of range: %u\n"
+msgstr ""
+
+#: dynobj.cc:552
+#, c-format
+msgid "%s: %s: verneed vna_next field out of range: %u\n"
+msgstr ""
+
+#: dynobj.cc:565
+#, c-format
+msgid "%s: %s: verneed vn_next field out of range: %u\n"
+msgstr ""
+
+#: dynobj.cc:613
+#, c-format
+msgid "%s: %s: size of dynamic symbols is not multiple of symbol size\n"
+msgstr ""
+
+#: dynobj.cc:1241
+#, c-format
+msgid "%s: symbol %s has undefined version %s\n"
+msgstr ""
+
+#: fileread.cc:55
+#, c-format
+msgid "%s: warning: close(%s) failed: %s"
+msgstr ""
+
+#: fileread.cc:143
+#, c-format
+msgid "%s: %s: lseek to %lld failed: %s"
+msgstr ""
+
+#: fileread.cc:153
+#, c-format
+msgid "%s: %s: read failed: %s\n"
+msgstr ""
+
+#: 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:365
+#, c-format
+msgid "%s: cannot find %s\n"
+msgstr ""
+
+#: fileread.cc:373
+#, c-format
+msgid "%s: cannot open %s: %s\n"
+msgstr ""
+
+#: gold.cc:106
+msgid "no input files"
+msgstr ""
+
+#: gold-threads.cc:46
+msgid "pthead_mutextattr_init failed"
+msgstr ""
+
+#: gold-threads.cc:49
+msgid "pthread_mutextattr_settype failed"
+msgstr ""
+
+#: gold-threads.cc:53
+msgid "pthread_mutex_init failed"
+msgstr ""
+
+#: gold-threads.cc:56
+msgid "pthread_mutexattr_destroy failed"
+msgstr ""
+
+#: gold-threads.cc:62
+msgid "pthread_mutex_destroy failed"
+msgstr ""
+
+#: gold-threads.cc:69
+msgid "pthread_mutex_lock failed"
+msgstr ""
+
+#: gold-threads.cc:76
+msgid "pthread_mutex_unlock failed"
+msgstr ""
+
+#: gold-threads.cc:157
+msgid "pthread_cond_init failed"
+msgstr ""
+
+#: gold-threads.cc:163
+msgid "pthread_cond_destroy failed"
+msgstr ""
+
+#: gold-threads.cc:170
+msgid "pthread_cond_wait failed"
+msgstr ""
+
+#: gold-threads.cc:177
+msgid "pthread_cond_signal failed"
+msgstr ""
+
+#. FIXME: This needs to specify the location somehow.
+#: i386.cc:100
+#, c-format
+msgid "%s: missing expected TLS relocation\n"
+msgstr ""
+
+#: i386.cc:729 i386.cc:870 i386.cc:1136
+#, c-format
+msgid "%s: %s: unexpected reloc %u in object file\n"
+msgstr ""
+
+#: i386.cc:765 i386.cc:784
+#, c-format
+msgid "%s: %s: unsupported reloc %u against local symbol\n"
+msgstr ""
+
+#: i386.cc:906 i386.cc:927
+#, c-format
+msgid "%s: %s: unsupported reloc %u against global symbol %s\n"
+msgstr ""
+
+#: i386.cc:950
+#, c-format
+msgid "%s: %s: unsupported RELA reloc section\n"
+msgstr ""
+
+#: i386.cc:1041
+#, c-format
+msgid "%s: %s: missing expected TLS relocation\n"
+msgstr ""
+
+#: i386.cc:1168 i386.cc:1245 i386.cc:1256
+#, c-format
+msgid "%s: %s: unsupported reloc %u\n"
+msgstr ""
+
+#: i386.cc:1195
+#, c-format
+msgid "%s: %s: TLS reloc but no TLS segment\n"
+msgstr ""
+
+#: i386.cc:1230
+#, c-format
+msgid "%s: %s: unsupported reloc type %u\n"
+msgstr ""
+
+#: i386.cc:1439
+#, c-format
+msgid "%s: %s: TLS relocation out of range\n"
+msgstr ""
+
+#: i386.cc:1457
+#, c-format
+msgid "%s: %s: TLS relocation against invalid instruction\n"
+msgstr ""
+
+#: merge.cc:252
+#, c-format
+msgid ""
+"%s: %s: mergeable string section length not multiple of character size\n"
+msgstr ""
+
+#: merge.cc:269
+#, c-format
+msgid "%s: %s: entry in mergeable string section not null terminated\n"
+msgstr ""
+
+#: object.cc:30
+#, c-format
+msgid "%s: %s: unsupported ELF machine number %d\n"
+msgstr ""
+
+#: object.cc:86
+#, c-format
+msgid "%s: %s: section name section has wrong type: %u\n"
+msgstr ""
+
+#: object.cc:228
+#, c-format
+msgid "%s: %s: invalid symbol table name index: %u\n"
+msgstr ""
+
+#: object.cc:236
+#, c-format
+msgid "%s: %s: symbol table name section has wrong type: %u\n"
+msgstr ""
+
+#: object.cc:292
+#, c-format
+msgid "%s: %s: section group %u info %u out of range\n"
+msgstr ""
+
+#: object.cc:309
+#, c-format
+msgid "%s: %s: symbol %u name offset %u out of range\n"
+msgstr ""
+
+#: object.cc:343
+#, c-format
+msgid "%s: %s: section %u in section group %u out of range"
+msgstr ""
+
+#: object.cc:487
+#, c-format
+msgid "%s: %s: size of symbols is not multiple of symbol size\n"
+msgstr ""
+
+#: object.cc:575
+#, c-format
+msgid "%s: %s: unknown section index %u for local symbol %u\n"
+msgstr ""
+
+#: object.cc:586
+#, c-format
+msgid "%s: %s: local symbol %u section index %u out of range\n"
+msgstr ""
+
+#: object.cc:620
+#, c-format
+msgid "%s: %s: local symbol %u section name out of range: %u >= %u\n"
+msgstr ""
+
+#: object.cc:834
+#, c-format
+msgid "%s: %s: unsupported ELF file type %d\n"
+msgstr ""
+
+#: object.cc:853 object.cc:906 object.cc:927
+#, c-format
+msgid "%s: %s: ELF file too short\n"
+msgstr ""
+
+#: object.cc:862
+#, c-format
+msgid "%s: %s: invalid ELF version 0\n"
+msgstr ""
+
+#: object.cc:865
+#, c-format
+msgid "%s: %s: unsupported ELF version %d\n"
+msgstr ""
+
+#: object.cc:873
+#, c-format
+msgid "%s: %s: invalid ELF class 0\n"
+msgstr ""
+
+#: object.cc:880
+#, c-format
+msgid "%s: %s: unsupported ELF class %d\n"
+msgstr ""
+
+#: object.cc:888
+#, c-format
+msgid "%s: %s: invalid ELF data encoding\n"
+msgstr ""
+
+#: object.cc:895
+#, c-format
+msgid "%s: %s: unsupported ELF data encoding %d\n"
+msgstr ""
+
+#: options.cc:115
+#, c-format
+msgid ""
+"Usage: %s [options] file...\n"
+"Options:\n"
+msgstr ""
+
+#: options.cc:227
+msgid "Search for library LIBNAME"
+msgstr ""
+
+#: options.cc:228
+msgid "-lLIBNAME --library LIBNAME"
+msgstr ""
+
+#: options.cc:230
+msgid "Start a library search group"
+msgstr ""
+
+#: options.cc:232
+msgid "End a library search group"
+msgstr ""
+
+#: options.cc:234
+msgid "Set dynamic linker path"
+msgstr ""
+
+#: options.cc:235
+msgid "-I PROGRAM, --dynamic-linker PROGRAM"
+msgstr ""
+
+#: options.cc:237
+msgid "Add directory to search path"
+msgstr ""
+
+#: options.cc:238
+msgid "-L DIR, --library-path DIR"
+msgstr ""
+
+#: options.cc:240
+msgid "Ignored for compatibility"
+msgstr ""
+
+#: options.cc:242
+msgid "Set output file name"
+msgstr ""
+
+#: options.cc:243
+msgid "-o FILE, --output FILE"
+msgstr ""
+
+#: options.cc:245
+msgid "Generate relocatable output"
+msgstr ""
+
+#: options.cc:247
+msgid "Generate shared library"
+msgstr ""
+
+#: options.cc:249
+msgid "Do not link against shared libraries"
+msgstr ""
+
+#: options.cc:252
+msgid "Only set DT_NEEDED for following dynamic libs if used"
+msgstr ""
+
+#: options.cc:255
+msgid "Always DT_NEEDED for following dynamic libs (default)"
+msgstr ""
+
+#: options.cc:257
+msgid "Report usage information"
+msgstr ""
+
+#: options.cc:393 options.cc:444 options.cc:523
+msgid "missing argument"
+msgstr ""
+
+#: options.cc:406 options.cc:453
+msgid "unknown option"
+msgstr ""
+
+#: options.cc:461
+#, c-format
+msgid "%s: missing group end"
+msgstr ""
+
+#: options.cc:536
+msgid "may not nest groups"
+msgstr ""
+
+#: options.cc:546
+msgid "group end without group start"
+msgstr ""
+
+#: options.cc:556
+#, c-format
+msgid "%s: use the --help option for usage information\n"
+msgstr ""
+
+#: options.cc:565 script.cc:1133
+#, c-format
+msgid "%s: %s: %s\n"
+msgstr ""
+
+#: options.cc:574
+#, c-format
+msgid "%s: -%c: %s\n"
+msgstr ""
+
+#: output.cc:903
+#, c-format
+msgid "%s: %s: invalid alignment %lu for section \"%s\"\n"
+msgstr ""
+
+#: output.cc:1519
+#, c-format
+msgid "%s: %s: open: %s\n"
+msgstr ""
+
+#: output.cc:1528
+#, c-format
+msgid "%s: %s: lseek: %s\n"
+msgstr ""
+
+#: output.cc:1535
+#, c-format
+msgid "%s: %s: write: %s\n"
+msgstr ""
+
+#: output.cc:1545
+#, c-format
+msgid "%s: %s: mmap: %s\n"
+msgstr ""
+
+#: output.cc:1559
+#, c-format
+msgid "%s: %s: munmap: %s\n"
+msgstr ""
+
+#: output.cc:1567
+#, c-format
+msgid "%s: %s: close: %s\n"
+msgstr ""
+
+#: readsyms.cc:93
+#, c-format
+msgid "%s: %s: ordinary object found in input group\n"
+msgstr ""
+
+#: readsyms.cc:136
+#, c-format
+msgid "%s: %s: file is empty\n"
+msgstr ""
+
+#. Here we have to handle any other input file types we need.
+#: readsyms.cc:149
+#, c-format
+msgid "%s: %s: not an object or archive\n"
+msgstr ""
+
+#: reloc.cc:169 reloc.cc:413
+#, c-format
+msgid "%s: %s: relocation section %u has bad info %u\n"
+msgstr ""
+
+#: reloc.cc:188 reloc.cc:430
+#, c-format
+msgid "%s: %s: relocation section %u uses unexpected symbol table %u\n"
+msgstr ""
+
+#: reloc.cc:204 reloc.cc:449
+#, c-format
+msgid "%s: %s: unexpected entsize for reloc section %u: %lu != %u"
+msgstr ""
+
+#: reloc.cc:215 reloc.cc:460
+#, c-format
+msgid "%s: %s: reloc section %u size %lu uneven"
+msgstr ""
+
+#: resolve.cc:147
+#, c-format
+msgid "%s: %s: invalid STB_LOCAL symbol %s in external symbols\n"
+msgstr ""
+
+#: resolve.cc:153
+#, c-format
+msgid "%s: %s: unsupported symbol binding %d for symbol %s\n"
+msgstr ""
+
+#: symtab.cc:450 symtab.cc:547
+#, c-format
+msgid "%s: %s: mixing 32-bit and 64-bit ELF objects\n"
+msgstr ""
+
+#: symtab.cc:467
+#, c-format
+msgid "%s: %s: bad global symbol name offset %u at %lu\n"
+msgstr ""
+
+#: symtab.cc:554
+#, c-format
+msgid "%s: %s: too few symbol versions\n"
+msgstr ""
+
+#: symtab.cc:574
+#, c-format
+msgid "%s: %s: bad symbol name offset %u at %lu\n"
+msgstr ""
+
+#: symtab.cc:618
+#, c-format
+msgid "%s: %s: versym for symbol %zu out of range: %u\n"
+msgstr ""
+
+#: symtab.cc:626
+#, c-format
+msgid "%s: %s: versym for symbol %zu has no name: %u\n"
+msgstr ""
+
+#: symtab.cc:1106 symtab.cc:1278
+#, c-format
+msgid "%s: %s: unsupported symbol section 0x%x\n"
+msgstr ""
+
+#: symtab.cc:1471
+#, c-format
+msgid "%s: %s: warning: %s\n"
+msgstr ""
+
+#: target-reloc.h:170
+#, c-format
+msgid "%s: %s: reloc has bad offset %zu\n"
+msgstr ""
+
+#: target-reloc.h:180
+#, c-format
+msgid "%s: %s: undefined reference to '%s'\n"
+msgstr ""
diff --git a/gold/readsyms.cc b/gold/readsyms.cc
new file mode 100644
index 000000000000..86828fc0a7c4
--- /dev/null
+++ b/gold/readsyms.cc
@@ -0,0 +1,313 @@
+// readsyms.cc -- read input file symbols for gold
+
+#include "gold.h"
+
+#include <cstring>
+
+#include "elfcpp.h"
+#include "options.h"
+#include "dirsearch.h"
+#include "symtab.h"
+#include "object.h"
+#include "archive.h"
+#include "script.h"
+#include "readsyms.h"
+
+namespace gold
+{
+
+// Class read_symbols.
+
+Read_symbols::~Read_symbols()
+{
+ // The this_blocker_ and next_blocker_ pointers are passed on to the
+ // Add_symbols task.
+}
+
+// Return whether a Read_symbols task is runnable. We can read an
+// ordinary input file immediately. For an archive specified using
+// -l, we have to wait until the search path is complete.
+
+Task::Is_runnable_type
+Read_symbols::is_runnable(Workqueue*)
+{
+ if (this->input_argument_->is_file()
+ && this->input_argument_->file().is_lib()
+ && this->dirpath_.token().is_blocked())
+ return IS_BLOCKED;
+
+ return IS_RUNNABLE;
+}
+
+// Return a Task_locker for a Read_symbols task. We don't need any
+// locks here.
+
+Task_locker*
+Read_symbols::locks(Workqueue*)
+{
+ return NULL;
+}
+
+// Run a Read_symbols task. This is where we actually read the
+// symbols and relocations.
+
+void
+Read_symbols::run(Workqueue* workqueue)
+{
+ if (this->input_argument_->is_group())
+ {
+ gold_assert(this->input_group_ == NULL);
+ this->do_group(workqueue);
+ return;
+ }
+
+ 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.
+
+ int ehdr_size = elfcpp::Elf_sizes<64>::ehdr_size;
+ off_t bytes;
+ const unsigned char* p = input_file->file().get_view(0, ehdr_size, &bytes);
+ if (bytes >= 4)
+ {
+ static unsigned char elfmagic[4] =
+ {
+ elfcpp::ELFMAG0, elfcpp::ELFMAG1,
+ elfcpp::ELFMAG2, elfcpp::ELFMAG3
+ };
+ if (memcmp(p, elfmagic, 4) == 0)
+ {
+ // This is an ELF object.
+
+ Object* obj = make_elf_object(input_file->filename(),
+ input_file, 0, p, bytes);
+
+ // We don't have a way to record a non-archive in an input
+ // group. If this is an ordinary object file, we can't
+ // include it more than once anyhow. If this is a dynamic
+ // object, then including it a second time changes nothing.
+ if (this->input_group_ != NULL && !obj->is_dynamic())
+ {
+ fprintf(stderr,
+ _("%s: %s: ordinary object found in input group\n"),
+ program_name, input_file->name());
+ gold_exit(false);
+ }
+
+ Read_symbols_data* sd = new Read_symbols_data;
+ obj->read_symbols(sd);
+ workqueue->queue_front(new Add_symbols(this->options_,
+ this->input_objects_,
+ this->symtab_, this->layout_,
+ obj, sd,
+ this->this_blocker_,
+ this->next_blocker_));
+
+ // Opening the file locked it, so now we need to unlock it.
+ input_file->file().unlock();
+
+ return;
+ }
+ }
+
+ if (bytes >= Archive::sarmag)
+ {
+ if (memcmp(p, Archive::armag, Archive::sarmag) == 0)
+ {
+ // This is an archive.
+ Archive* arch = new Archive(this->input_argument_->file().name(),
+ input_file);
+ arch->setup();
+ workqueue->queue(new Add_archive_symbols(this->options_,
+ this->symtab_,
+ this->layout_,
+ this->input_objects_,
+ arch,
+ this->input_group_,
+ this->this_blocker_,
+ this->next_blocker_));
+ return;
+ }
+ }
+
+ if (bytes == 0)
+ {
+ fprintf(stderr, _("%s: %s: file is empty\n"),
+ program_name, input_file->file().filename().c_str());
+ gold_exit(false);
+ }
+
+ // Try to parse this file as a script.
+ if (read_input_script(workqueue, this->options_, this->symtab_,
+ this->layout_, this->dirpath_, this->input_objects_,
+ this->input_group_, this->input_argument_, input_file,
+ p, bytes, this->this_blocker_, this->next_blocker_))
+ return;
+
+ // Here we have to handle any other input file types we need.
+ fprintf(stderr, _("%s: %s: not an object or archive\n"),
+ program_name, input_file->file().filename().c_str());
+ gold_exit(false);
+}
+
+// Handle a group. We need to walk through the arguments over and
+// over until we don't see any new undefined symbols. We do this by
+// setting off Read_symbols Tasks as usual, but recording the archive
+// entries instead of deleting them. We also start a Finish_group
+// Task which runs after we've read all the symbols. In that task we
+// process the archives in a loop until we are done.
+
+void
+Read_symbols::do_group(Workqueue* workqueue)
+{
+ Input_group* input_group = new Input_group();
+
+ const Input_file_group* group = this->input_argument_->group();
+ Task_token* this_blocker = this->this_blocker_;
+ for (Input_file_group::const_iterator p = group->begin();
+ p != group->end();
+ ++p)
+ {
+ const Input_argument* arg = &*p;
+ gold_assert(arg->is_file());
+
+ Task_token* next_blocker = new Task_token();
+ next_blocker->add_blocker();
+ workqueue->queue(new Read_symbols(this->options_, this->input_objects_,
+ this->symtab_, this->layout_,
+ this->dirpath_, arg, input_group,
+ this_blocker, next_blocker));
+ this_blocker = next_blocker;
+ }
+
+ const int saw_undefined = this->symtab_->saw_undefined();
+ workqueue->queue(new Finish_group(this->options_,
+ this->input_objects_,
+ this->symtab_,
+ this->layout_,
+ input_group,
+ saw_undefined,
+ this_blocker,
+ this->next_blocker_));
+}
+
+// Class Add_symbols.
+
+Add_symbols::~Add_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::Is_runnable_type
+Add_symbols::is_runnable(Workqueue*)
+{
+ if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
+ return IS_BLOCKED;
+ if (this->object_->is_locked())
+ return IS_LOCKED;
+ return IS_RUNNABLE;
+}
+
+class Add_symbols::Add_symbols_locker : public Task_locker
+{
+ public:
+ Add_symbols_locker(Task_token& token, Workqueue* workqueue,
+ Object* object)
+ : blocker_(token, workqueue), objlock_(*object)
+ { }
+
+ private:
+ Task_locker_block blocker_;
+ Task_locker_obj<Object> objlock_;
+};
+
+Task_locker*
+Add_symbols::locks(Workqueue* workqueue)
+{
+ return new Add_symbols_locker(*this->next_blocker_, workqueue,
+ this->object_);
+}
+
+// Add the symbols in the object to the symbol table.
+
+void
+Add_symbols::run(Workqueue*)
+{
+ if (!this->input_objects_->add_object(this->object_))
+ {
+ // FIXME: We need to close the descriptor here.
+ delete this->object_;
+ }
+ else
+ {
+ this->object_->layout(this->options_, this->symtab_, this->layout_,
+ this->sd_);
+ this->object_->add_symbols(this->symtab_, this->sd_);
+ }
+ delete this->sd_;
+ this->sd_ = NULL;
+}
+
+// Class Finish_group.
+
+Finish_group::~Finish_group()
+{
+ if (this->this_blocker_ != NULL)
+ delete this->this_blocker_;
+ // next_blocker_ is deleted by the task associated with the next
+ // input file following the group.
+}
+
+// We need to wait for THIS_BLOCKER_ and unblock NEXT_BLOCKER_.
+
+Task::Is_runnable_type
+Finish_group::is_runnable(Workqueue*)
+{
+ if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
+ return IS_BLOCKED;
+ return IS_RUNNABLE;
+}
+
+Task_locker*
+Finish_group::locks(Workqueue* workqueue)
+{
+ return new Task_locker_block(*this->next_blocker_, workqueue);
+}
+
+// Loop over the archives until there are no new undefined symbols.
+
+void
+Finish_group::run(Workqueue*)
+{
+ int saw_undefined = this->saw_undefined_;
+ while (saw_undefined != this->symtab_->saw_undefined())
+ {
+ saw_undefined = this->symtab_->saw_undefined();
+
+ for (Input_group::const_iterator p = this->input_group_->begin();
+ p != this->input_group_->end();
+ ++p)
+ {
+ Task_lock_obj<Archive> tl(**p);
+
+ (*p)->add_symbols(this->options_, this->symtab_, this->layout_,
+ this->input_objects_);
+ }
+ }
+
+ // Delete all the archives now that we no longer need them.
+ for (Input_group::const_iterator p = this->input_group_->begin();
+ p != this->input_group_->end();
+ ++p)
+ delete *p;
+ delete this->input_group_;
+}
+
+} // End namespace gold.
diff --git a/gold/readsyms.h b/gold/readsyms.h
new file mode 100644
index 000000000000..d5ada61d25ed
--- /dev/null
+++ b/gold/readsyms.h
@@ -0,0 +1,194 @@
+// readsyms.h -- read input file symbols for gold -*- C++ -*-
+
+#ifndef GOLD_READSYMS_H
+#define GOLD_READSYMS_H
+
+#include <vector>
+
+#include "workqueue.h"
+#include "object.h"
+
+namespace gold
+{
+
+class Input_objects;
+class Symbol_table;
+class Input_group;
+class Archive;
+
+// This Task is responsible for reading the symbols from an input
+// file. This also includes reading the relocations so that we can
+// check for any that require a PLT and/or a GOT. After the data has
+// been read, this queues up another task to actually add the symbols
+// to the symbol table. The tasks are separated because the file
+// reading can occur in parallel but adding the symbols must be done
+// in the order of the input files.
+
+class Read_symbols : public Task
+{
+ public:
+ // DIRPATH is the list of directories to search for libraries.
+ // INPUT is the file to read. INPUT_GROUP is not NULL if we are in
+ // the middle of an input group. THIS_BLOCKER is used to prevent
+ // the associated Add_symbols task from running before the previous
+ // one has completed; it will be NULL for the first task.
+ // NEXT_BLOCKER is used to block the next input file from adding
+ // symbols.
+ Read_symbols(const General_options& options, Input_objects* input_objects,
+ Symbol_table* symtab, Layout* layout, const Dirsearch& dirpath,
+ const Input_argument* input_argument, Input_group* input_group,
+ Task_token* this_blocker, Task_token* next_blocker)
+ : options_(options), input_objects_(input_objects), symtab_(symtab),
+ layout_(layout), dirpath_(dirpath), input_argument_(input_argument),
+ input_group_(input_group), this_blocker_(this_blocker),
+ next_blocker_(next_blocker)
+ { }
+
+ ~Read_symbols();
+
+ // The standard Task methods.
+
+ Is_runnable_type
+ is_runnable(Workqueue*);
+
+ Task_locker*
+ locks(Workqueue*);
+
+ void
+ run(Workqueue*);
+
+ private:
+ // Handle an archive group.
+ void
+ do_group(Workqueue*);
+
+ const General_options& options_;
+ Input_objects* input_objects_;
+ Symbol_table* symtab_;
+ Layout* layout_;
+ const Dirsearch& dirpath_;
+ const Input_argument* input_argument_;
+ Input_group* input_group_;
+ Task_token* this_blocker_;
+ Task_token* next_blocker_;
+};
+
+// 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_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_symbols(const General_options& options, Input_objects* input_objects,
+ Symbol_table* symtab, Layout* layout, Object* object,
+ Read_symbols_data* sd, Task_token* this_blocker,
+ Task_token* next_blocker)
+ : options_(options), input_objects_(input_objects), symtab_(symtab),
+ layout_(layout), object_(object), sd_(sd), this_blocker_(this_blocker),
+ next_blocker_(next_blocker)
+ { }
+
+ ~Add_symbols();
+
+ // The standard Task methods.
+
+ Is_runnable_type
+ is_runnable(Workqueue*);
+
+ Task_locker*
+ locks(Workqueue*);
+
+ void
+ run(Workqueue*);
+
+private:
+ class Add_symbols_locker;
+
+ const General_options& options_;
+ Input_objects* input_objects_;
+ Symbol_table* symtab_;
+ Layout* layout_;
+ Object* object_;
+ Read_symbols_data* sd_;
+ Task_token* this_blocker_;
+ Task_token* next_blocker_;
+};
+
+// This class is used to track the archives in a group.
+
+class Input_group
+{
+ public:
+ typedef std::vector<Archive*> Archives;
+ typedef Archives::const_iterator const_iterator;
+
+ Input_group()
+ : archives_()
+ { }
+
+ // Add an archive to the group.
+ void
+ add_archive(Archive* arch)
+ { this->archives_.push_back(arch); }
+
+ // Loop over the archives in the group.
+
+ const_iterator
+ begin() const
+ { return this->archives_.begin(); }
+
+ const_iterator
+ end() const
+ { return this->archives_.end(); }
+
+ private:
+ Archives archives_;
+};
+
+// This class is used to finish up handling a group. It is just a
+// closure.
+
+class Finish_group : public Task
+{
+ public:
+ Finish_group(const General_options& options, Input_objects* input_objects,
+ Symbol_table* symtab, Layout* layout, Input_group* input_group,
+ int saw_undefined, Task_token* this_blocker,
+ Task_token* next_blocker)
+ : options_(options), input_objects_(input_objects), symtab_(symtab),
+ layout_(layout), input_group_(input_group),
+ saw_undefined_(saw_undefined), this_blocker_(this_blocker),
+ next_blocker_(next_blocker)
+ { }
+
+ ~Finish_group();
+
+ // The standard Task methods.
+
+ Is_runnable_type
+ is_runnable(Workqueue*);
+
+ Task_locker*
+ locks(Workqueue*);
+
+ void
+ run(Workqueue*);
+
+ private:
+ const General_options& options_;
+ Input_objects* input_objects_;
+ Symbol_table* symtab_;
+ Layout* layout_;
+ Input_group* input_group_;
+ int saw_undefined_;
+ Task_token* this_blocker_;
+ Task_token* next_blocker_;
+};
+
+} // end namespace gold
+
+#endif // !defined(GOLD_READSYMS_H)
diff --git a/gold/reloc-types.h b/gold/reloc-types.h
new file mode 100644
index 000000000000..62538d60117c
--- /dev/null
+++ b/gold/reloc-types.h
@@ -0,0 +1,36 @@
+// reloc-types.h -- ELF relocation templates for gold -*- C++ -*-
+
+// This header files defines a few convenient templated types for use
+// when handling ELF relocations.
+
+#ifndef GOLD_RELOC_TYPES_H
+#define GOLD_RELOC_TYPES_H
+
+#include "elfcpp.h"
+
+namespace gold
+{
+
+// Pick the ELF relocation accessor class and the size based on
+// SH_TYPE, which is either elfcpp::SHT_REL or elfcpp::SHT_RELA.
+
+template<int sh_type, int size, bool big_endian>
+struct Reloc_types;
+
+template<int size, bool big_endian>
+struct Reloc_types<elfcpp::SHT_REL, size, big_endian>
+{
+ typedef typename elfcpp::Rel<size, big_endian> Reloc;
+ static const int reloc_size = elfcpp::Elf_sizes<size>::rel_size;
+};
+
+template<int size, bool big_endian>
+struct Reloc_types<elfcpp::SHT_RELA, size, big_endian>
+{
+ typedef typename elfcpp::Rela<size, big_endian> Reloc;
+ static const int reloc_size = elfcpp::Elf_sizes<size>::rela_size;
+};
+
+}; // End namespace gold.
+
+#endif // !defined(GOLD_RELOC_TYPE_SH)
diff --git a/gold/reloc.cc b/gold/reloc.cc
new file mode 100644
index 000000000000..76ab19613953
--- /dev/null
+++ b/gold/reloc.cc
@@ -0,0 +1,738 @@
+// reloc.cc -- relocate input files for gold.
+
+#include "gold.h"
+
+#include "workqueue.h"
+#include "object.h"
+#include "symtab.h"
+#include "output.h"
+#include "reloc.h"
+
+namespace gold
+{
+
+// Read_relocs methods.
+
+// These tasks just read the relocation information from the file.
+// After reading it, the start another task to process the
+// information. These tasks requires access to the file.
+
+Task::Is_runnable_type
+Read_relocs::is_runnable(Workqueue*)
+{
+ return this->object_->is_locked() ? IS_LOCKED : IS_RUNNABLE;
+}
+
+// Lock the file.
+
+Task_locker*
+Read_relocs::locks(Workqueue*)
+{
+ return new Task_locker_obj<Object>(*this->object_);
+}
+
+// Read the relocations and then start a Scan_relocs_task.
+
+void
+Read_relocs::run(Workqueue* workqueue)
+{
+ Read_relocs_data *rd = new Read_relocs_data;
+ this->object_->read_relocs(rd);
+ workqueue->queue_front(new Scan_relocs(this->options_, this->symtab_,
+ this->layout_, this->object_, rd,
+ this->symtab_lock_, this->blocker_));
+}
+
+// Scan_relocs methods.
+
+// These tasks scan the relocations read by Read_relocs and mark up
+// the symbol table to indicate which relocations are required. We
+// use a lock on the symbol table to keep them from interfering with
+// each other.
+
+Task::Is_runnable_type
+Scan_relocs::is_runnable(Workqueue*)
+{
+ if (!this->symtab_lock_->is_writable() || this->object_->is_locked())
+ return IS_LOCKED;
+ return IS_RUNNABLE;
+}
+
+// Return the locks we hold: one on the file, one on the symbol table
+// and one blocker.
+
+class Scan_relocs::Scan_relocs_locker : public Task_locker
+{
+ public:
+ Scan_relocs_locker(Object* object, Task_token& symtab_lock, Task* task,
+ Task_token& blocker, Workqueue* workqueue)
+ : objlock_(*object), symtab_locker_(symtab_lock, task),
+ blocker_(blocker, workqueue)
+ { }
+
+ private:
+ Task_locker_obj<Object> objlock_;
+ Task_locker_write symtab_locker_;
+ Task_locker_block blocker_;
+};
+
+Task_locker*
+Scan_relocs::locks(Workqueue* workqueue)
+{
+ return new Scan_relocs_locker(this->object_, *this->symtab_lock_, this,
+ *this->blocker_, workqueue);
+}
+
+// Scan the relocs.
+
+void
+Scan_relocs::run(Workqueue*)
+{
+ this->object_->scan_relocs(this->options_, this->symtab_, this->layout_,
+ this->rd_);
+ delete this->rd_;
+ this->rd_ = NULL;
+}
+
+// Relocate_task methods.
+
+// These tasks are always runnable.
+
+Task::Is_runnable_type
+Relocate_task::is_runnable(Workqueue*)
+{
+ return IS_RUNNABLE;
+}
+
+// We want to lock the file while we run. We want to unblock
+// FINAL_BLOCKER when we are done.
+
+class Relocate_task::Relocate_locker : public Task_locker
+{
+ public:
+ Relocate_locker(Task_token& token, Workqueue* workqueue,
+ Object* object)
+ : blocker_(token, workqueue), objlock_(*object)
+ { }
+
+ private:
+ Task_locker_block blocker_;
+ Task_locker_obj<Object> objlock_;
+};
+
+Task_locker*
+Relocate_task::locks(Workqueue* workqueue)
+{
+ return new Relocate_locker(*this->final_blocker_, workqueue,
+ this->object_);
+}
+
+// Run the task.
+
+void
+Relocate_task::run(Workqueue*)
+{
+ this->object_->relocate(this->options_, this->symtab_, this->layout_,
+ this->of_);
+}
+
+// Read the relocs and local symbols from the object file and store
+// the information in RD.
+
+template<int size, bool big_endian>
+void
+Sized_relobj<size, big_endian>::do_read_relocs(Read_relocs_data* rd)
+{
+ rd->relocs.clear();
+
+ unsigned int shnum = this->shnum();
+ if (shnum == 0)
+ return;
+
+ rd->relocs.reserve(shnum / 2);
+
+ const unsigned char *pshdrs = this->get_view(this->elf_file_.shoff(),
+ shnum * This::shdr_size);
+ // Skip the first, dummy, section.
+ const unsigned char *ps = pshdrs + This::shdr_size;
+ for (unsigned int i = 1; i < shnum; ++i, ps += This::shdr_size)
+ {
+ typename This::Shdr shdr(ps);
+
+ unsigned int sh_type = shdr.get_sh_type();
+ if (sh_type != elfcpp::SHT_REL && sh_type != elfcpp::SHT_RELA)
+ continue;
+
+ unsigned int shndx = shdr.get_sh_info();
+ if (shndx >= shnum)
+ {
+ fprintf(stderr, _("%s: %s: relocation section %u has bad info %u\n"),
+ program_name, this->name().c_str(), i, shndx);
+ gold_exit(false);
+ }
+
+ if (!this->is_section_included(shndx))
+ continue;
+
+ // We are scanning relocations in order to fill out the GOT and
+ // PLT sections. Relocations for sections which are not
+ // allocated (typically debugging sections) should not add new
+ // GOT and PLT entries. So we skip them.
+ typename This::Shdr secshdr(pshdrs + shndx * This::shdr_size);
+ if ((secshdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0)
+ continue;
+
+ if (shdr.get_sh_link() != this->symtab_shndx_)
+ {
+ fprintf(stderr,
+ _("%s: %s: relocation section %u uses unexpected "
+ "symbol table %u\n"),
+ program_name, this->name().c_str(), i, shdr.get_sh_link());
+ gold_exit(false);
+ }
+
+ off_t sh_size = shdr.get_sh_size();
+
+ unsigned int reloc_size;
+ if (sh_type == elfcpp::SHT_REL)
+ reloc_size = elfcpp::Elf_sizes<size>::rel_size;
+ else
+ reloc_size = elfcpp::Elf_sizes<size>::rela_size;
+ if (reloc_size != shdr.get_sh_entsize())
+ {
+ fprintf(stderr,
+ _("%s: %s: unexpected entsize for reloc section %u: "
+ "%lu != %u"),
+ program_name, this->name().c_str(), i,
+ static_cast<unsigned long>(shdr.get_sh_entsize()),
+ reloc_size);
+ gold_exit(false);
+ }
+
+ size_t reloc_count = sh_size / reloc_size;
+ if (reloc_count * reloc_size != sh_size)
+ {
+ fprintf(stderr, _("%s: %s: reloc section %u size %lu uneven"),
+ program_name, this->name().c_str(), i,
+ static_cast<unsigned long>(sh_size));
+ gold_exit(false);
+ }
+
+ rd->relocs.push_back(Section_relocs());
+ Section_relocs& sr(rd->relocs.back());
+ sr.reloc_shndx = i;
+ sr.data_shndx = shndx;
+ sr.contents = this->get_lasting_view(shdr.get_sh_offset(), sh_size);
+ sr.sh_type = sh_type;
+ sr.reloc_count = reloc_count;
+ }
+
+ // Read the local symbols.
+ gold_assert(this->symtab_shndx_ != -1U);
+ if (this->symtab_shndx_ == 0 || this->local_symbol_count_ == 0)
+ rd->local_symbols = NULL;
+ else
+ {
+ typename This::Shdr symtabshdr(pshdrs
+ + this->symtab_shndx_ * This::shdr_size);
+ gold_assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
+ const int sym_size = This::sym_size;
+ const unsigned int loccount = this->local_symbol_count_;
+ gold_assert(loccount == symtabshdr.get_sh_info());
+ off_t locsize = loccount * sym_size;
+ rd->local_symbols = this->get_lasting_view(symtabshdr.get_sh_offset(),
+ locsize);
+ }
+}
+
+// Scan the relocs and adjust the symbol table. This looks for
+// relocations which require GOT/PLT/COPY relocations.
+
+template<int size, bool big_endian>
+void
+Sized_relobj<size, big_endian>::do_scan_relocs(const General_options& options,
+ Symbol_table* symtab,
+ Layout* layout,
+ Read_relocs_data* rd)
+{
+ Sized_target<size, big_endian>* target = this->sized_target();
+
+ const unsigned char* local_symbols;
+ if (rd->local_symbols == NULL)
+ local_symbols = NULL;
+ else
+ local_symbols = rd->local_symbols->data();
+
+ for (Read_relocs_data::Relocs_list::iterator p = rd->relocs.begin();
+ p != rd->relocs.end();
+ ++p)
+ {
+ target->scan_relocs(options, symtab, layout, this, p->data_shndx,
+ p->sh_type, p->contents->data(), p->reloc_count,
+ this->local_symbol_count_,
+ local_symbols,
+ this->symbols_);
+ delete p->contents;
+ p->contents = NULL;
+ }
+
+ if (rd->local_symbols != NULL)
+ {
+ delete rd->local_symbols;
+ rd->local_symbols = NULL;
+ }
+}
+
+// Relocate the input sections and write out the local symbols.
+
+template<int size, bool big_endian>
+void
+Sized_relobj<size, big_endian>::do_relocate(const General_options& options,
+ const Symbol_table* symtab,
+ const Layout* layout,
+ Output_file* of)
+{
+ unsigned int shnum = this->shnum();
+
+ // Read the section headers.
+ const unsigned char* pshdrs = this->get_view(this->elf_file_.shoff(),
+ shnum * This::shdr_size);
+
+ Views views;
+ views.resize(shnum);
+
+ // Make two passes over the sections. The first one copies the
+ // section data to the output file. The second one applies
+ // relocations.
+
+ this->write_sections(pshdrs, of, &views);
+
+ // Apply relocations.
+
+ this->relocate_sections(options, symtab, layout, pshdrs, &views);
+
+ // Write out the accumulated views.
+ for (unsigned int i = 1; i < shnum; ++i)
+ {
+ if (views[i].view != NULL)
+ of->write_output_view(views[i].offset, views[i].view_size,
+ views[i].view);
+ }
+
+ // Write out the local symbols.
+ this->write_local_symbols(of, layout->sympool());
+}
+
+// Write section data to the output file. PSHDRS points to the
+// section headers. Record the views in *PVIEWS for use when
+// relocating.
+
+template<int size, bool big_endian>
+void
+Sized_relobj<size, big_endian>::write_sections(const unsigned char* pshdrs,
+ Output_file* of,
+ Views* pviews)
+{
+ unsigned int shnum = this->shnum();
+ std::vector<Map_to_output>& map_sections(this->map_to_output());
+
+ const unsigned char* p = pshdrs + This::shdr_size;
+ for (unsigned int i = 1; i < shnum; ++i, p += This::shdr_size)
+ {
+ View_size* pvs = &(*pviews)[i];
+
+ pvs->view = NULL;
+
+ if (map_sections[i].offset == -1)
+ continue;
+
+ const Output_section* os = map_sections[i].output_section;
+ if (os == NULL)
+ continue;
+
+ typename This::Shdr shdr(p);
+
+ if (shdr.get_sh_type() == elfcpp::SHT_NOBITS)
+ continue;
+
+ off_t start = os->offset() + map_sections[i].offset;
+ off_t sh_size = shdr.get_sh_size();
+
+ if (sh_size == 0)
+ continue;
+
+ gold_assert(map_sections[i].offset >= 0
+ && map_sections[i].offset + sh_size <= os->data_size());
+
+ unsigned char* view = of->get_output_view(start, sh_size);
+ this->read(shdr.get_sh_offset(), sh_size, view);
+
+ pvs->view = view;
+ pvs->address = os->address() + map_sections[i].offset;
+ pvs->offset = start;
+ pvs->view_size = sh_size;
+ }
+}
+
+// Relocate section data. VIEWS points to the section data as views
+// in the output file.
+
+template<int size, bool big_endian>
+void
+Sized_relobj<size, big_endian>::relocate_sections(
+ const General_options& options,
+ const Symbol_table* symtab,
+ const Layout* layout,
+ const unsigned char* pshdrs,
+ Views* pviews)
+{
+ unsigned int shnum = this->shnum();
+ Sized_target<size, big_endian>* target = this->sized_target();
+
+ Relocate_info<size, big_endian> relinfo;
+ relinfo.options = &options;
+ relinfo.symtab = symtab;
+ relinfo.layout = layout;
+ relinfo.object = this;
+ relinfo.local_symbol_count = this->local_symbol_count_;
+ relinfo.local_values = &this->local_values_;
+ relinfo.symbols = this->symbols_;
+
+ const unsigned char* p = pshdrs + This::shdr_size;
+ for (unsigned int i = 1; i < shnum; ++i, p += This::shdr_size)
+ {
+ typename This::Shdr shdr(p);
+
+ unsigned int sh_type = shdr.get_sh_type();
+ if (sh_type != elfcpp::SHT_REL && sh_type != elfcpp::SHT_RELA)
+ continue;
+
+ unsigned int index = shdr.get_sh_info();
+ if (index >= this->shnum())
+ {
+ fprintf(stderr, _("%s: %s: relocation section %u has bad info %u\n"),
+ program_name, this->name().c_str(), i, index);
+ gold_exit(false);
+ }
+
+ if (!this->is_section_included(index))
+ {
+ // This relocation section is against a section which we
+ // discarded.
+ continue;
+ }
+
+ gold_assert((*pviews)[index].view != NULL);
+
+ if (shdr.get_sh_link() != this->symtab_shndx_)
+ {
+ fprintf(stderr,
+ _("%s: %s: relocation section %u uses unexpected "
+ "symbol table %u\n"),
+ program_name, this->name().c_str(), i, shdr.get_sh_link());
+ gold_exit(false);
+ }
+
+ off_t sh_size = shdr.get_sh_size();
+ const unsigned char* prelocs = this->get_view(shdr.get_sh_offset(),
+ sh_size);
+
+ unsigned int reloc_size;
+ if (sh_type == elfcpp::SHT_REL)
+ reloc_size = elfcpp::Elf_sizes<size>::rel_size;
+ else
+ reloc_size = elfcpp::Elf_sizes<size>::rela_size;
+
+ if (reloc_size != shdr.get_sh_entsize())
+ {
+ fprintf(stderr,
+ _("%s: %s: unexpected entsize for reloc section %u: "
+ "%lu != %u"),
+ program_name, this->name().c_str(), i,
+ static_cast<unsigned long>(shdr.get_sh_entsize()),
+ reloc_size);
+ gold_exit(false);
+ }
+
+ size_t reloc_count = sh_size / reloc_size;
+ if (reloc_count * reloc_size != sh_size)
+ {
+ fprintf(stderr, _("%s: %s: reloc section %u size %lu uneven"),
+ program_name, this->name().c_str(), i,
+ static_cast<unsigned long>(sh_size));
+ gold_exit(false);
+ }
+
+ relinfo.reloc_shndx = i;
+ relinfo.data_shndx = index;
+ target->relocate_section(&relinfo,
+ sh_type,
+ prelocs,
+ reloc_count,
+ (*pviews)[index].view,
+ (*pviews)[index].address,
+ (*pviews)[index].view_size);
+ }
+}
+
+// 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<int size, bool big_endian>
+bool
+Copy_relocs<size, big_endian>::Copy_reloc_entry::should_emit()
+{
+ if (this->sym_ == NULL)
+ return false;
+ if (this->sym_->is_from_dynobj())
+ return true;
+ this->sym_ = NULL;
+ return false;
+}
+
+// Emit a reloc into a SHT_REL section.
+
+template<int size, bool big_endian>
+void
+Copy_relocs<size, big_endian>::Copy_reloc_entry::emit(
+ Output_data_reloc<elfcpp::SHT_REL, true, size, big_endian>* reloc_data)
+{
+ this->sym_->set_needs_dynsym_entry();
+ reloc_data->add_global(this->sym_, this->reloc_type_, this->relobj_,
+ this->shndx_, this->address_);
+}
+
+// Emit a reloc into a SHT_RELA section.
+
+template<int size, bool big_endian>
+void
+Copy_relocs<size, big_endian>::Copy_reloc_entry::emit(
+ Output_data_reloc<elfcpp::SHT_RELA, true, size, big_endian>* reloc_data)
+{
+ this->sym_->set_needs_dynsym_entry();
+ 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<int size, bool big_endian>
+bool
+Copy_relocs<size, big_endian>::need_copy_reloc(
+ const General_options*,
+ Relobj* object,
+ unsigned int shndx,
+ Sized_symbol<size>* 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)
+ return true;
+
+ return false;
+}
+
+// Save a Rel reloc.
+
+template<int size, bool big_endian>
+void
+Copy_relocs<size, big_endian>::save(
+ Symbol* sym,
+ Relobj* relobj,
+ unsigned int shndx,
+ const elfcpp::Rel<size, big_endian>& rel)
+{
+ unsigned int reloc_type = elfcpp::elf_r_type<size>(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<int size, bool big_endian>
+void
+Copy_relocs<size, big_endian>::save(
+ Symbol* sym,
+ Relobj* relobj,
+ unsigned int shndx,
+ const elfcpp::Rela<size, big_endian>& rela)
+{
+ unsigned int reloc_type = elfcpp::elf_r_type<size>(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<int size, bool big_endian>
+bool
+Copy_relocs<size, big_endian>::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<int size, bool big_endian>
+template<int sh_type>
+void
+Copy_relocs<size, big_endian>::emit(
+ Output_data_reloc<sh_type, true, size, big_endian>* 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.
+
+template
+void
+Sized_relobj<32, false>::do_read_relocs(Read_relocs_data* rd);
+
+template
+void
+Sized_relobj<32, true>::do_read_relocs(Read_relocs_data* rd);
+
+template
+void
+Sized_relobj<64, false>::do_read_relocs(Read_relocs_data* rd);
+
+template
+void
+Sized_relobj<64, true>::do_read_relocs(Read_relocs_data* rd);
+
+template
+void
+Sized_relobj<32, false>::do_scan_relocs(const General_options& options,
+ Symbol_table* symtab,
+ Layout* layout,
+ Read_relocs_data* rd);
+
+template
+void
+Sized_relobj<32, true>::do_scan_relocs(const General_options& options,
+ Symbol_table* symtab,
+ Layout* layout,
+ Read_relocs_data* rd);
+
+template
+void
+Sized_relobj<64, false>::do_scan_relocs(const General_options& options,
+ Symbol_table* symtab,
+ Layout* layout,
+ Read_relocs_data* rd);
+
+template
+void
+Sized_relobj<64, true>::do_scan_relocs(const General_options& options,
+ Symbol_table* symtab,
+ Layout* layout,
+ Read_relocs_data* rd);
+
+template
+void
+Sized_relobj<32, false>::do_relocate(const General_options& options,
+ const Symbol_table* symtab,
+ const Layout* layout,
+ Output_file* of);
+
+template
+void
+Sized_relobj<32, true>::do_relocate(const General_options& options,
+ const Symbol_table* symtab,
+ const Layout* layout,
+ Output_file* of);
+
+template
+void
+Sized_relobj<64, false>::do_relocate(const General_options& options,
+ const Symbol_table* symtab,
+ const Layout* layout,
+ Output_file* of);
+
+template
+void
+Sized_relobj<64, true>::do_relocate(const General_options& options,
+ const Symbol_table* symtab,
+ const Layout* layout,
+ Output_file* of);
+
+template
+class Copy_relocs<32, false>;
+
+template
+class Copy_relocs<32, true>;
+
+template
+class Copy_relocs<64, false>;
+
+template
+class Copy_relocs<64, true>;
+
+template
+void
+Copy_relocs<32, false>::emit<elfcpp::SHT_REL>(
+ Output_data_reloc<elfcpp::SHT_REL, true, 32, false>*);
+
+template
+void
+Copy_relocs<32, true>::emit<elfcpp::SHT_REL>(
+ Output_data_reloc<elfcpp::SHT_REL, true, 32, true>*);
+
+template
+void
+Copy_relocs<64, false>::emit<elfcpp::SHT_REL>(
+ Output_data_reloc<elfcpp::SHT_REL, true, 64, false>*);
+
+template
+void
+Copy_relocs<64, true>::emit<elfcpp::SHT_REL>(
+ Output_data_reloc<elfcpp::SHT_REL, true, 64, true>*);
+
+template
+void
+Copy_relocs<32, false>::emit<elfcpp::SHT_RELA>(
+ Output_data_reloc<elfcpp::SHT_RELA , true, 32, false>*);
+
+template
+void
+Copy_relocs<32, true>::emit<elfcpp::SHT_RELA>(
+ Output_data_reloc<elfcpp::SHT_RELA, true, 32, true>*);
+
+template
+void
+Copy_relocs<64, false>::emit<elfcpp::SHT_RELA>(
+ Output_data_reloc<elfcpp::SHT_RELA, true, 64, false>*);
+
+template
+void
+Copy_relocs<64, true>::emit<elfcpp::SHT_RELA>(
+ Output_data_reloc<elfcpp::SHT_RELA, true, 64, true>*);
+
+} // End namespace gold.
diff --git a/gold/reloc.h b/gold/reloc.h
new file mode 100644
index 000000000000..1aa0d896717f
--- /dev/null
+++ b/gold/reloc.h
@@ -0,0 +1,409 @@
+// reloc.h -- relocate input files for gold -*- C++ -*-
+
+#ifndef GOLD_RELOC_H
+#define GOLD_RELOC_H
+
+#include <byteswap.h>
+
+#include "workqueue.h"
+
+namespace gold
+{
+
+class General_options;
+class Relobj;
+class Read_relocs_data;
+class Symbol;
+class Layout;
+
+template<int size>
+class Sized_symbol;
+
+template<int size, bool big_endian>
+class Sized_relobj;
+
+template<int size>
+class Symbol_value;
+
+template<int sh_type, bool dynamic, int size, bool big_endian>
+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.
+
+class Read_relocs : public Task
+{
+ public:
+ // SYMTAB_LOCK is used to lock the symbol table. BLOCKER should be
+ // unblocked when the Scan_relocs task completes.
+ Read_relocs(const General_options& options, Symbol_table* symtab,
+ Layout* layout, Relobj* object, Task_token* symtab_lock,
+ Task_token* blocker)
+ : options_(options), symtab_(symtab), layout_(layout), object_(object),
+ symtab_lock_(symtab_lock), blocker_(blocker)
+ { }
+
+ // The standard Task methods.
+
+ Is_runnable_type
+ is_runnable(Workqueue*);
+
+ Task_locker*
+ locks(Workqueue*);
+
+ void
+ run(Workqueue*);
+
+ private:
+ const General_options& options_;
+ Symbol_table* symtab_;
+ Layout* layout_;
+ Relobj* object_;
+ Task_token* symtab_lock_;
+ Task_token* blocker_;
+};
+
+// Scan the relocations for an object to see if they require any
+// GOT/PLT/COPY relocations.
+
+class Scan_relocs : public Task
+{
+ public:
+ // SYMTAB_LOCK is used to lock the symbol table. BLOCKER should be
+ // unblocked when the task completes.
+ Scan_relocs(const General_options& options, Symbol_table* symtab,
+ Layout* layout, Relobj* object, Read_relocs_data* rd,
+ Task_token* symtab_lock, Task_token* blocker)
+ : options_(options), symtab_(symtab), layout_(layout), object_(object),
+ rd_(rd), symtab_lock_(symtab_lock), blocker_(blocker)
+ { }
+
+ // The standard Task methods.
+
+ Is_runnable_type
+ is_runnable(Workqueue*);
+
+ Task_locker*
+ locks(Workqueue*);
+
+ void
+ run(Workqueue*);
+
+ private:
+ class Scan_relocs_locker;
+
+ const General_options& options_;
+ Symbol_table* symtab_;
+ Layout* layout_;
+ Relobj* object_;
+ Read_relocs_data* rd_;
+ Task_token* symtab_lock_;
+ Task_token* blocker_;
+};
+
+// A class to perform all the relocations for an object file.
+
+class Relocate_task : public Task
+{
+ public:
+ Relocate_task(const General_options& options, const Symbol_table* symtab,
+ const Layout* layout, Relobj* object, Output_file* of,
+ Task_token* final_blocker)
+ : options_(options), symtab_(symtab), layout_(layout), object_(object),
+ of_(of), final_blocker_(final_blocker)
+ { }
+
+ // The standard Task methods.
+
+ Is_runnable_type
+ is_runnable(Workqueue*);
+
+ Task_locker*
+ locks(Workqueue*);
+
+ void
+ run(Workqueue*);
+
+ private:
+ class Relocate_locker;
+
+ const General_options& options_;
+ const Symbol_table* symtab_;
+ const Layout* layout_;
+ Relobj* object_;
+ Output_file* of_;
+ Task_token* final_blocker_;
+};
+
+// Standard relocation routines which are used on many targets. Here
+// SIZE and BIG_ENDIAN refer to the target, not the relocation type.
+
+template<int size, bool big_endian>
+class Relocate_functions
+{
+private:
+ // Do a simple relocation with the addend in the section contents.
+ // VALSIZE is the size of the value.
+ template<int valsize>
+ static inline void
+ rel(unsigned char* view,
+ typename elfcpp::Swap<valsize, big_endian>::Valtype value)
+ {
+ typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype x = elfcpp::Swap<valsize, big_endian>::readval(wv);
+ elfcpp::Swap<valsize, big_endian>::writeval(wv, x + value);
+ }
+
+ // Do a simple relocation using a Symbol_value with the addend in
+ // the section contents. VALSIZE is the size of the value to
+ // relocate.
+ template<int valsize>
+ static inline void
+ rel(unsigned char* view,
+ const Sized_relobj<size, big_endian>* object,
+ const Symbol_value<size>* psymval)
+ {
+ typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype x = elfcpp::Swap<valsize, big_endian>::readval(wv);
+ x = psymval->value(object, x);
+ elfcpp::Swap<valsize, big_endian>::writeval(wv, x);
+ }
+
+ // Do a simple PC relative relocation with the addend in the section
+ // contents. VALSIZE is the size of the value.
+ template<int valsize>
+ static inline void
+ pcrel(unsigned char* view,
+ typename elfcpp::Swap<valsize, big_endian>::Valtype value,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ {
+ typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype x = elfcpp::Swap<valsize, big_endian>::readval(wv);
+ elfcpp::Swap<valsize, big_endian>::writeval(wv, x + value - address);
+ }
+
+ // Do a simple PC relative relocation with a Symbol_value with the
+ // addend in the section contents. VALSIZE is the size of the
+ // value.
+ template<int valsize>
+ static inline void
+ pcrel(unsigned char* view,
+ const Sized_relobj<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ {
+ typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype x = elfcpp::Swap<valsize, big_endian>::readval(wv);
+ x = psymval->value(object, x);
+ elfcpp::Swap<valsize, big_endian>::writeval(wv, x - address);
+ }
+
+ typedef Relocate_functions<size, big_endian> This;
+
+public:
+ // Do a simple 8-bit REL relocation with the addend in the section
+ // contents.
+ static inline void
+ rel8(unsigned char* view, unsigned char value)
+ { This::template rel<8>(view, value); }
+
+ static inline void
+ rel8(unsigned char* view,
+ const Sized_relobj<size, big_endian>* object,
+ const Symbol_value<size>* psymval)
+ { This::template rel<8>(view, object, psymval); }
+
+ // Do a simple 8-bit PC relative relocation with the addend in the
+ // section contents.
+ static inline void
+ pcrel8(unsigned char* view, unsigned char value,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ { This::template pcrel<8>(view, value, address); }
+
+ static inline void
+ pcrel8(unsigned char* view,
+ const Sized_relobj<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ { This::template pcrel<8>(view, object, psymval, address); }
+
+ // Do a simple 16-bit REL relocation with the addend in the section
+ // contents.
+ static inline void
+ rel16(unsigned char* view, elfcpp::Elf_Half value)
+ { This::template rel<16>(view, value); }
+
+ static inline void
+ rel16(unsigned char* view,
+ const Sized_relobj<size, big_endian>* object,
+ const Symbol_value<size>* psymval)
+ { This::template rel<16>(view, object, psymval); }
+
+ // Do a simple 32-bit PC relative REL relocation with the addend in
+ // the section contents.
+ static inline void
+ pcrel16(unsigned char* view, elfcpp::Elf_Word value,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ { This::template pcrel<16>(view, value, address); }
+
+ static inline void
+ pcrel16(unsigned char* view,
+ const Sized_relobj<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ { This::template pcrel<16>(view, object, psymval, address); }
+
+ // Do a simple 32-bit REL relocation with the addend in the section
+ // contents.
+ static inline void
+ rel32(unsigned char* view, elfcpp::Elf_Word value)
+ { This::template rel<32>(view, value); }
+
+ static inline void
+ rel32(unsigned char* view,
+ const Sized_relobj<size, big_endian>* object,
+ const Symbol_value<size>* psymval)
+ { This::template rel<32>(view, object, psymval); }
+
+ // Do a simple 32-bit PC relative REL relocation with the addend in
+ // the section contents.
+ static inline void
+ pcrel32(unsigned char* view, elfcpp::Elf_Word value,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ { This::template pcrel<32>(view, value, address); }
+
+ static inline void
+ pcrel32(unsigned char* view,
+ const Sized_relobj<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ { This::template pcrel<32>(view, object, psymval, address); }
+
+ // Do a simple 64-bit REL relocation with the addend in the section
+ // contents.
+ static inline void
+ rel64(unsigned char* view, elfcpp::Elf_Xword value)
+ { This::template rel<64>(view, value); }
+
+ static inline void
+ rel64(unsigned char* view,
+ const Sized_relobj<size, big_endian>* object,
+ const Symbol_value<size>* psymval)
+ { This::template rel<64>(view, object, psymval); }
+
+ // Do a simple 64-bit PC relative REL relocation with the addend in
+ // the section contents.
+ static inline void
+ pcrel64(unsigned char* view, elfcpp::Elf_Xword value,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ { This::template pcrel<64>(view, value, address); }
+
+ static inline void
+ pcrel64(unsigned char* view,
+ const Sized_relobj<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Elf_types<size>::Elf_Addr address)
+ { This::template pcrel<64>(view, object, psymval, 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<int size, bool big_endian>
+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,
+ Sized_symbol<size>* 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<size, big_endian>&);
+
+ // Save a Rela against SYM for possible emission later.
+ void
+ save(Symbol* sym, Relobj*, unsigned int shndx,
+ const elfcpp::Rela<size, big_endian>&);
+
+ // 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<int sh_type>
+ void
+ emit(Output_data_reloc<sh_type, true, size, big_endian>*);
+
+ private:
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+ typedef typename elfcpp::Elf_types<size>::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<elfcpp::SHT_REL, true, size, big_endian>*);
+
+ void
+ emit(Output_data_reloc<elfcpp::SHT_RELA, true, size, big_endian>*);
+
+ 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_entry> Copy_reloc_entries;
+
+ // The list of relocs we are saving.
+ Copy_reloc_entries entries_;
+};
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_RELOC_H)
diff --git a/gold/resolve.cc b/gold/resolve.cc
new file mode 100644
index 000000000000..1d874863d628
--- /dev/null
+++ b/gold/resolve.cc
@@ -0,0 +1,560 @@
+// resolve.cc -- symbol resolution for gold
+
+#include "gold.h"
+
+#include "elfcpp.h"
+#include "target.h"
+#include "object.h"
+#include "symtab.h"
+
+namespace gold
+{
+
+// Symbol methods used in this file.
+
+// Override the fields in Symbol.
+
+template<int size, bool big_endian>
+void
+Symbol::override_base(const elfcpp::Sym<size, big_endian>& sym,
+ Object* object, const char* version)
+{
+ gold_assert(this->source_ == FROM_OBJECT);
+ this->u_.from_object.object = object;
+ if (version != NULL && this->version() != version)
+ {
+ gold_assert(this->version() == NULL);
+ this->version_ = version;
+ }
+ // FIXME: Handle SHN_XINDEX.
+ this->u_.from_object.shndx = sym.get_st_shndx();
+ this->type_ = sym.get_st_type();
+ this->binding_ = sym.get_st_bind();
+ this->visibility_ = sym.get_st_visibility();
+ this->nonvis_ = sym.get_st_nonvis();
+}
+
+// Override the fields in Sized_symbol.
+
+template<int size>
+template<bool big_endian>
+void
+Sized_symbol<size>::override(const elfcpp::Sym<size, big_endian>& sym,
+ Object* object, const char* version)
+{
+ this->override_base(sym, object, version);
+ this->value_ = sym.get_st_value();
+ this->symsize_ = sym.get_st_size();
+}
+
+// Resolve a symbol. This is called the second and subsequent times
+// we see a symbol. TO is the pre-existing symbol. SYM is the new
+// symbol, seen in OBJECT. VERSION of the version of SYM.
+
+template<int size, bool big_endian>
+void
+Symbol_table::resolve(Sized_symbol<size>* to,
+ const elfcpp::Sym<size, big_endian>& sym,
+ Object* object, const char* version)
+{
+ if (object->target()->has_resolve())
+ {
+ Sized_target<size, big_endian>* sized_target;
+ sized_target = object->sized_target
+ SELECT_SIZE_ENDIAN_NAME(size, big_endian) (
+ SELECT_SIZE_ENDIAN_ONLY(size, big_endian));
+ sized_target->resolve(to, sym, object, version);
+ return;
+ }
+
+ // Build a little code for each symbol.
+ // Bit 0: 0 for global, 1 for weak.
+ // Bit 1: 0 for regular object, 1 for shared object
+ // Bits 2-3: 0 for normal, 1 for undefined, 2 for common
+ // This gives us values from 0 to 11:
+
+ enum
+ {
+ DEF = 0,
+ WEAK_DEF = 1,
+ DYN_DEF = 2,
+ DYN_WEAK_DEF = 3,
+ UNDEF = 4,
+ WEAK_UNDEF = 5,
+ DYN_UNDEF = 6,
+ DYN_WEAK_UNDEF = 7,
+ COMMON = 8,
+ WEAK_COMMON = 9,
+ DYN_COMMON = 10,
+ DYN_WEAK_COMMON = 11
+ };
+
+ int tobits;
+ switch (to->binding())
+ {
+ case elfcpp::STB_GLOBAL:
+ tobits = 0;
+ break;
+
+ case elfcpp::STB_WEAK:
+ tobits = 1;
+ break;
+
+ case elfcpp::STB_LOCAL:
+ // We should only see externally visible symbols in the symbol
+ // table.
+ gold_unreachable();
+
+ default:
+ // Any target which wants to handle STB_LOOS, etc., needs to
+ // define a resolve method.
+ gold_unreachable();
+ }
+
+ if (to->source() == Symbol::FROM_OBJECT
+ && to->object()->is_dynamic())
+ tobits |= (1 << 1);
+
+ switch (to->shndx())
+ {
+ case elfcpp::SHN_UNDEF:
+ tobits |= (1 << 2);
+ break;
+
+ case elfcpp::SHN_COMMON:
+ tobits |= (2 << 2);
+ break;
+
+ default:
+ if (to->type() == elfcpp::STT_COMMON)
+ tobits |= (2 << 2);
+ break;
+ }
+
+ int frombits;
+ switch (sym.get_st_bind())
+ {
+ case elfcpp::STB_GLOBAL:
+ frombits = 0;
+ break;
+
+ case elfcpp::STB_WEAK:
+ frombits = 1;
+ break;
+
+ case elfcpp::STB_LOCAL:
+ fprintf(stderr,
+ _("%s: %s: invalid STB_LOCAL symbol %s in external symbols\n"),
+ program_name, object->name().c_str(), to->name());
+ gold_exit(false);
+
+ default:
+ fprintf(stderr,
+ _("%s: %s: unsupported symbol binding %d for symbol %s\n"),
+ program_name, object->name().c_str(),
+ static_cast<int>(sym.get_st_bind()), to->name());
+ gold_exit(false);
+ }
+
+ if (!object->is_dynamic())
+ {
+ // Record that we've seen this symbol in a regular object.
+ to->set_in_reg();
+ }
+ else
+ {
+ frombits |= (1 << 1);
+
+ // Record that we've seen this symbol in a dynamic object.
+ to->set_in_dyn();
+ }
+
+ switch (sym.get_st_shndx())
+ {
+ case elfcpp::SHN_UNDEF:
+ frombits |= (1 << 2);
+ break;
+
+ case elfcpp::SHN_COMMON:
+ frombits |= (2 << 2);
+ break;
+
+ default:
+ if (sym.get_st_type() == elfcpp::STT_COMMON)
+ frombits |= (2 << 2);
+ break;
+ }
+
+ if ((tobits & (1 << 1)) != (frombits & (1 << 1)))
+ {
+ // This symbol is seen in both a dynamic object and a regular
+ // object. That means that we need the symbol to go into the
+ // dynamic symbol table, so that the dynamic linker can use the
+ // regular symbol to override or define the dynamic symbol.
+ to->set_needs_dynsym_entry();
+ }
+
+ // FIXME: Warn if either but not both of TO and SYM are STT_TLS.
+
+ // We use a giant switch table for symbol resolution. This code is
+ // unwieldy, but: 1) it is efficient; 2) we definitely handle all
+ // cases; 3) it is easy to change the handling of a particular case.
+ // The alternative would be a series of conditionals, but it is easy
+ // to get the ordering wrong. This could also be done as a table,
+ // but that is no easier to understand than this large switch
+ // statement.
+
+ switch (tobits * 16 + frombits)
+ {
+ case DEF * 16 + DEF:
+ // Two definitions of the same symbol.
+ fprintf(stderr, "%s: %s: multiple definition of %s\n",
+ program_name, object->name().c_str(), to->name());
+ // FIXME: Report locations. Record that we have seen an error.
+ return;
+
+ case WEAK_DEF * 16 + DEF:
+ // We've seen a weak definition, and now we see a strong
+ // definition. In the original SVR4 linker, this was treated as
+ // a multiple definition error. In the Solaris linker and the
+ // GNU linker, a weak definition followed by a regular
+ // definition causes the weak definition to be overridden. We
+ // are currently compatible with the GNU linker. In the future
+ // we should add a target specific option to change this.
+ // FIXME.
+ to->override(sym, object, version);
+ return;
+
+ case DYN_DEF * 16 + DEF:
+ case DYN_WEAK_DEF * 16 + DEF:
+ // We've seen a definition in a dynamic object, and now we see a
+ // definition in a regular object. The definition in the
+ // regular object overrides the definition in the dynamic
+ // object.
+ to->override(sym, object, version);
+ return;
+
+ case UNDEF * 16 + DEF:
+ case WEAK_UNDEF * 16 + DEF:
+ case DYN_UNDEF * 16 + DEF:
+ case DYN_WEAK_UNDEF * 16 + DEF:
+ // We've seen an undefined reference, and now we see a
+ // definition. We use the definition.
+ to->override(sym, object, version);
+ return;
+
+ case COMMON * 16 + DEF:
+ case WEAK_COMMON * 16 + DEF:
+ case DYN_COMMON * 16 + DEF:
+ case DYN_WEAK_COMMON * 16 + DEF:
+ // We've seen a common symbol and now we see a definition. The
+ // definition overrides. FIXME: We should optionally issue, version a
+ // warning.
+ to->override(sym, object, version);
+ return;
+
+ case DEF * 16 + WEAK_DEF:
+ case WEAK_DEF * 16 + WEAK_DEF:
+ // We've seen a definition and now we see a weak definition. We
+ // ignore the new weak definition.
+ return;
+
+ case DYN_DEF * 16 + WEAK_DEF:
+ case DYN_WEAK_DEF * 16 + WEAK_DEF:
+ // We've seen a dynamic definition and now we see a regular weak
+ // definition. The regular weak definition overrides.
+ to->override(sym, object, version);
+ return;
+
+ case UNDEF * 16 + WEAK_DEF:
+ case WEAK_UNDEF * 16 + WEAK_DEF:
+ case DYN_UNDEF * 16 + WEAK_DEF:
+ case DYN_WEAK_UNDEF * 16 + WEAK_DEF:
+ // A weak definition of a currently undefined symbol.
+ to->override(sym, object, version);
+ return;
+
+ case COMMON * 16 + WEAK_DEF:
+ case WEAK_COMMON * 16 + WEAK_DEF:
+ // A weak definition does not override a common definition.
+ return;
+
+ case DYN_COMMON * 16 + WEAK_DEF:
+ case DYN_WEAK_COMMON * 16 + WEAK_DEF:
+ // A weak definition does override a definition in a dynamic
+ // object. FIXME: We should optionally issue a warning.
+ to->override(sym, object, version);
+ return;
+
+ case DEF * 16 + DYN_DEF:
+ case WEAK_DEF * 16 + DYN_DEF:
+ case DYN_DEF * 16 + DYN_DEF:
+ case DYN_WEAK_DEF * 16 + DYN_DEF:
+ // Ignore a dynamic definition if we already have a definition.
+ return;
+
+ case UNDEF * 16 + DYN_DEF:
+ case WEAK_UNDEF * 16 + DYN_DEF:
+ case DYN_UNDEF * 16 + DYN_DEF:
+ case DYN_WEAK_UNDEF * 16 + DYN_DEF:
+ // Use a dynamic definition if we have a reference.
+ to->override(sym, object, version);
+ return;
+
+ case COMMON * 16 + DYN_DEF:
+ case WEAK_COMMON * 16 + DYN_DEF:
+ case DYN_COMMON * 16 + DYN_DEF:
+ case DYN_WEAK_COMMON * 16 + DYN_DEF:
+ // Ignore a dynamic definition if we already have a common
+ // definition.
+ return;
+
+ case DEF * 16 + DYN_WEAK_DEF:
+ case WEAK_DEF * 16 + DYN_WEAK_DEF:
+ case DYN_DEF * 16 + DYN_WEAK_DEF:
+ case DYN_WEAK_DEF * 16 + DYN_WEAK_DEF:
+ // Ignore a weak dynamic definition if we already have a
+ // definition.
+ return;
+
+ case UNDEF * 16 + DYN_WEAK_DEF:
+ case WEAK_UNDEF * 16 + DYN_WEAK_DEF:
+ case DYN_UNDEF * 16 + DYN_WEAK_DEF:
+ case DYN_WEAK_UNDEF * 16 + DYN_WEAK_DEF:
+ // Use a weak dynamic definition if we have a reference.
+ to->override(sym, object, version);
+ return;
+
+ case COMMON * 16 + DYN_WEAK_DEF:
+ case WEAK_COMMON * 16 + DYN_WEAK_DEF:
+ case DYN_COMMON * 16 + DYN_WEAK_DEF:
+ case DYN_WEAK_COMMON * 16 + DYN_WEAK_DEF:
+ // Ignore a weak dynamic definition if we already have a common
+ // definition.
+ return;
+
+ case DEF * 16 + UNDEF:
+ case WEAK_DEF * 16 + UNDEF:
+ case DYN_DEF * 16 + UNDEF:
+ case DYN_WEAK_DEF * 16 + UNDEF:
+ case UNDEF * 16 + UNDEF:
+ // A new undefined reference tells us nothing.
+ return;
+
+ case WEAK_UNDEF * 16 + UNDEF:
+ case DYN_UNDEF * 16 + UNDEF:
+ case DYN_WEAK_UNDEF * 16 + UNDEF:
+ // A strong undef overrides a dynamic or weak undef.
+ to->override(sym, object, version);
+ return;
+
+ case COMMON * 16 + UNDEF:
+ case WEAK_COMMON * 16 + UNDEF:
+ case DYN_COMMON * 16 + UNDEF:
+ case DYN_WEAK_COMMON * 16 + UNDEF:
+ // A new undefined reference tells us nothing.
+ return;
+
+ case DEF * 16 + WEAK_UNDEF:
+ case WEAK_DEF * 16 + WEAK_UNDEF:
+ case DYN_DEF * 16 + WEAK_UNDEF:
+ case DYN_WEAK_DEF * 16 + WEAK_UNDEF:
+ case UNDEF * 16 + WEAK_UNDEF:
+ case WEAK_UNDEF * 16 + WEAK_UNDEF:
+ case DYN_UNDEF * 16 + WEAK_UNDEF:
+ case DYN_WEAK_UNDEF * 16 + WEAK_UNDEF:
+ case COMMON * 16 + WEAK_UNDEF:
+ case WEAK_COMMON * 16 + WEAK_UNDEF:
+ case DYN_COMMON * 16 + WEAK_UNDEF:
+ case DYN_WEAK_COMMON * 16 + WEAK_UNDEF:
+ // A new weak undefined reference tells us nothing.
+ return;
+
+ case DEF * 16 + DYN_UNDEF:
+ case WEAK_DEF * 16 + DYN_UNDEF:
+ case DYN_DEF * 16 + DYN_UNDEF:
+ case DYN_WEAK_DEF * 16 + DYN_UNDEF:
+ case UNDEF * 16 + DYN_UNDEF:
+ case WEAK_UNDEF * 16 + DYN_UNDEF:
+ case DYN_UNDEF * 16 + DYN_UNDEF:
+ case DYN_WEAK_UNDEF * 16 + DYN_UNDEF:
+ case COMMON * 16 + DYN_UNDEF:
+ case WEAK_COMMON * 16 + DYN_UNDEF:
+ case DYN_COMMON * 16 + DYN_UNDEF:
+ case DYN_WEAK_COMMON * 16 + DYN_UNDEF:
+ // A new dynamic undefined reference tells us nothing.
+ return;
+
+ case DEF * 16 + DYN_WEAK_UNDEF:
+ case WEAK_DEF * 16 + DYN_WEAK_UNDEF:
+ case DYN_DEF * 16 + DYN_WEAK_UNDEF:
+ case DYN_WEAK_DEF * 16 + DYN_WEAK_UNDEF:
+ case UNDEF * 16 + DYN_WEAK_UNDEF:
+ case WEAK_UNDEF * 16 + DYN_WEAK_UNDEF:
+ case DYN_UNDEF * 16 + DYN_WEAK_UNDEF:
+ case DYN_WEAK_UNDEF * 16 + DYN_WEAK_UNDEF:
+ case COMMON * 16 + DYN_WEAK_UNDEF:
+ case WEAK_COMMON * 16 + DYN_WEAK_UNDEF:
+ case DYN_COMMON * 16 + DYN_WEAK_UNDEF:
+ case DYN_WEAK_COMMON * 16 + DYN_WEAK_UNDEF:
+ // A new weak dynamic undefined reference tells us nothing.
+ return;
+
+ case DEF * 16 + COMMON:
+ // A common symbol does not override a definition.
+ return;
+
+ case WEAK_DEF * 16 + COMMON:
+ case DYN_DEF * 16 + COMMON:
+ case DYN_WEAK_DEF * 16 + COMMON:
+ // A common symbol does override a weak definition or a dynamic
+ // definition.
+ to->override(sym, object, version);
+ return;
+
+ case UNDEF * 16 + COMMON:
+ case WEAK_UNDEF * 16 + COMMON:
+ case DYN_UNDEF * 16 + COMMON:
+ case DYN_WEAK_UNDEF * 16 + COMMON:
+ // A common symbol is a definition for a reference.
+ to->override(sym, object, version);
+ return;
+
+ case COMMON * 16 + COMMON:
+ // Set the size to the maximum.
+ if (sym.get_st_size() > to->symsize())
+ to->set_symsize(sym.get_st_size());
+ return;
+
+ case WEAK_COMMON * 16 + COMMON:
+ // I'm not sure just what a weak common symbol means, but
+ // presumably it can be overridden by a regular common symbol.
+ to->override(sym, object, version);
+ return;
+
+ case DYN_COMMON * 16 + COMMON:
+ case DYN_WEAK_COMMON * 16 + COMMON:
+ {
+ // Use the real common symbol, but adjust the size if necessary.
+ typename Sized_symbol<size>::Size_type symsize = to->symsize();
+ to->override(sym, object, version);
+ if (to->symsize() < symsize)
+ to->set_symsize(symsize);
+ }
+ return;
+
+ case DEF * 16 + WEAK_COMMON:
+ case WEAK_DEF * 16 + WEAK_COMMON:
+ case DYN_DEF * 16 + WEAK_COMMON:
+ case DYN_WEAK_DEF * 16 + WEAK_COMMON:
+ // Whatever a weak common symbol is, it won't override a
+ // definition.
+ return;
+
+ case UNDEF * 16 + WEAK_COMMON:
+ case WEAK_UNDEF * 16 + WEAK_COMMON:
+ case DYN_UNDEF * 16 + WEAK_COMMON:
+ case DYN_WEAK_UNDEF * 16 + WEAK_COMMON:
+ // A weak common symbol is better than an undefined symbol.
+ to->override(sym, object, version);
+ return;
+
+ case COMMON * 16 + WEAK_COMMON:
+ case WEAK_COMMON * 16 + WEAK_COMMON:
+ case DYN_COMMON * 16 + WEAK_COMMON:
+ case DYN_WEAK_COMMON * 16 + WEAK_COMMON:
+ // Ignore a weak common symbol in the presence of a real common
+ // symbol.
+ return;
+
+ case DEF * 16 + DYN_COMMON:
+ case WEAK_DEF * 16 + DYN_COMMON:
+ case DYN_DEF * 16 + DYN_COMMON:
+ case DYN_WEAK_DEF * 16 + DYN_COMMON:
+ // Ignore a dynamic common symbol in the presence of a
+ // definition.
+ return;
+
+ case UNDEF * 16 + DYN_COMMON:
+ case WEAK_UNDEF * 16 + DYN_COMMON:
+ case DYN_UNDEF * 16 + DYN_COMMON:
+ case DYN_WEAK_UNDEF * 16 + DYN_COMMON:
+ // A dynamic common symbol is a definition of sorts.
+ to->override(sym, object, version);
+ return;
+
+ case COMMON * 16 + DYN_COMMON:
+ case WEAK_COMMON * 16 + DYN_COMMON:
+ case DYN_COMMON * 16 + DYN_COMMON:
+ case DYN_WEAK_COMMON * 16 + DYN_COMMON:
+ // Set the size to the maximum.
+ if (sym.get_st_size() > to->symsize())
+ to->set_symsize(sym.get_st_size());
+ return;
+
+ case DEF * 16 + DYN_WEAK_COMMON:
+ case WEAK_DEF * 16 + DYN_WEAK_COMMON:
+ case DYN_DEF * 16 + DYN_WEAK_COMMON:
+ case DYN_WEAK_DEF * 16 + DYN_WEAK_COMMON:
+ // A common symbol is ignored in the face of a definition.
+ return;
+
+ case UNDEF * 16 + DYN_WEAK_COMMON:
+ case WEAK_UNDEF * 16 + DYN_WEAK_COMMON:
+ case DYN_UNDEF * 16 + DYN_WEAK_COMMON:
+ case DYN_WEAK_UNDEF * 16 + DYN_WEAK_COMMON:
+ // I guess a weak common symbol is better than a definition.
+ to->override(sym, object, version);
+ return;
+
+ case COMMON * 16 + DYN_WEAK_COMMON:
+ case WEAK_COMMON * 16 + DYN_WEAK_COMMON:
+ case DYN_COMMON * 16 + DYN_WEAK_COMMON:
+ case DYN_WEAK_COMMON * 16 + DYN_WEAK_COMMON:
+ // Set the size to the maximum.
+ if (sym.get_st_size() > to->symsize())
+ to->set_symsize(sym.get_st_size());
+ return;
+
+ default:
+ gold_unreachable();
+ }
+}
+
+// Instantiate the templates we need. We could use the configure
+// script to restrict this to only the ones needed for implemented
+// targets.
+
+template
+void
+Symbol_table::resolve<32, true>(
+ Sized_symbol<32>* to,
+ const elfcpp::Sym<32, true>& sym,
+ Object* object,
+ const char* version);
+
+template
+void
+Symbol_table::resolve<32, false>(
+ Sized_symbol<32>* to,
+ const elfcpp::Sym<32, false>& sym,
+ Object* object,
+ const char* version);
+
+template
+void
+Symbol_table::resolve<64, true>(
+ Sized_symbol<64>* to,
+ const elfcpp::Sym<64, true>& sym,
+ Object* object,
+ const char* version);
+
+template
+void
+Symbol_table::resolve<64, false>(
+ Sized_symbol<64>* to,
+ const elfcpp::Sym<64, false>& sym,
+ Object* object,
+ const char* version);
+
+} // End namespace gold.
diff --git a/gold/script-c.h b/gold/script-c.h
new file mode 100644
index 000000000000..e40488985d0f
--- /dev/null
+++ b/gold/script-c.h
@@ -0,0 +1,53 @@
+/* script-c.h -- C interface for linker scripts in gold. */
+
+/* This file exists so that both the bison parser and script.cc can
+ include it, so that they can communicate back and forth. */
+
+#ifndef GOLD_SCRIPT_C_H
+#define GOLD_SCRIPT_C_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "yyscript.h"
+
+/* The bison parser function. */
+
+extern int
+yyparse(void* closure);
+
+/* Called by the bison parser skeleton to return the next token. */
+
+extern int
+yylex(YYSTYPE*, void* closure);
+
+/* Called by the bison parser skeleton to report an error. */
+
+extern void
+yyerror(void* closure, const char*);
+
+/* Called by the bison parser to add a file to the link. */
+
+extern void
+script_add_file(void* closure, const char*);
+
+/* Called by the bison parser to start and stop a group. */
+
+extern void
+script_start_group(void* closure);
+extern void
+script_end_group(void* closure);
+
+/* Called by the bison parser to start and end an AS_NEEDED list. */
+
+extern void
+script_start_as_needed(void* closure);
+extern void
+script_end_as_needed(void* closure);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !defined(GOLD_SCRIPT_C_H) */
diff --git a/gold/script.cc b/gold/script.cc
new file mode 100644
index 000000000000..f5584d9b01ea
--- /dev/null
+++ b/gold/script.cc
@@ -0,0 +1,1193 @@
+// script.cc -- handle linker scripts for gold.
+
+#include "gold.h"
+
+#include <string>
+#include <vector>
+#include <cstdio>
+#include <cstdlib>
+
+#include "options.h"
+#include "fileread.h"
+#include "workqueue.h"
+#include "readsyms.h"
+#include "yyscript.h"
+#include "script.h"
+#include "script-c.h"
+
+namespace gold
+{
+
+// A token read from a script file. We don't implement keywords here;
+// all keywords are simply represented as a string.
+
+class Token
+{
+ public:
+ // Token classification.
+ enum Classification
+ {
+ // Token is invalid.
+ TOKEN_INVALID,
+ // Token indicates end of input.
+ TOKEN_EOF,
+ // Token is a string of characters.
+ TOKEN_STRING,
+ // Token is an operator.
+ TOKEN_OPERATOR,
+ // Token is a number (an integer).
+ TOKEN_INTEGER
+ };
+
+ // We need an empty constructor so that we can put this STL objects.
+ Token()
+ : classification_(TOKEN_INVALID), value_(), opcode_(0),
+ lineno_(0), charpos_(0)
+ { }
+
+ // A general token with no value.
+ Token(Classification classification, int lineno, int charpos)
+ : classification_(classification), value_(), opcode_(0),
+ lineno_(lineno), charpos_(charpos)
+ {
+ gold_assert(classification == TOKEN_INVALID
+ || classification == TOKEN_EOF);
+ }
+
+ // A general token with a value.
+ Token(Classification classification, const std::string& value,
+ int lineno, int charpos)
+ : classification_(classification), value_(value), opcode_(0),
+ lineno_(lineno), charpos_(charpos)
+ {
+ gold_assert(classification != TOKEN_INVALID
+ && classification != TOKEN_EOF);
+ }
+
+ // A token representing a string of characters.
+ Token(const std::string& s, int lineno, int charpos)
+ : classification_(TOKEN_STRING), value_(s), opcode_(0),
+ lineno_(lineno), charpos_(charpos)
+ { }
+
+ // A token representing an operator.
+ Token(int opcode, int lineno, int charpos)
+ : classification_(TOKEN_OPERATOR), value_(), opcode_(opcode),
+ lineno_(lineno), charpos_(charpos)
+ { }
+
+ // Return whether the token is invalid.
+ bool
+ is_invalid() const
+ { return this->classification_ == TOKEN_INVALID; }
+
+ // Return whether this is an EOF token.
+ bool
+ is_eof() const
+ { return this->classification_ == TOKEN_EOF; }
+
+ // Return the token classification.
+ Classification
+ classification() const
+ { return this->classification_; }
+
+ // Return the line number at which the token starts.
+ int
+ lineno() const
+ { return this->lineno_; }
+
+ // Return the character position at this the token starts.
+ int
+ charpos() const
+ { return this->charpos_; }
+
+ // Get the value of a token.
+
+ const std::string&
+ string_value() const
+ {
+ gold_assert(this->classification_ == TOKEN_STRING);
+ return this->value_;
+ }
+
+ int
+ operator_value() const
+ {
+ gold_assert(this->classification_ == TOKEN_OPERATOR);
+ return this->opcode_;
+ }
+
+ int64_t
+ integer_value() const
+ {
+ gold_assert(this->classification_ == TOKEN_INTEGER);
+ return strtoll(this->value_.c_str(), NULL, 0);
+ }
+
+ private:
+ // The token classification.
+ Classification classification_;
+ // The token value, for TOKEN_STRING or TOKEN_INTEGER.
+ std::string value_;
+ // The token value, for TOKEN_OPERATOR.
+ int opcode_;
+ // The line number where this token started (one based).
+ int lineno_;
+ // The character position within the line where this token started
+ // (one based).
+ int charpos_;
+};
+
+// This class handles lexing a file into a sequence of tokens. We
+// don't expect linker scripts to be large, so we just read them and
+// tokenize them all at once.
+
+class Lex
+{
+ public:
+ Lex(Input_file* input_file)
+ : input_file_(input_file), tokens_()
+ { }
+
+ // Tokenize the file. Return the final token, which will be either
+ // an invalid token or an EOF token. An invalid token indicates
+ // that tokenization failed.
+ Token
+ tokenize();
+
+ // A token sequence.
+ typedef std::vector<Token> Token_sequence;
+
+ // Return the tokens.
+ const Token_sequence&
+ tokens() const
+ { return this->tokens_; }
+
+ private:
+ Lex(const Lex&);
+ Lex& operator=(const Lex&);
+
+ // Read the file into a string buffer.
+ void
+ read_file(std::string*);
+
+ // Make a general token with no value at the current location.
+ Token
+ make_token(Token::Classification c, const char* p) const
+ { return Token(c, this->lineno_, p - this->linestart_ + 1); }
+
+ // Make a general token with a value at the current location.
+ Token
+ make_token(Token::Classification c, const std::string& v, const char* p)
+ const
+ { return Token(c, v, this->lineno_, p - this->linestart_ + 1); }
+
+ // Make an operator token at the current location.
+ Token
+ make_token(int opcode, const char* p) const
+ { return Token(opcode, this->lineno_, p - this->linestart_ + 1); }
+
+ // Make an invalid token at the current location.
+ Token
+ make_invalid_token(const char* p)
+ { return this->make_token(Token::TOKEN_INVALID, p); }
+
+ // Make an EOF token at the current location.
+ Token
+ make_eof_token(const char* p)
+ { return this->make_token(Token::TOKEN_EOF, p); }
+
+ // Return whether C can be the first character in a name. C2 is the
+ // next character, since we sometimes need that.
+ static inline bool
+ can_start_name(char c, char c2);
+
+ // Return whether C can appear in a name which has already started.
+ static inline bool
+ can_continue_name(char c);
+
+ // Return whether C, C2, C3 can start a hex number.
+ static inline bool
+ can_start_hex(char c, char c2, char c3);
+
+ // Return whether C can appear in a hex number.
+ static inline bool
+ can_continue_hex(char c);
+
+ // Return whether C can start a non-hex number.
+ static inline bool
+ can_start_number(char c);
+
+ // Return whether C can appear in a non-hex number.
+ static inline bool
+ can_continue_number(char c)
+ { return Lex::can_start_number(c); }
+
+ // If C1 C2 C3 form a valid three character operator, return the
+ // opcode. Otherwise return 0.
+ static inline int
+ three_char_operator(char c1, char c2, char c3);
+
+ // If C1 C2 form a valid two character operator, return the opcode.
+ // Otherwise return 0.
+ static inline int
+ two_char_operator(char c1, char c2);
+
+ // If C1 is a valid one character operator, return the opcode.
+ // Otherwise return 0.
+ static inline int
+ one_char_operator(char c1);
+
+ // Read the next token.
+ Token
+ get_token(const char**);
+
+ // Skip a C style /* */ comment. Return false if the comment did
+ // not end.
+ bool
+ skip_c_comment(const char**);
+
+ // Skip a line # comment. Return false if there was no newline.
+ bool
+ skip_line_comment(const char**);
+
+ // Build a token CLASSIFICATION from all characters that match
+ // CAN_CONTINUE_FN. The token starts at START. Start matching from
+ // MATCH. Set *PP to the character following the token.
+ inline Token
+ gather_token(Token::Classification, bool (*can_continue_fn)(char),
+ const char* start, const char* match, const char** pp);
+
+ // Build a token from a quoted string.
+ Token
+ gather_quoted_string(const char** pp);
+
+ // The file we are reading.
+ Input_file* input_file_;
+ // The token sequence we create.
+ Token_sequence tokens_;
+ // The current line number.
+ int lineno_;
+ // The start of the current line in the buffer.
+ const char* linestart_;
+};
+
+// Read the whole file into memory. We don't expect linker scripts to
+// be large, so we just use a std::string as a buffer. We ignore the
+// data we've already read, so that we read aligned buffers.
+
+void
+Lex::read_file(std::string* contents)
+{
+ contents->clear();
+ off_t off = 0;
+ off_t got;
+ unsigned char buf[BUFSIZ];
+ do
+ {
+ this->input_file_->file().read(off, sizeof buf, buf, &got);
+ contents->append(reinterpret_cast<char*>(&buf[0]), got);
+ }
+ while (got == sizeof buf);
+}
+
+// Return whether C can be the start of a name, if the next character
+// is C2. A name can being with a letter, underscore, period, or
+// dollar sign. Because a name can be a file name, we also permit
+// forward slash, backslash, and tilde. Tilde is the tricky case
+// here; GNU ld also uses it as a bitwise not operator. It is only
+// recognized as the operator if it is not immediately followed by
+// some character which can appear in a symbol. That is, "~0" is a
+// symbol name, and "~ 0" is an expression using bitwise not. We are
+// compatible.
+
+inline bool
+Lex::can_start_name(char c, char c2)
+{
+ switch (c)
+ {
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+ case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
+ case 'M': case 'N': case 'O': case 'Q': case 'P': case 'R':
+ case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
+ case 'Y': case 'Z':
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
+ case 'm': case 'n': case 'o': case 'q': case 'p': case 'r':
+ case 's': case 't': case 'u': case 'v': case 'w': case 'x':
+ case 'y': case 'z':
+ case '_': case '.': case '$': case '/': case '\\':
+ return true;
+
+ case '~':
+ return can_continue_name(c2);
+
+ default:
+ return false;
+ }
+}
+
+// Return whether C can continue a name which has already started.
+// Subsequent characters in a name are the same as the leading
+// characters, plus digits and "=+-:[],?*". So in general the linker
+// script language requires spaces around operators.
+
+inline bool
+Lex::can_continue_name(char c)
+{
+ switch (c)
+ {
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+ case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
+ case 'M': case 'N': case 'O': case 'Q': case 'P': case 'R':
+ case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
+ case 'Y': case 'Z':
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
+ case 'm': case 'n': case 'o': case 'q': case 'p': case 'r':
+ case 's': case 't': case 'u': case 'v': case 'w': case 'x':
+ case 'y': case 'z':
+ case '_': case '.': case '$': case '/': case '\\':
+ case '~':
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ case '=': case '+': case '-': case ':': case '[': case ']':
+ case ',': case '?': case '*':
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+// For a number we accept 0x followed by hex digits, or any sequence
+// of digits. The old linker accepts leading '$' for hex, and
+// trailing HXBOD. Those are for MRI compatibility and we don't
+// accept them. The old linker also accepts trailing MK for mega or
+// kilo. Those are mentioned in the documentation, and we accept
+// them.
+
+// Return whether C1 C2 C3 can start a hex number.
+
+inline bool
+Lex::can_start_hex(char c1, char c2, char c3)
+{
+ if (c1 == '0' && (c2 == 'x' || c2 == 'X'))
+ return Lex::can_continue_hex(c3);
+ return false;
+}
+
+// Return whether C can appear in a hex number.
+
+inline bool
+Lex::can_continue_hex(char c)
+{
+ switch (c)
+ {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+// Return whether C can start a non-hex number.
+
+inline bool
+Lex::can_start_number(char c)
+{
+ switch (c)
+ {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+// If C1 C2 C3 form a valid three character operator, return the
+// opcode (defined in the yyscript.h file generated from yyscript.y).
+// Otherwise return 0.
+
+inline int
+Lex::three_char_operator(char c1, char c2, char c3)
+{
+ switch (c1)
+ {
+ case '<':
+ if (c2 == '<' && c3 == '=')
+ return LSHIFTEQ;
+ break;
+ case '>':
+ if (c2 == '>' && c3 == '=')
+ return RSHIFTEQ;
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+// If C1 C2 form a valid two character operator, return the opcode
+// (defined in the yyscript.h file generated from yyscript.y).
+// Otherwise return 0.
+
+inline int
+Lex::two_char_operator(char c1, char c2)
+{
+ switch (c1)
+ {
+ case '=':
+ if (c2 == '=')
+ return EQ;
+ break;
+ case '!':
+ if (c2 == '=')
+ return NE;
+ break;
+ case '+':
+ if (c2 == '=')
+ return PLUSEQ;
+ break;
+ case '-':
+ if (c2 == '=')
+ return MINUSEQ;
+ break;
+ case '*':
+ if (c2 == '=')
+ return MULTEQ;
+ break;
+ case '/':
+ if (c2 == '=')
+ return DIVEQ;
+ break;
+ case '|':
+ if (c2 == '=')
+ return OREQ;
+ if (c2 == '|')
+ return OROR;
+ break;
+ case '&':
+ if (c2 == '=')
+ return ANDEQ;
+ if (c2 == '&')
+ return ANDAND;
+ break;
+ case '>':
+ if (c2 == '=')
+ return GE;
+ if (c2 == '>')
+ return RSHIFT;
+ break;
+ case '<':
+ if (c2 == '=')
+ return LE;
+ if (c2 == '<')
+ return LSHIFT;
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+// If C1 is a valid operator, return the opcode. Otherwise return 0.
+
+inline int
+Lex::one_char_operator(char c1)
+{
+ switch (c1)
+ {
+ case '+':
+ case '-':
+ case '*':
+ case '/':
+ case '%':
+ case '!':
+ case '&':
+ case '|':
+ case '^':
+ case '~':
+ case '<':
+ case '>':
+ case '=':
+ case '?':
+ case ',':
+ case '(':
+ case ')':
+ case '{':
+ case '}':
+ case '[':
+ case ']':
+ case ':':
+ case ';':
+ return c1;
+ default:
+ return 0;
+ }
+}
+
+// Skip a C style comment. *PP points to just after the "/*". Return
+// false if the comment did not end.
+
+bool
+Lex::skip_c_comment(const char** pp)
+{
+ const char* p = *pp;
+ while (p[0] != '*' || p[1] != '/')
+ {
+ if (*p == '\0')
+ {
+ *pp = p;
+ return false;
+ }
+
+ if (*p == '\n')
+ {
+ ++this->lineno_;
+ this->linestart_ = p + 1;
+ }
+ ++p;
+ }
+
+ *pp = p + 2;
+ return true;
+}
+
+// Skip a line # comment. Return false if there was no newline.
+
+bool
+Lex::skip_line_comment(const char** pp)
+{
+ const char* p = *pp;
+ size_t skip = strcspn(p, "\n");
+ if (p[skip] == '\0')
+ {
+ *pp = p + skip;
+ return false;
+ }
+
+ p += skip + 1;
+ ++this->lineno_;
+ this->linestart_ = p;
+ *pp = p;
+
+ return true;
+}
+
+// Build a token CLASSIFICATION from all characters that match
+// CAN_CONTINUE_FN. Update *PP.
+
+inline Token
+Lex::gather_token(Token::Classification classification,
+ bool (*can_continue_fn)(char),
+ const char* start,
+ const char* match,
+ const char **pp)
+{
+ while ((*can_continue_fn)(*match))
+ ++match;
+ *pp = match;
+ return this->make_token(classification,
+ std::string(start, match - start),
+ start);
+}
+
+// Build a token from a quoted string.
+
+Token
+Lex::gather_quoted_string(const char** pp)
+{
+ const char* start = *pp;
+ const char* p = start;
+ ++p;
+ size_t skip = strcspn(p, "\"\n");
+ if (p[skip] != '"')
+ return this->make_invalid_token(start);
+ *pp = p + skip + 1;
+ return this->make_token(Token::TOKEN_STRING,
+ std::string(p, skip),
+ start);
+}
+
+// Return the next token at *PP. Update *PP. General guideline: we
+// require linker scripts to be simple ASCII. No unicode linker
+// scripts. In particular we can assume that any '\0' is the end of
+// the input.
+
+Token
+Lex::get_token(const char** pp)
+{
+ const char* p = *pp;
+
+ while (true)
+ {
+ if (*p == '\0')
+ {
+ *pp = p;
+ return this->make_eof_token(p);
+ }
+
+ // Skip whitespace quickly.
+ while (*p == ' ' || *p == '\t')
+ ++p;
+
+ if (*p == '\n')
+ {
+ ++p;
+ ++this->lineno_;
+ this->linestart_ = p;
+ continue;
+ }
+
+ // Skip C style comments.
+ if (p[0] == '/' && p[1] == '*')
+ {
+ int lineno = this->lineno_;
+ int charpos = p - this->linestart_ + 1;
+
+ *pp = p + 2;
+ if (!this->skip_c_comment(pp))
+ return Token(Token::TOKEN_INVALID, lineno, charpos);
+ p = *pp;
+
+ continue;
+ }
+
+ // Skip line comments.
+ if (*p == '#')
+ {
+ *pp = p + 1;
+ if (!this->skip_line_comment(pp))
+ return this->make_eof_token(p);
+ p = *pp;
+ continue;
+ }
+
+ // Check for a name.
+ if (Lex::can_start_name(p[0], p[1]))
+ return this->gather_token(Token::TOKEN_STRING,
+ Lex::can_continue_name,
+ p, p + 2, pp);
+
+ // We accept any arbitrary name in double quotes, as long as it
+ // does not cross a line boundary.
+ if (*p == '"')
+ {
+ *pp = p;
+ return this->gather_quoted_string(pp);
+ }
+
+ // Check for a number.
+
+ if (Lex::can_start_hex(p[0], p[1], p[2]))
+ return this->gather_token(Token::TOKEN_INTEGER,
+ Lex::can_continue_hex,
+ p, p + 3, pp);
+
+ if (Lex::can_start_number(p[0]))
+ return this->gather_token(Token::TOKEN_INTEGER,
+ Lex::can_continue_number,
+ p, p + 1, pp);
+
+ // Check for operators.
+
+ int opcode = Lex::three_char_operator(p[0], p[1], p[2]);
+ if (opcode != 0)
+ {
+ *pp = p + 3;
+ return this->make_token(opcode, p);
+ }
+
+ opcode = Lex::two_char_operator(p[0], p[1]);
+ if (opcode != 0)
+ {
+ *pp = p + 2;
+ return this->make_token(opcode, p);
+ }
+
+ opcode = Lex::one_char_operator(p[0]);
+ if (opcode != 0)
+ {
+ *pp = p + 1;
+ return this->make_token(opcode, p);
+ }
+
+ return this->make_token(Token::TOKEN_INVALID, p);
+ }
+}
+
+// Tokenize the file. Return the final token.
+
+Token
+Lex::tokenize()
+{
+ std::string contents;
+ this->read_file(&contents);
+
+ const char* p = contents.c_str();
+
+ this->lineno_ = 1;
+ this->linestart_ = p;
+
+ while (true)
+ {
+ Token t(this->get_token(&p));
+
+ // Don't let an early null byte fool us into thinking that we've
+ // reached the end of the file.
+ if (t.is_eof()
+ && static_cast<size_t>(p - contents.c_str()) < contents.length())
+ t = this->make_invalid_token(p);
+
+ if (t.is_invalid() || t.is_eof())
+ return t;
+
+ this->tokens_.push_back(t);
+ }
+}
+
+// A trivial task which waits for THIS_BLOCKER to be clear and then
+// clears NEXT_BLOCKER. THIS_BLOCKER may be NULL.
+
+class Script_unblock : public Task
+{
+ public:
+ Script_unblock(Task_token* this_blocker, Task_token* next_blocker)
+ : this_blocker_(this_blocker), next_blocker_(next_blocker)
+ { }
+
+ ~Script_unblock()
+ {
+ if (this->this_blocker_ != NULL)
+ delete this->this_blocker_;
+ }
+
+ Is_runnable_type
+ is_runnable(Workqueue*)
+ {
+ if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
+ return IS_BLOCKED;
+ return IS_RUNNABLE;
+ }
+
+ Task_locker*
+ locks(Workqueue* workqueue)
+ {
+ return new Task_locker_block(*this->next_blocker_, workqueue);
+ }
+
+ void
+ run(Workqueue*)
+ { }
+
+ private:
+ Task_token* this_blocker_;
+ Task_token* next_blocker_;
+};
+
+// This class holds data passed through the parser to the lexer and to
+// the parser support functions. This avoids global variables. We
+// can't use global variables because we need not be called in the
+// main thread.
+
+class Parser_closure
+{
+ public:
+ Parser_closure(const char* filename,
+ const Position_dependent_options& posdep_options,
+ bool in_group,
+ const Lex::Token_sequence* tokens)
+ : filename_(filename), posdep_options_(posdep_options),
+ in_group_(in_group), tokens_(tokens),
+ next_token_index_(0), inputs_(NULL)
+ { }
+
+ // Return the file name.
+ const char*
+ filename() const
+ { return this->filename_; }
+
+ // Return the position dependent options. The caller may modify
+ // this.
+ Position_dependent_options&
+ position_dependent_options()
+ { return this->posdep_options_; }
+
+ // Return whether this script is being run in a group.
+ bool
+ in_group() const
+ { return this->in_group_; }
+
+ // Whether we are at the end of the token list.
+ bool
+ at_eof() const
+ { return this->next_token_index_ >= this->tokens_->size(); }
+
+ // Return the next token.
+ const Token*
+ next_token()
+ {
+ const Token* ret = &(*this->tokens_)[this->next_token_index_];
+ ++this->next_token_index_;
+ return ret;
+ }
+
+ // Return the list of input files, creating it if necessary. This
+ // is a space leak--we never free the INPUTS_ pointer.
+ Input_arguments*
+ inputs()
+ {
+ if (this->inputs_ == NULL)
+ this->inputs_ = new Input_arguments();
+ return this->inputs_;
+ }
+
+ // Return whether we saw any input files.
+ bool
+ saw_inputs() const
+ { return this->inputs_ != NULL && !this->inputs_->empty(); }
+
+ private:
+ // The name of the file we are reading.
+ const char* filename_;
+ // The position dependent options.
+ Position_dependent_options posdep_options_;
+ // Whether we are currently in a --start-group/--end-group.
+ bool in_group_;
+
+ // The tokens to be returned by the lexer.
+ const Lex::Token_sequence* tokens_;
+ // The index of the next token to return.
+ unsigned int next_token_index_;
+ // New input files found to add to the link.
+ Input_arguments* inputs_;
+};
+
+// FILE was found as an argument on the command line. Try to read it
+// as a script. We've already read BYTES of data into P, but we
+// ignore that. Return true if the file was handled.
+
+bool
+read_input_script(Workqueue* workqueue, const General_options& options,
+ Symbol_table* symtab, Layout* layout,
+ const Dirsearch& dirsearch, Input_objects* input_objects,
+ Input_group* input_group,
+ const Input_argument* input_argument,
+ Input_file* input_file, const unsigned char*, off_t,
+ Task_token* this_blocker, Task_token* next_blocker)
+{
+ Lex lex(input_file);
+ if (lex.tokenize().is_invalid())
+ return false;
+
+ Parser_closure closure(input_file->filename().c_str(),
+ input_argument->file().options(),
+ input_group != NULL,
+ &lex.tokens());
+
+ if (yyparse(&closure) != 0)
+ return false;
+
+ // THIS_BLOCKER must be clear before we may add anything to the
+ // symbol table. We are responsible for unblocking NEXT_BLOCKER
+ // when we are done. We are responsible for deleting THIS_BLOCKER
+ // when it is unblocked.
+
+ if (!closure.saw_inputs())
+ {
+ // The script did not add any files to read. Note that we are
+ // not permitted to call NEXT_BLOCKER->unblock() here even if
+ // THIS_BLOCKER is NULL, as we are not in the main thread.
+ workqueue->queue(new Script_unblock(this_blocker, next_blocker));
+ return true;
+ }
+
+ for (Input_arguments::const_iterator p = closure.inputs()->begin();
+ p != closure.inputs()->end();
+ ++p)
+ {
+ Task_token* nb;
+ if (p + 1 == closure.inputs()->end())
+ nb = next_blocker;
+ else
+ {
+ nb = new Task_token();
+ nb->add_blocker();
+ }
+ workqueue->queue(new Read_symbols(options, input_objects, symtab,
+ layout, dirsearch, &*p,
+ input_group, this_blocker, nb));
+ this_blocker = nb;
+ }
+
+ return true;
+}
+
+// Manage mapping from keywords to the codes expected by the bison
+// parser.
+
+class Keyword_to_parsecode
+{
+ public:
+ // The structure which maps keywords to parsecodes.
+ struct Keyword_parsecode
+ {
+ // Keyword.
+ const char* keyword;
+ // Corresponding parsecode.
+ int parsecode;
+ };
+
+ // Return the parsecode corresponding KEYWORD, or 0 if it is not a
+ // keyword.
+ static int
+ keyword_to_parsecode(const char* keyword);
+
+ private:
+ // The array of all keywords.
+ static const Keyword_parsecode keyword_parsecodes_[];
+
+ // The number of keywords.
+ static const int keyword_count;
+};
+
+// Mapping from keyword string to keyword parsecode. This array must
+// be kept in sorted order. Parsecodes are looked up using bsearch.
+// This array must correspond to the list of parsecodes in yyscript.y.
+
+const Keyword_to_parsecode::Keyword_parsecode
+Keyword_to_parsecode::keyword_parsecodes_[] =
+{
+ { "ABSOLUTE", ABSOLUTE },
+ { "ADDR", ADDR },
+ { "ALIGN", ALIGN_K },
+ { "ASSERT", ASSERT_K },
+ { "AS_NEEDED", AS_NEEDED },
+ { "AT", AT },
+ { "BIND", BIND },
+ { "BLOCK", BLOCK },
+ { "BYTE", BYTE },
+ { "CONSTANT", CONSTANT },
+ { "CONSTRUCTORS", CONSTRUCTORS },
+ { "COPY", COPY },
+ { "CREATE_OBJECT_SYMBOLS", CREATE_OBJECT_SYMBOLS },
+ { "DATA_SEGMENT_ALIGN", DATA_SEGMENT_ALIGN },
+ { "DATA_SEGMENT_END", DATA_SEGMENT_END },
+ { "DATA_SEGMENT_RELRO_END", DATA_SEGMENT_RELRO_END },
+ { "DEFINED", DEFINED },
+ { "DSECT", DSECT },
+ { "ENTRY", ENTRY },
+ { "EXCLUDE_FILE", EXCLUDE_FILE },
+ { "EXTERN", EXTERN },
+ { "FILL", FILL },
+ { "FLOAT", FLOAT },
+ { "FORCE_COMMON_ALLOCATION", FORCE_COMMON_ALLOCATION },
+ { "GROUP", GROUP },
+ { "HLL", HLL },
+ { "INCLUDE", INCLUDE },
+ { "INFO", INFO },
+ { "INHIBIT_COMMON_ALLOCATION", INHIBIT_COMMON_ALLOCATION },
+ { "INPUT", INPUT },
+ { "KEEP", KEEP },
+ { "LENGTH", LENGTH },
+ { "LOADADDR", LOADADDR },
+ { "LONG", LONG },
+ { "MAP", MAP },
+ { "MAX", MAX_K },
+ { "MEMORY", MEMORY },
+ { "MIN", MIN_K },
+ { "NEXT", NEXT },
+ { "NOCROSSREFS", NOCROSSREFS },
+ { "NOFLOAT", NOFLOAT },
+ { "NOLOAD", NOLOAD },
+ { "ONLY_IF_RO", ONLY_IF_RO },
+ { "ONLY_IF_RW", ONLY_IF_RW },
+ { "ORIGIN", ORIGIN },
+ { "OUTPUT", OUTPUT },
+ { "OUTPUT_ARCH", OUTPUT_ARCH },
+ { "OUTPUT_FORMAT", OUTPUT_FORMAT },
+ { "OVERLAY", OVERLAY },
+ { "PHDRS", PHDRS },
+ { "PROVIDE", PROVIDE },
+ { "PROVIDE_HIDDEN", PROVIDE_HIDDEN },
+ { "QUAD", QUAD },
+ { "SEARCH_DIR", SEARCH_DIR },
+ { "SECTIONS", SECTIONS },
+ { "SEGMENT_START", SEGMENT_START },
+ { "SHORT", SHORT },
+ { "SIZEOF", SIZEOF },
+ { "SIZEOF_HEADERS", SIZEOF_HEADERS },
+ { "SORT_BY_ALIGNMENT", SORT_BY_ALIGNMENT },
+ { "SORT_BY_NAME", SORT_BY_NAME },
+ { "SPECIAL", SPECIAL },
+ { "SQUAD", SQUAD },
+ { "STARTUP", STARTUP },
+ { "SUBALIGN", SUBALIGN },
+ { "SYSLIB", SYSLIB },
+ { "TARGET", TARGET_K },
+ { "TRUNCATE", TRUNCATE },
+ { "VERSION", VERSIONK },
+ { "global", GLOBAL },
+ { "l", LENGTH },
+ { "len", LENGTH },
+ { "local", LOCAL },
+ { "o", ORIGIN },
+ { "org", ORIGIN },
+ { "sizeof_headers", SIZEOF_HEADERS },
+};
+
+const int Keyword_to_parsecode::keyword_count =
+ (sizeof(Keyword_to_parsecode::keyword_parsecodes_)
+ / sizeof(Keyword_to_parsecode::keyword_parsecodes_[0]));
+
+// Comparison function passed to bsearch.
+
+extern "C"
+{
+
+static int
+ktt_compare(const void* keyv, const void* kttv)
+{
+ const char* key = static_cast<const char*>(keyv);
+ const Keyword_to_parsecode::Keyword_parsecode* ktt =
+ static_cast<const Keyword_to_parsecode::Keyword_parsecode*>(kttv);
+ return strcmp(key, ktt->keyword);
+}
+
+} // End extern "C".
+
+int
+Keyword_to_parsecode::keyword_to_parsecode(const char* keyword)
+{
+ void* kttv = bsearch(keyword,
+ Keyword_to_parsecode::keyword_parsecodes_,
+ Keyword_to_parsecode::keyword_count,
+ sizeof(Keyword_to_parsecode::keyword_parsecodes_[0]),
+ ktt_compare);
+ if (kttv == NULL)
+ return 0;
+ Keyword_parsecode* ktt = static_cast<Keyword_parsecode*>(kttv);
+ return ktt->parsecode;
+}
+
+} // End namespace gold.
+
+// The remaining functions are extern "C", so it's clearer to not put
+// them in namespace gold.
+
+using namespace gold;
+
+// This function is called by the bison parser to return the next
+// token.
+
+extern "C" int
+yylex(YYSTYPE* lvalp, void* closurev)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+
+ if (closure->at_eof())
+ return 0;
+
+ const Token* token = closure->next_token();
+
+ switch (token->classification())
+ {
+ default:
+ case Token::TOKEN_INVALID:
+ case Token::TOKEN_EOF:
+ gold_unreachable();
+
+ case Token::TOKEN_STRING:
+ {
+ const char* str = token->string_value().c_str();
+ int parsecode = Keyword_to_parsecode::keyword_to_parsecode(str);
+ if (parsecode != 0)
+ return parsecode;
+ lvalp->string = str;
+ return STRING;
+ }
+
+ case Token::TOKEN_OPERATOR:
+ return token->operator_value();
+
+ case Token::TOKEN_INTEGER:
+ lvalp->integer = token->integer_value();
+ return INTEGER;
+ }
+}
+
+// This function is called by the bison parser to report an error.
+
+extern "C" void
+yyerror(void* closurev, const char* message)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+
+ fprintf(stderr, _("%s: %s: %s\n"),
+ program_name, closure->filename(), message);
+ gold_exit(false);
+}
+
+// Called by the bison parser to add a file to the link.
+
+extern "C" void
+script_add_file(void* closurev, const char* name)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ Input_file_argument file(name, false, closure->position_dependent_options());
+ closure->inputs()->add_file(file);
+}
+
+// Called by the bison parser to start a group. If we are already in
+// a group, that means that this script was invoked within a
+// --start-group --end-group sequence on the command line, or that
+// this script was found in a GROUP of another script. In that case,
+// we simply continue the existing group, rather than starting a new
+// one. It is possible to construct a case in which this will do
+// something other than what would happen if we did a recursive group,
+// but it's hard to imagine why the different behaviour would be
+// useful for a real program. Avoiding recursive groups is simpler
+// and more efficient.
+
+extern "C" void
+script_start_group(void* closurev)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ if (!closure->in_group())
+ closure->inputs()->start_group();
+}
+
+// Called by the bison parser at the end of a group.
+
+extern "C" void
+script_end_group(void* closurev)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ if (!closure->in_group())
+ closure->inputs()->end_group();
+}
+
+// Called by the bison parser to start an AS_NEEDED list.
+
+extern "C" void
+script_start_as_needed(void* closurev)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ closure->position_dependent_options().set_as_needed();
+}
+
+// Called by the bison parser at the end of an AS_NEEDED list.
+
+extern "C" void
+script_end_as_needed(void* closurev)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ closure->position_dependent_options().clear_as_needed();
+}
diff --git a/gold/script.h b/gold/script.h
new file mode 100644
index 000000000000..de2e5af1a661
--- /dev/null
+++ b/gold/script.h
@@ -0,0 +1,39 @@
+// script.h -- handle linker scripts for gold -*- C++ -*-
+
+// We implement a subset of the original GNU ld linker script language
+// for compatibility. The goal is not to implement the entire
+// language. It is merely to implement enough to handle common uses.
+// In particular we need to handle /usr/lib/libc.so on a typical
+// GNU/Linux system, and we want to handle linker scripts used by the
+// Linux kernel build.
+
+#ifndef GOLD_SCRIPT_H
+#define GOLD_SCRIPT_H
+
+namespace gold
+{
+
+class General_options;
+class Symbol_table;
+class Layout;
+class Input_objects;
+class Input_group;
+class Input_file;
+class Task_token;
+
+// FILE was found as an argument on the command line, but was not
+// recognized as an ELF file. Try to read it as a script. We've
+// already read BYTES of data into P. Return true if the file was
+// handled. This has to handle /usr/lib/libc.so on a GNU/Linux
+// system.
+
+bool
+read_input_script(Workqueue*, const General_options&, Symbol_table*, Layout*,
+ const Dirsearch&, Input_objects*, Input_group*,
+ const Input_argument*, Input_file*, const unsigned char* p,
+ off_t bytes, Task_token* this_blocker,
+ Task_token* next_blocker);
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_SCRIPT_H)
diff --git a/gold/stringpool.cc b/gold/stringpool.cc
new file mode 100644
index 000000000000..34c11b4fc42a
--- /dev/null
+++ b/gold/stringpool.cc
@@ -0,0 +1,386 @@
+// stringpool.cc -- a string pool for gold
+
+#include "gold.h"
+
+#include <cstring>
+#include <algorithm>
+#include <vector>
+
+#include "output.h"
+#include "stringpool.h"
+
+namespace gold
+{
+
+template<typename Stringpool_char>
+Stringpool_template<Stringpool_char>::Stringpool_template(bool zero_null)
+ : string_set_(), strings_(), strtab_size_(0), next_index_(1),
+ zero_null_(zero_null)
+{
+}
+
+template<typename Stringpool_char>
+Stringpool_template<Stringpool_char>::~Stringpool_template()
+{
+ for (typename std::list<Stringdata*>::iterator p = this->strings_.begin();
+ p != this->strings_.end();
+ ++p)
+ delete[] reinterpret_cast<char*>(*p);
+}
+
+// Return the length of a string of arbitrary character type.
+
+template<typename Stringpool_char>
+size_t
+Stringpool_template<Stringpool_char>::string_length(const Stringpool_char* p)
+{
+ size_t len = 0;
+ for (; *p != 0; ++p)
+ ++len;
+ return len;
+}
+
+// Specialize string_length for char. Maybe we could just use
+// std::char_traits<>::length?
+
+template<>
+inline size_t
+Stringpool_template<char>::string_length(const char* p)
+{
+ return strlen(p);
+}
+
+// Equality comparison function.
+
+template<typename Stringpool_char>
+bool
+Stringpool_template<Stringpool_char>::Stringpool_eq::operator()(
+ const Stringpool_char* s1,
+ const Stringpool_char* s2) const
+{
+ while (*s1 != 0)
+ if (*s1++ != *s2++)
+ return false;
+ return *s2 == 0;
+}
+
+// Specialize equality comparison for char.
+
+template<>
+bool
+Stringpool_template<char>::Stringpool_eq::operator()(const char* s1,
+ const char* s2) const
+{
+ return strcmp(s1, s2) == 0;
+}
+
+// Hash function.
+
+template<typename Stringpool_char>
+size_t
+Stringpool_template<Stringpool_char>::Stringpool_hash::operator()(
+ const Stringpool_char* s) const
+{
+ // Fowler/Noll/Vo (FNV) hash (type FNV-1a).
+ if (sizeof(size_t) == 8)
+ {
+ size_t result = static_cast<size_t>(14695981039346656037ULL);
+ while (*s != 0)
+ {
+ const char* p = reinterpret_cast<const char*>(s);
+ for (size_t i = 0; i < sizeof(Stringpool_char); ++i)
+ {
+ result &= (size_t) *p++;
+ result *= 1099511628211ULL;
+ }
+ ++s;
+ }
+ return result;
+ }
+ else
+ {
+ size_t result = 2166136261UL;
+ while (*s != 0)
+ {
+ const char* p = reinterpret_cast<const char*>(s);
+ for (size_t i = 0; i < sizeof(Stringpool_char); ++i)
+ {
+ result ^= (size_t) *p++;
+ result *= 16777619UL;
+ }
+ ++s;
+ }
+ return result;
+ }
+}
+
+// Add a string to the list of canonical strings. Return a pointer to
+// the canonical string. If PKEY is not NULL, set *PKEY to the key.
+
+template<typename Stringpool_char>
+const Stringpool_char*
+Stringpool_template<Stringpool_char>::add_string(const Stringpool_char* s,
+ Key* pkey)
+{
+ // We are in trouble if we've already computed the string offsets.
+ gold_assert(this->strtab_size_ == 0);
+
+ // The size we allocate for a new Stringdata.
+ const size_t buffer_size = 1000;
+ // The amount we multiply the Stringdata index when calculating the
+ // key.
+ const size_t key_mult = 1024;
+ gold_assert(key_mult >= buffer_size);
+
+ size_t len = (string_length(s) + 1) * sizeof(Stringpool_char);
+
+ size_t alc;
+ bool front = true;
+ if (len > buffer_size)
+ {
+ alc = sizeof(Stringdata) + len;
+ front = false;
+ }
+ else if (this->strings_.empty())
+ alc = sizeof(Stringdata) + buffer_size;
+ else
+ {
+ Stringdata *psd = this->strings_.front();
+ if (len > psd->alc - psd->len)
+ alc = sizeof(Stringdata) + buffer_size;
+ else
+ {
+ char* ret = psd->data + psd->len;
+ memcpy(ret, s, len);
+
+ if (pkey != NULL)
+ *pkey = psd->index * key_mult + psd->len;
+
+ psd->len += len;
+
+ return reinterpret_cast<const Stringpool_char*>(ret);
+ }
+ }
+
+ Stringdata *psd = reinterpret_cast<Stringdata*>(new char[alc]);
+ psd->alc = alc - sizeof(Stringdata);
+ memcpy(psd->data, s, len);
+ psd->len = len;
+ psd->index = this->next_index_;
+ ++this->next_index_;
+
+ if (pkey != NULL)
+ *pkey = psd->index * key_mult;
+
+ if (front)
+ this->strings_.push_front(psd);
+ else
+ this->strings_.push_back(psd);
+
+ return reinterpret_cast<const Stringpool_char*>(psd->data);
+}
+
+// Add a string to a string pool.
+
+template<typename Stringpool_char>
+const Stringpool_char*
+Stringpool_template<Stringpool_char>::add(const Stringpool_char* s, Key* pkey)
+{
+ // FIXME: This will look up the entry twice in the hash table. The
+ // problem is that we can't insert S before we canonicalize it. I
+ // don't think there is a way to handle this correctly with
+ // unordered_map, so this should be replaced with custom code to do
+ // what we need, which is to return the empty slot.
+
+ typename String_set_type::const_iterator p = this->string_set_.find(s);
+ if (p != this->string_set_.end())
+ {
+ if (pkey != NULL)
+ *pkey = p->second.first;
+ return p->first;
+ }
+
+ Key k;
+ const Stringpool_char* ret = this->add_string(s, &k);
+
+ const off_t ozero = 0;
+ std::pair<const Stringpool_char*, Val> element(ret,
+ std::make_pair(k, ozero));
+ std::pair<typename String_set_type::iterator, bool> ins =
+ this->string_set_.insert(element);
+ gold_assert(ins.second);
+
+ if (pkey != NULL)
+ *pkey = k;
+
+ return ret;
+}
+
+// Add a prefix of a string to a string pool.
+
+template<typename Stringpool_char>
+const Stringpool_char*
+Stringpool_template<Stringpool_char>::add(const Stringpool_char* s, size_t len,
+ Key* pkey)
+{
+ // FIXME: This implementation should be rewritten when we rewrite
+ // the hash table to avoid copying.
+ std::basic_string<Stringpool_char> st(s, len);
+ return this->add(st, pkey);
+}
+
+template<typename Stringpool_char>
+const Stringpool_char*
+Stringpool_template<Stringpool_char>::find(const Stringpool_char* s,
+ Key* pkey) const
+{
+ typename String_set_type::const_iterator p = this->string_set_.find(s);
+ if (p == this->string_set_.end())
+ return NULL;
+
+ if (pkey != NULL)
+ *pkey = p->second.first;
+
+ return p->first;
+}
+
+// Comparison routine used when sorting into an ELF strtab. We want
+// to sort this so that when one string is a suffix of another, we
+// always see the shorter string immediately after the longer string.
+// For example, we want to see these strings in this order:
+// abcd
+// cd
+// d
+// When strings are not suffixes, we don't care what order they are
+// in, but we need to ensure that suffixes wind up next to each other.
+// So we do a reversed lexicographic sort on the reversed string.
+
+template<typename Stringpool_char>
+bool
+Stringpool_template<Stringpool_char>::Stringpool_sort_comparison::operator()(
+ typename String_set_type::iterator it1,
+ typename String_set_type::iterator it2) const
+{
+ const Stringpool_char* s1 = it1->first;
+ const Stringpool_char* s2 = it2->first;
+ size_t len1 = string_length(s1);
+ size_t len2 = string_length(s2);
+ size_t minlen = len1 < len2 ? len1 : len2;
+ const Stringpool_char* p1 = s1 + len1 - 1;
+ const Stringpool_char* p2 = s2 + len2 - 1;
+ for (size_t i = minlen; i > 0; --i, --p1, --p2)
+ {
+ if (*p1 != *p2)
+ return *p1 > *p2;
+ }
+ return len1 > len2;
+}
+
+// Return whether s1 is a suffix of s2.
+
+template<typename Stringpool_char>
+bool
+Stringpool_template<Stringpool_char>::is_suffix(const Stringpool_char* s1,
+ const Stringpool_char* s2)
+{
+ size_t len1 = string_length(s1);
+ size_t len2 = string_length(s2);
+ if (len1 > len2)
+ return false;
+ return memcmp(s1, s2 + len2 - len1, len1 * sizeof(Stringpool_char)) == 0;
+}
+
+// Turn the stringpool into an ELF strtab: determine the offsets of
+// each string in the table.
+
+template<typename Stringpool_char>
+void
+Stringpool_template<Stringpool_char>::set_string_offsets()
+{
+ if (this->strtab_size_ != 0)
+ {
+ // We've already computed the offsets.
+ return;
+ }
+
+ size_t count = this->string_set_.size();
+
+ std::vector<typename String_set_type::iterator> v;
+ v.reserve(count);
+
+ for (typename String_set_type::iterator p = this->string_set_.begin();
+ p != this->string_set_.end();
+ ++p)
+ v.push_back(p);
+
+ std::sort(v.begin(), v.end(), Stringpool_sort_comparison());
+
+ const size_t charsize = sizeof(Stringpool_char);
+
+ // Offset 0 may be reserved for the empty string.
+ off_t offset = this->zero_null_ ? charsize : 0;
+ for (size_t i = 0; i < count; ++i)
+ {
+ if (this->zero_null_ && v[i]->first[0] == 0)
+ v[i]->second.second = 0;
+ else if (i > 0 && is_suffix(v[i]->first, v[i - 1]->first))
+ v[i]->second.second = (v[i - 1]->second.second
+ + ((string_length(v[i - 1]->first)
+ - string_length(v[i]->first))
+ * charsize));
+ else
+ {
+ v[i]->second.second = offset;
+ offset += (string_length(v[i]->first) + 1) * charsize;
+ }
+ }
+
+ this->strtab_size_ = offset;
+}
+
+// Get the offset of a string in the ELF strtab. The string must
+// exist.
+
+template<typename Stringpool_char>
+off_t
+Stringpool_template<Stringpool_char>::get_offset(const Stringpool_char* s)
+ const
+{
+ gold_assert(this->strtab_size_ != 0);
+ typename String_set_type::const_iterator p = this->string_set_.find(s);
+ if (p != this->string_set_.end())
+ return p->second.second;
+ gold_unreachable();
+}
+
+// Write the ELF strtab into the output file at the specified offset.
+
+template<typename Stringpool_char>
+void
+Stringpool_template<Stringpool_char>::write(Output_file* of, off_t offset)
+{
+ gold_assert(this->strtab_size_ != 0);
+ unsigned char* viewu = of->get_output_view(offset, this->strtab_size_);
+ char* view = reinterpret_cast<char*>(viewu);
+ if (this->zero_null_)
+ view[0] = '\0';
+ for (typename String_set_type::const_iterator p = this->string_set_.begin();
+ p != this->string_set_.end();
+ ++p)
+ memcpy(view + p->second.second, p->first,
+ (string_length(p->first) + 1) * sizeof(Stringpool_char));
+ of->write_output_view(offset, this->strtab_size_, viewu);
+}
+
+// Instantiate the templates we need.
+
+template
+class Stringpool_template<char>;
+
+template
+class Stringpool_template<uint16_t>;
+
+template
+class Stringpool_template<uint32_t>;
+
+} // End namespace gold.
diff --git a/gold/stringpool.h b/gold/stringpool.h
new file mode 100644
index 000000000000..b9a65f6db98d
--- /dev/null
+++ b/gold/stringpool.h
@@ -0,0 +1,167 @@
+// stringpool.h -- a string pool for gold -*- C++ -*-
+
+#include <string>
+#include <list>
+
+// Stringpool
+// Manage a pool of unique strings.
+
+#ifndef GOLD_STRINGPOOL_H
+#define GOLD_STRINGPOOL_H
+
+namespace gold
+{
+
+class Output_file;
+
+template<typename Stringpool_char>
+class Stringpool_template
+{
+ public:
+ // The type of a key into the stringpool. A key value will always
+ // be the same during any run of the linker. The string pointers
+ // may change when using address space randomization. We use key
+ // values in order to get repeatable runs when the value is inserted
+ // into an unordered hash table. Zero is never a valid key.
+ typedef size_t Key;
+
+ // Create a Stringpool. ZERO_NULL is true if we should reserve
+ // offset 0 to hold the empty string.
+ Stringpool_template(bool zero_null = true);
+
+ ~Stringpool_template();
+
+ // Add a string to the pool. This returns a canonical permanent
+ // pointer to the string. If PKEY is not NULL, this sets *PKEY to
+ // the key for the string.
+ const Stringpool_char*
+ add(const Stringpool_char*, Key* pkey);
+
+ const Stringpool_char*
+ add(const std::basic_string<Stringpool_char>& s, Key* pkey)
+ { return this->add(s.c_str(), pkey); }
+
+ // Add the prefix of a string to the pool.
+ const Stringpool_char*
+ add(const Stringpool_char*, size_t, Key* pkey);
+
+ // If a string is present, return the canonical string. Otherwise,
+ // return NULL. If PKEY is not NULL, set *PKEY to the key.
+ const Stringpool_char*
+ find(const Stringpool_char*, Key* pkey) const;
+
+ // Turn the stringpool into an ELF strtab: determine the offsets of
+ // all the strings.
+ void
+ set_string_offsets();
+
+ // Get the offset of a string in an ELF strtab. This returns the
+ // offset in bytes, not characters.
+ off_t
+ get_offset(const Stringpool_char*) const;
+
+ off_t
+ get_offset(const std::basic_string<Stringpool_char>& s) const
+ { return this->get_offset(s.c_str()); }
+
+ // Get the size of the ELF strtab. This returns the number of
+ // bytes, not characters.
+ off_t
+ get_strtab_size() const
+ {
+ gold_assert(this->strtab_size_ != 0);
+ return this->strtab_size_;
+ }
+
+ // Write the strtab into the output file at the specified offset.
+ void
+ write(Output_file*, off_t offset);
+
+ private:
+ Stringpool_template(const Stringpool_template&);
+ Stringpool_template& operator=(const Stringpool_template&);
+
+ // Return the length of a string.
+ static size_t
+ string_length(const Stringpool_char*);
+
+ // We store the actual data in a list of these buffers.
+ struct Stringdata
+ {
+ // Length of data in buffer.
+ size_t len;
+ // Allocated size of buffer.
+ size_t alc;
+ // Buffer index.
+ unsigned int index;
+ // Buffer.
+ char data[1];
+ };
+
+ // Copy a string into the buffers, returning a canonical string.
+ const Stringpool_char*
+ add_string(const Stringpool_char*, Key*);
+
+ struct Stringpool_hash
+ {
+ size_t
+ operator()(const Stringpool_char*) const;
+ };
+
+ struct Stringpool_eq
+ {
+ bool
+ operator()(const Stringpool_char* p1, const Stringpool_char* p2) const;
+ };
+
+ // Return whether s1 is a suffix of s2.
+ static bool
+ is_suffix(const Stringpool_char* s1, const Stringpool_char* s2);
+
+ // The hash table is a map from string names to a pair of Key and
+ // ELF strtab offsets. We only use the offsets if we turn this into
+ // an ELF strtab section.
+
+ typedef std::pair<Key, off_t> Val;
+
+#ifdef HAVE_TR1_UNORDERED_SET
+ typedef Unordered_map<const Stringpool_char*, Val, Stringpool_hash,
+ Stringpool_eq,
+ std::allocator<std::pair<const Stringpool_char* const,
+ Val> >,
+ true> String_set_type;
+#else
+ typedef Unordered_map<const Stringpool_char*, Val, Stringpool_hash,
+ Stringpool_eq> String_set_type;
+#endif
+
+ // Comparison routine used when sorting into an ELF strtab.
+
+ struct Stringpool_sort_comparison
+ {
+ bool
+ operator()(typename String_set_type::iterator,
+ typename String_set_type::iterator) const;
+ };
+
+ // List of Stringdata structures.
+ typedef std::list<Stringdata*> Stringdata_list;
+
+ // Mapping from const char* to namepool entry.
+ String_set_type string_set_;
+ // List of buffers.
+ Stringdata_list strings_;
+ // Size of ELF strtab.
+ off_t strtab_size_;
+ // Next Stringdata index.
+ unsigned int next_index_;
+ // Whether to reserve offset 0 to hold the null string.
+ bool zero_null_;
+};
+
+// The most common type of Stringpool.
+typedef Stringpool_template<char> Stringpool;
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_STRINGPOOL_H)
diff --git a/gold/strtab.h b/gold/strtab.h
new file mode 100644
index 000000000000..ab22b8fc286f
--- /dev/null
+++ b/gold/strtab.h
@@ -0,0 +1,73 @@
+// strtab.h -- manage an ELF string table for gold -*- C++ -*-
+
+#ifndef GOLD_STRTAB_H
+#define GOLD_STRTAB_H
+
+#include <cstring>
+#include <string>
+
+namespace gold
+{
+
+// This class holds an ELF string table. We keep a reference count
+// for each string, which we use to determine which strings are
+// actually required at the end. When all operations are done, the
+// string table is finalized, which sets the offsets to use for each
+// string.
+
+class Strtab
+{
+ public:
+ Strtab();
+
+ ~Strtab();
+
+ Strtab_ref* add(const char*);
+
+ Strtab_ref* add(const std::string& s)
+ { return this->add(s.c_str()); }
+
+ private:
+ Strtab(const Strtab&);
+ Strtab& operator=(const Strtab&);
+
+ struct strtab_hash
+ {
+ std::size_t
+ operator()(const char*p);
+ };
+
+ struct strtab_eq
+ {
+ bool
+ operator()(const char* p1, const char* p2)
+ { return strcmp(p1, p2) == 0; }
+ };
+
+ Unordered_map<const char*, Strtab_ref*, strtab_hash, strtab_eq,
+ std::allocator<std::pair<const char* const, Strtab_ref*> >,
+ true> strings_;
+};
+
+// Users of Strtab work with pointers to Strtab_ref structures. These
+// are allocated via new and should be deleted if the string is no
+// longer needed.
+
+class Strtab_ref
+{
+ public:
+ ~Strtab_ref();
+
+ const char*
+ str() const;
+
+ private:
+ Strtab_ref(const Strtab_ref&);
+ Strtab_ref& operator=(const Strtab_ref&);
+
+ int refs_;
+};
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_STRTAB_H)
diff --git a/gold/symtab.cc b/gold/symtab.cc
new file mode 100644
index 000000000000..01e000d874e7
--- /dev/null
+++ b/gold/symtab.cc
@@ -0,0 +1,1567 @@
+// symtab.cc -- the gold symbol table
+
+#include "gold.h"
+
+#include <stdint.h>
+#include <string>
+#include <utility>
+
+#include "object.h"
+#include "dynobj.h"
+#include "output.h"
+#include "target.h"
+#include "workqueue.h"
+#include "symtab.h"
+
+namespace gold
+{
+
+// Class Symbol.
+
+// Initialize fields in Symbol. This initializes everything except u_
+// and source_.
+
+void
+Symbol::init_fields(const char* name, const char* version,
+ elfcpp::STT type, elfcpp::STB binding,
+ elfcpp::STV visibility, unsigned char nonvis)
+{
+ this->name_ = name;
+ this->version_ = version;
+ this->symtab_index_ = 0;
+ this->dynsym_index_ = 0;
+ this->got_offset_ = 0;
+ this->type_ = type;
+ this->binding_ = binding;
+ this->visibility_ = visibility;
+ this->nonvis_ = nonvis;
+ this->is_target_special_ = false;
+ this->is_def_ = false;
+ this->is_forwarder_ = false;
+ this->needs_dynsym_entry_ = false;
+ this->in_reg_ = false;
+ this->in_dyn_ = false;
+ this->has_got_offset_ = false;
+ this->has_warning_ = false;
+}
+
+// Initialize the fields in the base class Symbol for SYM in OBJECT.
+
+template<int size, bool big_endian>
+void
+Symbol::init_base(const char* name, const char* version, Object* object,
+ const elfcpp::Sym<size, big_endian>& sym)
+{
+ this->init_fields(name, version, sym.get_st_type(), sym.get_st_bind(),
+ sym.get_st_visibility(), sym.get_st_nonvis());
+ this->u_.from_object.object = object;
+ // FIXME: Handle SHN_XINDEX.
+ this->u_.from_object.shndx = sym.get_st_shndx();
+ this->source_ = FROM_OBJECT;
+ this->in_reg_ = !object->is_dynamic();
+ this->in_dyn_ = object->is_dynamic();
+}
+
+// Initialize the fields in the base class Symbol for a symbol defined
+// in an Output_data.
+
+void
+Symbol::init_base(const char* name, Output_data* od, elfcpp::STT type,
+ elfcpp::STB binding, elfcpp::STV visibility,
+ unsigned char nonvis, bool offset_is_from_end)
+{
+ this->init_fields(name, NULL, type, binding, visibility, nonvis);
+ this->u_.in_output_data.output_data = od;
+ this->u_.in_output_data.offset_is_from_end = offset_is_from_end;
+ this->source_ = IN_OUTPUT_DATA;
+ this->in_reg_ = true;
+}
+
+// Initialize the fields in the base class Symbol for a symbol defined
+// in an Output_segment.
+
+void
+Symbol::init_base(const char* name, Output_segment* os, elfcpp::STT type,
+ elfcpp::STB binding, elfcpp::STV visibility,
+ unsigned char nonvis, Segment_offset_base offset_base)
+{
+ this->init_fields(name, NULL, type, binding, visibility, nonvis);
+ this->u_.in_output_segment.output_segment = os;
+ this->u_.in_output_segment.offset_base = offset_base;
+ this->source_ = IN_OUTPUT_SEGMENT;
+ this->in_reg_ = true;
+}
+
+// Initialize the fields in the base class Symbol for a symbol defined
+// as a constant.
+
+void
+Symbol::init_base(const char* name, elfcpp::STT type,
+ elfcpp::STB binding, elfcpp::STV visibility,
+ unsigned char nonvis)
+{
+ this->init_fields(name, NULL, type, binding, visibility, nonvis);
+ this->source_ = CONSTANT;
+ this->in_reg_ = true;
+}
+
+// Initialize the fields in Sized_symbol for SYM in OBJECT.
+
+template<int size>
+template<bool big_endian>
+void
+Sized_symbol<size>::init(const char* name, const char* version, Object* object,
+ const elfcpp::Sym<size, big_endian>& sym)
+{
+ this->init_base(name, version, object, sym);
+ this->value_ = sym.get_st_value();
+ this->symsize_ = sym.get_st_size();
+}
+
+// Initialize the fields in Sized_symbol for a symbol defined in an
+// Output_data.
+
+template<int size>
+void
+Sized_symbol<size>::init(const char* name, Output_data* od,
+ Value_type value, Size_type symsize,
+ elfcpp::STT type, elfcpp::STB binding,
+ elfcpp::STV visibility, unsigned char nonvis,
+ bool offset_is_from_end)
+{
+ this->init_base(name, od, type, binding, visibility, nonvis,
+ offset_is_from_end);
+ this->value_ = value;
+ this->symsize_ = symsize;
+}
+
+// Initialize the fields in Sized_symbol for a symbol defined in an
+// Output_segment.
+
+template<int size>
+void
+Sized_symbol<size>::init(const char* name, Output_segment* os,
+ Value_type value, Size_type symsize,
+ elfcpp::STT type, elfcpp::STB binding,
+ elfcpp::STV visibility, unsigned char nonvis,
+ Segment_offset_base offset_base)
+{
+ this->init_base(name, os, type, binding, visibility, nonvis, offset_base);
+ this->value_ = value;
+ this->symsize_ = symsize;
+}
+
+// Initialize the fields in Sized_symbol for a symbol defined as a
+// constant.
+
+template<int size>
+void
+Sized_symbol<size>::init(const char* name, Value_type value, Size_type symsize,
+ elfcpp::STT type, elfcpp::STB binding,
+ elfcpp::STV visibility, unsigned char nonvis)
+{
+ this->init_base(name, type, binding, visibility, nonvis);
+ this->value_ = value;
+ this->symsize_ = symsize;
+}
+
+// Class Symbol_table.
+
+Symbol_table::Symbol_table()
+ : size_(0), saw_undefined_(0), offset_(0), table_(), namepool_(),
+ forwarders_(), commons_(), warnings_()
+{
+}
+
+Symbol_table::~Symbol_table()
+{
+}
+
+// The hash function. The key is always canonicalized, so we use a
+// simple combination of the pointers.
+
+size_t
+Symbol_table::Symbol_table_hash::operator()(const Symbol_table_key& key) const
+{
+ return key.first ^ key.second;
+}
+
+// The symbol table key equality function. This is only called with
+// canonicalized name and version strings, so we can use pointer
+// comparison.
+
+bool
+Symbol_table::Symbol_table_eq::operator()(const Symbol_table_key& k1,
+ const Symbol_table_key& k2) const
+{
+ return k1.first == k2.first && k1.second == k2.second;
+}
+
+// Make TO a symbol which forwards to FROM.
+
+void
+Symbol_table::make_forwarder(Symbol* from, Symbol* to)
+{
+ gold_assert(from != to);
+ gold_assert(!from->is_forwarder() && !to->is_forwarder());
+ this->forwarders_[from] = to;
+ from->set_forwarder();
+}
+
+// Resolve the forwards from FROM, returning the real symbol.
+
+Symbol*
+Symbol_table::resolve_forwards(const Symbol* from) const
+{
+ gold_assert(from->is_forwarder());
+ Unordered_map<const Symbol*, Symbol*>::const_iterator p =
+ this->forwarders_.find(from);
+ gold_assert(p != this->forwarders_.end());
+ return p->second;
+}
+
+// Look up a symbol by name.
+
+Symbol*
+Symbol_table::lookup(const char* name, const char* version) const
+{
+ Stringpool::Key name_key;
+ name = this->namepool_.find(name, &name_key);
+ if (name == NULL)
+ return NULL;
+
+ Stringpool::Key version_key = 0;
+ if (version != NULL)
+ {
+ version = this->namepool_.find(version, &version_key);
+ if (version == NULL)
+ return NULL;
+ }
+
+ Symbol_table_key key(name_key, version_key);
+ Symbol_table::Symbol_table_type::const_iterator p = this->table_.find(key);
+ if (p == this->table_.end())
+ return NULL;
+ return p->second;
+}
+
+// Resolve a Symbol with another Symbol. This is only used in the
+// unusual case where there are references to both an unversioned
+// symbol and a symbol with a version, and we then discover that that
+// version is the default version. Because this is unusual, we do
+// this the slow way, by converting back to an ELF symbol.
+
+template<int size, bool big_endian>
+void
+Symbol_table::resolve(Sized_symbol<size>* to, const Sized_symbol<size>* from,
+ const char* version ACCEPT_SIZE_ENDIAN)
+{
+ unsigned char buf[elfcpp::Elf_sizes<size>::sym_size];
+ elfcpp::Sym_write<size, big_endian> esym(buf);
+ // We don't bother to set the st_name field.
+ esym.put_st_value(from->value());
+ esym.put_st_size(from->symsize());
+ esym.put_st_info(from->binding(), from->type());
+ esym.put_st_other(from->visibility(), from->nonvis());
+ esym.put_st_shndx(from->shndx());
+ Symbol_table::resolve(to, esym.sym(), from->object(), version);
+}
+
+// Add one symbol from OBJECT to the symbol table. NAME is symbol
+// name and VERSION is the version; both are canonicalized. DEF is
+// whether this is the default version.
+
+// If DEF is true, then this is the definition of a default version of
+// a symbol. That means that any lookup of NAME/NULL and any lookup
+// of NAME/VERSION should always return the same symbol. This is
+// obvious for references, but in particular we want to do this for
+// definitions: overriding NAME/NULL should also override
+// NAME/VERSION. If we don't do that, it would be very hard to
+// override functions in a shared library which uses versioning.
+
+// We implement this by simply making both entries in the hash table
+// point to the same Symbol structure. That is easy enough if this is
+// the first time we see NAME/NULL or NAME/VERSION, but it is possible
+// that we have seen both already, in which case they will both have
+// independent entries in the symbol table. We can't simply change
+// the symbol table entry, because we have pointers to the entries
+// attached to the object files. So we mark the entry attached to the
+// object file as a forwarder, and record it in the forwarders_ map.
+// Note that entries in the hash table will never be marked as
+// forwarders.
+
+template<int size, bool big_endian>
+Symbol*
+Symbol_table::add_from_object(Object* object,
+ const char *name,
+ Stringpool::Key name_key,
+ const char *version,
+ Stringpool::Key version_key,
+ bool def,
+ const elfcpp::Sym<size, big_endian>& sym)
+{
+ Symbol* const snull = NULL;
+ std::pair<typename Symbol_table_type::iterator, bool> ins =
+ this->table_.insert(std::make_pair(std::make_pair(name_key, version_key),
+ snull));
+
+ std::pair<typename Symbol_table_type::iterator, bool> insdef =
+ std::make_pair(this->table_.end(), false);
+ if (def)
+ {
+ const Stringpool::Key vnull_key = 0;
+ insdef = this->table_.insert(std::make_pair(std::make_pair(name_key,
+ vnull_key),
+ snull));
+ }
+
+ // ins.first: an iterator, which is a pointer to a pair.
+ // ins.first->first: the key (a pair of name and version).
+ // ins.first->second: the value (Symbol*).
+ // ins.second: true if new entry was inserted, false if not.
+
+ Sized_symbol<size>* ret;
+ bool was_undefined;
+ bool was_common;
+ if (!ins.second)
+ {
+ // We already have an entry for NAME/VERSION.
+ ret = this->get_sized_symbol SELECT_SIZE_NAME(size) (ins.first->second
+ SELECT_SIZE(size));
+ gold_assert(ret != NULL);
+
+ was_undefined = ret->is_undefined();
+ was_common = ret->is_common();
+
+ Symbol_table::resolve(ret, sym, object, version);
+
+ if (def)
+ {
+ if (insdef.second)
+ {
+ // This is the first time we have seen NAME/NULL. Make
+ // NAME/NULL point to NAME/VERSION.
+ insdef.first->second = ret;
+ }
+ else if (insdef.first->second != ret)
+ {
+ // This is the unfortunate case where we already have
+ // entries for both NAME/VERSION and NAME/NULL.
+ const Sized_symbol<size>* sym2;
+ sym2 = this->get_sized_symbol SELECT_SIZE_NAME(size) (
+ insdef.first->second
+ SELECT_SIZE(size));
+ Symbol_table::resolve SELECT_SIZE_ENDIAN_NAME(size, big_endian) (
+ ret, sym2, version SELECT_SIZE_ENDIAN(size, big_endian));
+ this->make_forwarder(insdef.first->second, ret);
+ insdef.first->second = ret;
+ }
+ }
+ }
+ else
+ {
+ // This is the first time we have seen NAME/VERSION.
+ gold_assert(ins.first->second == NULL);
+
+ was_undefined = false;
+ was_common = false;
+
+ if (def && !insdef.second)
+ {
+ // We already have an entry for NAME/NULL. If we override
+ // it, then change it to NAME/VERSION.
+ ret = this->get_sized_symbol SELECT_SIZE_NAME(size) (
+ insdef.first->second
+ SELECT_SIZE(size));
+ Symbol_table::resolve(ret, sym, object, version);
+ ins.first->second = ret;
+ }
+ else
+ {
+ Sized_target<size, big_endian>* target =
+ object->sized_target SELECT_SIZE_ENDIAN_NAME(size, big_endian) (
+ SELECT_SIZE_ENDIAN_ONLY(size, big_endian));
+ if (!target->has_make_symbol())
+ ret = new Sized_symbol<size>();
+ else
+ {
+ ret = target->make_symbol();
+ if (ret == NULL)
+ {
+ // This means that we don't want a symbol table
+ // entry after all.
+ if (!def)
+ this->table_.erase(ins.first);
+ else
+ {
+ this->table_.erase(insdef.first);
+ // Inserting insdef invalidated ins.
+ this->table_.erase(std::make_pair(name_key,
+ version_key));
+ }
+ return NULL;
+ }
+ }
+
+ ret->init(name, version, object, sym);
+
+ ins.first->second = ret;
+ if (def)
+ {
+ // This is the first time we have seen NAME/NULL. Point
+ // it at the new entry for NAME/VERSION.
+ gold_assert(insdef.second);
+ insdef.first->second = ret;
+ }
+ }
+ }
+
+ // Record every time we see a new undefined symbol, to speed up
+ // archive groups.
+ if (!was_undefined && ret->is_undefined())
+ ++this->saw_undefined_;
+
+ // Keep track of common symbols, to speed up common symbol
+ // allocation.
+ if (!was_common && ret->is_common())
+ this->commons_.push_back(ret);
+
+ return ret;
+}
+
+// Add all the symbols in a relocatable object to the hash table.
+
+template<int size, bool big_endian>
+void
+Symbol_table::add_from_relobj(
+ Sized_relobj<size, big_endian>* relobj,
+ const unsigned char* syms,
+ size_t count,
+ const char* sym_names,
+ size_t sym_name_size,
+ Symbol** sympointers)
+{
+ // We take the size from the first object we see.
+ if (this->get_size() == 0)
+ this->set_size(size);
+
+ if (size != this->get_size() || size != relobj->target()->get_size())
+ {
+ fprintf(stderr, _("%s: %s: mixing 32-bit and 64-bit ELF objects\n"),
+ program_name, relobj->name().c_str());
+ gold_exit(false);
+ }
+
+ const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+
+ const unsigned char* p = syms;
+ for (size_t i = 0; i < count; ++i, p += sym_size)
+ {
+ elfcpp::Sym<size, big_endian> sym(p);
+ elfcpp::Sym<size, big_endian>* psym = &sym;
+
+ unsigned int st_name = psym->get_st_name();
+ if (st_name >= sym_name_size)
+ {
+ fprintf(stderr,
+ _("%s: %s: bad global symbol name offset %u at %lu\n"),
+ program_name, relobj->name().c_str(), st_name,
+ static_cast<unsigned long>(i));
+ gold_exit(false);
+ }
+
+ const char* name = sym_names + st_name;
+
+ // A symbol defined in a section which we are not including must
+ // be treated as an undefined symbol.
+ unsigned char symbuf[sym_size];
+ elfcpp::Sym<size, big_endian> sym2(symbuf);
+ unsigned int st_shndx = psym->get_st_shndx();
+ if (st_shndx != elfcpp::SHN_UNDEF
+ && st_shndx < elfcpp::SHN_LORESERVE
+ && !relobj->is_section_included(st_shndx))
+ {
+ memcpy(symbuf, p, sym_size);
+ elfcpp::Sym_write<size, big_endian> sw(symbuf);
+ sw.put_st_shndx(elfcpp::SHN_UNDEF);
+ psym = &sym2;
+ }
+
+ // In an object file, an '@' in the name separates the symbol
+ // name from the version name. If there are two '@' characters,
+ // this is the default version.
+ const char* ver = strchr(name, '@');
+
+ Symbol* res;
+ if (ver == NULL)
+ {
+ Stringpool::Key name_key;
+ name = this->namepool_.add(name, &name_key);
+ res = this->add_from_object(relobj, name, name_key, NULL, 0,
+ false, *psym);
+ }
+ else
+ {
+ Stringpool::Key name_key;
+ name = this->namepool_.add(name, ver - name, &name_key);
+
+ bool def = false;
+ ++ver;
+ if (*ver == '@')
+ {
+ def = true;
+ ++ver;
+ }
+
+ Stringpool::Key ver_key;
+ ver = this->namepool_.add(ver, &ver_key);
+
+ res = this->add_from_object(relobj, name, name_key, ver, ver_key,
+ def, *psym);
+ }
+
+ *sympointers++ = res;
+ }
+}
+
+// Add all the symbols in a dynamic object to the hash table.
+
+template<int size, bool big_endian>
+void
+Symbol_table::add_from_dynobj(
+ Sized_dynobj<size, big_endian>* dynobj,
+ const unsigned char* syms,
+ size_t count,
+ const char* sym_names,
+ size_t sym_name_size,
+ const unsigned char* versym,
+ size_t versym_size,
+ const std::vector<const char*>* version_map)
+{
+ // We take the size from the first object we see.
+ if (this->get_size() == 0)
+ this->set_size(size);
+
+ if (size != this->get_size() || size != dynobj->target()->get_size())
+ {
+ fprintf(stderr, _("%s: %s: mixing 32-bit and 64-bit ELF objects\n"),
+ program_name, dynobj->name().c_str());
+ gold_exit(false);
+ }
+
+ if (versym != NULL && versym_size / 2 < count)
+ {
+ fprintf(stderr, _("%s: %s: too few symbol versions\n"),
+ program_name, dynobj->name().c_str());
+ gold_exit(false);
+ }
+
+ const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+
+ const unsigned char* p = syms;
+ const unsigned char* vs = versym;
+ for (size_t i = 0; i < count; ++i, p += sym_size, vs += 2)
+ {
+ elfcpp::Sym<size, big_endian> sym(p);
+
+ // Ignore symbols with local binding.
+ if (sym.get_st_bind() == elfcpp::STB_LOCAL)
+ continue;
+
+ unsigned int st_name = sym.get_st_name();
+ if (st_name >= sym_name_size)
+ {
+ fprintf(stderr, _("%s: %s: bad symbol name offset %u at %lu\n"),
+ program_name, dynobj->name().c_str(), st_name,
+ static_cast<unsigned long>(i));
+ gold_exit(false);
+ }
+
+ const char* name = sym_names + st_name;
+
+ if (versym == NULL)
+ {
+ Stringpool::Key name_key;
+ name = this->namepool_.add(name, &name_key);
+ this->add_from_object(dynobj, name, name_key, NULL, 0,
+ false, sym);
+ continue;
+ }
+
+ // Read the version information.
+
+ unsigned int v = elfcpp::Swap<16, big_endian>::readval(vs);
+
+ bool hidden = (v & elfcpp::VERSYM_HIDDEN) != 0;
+ v &= elfcpp::VERSYM_VERSION;
+
+ if (v == static_cast<unsigned int>(elfcpp::VER_NDX_LOCAL))
+ {
+ // This symbol should not be visible outside the object.
+ continue;
+ }
+
+ // At this point we are definitely going to add this symbol.
+ Stringpool::Key name_key;
+ name = this->namepool_.add(name, &name_key);
+
+ if (v == static_cast<unsigned int>(elfcpp::VER_NDX_GLOBAL))
+ {
+ // This symbol does not have a version.
+ this->add_from_object(dynobj, name, name_key, NULL, 0, false, sym);
+ continue;
+ }
+
+ if (v >= version_map->size())
+ {
+ fprintf(stderr,
+ _("%s: %s: versym for symbol %zu out of range: %u\n"),
+ program_name, dynobj->name().c_str(), i, v);
+ gold_exit(false);
+ }
+
+ const char* version = (*version_map)[v];
+ if (version == NULL)
+ {
+ fprintf(stderr, _("%s: %s: versym for symbol %zu has no name: %u\n"),
+ program_name, dynobj->name().c_str(), i, v);
+ gold_exit(false);
+ }
+
+ Stringpool::Key version_key;
+ version = this->namepool_.add(version, &version_key);
+
+ // If this is an absolute symbol, and the version name and
+ // symbol name are the same, then this is the version definition
+ // symbol. These symbols exist to support using -u to pull in
+ // particular versions. We do not want to record a version for
+ // them.
+ if (sym.get_st_shndx() == elfcpp::SHN_ABS && name_key == version_key)
+ {
+ this->add_from_object(dynobj, name, name_key, NULL, 0, false, sym);
+ continue;
+ }
+
+ const bool def = !hidden && sym.get_st_shndx() != elfcpp::SHN_UNDEF;
+
+ this->add_from_object(dynobj, name, name_key, version, version_key,
+ def, sym);
+ }
+}
+
+// Create and return a specially defined symbol. If ONLY_IF_REF is
+// true, then only create the symbol if there is a reference to it.
+
+template<int size, bool big_endian>
+Sized_symbol<size>*
+Symbol_table::define_special_symbol(const Target* target, const char* name,
+ const char* version, bool only_if_ref
+ ACCEPT_SIZE_ENDIAN)
+{
+ gold_assert(this->size_ == size);
+
+ Symbol* oldsym;
+ Sized_symbol<size>* sym;
+
+ if (only_if_ref)
+ {
+ oldsym = this->lookup(name, version);
+ if (oldsym == NULL || !oldsym->is_undefined())
+ return NULL;
+ sym = NULL;
+
+ // Canonicalize NAME and VERSION.
+ name = oldsym->name();
+ version = oldsym->version();
+ }
+ else
+ {
+ // Canonicalize NAME and VERSION.
+ Stringpool::Key name_key;
+ name = this->namepool_.add(name, &name_key);
+
+ Stringpool::Key version_key = 0;
+ if (version != NULL)
+ version = this->namepool_.add(version, &version_key);
+
+ Symbol* const snull = NULL;
+ std::pair<typename Symbol_table_type::iterator, bool> ins =
+ this->table_.insert(std::make_pair(std::make_pair(name_key,
+ version_key),
+ snull));
+
+ if (!ins.second)
+ {
+ // We already have a symbol table entry for NAME/VERSION.
+ oldsym = ins.first->second;
+ gold_assert(oldsym != NULL);
+ sym = NULL;
+ }
+ else
+ {
+ // We haven't seen this symbol before.
+ gold_assert(ins.first->second == NULL);
+
+ if (!target->has_make_symbol())
+ sym = new Sized_symbol<size>();
+ else
+ {
+ gold_assert(target->get_size() == size);
+ gold_assert(target->is_big_endian() ? big_endian : !big_endian);
+ typedef Sized_target<size, big_endian> My_target;
+ const My_target* sized_target =
+ static_cast<const My_target*>(target);
+ sym = sized_target->make_symbol();
+ if (sym == NULL)
+ return NULL;
+ }
+
+ ins.first->second = sym;
+ oldsym = NULL;
+ }
+ }
+
+ if (oldsym != NULL)
+ {
+ gold_assert(sym == NULL);
+
+ sym = this->get_sized_symbol SELECT_SIZE_NAME(size) (oldsym
+ SELECT_SIZE(size));
+ gold_assert(sym->source() == Symbol::FROM_OBJECT);
+ const int old_shndx = sym->shndx();
+ if (old_shndx != elfcpp::SHN_UNDEF
+ && old_shndx != elfcpp::SHN_COMMON
+ && !sym->object()->is_dynamic())
+ {
+ fprintf(stderr, "%s: linker defined: multiple definition of %s\n",
+ program_name, name);
+ // FIXME: Report old location. Record that we have seen an
+ // error.
+ return NULL;
+ }
+
+ // Our new definition is going to override the old reference.
+ }
+
+ return sym;
+}
+
+// Define a symbol based on an Output_data.
+
+Symbol*
+Symbol_table::define_in_output_data(const Target* target, const char* name,
+ const char* version, Output_data* od,
+ uint64_t value, uint64_t symsize,
+ elfcpp::STT type, elfcpp::STB binding,
+ elfcpp::STV visibility,
+ unsigned char nonvis,
+ bool offset_is_from_end,
+ bool only_if_ref)
+{
+ gold_assert(target->get_size() == this->size_);
+ if (this->size_ == 32)
+ return this->do_define_in_output_data<32>(target, name, version, od, value,
+ symsize, type, binding,
+ visibility, nonvis,
+ offset_is_from_end, only_if_ref);
+ else if (this->size_ == 64)
+ return this->do_define_in_output_data<64>(target, name, version, od, value,
+ symsize, type, binding,
+ visibility, nonvis,
+ offset_is_from_end, only_if_ref);
+ else
+ gold_unreachable();
+}
+
+// Define a symbol in an Output_data, sized version.
+
+template<int size>
+Sized_symbol<size>*
+Symbol_table::do_define_in_output_data(
+ const Target* target,
+ const char* name,
+ const char* version,
+ Output_data* od,
+ typename elfcpp::Elf_types<size>::Elf_Addr value,
+ typename elfcpp::Elf_types<size>::Elf_WXword symsize,
+ elfcpp::STT type,
+ elfcpp::STB binding,
+ elfcpp::STV visibility,
+ unsigned char nonvis,
+ bool offset_is_from_end,
+ bool only_if_ref)
+{
+ Sized_symbol<size>* sym;
+
+ if (target->is_big_endian())
+ sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, true) (
+ target, name, version, only_if_ref
+ SELECT_SIZE_ENDIAN(size, true));
+ else
+ sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, false) (
+ target, name, version, only_if_ref
+ SELECT_SIZE_ENDIAN(size, false));
+
+ if (sym == NULL)
+ return NULL;
+
+ sym->init(name, od, value, symsize, type, binding, visibility, nonvis,
+ offset_is_from_end);
+
+ return sym;
+}
+
+// Define a symbol based on an Output_segment.
+
+Symbol*
+Symbol_table::define_in_output_segment(const Target* target, const char* name,
+ const char* version, Output_segment* os,
+ uint64_t value, uint64_t symsize,
+ elfcpp::STT type, elfcpp::STB binding,
+ elfcpp::STV visibility,
+ unsigned char nonvis,
+ Symbol::Segment_offset_base offset_base,
+ bool only_if_ref)
+{
+ gold_assert(target->get_size() == this->size_);
+ if (this->size_ == 32)
+ return this->do_define_in_output_segment<32>(target, name, version, os,
+ value, symsize, type, binding,
+ visibility, nonvis,
+ offset_base, only_if_ref);
+ else if (this->size_ == 64)
+ return this->do_define_in_output_segment<64>(target, name, version, os,
+ value, symsize, type, binding,
+ visibility, nonvis,
+ offset_base, only_if_ref);
+ else
+ gold_unreachable();
+}
+
+// Define a symbol in an Output_segment, sized version.
+
+template<int size>
+Sized_symbol<size>*
+Symbol_table::do_define_in_output_segment(
+ const Target* target,
+ const char* name,
+ const char* version,
+ Output_segment* os,
+ typename elfcpp::Elf_types<size>::Elf_Addr value,
+ typename elfcpp::Elf_types<size>::Elf_WXword symsize,
+ elfcpp::STT type,
+ elfcpp::STB binding,
+ elfcpp::STV visibility,
+ unsigned char nonvis,
+ Symbol::Segment_offset_base offset_base,
+ bool only_if_ref)
+{
+ Sized_symbol<size>* sym;
+
+ if (target->is_big_endian())
+ sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, true) (
+ target, name, version, only_if_ref
+ SELECT_SIZE_ENDIAN(size, true));
+ else
+ sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, false) (
+ target, name, version, only_if_ref
+ SELECT_SIZE_ENDIAN(size, false));
+
+ if (sym == NULL)
+ return NULL;
+
+ sym->init(name, os, value, symsize, type, binding, visibility, nonvis,
+ offset_base);
+
+ return sym;
+}
+
+// Define a special symbol with a constant value. It is a multiple
+// definition error if this symbol is already defined.
+
+Symbol*
+Symbol_table::define_as_constant(const Target* target, const char* name,
+ const char* version, uint64_t value,
+ uint64_t symsize, elfcpp::STT type,
+ elfcpp::STB binding, elfcpp::STV visibility,
+ unsigned char nonvis, bool only_if_ref)
+{
+ gold_assert(target->get_size() == this->size_);
+ if (this->size_ == 32)
+ return this->do_define_as_constant<32>(target, name, version, value,
+ symsize, type, binding, visibility,
+ nonvis, only_if_ref);
+ else if (this->size_ == 64)
+ return this->do_define_as_constant<64>(target, name, version, value,
+ symsize, type, binding, visibility,
+ nonvis, only_if_ref);
+ else
+ gold_unreachable();
+}
+
+// Define a symbol as a constant, sized version.
+
+template<int size>
+Sized_symbol<size>*
+Symbol_table::do_define_as_constant(
+ const Target* target,
+ const char* name,
+ const char* version,
+ typename elfcpp::Elf_types<size>::Elf_Addr value,
+ typename elfcpp::Elf_types<size>::Elf_WXword symsize,
+ elfcpp::STT type,
+ elfcpp::STB binding,
+ elfcpp::STV visibility,
+ unsigned char nonvis,
+ bool only_if_ref)
+{
+ Sized_symbol<size>* sym;
+
+ if (target->is_big_endian())
+ sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, true) (
+ target, name, version, only_if_ref
+ SELECT_SIZE_ENDIAN(size, true));
+ else
+ sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, false) (
+ target, name, version, only_if_ref
+ SELECT_SIZE_ENDIAN(size, false));
+
+ if (sym == NULL)
+ return NULL;
+
+ sym->init(name, value, symsize, type, binding, visibility, nonvis);
+
+ return sym;
+}
+
+// Define a set of symbols in output sections.
+
+void
+Symbol_table::define_symbols(const Layout* layout, const Target* target,
+ int count, const Define_symbol_in_section* p)
+{
+ for (int i = 0; i < count; ++i, ++p)
+ {
+ Output_section* os = layout->find_output_section(p->output_section);
+ if (os != NULL)
+ this->define_in_output_data(target, p->name, NULL, os, p->value,
+ p->size, p->type, p->binding,
+ p->visibility, p->nonvis,
+ p->offset_is_from_end, p->only_if_ref);
+ else
+ this->define_as_constant(target, p->name, NULL, 0, p->size, p->type,
+ p->binding, p->visibility, p->nonvis,
+ p->only_if_ref);
+ }
+}
+
+// Define a set of symbols in output segments.
+
+void
+Symbol_table::define_symbols(const Layout* layout, const Target* target,
+ int count, const Define_symbol_in_segment* p)
+{
+ for (int i = 0; i < count; ++i, ++p)
+ {
+ Output_segment* os = layout->find_output_segment(p->segment_type,
+ p->segment_flags_set,
+ p->segment_flags_clear);
+ if (os != NULL)
+ this->define_in_output_segment(target, p->name, NULL, os, p->value,
+ p->size, p->type, p->binding,
+ p->visibility, p->nonvis,
+ p->offset_base, p->only_if_ref);
+ else
+ this->define_as_constant(target, p->name, NULL, 0, p->size, p->type,
+ p->binding, p->visibility, p->nonvis,
+ p->only_if_ref);
+ }
+}
+
+// Set the dynamic symbol indexes. INDEX is the index of the first
+// global dynamic symbol. Pointers to the symbols are stored into the
+// vector SYMS. The names are added to DYNPOOL. This returns an
+// updated dynamic symbol index.
+
+unsigned int
+Symbol_table::set_dynsym_indexes(const General_options* options,
+ const Target* target,
+ unsigned int index,
+ std::vector<Symbol*>* syms,
+ Stringpool* dynpool,
+ Versions* versions)
+{
+ for (Symbol_table_type::iterator p = this->table_.begin();
+ p != this->table_.end();
+ ++p)
+ {
+ Symbol* sym = p->second;
+
+ // Note that SYM may already have a dynamic symbol index, since
+ // some symbols appear more than once in the symbol table, with
+ // and without a version.
+
+ if (!sym->needs_dynsym_entry())
+ sym->set_dynsym_index(-1U);
+ else if (!sym->has_dynsym_index())
+ {
+ sym->set_dynsym_index(index);
+ ++index;
+ syms->push_back(sym);
+ dynpool->add(sym->name(), NULL);
+
+ // Record any version information.
+ if (sym->version() != NULL)
+ versions->record_version(options, dynpool, sym);
+ }
+ }
+
+ // Finish up the versions. In some cases this may add new dynamic
+ // symbols.
+ index = versions->finalize(target, this, index, syms);
+
+ return index;
+}
+
+// Set the final values for all the symbols. The index of the first
+// global symbol in the output file is INDEX. Record the file offset
+// OFF. Add their names to POOL. Return the new file offset.
+
+off_t
+Symbol_table::finalize(unsigned int index, off_t off, off_t dynoff,
+ size_t dyn_global_index, size_t dyncount,
+ Stringpool* pool)
+{
+ off_t ret;
+
+ gold_assert(index != 0);
+ this->first_global_index_ = index;
+
+ this->dynamic_offset_ = dynoff;
+ this->first_dynamic_global_index_ = dyn_global_index;
+ this->dynamic_count_ = dyncount;
+
+ if (this->size_ == 32)
+ ret = this->sized_finalize<32>(index, off, pool);
+ else if (this->size_ == 64)
+ ret = this->sized_finalize<64>(index, off, pool);
+ else
+ gold_unreachable();
+
+ // Now that we have the final symbol table, we can reliably note
+ // which symbols should get warnings.
+ this->warnings_.note_warnings(this);
+
+ return ret;
+}
+
+// Set the final value for all the symbols. This is called after
+// Layout::finalize, so all the output sections have their final
+// address.
+
+template<int size>
+off_t
+Symbol_table::sized_finalize(unsigned index, off_t off, Stringpool* pool)
+{
+ off = align_address(off, size >> 3);
+ this->offset_ = off;
+
+ size_t orig_index = index;
+
+ const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+ for (Symbol_table_type::iterator p = this->table_.begin();
+ p != this->table_.end();
+ ++p)
+ {
+ Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(p->second);
+
+ // FIXME: Here we need to decide which symbols should go into
+ // the output file, based on --strip.
+
+ // The default version of a symbol may appear twice in the
+ // symbol table. We only need to finalize it once.
+ if (sym->has_symtab_index())
+ continue;
+
+ if (!sym->in_reg())
+ {
+ gold_assert(!sym->has_symtab_index());
+ sym->set_symtab_index(-1U);
+ gold_assert(sym->dynsym_index() == -1U);
+ continue;
+ }
+
+ typename Sized_symbol<size>::Value_type value;
+
+ switch (sym->source())
+ {
+ case Symbol::FROM_OBJECT:
+ {
+ unsigned int shndx = sym->shndx();
+
+ // FIXME: We need some target specific support here.
+ if (shndx >= elfcpp::SHN_LORESERVE
+ && shndx != elfcpp::SHN_ABS)
+ {
+ fprintf(stderr, _("%s: %s: unsupported symbol section 0x%x\n"),
+ program_name, sym->name(), shndx);
+ gold_exit(false);
+ }
+
+ Object* symobj = sym->object();
+ if (symobj->is_dynamic())
+ {
+ value = 0;
+ shndx = elfcpp::SHN_UNDEF;
+ }
+ else if (shndx == elfcpp::SHN_UNDEF)
+ value = 0;
+ else if (shndx == elfcpp::SHN_ABS)
+ value = sym->value();
+ else
+ {
+ Relobj* relobj = static_cast<Relobj*>(symobj);
+ off_t secoff;
+ Output_section* os = relobj->output_section(shndx, &secoff);
+
+ if (os == NULL)
+ {
+ sym->set_symtab_index(-1U);
+ gold_assert(sym->dynsym_index() == -1U);
+ continue;
+ }
+
+ value = sym->value() + os->address() + secoff;
+ }
+ }
+ break;
+
+ case Symbol::IN_OUTPUT_DATA:
+ {
+ Output_data* od = sym->output_data();
+ value = sym->value() + od->address();
+ if (sym->offset_is_from_end())
+ value += od->data_size();
+ }
+ break;
+
+ case Symbol::IN_OUTPUT_SEGMENT:
+ {
+ Output_segment* os = sym->output_segment();
+ value = sym->value() + os->vaddr();
+ switch (sym->offset_base())
+ {
+ case Symbol::SEGMENT_START:
+ break;
+ case Symbol::SEGMENT_END:
+ value += os->memsz();
+ break;
+ case Symbol::SEGMENT_BSS:
+ value += os->filesz();
+ break;
+ default:
+ gold_unreachable();
+ }
+ }
+ break;
+
+ case Symbol::CONSTANT:
+ value = sym->value();
+ break;
+
+ default:
+ gold_unreachable();
+ }
+
+ sym->set_value(value);
+ sym->set_symtab_index(index);
+ pool->add(sym->name(), NULL);
+ ++index;
+ off += sym_size;
+ }
+
+ this->output_count_ = index - orig_index;
+
+ return off;
+}
+
+// Write out the global symbols.
+
+void
+Symbol_table::write_globals(const Target* target, const Stringpool* sympool,
+ const Stringpool* dynpool, Output_file* of) const
+{
+ if (this->size_ == 32)
+ {
+ if (target->is_big_endian())
+ this->sized_write_globals<32, true>(target, sympool, dynpool, of);
+ else
+ this->sized_write_globals<32, false>(target, sympool, dynpool, of);
+ }
+ else if (this->size_ == 64)
+ {
+ if (target->is_big_endian())
+ this->sized_write_globals<64, true>(target, sympool, dynpool, of);
+ else
+ this->sized_write_globals<64, false>(target, sympool, dynpool, of);
+ }
+ else
+ gold_unreachable();
+}
+
+// Write out the global symbols.
+
+template<int size, bool big_endian>
+void
+Symbol_table::sized_write_globals(const Target*,
+ const Stringpool* sympool,
+ const Stringpool* dynpool,
+ Output_file* of) const
+{
+ const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+ unsigned int index = this->first_global_index_;
+ const off_t oview_size = this->output_count_ * sym_size;
+ unsigned char* const psyms = of->get_output_view(this->offset_, oview_size);
+
+ unsigned int dynamic_count = this->dynamic_count_;
+ off_t dynamic_size = dynamic_count * sym_size;
+ unsigned int first_dynamic_global_index = this->first_dynamic_global_index_;
+ unsigned char* dynamic_view;
+ if (this->dynamic_offset_ == 0)
+ dynamic_view = NULL;
+ else
+ dynamic_view = of->get_output_view(this->dynamic_offset_, dynamic_size);
+
+ unsigned char* ps = psyms;
+ for (Symbol_table_type::const_iterator p = this->table_.begin();
+ p != this->table_.end();
+ ++p)
+ {
+ Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(p->second);
+
+ unsigned int sym_index = sym->symtab_index();
+ unsigned int dynsym_index;
+ if (dynamic_view == NULL)
+ dynsym_index = -1U;
+ else
+ dynsym_index = sym->dynsym_index();
+
+ if (sym_index == -1U && dynsym_index == -1U)
+ {
+ // This symbol is not included in the output file.
+ continue;
+ }
+
+ if (sym_index == index)
+ ++index;
+ else if (sym_index != -1U)
+ {
+ // We have already seen this symbol, because it has a
+ // default version.
+ gold_assert(sym_index < index);
+ if (dynsym_index == -1U)
+ continue;
+ sym_index = -1U;
+ }
+
+ unsigned int shndx;
+ switch (sym->source())
+ {
+ case Symbol::FROM_OBJECT:
+ {
+ unsigned int in_shndx = sym->shndx();
+
+ // FIXME: We need some target specific support here.
+ if (in_shndx >= elfcpp::SHN_LORESERVE
+ && in_shndx != elfcpp::SHN_ABS)
+ {
+ fprintf(stderr, _("%s: %s: unsupported symbol section 0x%x\n"),
+ program_name, sym->name(), in_shndx);
+ gold_exit(false);
+ }
+
+ Object* symobj = sym->object();
+ if (symobj->is_dynamic())
+ {
+ // FIXME.
+ shndx = elfcpp::SHN_UNDEF;
+ }
+ else if (in_shndx == elfcpp::SHN_UNDEF
+ || in_shndx == elfcpp::SHN_ABS)
+ shndx = in_shndx;
+ else
+ {
+ Relobj* relobj = static_cast<Relobj*>(symobj);
+ off_t secoff;
+ Output_section* os = relobj->output_section(in_shndx, &secoff);
+ gold_assert(os != NULL);
+ shndx = os->out_shndx();
+ }
+ }
+ break;
+
+ case Symbol::IN_OUTPUT_DATA:
+ shndx = sym->output_data()->out_shndx();
+ break;
+
+ case Symbol::IN_OUTPUT_SEGMENT:
+ shndx = elfcpp::SHN_ABS;
+ break;
+
+ case Symbol::CONSTANT:
+ shndx = elfcpp::SHN_ABS;
+ break;
+
+ default:
+ gold_unreachable();
+ }
+
+ if (sym_index != -1U)
+ {
+ this->sized_write_symbol SELECT_SIZE_ENDIAN_NAME(size, big_endian) (
+ sym, shndx, sympool, ps
+ SELECT_SIZE_ENDIAN(size, big_endian));
+ ps += sym_size;
+ }
+
+ if (dynsym_index != -1U)
+ {
+ dynsym_index -= first_dynamic_global_index;
+ gold_assert(dynsym_index < dynamic_count);
+ unsigned char* pd = dynamic_view + (dynsym_index * sym_size);
+ this->sized_write_symbol SELECT_SIZE_ENDIAN_NAME(size, big_endian) (
+ sym, shndx, dynpool, pd
+ SELECT_SIZE_ENDIAN(size, big_endian));
+ }
+ }
+
+ gold_assert(ps - psyms == oview_size);
+
+ of->write_output_view(this->offset_, oview_size, psyms);
+ if (dynamic_view != NULL)
+ of->write_output_view(this->dynamic_offset_, dynamic_size, dynamic_view);
+}
+
+// Write out the symbol SYM, in section SHNDX, to P. POOL is the
+// strtab holding the name.
+
+template<int size, bool big_endian>
+void
+Symbol_table::sized_write_symbol(Sized_symbol<size>* sym,
+ unsigned int shndx,
+ const Stringpool* pool,
+ unsigned char* p
+ ACCEPT_SIZE_ENDIAN) const
+{
+ elfcpp::Sym_write<size, big_endian> osym(p);
+ osym.put_st_name(pool->get_offset(sym->name()));
+ osym.put_st_value(sym->value());
+ osym.put_st_size(sym->symsize());
+ osym.put_st_info(elfcpp::elf_st_info(sym->binding(), sym->type()));
+ osym.put_st_other(elfcpp::elf_st_other(sym->visibility(), sym->nonvis()));
+ osym.put_st_shndx(shndx);
+}
+
+// Write out a section symbol. Return the update offset.
+
+void
+Symbol_table::write_section_symbol(const Target* target,
+ const Output_section *os,
+ Output_file* of,
+ off_t offset) const
+{
+ if (this->size_ == 32)
+ {
+ if (target->is_big_endian())
+ this->sized_write_section_symbol<32, true>(os, of, offset);
+ else
+ this->sized_write_section_symbol<32, false>(os, of, offset);
+ }
+ else if (this->size_ == 64)
+ {
+ if (target->is_big_endian())
+ this->sized_write_section_symbol<64, true>(os, of, offset);
+ else
+ this->sized_write_section_symbol<64, false>(os, of, offset);
+ }
+ else
+ gold_unreachable();
+}
+
+// Write out a section symbol, specialized for size and endianness.
+
+template<int size, bool big_endian>
+void
+Symbol_table::sized_write_section_symbol(const Output_section* os,
+ Output_file* of,
+ off_t offset) const
+{
+ const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+
+ unsigned char* pov = of->get_output_view(offset, sym_size);
+
+ elfcpp::Sym_write<size, big_endian> osym(pov);
+ osym.put_st_name(0);
+ osym.put_st_value(os->address());
+ osym.put_st_size(0);
+ osym.put_st_info(elfcpp::elf_st_info(elfcpp::STB_LOCAL,
+ elfcpp::STT_SECTION));
+ osym.put_st_other(elfcpp::elf_st_other(elfcpp::STV_DEFAULT, 0));
+ osym.put_st_shndx(os->out_shndx());
+
+ of->write_output_view(offset, sym_size, pov);
+}
+
+// Warnings functions.
+
+// Add a new warning.
+
+void
+Warnings::add_warning(Symbol_table* symtab, const char* name, Object* obj,
+ unsigned int shndx)
+{
+ name = symtab->canonicalize_name(name);
+ this->warnings_[name].set(obj, shndx);
+}
+
+// Look through the warnings and mark the symbols for which we should
+// warn. This is called during Layout::finalize when we know the
+// sources for all the symbols.
+
+void
+Warnings::note_warnings(Symbol_table* symtab)
+{
+ for (Warning_table::iterator p = this->warnings_.begin();
+ p != this->warnings_.end();
+ ++p)
+ {
+ Symbol* sym = symtab->lookup(p->first, NULL);
+ if (sym != NULL
+ && sym->source() == Symbol::FROM_OBJECT
+ && sym->object() == p->second.object)
+ {
+ sym->set_has_warning();
+
+ // Read the section contents to get the warning text. It
+ // would be nicer if we only did this if we have to actually
+ // issue a warning. Unfortunately, warnings are issued as
+ // we relocate sections. That means that we can not lock
+ // the object then, as we might try to issue the same
+ // warning multiple times simultaneously.
+ {
+ Task_locker_obj<Object> tl(*p->second.object);
+ const unsigned char* c;
+ off_t len;
+ c = p->second.object->section_contents(p->second.shndx, &len);
+ p->second.set_text(reinterpret_cast<const char*>(c), len);
+ }
+ }
+ }
+}
+
+// Issue a warning. This is called when we see a relocation against a
+// symbol for which has a warning.
+
+void
+Warnings::issue_warning(const Symbol* sym, const std::string& location) const
+{
+ gold_assert(sym->has_warning());
+ Warning_table::const_iterator p = this->warnings_.find(sym->name());
+ gold_assert(p != this->warnings_.end());
+ fprintf(stderr, _("%s: %s: warning: %s\n"), program_name, location.c_str(),
+ p->second.text.c_str());
+}
+
+// Instantiate the templates we need. We could use the configure
+// script to restrict this to only the ones needed for implemented
+// targets.
+
+template
+void
+Symbol_table::add_from_relobj<32, true>(
+ Sized_relobj<32, true>* relobj,
+ const unsigned char* syms,
+ size_t count,
+ const char* sym_names,
+ size_t sym_name_size,
+ Symbol** sympointers);
+
+template
+void
+Symbol_table::add_from_relobj<32, false>(
+ Sized_relobj<32, false>* relobj,
+ const unsigned char* syms,
+ size_t count,
+ const char* sym_names,
+ size_t sym_name_size,
+ Symbol** sympointers);
+
+template
+void
+Symbol_table::add_from_relobj<64, true>(
+ Sized_relobj<64, true>* relobj,
+ const unsigned char* syms,
+ size_t count,
+ const char* sym_names,
+ size_t sym_name_size,
+ Symbol** sympointers);
+
+template
+void
+Symbol_table::add_from_relobj<64, false>(
+ Sized_relobj<64, false>* relobj,
+ const unsigned char* syms,
+ size_t count,
+ const char* sym_names,
+ size_t sym_name_size,
+ Symbol** sympointers);
+
+template
+void
+Symbol_table::add_from_dynobj<32, true>(
+ Sized_dynobj<32, true>* dynobj,
+ const unsigned char* syms,
+ size_t count,
+ const char* sym_names,
+ size_t sym_name_size,
+ const unsigned char* versym,
+ size_t versym_size,
+ const std::vector<const char*>* version_map);
+
+template
+void
+Symbol_table::add_from_dynobj<32, false>(
+ Sized_dynobj<32, false>* dynobj,
+ const unsigned char* syms,
+ size_t count,
+ const char* sym_names,
+ size_t sym_name_size,
+ const unsigned char* versym,
+ size_t versym_size,
+ const std::vector<const char*>* version_map);
+
+template
+void
+Symbol_table::add_from_dynobj<64, true>(
+ Sized_dynobj<64, true>* dynobj,
+ const unsigned char* syms,
+ size_t count,
+ const char* sym_names,
+ size_t sym_name_size,
+ const unsigned char* versym,
+ size_t versym_size,
+ const std::vector<const char*>* version_map);
+
+template
+void
+Symbol_table::add_from_dynobj<64, false>(
+ Sized_dynobj<64, false>* dynobj,
+ const unsigned char* syms,
+ size_t count,
+ const char* sym_names,
+ size_t sym_name_size,
+ const unsigned char* versym,
+ size_t versym_size,
+ const std::vector<const char*>* version_map);
+
+} // End namespace gold.
diff --git a/gold/symtab.h b/gold/symtab.h
new file mode 100644
index 000000000000..66e98bc6d25e
--- /dev/null
+++ b/gold/symtab.h
@@ -0,0 +1,1050 @@
+// symtab.h -- the gold symbol table -*- C++ -*-
+
+// Symbol_table
+// The symbol table.
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "elfcpp.h"
+#include "stringpool.h"
+#include "object.h"
+
+#ifndef GOLD_SYMTAB_H
+#define GOLD_SYMTAB_H
+
+namespace gold
+{
+
+class Object;
+class Relobj;
+template<int size, bool big_endian>
+class Sized_relobj;
+class Dynobj;
+template<int size, bool big_endian>
+class Sized_dynobj;
+class Versions;
+class Output_data;
+class Output_section;
+class Output_segment;
+class Output_file;
+class Target;
+
+// The base class of an entry in the symbol table. The symbol table
+// can have a lot of entries, so we don't want this class to big.
+// Size dependent fields can be found in the template class
+// Sized_symbol. Targets may support their own derived classes.
+
+class Symbol
+{
+ public:
+ // Because we want the class to be small, we don't use any virtual
+ // functions. But because symbols can be defined in different
+ // places, we need to classify them. This enum is the different
+ // sources of symbols we support.
+ enum Source
+ {
+ // Symbol defined in a relocatable or dynamic input file--this is
+ // the most common case.
+ FROM_OBJECT,
+ // Symbol defined in an Output_data, a special section created by
+ // the target.
+ IN_OUTPUT_DATA,
+ // Symbol defined in an Output_segment, with no associated
+ // section.
+ IN_OUTPUT_SEGMENT,
+ // Symbol value is constant.
+ CONSTANT
+ };
+
+ // When the source is IN_OUTPUT_SEGMENT, we need to describe what
+ // the offset means.
+ enum Segment_offset_base
+ {
+ // From the start of the segment.
+ SEGMENT_START,
+ // From the end of the segment.
+ SEGMENT_END,
+ // From the filesz of the segment--i.e., after the loaded bytes
+ // but before the bytes which are allocated but zeroed.
+ SEGMENT_BSS
+ };
+
+ // Return the symbol name.
+ const char*
+ name() const
+ { return this->name_; }
+
+ // Return the symbol version. This will return NULL for an
+ // unversioned symbol.
+ const char*
+ version() const
+ { return this->version_; }
+
+ // Return the symbol source.
+ Source
+ source() const
+ { return this->source_; }
+
+ // Return the object with which this symbol is associated.
+ Object*
+ object() const
+ {
+ gold_assert(this->source_ == FROM_OBJECT);
+ return this->u_.from_object.object;
+ }
+
+ // Return the index of the section in the input relocatable or
+ // dynamic object file.
+ unsigned int
+ shndx() const
+ {
+ gold_assert(this->source_ == FROM_OBJECT);
+ return this->u_.from_object.shndx;
+ }
+
+ // Return the output data section with which this symbol is
+ // associated, if the symbol was specially defined with respect to
+ // an output data section.
+ Output_data*
+ output_data() const
+ {
+ gold_assert(this->source_ == IN_OUTPUT_DATA);
+ return this->u_.in_output_data.output_data;
+ }
+
+ // If this symbol was defined with respect to an output data
+ // section, return whether the value is an offset from end.
+ bool
+ offset_is_from_end() const
+ {
+ gold_assert(this->source_ == IN_OUTPUT_DATA);
+ return this->u_.in_output_data.offset_is_from_end;
+ }
+
+ // Return the output segment with which this symbol is associated,
+ // if the symbol was specially defined with respect to an output
+ // segment.
+ Output_segment*
+ output_segment() const
+ {
+ gold_assert(this->source_ == IN_OUTPUT_SEGMENT);
+ return this->u_.in_output_segment.output_segment;
+ }
+
+ // If this symbol was defined with respect to an output segment,
+ // return the offset base.
+ Segment_offset_base
+ offset_base() const
+ {
+ gold_assert(this->source_ == IN_OUTPUT_SEGMENT);
+ return this->u_.in_output_segment.offset_base;
+ }
+
+ // Return the symbol binding.
+ elfcpp::STB
+ binding() const
+ { return this->binding_; }
+
+ // Return the symbol type.
+ elfcpp::STT
+ type() const
+ { return this->type_; }
+
+ // Return the symbol visibility.
+ elfcpp::STV
+ visibility() const
+ { return this->visibility_; }
+
+ // Return the non-visibility part of the st_other field.
+ unsigned char
+ nonvis() const
+ { return this->nonvis_; }
+
+ // Return whether this symbol is a forwarder. This will never be
+ // true of a symbol found in the hash table, but may be true of
+ // symbol pointers attached to object files.
+ bool
+ is_forwarder() const
+ { return this->is_forwarder_; }
+
+ // Mark this symbol as a forwarder.
+ void
+ set_forwarder()
+ { this->is_forwarder_ = true; }
+
+ // Return whether this symbol needs an entry in the dynamic symbol
+ // table.
+ bool
+ needs_dynsym_entry() const
+ { return this->needs_dynsym_entry_; }
+
+ // Mark this symbol as needing an entry in the dynamic symbol table.
+ void
+ set_needs_dynsym_entry()
+ { this->needs_dynsym_entry_ = true; }
+
+ // Return whether this symbol has been seen in a regular object.
+ bool
+ in_reg() const
+ { return this->in_reg_; }
+
+ // Mark this symbol as having been seen in a regular object.
+ void
+ set_in_reg()
+ { this->in_reg_ = true; }
+
+ // Mark this symbol as having been seen in a dynamic object.
+ void
+ set_in_dyn()
+ { this->in_dyn_ = 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
+ // value by Symbol_table::finalize. It is an error to ask for the
+ // symbol table index before it has been set.
+ unsigned int
+ symtab_index() const
+ {
+ gold_assert(this->symtab_index_ != 0);
+ return this->symtab_index_;
+ }
+
+ // Set the index of the symbol in the output file symbol table.
+ void
+ set_symtab_index(unsigned int index)
+ {
+ gold_assert(index != 0);
+ this->symtab_index_ = index;
+ }
+
+ // Return whether this symbol already has an index in the output
+ // file symbol table.
+ bool
+ has_symtab_index() const
+ { return this->symtab_index_ != 0; }
+
+ // Return the index of this symbol in the dynamic symbol table. A
+ // value of -1U means that this symbol is not going into the dynamic
+ // symbol table. This starts out as zero, and is set to a non-zero
+ // during Layout::finalize. It is an error to ask for the dynamic
+ // symbol table index before it has been set.
+ unsigned int
+ dynsym_index() const
+ {
+ gold_assert(this->dynsym_index_ != 0);
+ return this->dynsym_index_;
+ }
+
+ // Set the index of the symbol in the dynamic symbol table.
+ void
+ set_dynsym_index(unsigned int index)
+ {
+ gold_assert(index != 0);
+ this->dynsym_index_ = index;
+ }
+
+ // Return whether this symbol already has an index in the dynamic
+ // symbol table.
+ bool
+ has_dynsym_index() const
+ { return this->dynsym_index_ != 0; }
+
+ // Return whether this symbol has an entry in the GOT section.
+ bool
+ has_got_offset() const
+ { return this->has_got_offset_; }
+
+ // Return the offset into the GOT section of this symbol.
+ unsigned int
+ got_offset() const
+ {
+ gold_assert(this->has_got_offset());
+ return this->got_offset_;
+ }
+
+ // Set the GOT offset of this symbol.
+ void
+ set_got_offset(unsigned int got_offset)
+ {
+ this->has_got_offset_ = true;
+ this->got_offset_ = got_offset;
+ }
+
+ // Return whether this symbol has an entry in the PLT section.
+ bool
+ has_plt_offset() const
+ { return this->has_plt_offset_; }
+
+ // Return the offset into the PLT section of this symbol.
+ unsigned int
+ plt_offset() const
+ {
+ gold_assert(this->has_plt_offset());
+ return this->plt_offset_;
+ }
+
+ // Set the PLT offset of this symbol.
+ void
+ set_plt_offset(unsigned int plt_offset)
+ {
+ this->has_plt_offset_ = true;
+ this->plt_offset_ = plt_offset;
+ }
+
+ // Return true if the final value of this symbol is known at link
+ // time.
+ bool
+ final_value_is_known(const General_options* options) const
+ {
+ if (options->is_shared())
+ return false;
+ return this->source_ != FROM_OBJECT || !this->object()->is_dynamic();
+ }
+
+ // Return whether this is a defined symbol (not undefined or
+ // common).
+ bool
+ is_defined() const
+ {
+ return (this->source_ != FROM_OBJECT
+ || (this->shndx() != elfcpp::SHN_UNDEF
+ && this->shndx() != elfcpp::SHN_COMMON));
+ }
+
+ // Return true if this symbol is from a dynamic object.
+ bool
+ is_from_dynobj() const
+ {
+ return this->source_ == FROM_OBJECT && this->object()->is_dynamic();
+ }
+
+ // Return whether this is an undefined symbol.
+ bool
+ is_undefined() const
+ {
+ return this->source_ == FROM_OBJECT && this->shndx() == elfcpp::SHN_UNDEF;
+ }
+
+ // Return whether this is a common symbol.
+ bool
+ is_common() const
+ {
+ return (this->source_ == FROM_OBJECT
+ && (this->shndx() == elfcpp::SHN_COMMON
+ || this->type_ == elfcpp::STT_COMMON));
+ }
+
+ // Return whether there should be a warning for references to this
+ // symbol.
+ bool
+ has_warning() const
+ { return this->has_warning_; }
+
+ // Mark this symbol as having a warning.
+ void
+ set_has_warning()
+ { this->has_warning_ = true; }
+
+ protected:
+ // Instances of this class should always be created at a specific
+ // size.
+ Symbol()
+ { memset(this, 0, sizeof *this); }
+
+ // Initialize the general fields.
+ void
+ init_fields(const char* name, const char* version,
+ elfcpp::STT type, elfcpp::STB binding,
+ elfcpp::STV visibility, unsigned char nonvis);
+
+ // Initialize fields from an ELF symbol in OBJECT.
+ template<int size, bool big_endian>
+ void
+ init_base(const char *name, const char* version, Object* object,
+ const elfcpp::Sym<size, big_endian>&);
+
+ // Initialize fields for an Output_data.
+ void
+ init_base(const char* name, Output_data*, elfcpp::STT, elfcpp::STB,
+ elfcpp::STV, unsigned char nonvis, bool offset_is_from_end);
+
+ // Initialize fields for an Output_segment.
+ void
+ init_base(const char* name, Output_segment* os, elfcpp::STT type,
+ elfcpp::STB binding, elfcpp::STV visibility,
+ unsigned char nonvis, Segment_offset_base offset_base);
+
+ // Initialize fields for a constant.
+ void
+ init_base(const char* name, elfcpp::STT type, elfcpp::STB binding,
+ elfcpp::STV visibility, unsigned char nonvis);
+
+ // Override existing symbol.
+ template<int size, bool big_endian>
+ void
+ override_base(const elfcpp::Sym<size, big_endian>&, Object* object,
+ const char* version);
+
+ private:
+ Symbol(const Symbol&);
+ Symbol& operator=(const Symbol&);
+
+ // Symbol name (expected to point into a Stringpool).
+ const char* name_;
+ // Symbol version (expected to point into a Stringpool). This may
+ // be NULL.
+ const char* version_;
+
+ union
+ {
+ // This struct is used if SOURCE_ == FROM_OBJECT.
+ struct
+ {
+ // Object in which symbol is defined, or in which it was first
+ // seen.
+ Object* object;
+ // Section number in object_ in which symbol is defined.
+ unsigned int shndx;
+ } from_object;
+
+ // This struct is used if SOURCE_ == IN_OUTPUT_DATA.
+ struct
+ {
+ // Output_data in which symbol is defined. Before
+ // Layout::finalize the symbol's value is an offset within the
+ // Output_data.
+ Output_data* output_data;
+ // True if the offset is from the end, false if the offset is
+ // from the beginning.
+ bool offset_is_from_end;
+ } in_output_data;
+
+ // This struct is used if SOURCE_ == IN_OUTPUT_SEGMENT.
+ struct
+ {
+ // Output_segment in which the symbol is defined. Before
+ // Layout::finalize the symbol's value is an offset.
+ Output_segment* output_segment;
+ // The base to use for the offset before Layout::finalize.
+ Segment_offset_base offset_base;
+ } in_output_segment;
+ } u_;
+
+ // The index of this symbol in the output file. If the symbol is
+ // not going into the output file, this value is -1U. This field
+ // starts as always holding zero. It is set to a non-zero value by
+ // Symbol_table::finalize.
+ unsigned int symtab_index_;
+
+ // The index of this symbol in the dynamic symbol table. If the
+ // symbol is not going into the dynamic symbol table, this value is
+ // -1U. This field starts as always holding zero. It is set to a
+ // non-zero value during Layout::finalize.
+ unsigned int dynsym_index_;
+
+ // If this symbol has an entry in the GOT section (has_got_offset_
+ // is true), this is the offset from the start of the GOT section.
+ unsigned int got_offset_;
+
+ // If this symbol has an entry in the PLT section (has_plt_offset_
+ // is true), then this is the offset from the start of the PLT
+ // section.
+ unsigned int plt_offset_;
+
+ // Symbol type.
+ elfcpp::STT type_ : 4;
+ // Symbol binding.
+ elfcpp::STB binding_ : 4;
+ // Symbol visibility.
+ elfcpp::STV visibility_ : 2;
+ // Rest of symbol st_other field.
+ unsigned int nonvis_ : 6;
+ // The type of symbol.
+ Source source_ : 3;
+ // True if this symbol always requires special target-specific
+ // handling.
+ bool is_target_special_ : 1;
+ // True if this is the default version of the symbol.
+ bool is_def_ : 1;
+ // True if this symbol really forwards to another symbol. This is
+ // used when we discover after the fact that two different entries
+ // in the hash table really refer to the same symbol. This will
+ // never be set for a symbol found in the hash table, but may be set
+ // for a symbol found in the list of symbols attached to an Object.
+ // It forwards to the symbol found in the forwarders_ map of
+ // Symbol_table.
+ bool is_forwarder_ : 1;
+ // True if this symbol needs to be in the dynamic symbol table.
+ bool needs_dynsym_entry_ : 1;
+ // True if we've seen this symbol in a regular object.
+ bool in_reg_ : 1;
+ // True if we've seen this symbol in a dynamic object.
+ bool in_dyn_ : 1;
+ // True if the symbol has an entry in the GOT section.
+ bool has_got_offset_ : 1;
+ // True if the symbol has an entry in the PLT section.
+ bool has_plt_offset_ : 1;
+ // True if there is a warning for this symbol.
+ bool has_warning_ : 1;
+};
+
+// The parts of a symbol which are size specific. Using a template
+// derived class like this helps us use less space on a 32-bit system.
+
+template<int size>
+class Sized_symbol : public Symbol
+{
+ public:
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Value_type;
+ typedef typename elfcpp::Elf_types<size>::Elf_WXword Size_type;
+
+ Sized_symbol()
+ { }
+
+ // Initialize fields from an ELF symbol in OBJECT.
+ template<bool big_endian>
+ void
+ init(const char *name, const char* version, Object* object,
+ const elfcpp::Sym<size, big_endian>&);
+
+ // Initialize fields for an Output_data.
+ void
+ init(const char* name, Output_data*, Value_type value, Size_type symsize,
+ elfcpp::STT, elfcpp::STB, elfcpp::STV, unsigned char nonvis,
+ bool offset_is_from_end);
+
+ // Initialize fields for an Output_segment.
+ void
+ init(const char* name, Output_segment*, Value_type value, Size_type symsize,
+ elfcpp::STT, elfcpp::STB, elfcpp::STV, unsigned char nonvis,
+ Segment_offset_base offset_base);
+
+ // Initialize fields for a constant.
+ void
+ init(const char* name, Value_type value, Size_type symsize,
+ elfcpp::STT, elfcpp::STB, elfcpp::STV, unsigned char nonvis);
+
+ // Override existing symbol.
+ template<bool big_endian>
+ void
+ override(const elfcpp::Sym<size, big_endian>&, Object* object,
+ const char* version);
+
+ // Return the symbol's value.
+ Value_type
+ value() const
+ { return this->value_; }
+
+ // Return the symbol's size (we can't call this 'size' because that
+ // is a template parameter).
+ Size_type
+ symsize() const
+ { return this->symsize_; }
+
+ // Set the symbol size. This is used when resolving common symbols.
+ void
+ set_symsize(Size_type symsize)
+ { this->symsize_ = symsize; }
+
+ // Set the symbol value. This is called when we store the final
+ // values of the symbols into the symbol table.
+ void
+ set_value(Value_type value)
+ { this->value_ = value; }
+
+ private:
+ Sized_symbol(const Sized_symbol&);
+ Sized_symbol& operator=(const Sized_symbol&);
+
+ // Symbol value. Before Layout::finalize this is the offset in the
+ // input section. This is set to the final value during
+ // Layout::finalize.
+ Value_type value_;
+ // Symbol size.
+ Size_type symsize_;
+};
+
+// A struct describing a symbol defined by the linker, where the value
+// of the symbol is defined based on an output section. This is used
+// for symbols defined by the linker, like "_init_array_start".
+
+struct Define_symbol_in_section
+{
+ // The symbol name.
+ const char* name;
+ // The name of the output section with which this symbol should be
+ // associated. If there is no output section with that name, the
+ // symbol will be defined as zero.
+ const char* output_section;
+ // The offset of the symbol within the output section. This is an
+ // offset from the start of the output section, unless start_at_end
+ // is true, in which case this is an offset from the end of the
+ // output section.
+ uint64_t value;
+ // The size of the symbol.
+ uint64_t size;
+ // The symbol type.
+ elfcpp::STT type;
+ // The symbol binding.
+ elfcpp::STB binding;
+ // The symbol visibility.
+ elfcpp::STV visibility;
+ // The rest of the st_other field.
+ unsigned char nonvis;
+ // If true, the value field is an offset from the end of the output
+ // section.
+ bool offset_is_from_end;
+ // If true, this symbol is defined only if we see a reference to it.
+ bool only_if_ref;
+};
+
+// A struct describing a symbol defined by the linker, where the value
+// of the symbol is defined based on a segment. This is used for
+// symbols defined by the linker, like "_end". We describe the
+// segment with which the symbol should be associated by its
+// characteristics. If no segment meets these characteristics, the
+// symbol will be defined as zero. If there is more than one segment
+// which meets these characteristics, we will use the first one.
+
+struct Define_symbol_in_segment
+{
+ // The symbol name.
+ const char* name;
+ // The segment type where the symbol should be defined, typically
+ // PT_LOAD.
+ elfcpp::PT segment_type;
+ // Bitmask of segment flags which must be set.
+ elfcpp::PF segment_flags_set;
+ // Bitmask of segment flags which must be clear.
+ elfcpp::PF segment_flags_clear;
+ // The offset of the symbol within the segment. The offset is
+ // calculated from the position set by offset_base.
+ uint64_t value;
+ // The size of the symbol.
+ uint64_t size;
+ // The symbol type.
+ elfcpp::STT type;
+ // The symbol binding.
+ elfcpp::STB binding;
+ // The symbol visibility.
+ elfcpp::STV visibility;
+ // The rest of the st_other field.
+ unsigned char nonvis;
+ // The base from which we compute the offset.
+ Symbol::Segment_offset_base offset_base;
+ // If true, this symbol is defined only if we see a reference to it.
+ bool only_if_ref;
+};
+
+// This class manages warnings. Warnings are a GNU extension. When
+// we see a section named .gnu.warning.SYM in an object file, and if
+// we wind using the definition of SYM from that object file, then we
+// will issue a warning for any relocation against SYM from a
+// different object file. The text of the warning is the contents of
+// the section. This is not precisely the definition used by the old
+// GNU linker; the old GNU linker treated an occurrence of
+// .gnu.warning.SYM as defining a warning symbol. A warning symbol
+// would trigger a warning on any reference. However, it was
+// inconsistent in that a warning in a dynamic object only triggered
+// if there was no definition in a regular object. This linker is
+// different in that we only issue a warning if we use the symbol
+// definition from the same object file as the warning section.
+
+class Warnings
+{
+ public:
+ Warnings()
+ : warnings_()
+ { }
+
+ // Add a warning for symbol NAME in section SHNDX in object OBJ.
+ void
+ add_warning(Symbol_table* symtab, const char* name, Object* obj,
+ unsigned int shndx);
+
+ // For each symbol for which we should give a warning, make a note
+ // on the symbol.
+ void
+ note_warnings(Symbol_table* symtab);
+
+ // Issue a warning for a reference to SYM at LOCATION.
+ void
+ issue_warning(const Symbol* sym, const std::string& location) const;
+
+ private:
+ Warnings(const Warnings&);
+ Warnings& operator=(const Warnings&);
+
+ // What we need to know to get the warning text.
+ struct Warning_location
+ {
+ // The object the warning is in.
+ Object* object;
+ // The index of the warning section.
+ unsigned int shndx;
+ // The warning text if we have already loaded it.
+ std::string text;
+
+ Warning_location()
+ : object(NULL), shndx(0), text()
+ { }
+
+ void
+ set(Object* o, unsigned int s)
+ {
+ this->object = o;
+ this->shndx = s;
+ }
+
+ void
+ set_text(const char* t, off_t l)
+ { this->text.assign(t, l); }
+ };
+
+ // A mapping from warning symbol names (canonicalized in
+ // Symbol_table's namepool_ field) to
+ typedef Unordered_map<const char*, Warning_location> Warning_table;
+
+ Warning_table warnings_;
+};
+
+// The main linker symbol table.
+
+class Symbol_table
+{
+ public:
+ Symbol_table();
+
+ ~Symbol_table();
+
+ // Add COUNT external symbols from the relocatable object RELOBJ to
+ // the symbol table. SYMS is the symbols, SYM_NAMES is their names,
+ // SYM_NAME_SIZE is the size of SYM_NAMES. This sets SYMPOINTERS to
+ // point to the symbols in the symbol table.
+ template<int size, bool big_endian>
+ void
+ add_from_relobj(Sized_relobj<size, big_endian>* relobj,
+ const unsigned char* syms, size_t count,
+ const char* sym_names, size_t sym_name_size,
+ Symbol** sympointers);
+
+ // 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
+ // symbol version data.
+ template<int size, bool big_endian>
+ void
+ add_from_dynobj(Sized_dynobj<size, big_endian>* dynobj,
+ const unsigned char* syms, size_t count,
+ const char* sym_names, size_t sym_name_size,
+ const unsigned char* versym, size_t versym_size,
+ const std::vector<const char*>*);
+
+ // Define a special symbol based on an Output_data. It is a
+ // multiple definition error if this symbol is already defined.
+ Symbol*
+ define_in_output_data(const Target*, const char* name, const char* version,
+ Output_data*, uint64_t value, uint64_t symsize,
+ elfcpp::STT type, elfcpp::STB binding,
+ elfcpp::STV visibility, unsigned char nonvis,
+ bool offset_is_from_end, bool only_if_ref);
+
+ // Define a special symbol based on an Output_segment. It is a
+ // multiple definition error if this symbol is already defined.
+ Symbol*
+ define_in_output_segment(const Target*, const char* name,
+ const char* version, Output_segment*,
+ uint64_t value, uint64_t symsize,
+ elfcpp::STT type, elfcpp::STB binding,
+ elfcpp::STV visibility, unsigned char nonvis,
+ Symbol::Segment_offset_base, bool only_if_ref);
+
+ // Define a special symbol with a constant value. It is a multiple
+ // definition error if this symbol is already defined.
+ Symbol*
+ define_as_constant(const Target*, const char* name, const char* version,
+ uint64_t value, uint64_t symsize, elfcpp::STT type,
+ elfcpp::STB binding, elfcpp::STV visibility,
+ unsigned char nonvis, bool only_if_ref);
+
+ // Define a set of symbols in output sections.
+ void
+ define_symbols(const Layout*, const Target*, int count,
+ const Define_symbol_in_section*);
+
+ // Define a set of symbols in output segments.
+ void
+ define_symbols(const Layout*, const Target*, int count,
+ const Define_symbol_in_segment*);
+
+ // Look up a symbol.
+ Symbol*
+ lookup(const char*, const char* version = NULL) const;
+
+ // Return the real symbol associated with the forwarder symbol FROM.
+ Symbol*
+ resolve_forwards(const Symbol* from) const;
+
+ // Return the bitsize (32 or 64) of the symbols in the table.
+ int
+ get_size() const
+ { return this->size_; }
+
+ // Return the sized version of a symbol in this table.
+ template<int size>
+ Sized_symbol<size>*
+ get_sized_symbol(Symbol* ACCEPT_SIZE) const;
+
+ template<int size>
+ const Sized_symbol<size>*
+ get_sized_symbol(const Symbol* ACCEPT_SIZE) const;
+
+ // Return the count of undefined symbols seen.
+ int
+ saw_undefined() const
+ { return this->saw_undefined_; }
+
+ // Allocate the common symbols
+ void
+ allocate_commons(const General_options&, Layout*);
+
+ // Add a warning for symbol NAME in section SHNDX in object OBJ.
+ void
+ add_warning(const char* name, Object* obj, unsigned int shndx)
+ { this->warnings_.add_warning(this, name, obj, shndx); }
+
+ // Canonicalize a symbol name for use in the hash table.
+ const char*
+ canonicalize_name(const char* name)
+ { return this->namepool_.add(name, NULL); }
+
+ // Possibly issue a warning for a reference to SYM at LOCATION which
+ // is in OBJ.
+ void
+ issue_warning(const Symbol* sym, const std::string& location) const
+ { this->warnings_.issue_warning(sym, location); }
+
+ // Set the dynamic symbol indexes. INDEX is the index of the first
+ // global dynamic symbol. Pointers to the symbols are stored into
+ // the vector. The names are stored into the Stringpool. This
+ // returns an updated dynamic symbol index.
+ unsigned int
+ set_dynsym_indexes(const General_options*, const Target*, unsigned int index,
+ std::vector<Symbol*>*, Stringpool*, Versions*);
+
+ // Finalize the symbol table after we have set the final addresses
+ // of all the input sections. This sets the final symbol indexes,
+ // values and adds the names to *POOL. INDEX is the index of the
+ // first global symbol. OFF is the file offset of the global symbol
+ // table, DYNOFF is the offset of the globals in the dynamic symbol
+ // table, DYN_GLOBAL_INDEX is the index of the first global dynamic
+ // symbol, and DYNCOUNT is the number of global dynamic symbols.
+ // This records the parameters, and returns the new file offset.
+ off_t
+ finalize(unsigned int index, off_t off, off_t dynoff,
+ size_t dyn_global_index, size_t dyncount, Stringpool* pool);
+
+ // Write out the global symbols.
+ void
+ write_globals(const Target*, const Stringpool*, const Stringpool*,
+ Output_file*) const;
+
+ // Write out a section symbol. Return the updated offset.
+ void
+ write_section_symbol(const Target*, const Output_section*, Output_file*,
+ off_t) const;
+
+ private:
+ Symbol_table(const Symbol_table&);
+ Symbol_table& operator=(const Symbol_table&);
+
+ // Set the size (32 or 64) of the symbols in the table.
+ void
+ set_size(int size)
+ { this->size_ = size; }
+
+ // Make FROM a forwarder symbol to TO.
+ void
+ make_forwarder(Symbol* from, Symbol* to);
+
+ // Add a symbol.
+ template<int size, bool big_endian>
+ Symbol*
+ add_from_object(Object*, const char *name, Stringpool::Key name_key,
+ const char *version, Stringpool::Key version_key,
+ bool def, const elfcpp::Sym<size, big_endian>& sym);
+
+ // Resolve symbols.
+ template<int size, bool big_endian>
+ static void
+ resolve(Sized_symbol<size>* to,
+ const elfcpp::Sym<size, big_endian>& sym,
+ Object*, const char* version);
+
+ template<int size, bool big_endian>
+ static void
+ resolve(Sized_symbol<size>* to, const Sized_symbol<size>* from,
+ const char* version ACCEPT_SIZE_ENDIAN);
+
+ // Define a special symbol.
+ template<int size, bool big_endian>
+ Sized_symbol<size>*
+ define_special_symbol(const Target* target, const char* name,
+ const char* version, bool only_if_ref
+ ACCEPT_SIZE_ENDIAN);
+
+ // Define a symbol in an Output_data, sized version.
+ template<int size>
+ Sized_symbol<size>*
+ do_define_in_output_data(const Target*, const char* name,
+ const char* version, Output_data*,
+ typename elfcpp::Elf_types<size>::Elf_Addr value,
+ typename elfcpp::Elf_types<size>::Elf_WXword ssize,
+ elfcpp::STT type, elfcpp::STB binding,
+ elfcpp::STV visibility, unsigned char nonvis,
+ bool offset_is_from_end, bool only_if_ref);
+
+ // Define a symbol in an Output_segment, sized version.
+ template<int size>
+ Sized_symbol<size>*
+ do_define_in_output_segment(
+ const Target*, const char* name, const char* version, Output_segment* os,
+ typename elfcpp::Elf_types<size>::Elf_Addr value,
+ typename elfcpp::Elf_types<size>::Elf_WXword ssize,
+ elfcpp::STT type, elfcpp::STB binding,
+ elfcpp::STV visibility, unsigned char nonvis,
+ Symbol::Segment_offset_base offset_base, bool only_if_ref);
+
+ // Define a symbol as a constant, sized version.
+ template<int size>
+ Sized_symbol<size>*
+ do_define_as_constant(
+ const Target*, const char* name, const char* version,
+ typename elfcpp::Elf_types<size>::Elf_Addr value,
+ typename elfcpp::Elf_types<size>::Elf_WXword ssize,
+ elfcpp::STT type, elfcpp::STB binding,
+ elfcpp::STV visibility, unsigned char nonvis,
+ bool only_if_ref);
+
+ // Allocate the common symbols, sized version.
+ template<int size>
+ void
+ do_allocate_commons(const General_options&, Layout*);
+
+ // Finalize symbols specialized for size.
+ template<int size>
+ off_t
+ sized_finalize(unsigned int, off_t, Stringpool*);
+
+ // Write globals specialized for size and endianness.
+ template<int size, bool big_endian>
+ void
+ sized_write_globals(const Target*, const Stringpool*, const Stringpool*,
+ Output_file*) const;
+
+ // Write out a symbol to P.
+ template<int size, bool big_endian>
+ void
+ sized_write_symbol(Sized_symbol<size>*, unsigned int shndx,
+ const Stringpool*, unsigned char* p
+ ACCEPT_SIZE_ENDIAN) const;
+
+ // Write out a section symbol, specialized for size and endianness.
+ template<int size, bool big_endian>
+ void
+ sized_write_section_symbol(const Output_section*, Output_file*, off_t) const;
+
+ // The type of the symbol hash table.
+
+ typedef std::pair<Stringpool::Key, Stringpool::Key> Symbol_table_key;
+
+ struct Symbol_table_hash
+ {
+ size_t
+ operator()(const Symbol_table_key&) const;
+ };
+
+ struct Symbol_table_eq
+ {
+ bool
+ operator()(const Symbol_table_key&, const Symbol_table_key&) const;
+ };
+
+ typedef Unordered_map<Symbol_table_key, Symbol*, Symbol_table_hash,
+ Symbol_table_eq> Symbol_table_type;
+
+ // The type of the list of common symbols.
+
+ typedef std::vector<Symbol*> Commons_type;
+
+ // The size of the symbols in the symbol table (32 or 64).
+ int size_;
+
+ // We increment this every time we see a new undefined symbol, for
+ // use in archive groups.
+ int saw_undefined_;
+
+ // The index of the first global symbol in the output file.
+ unsigned int first_global_index_;
+
+ // The file offset within the output symtab section where we should
+ // write the table.
+ off_t offset_;
+
+ // The number of global symbols we want to write out.
+ size_t output_count_;
+
+ // The file offset of the global dynamic symbols, or 0 if none.
+ off_t dynamic_offset_;
+
+ // The index of the first global dynamic symbol.
+ unsigned int first_dynamic_global_index_;
+
+ // The number of global dynamic symbols, or 0 if none.
+ off_t dynamic_count_;
+
+ // The symbol hash table.
+ Symbol_table_type table_;
+
+ // A pool of symbol names. This is used for all global symbols.
+ // Entries in the hash table point into this pool.
+ Stringpool namepool_;
+
+ // Forwarding symbols.
+ Unordered_map<const Symbol*, Symbol*> forwarders_;
+
+ // We don't expect there to be very many common symbols, so we keep
+ // a list of them. When we find a common symbol we add it to this
+ // list. It is possible that by the time we process the list the
+ // symbol is no longer a common symbol. It may also have become a
+ // forwarder.
+ Commons_type commons_;
+
+ // Manage symbol warnings.
+ Warnings warnings_;
+};
+
+// We inline get_sized_symbol for efficiency.
+
+template<int size>
+Sized_symbol<size>*
+Symbol_table::get_sized_symbol(Symbol* sym ACCEPT_SIZE) const
+{
+ gold_assert(size == this->get_size());
+ return static_cast<Sized_symbol<size>*>(sym);
+}
+
+template<int size>
+const Sized_symbol<size>*
+Symbol_table::get_sized_symbol(const Symbol* sym ACCEPT_SIZE) const
+{
+ gold_assert(size == this->get_size());
+ return static_cast<const Sized_symbol<size>*>(sym);
+}
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_SYMTAB_H)
diff --git a/gold/target-reloc.h b/gold/target-reloc.h
new file mode 100644
index 000000000000..d282805dbebb
--- /dev/null
+++ b/gold/target-reloc.h
@@ -0,0 +1,193 @@
+// target-reloc.h -- target specific relocation support -*- C++ -*-
+
+#ifndef GOLD_TARGET_RELOC_H
+#define GOLD_TARGET_RELOC_H
+
+#include "elfcpp.h"
+#include "object.h"
+#include "symtab.h"
+#include "reloc-types.h"
+
+namespace gold
+{
+
+// This function implements the generic part of reloc scanning. This
+// is an inline function which takes a class whose operator()
+// implements the machine specific part of scanning. We do it this
+// way to avoidmaking a function call for each relocation, and to
+// avoid repeating the generic code for each target.
+
+template<int size, bool big_endian, typename Target_type, int sh_type,
+ typename Scan>
+inline void
+scan_relocs(
+ const General_options& options,
+ Symbol_table* symtab,
+ Layout* layout,
+ Target_type* target,
+ Sized_relobj<size, big_endian>* object,
+ unsigned int data_shndx,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ size_t local_count,
+ const unsigned char* plocal_syms,
+ Symbol** global_syms)
+{
+ typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype;
+ const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
+ const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+ Scan scan;
+
+ for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
+ {
+ Reltype reloc(prelocs);
+
+ typename elfcpp::Elf_types<size>::Elf_WXword r_info = reloc.get_r_info();
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
+ unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
+
+ if (r_sym < local_count)
+ {
+ gold_assert(plocal_syms != NULL);
+ typename elfcpp::Sym<size, big_endian> lsym(plocal_syms
+ + r_sym * sym_size);
+ const unsigned int shndx = lsym.get_st_shndx();
+ if (shndx < elfcpp::SHN_LORESERVE
+ && shndx != elfcpp::SHN_UNDEF
+ && !object->is_section_included(lsym.get_st_shndx()))
+ {
+ // RELOC is a relocation against a local symbol in a
+ // section we are discarding. We can ignore this
+ // relocation. It will eventually become a reloc
+ // against the value zero.
+ //
+ // FIXME: We should issue a warning if this is an
+ // allocated section; is this the best place to do it?
+ //
+ // FIXME: The old GNU linker would in some cases look
+ // for the linkonce section which caused this section to
+ // be discarded, and, if the other section was the same
+ // size, change the reloc to refer to the other section.
+ // That seems risky and weird to me, and I don't know of
+ // any case where it is actually required.
+
+ continue;
+ }
+
+ scan.local(options, symtab, layout, target, object, data_shndx,
+ reloc, r_type, lsym);
+ }
+ else
+ {
+ Symbol* gsym = global_syms[r_sym - local_count];
+ gold_assert(gsym != NULL);
+ if (gsym->is_forwarder())
+ gsym = symtab->resolve_forwards(gsym);
+
+ scan.global(options, symtab, layout, target, object, data_shndx,
+ reloc, r_type, gsym);
+ }
+ }
+}
+
+// This function implements the generic part of relocation processing.
+// This is an inline function which take a class whose operator()
+// implements the machine specific part of relocation. We do it this
+// way to avoid making a function call for each relocation, and to
+// avoid repeating the generic relocation handling code for each
+// target.
+
+// SIZE is the ELF size: 32 or 64. BIG_ENDIAN is the endianness of
+// the data. SH_TYPE is the section type: SHT_REL or SHT_RELA.
+// RELOCATE implements operator() to do a relocation.
+
+// PRELOCS points to the relocation data. RELOC_COUNT is the number
+// of relocs. VIEW is the section data, VIEW_ADDRESS is its memory
+// address, and VIEW_SIZE is the size.
+
+template<int size, bool big_endian, typename Target_type, int sh_type,
+ typename Relocate>
+inline void
+relocate_section(
+ const Relocate_info<size, big_endian>* relinfo,
+ Target_type* target,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ unsigned char* view,
+ typename elfcpp::Elf_types<size>::Elf_Addr view_address,
+ off_t view_size)
+{
+ typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype;
+ const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
+ Relocate relocate;
+
+ unsigned int local_count = relinfo->local_symbol_count;
+ const typename Sized_relobj<size, big_endian>::Local_values* local_values =
+ relinfo->local_values;
+ const Symbol* const * global_syms = relinfo->symbols;
+
+ for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
+ {
+ Reltype reloc(prelocs);
+
+ off_t offset = reloc.get_r_offset();
+
+ typename elfcpp::Elf_types<size>::Elf_WXword r_info = reloc.get_r_info();
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
+ unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
+
+ const Sized_symbol<size>* sym;
+
+ Symbol_value<size> symval;
+ const Symbol_value<size> *psymval;
+ if (r_sym < local_count)
+ {
+ sym = NULL;
+ psymval = &(*local_values)[r_sym];
+ }
+ else
+ {
+ const Symbol* gsym = global_syms[r_sym - local_count];
+ gold_assert(gsym != NULL);
+ if (gsym->is_forwarder())
+ gsym = relinfo->symtab->resolve_forwards(gsym);
+
+ sym = static_cast<const Sized_symbol<size>*>(gsym);
+ if (sym->has_symtab_index())
+ symval.set_output_symtab_index(sym->symtab_index());
+ else
+ symval.set_no_output_symtab_entry();
+ symval.set_output_value(sym->value());
+ psymval = &symval;
+ }
+
+ if (!relocate.relocate(relinfo, target, i, reloc, r_type, sym, psymval,
+ view + offset, view_address + offset, view_size))
+ continue;
+
+ if (offset < 0 || offset >= view_size)
+ {
+ fprintf(stderr, _("%s: %s: reloc has bad offset %zu\n"),
+ program_name, relinfo->location(i, offset).c_str(),
+ static_cast<size_t>(offset));
+ gold_exit(false);
+ }
+
+ if (sym != NULL
+ && sym->is_undefined()
+ && sym->binding() != elfcpp::STB_WEAK)
+ {
+ fprintf(stderr, _("%s: %s: undefined reference to '%s'\n"),
+ program_name, relinfo->location(i, offset).c_str(),
+ sym->name());
+ // gold_exit(false);
+ }
+
+ if (sym != NULL && sym->has_warning())
+ relinfo->symtab->issue_warning(sym, relinfo->location(i, offset));
+ }
+}
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_TARGET_RELOC_H)
diff --git a/gold/target-select.cc b/gold/target-select.cc
new file mode 100644
index 000000000000..d15d0e346d1d
--- /dev/null
+++ b/gold/target-select.cc
@@ -0,0 +1,52 @@
+// target-select.cc -- select a target for an object file
+
+#include "gold.h"
+
+#include "elfcpp.h"
+#include "target-select.h"
+
+namespace
+{
+
+// The start of the list of target selectors.
+
+gold::Target_selector* target_selectors;
+
+} // End anonymous namespace.
+
+namespace gold
+{
+
+// Construct a Target_selector, which means adding it to the linked
+// list. This runs at global constructor time, so we want it to be
+// fast.
+
+Target_selector::Target_selector(int machine, int size, bool big_endian)
+ : machine_(machine), size_(size), big_endian_(big_endian)
+{
+ this->next_ = target_selectors;
+ target_selectors = this;
+}
+
+// Find the target for an ELF file.
+
+extern Target*
+select_target(int machine, int size, bool big_endian, int osabi,
+ int abiversion)
+{
+ for (Target_selector* p = target_selectors; p != NULL; p = p->next())
+ {
+ int pmach = p->machine();
+ if ((pmach == machine || pmach == elfcpp::EM_NONE)
+ && p->size() == size
+ && p->big_endian() ? big_endian : !big_endian)
+ {
+ Target* ret = p->recognize(machine, osabi, abiversion);
+ if (ret != NULL)
+ return ret;
+ }
+ }
+ return NULL;
+}
+
+} // End namespace gold.
diff --git a/gold/target-select.h b/gold/target-select.h
new file mode 100644
index 000000000000..8ccd75fac757
--- /dev/null
+++ b/gold/target-select.h
@@ -0,0 +1,69 @@
+// target-select.h -- select a target for an object file -*- C++ -*-
+
+#ifndef GOLD_TARGET_SELECT_H
+#define GOLD_TARGET_SELECT_H
+
+namespace gold
+{
+
+class Target;
+
+// We want to avoid a master list of targets, which implies using a
+// global constructor. And we also want the program to start up as
+// quickly as possible, which implies avoiding global constructors.
+// We compromise on a very simple global constructor. We use a target
+// selector, which specifies an ELF machine number and a recognition
+// function. We use global constructors to build a linked list of
+// target selectors--a simple pointer list, not a std::list.
+
+class Target_selector
+{
+ public:
+ // Create a target selector for a specific machine number, size (32
+ // or 64), and endianness. The machine number can be EM_NONE to
+ // test for any machine number.
+ Target_selector(int machine, int size, bool big_endian);
+
+ virtual ~Target_selector()
+ { }
+
+ // If we can handle this target, return a pointer to a target
+ // structure. The size and endianness are known.
+ virtual Target* recognize(int machine, int osabi, int abiversion) = 0;
+
+ // Return the next Target_selector in the linked list.
+ Target_selector*
+ next() const
+ { return this->next_; }
+
+ // Return the machine number this selector is looking for, which can
+ // be EM_NONE to match any machine number.
+ int
+ machine() const
+ { return this->machine_; }
+
+ // Return the size this is looking for (32 or 64).
+ int
+ size() const
+ { return this->size_; }
+
+ // Return the endianness this is looking for.
+ bool
+ big_endian() const
+ { return this->big_endian_; }
+
+ private:
+ int machine_;
+ int size_;
+ bool big_endian_;
+ Target_selector* next_;
+};
+
+// Select the target for an ELF file.
+
+extern Target* select_target(int machine, int size, bool big_endian,
+ int osabi, int abiversion);
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_TARGET_SELECT_H)
diff --git a/gold/target.h b/gold/target.h
new file mode 100644
index 000000000000..9181a93193d5
--- /dev/null
+++ b/gold/target.h
@@ -0,0 +1,210 @@
+// target.h -- target support for gold -*- C++ -*-
+
+// The abstract class Target is the interface for target specific
+// support. It defines abstract methods which each target must
+// implement. Typically there will be one target per processor, but
+// in some cases it may be necessary to have subclasses.
+
+// For speed and consistency we want to use inline functions to handle
+// relocation processing. So besides implementations of the abstract
+// methods, each target is expected to define a template
+// specialization of the relocation functions.
+
+#ifndef GOLD_TARGET_H
+#define GOLD_TARGET_H
+
+#include "elfcpp.h"
+
+namespace gold
+{
+
+class General_options;
+class Object;
+template<int size, bool big_endian>
+class Sized_relobj;
+template<int size, bool big_endian>
+struct Relocate_info;
+class Symbol;
+template<int size>
+class Sized_symbol;
+class Symbol_table;
+
+// The abstract class for target specific handling.
+
+class Target
+{
+ public:
+ virtual ~Target()
+ { }
+
+ // Return the bit size that this target implements. This should
+ // return 32 or 64.
+ int
+ get_size() const
+ { return this->pti_->size; }
+
+ // Return whether this target is big-endian.
+ bool
+ is_big_endian() const
+ { return this->pti_->is_big_endian; }
+
+ // Machine code to store in e_machine field of ELF header.
+ elfcpp::EM
+ machine_code() const
+ { return this->pti_->machine_code; }
+
+ // Whether this target has a specific make_symbol function.
+ bool
+ has_make_symbol() const
+ { return this->pti_->has_make_symbol; }
+
+ // Whether this target has a specific resolve function.
+ bool
+ has_resolve() const
+ { return this->pti_->has_resolve; }
+
+ // Return the default name of the dynamic linker.
+ const char*
+ dynamic_linker() const
+ { return this->pti_->dynamic_linker; }
+
+ // Return the default address to use for the text segment.
+ uint64_t
+ text_segment_address() const
+ { return this->pti_->text_segment_address; }
+
+ // Return the ABI specified page size.
+ uint64_t
+ abi_pagesize() const
+ { return this->pti_->abi_pagesize; }
+
+ // Return the common page size used on actual systems.
+ uint64_t
+ 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(const General_options* options, Layout* layout)
+ { return this->do_finalize_sections(options, 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
+ // simple information.
+ struct Target_info
+ {
+ // Address size (32 or 64).
+ int size;
+ // Whether the target is big endian.
+ bool is_big_endian;
+ // The code to store in the e_machine field of the ELF header.
+ elfcpp::EM machine_code;
+ // Whether this target has a specific make_symbol function.
+ bool has_make_symbol;
+ // Whether this target has a specific resolve function.
+ bool has_resolve;
+ // The default dynamic linker name.
+ const char* dynamic_linker;
+ // The default text segment address.
+ uint64_t text_segment_address;
+ // The ABI specified page size.
+ uint64_t abi_pagesize;
+ // The common page size used by actual implementations.
+ uint64_t common_pagesize;
+ };
+
+ Target(const Target_info* pti)
+ : pti_(pti)
+ { }
+
+ // Virtual function which may be implemented by the child class.
+ virtual void
+ do_finalize_sections(const General_options*, Layout*)
+ { }
+
+ private:
+ Target(const Target&);
+ Target& operator=(const Target&);
+
+ // The target information.
+ const Target_info* pti_;
+};
+
+// The abstract class for a specific size and endianness of target.
+// Each actual target implementation class should derive from an
+// instantiation of Sized_target.
+
+template<int size, bool big_endian>
+class Sized_target : public Target
+{
+ public:
+ // Make a new symbol table entry for the target. This should be
+ // overridden by a target which needs additional information in the
+ // symbol table. This will only be called if has_make_symbol()
+ // returns true.
+ virtual Sized_symbol<size>*
+ make_symbol() const
+ { gold_unreachable(); }
+
+ // Resolve a symbol for the target. This should be overridden by a
+ // target which needs to take special action. TO is the
+ // pre-existing symbol. SYM is the new symbol, seen in OBJECT.
+ // VERSION is the version of SYM. This will only be called if
+ // has_resolve() returns true.
+ virtual void
+ resolve(Symbol*, const elfcpp::Sym<size, big_endian>&, Object*,
+ const char*)
+ { gold_unreachable(); }
+
+ // Scan the relocs for a section, and record any information
+ // required for the symbol. OPTIONS is the command line options.
+ // SYMTAB is the symbol table. OBJECT is the object in which the
+ // section appears. DATA_SHNDX is the section index that these
+ // relocs apply to. SH_TYPE is the type of the relocation section,
+ // SHT_REL or SHT_RELA. PRELOCS points to the relocation data.
+ // RELOC_COUNT is the number of relocs. LOCAL_SYMBOL_COUNT is the
+ // number of local symbols. PLOCAL_SYMBOLS points to the local
+ // symbol data from OBJECT. GLOBAL_SYMBOLS is the array of pointers
+ // to the global symbol table from OBJECT.
+ virtual void
+ scan_relocs(const General_options& options,
+ Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj<size, big_endian>* object,
+ unsigned int data_shndx,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ size_t local_symbol_count,
+ const unsigned char* plocal_symbols,
+ Symbol** global_symbols) = 0;
+
+ // Relocate section data. SH_TYPE is the type of the relocation
+ // section, SHT_REL or SHT_RELA. PRELOCS points to the relocation
+ // information. RELOC_COUNT is the number of relocs. VIEW is a
+ // view into the output file holding the section contents,
+ // VIEW_ADDRESS is the virtual address of the view, and VIEW_SIZE is
+ // the size of the view.
+ virtual void
+ relocate_section(const Relocate_info<size, big_endian>*,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ unsigned char* view,
+ typename elfcpp::Elf_types<size>::Elf_Addr view_address,
+ off_t view_size) = 0;
+
+ protected:
+ Sized_target(const Target::Target_info* pti)
+ : Target(pti)
+ {
+ gold_assert(pti->size == size);
+ gold_assert(pti->is_big_endian ? big_endian : !big_endian);
+ }
+};
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_TARGET_H)
diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am
new file mode 100644
index 000000000000..122be70592b2
--- /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 000000000000..4967af6c862c
--- /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 000000000000..c15237d822bd
--- /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 000000000000..37a4ada9ab06
--- /dev/null
+++ b/gold/testsuite/test.cc
@@ -0,0 +1,78 @@
+// test.cc -- simplistic test framework for gold.
+
+#include "gold.h"
+
+#include <cstdio>
+
+#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 000000000000..e0556e267316
--- /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 000000000000..bfe3c9d7a18b
--- /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<elfcpp::EM>(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 000000000000..c123107e4969
--- /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 000000000000..eb46b72d84f6
--- /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());
+}
diff --git a/gold/workqueue.cc b/gold/workqueue.cc
new file mode 100644
index 000000000000..9062118aaa00
--- /dev/null
+++ b/gold/workqueue.cc
@@ -0,0 +1,404 @@
+// workqueue.cc -- the workqueue for gold
+
+#include "gold.h"
+
+#include "workqueue.h"
+
+namespace gold
+{
+
+// Task_token methods.
+
+Task_token::Task_token()
+ : is_blocker_(false), readers_(0), writer_(NULL)
+{
+}
+
+Task_token::~Task_token()
+{
+ gold_assert(this->readers_ == 0 && this->writer_ == NULL);
+}
+
+bool
+Task_token::is_readable() const
+{
+ gold_assert(!this->is_blocker_);
+ return this->writer_ == NULL;
+}
+
+void
+Task_token::add_reader()
+{
+ gold_assert(!this->is_blocker_);
+ gold_assert(this->is_readable());
+ ++this->readers_;
+}
+
+void
+Task_token::remove_reader()
+{
+ gold_assert(!this->is_blocker_);
+ gold_assert(this->readers_ > 0);
+ --this->readers_;
+}
+
+bool
+Task_token::is_writable() const
+{
+ gold_assert(!this->is_blocker_);
+ return this->writer_ == NULL && this->readers_ == 0;
+}
+
+void
+Task_token::add_writer(const Task* t)
+{
+ gold_assert(!this->is_blocker_);
+ gold_assert(this->is_writable());
+ this->writer_ = t;
+}
+
+void
+Task_token::remove_writer(const Task* t)
+{
+ gold_assert(!this->is_blocker_);
+ gold_assert(this->writer_ == t);
+ this->writer_ = NULL;
+}
+
+bool
+Task_token::has_write_lock(const Task* t)
+{
+ gold_assert(!this->is_blocker_);
+ return this->writer_ == t;
+}
+
+// For blockers, we just use the readers_ field.
+
+void
+Task_token::add_blocker()
+{
+ if (this->readers_ == 0 && this->writer_ == NULL)
+ this->is_blocker_ = true;
+ else
+ gold_assert(this->is_blocker_);
+ ++this->readers_;
+}
+
+bool
+Task_token::remove_blocker()
+{
+ gold_assert(this->is_blocker_ && this->readers_ > 0);
+ --this->readers_;
+ return this->readers_ == 0;
+}
+
+bool
+Task_token::is_blocked() const
+{
+ gold_assert(this->is_blocker_
+ || (this->readers_ == 0 && this->writer_ == NULL));
+ return this->readers_ > 0;
+}
+
+// The Task_block_token class.
+
+Task_block_token::Task_block_token(Task_token& token, Workqueue* workqueue)
+ : token_(token), workqueue_(workqueue)
+{
+ // We must increment the block count when the task is created and
+ // put on the queue. This object is created when the task is run,
+ // so we don't increment the block count here.
+ gold_assert(this->token_.is_blocked());
+}
+
+Task_block_token::~Task_block_token()
+{
+ if (this->token_.remove_blocker())
+ {
+ // Tell the workqueue that a blocker was cleared. This is
+ // always called in the main thread, so no locking is required.
+ this->workqueue_->cleared_blocker();
+ }
+}
+
+// The Workqueue_runner abstract class.
+
+class Workqueue_runner
+{
+ public:
+ Workqueue_runner(Workqueue* workqueue)
+ : workqueue_(workqueue)
+ { }
+ virtual ~Workqueue_runner()
+ { }
+
+ // Run a task. This is always called in the main thread.
+ virtual void run(Task*, Task_locker*) = 0;
+
+ protected:
+ // This is called by an implementation when a task is completed.
+ void completed(Task* t, Task_locker* tl)
+ { this->workqueue_->completed(t, tl); }
+
+ Workqueue* get_workqueue() const
+ { return this->workqueue_; }
+
+ private:
+ Workqueue* workqueue_;
+};
+
+// The simple single-threaded implementation of Workqueue_runner.
+
+class Workqueue_runner_single : public Workqueue_runner
+{
+ public:
+ Workqueue_runner_single(Workqueue* workqueue)
+ : Workqueue_runner(workqueue)
+ { }
+ ~Workqueue_runner_single()
+ { }
+
+ void run(Task*, Task_locker*);
+};
+
+void
+Workqueue_runner_single::run(Task* t, Task_locker* tl)
+{
+ t->run(this->get_workqueue());
+ this->completed(t, tl);
+}
+
+// Workqueue methods.
+
+Workqueue::Workqueue(const General_options&)
+ : tasks_lock_(),
+ tasks_(),
+ completed_lock_(),
+ completed_(),
+ running_(0),
+ completed_condvar_(this->completed_lock_),
+ cleared_blockers_(0)
+{
+ // At some point we will select the specific implementation of
+ // Workqueue_runner to use based on the command line options.
+ this->runner_ = new Workqueue_runner_single(this);
+}
+
+Workqueue::~Workqueue()
+{
+ gold_assert(this->tasks_.empty());
+ gold_assert(this->completed_.empty());
+ gold_assert(this->running_ == 0);
+}
+
+// Add a task to the queue.
+
+void
+Workqueue::queue(Task* t)
+{
+ Hold_lock hl(this->tasks_lock_);
+ this->tasks_.push_back(t);
+}
+
+// Add a task to the front of the queue.
+
+void
+Workqueue::queue_front(Task* t)
+{
+ Hold_lock hl(this->tasks_lock_);
+ this->tasks_.push_front(t);
+}
+
+// Clear the list of completed tasks. Return whether we cleared
+// anything. The completed_lock_ must be held when this is called.
+
+bool
+Workqueue::clear_completed()
+{
+ if (this->completed_.empty())
+ return false;
+ do
+ {
+ delete this->completed_.front();
+ this->completed_.pop_front();
+ }
+ while (!this->completed_.empty());
+ return true;
+}
+
+// Find a runnable task in TASKS, which is non-empty. Return NULL if
+// none could be found. The tasks_lock_ must be held when this is
+// called. Sets ALL_BLOCKED if all non-runnable tasks are waiting on
+// a blocker.
+
+Task*
+Workqueue::find_runnable(Task_list& tasks, bool* all_blocked)
+{
+ Task* tlast = tasks.back();
+ *all_blocked = true;
+ while (true)
+ {
+ Task* t = tasks.front();
+ tasks.pop_front();
+
+ Task::Is_runnable_type is_runnable = t->is_runnable(this);
+ if (is_runnable == Task::IS_RUNNABLE)
+ return t;
+
+ if (is_runnable != Task::IS_BLOCKED)
+ *all_blocked = false;
+
+ tasks.push_back(t);
+
+ if (t == tlast)
+ {
+ // We couldn't find any runnable task. If there are any
+ // completed tasks, free their locks and try again.
+
+ {
+ Hold_lock hl2(this->completed_lock_);
+
+ if (!this->clear_completed())
+ {
+ // There had better be some tasks running, or we will
+ // never find a runnable task.
+ gold_assert(this->running_ > 0);
+
+ // We couldn't find any runnable tasks, and we
+ // couldn't release any locks.
+ return NULL;
+ }
+ }
+
+ // We're going around again, so recompute ALL_BLOCKED.
+ *all_blocked = true;
+ }
+ }
+}
+
+// Process all the tasks on the workqueue. This is the main loop in
+// the linker. Note that as we process tasks, new tasks will be
+// added.
+
+void
+Workqueue::process()
+{
+ while (true)
+ {
+ Task* t;
+ bool empty;
+ bool all_blocked;
+
+ {
+ Hold_lock hl(this->tasks_lock_);
+
+ if (this->tasks_.empty())
+ {
+ t = NULL;
+ empty = true;
+ all_blocked = false;
+ }
+ else
+ {
+ t = this->find_runnable(this->tasks_, &all_blocked);
+ empty = false;
+ }
+ }
+
+ // If T != NULL, it is a task we can run.
+ // If T == NULL && empty, then there are no tasks waiting to
+ // be run at this level.
+ // If T == NULL && !empty, then there tasks waiting to be
+ // run at this level, but they are waiting for something to
+ // unlock.
+
+ if (t != NULL)
+ this->run(t);
+ else if (!empty)
+ {
+ {
+ Hold_lock hl(this->completed_lock_);
+
+ // There must be something for us to wait for, or we won't
+ // be able to make progress.
+ gold_assert(this->running_ > 0 || !this->completed_.empty());
+
+ if (all_blocked)
+ {
+ this->cleared_blockers_ = 0;
+ this->clear_completed();
+ while (this->cleared_blockers_ == 0)
+ {
+ gold_assert(this->running_ > 0);
+ this->completed_condvar_.wait();
+ this->clear_completed();
+ }
+ }
+ else
+ {
+ if (this->running_ > 0)
+ {
+ // Wait for a task to finish.
+ this->completed_condvar_.wait();
+ }
+ this->clear_completed();
+ }
+ }
+ }
+ else
+ {
+ {
+ Hold_lock hl(this->completed_lock_);
+
+ // If there are no running tasks, then we are done.
+ if (this->running_ == 0)
+ {
+ this->clear_completed();
+ return;
+ }
+
+ // Wait for a task to finish. Then we have to loop around
+ // again in case it added any new tasks before finishing.
+ this->completed_condvar_.wait();
+ this->clear_completed();
+ }
+ }
+ }
+}
+
+// Run a task. This is always called in the main thread.
+
+void
+Workqueue::run(Task* t)
+{
+ ++this->running_;
+ this->runner_->run(t, t->locks(this));
+}
+
+// This is called when a task is completed to put the locks on the
+// list to be released. We use a list because we only want the locks
+// to be released in the main thread.
+
+void
+Workqueue::completed(Task* t, Task_locker* tl)
+{
+ {
+ Hold_lock hl(this->completed_lock_);
+ gold_assert(this->running_ > 0);
+ --this->running_;
+ this->completed_.push_back(tl);
+ this->completed_condvar_.signal();
+ }
+ delete t;
+}
+
+// This is called when the last task for a blocker has completed.
+// This is always called in the main thread.
+
+void
+Workqueue::cleared_blocker()
+{
+ ++this->cleared_blockers_;
+}
+
+} // End namespace gold.
diff --git a/gold/workqueue.h b/gold/workqueue.h
new file mode 100644
index 000000000000..ed7a5b00d7dd
--- /dev/null
+++ b/gold/workqueue.h
@@ -0,0 +1,419 @@
+// workqueue.h -- the work queue for gold -*- C++ -*-
+
+// After processing the command line, everything the linker does is
+// driven from a work queue. This permits us to parallelize the
+// linker where possible.
+
+// Task_token
+// A simple locking implementation to ensure proper task ordering.
+// Task_read_token, Task_write_token
+// Lock a Task_token for read or write.
+// Task_locker
+// Task locking using RAII.
+// Task
+// An abstract class for jobs to run.
+
+#ifndef GOLD_WORKQUEUE_H
+#define GOLD_WORKQUEUE_H
+
+#include "gold-threads.h"
+#include "fileread.h"
+
+namespace gold
+{
+
+class General_options;
+class Task;
+class Workqueue;
+
+// Some tasks require access to shared data structures, such as the
+// symbol table. Some tasks must be executed in a particular error,
+// such as reading input file symbol tables--if we see foo.o -llib, we
+// have to read the symbols for foo.o before we read the ones for
+// -llib. To implement this safely and efficiently, we use tokens.
+// Task_tokens support shared read/exclusive write access to some
+// resource. Alternatively, they support blockers: blockers implement
+// the requirement that some set of tasks must complete before another
+// set of tasks can start. In such a case we increment the block
+// count when we create the task, and decrement it when the task
+// completes. Task_tokens are only manipulated by the main thread, so
+// they do not themselves require any locking.
+
+class Task_token
+{
+ public:
+ Task_token();
+
+ ~Task_token();
+
+ // A read/write token uses these methods.
+
+ bool
+ is_readable() const;
+
+ void
+ add_reader();
+
+ void
+ remove_reader();
+
+ bool
+ is_writable() const;
+
+ void
+ add_writer(const Task*);
+
+ void
+ remove_writer(const Task*);
+
+ bool
+ has_write_lock(const Task*);
+
+ // A blocker token uses these methods.
+
+ void
+ add_blocker();
+
+ // Returns true if block count drops to zero.
+ bool
+ remove_blocker();
+
+ bool
+ is_blocked() const;
+
+ private:
+ // It makes no sense to copy these.
+ Task_token(const Task_token&);
+ Task_token& operator=(const Task_token&);
+
+ bool is_blocker_;
+ int readers_;
+ const Task* writer_;
+};
+
+// In order to support tokens more reliably, we provide objects which
+// handle them using RAII.
+
+class Task_read_token
+{
+ public:
+ Task_read_token(Task_token& token)
+ : token_(token)
+ { this->token_.add_reader(); }
+
+ ~Task_read_token()
+ { this->token_.remove_reader(); }
+
+ private:
+ Task_read_token(const Task_read_token&);
+ Task_read_token& operator=(const Task_read_token&);
+
+ Task_token& token_;
+};
+
+class Task_write_token
+{
+ public:
+ Task_write_token(Task_token& token, const Task* task)
+ : token_(token), task_(task)
+ { this->token_.add_writer(this->task_); }
+
+ ~Task_write_token()
+ { this->token_.remove_writer(this->task_); }
+
+ private:
+ Task_write_token(const Task_write_token&);
+ Task_write_token& operator=(const Task_write_token&);
+
+ Task_token& token_;
+ const Task* task_;
+};
+
+class Task_block_token
+{
+ public:
+ // The blocker count must be incremented when the task is created.
+ // This object is created when the task is run. When we unblock the
+ // last task, we notify the workqueue.
+ Task_block_token(Task_token& token, Workqueue* workqueue);
+ ~Task_block_token();
+
+ private:
+ Task_block_token(const Task_block_token&);
+ Task_block_token& operator=(const Task_block_token&);
+
+ Task_token& token_;
+ Workqueue* workqueue_;
+};
+
+// An object which implements an RAII lock for any object which
+// supports lock and unlock methods.
+
+template<typename Obj>
+class Task_lock_obj
+{
+ public:
+ Task_lock_obj(Obj& obj)
+ : obj_(obj)
+ { this->obj_.lock(); }
+
+ ~Task_lock_obj()
+ { this->obj_.unlock(); }
+
+ private:
+ Task_lock_obj(const Task_lock_obj&);
+ Task_lock_obj& operator=(const Task_lock_obj&);
+
+ Obj& obj_;
+};
+
+// An abstract class used to lock Task_tokens using RAII. A typical
+// implementation would simply have a set of members of type
+// Task_read_token, Task_write_token, and Task_block_token.
+
+class Task_locker
+{
+ public:
+ Task_locker()
+ { }
+
+ virtual ~Task_locker()
+ { }
+};
+
+// A version of Task_locker which may be used for a single read lock.
+
+class Task_locker_read : public Task_locker
+{
+ public:
+ Task_locker_read(Task_token& token)
+ : read_token_(token)
+ { }
+
+ private:
+ Task_locker_read(const Task_locker_read&);
+ Task_locker_read& operator=(const Task_locker_read&);
+
+ Task_read_token read_token_;
+};
+
+// A version of Task_locker which may be used for a single write lock.
+
+class Task_locker_write : public Task_locker
+{
+ public:
+ Task_locker_write(Task_token& token, const Task* task)
+ : write_token_(token, task)
+ { }
+
+ private:
+ Task_locker_write(const Task_locker_write&);
+ Task_locker_write& operator=(const Task_locker_write&);
+
+ Task_write_token write_token_;
+};
+
+// A version of Task_locker which may be used for a single blocker
+// lock.
+
+class Task_locker_block : public Task_locker
+{
+ public:
+ Task_locker_block(Task_token& token, Workqueue* workqueue)
+ : block_token_(token, workqueue)
+ { }
+
+ private:
+ Task_locker_block(const Task_locker_block&);
+ Task_locker_block& operator=(const Task_locker_block&);
+
+ Task_block_token block_token_;
+};
+
+// A version of Task_locker which may be used to hold a lock on any
+// object which supports lock() and unlock() methods.
+
+template<typename Obj>
+class Task_locker_obj : public Task_locker
+{
+ public:
+ Task_locker_obj(Obj& obj)
+ : obj_lock_(obj)
+ { }
+
+ private:
+ Task_locker_obj(const Task_locker_obj&);
+ Task_locker_obj& operator=(const Task_locker_obj&);
+
+ Task_lock_obj<Obj> obj_lock_;
+};
+
+// The superclass for tasks to be placed on the workqueue. Each
+// specific task class will inherit from this one.
+
+class Task
+{
+ public:
+ Task()
+ { }
+ virtual ~Task()
+ { }
+
+ // Type returned by Is_runnable.
+ enum Is_runnable_type
+ {
+ // Task is runnable.
+ IS_RUNNABLE,
+ // Task is waiting for a block to clear.
+ IS_BLOCKED,
+ // Task is not waiting for a block, but is not runnable--i.e., is
+ // waiting for a lock.
+ IS_LOCKED
+ };
+
+ // Return whether the task can be run now. This method is only
+ // called from the main thread.
+ virtual Is_runnable_type
+ is_runnable(Workqueue*) = 0;
+
+ // Return a pointer to a Task_locker which locks all the resources
+ // required by the task. We delete the pointer when the task is
+ // complete. This method can return NULL if no locks are required.
+ // This method is only called from the main thread.
+ virtual Task_locker*
+ locks(Workqueue*) = 0;
+
+ // Run the task.
+ virtual void
+ run(Workqueue*) = 0;
+
+ private:
+ Task(const Task&);
+ Task& operator=(const Task&);
+};
+
+// A simple task which waits for a blocker and then runs a function.
+
+class Task_function_runner
+{
+ public:
+ virtual ~Task_function_runner()
+ { }
+
+ virtual void
+ run(Workqueue*) = 0;
+};
+
+class Task_function : public Task
+{
+ public:
+ // Both points should be allocated using new, and will be deleted
+ // after the task runs.
+ Task_function(Task_function_runner* runner, Task_token* blocker)
+ : runner_(runner), blocker_(blocker)
+ { }
+
+ ~Task_function()
+ {
+ delete this->runner_;
+ delete this->blocker_;
+ }
+
+ // The standard task methods.
+
+ // Wait until the task is unblocked.
+ Is_runnable_type
+ is_runnable(Workqueue*)
+ { return this->blocker_->is_blocked() ? IS_BLOCKED : IS_RUNNABLE; }
+
+ // This type of task does not normally hold any locks.
+ virtual Task_locker*
+ locks(Workqueue*)
+ { return NULL; }
+
+ // Run the action.
+ void
+ run(Workqueue* workqueue)
+ { this->runner_->run(workqueue); }
+
+ private:
+ Task_function(const Task_function&);
+ Task_function& operator=(const Task_function&);
+
+ Task_function_runner* runner_;
+ Task_token* blocker_;
+};
+
+// The workqueue
+
+class Workqueue_runner;
+
+class Workqueue
+{
+ public:
+ Workqueue(const General_options&);
+ ~Workqueue();
+
+ // Add a new task to the work queue.
+ void
+ queue(Task*);
+
+ // Add a new task to the front of the work queue. It will be the
+ // next task to run if it is ready.
+ void
+ queue_front(Task*);
+
+ // Process all the tasks on the work queue.
+ void
+ process();
+
+ // A complete set of blocking tasks has completed.
+ void
+ cleared_blocker();
+
+ private:
+ // This class can not be copied.
+ Workqueue(const Workqueue&);
+ Workqueue& operator=(const Workqueue&);
+
+ typedef std::list<Task*> Task_list;
+
+ // Run a task.
+ void run(Task*);
+
+ friend class Workqueue_runner;
+
+ // Find a runnable task.
+ Task* find_runnable(Task_list&, bool*);
+
+ // Add a lock to the completed queue.
+ void completed(Task*, Task_locker*);
+
+ // Clear the completed queue.
+ bool clear_completed();
+
+ // How to run a task. Only accessed from main thread.
+ Workqueue_runner* runner_;
+
+ // Lock for access to tasks_ members.
+ Lock tasks_lock_;
+ // List of tasks to execute at each link level.
+ Task_list tasks_;
+
+ // Lock for access to completed_ and running_ members.
+ Lock completed_lock_;
+ // List of Task_locker objects for main thread to free.
+ std::list<Task_locker*> completed_;
+ // Number of tasks currently running.
+ int running_;
+ // Condition variable signalled when a new entry is added to completed_.
+ Condvar completed_condvar_;
+
+ // Number of blocker tokens which were fully cleared. Only accessed
+ // from main thread.
+ int cleared_blockers_;
+};
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_WORKQUEUE_H)
diff --git a/gold/yyscript.y b/gold/yyscript.y
new file mode 100644
index 000000000000..0bd2b603b2e5
--- /dev/null
+++ b/gold/yyscript.y
@@ -0,0 +1,168 @@
+/* yyscript.y -- linker script grammer for gold. */
+
+/* This is a bison grammar to parse a subset of the original GNU ld
+ linker script language. */
+
+%{
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "script-c.h"
+
+%}
+
+/* We need to use a pure parser because we might be multi-threaded.
+ We pass some arguments through the parser to the lexer. */
+
+%pure-parser
+
+%parse-param {void* closure}
+%lex-param {void* closure}
+
+/* Since we require bison anyhow, we take advantage of it. */
+
+%error-verbose
+
+/* The values associated with tokens. */
+
+%union {
+ const char* string;
+ int64_t integer;
+}
+
+/* Operators, including a precedence table for expressions. */
+
+%right PLUSEQ MINUSEQ MULTEQ DIVEQ '=' LSHIFTEQ RSHIFTEQ ANDEQ OREQ
+%right '?' ':'
+%left OROR
+%left ANDAND
+%left '|'
+%left '^'
+%left '&'
+%left EQ NE
+%left '<' '>' LE GE
+%left LSHIFT RSHIFT
+%left '+' '-'
+%left '*' '/' '%'
+
+/* Constants. */
+
+%token <string> STRING
+%token <integer> INTEGER
+
+/* Keywords. This list is taken from ldgram.y and ldlex.l in the old
+ GNU linker, with the keywords which only appear in MRI mode
+ removed. Not all these keywords are actually used in this grammar.
+ In most cases the keyword is recognized as the token name in upper
+ case. The comments indicate where this is not the case. */
+
+%token ABSOLUTE
+%token ADDR
+%token ALIGN_K /* ALIGN */
+%token ASSERT_K /* ASSERT */
+%token AS_NEEDED
+%token AT
+%token BIND
+%token BLOCK
+%token BYTE
+%token CONSTANT
+%token CONSTRUCTORS
+%token COPY
+%token CREATE_OBJECT_SYMBOLS
+%token DATA_SEGMENT_ALIGN
+%token DATA_SEGMENT_END
+%token DATA_SEGMENT_RELRO_END
+%token DEFINED
+%token DSECT
+%token ENTRY
+%token EXCLUDE_FILE
+%token EXTERN
+%token FILL
+%token FLOAT
+%token FORCE_COMMON_ALLOCATION
+%token GLOBAL /* global */
+%token GROUP
+%token HLL
+%token INCLUDE
+%token INFO
+%token INHIBIT_COMMON_ALLOCATION
+%token INPUT
+%token KEEP
+%token LENGTH /* LENGTH, l, len */
+%token LOADADDR
+%token LOCAL /* local */
+%token LONG
+%token MAP
+%token MAX_K /* MAX */
+%token MEMORY
+%token MIN_K /* MIN */
+%token NEXT
+%token NOCROSSREFS
+%token NOFLOAT
+%token NOLOAD
+%token ONLY_IF_RO
+%token ONLY_IF_RW
+%token ORIGIN /* ORIGIN, o, org */
+%token OUTPUT
+%token OUTPUT_ARCH
+%token OUTPUT_FORMAT
+%token OVERLAY
+%token PHDRS
+%token PROVIDE
+%token PROVIDE_HIDDEN
+%token QUAD
+%token SEARCH_DIR
+%token SECTIONS
+%token SEGMENT_START
+%token SHORT
+%token SIZEOF
+%token SIZEOF_HEADERS /* SIZEOF_HEADERS, sizeof_headers */
+%token SORT_BY_ALIGNMENT
+%token SORT_BY_NAME
+%token SPECIAL
+%token SQUAD
+%token STARTUP
+%token SUBALIGN
+%token SYSLIB
+%token TARGET_K /* TARGET */
+%token TRUNCATE
+%token VERSIONK /* VERSION */
+
+%%
+
+file_list:
+ file_list file_cmd
+ | /* empty */
+ ;
+
+file_cmd:
+ OUTPUT_FORMAT '(' STRING ')'
+ | GROUP
+ { script_start_group(closure); }
+ '(' input_list ')'
+ { script_end_group(closure); }
+ ;
+
+input_list:
+ input_list_element
+ | input_list opt_comma input_list_element
+ ;
+
+input_list_element:
+ STRING
+ { script_add_file(closure, $1); }
+ | AS_NEEDED
+ { script_start_as_needed(closure); }
+ '(' input_list ')'
+ { script_end_as_needed(closure); }
+ ;
+
+opt_comma:
+ ','
+ | /* empty */
+ ;
+
+%%