]> rtime.felk.cvut.cz Git - fpga/lx-cpu1/binutils-tumbl.git/commitdiff
More dynamic object support, initial scripting support.
authorIan Lance Taylor <iant@google.com>
Tue, 14 Nov 2006 19:21:05 +0000 (19:21 +0000)
committerIan Lance Taylor <iant@google.com>
Tue, 14 Nov 2006 19:21:05 +0000 (19:21 +0000)
31 files changed:
elfcpp/elfcpp.h
elfcpp/elfcpp_internal.h
gold/Makefile.am
gold/Makefile.in
gold/common.cc
gold/configure
gold/configure.ac
gold/dynobj.cc [new file with mode: 0644]
gold/dynobj.h
gold/gold.cc
gold/i386.cc
gold/layout.cc
gold/layout.h
gold/object.cc
gold/object.h
gold/options.cc
gold/options.h
gold/output.cc
gold/output.h
gold/po/POTFILES.in
gold/po/gold.pot
gold/readsyms.cc
gold/readsyms.h
gold/reloc.cc
gold/script-c.h [new file with mode: 0644]
gold/script.cc [new file with mode: 0644]
gold/script.h [new file with mode: 0644]
gold/symtab.cc
gold/symtab.h
gold/target.h
gold/yyscript.y [new file with mode: 0644]

index 322afb47d7f0a3e07f57211b76c01041301cd689..e106fabbb125de0aba8ef944071e2933d4822bfa 100644 (file)
@@ -530,6 +530,138 @@ elf_r_info<64>(unsigned int s, unsigned int t)
   return (static_cast<Elf_Xword>(s) << 32) + (t & 0xffffffff);
 }
 
+// Dynamic tags found in the PT_DYNAMIC segment.
+
+enum DT
+{
+  DT_NULL = 0,
+  DT_NEEDED = 1,
+  DT_PLTRELSZ = 2,
+  DT_PLTGOT = 3,
+  DT_HASH = 4,
+  DT_STRTAB = 5,
+  DT_SYMTAB = 6,
+  DT_RELA = 7,
+  DT_RELASZ = 8,
+  DT_RELAENT = 9,
+  DT_STRSZ = 10,
+  DT_SYMENT = 11,
+  DT_INIT = 12,
+  DT_FINI = 13,
+  DT_SONAME = 14,
+  DT_RPATH = 15,
+  DT_SYMBOLIC = 16,
+  DT_REL = 17,
+  DT_RELSZ = 18,
+  DT_RELENT = 19,
+  DT_PLTREL = 20,
+  DT_DEBUG = 21,
+  DT_TEXTREL = 22,
+  DT_JMPREL = 23,
+  DT_BIND_NOW = 24,
+  DT_INIT_ARRAY = 25,
+  DT_FINI_ARRAY = 26,
+  DT_INIT_ARRAYSZ = 27,
+  DT_FINI_ARRAYSZ = 28,
+  DT_RUNPATH = 29,
+  DT_FLAGS = 30,
+  DT_ENCODING = 32,
+  DT_PREINIT_ARRAY = 33,
+  DT_PREINIT_ARRAYSZ = 33,
+  DT_LOOS = 0x6000000d,
+  DT_HIOS = 0x6ffff000,
+  DT_LOPROC = 0x70000000,
+  DT_HIPROC = 0x7fffffff,
+
+  // The remaining values are extensions used by GNU or Solaris.
+  DT_VALRNGLO = 0x6ffffd00,
+  DT_GNU_PRELINKED = 0x6ffffdf5,
+  DT_GNU_CONFLICTSZ = 0x6ffffdf6,
+  DT_GNU_LIBLISTSZ = 0x6ffffdf7,
+  DT_CHECKSUM = 0x6ffffdf8,
+  DT_PLTPADSZ = 0x6ffffdf9,
+  DT_MOVEENT = 0x6ffffdfa,
+  DT_MOVESZ = 0x6ffffdfb,
+  DT_FEATURE = 0x6ffffdfc,
+  DT_POSFLAG_1 = 0x6ffffdfd,
+  DT_SYMINSZ = 0x6ffffdfe,
+  DT_SYMINENT = 0x6ffffdff,
+  DT_VALRNGHI = 0x6ffffdff,
+
+  DT_ADDRRNGLO = 0x6ffffe00,
+  DT_GNU_HASH = 0x6ffffef5,
+  DT_TLSDESC_PLT = 0x6ffffef6,
+  DT_TLSDESC_GOT = 0x6ffffef7,
+  DT_GNU_CONFLICT = 0x6ffffef8,
+  DT_GNU_LIBLIST = 0x6ffffef9,
+  DT_CONFIG = 0x6ffffefa,
+  DT_DEPAUDIT = 0x6ffffefb,
+  DT_AUDIT = 0x6ffffefc,
+  DT_PLTPAD = 0x6ffffefd,
+  DT_MOVETAB = 0x6ffffefe,
+  DT_SYMINFO = 0x6ffffeff,
+  DT_ADDRRNGHI = 0x6ffffeff,
+
+  DT_RELACOUNT = 0x6ffffff9,
+  DT_RELCOUNT = 0x6ffffffa,
+  DT_FLAGS_1 = 0x6ffffffb,
+  DT_VERDEF = 0x6ffffffc,
+  DT_VERDEFNUM = 0x6ffffffd,
+  DT_VERNEED = 0x6ffffffe,
+  DT_VERNEEDNUM = 0x6fffffff,
+
+  DT_VERSYM = 0x6ffffff0,
+
+  DT_AUXILIARY = 0x7ffffffd,
+  DT_USED = 0x7ffffffe,
+  DT_FILTER = 0x7fffffff
+};
+
+// Flags found in the DT_FLAGS dynamic element.
+
+enum DF
+{
+  DF_ORIGIN = 0x1,
+  DF_SYMBOLIC = 0x2,
+  DF_TEXTREL = 0x4,
+  DF_BIND_NOW = 0x8,
+  DF_STATIC_TLS = 0x10
+};
+
+// Version numbers which appear in the vd_version field of a Verdef
+// structure.
+
+const int VER_DEF_NONE = 0;
+const int VER_DEF_CURRENT = 1;
+
+// Version numbers which appear in the vn_version field of a Verneed
+// structure.
+
+const int VER_NEED_NONE = 0;
+const int VER_NEED_CURRENT = 1;
+
+// Bit flags which appear in vd_flags of Verdef and vna_flags of
+// Vernaux.
+
+const int VER_FLG_BASE = 0x1;
+const int VER_FLG_WEAK = 0x2;
+
+// Special constants found in the SHT_GNU_versym entries.
+
+const int VER_NDX_LOCAL = 0;
+const int VER_NDX_GLOBAL = 1;
+
+// A SHT_GNU_versym section holds 16-bit words.  This bit is set if
+// the symbol is hidden and can only be seen when referenced using an
+// explicit version number.  This is a GNU extension.
+
+const int VERSYM_HIDDEN = 0x8000;
+
+// This is the mask for the rest of the data in a word read from a
+// SHT_GNU_versym section.
+
+const int VERSYM_VERSION = 0x7fff;
+
 } // End namespace elfcpp.
 
 // Include internal details after defining the types.
@@ -558,6 +690,8 @@ struct Elf_sizes
   // Sizes of ELF reloc entries.
   static const int rel_size = sizeof(internal::Rel_data<size>);
   static const int rela_size = sizeof(internal::Rela_data<size>);
+  // Size of ELF dynamic entry.
+  static const int dyn_size = sizeof(internal::Dyn_data<size>);
 };
 
 // Accessor class for the ELF file header.
@@ -1087,6 +1221,198 @@ class Rela
   const internal::Rela_data<size>* p_;
 };
 
+// Accessor classes for entries in the ELF SHT_DYNAMIC section aka
+// PT_DYNAMIC segment.
+
+template<int size, bool big_endian>
+class Dyn
+{
+ public:
+  Dyn(const unsigned char* p)
+    : p_(reinterpret_cast<const internal::Dyn_data<size>*>(p))
+  { }
+
+  template<typename File>
+  Dyn(File* file, typename File::Location loc)
+    : p_(reinterpret_cast<const internal::Dyn_data<size>*>(
+          file->view(loc.file_offset, loc.data_size).data()))
+  { }
+
+  typename Elf_types<size>::Elf_Swxword
+  get_d_tag() const
+  { return Convert<size, big_endian>::convert_host(this->p_->d_tag); }
+
+  typename Elf_types<size>::Elf_WXword
+  get_d_val() const
+  { return Convert<size, big_endian>::convert_host(this->p_->d_val); }
+
+  typename Elf_types<size>::Elf_Addr
+  get_d_ptr() const
+  { return Convert<size, big_endian>::convert_host(this->p_->d_val); }
+
+ private:
+  const internal::Dyn_data<size>* p_;
+};
+
+// Accessor classes for entries in the ELF SHT_GNU_verdef section.
+
+template<int size, bool big_endian>
+class Verdef
+{
+ public:
+  Verdef(const unsigned char* p)
+    : p_(reinterpret_cast<const internal::Verdef_data*>(p))
+  { }
+
+  template<typename File>
+  Verdef(File* file, typename File::Location loc)
+    : p_(reinterpret_cast<const internal::Verdef_data*>(
+          file->view(loc.file_offset, loc.data_size).data()))
+  { }
+
+  Elf_Half
+  get_vd_version() const
+  { return Convert<16, big_endian>::convert_host(this->p_->vd_version); }
+
+  Elf_Half
+  get_vd_flags() const
+  { return Convert<16, big_endian>::convert_host(this->p_->vd_flags); }
+
+  Elf_Half
+  get_vd_ndx() const
+  { return Convert<16, big_endian>::convert_host(this->p_->vd_ndx); }
+
+  Elf_Half
+  get_vd_cnt() const
+  { return Convert<16, big_endian>::convert_host(this->p_->vd_cnt); }
+
+  Elf_Word
+  get_vd_hash() const
+  { return Convert<32, big_endian>::convert_host(this->p_->vd_hash); }
+
+  Elf_Word
+  get_vd_aux() const
+  { return Convert<32, big_endian>::convert_host(this->p_->vd_aux); }
+
+  Elf_Word
+  get_vd_next() const
+  { return Convert<32, big_endian>::convert_host(this->p_->vd_next); }
+
+ private:
+  const internal::Verdef_data* p_;
+};
+
+// Accessor classes for auxiliary entries in the ELF SHT_GNU_verdef
+// section.
+
+template<int size, bool big_endian>
+class Verdaux
+{
+ public:
+  Verdaux(const unsigned char* p)
+    : p_(reinterpret_cast<const internal::Verdaux_data*>(p))
+  { }
+
+  template<typename File>
+  Verdaux(File* file, typename File::Location loc)
+    : p_(reinterpret_cast<const internal::Verdaux_data*>(
+          file->view(loc.file_offset, loc.data_size).data()))
+  { }
+
+  Elf_Word
+  get_vda_name() const
+  { return Convert<32, big_endian>::convert_host(this->p_->vda_name); }
+
+  Elf_Word
+  get_vda_next() const
+  { return Convert<32, big_endian>::convert_host(this->p_->vda_next); }
+
+ private:
+  const internal::Verdaux_data* p_;
+};
+
+// Accessor classes for entries in the ELF SHT_GNU_verneed section.
+
+template<int size, bool big_endian>
+class Verneed
+{
+ public:
+  Verneed(const unsigned char* p)
+    : p_(reinterpret_cast<const internal::Verneed_data*>(p))
+  { }
+
+  template<typename File>
+  Verneed(File* file, typename File::Location loc)
+    : p_(reinterpret_cast<const internal::Verneed_data*>(
+          file->view(loc.file_offset, loc.data_size).data()))
+  { }
+
+  Elf_Half
+  get_vn_version() const
+  { return Convert<16, big_endian>::convert_host(this->p_->vn_version); }
+
+  Elf_Half
+  get_vn_cnt() const
+  { return Convert<16, big_endian>::convert_host(this->p_->vn_cnt); }
+
+  Elf_Word
+  get_vn_file() const
+  { return Convert<32, big_endian>::convert_host(this->p_->vn_file); }
+
+  Elf_Word
+  get_vn_aux() const
+  { return Convert<32, big_endian>::convert_host(this->p_->vn_aux); }
+
+  Elf_Word
+  get_vn_next() const
+  { return Convert<32, big_endian>::convert_host(this->p_->vn_next); }
+
+ private:
+  const internal::Verneed_data* p_;
+};
+
+// Accessor classes for auxiliary entries in the ELF SHT_GNU_verneed
+// section.
+
+template<int size, bool big_endian>
+class Vernaux
+{
+ public:
+  Vernaux(const unsigned char* p)
+    : p_(reinterpret_cast<const internal::Vernaux_data*>(p))
+  { }
+
+  template<typename File>
+  Vernaux(File* file, typename File::Location loc)
+    : p_(reinterpret_cast<const internal::Vernaux_data*>(
+          file->view(loc.file_offset, loc.data_size).data()))
+  { }
+
+  Elf_Word
+  get_vna_hash() const
+  { return Convert<32, big_endian>::convert_host(this->p_->vna_hash); }
+
+  Elf_Half
+  get_vna_flags() const
+  { return Convert<16, big_endian>::convert_host(this->p_->vna_flags); }
+
+  Elf_Half
+  get_vna_other() const
+  { return Convert<16, big_endian>::convert_host(this->p_->vna_other); }
+
+  Elf_Word
+  get_vna_name() const
+  { return Convert<32, big_endian>::convert_host(this->p_->vna_name); }
+
+  Elf_Word
+  get_vna_next() const
+  { return Convert<32, big_endian>::convert_host(this->p_->vna_next); }
+
+ private:
+  const internal::Vernaux_data* p_;
+};
+
+
 } // End namespace elfcpp.
 
 #endif // !defined(ELFPCP_H)
index c991535cb0acb9d3c831df059b2c1c0efae3f5f0..7a2b5d4836bd8420fa83e21cd82b6d75a12058ee 100644 (file)
@@ -35,7 +35,7 @@ struct Ehdr_data
   Elf_Half e_shstrndx;
 };
 
-// An Elf section header.
+// An ELF section header.
 
 template<int size>
 struct Shdr_data
@@ -114,7 +114,7 @@ struct Sym_data<64>
   Elf_Xword st_size;
 };
 
-// Elf relocation table entries.
+// ELF relocation table entries.
 
 template<int size>
 struct Rel_data
@@ -131,6 +131,81 @@ struct Rela_data
   typename Elf_types<size>::Elf_Swxword r_addend;
 };
 
+// An entry in the ELF SHT_DYNAMIC section aka PT_DYNAMIC segment.
+
+template<int size>
+struct Dyn_data
+{
+  typename Elf_types<size>::Elf_Swxword d_tag;
+  typename Elf_types<size>::Elf_WXword d_val;
+};
+
+// An entry in a SHT_GNU_verdef section.  This structure is the same
+// in 32-bit and 64-bit ELF files.
+
+struct Verdef_data
+{
+  // Version number of structure (VER_DEF_*).
+  Elf_Half vd_version;
+  // Bit flags (VER_FLG_*).
+  Elf_Half vd_flags;
+  // Version index.
+  Elf_Half vd_ndx;
+  // Number of auxiliary Verdaux entries.
+  Elf_Half vd_cnt;
+  // Hash of name.
+  Elf_Word vd_hash;
+  // Byte offset to first Verdaux entry.
+  Elf_Word vd_aux;
+  // Byte offset to next Verdef entry.
+  Elf_Word vd_next;
+};
+
+// An auxiliary entry in a SHT_GNU_verdef section.  This structure is
+// the same in 32-bit and 64-bit ELF files.
+
+struct Verdaux_data
+{
+  // Offset in string table of version name.
+  Elf_Word vda_name;
+  // Byte offset to next Verdaux entry.
+  Elf_Word vda_next;
+};
+
+// An entry in a SHT_GNU_verneed section.  This structure is the same
+// in 32-bit and 64-bit ELF files.
+
+struct Verneed_data
+{
+  // Version number of structure (VER_NEED_*).
+  Elf_Half vn_version;
+  // Number of auxiliary Vernaux entries.
+  Elf_Half vn_cnt;
+  // Offset in string table of library name.
+  Elf_Word vn_file;
+  // Byte offset to first Vernaux entry.
+  Elf_Word vn_aux;
+  // Byt eoffset to next Verneed entry.
+  Elf_Word vn_next;
+};
+
+// An auxiliary entry in a SHT_GNU_verneed section.  This structure is
+// the same in 32-bit and 64-bit ELF files.
+
+struct Vernaux_data
+{
+  // Hash of dependency name.
+  Elf_Word vna_hash;
+  // Bit flags (VER_FLG_*).
+  Elf_Half vna_flags;
+  // Version index used in SHT_GNU_versym entries.
+  Elf_Half vna_other;
+  // Offset in string table of version name.
+  Elf_Word vna_name;
+  // Byte offset to next Vernaux entry.
+  Elf_Word vna_next;
+};
+
 } // End namespace internal.
 
 } // End namespace elfcpp.
index 13aae2678e497a72d0228dba6d7a9d26433eb32a..12ec749920746cb86bbfa1bf4ea978011ed6c349 100644 (file)
@@ -15,6 +15,8 @@ INCLUDES = -D_GNU_SOURCE \
        -DLOCALEDIR="\"$(datadir)/locale\"" \
        @INCINTL@
 
+YFLAGS = -d
+
 noinst_PROGRAMS = ld-new
 
 CCFILES = \
@@ -22,6 +24,7 @@ CCFILES = \
        common.cc \
        defstd.cc \
        dirsearch.cc \
+       dynobj.cc \
        fileread.cc \
        gold.cc \
        gold-threads.cc \
@@ -32,6 +35,7 @@ CCFILES = \
        readsyms.cc \
        reloc.cc \
        resolve.cc \
+       script.cc \
        symtab.cc \
        stringpool.cc \
        target-select.cc \
@@ -42,6 +46,7 @@ HFILES = \
        common.h \
        defstd.h \
        dirsearch.h \
+       dynobj.h \
        fileread.h \
        gold.h \
        gold-threads.h \
@@ -51,6 +56,7 @@ HFILES = \
        output.h \
        readsyms.h \
        reloc.h \
+       script.h \
        stringpool.h \
        symtab.h \
        target.h \
@@ -61,7 +67,10 @@ HFILES = \
 TARGETFILES = \
        i386.cc
 
-OFILES = gold.o options.o
+YFILES = \
+       yyscript.y
+
+EXTRA_DIST = yyscript.c yyscript.h
 
 POTFILES= $(CCFILES) $(HFILES) $(TARGETFILES)
 
@@ -69,10 +78,13 @@ po/POTFILES.in: @MAINT@ Makefile
        for f in $(POTFILES); do echo $$f; done | LC_COLLATE= sort > tmp \
          && mv tmp $(srcdir)/po/POTFILES.in
 
-ld_new_SOURCES = $(CCFILES) $(HFILES) $(TARGETFILES)
+ld_new_SOURCES = $(CCFILES) $(HFILES) $(TARGETFILES) $(YFILES)
 ld_new_DEPENDENCIES = $(LIBINTL_DEP)
 ld_new_LDADD = $(LIBINTL)
 
+# Use an explicit dependency for the bison generated header file.
+script.$(OBJEXT): yyscript.h
+
 .PHONY: install-exec-local
 
 install-exec-local: ld-new$(EXEEXT)
index d4c0c67c5ac2eae09115c08c2419235ca11eaf73..deef51c43ce1ad93f6fb204af8ba8351ff710b37 100644 (file)
@@ -45,7 +45,8 @@ DIST_COMMON = README $(am__configure_deps) $(srcdir)/../config.guess \
        $(srcdir)/../install-sh $(srcdir)/../missing \
        $(srcdir)/../mkinstalldirs $(srcdir)/Makefile.am \
        $(srcdir)/Makefile.in $(srcdir)/config.in \
-       $(top_srcdir)/configure $(top_srcdir)/po/Make-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 \
@@ -63,29 +64,32 @@ CONFIG_HEADER = config.h
 CONFIG_CLEAN_FILES = po/Makefile.in
 PROGRAMS = $(noinst_PROGRAMS)
 am__objects_1 = archive.$(OBJEXT) common.$(OBJEXT) defstd.$(OBJEXT) \
-       dirsearch.$(OBJEXT) fileread.$(OBJEXT) gold.$(OBJEXT) \
-       gold-threads.$(OBJEXT) layout.$(OBJEXT) object.$(OBJEXT) \
-       options.$(OBJEXT) output.$(OBJEXT) readsyms.$(OBJEXT) \
-       reloc.$(OBJEXT) resolve.$(OBJEXT) symtab.$(OBJEXT) \
-       stringpool.$(OBJEXT) target-select.$(OBJEXT) \
-       workqueue.$(OBJEXT)
+       dirsearch.$(OBJEXT) dynobj.$(OBJEXT) fileread.$(OBJEXT) \
+       gold.$(OBJEXT) gold-threads.$(OBJEXT) layout.$(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 = i386.$(OBJEXT)
-am_ld_new_OBJECTS = $(am__objects_1) $(am__objects_2) $(am__objects_3)
+am__objects_4 = yyscript.$(OBJEXT)
+am_ld_new_OBJECTS = $(am__objects_1) $(am__objects_2) $(am__objects_3) \
+       $(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 $@
-COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
-       $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
-CCLD = $(CC)
-LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+YACCCOMPILE = $(YACC) $(YFLAGS) $(AM_YFLAGS)
 SOURCES = $(ld_new_SOURCES)
 DIST_SOURCES = $(ld_new_SOURCES)
 RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
@@ -175,6 +179,7 @@ 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_STRIP = @ac_ct_STRIP@
@@ -229,11 +234,13 @@ INCLUDES = -D_GNU_SOURCE \
        -DLOCALEDIR="\"$(datadir)/locale\"" \
        @INCINTL@
 
+YFLAGS = -d
 CCFILES = \
        archive.cc \
        common.cc \
        defstd.cc \
        dirsearch.cc \
+       dynobj.cc \
        fileread.cc \
        gold.cc \
        gold-threads.cc \
@@ -244,6 +251,7 @@ CCFILES = \
        readsyms.cc \
        reloc.cc \
        resolve.cc \
+       script.cc \
        symtab.cc \
        stringpool.cc \
        target-select.cc \
@@ -254,6 +262,7 @@ HFILES = \
        common.h \
        defstd.h \
        dirsearch.h \
+       dynobj.h \
        fileread.h \
        gold.h \
        gold-threads.h \
@@ -263,6 +272,7 @@ HFILES = \
        output.h \
        readsyms.h \
        reloc.h \
+       script.h \
        stringpool.h \
        symtab.h \
        target.h \
@@ -273,16 +283,19 @@ HFILES = \
 TARGETFILES = \
        i386.cc
 
-OFILES = gold.o options.o
+YFILES = \
+       yyscript.y
+
+EXTRA_DIST = yyscript.c yyscript.h
 POTFILES = $(CCFILES) $(HFILES) $(TARGETFILES)
-ld_new_SOURCES = $(CCFILES) $(HFILES) $(TARGETFILES)
+ld_new_SOURCES = $(CCFILES) $(HFILES) $(TARGETFILES) $(YFILES)
 ld_new_DEPENDENCIES = $(LIBINTL_DEP)
 ld_new_LDADD = $(LIBINTL)
 all: config.h
        $(MAKE) $(AM_MAKEFLAGS) all-recursive
 
 .SUFFIXES:
-.SUFFIXES: .cc .o .obj
+.SUFFIXES: .c .cc .o .obj .y
 am--refresh:
        @:
 $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
@@ -338,6 +351,11 @@ po/Makefile.in: $(top_builddir)/config.status $(top_srcdir)/po/Make-in
 
 clean-noinstPROGRAMS:
        -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS)
+yyscript.h: yyscript.c
+       @if test ! -f $@; then \
+         rm -f yyscript.c; \
+         $(MAKE) yyscript.c; \
+       else :; fi
 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)
@@ -352,6 +370,7 @@ distclean-compile:
 @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@
@@ -363,10 +382,26 @@ distclean-compile:
 @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 $@ $<; \
@@ -381,6 +416,27 @@ distclean-compile:
 @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
@@ -686,6 +742,8 @@ distclean-generic:
 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-noinstPROGRAMS mostlyclean-am
@@ -761,6 +819,9 @@ po/POTFILES.in: @MAINT@ Makefile
        for f in $(POTFILES); do echo $$f; done | LC_COLLATE= sort > tmp \
          && mv tmp $(srcdir)/po/POTFILES.in
 
+# Use an explicit dependency for the bison generated header file.
+script.$(OBJEXT): yyscript.h
+
 .PHONY: install-exec-local
 
 install-exec-local: ld-new$(EXEEXT)
index 358ed8d0d9469613b44b8000a830692ff0fcb506..7ba8adc2697d68987e146b50aeb1df5f303b681f 100644 (file)
@@ -171,7 +171,7 @@ Symbol_table::do_allocate_commons(const General_options&,
 
   // Place them in a newly allocated .bss section.
 
-  Output_section_common *poc = new Output_section_common(addralign);
+  Output_data_common *poc = new Output_data_common(addralign);
 
   layout->add_output_section_data(".bss", elfcpp::SHT_NOBITS,
                                  elfcpp::SHF_WRITE | elfcpp::SHF_ALLOC,
index a64cd709b5c2cc2896d0b57717b681a122ec76e1..8be7e913a5dc5e385c56ea19a36f0a869bb8bb1c 100755 (executable)
@@ -309,7 +309,7 @@ ac_includes_default="\
 # include <unistd.h>
 #endif"
 
-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar 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 USE_NLS LIBINTL LIBINTL_DEP INCINTL XGETTEXT GMSGFMT POSUB CATALOGS DATADIRNAME INSTOBJEXT GENCAT CATOBJEXT MKINSTALLDIRS MSGFMT MSGMERGE WARN_CFLAGS NO_WERROR WARN_CXXFLAGS LFS_CXXFLAGS CXXCPP EGREP MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT LIBOBJS LTLIBOBJS'
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE YACC 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.
@@ -3409,6 +3409,47 @@ else
 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"
+
 # 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:
@@ -5746,6 +5787,7 @@ 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,@USE_NLS@,$USE_NLS,;t t
 s,@LIBINTL@,$LIBINTL,;t t
 s,@LIBINTL_DEP@,$LIBINTL_DEP,;t t
index 42cba7f8b4a70f459509f2ef4b3f5ccf0ac6658f..10e0db98b27b86f0c156b8986229c9b38bb730a6 100644 (file)
@@ -12,6 +12,7 @@ AM_CONFIG_HEADER(config.h:config.in)
 
 AC_PROG_CC
 AC_PROG_CXX
+AC_PROG_YACC
 AC_PROG_INSTALL
 ZW_GNU_GETTEXT_SISTER_DIR
 AM_PO_SUBDIRS
diff --git a/gold/dynobj.cc b/gold/dynobj.cc
new file mode 100644 (file)
index 0000000..ba1fb15
--- /dev/null
@@ -0,0 +1,670 @@
+// dynobj.cc -- dynamic object support for gold
+
+#include "gold.h"
+
+#include <vector>
+#include <cstring>
+
+#include "symtab.h"
+#include "dynobj.h"
+
+namespace gold
+{
+
+// 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),
+    soname_()
+{
+}
+
+// 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);
+
+  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 soname_ 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);
+  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->soname_ = std::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);
+      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
+{
+  assert(ndx < version_map->size());
+  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;
+}
+
+// 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;
+
+  // First find the largest version index.
+  unsigned int maxver = 0;
+
+  if (sd->verdef != NULL)
+    {
+      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);
+
+         const unsigned int vd_ndx = verdef.get_vd_ndx();
+
+         // The GNU linker clears the VERSYM_HIDDEN bit.  I'm not
+         // sure why.
+
+         if (vd_ndx > maxver)
+           maxver = vd_ndx;
+
+         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;
+       }
+    }
+
+  if (sd->verneed != NULL)
+    {
+      const unsigned char* pverneed = sd->verneed->data();
+      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);
+
+         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_other = vernaux.get_vna_other();
+             if (vna_other > maxver)
+               maxver = vna_other;
+
+             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;
+       }
+    }
+
+  // Now MAXVER is the largest version index we have seen.
+
+  version_map->resize(maxver + 1);
+
+  const char* names = reinterpret_cast<const char*>(sd->symbol_names->data());
+  off_t names_size = sd->symbol_names_size;
+
+  if (sd->verdef != NULL)
+    {
+      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);
+
+         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, verdef.get_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;
+       }
+    }
+
+  if (sd->verneed != NULL)
+    {
+      const unsigned char* pverneed = sd->verneed->data();
+      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);
+
+         const unsigned int vn_aux = verneed.get_vn_aux();
+         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);
+
+             pvna += vernaux.get_vna_next();
+           }
+
+         p += verneed.get_vn_next();
+       }
+    }
+}
+
+// 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)
+    {
+      assert(sd->symbol_names == NULL);
+      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;
+    }
+}
+
+// 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>;
+
+} // End namespace gold.
index 99e78830d15b70e5b35e3f842e1fa4aa67a00120..04a2c631a3fc6e09d4928631b23af0bee9ee1293 100644 (file)
@@ -3,6 +3,8 @@
 #ifndef GOLD_DYNOBJ_H
 #define GOLD_DYNOBJ_H
 
+#include <vector>
+
 #include "object.h"
 
 namespace gold
@@ -28,6 +30,10 @@ class Sized_dynobj : public Dynobj
   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*);
@@ -41,14 +47,65 @@ class Sized_dynobj : public Dynobj
   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.
-  const unsigned char*
-  do_section_contents(unsigned int shnum, off_t* plen) = 0;
+  Object::Location
+  do_section_contents(unsigned int shndx)
+  { return this->elf_file_.section_contents(shndx); }
 
-  // Get the name of a section.
-  std::string
-  do_section_name(unsigned int shnum);
+ 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 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_;
+  // The DT_SONAME name, if any.
+  std::string soname_;
 };
 
 } // End namespace gold.
index c2372adf526bed18c35c3174542521157b13fa6d..3073b1869e615a1aa98803e33293036f20f8fd66 100644 (file)
@@ -113,7 +113,7 @@ queue_initial_tasks(const General_options& options,
       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,
+                                       search_path, &*p, NULL, this_blocker,
                                        next_blocker));
       this_blocker = next_blocker;
     }
index 15376f9598ee40522089e1ebf47008251baba3e4..dc13dca1fba656e31df0e79cd41ac28288bde373 100644 (file)
@@ -149,7 +149,7 @@ class Target_i386 : public Sized_target<32, false>
   optimize_tls_reloc(const General_options*, bool is_local, int r_type);
 
   // Get the GOT section, creating it if necessary.
-  Output_section_got<32, false>*
+  Output_data_got<32, false>*
   got_section(Symbol_table*, Layout*);
 
   // Information about this specific target which we pass to the
@@ -157,7 +157,7 @@ class Target_i386 : public Sized_target<32, false>
   static const Target::Target_info i386_info;
 
   // The GOT section.
-  Output_section_got<32, false>* got_;
+  Output_data_got<32, false>* got_;
 };
 
 const Target::Target_info Target_i386::i386_info =
@@ -166,20 +166,21 @@ const Target::Target_info Target_i386::i386_info =
   false,               // is_big_endian
   elfcpp::EM_386,      // machine_code
   false,               // has_make_symbol
-  false,               // has_resolve,
-  0x08048000,          // text_segment_address,
+  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_section_got<32, false>*
+Output_data_got<32, false>*
 Target_i386::got_section(Symbol_table* symtab, Layout* layout)
 {
   if (this->got_ == NULL)
     {
-      this->got_ = new Output_section_got<32, false>();
+      this->got_ = new Output_data_got<32, false>();
 
       assert(symtab != NULL && layout != NULL);
       layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
@@ -393,13 +394,8 @@ Target_i386::Scan::global(const General_options& options,
 
     case elfcpp::R_386_GOT32:
       // The symbol requires a GOT entry.
-      if (!gsym->has_got_offset())
+      if (target->got_section(symtab, layout)->add_global(gsym))
        {
-         Output_section_got<32, false>* got = target->got_section(symtab,
-                                                                  layout);
-         const unsigned int got_offset = got->add_global(gsym);
-         gsym->set_got_offset(got_offset);
-
          // If this symbol is not resolved locally, we need to add a
          // dynamic relocation for it.
          if (!gsym->is_resolved_locally())
index e969a806a08526361ae36f00364c4f7734ffb471..bcb10295371700a96cce187b043b40b391a8d267 100644 (file)
@@ -355,13 +355,30 @@ Layout::find_first_load_seg()
 off_t
 Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
 {
+  const int size = input_objects->target()->get_size();
+
+  Output_segment* phdr_seg = NULL;
   if (input_objects->any_dynamic())
     {
-      // If there are any dynamic objects in the link, then we need
-      // some additional segments: PT_PHDRS, PT_INTERP, and
-      // PT_DYNAMIC.  We also need to finalize the dynamic symbol
-      // table and create the dynamic hash table.
-      abort();
+      // 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,
+      // the dynamic relocations, and the version sections.
+      this->create_dynamic_symtab(size, symtab);
+
+      // Create the .dynamic section to hold the dynamic data, and put
+      // it in a PT_DYNAMIC segment.
+      this->create_dynamic_section();
+
+      // Create the .interp section to hold the name of the
+      // interpreter, and put it in a PT_INTERP segment.
+      this->create_interp(input_objects->target());
     }
 
   // FIXME: Handle PT_GNU_STACK.
@@ -369,14 +386,14 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
   Output_segment* load_seg = this->find_first_load_seg();
 
   // Lay out the segment headers.
-  int size = input_objects->target()->get_size();
   bool big_endian = input_objects->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);
-  // FIXME: Attach them to PT_PHDRS if necessary.
+  if (phdr_seg != NULL)
+    phdr_seg->add_initial_output_data(segment_headers);
 
   // Lay out the file header.
   Output_file_header* file_header;
@@ -736,6 +753,49 @@ Layout::create_shdrs(int size, bool big_endian, off_t* poff)
   return oshdrs;
 }
 
+// Create the dynamic symbol table.
+
+void
+Layout::create_dynamic_symtab(int, Symbol_table*)
+{
+  abort();
+}
+
+// Create the .dynamic section and PT_DYNAMIC segment.
+
+void
+Layout::create_dynamic_section()
+{
+  abort();
+}
+
+// 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();
+      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);
+}
+
 // The mapping of .gnu.linkonce section names to real section names.
 
 #define MAPPING_INIT(f, t) { f, sizeof(f) - 1, t, sizeof(t) - 1 }
index fa34617a3bed84819cb3bc535a45334c0389ec7f..759fd85f840476735df986596a1680e4424d4a92 100644 (file)
@@ -154,15 +154,6 @@ class Layout
   Output_segment*
   find_first_load_seg();
 
-  // 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 indices of all the
-  // sections not associated with a segment.
-  off_t
-  set_section_offsets(off_t, unsigned int *pshndx);
-
   // Create the output sections for the symbol table.
   void
   create_symtab_sections(int size, const Input_objects*, Symbol_table*, off_t*,
@@ -177,6 +168,18 @@ class Layout
   Output_section_headers*
   create_shdrs(int size, bool big_endian, off_t*);
 
+  // Create the dynamic symbol table.
+  void
+  create_dynamic_symtab(int size, Symbol_table*);
+
+  // Create the .dynamic section and PT_DYNAMIC segment.
+  void
+  create_dynamic_section();
+
+  // Create the .interp section and PT_INTERP segment.
+  void
+  create_interp(const Target* target);
+
   // Return whether to include this section in the link.
   template<int size, bool big_endian>
   bool
@@ -204,6 +207,15 @@ class Layout
   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 indices 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);
index 677c731fb745b070254bbc968d382fc85abd7469..1bfd9698e06f3c98827bef16ce3048522b3299d1 100644 (file)
@@ -19,6 +19,22 @@ 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
@@ -45,6 +61,58 @@ Object::section_contents(unsigned int shndx, off_t* plen)
   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>
@@ -55,8 +123,7 @@ Sized_relobj<size, big_endian>::Sized_relobj(
     const elfcpp::Ehdr<size, big_endian>& ehdr)
   : Relobj(name, input_file, offset),
     elf_file_(this, ehdr),
-    section_headers_(NULL),
-    symtab_shndx_(0),
+    symtab_shndx_(-1U),
     local_symbol_count_(0),
     output_local_symbol_count_(0),
     symbols_(NULL),
@@ -78,43 +145,41 @@ void
 Sized_relobj<size, big_endian>::setup(
     const elfcpp::Ehdr<size, big_endian>& ehdr)
 {
-  int machine = ehdr.get_e_machine();
-  Target* target = select_target(machine, size, big_endian,
-                                ehdr.get_e_ident()[elfcpp::EI_OSABI],
-                                ehdr.get_e_ident()[elfcpp::EI_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->set_target(target);
+  this->set_target(ehdr.get_e_machine(), size, big_endian,
+                  ehdr.get_e_ident()[elfcpp::EI_OSABI],
+                  ehdr.get_e_ident()[elfcpp::EI_ABIVERSION]);
 
-  unsigned int shnum = this->elf_file_.shnum();
+  const unsigned int shnum = this->elf_file_.shnum();
   this->set_shnum(shnum);
-  if (shnum == 0)
-    return;
-
-  // We store the section headers in a File_view until do_read_symbols.
-  off_t shoff = this->elf_file_.shoff();
-  this->section_headers_ = this->get_lasting_view(shoff,
-                                                 shnum * This::shdr_size);
+}
 
-  // Find the SHT_SYMTAB section.  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.
-  const unsigned char* p = this->section_headers_->data();
+// 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.
 
-  // Skip the first section, which is always empty.
-  p += This::shdr_size;
-  for (unsigned int i = 1; i < shnum; ++i, p += This::shdr_size)
+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)
     {
-      typename This::Shdr shdr(p);
-      if (shdr.get_sh_type() == elfcpp::SHT_SYMTAB)
+      // 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)
        {
-         this->symtab_shndx_ = i;
-         break;
+         --i;
+         p -= This::shdr_size;
+         typename This::Shdr shdr(p);
+         if (shdr.get_sh_type() == elfcpp::SHT_SYMTAB)
+           {
+             this->symtab_shndx_ = i;
+             break;
+           }
        }
     }
 }
@@ -125,19 +190,11 @@ template<int size, bool big_endian>
 void
 Sized_relobj<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
 {
-  // Transfer our view of the section headers to SD.
-  sd->section_headers = this->section_headers_;
-  this->section_headers_ = NULL;
+  this->read_section_data(&this->elf_file_, sd);
 
-  // Read the section names.
-  const unsigned char* pshdrs = sd->section_headers->data();
-  const unsigned char* pshdrnames = (pshdrs
-                                    + (this->elf_file_.shstrndx()
-                                       * This::shdr_size));
-  typename This::Shdr shdrnames(pshdrnames);
-  sd->section_names_size = shdrnames.get_sh_size();
-  sd->section_names = this->get_lasting_view(shdrnames.get_sh_offset(),
-                                            sd->section_names_size);
+  const unsigned char* const pshdrs = sd->section_headers->data();
+
+  this->find_symtab(pshdrs);
 
   if (this->symtab_shndx_ == 0)
     {
@@ -166,15 +223,14 @@ Sized_relobj<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
   File_view* fvsymtab = this->get_lasting_view(extoff, extsize);
 
   // Read the section header for the symbol names.
-  unsigned int shnum = this->shnum();
-  unsigned int strtab_shnum = symtabshdr.get_sh_link();
-  if (strtab_shnum == 0 || strtab_shnum >= shnum)
+  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_shnum);
+             program_name, this->name().c_str(), strtab_shndx);
       gold_exit(false);
     }
-  typename This::Shdr strtabshdr(pshdrs + strtab_shnum * This::shdr_size);
+  typename This::Shdr strtabshdr(pshdrs + strtab_shndx * This::shdr_size);
   if (strtabshdr.get_sh_type() != elfcpp::SHT_STRTAB)
     {
       fprintf(stderr,
@@ -336,7 +392,7 @@ Sized_relobj<size, big_endian>::do_layout(const General_options& options,
                                          Layout* layout,
                                          Read_symbols_data* sd)
 {
-  unsigned int shnum = this->shnum();
+  const unsigned int shnum = this->shnum();
   if (shnum == 0)
     return;
 
@@ -353,9 +409,6 @@ Sized_relobj<size, big_endian>::do_layout(const General_options& options,
   // Keep track of which sections to omit.
   std::vector<bool> omit(shnum, false);
 
-  const char warn_prefix[] = ".gnu.warning.";
-  const int warn_prefix_len = sizeof warn_prefix - 1;
-
   // Skip the first, dummy, section.
   pshdrs += This::shdr_size;
   for (unsigned int i = 1; i < shnum; ++i, pshdrs += This::shdr_size)
@@ -373,9 +426,8 @@ Sized_relobj<size, big_endian>::do_layout(const General_options& options,
 
       const char* name = pnames + shdr.get_sh_name();
 
-      if (strncmp(name, warn_prefix, warn_prefix_len) == 0)
+      if (this->handle_gnu_warning_section(name, i, symtab))
        {
-         symtab->add_warning(name + warn_prefix_len, this, i);
          if (!options.is_relocatable())
            omit[i] = true;
        }
@@ -442,10 +494,8 @@ Sized_relobj<size, big_endian>::do_add_symbols(Symbol_table* symtab,
 
   const char* sym_names =
     reinterpret_cast<const char*>(sd->symbol_names->data());
-  symtab->add_from_object<size, big_endian>(this, sd->symbols->data(),
-                                           symcount, sym_names, 
-                                           sd->symbol_names_size,
-                                           this->symbols_);
+  symtab->add_from_relobj(this, sd->symbols->data(), symcount, sym_names, 
+                         sd->symbol_names_size, this->symbols_);
 
   delete sd->symbols;
   sd->symbols = NULL;
@@ -464,6 +514,7 @@ off_t
 Sized_relobj<size, big_endian>::do_finalize_local_symbols(off_t off,
                                                          Stringpool* pool)
 {
+  assert(this->symtab_shndx_ != -1U);
   if (this->symtab_shndx_ == 0)
     {
       // This object has no symbols.  Weird but legal.
@@ -577,6 +628,7 @@ void
 Sized_relobj<size, big_endian>::write_local_symbols(Output_file* of,
                                                    const Stringpool* sympool)
 {
+  assert(this->symtab_shndx_ != -1U);
   if (this->symtab_shndx_ == 0)
     {
       // This object has no symbols.  Weird but legal.
@@ -711,13 +763,6 @@ 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 && et != elfcpp::ET_DYN)
-    {
-      fprintf(stderr, "%s: %s: unsupported ELF type %d\n",
-             program_name, name.c_str(), static_cast<int>(et));
-      gold_exit(false);
-    }
-
   if (et == elfcpp::ET_REL)
     {
       Sized_relobj<size, big_endian>* obj =
@@ -725,17 +770,18 @@ make_elf_sized_object(const std::string& name, Input_file* input_file,
       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
     {
-      // elfcpp::ET_DYN
-      fprintf(stderr, _("%s: %s: dynamic objects are not yet supported\n"),
-             program_name, name.c_str());
+      fprintf(stderr, _("%s: %s: unsupported ELF file type %d\n"),
+             program_name, name.c_str(), et);
       gold_exit(false);
-//       Sized_dynobj<size, big_endian>* obj =
-//     new Sized_dynobj<size, big_endian>(this->input_.name(), input_file,
-//                                        offset, ehdr);
-//       obj->setup(ehdr);
-//       return obj;
     }
 }
 
index 54f0350016e0716fbbd98538d053e7e3ffbf5780..63613569493bea42cda021830def731026f86756 100644 (file)
@@ -40,6 +40,19 @@ struct Read_symbols_data
   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
@@ -84,7 +97,7 @@ class Object
   // 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),
+    : name_(name), input_file_(input_file), offset_(offset), shnum_(-1U),
       is_dynamic_(is_dynamic), target_(NULL)
   { }
 
@@ -256,8 +269,33 @@ class Object
 
   // Set the target.
   void
-  set_target(Target* target)
-  { this->target_ = target; }
+  set_target(int machine, int size, bool big_endian, int osabi,
+            int abiversion);
+
+  // Get the number of sections.
+  unsigned int
+  shnum() const
+  { return this->shnum_; }
+
+  // Set the number of sections.
+  void
+  set_shnum(int shnum)
+  { 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.
@@ -271,6 +309,8 @@ class Object
   // 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.
@@ -377,24 +417,12 @@ class Relobj : public Object
   do_relocate(const General_options& options, const Symbol_table* symtab,
              const Layout*, Output_file* of) = 0;
 
-  // Get the number of sections.
-  unsigned int
-  shnum() const
-  { return this->shnum_; }
-
-  // Set the number of sections.
-  void
-  set_shnum(int shnum)
-  { this->shnum_ = shnum; }
-
   // Return the vector mapping input sections to output sections.
   std::vector<Map_to_output>&
   map_to_output()
   { return this->map_to_output_; }
 
  private:
-  // Number of input sections.
-  unsigned int shnum_;
   // Mapping from input sections to output section.
   std::vector<Map_to_output> map_to_output_;
 };
@@ -428,6 +456,11 @@ class Sized_relobj : public Relobj
   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*);
@@ -441,11 +474,6 @@ class Sized_relobj : public Relobj
   do_scan_relocs(const General_options&, Symbol_table*, Layout*,
                 Read_relocs_data*);
 
-  // Lay out the input sections.
-  void
-  do_layout(const General_options&, Symbol_table*, Layout*,
-           Read_symbols_data*);
-
   // Finalize the local symbols.
   off_t
   do_finalize_local_symbols(off_t, Stringpool*);
@@ -461,7 +489,7 @@ class Sized_relobj : public Relobj
   { return this->elf_file_.section_name(shndx); }
 
   // Return the location of the contents of a section.
-  Location
+  Object::Location
   do_section_contents(unsigned int shndx)
   { return this->elf_file_.section_contents(shndx); }
 
@@ -482,6 +510,10 @@ class Sized_relobj : public Relobj
   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,
@@ -520,8 +552,6 @@ class Sized_relobj : public Relobj
 
   // General access to the ELF file.
   elfcpp::Elf_file<size, big_endian, Object> elf_file_;
-  // If non-NULL, a view of the section header data.
-  File_view* section_headers_;
   // Index of SHT_SYMTAB section.
   unsigned int symtab_shndx_;
   // The number of local symbols.
index 2fea87da39a16b75e95db80f8baa8cadafe82fa6..6b88429a882e066ec13916784c9cfb7cb6578271 100644 (file)
@@ -231,6 +231,9 @@ options::Command_line_options::options[] =
          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),
@@ -245,6 +248,12 @@ options::Command_line_options::options[] =
                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)
 };
@@ -255,7 +264,8 @@ const int options::Command_line_options::options_size =
 // The default values for the general options.
 
 General_options::General_options()
-  : search_path_(),
+  : dynamic_linker_(NULL),
+    search_path_(),
     output_file_name_("a.out"),
     is_relocatable_(false),
     is_shared_(false),
@@ -270,10 +280,47 @@ Position_dependent_options::Position_dependent_options()
 {
 }
 
+// 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
+    {
+      assert(!this->input_argument_list_.empty());
+      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()
+{
+  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()
+{
+  assert(this->in_group_);
+  this->in_group_ = false;
+}
+
 // Command_line options.
 
 Command_line::Command_line()
-  : options_(), position_options_(), inputs_(), in_group_(false)
+  : options_(), position_options_(), inputs_()
 {
 }
 
@@ -409,7 +456,7 @@ Command_line::process(int argc, char** argv)
        }
     }
 
-  if (this->in_group_)
+  if (this->inputs_.in_group())
     {
       fprintf(stderr, _("%s: missing group end"), program_name);
       this->usage();
@@ -452,14 +499,7 @@ void
 Command_line::add_file(const char* name, bool is_lib)
 {
   Input_file_argument file(name, is_lib, this->position_options_);
-  if (!this->in_group_)
-    this->inputs_.push_back(Input_argument(file));
-  else
-    {
-      assert(!this->inputs_.empty());
-      assert(this->inputs_.back().is_group());
-      this->inputs_.back().group()->add_file(file);
-    }
+  this->inputs_.add_file(file);
 }
 
 // Handle the -l option, which requires special treatment.
@@ -492,14 +532,9 @@ Command_line::process_l_option(int argc, char** argv, char* arg)
 void
 Command_line::start_group(const char* arg)
 {
-  if (this->in_group_)
+  if (this->inputs_.in_group())
     this->usage(_("may not nest groups"), arg);
-
-  // This object is leaked.
-  Input_file_group* group = new Input_file_group();
-  this->inputs_.push_back(Input_argument(group));
-
-  this->in_group_ = true;
+  this->inputs_.start_group();
 }
 
 // Handle the --end-group option.
@@ -507,9 +542,9 @@ Command_line::start_group(const char* arg)
 void
 Command_line::end_group(const char* arg)
 {
-  if (!this->in_group_)
+  if (!this->inputs_.in_group())
     this->usage(_("group end without group start"), arg);
-  this->in_group_ = false;
+  this->inputs_.end_group();
 }
 
 // Report a usage error.  */
index 27db787edc2ceffb8284dce62a48f866a4e570be..ac515246236fe2cb86d76ff4e844b8671d3eab7b 100644 (file)
@@ -38,6 +38,11 @@ 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;
 
@@ -66,9 +71,17 @@ class General_options
   { 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); }
@@ -93,15 +106,12 @@ class General_options
   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_;
-
-  // Don't copy this structure.
-  General_options(const General_options&);
-  General_options& operator=(const General_options&);
 };
 
 // The current state of the position dependent options.
@@ -112,14 +122,16 @@ class Position_dependent_options
   Position_dependent_options();
 
   // -Bstatic: Whether we are searching for a static archive rather
-  // -than a shared object.
+  // than a shared object.
   bool
-  do_static_search()
+  do_static_search() const
   { return this->do_static_search_; }
 
- private:
-  friend class Command_line;
-  friend class options::Command_line_options;
+  // --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()
@@ -129,7 +141,17 @@ class Position_dependent_options
   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.
@@ -138,7 +160,7 @@ class Input_file_argument
 {
  public:
   Input_file_argument()
-    : name_(NULL), is_lib_(false), options_()
+    : name_(), is_lib_(false), options_()
   { }
 
   Input_file_argument(const char* name, bool is_lib,
@@ -148,7 +170,7 @@ class Input_file_argument
 
   const char*
   name() const
-  { return this->name_; }
+  { return this->name_.c_str(); }
 
   const Position_dependent_options&
   options() const
@@ -159,7 +181,10 @@ class Input_file_argument
   { return this->is_lib_; }
 
  private:
-  const char* name_;
+  // 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_;
 };
@@ -250,12 +275,60 @@ class Input_file_group
   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 std::vector<Input_argument> Input_arguments;
   typedef Input_arguments::const_iterator const_iterator;
 
   Command_line();
@@ -315,7 +388,6 @@ class Command_line
   General_options options_;
   Position_dependent_options position_options_;
   Input_arguments inputs_;
-  bool in_group_;
 };
 
 } // End namespace gold.
index 40d58668c0771258bcc5d1c438eee03545b3a00c..aba8ee170596670a664c2521fd823540da7e9454 100644 (file)
@@ -48,14 +48,6 @@ Output_data::default_alignment(int size)
     abort();
 }
 
-// Output_data_const methods.
-
-void
-Output_data_const::do_write(Output_file* output)
-{
-  output->write(this->offset(), data_.data(), data_.size());
-}
-
 // Output_section_header methods.  This currently assumes that the
 // segment and section lists are complete at construction time.
 
@@ -357,13 +349,30 @@ Output_file_header::do_sized_write(Output_file* of)
   of->write_output_view(0, ehdr_size, view);
 }
 
-// Output_section_got::Got_entry methods.
+// Output_data_const methods.
+
+void
+Output_data_const::do_write(Output_file* output)
+{
+  output->write(this->offset(), data_.data(), data_.size());
+}
+
+// Output_section_data methods.
+
+unsigned int
+Output_section_data::do_out_shndx() const
+{
+  assert(this->output_section_ != NULL);
+  return this->output_section_->out_shndx();
+}
+
+// Output_data_got::Got_entry methods.
 
 // Write out the entry.
 
 template<int size, bool big_endian>
 void
-Output_section_got<size, big_endian>::Got_entry::write(unsigned char* pov)
+Output_data_got<size, big_endian>::Got_entry::write(unsigned char* pov)
     const
 {
   Valtype val = 0;
@@ -402,22 +411,30 @@ Output_section_got<size, big_endian>::Got_entry::write(unsigned char* pov)
   elfcpp::Swap<size, big_endian>::writeval(povv, val);
 }
 
-// Output_section_data methods.
+// Output_data_got methods.
 
-unsigned int
-Output_section_data::do_out_shndx() const
+// 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)
 {
-  assert(this->output_section_ != NULL);
-  return this->output_section_->out_shndx();
-}
+  if (gsym->has_got_offset())
+    return false;
 
-// Output_section_got methods.
+  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_section_got<size, big_endian>::do_write(Output_file* of)
+Output_data_got<size, big_endian>::do_write(Output_file* of)
 {
   const int add = size / 8;
 
@@ -655,7 +672,8 @@ Output_segment::Output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags)
 
 void
 Output_segment::add_output_section(Output_section* os,
-                                  elfcpp::Elf_Word seg_flags)
+                                  elfcpp::Elf_Word seg_flags,
+                                  bool front)
 {
   assert((os->flags() & elfcpp::SHF_ALLOC) != 0);
   assert(!this->is_align_known_);
@@ -690,6 +708,7 @@ Output_segment::add_output_section(Output_section* os,
          --p;
          if ((*p)->is_section_type(elfcpp::SHT_NOTE))
            {
+             // We don't worry about the FRONT parameter.
              ++p;
              pdl->insert(p, os);
              return;
@@ -730,6 +749,7 @@ Output_segment::add_output_section(Output_section* os,
 
          if (insert)
            {
+             // We don't worry about the FRONT parameter.
              ++p;
              pdl->insert(p, os);
              return;
@@ -737,11 +757,14 @@ Output_segment::add_output_section(Output_section* os,
        }
       while (p != pdl->begin());
 
-      // There are no TLS sections yet; put this one at the end of the
-      // section list.
+      // There are no TLS sections yet; put this one at the requested
+      // location in the section list.
     }
 
-  pdl->push_back(os);
+  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
@@ -1121,19 +1144,15 @@ Output_section::add_input_section<64, true>(
     const elfcpp::Shdr<64, true>& shdr);
 
 template
-void
-Output_section_got<32, false>::do_write(Output_file* of);
+class Output_data_got<32, false>;
 
 template
-void
-Output_section_got<32, true>::do_write(Output_file* of);
+class Output_data_got<32, true>;
 
 template
-void
-Output_section_got<64, false>::do_write(Output_file* of);
+class Output_data_got<64, false>;
 
 template
-void
-Output_section_got<64, true>::do_write(Output_file* of);
+class Output_data_got<64, true>;
 
 } // End namespace gold.
index dc1653a987ccf9a46a252252c65799ccb49beae2..9763d7490189a7508523787b67e368a04370147c 100644 (file)
@@ -160,34 +160,6 @@ class Output_data
   off_t offset_;
 };
 
-// A simple case of Output_data in which we have constant data to
-// output.
-
-class Output_data_const : public Output_data
-{
- public:
-  Output_data_const(const std::string& data, uint64_t addralign)
-    : Output_data(data.size()), data_(data), addralign_(addralign)
-  { }
-
-  Output_data_const(const char* p, off_t len, uint64_t addralign)
-    : Output_data(len), data_(p, len), addralign_(addralign)
-  { }
-
-  // Write the data to the file.
-  void
-  do_write(Output_file* output);
-
-  // Return the required alignment.
-  uint64_t
-  do_addralign() const
-  { return this->addralign_; }
-
- private:
-  std::string data_;
-  uint64_t addralign_;
-};
-
 // Output the section headers.
 
 class Output_section_headers : public Output_data
@@ -340,13 +312,40 @@ class Output_section_data : public Output_data
   uint64_t addralign_;
 };
 
-// Output_section_common is used to handle the common symbols.  This
-// is quite simple.
+// A simple case of Output_data in which we have constant data to
+// output.
 
-class Output_section_common : public Output_section_data
+class Output_data_const : public Output_section_data
 {
  public:
-  Output_section_common(uint64_t addralign)
+  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)
+  { }
+
+  // Write the data to the file.
+  void
+  do_write(Output_file* output);
+
+ private:
+  std::string data_;
+};
+
+// Output_data_common is used to handle the common symbols.  This is
+// quite simple.
+
+class Output_data_common : public Output_section_data
+{
+ public:
+  Output_data_common(uint64_t addralign)
     : Output_section_data(addralign)
   { }
 
@@ -362,32 +361,26 @@ class Output_section_common : public Output_section_data
   { }
 };
 
-// Output_section_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
+// 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.  The GOT code is then responsible for writing out the data
-// and for generating relocs as required.
+// needed.
 
 template<int size, bool big_endian>
-class Output_section_got : public Output_section_data
+class Output_data_got : public Output_section_data
 {
  public:
   typedef typename elfcpp::Elf_types<size>::Elf_Addr Valtype;
 
-  Output_section_got()
+  Output_data_got()
     : Output_section_data(Output_data::default_alignment(size)),
       entries_()
   { }
 
-  // Add an entry for a global symbol to the GOT.  This returns the
-  // offset of the new entry from the start of the GOT.
-  unsigned int
-  add_global(Symbol* gsym)
-  {
-    this->entries_.push_back(Got_entry(gsym));
-    this->set_got_size();
-    return this->last_got_offset();
-  }
+  // 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.
@@ -789,7 +782,13 @@ class Output_segment
 
   // Add an Output_section to this segment.
   void
-  add_output_section(Output_section*, elfcpp::Elf_Word seg_flags);
+  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.
@@ -832,6 +831,11 @@ class 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*);
index 5d4a4a092ba178c1d55cc9be2b9f79cc5516f26b..d13ddf5ab027ea265f8107f431e4d982c3c23ced 100644 (file)
@@ -6,6 +6,8 @@ defstd.cc
 defstd.h
 dirsearch.cc
 dirsearch.h
+dynobj.cc
+dynobj.h
 fileread.cc
 fileread.h
 gold.cc
@@ -26,6 +28,8 @@ readsyms.h
 reloc.cc
 reloc.h
 resolve.cc
+script.cc
+script.h
 stringpool.cc
 stringpool.h
 symtab.cc
index a6c2aa2172d549826db8ce91053de242c70a8c53..c002c5c3411be05a3f04bdbbdedb41a183acb296 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2006-11-07 10:50-0800\n"
+"POT-Creation-Date: 2006-11-14 11:17-0800\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"
@@ -61,6 +61,101 @@ msgstr ""
 msgid "can not read directory %s"
 msgstr ""
 
+#: dynobj.cc:97
+#, c-format
+msgid "%s: %s: unexpected duplicate type %u section: %u, %u\n"
+msgstr ""
+
+#: dynobj.cc:138
+#, c-format
+msgid "%s: %s: unexpected link in section %u header: %u != %u\n"
+msgstr ""
+
+#: dynobj.cc:176
+#, c-format
+msgid "%s: %s: DYNAMIC section %u link out of range: %u\n"
+msgstr ""
+
+#: dynobj.cc:186
+#, c-format
+msgid "%s: %s: DYNAMIC section %u link %u is not a strtab\n"
+msgstr ""
+
+#: dynobj.cc:208
+#, c-format
+msgid "%s: %s: DT_SONAME value out of range: %lld >= %lld\n"
+msgstr ""
+
+#: dynobj.cc:225
+#, c-format
+msgid "%s: %s: missing DT_NULL in dynamic segment\n"
+msgstr ""
+
+#: dynobj.cc:273
+#, c-format
+msgid "%s: %s: invalid dynamic symbol table name index: %u\n"
+msgstr ""
+
+#: dynobj.cc:281
+#, c-format
+msgid "%s: %s: dynamic symbol table name section has wrong type: %u\n"
+msgstr ""
+
+#: dynobj.cc:356 object.cc:421
+#, c-format
+msgid "%s: %s: bad section name offset for section %u: %lu\n"
+msgstr ""
+
+#: dynobj.cc:386
+#, c-format
+msgid "%s: %s: duplicate definition for version %u\n"
+msgstr ""
+
+#: dynobj.cc:430 dynobj.cc:549
+#, c-format
+msgid "%s: %s: verdef vd_next field out of range: %u\n"
+msgstr ""
+
+#: dynobj.cc:454
+#, c-format
+msgid "%s: %s: verneed vn_aux field out of range: %u\n"
+msgstr ""
+
+#: dynobj.cc:473
+#, c-format
+msgid "%s: %s: verneed vna_next field out of range: %u\n"
+msgstr ""
+
+#: dynobj.cc:486
+#, c-format
+msgid "%s: %s: verneed vn_next field out of range: %u\n"
+msgstr ""
+
+#: dynobj.cc:516
+#, c-format
+msgid "%s: %s: verdef vd_cnt field too small: %u\n"
+msgstr ""
+
+#: dynobj.cc:525
+#, c-format
+msgid "%s: %s: verdef vd_aux field out of range: %u\n"
+msgstr ""
+
+#: dynobj.cc:537
+#, c-format
+msgid "%s: %s: verdaux vda_name field out of range: %u\n"
+msgstr ""
+
+#: dynobj.cc:579
+#, c-format
+msgid "%s: %s: vernaux vna_name field out of range: %u\n"
+msgstr ""
+
+#: dynobj.cc:615
+#, c-format
+msgid "%s: %s: size of dynamic symbols is not multiple of symbol size\n"
+msgstr ""
+
 #: fileread.cc:56
 #, c-format
 msgid "%s: warning: close(%s) failed: %s"
@@ -145,148 +240,147 @@ msgstr ""
 msgid "%s: missing expected TLS relocation\n"
 msgstr ""
 
-#: i386.cc:306 i386.cc:434 i386.cc:627
+#: i386.cc:307 i386.cc:430 i386.cc:623
 #, c-format
 msgid "%s: %s: unexpected reloc %u in object file\n"
 msgstr ""
 
-#: i386.cc:339 i386.cc:358
+#: i386.cc:340 i386.cc:359
 #, c-format
 msgid "%s: %s: unsupported reloc %u against local symbol\n"
 msgstr ""
 
-#: i386.cc:415 i386.cc:469 i386.cc:487
+#: i386.cc:411 i386.cc:465 i386.cc:483
 #, c-format
 msgid "%s: %s: unsupported reloc %u against global symbol %s\n"
 msgstr ""
 
-#: i386.cc:509
+#: i386.cc:505
 #, c-format
 msgid "%s: %s: unsupported RELA reloc section\n"
 msgstr ""
 
-#: i386.cc:548
+#: i386.cc:544
 #, c-format
 msgid "%s: %s: missing expected TLS relocation\n"
 msgstr ""
 
-#: i386.cc:594 i386.cc:659 i386.cc:732 i386.cc:743
+#: i386.cc:590 i386.cc:655 i386.cc:728 i386.cc:739
 #, c-format
 msgid "%s: %s: unsupported reloc %u\n"
 msgstr ""
 
-#: i386.cc:686
+#: i386.cc:682
 #, c-format
 msgid "%s: %s: TLS reloc but no TLS segment\n"
 msgstr ""
 
-#: i386.cc:717
+#: i386.cc:713
 #, c-format
 msgid "%s: %s: unsupported reloc type %u\n"
 msgstr ""
 
-#: i386.cc:926
+#: i386.cc:922
 #, c-format
 msgid "%s: %s: TLS relocation out of range\n"
 msgstr ""
 
-#: i386.cc:944
+#: i386.cc:940
 #, c-format
 msgid "%s: %s: TLS relocation against invalid instruction\n"
 msgstr ""
 
-#: object.cc:87
+#: object.cc:31
 #, c-format
 msgid "%s: %s: unsupported ELF machine number %d\n"
 msgstr ""
 
-#: object.cc:173
+#: object.cc:87
+#, c-format
+msgid "%s: %s: section name section has wrong type: %u\n"
+msgstr ""
+
+#: object.cc:229
 #, c-format
 msgid "%s: %s: invalid symbol table name index: %u\n"
 msgstr ""
 
-#: object.cc:181
+#: object.cc:237
 #, c-format
 msgid "%s: %s: symbol table name section has wrong type: %u\n"
 msgstr ""
 
-#: object.cc:237
+#: object.cc:293
 #, c-format
 msgid "%s: %s: section group %u info %u out of range\n"
 msgstr ""
 
-#: object.cc:254
+#: object.cc:310
 #, c-format
 msgid "%s: %s: symbol %u name offset %u out of range\n"
 msgstr ""
 
-#: object.cc:288
+#: object.cc:344
 #, c-format
 msgid "%s: %s: section %u in section group %u out of range"
 msgstr ""
 
-#: object.cc:368
-#, c-format
-msgid "%s: %s: bad section name offset for section %u: %lu\n"
-msgstr ""
-
-#: object.cc:436
+#: object.cc:488
 #, c-format
 msgid "%s: %s: size of symbols is not multiple of symbol size\n"
 msgstr ""
 
-#: object.cc:521
+#: object.cc:572
 #, c-format
 msgid "%s: %s: unknown section index %u for local symbol %u\n"
 msgstr ""
 
-#: object.cc:532
+#: object.cc:583
 #, c-format
 msgid "%s: %s: local symbol %u section index %u out of range\n"
 msgstr ""
 
-#: object.cc:554
+#: object.cc:605
 #, c-format
 msgid "%s: %s: local symbol %u section name out of range: %u >= %u\n"
 msgstr ""
 
-#. elfcpp::ET_DYN
-#: object.cc:731
+#: object.cc:782
 #, c-format
-msgid "%s: %s: dynamic objects are not yet supported\n"
+msgid "%s: %s: unsupported ELF file type %d\n"
 msgstr ""
 
-#: object.cc:755 object.cc:808 object.cc:829
+#: object.cc:801 object.cc:854 object.cc:875
 #, c-format
 msgid "%s: %s: ELF file too short\n"
 msgstr ""
 
-#: object.cc:764
+#: object.cc:810
 #, c-format
 msgid "%s: %s: invalid ELF version 0\n"
 msgstr ""
 
-#: object.cc:767
+#: object.cc:813
 #, c-format
 msgid "%s: %s: unsupported ELF version %d\n"
 msgstr ""
 
-#: object.cc:775
+#: object.cc:821
 #, c-format
 msgid "%s: %s: invalid ELF class 0\n"
 msgstr ""
 
-#: object.cc:782
+#: object.cc:828
 #, c-format
 msgid "%s: %s: unsupported ELF class %d\n"
 msgstr ""
 
-#: object.cc:790
+#: object.cc:836
 #, c-format
 msgid "%s: %s: invalid ELF data encoding\n"
 msgstr ""
 
-#: object.cc:797
+#: object.cc:843
 #, c-format
 msgid "%s: %s: unsupported ELF data encoding %d\n"
 msgstr ""
@@ -315,139 +409,160 @@ msgid "End a library search group"
 msgstr ""
 
 #: options.cc:234
-msgid "Add directory to search path"
+msgid "Set dynamic linker path"
 msgstr ""
 
 #: options.cc:235
-msgid "-L DIR, --library-path DIR"
+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:239
+#: options.cc:242
 msgid "Set output file name"
 msgstr ""
 
-#: options.cc:240
+#: options.cc:243
 msgid "-o FILE, --output FILE"
 msgstr ""
 
-#: options.cc:242
+#: options.cc:245
 msgid "Generate relocatable output"
 msgstr ""
 
-#: options.cc:244
+#: options.cc:247
 msgid "Generate shared library"
 msgstr ""
 
-#: options.cc:246
+#: options.cc:249
 msgid "Do not link against shared libraries"
 msgstr ""
 
-#: options.cc:248
+#: 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:346 options.cc:397 options.cc:483
+#: options.cc:393 options.cc:444 options.cc:523
 msgid "missing argument"
 msgstr ""
 
-#: options.cc:359 options.cc:406
+#: options.cc:406 options.cc:453
 msgid "unknown option"
 msgstr ""
 
-#: options.cc:414
+#: options.cc:461
 #, c-format
 msgid "%s: missing group end"
 msgstr ""
 
-#: options.cc:496
+#: options.cc:536
 msgid "may not nest groups"
 msgstr ""
 
-#: options.cc:511
+#: options.cc:546
 msgid "group end without group start"
 msgstr ""
 
-#: options.cc:521
+#: options.cc:556
 #, c-format
 msgid "%s: use the --help option for usage information\n"
 msgstr ""
 
-#: options.cc:530
+#: options.cc:565 script.cc:1128
 #, c-format
 msgid "%s: %s: %s\n"
 msgstr ""
 
-#: options.cc:539
+#: options.cc:574
 #, c-format
 msgid "%s: -%c: %s\n"
 msgstr ""
 
-#: output.cc:521
+#: output.cc:538
 #, c-format
 msgid "%s: %s: invalid alignment %lu for section \"%s\"\n"
 msgstr ""
 
-#: output.cc:1033
+#: output.cc:1056
 #, c-format
 msgid "%s: %s: open: %s\n"
 msgstr ""
 
-#: output.cc:1042
+#: output.cc:1065
 #, c-format
 msgid "%s: %s: lseek: %s\n"
 msgstr ""
 
-#: output.cc:1049
+#: output.cc:1072
 #, c-format
 msgid "%s: %s: write: %s\n"
 msgstr ""
 
-#: output.cc:1059
+#: output.cc:1082
 #, c-format
 msgid "%s: %s: mmap: %s\n"
 msgstr ""
 
-#: output.cc:1073
+#: output.cc:1096
 #, c-format
 msgid "%s: %s: munmap: %s\n"
 msgstr ""
 
-#: output.cc:1081
+#: output.cc:1104
 #, c-format
 msgid "%s: %s: close: %s\n"
 msgstr ""
 
-#: readsyms.cc:85
+#: 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:129
+#: readsyms.cc:149
 #, c-format
 msgid "%s: %s: not an object or archive\n"
 msgstr ""
 
-#: reloc.cc:168 reloc.cc:408
+#: reloc.cc:168 reloc.cc:409
 #, c-format
 msgid "%s: %s: relocation section %u has bad info %u\n"
 msgstr ""
 
-#: reloc.cc:187 reloc.cc:425
+#: reloc.cc:187 reloc.cc:426
 #, c-format
 msgid "%s: %s: relocation section %u uses unexpected symbol table %u\n"
 msgstr ""
 
-#: reloc.cc:203 reloc.cc:444
+#: reloc.cc:203 reloc.cc:445
 #, c-format
 msgid "%s: %s: unexpected entsize for reloc section %u: %lu != %u"
 msgstr ""
 
-#: reloc.cc:214 reloc.cc:455
+#: reloc.cc:214 reloc.cc:456
 #, c-format
 msgid "%s: %s: reloc section %u size %lu uneven"
 msgstr ""
@@ -462,22 +577,42 @@ msgstr ""
 msgid "%s: %s: unsupported symbol binding %d for symbol %s\n"
 msgstr ""
 
-#: symtab.cc:441
+#: symtab.cc:443 symtab.cc:540
 #, c-format
 msgid "%s: %s: mixing 32-bit and 64-bit ELF objects\n"
 msgstr ""
 
-#: symtab.cc:458
+#: symtab.cc:460
 #, c-format
 msgid "%s: %s: bad global symbol name offset %u at %lu\n"
 msgstr ""
 
-#: symtab.cc:883 symtab.cc:1022
+#: symtab.cc:547
+#, c-format
+msgid "%s: %s: too few symbol versions\n"
+msgstr ""
+
+#: symtab.cc:567
+#, c-format
+msgid "%s: %s: bad symbol name offset %u at %lu\n"
+msgstr ""
+
+#: symtab.cc:611
+#, c-format
+msgid "%s: %s: versym for symbol %zu out of range: %u\n"
+msgstr ""
+
+#: symtab.cc:619
+#, c-format
+msgid "%s: %s: versym for symbol %zu has no name: %u\n"
+msgstr ""
+
+#: symtab.cc:1010 symtab.cc:1149
 #, c-format
 msgid "%s: %s: unsupported symbol section 0x%x\n"
 msgstr ""
 
-#: symtab.cc:1135
+#: symtab.cc:1262
 #, c-format
 msgid "%s: %s: warning: %s\n"
 msgstr ""
index c120fcb7ccdaa8fe257a4d2bb5b723f1c747ce30..c301d16040c0791ede6b9a86c9f8007d5e59a5dc 100644 (file)
@@ -10,6 +10,7 @@
 #include "symtab.h"
 #include "object.h"
 #include "archive.h"
+#include "script.h"
 #include "readsyms.h"
 
 namespace gold
@@ -30,8 +31,8 @@ Read_symbols::~Read_symbols()
 Task::Is_runnable_type
 Read_symbols::is_runnable(Workqueue*)
 {
-  if (this->input_.is_file()
-      && this->input_.file().is_lib()
+  if (this->input_argument_->is_file()
+      && this->input_argument_->file().is_lib()
       && this->dirpath_.token().is_blocked())
     return IS_BLOCKED;
 
@@ -53,14 +54,14 @@ Read_symbols::locks(Workqueue*)
 void
 Read_symbols::run(Workqueue* workqueue)
 {
-  if (this->input_.is_group())
+  if (this->input_argument_->is_group())
     {
       assert(this->input_group_ == NULL);
       this->do_group(workqueue);
       return;
     }
 
-  Input_file* input_file = new Input_file(this->input_.file());
+  Input_file* input_file = new Input_file(this->input_argument_->file());
   input_file->open(this->options_, this->dirpath_);
 
   // Read enough of the file to pick up the entire ELF header.
@@ -79,7 +80,14 @@ Read_symbols::run(Workqueue* workqueue)
        {
          // This is an ELF object.
 
-         if (this->input_group_ != NULL)
+         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"),
@@ -87,9 +95,6 @@ Read_symbols::run(Workqueue* workqueue)
              gold_exit(false);
            }
 
-         Object* obj = make_elf_object(this->input_.file().name(),
-                                       input_file, 0, p, bytes);
-
          Read_symbols_data* sd = new Read_symbols_data;
          obj->read_symbols(sd);
          workqueue->queue_front(new Add_symbols(this->options_,
@@ -111,7 +116,8 @@ Read_symbols::run(Workqueue* workqueue)
       if (memcmp(p, Archive::armag, Archive::sarmag) == 0)
        {
          // This is an archive.
-         Archive* arch = new Archive(this->input_.file().name(), input_file);
+         Archive* arch = new Archive(this->input_argument_->file().name(),
+                                     input_file);
          arch->setup();
          workqueue->queue(new Add_archive_symbols(this->options_,
                                                   this->symtab_,
@@ -125,6 +131,20 @@ Read_symbols::run(Workqueue* workqueue)
        }
     }
 
+  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());
@@ -143,14 +163,14 @@ Read_symbols::do_group(Workqueue* workqueue)
 {
   Input_group* input_group = new Input_group();
 
-  const Input_file_group* group = this->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);
-      assert(arg.is_file());
+      const Input_argument* arg = &*p;
+      assert(arg->is_file());
 
       Task_token* next_blocker = new Task_token();
       next_blocker->add_blocker();
index 6631011eb4033c64473e1d4f9352eea1494f0771..d5ada61d25ed834aff40428f1ab2f2de14e12648 100644 (file)
@@ -36,10 +36,10 @@ class Read_symbols : public Task
   // symbols.
   Read_symbols(const General_options& options, Input_objects* input_objects,
               Symbol_table* symtab, Layout* layout, const Dirsearch& dirpath,
-              const Input_argument& input, Input_group* input_group,
+              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_(input),
+      layout_(layout), dirpath_(dirpath), input_argument_(input_argument),
       input_group_(input_group), this_blocker_(this_blocker),
       next_blocker_(next_blocker)
   { }
@@ -67,7 +67,7 @@ class Read_symbols : public Task
   Symbol_table* symtab_;
   Layout* layout_;
   const Dirsearch& dirpath_;
-  const Input_argument& input_;
+  const Input_argument* input_argument_;
   Input_group* input_group_;
   Task_token* this_blocker_;
   Task_token* next_blocker_;
index bc38904094aea9b25cc05942b80e8a430fb8e6ad..dd3eef12fee623e9b6e96d4c63e8e9017ebf6523 100644 (file)
@@ -227,6 +227,7 @@ Sized_relobj<size, big_endian>::do_read_relocs(Read_relocs_data* rd)
     }
 
   // Read the local symbols.
+  assert(this->symtab_shndx_ != -1U);
   if (this->symtab_shndx_ == 0 || this->local_symbol_count_ == 0)
     rd->local_symbols = NULL;
   else
diff --git a/gold/script-c.h b/gold/script-c.h
new file mode 100644 (file)
index 0000000..e404889
--- /dev/null
@@ -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 (file)
index 0000000..b22611f
--- /dev/null
@@ -0,0 +1,1188 @@
+// script.cc -- handle linker scripts for gold.
+
+#include "gold.h"
+
+#include <string>
+#include <vector>
+#include <cassert>
+#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)
+  { 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)
+  { 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
+  {
+    assert(this->classification_ == TOKEN_STRING);
+    return this->value_;
+  }
+
+  int
+  operator_value() const
+  {
+    assert(this->classification_ == TOKEN_OPERATOR);
+    return this->opcode_;
+  }
+
+  int64_t
+  integer_value() const
+  {
+    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:
+      abort();
+
+    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 (file)
index 0000000..de2e5af
--- /dev/null
@@ -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)
index ac14c0121a385a0354e3154651a033d0854fc28a..9279d265672c2623cd9755bd5852dfd698606038 100644 (file)
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "object.h"
+#include "dynobj.h"
 #include "output.h"
 #include "target.h"
 #include "workqueue.h"
@@ -194,6 +195,7 @@ Symbol_table::Symbol_table_eq::operator()(const Symbol_table_key& k1,
 void
 Symbol_table::make_forwarder(Symbol* from, Symbol* to)
 {
+  assert(from != to);
   assert(!from->is_forwarder() && !to->is_forwarder());
   this->forwarders_[from] = to;
   from->set_forwarder();
@@ -334,7 +336,7 @@ Symbol_table::add_from_object(Object* object,
              // NAME/NULL point to NAME/VERSION.
              insdef.first->second = ret;
            }
-         else
+         else if (insdef.first->second != ret)
            {
              // This is the unfortunate case where we already have
              // entries for both NAME/VERSION and NAME/NULL.
@@ -424,8 +426,8 @@ Symbol_table::add_from_object(Object* object,
 
 template<int size, bool big_endian>
 void
-Symbol_table::add_from_object(
-    Relobj* object,
+Symbol_table::add_from_relobj(
+    Sized_relobj<size, big_endian>* relobj,
     const unsigned char* syms,
     size_t count,
     const char* sym_names,
@@ -436,10 +438,10 @@ Symbol_table::add_from_object(
   if (this->get_size() == 0)
     this->set_size(size);
 
-  if (size != this->get_size() || size != object->target()->get_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, object->name().c_str());
+             program_name, relobj->name().c_str());
       gold_exit(false);
     }
 
@@ -456,11 +458,13 @@ Symbol_table::add_from_object(
        {
          fprintf(stderr,
                  _("%s: %s: bad global symbol name offset %u at %lu\n"),
-                 program_name, object->name().c_str(), st_name,
+                 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];
@@ -468,7 +472,7 @@ Symbol_table::add_from_object(
       unsigned int st_shndx = psym->get_st_shndx();
       if (st_shndx != elfcpp::SHN_UNDEF
          && st_shndx < elfcpp::SHN_LORESERVE
-         && !object->is_section_included(st_shndx))
+         && !relobj->is_section_included(st_shndx))
        {
          memcpy(symbuf, p, sym_size);
          elfcpp::Sym_write<size, big_endian> sw(symbuf);
@@ -476,8 +480,6 @@ Symbol_table::add_from_object(
          psym = &sym2;
        }
 
-      const char* name = sym_names + st_name;
-
       // 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.
@@ -488,7 +490,7 @@ Symbol_table::add_from_object(
        {
          Stringpool::Key name_key;
          name = this->namepool_.add(name, &name_key);
-         res = this->add_from_object(object, name, name_key, NULL, 0,
+         res = this->add_from_object(relobj, name, name_key, NULL, 0,
                                      false, *psym);
        }
       else
@@ -507,7 +509,7 @@ Symbol_table::add_from_object(
          Stringpool::Key ver_key;
          ver = this->namepool_.add(ver, &ver_key);
 
-         res = this->add_from_object(object, name, name_key, ver, ver_key,
+         res = this->add_from_object(relobj, name, name_key, ver, ver_key,
                                      def, *psym);
        }
 
@@ -515,6 +517,131 @@ Symbol_table::add_from_object(
     }
 }
 
+// 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.
 
@@ -1142,8 +1269,8 @@ Warnings::issue_warning(Symbol* sym, const std::string& location) const
 
 template
 void
-Symbol_table::add_from_object<32, true>(
-    Relobj* object,
+Symbol_table::add_from_relobj<32, true>(
+    Sized_relobj<32, true>* relobj,
     const unsigned char* syms,
     size_t count,
     const char* sym_names,
@@ -1152,8 +1279,8 @@ Symbol_table::add_from_object<32, true>(
 
 template
 void
-Symbol_table::add_from_object<32, false>(
-    Relobj* object,
+Symbol_table::add_from_relobj<32, false>(
+    Sized_relobj<32, false>* relobj,
     const unsigned char* syms,
     size_t count,
     const char* sym_names,
@@ -1162,8 +1289,8 @@ Symbol_table::add_from_object<32, false>(
 
 template
 void
-Symbol_table::add_from_object<64, true>(
-    Relobj* object,
+Symbol_table::add_from_relobj<64, true>(
+    Sized_relobj<64, true>* relobj,
     const unsigned char* syms,
     size_t count,
     const char* sym_names,
@@ -1172,12 +1299,60 @@ Symbol_table::add_from_object<64, true>(
 
 template
 void
-Symbol_table::add_from_object<64, false>(
-    Relobj* object,
+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.
index 65898990c876339b0fb9f1649a741cb34371e06a..e97260024989f948d27d9a64a11793695e667dd3 100644 (file)
@@ -20,7 +20,11 @@ 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 Output_data;
 class Output_segment;
 class Output_file;
@@ -592,16 +596,29 @@ class Symbol_table
 
   ~Symbol_table();
 
-  // Add COUNT external symbols from the relocatable object OBJECT to
+  // 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_object(Relobj* object, const unsigned char* syms,
-                 size_t count, const char* sym_names, size_t sym_name_size,
+  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.
   template<int size, bool big_endian>
   Sized_symbol<size>*
index 8e00a4da5ab8472b2a68412a4cf82d99714daef7..5a86c357dad9e558eaa4ef7ce0548c31996593dd 100644 (file)
@@ -65,6 +65,11 @@ class Target
   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
@@ -96,6 +101,8 @@ class Target
     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.
diff --git a/gold/yyscript.y b/gold/yyscript.y
new file mode 100644 (file)
index 0000000..0bd2b60
--- /dev/null
@@ -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 */
+       ;
+
+%%