]> rtime.felk.cvut.cz Git - fpga/lx-cpu1/binutils-tumbl.git/commitdiff
Another snapshot of the current state of the sources. Gets to the
authorIan Lance Taylor <iant@google.com>
Fri, 18 Aug 2006 22:29:20 +0000 (22:29 +0000)
committerIan Lance Taylor <iant@google.com>
Fri, 18 Aug 2006 22:29:20 +0000 (22:29 +0000)
point of symbol resolution and can now issue a multiple definition
error.  Also added target selection infrastructure.

20 files changed:
elfcpp/elfcpp.h
gold/Makefile.am
gold/Makefile.in
gold/gold.cc
gold/i386.cc [new file with mode: 0644]
gold/object.cc
gold/object.h
gold/po/POTFILES.in
gold/po/gold.pot
gold/readsyms.cc
gold/readsyms.h
gold/resolve.cc [new file with mode: 0644]
gold/stringpool.cc [new file with mode: 0644]
gold/stringpool.h [new file with mode: 0644]
gold/strtab.h [new file with mode: 0644]
gold/symtab.cc [new file with mode: 0644]
gold/symtab.h
gold/target-select.cc [new file with mode: 0644]
gold/target-select.h [new file with mode: 0644]
gold/target.h

index 14027fad05af907a1a0c08c857fd471394a345dd..9af0b8d4de437669ee2361e02791fe4e92e94228 100644 (file)
@@ -396,6 +396,25 @@ enum STT
   STT_HIPROC = 15
 };
 
+inline STB
+elf_st_bind(unsigned char info)
+{
+  return static_cast<STB>(info >> 4);
+}
+
+inline STT
+elf_st_type(unsigned char info)
+{
+  return static_cast<STT>(info & 0xf);
+}
+
+inline unsigned char
+elf_st_info(STB bind, STT type)
+{
+  return ((static_cast<unsigned char>(bind) << 4)
+         + (static_cast<unsigned char>(type) & 0xf));
+}
+
 // Symbol visibility from Sym st_other field.
 
 enum STV
@@ -406,6 +425,18 @@ enum STV
   STV_PROTECTED = 3
 };
 
+inline STV
+elf_st_visibility(unsigned char other)
+{
+  return static_cast<STV>(other & 0x3);
+}
+
+inline unsigned char
+elf_st_nonvis(unsigned char other)
+{
+  return static_cast<STV>(other >> 2);
+}
+
 } // End namespace elfcpp.
 
 // Include internal details after defining the types.
@@ -576,16 +607,32 @@ class Sym
 
   typename Elf_types<size>::Elf_WXword
   get_st_size() const
-  { return internal::convert_wxword<big_endian>(this->p_->st_size); }
+  { return internal::convert_wxword<size, big_endian>(this->p_->st_size); }
 
   unsigned char
   get_st_info() const
   { return this->p_->st_info; }
 
+  STB
+  get_st_bind() const
+  { return elf_st_bind(this->get_st_info()); }
+
+  STT
+  get_st_type() const
+  { return elf_st_type(this->get_st_info()); }
+
   unsigned char
   get_st_other() const
   { return this->p_->st_other; }
 
+  STV
+  get_st_visibility() const
+  { return elf_st_visibility(this->get_st_other()); }
+
+  unsigned char
+  get_st_nonvis() const
+  { return elf_st_nonvis(this->get_st_other()); }
+
   Elf_Half
   get_st_shndx() const
   { return internal::convert_half<big_endian>(this->p_->st_shndx); }
index acff0a449e51104b4853f4f8b766caa7589c61f2..a01aef4aab138a5a413b43d71cab2edb764d4c80 100644 (file)
@@ -17,7 +17,7 @@ INCLUDES = -D_GNU_SOURCE \
 
 noinst_PROGRAMS = ld-new
 
-CFILES = \
+CCFILES = \
        dirsearch.cc \
        fileread.cc \
        gold.cc \
@@ -25,6 +25,10 @@ CFILES = \
        object.cc \
        options.cc \
        readsyms.cc \
+       resolve.cc \
+       symtab.cc \
+       stringpool.cc \
+       target-select.cc \
        workqueue.cc
 
 HFILES = \
@@ -35,20 +39,25 @@ HFILES = \
        object.h \
        options.h \
        readsyms.h \
+       stringpool.h \
        symtab.h \
        target.h \
        targetsize.h \
+       target-select.h \
        workqueue.h
 
+TARGETFILES = \
+       i386.cc
+
 OFILES = gold.o options.o
 
-POTFILES= $(CFILES) $(HFILES)
+POTFILES= $(CCFILES) $(HFILES) $(TARGETFILES)
 
 po/POTFILES.in: @MAINT@ Makefile
        for f in $(POTFILES); do echo $$f; done | LC_COLLATE= sort > tmp \
          && mv tmp $(srcdir)/po/POTFILES.in
 
-ld_new_SOURCES = $(CFILES) $(HFILES)
+ld_new_SOURCES = $(CCFILES) $(HFILES) $(TARGETFILES)
 ld_new_DEPENDENCIES = $(LIBINTL_DEP)
 ld_new_LDADD = $(LIBINTL)
 
index 31a01c463bc8069992a2bb02636297303be372e3..8881517e77bdcb0c1a0894706cfe598918403078 100644 (file)
@@ -67,9 +67,12 @@ CONFIG_CLEAN_FILES = po/Makefile.in
 PROGRAMS = $(noinst_PROGRAMS)
 am__objects_1 = dirsearch.$(OBJEXT) fileread.$(OBJEXT) gold.$(OBJEXT) \
        gold-threads.$(OBJEXT) object.$(OBJEXT) options.$(OBJEXT) \
-       readsyms.$(OBJEXT) workqueue.$(OBJEXT)
+       readsyms.$(OBJEXT) resolve.$(OBJEXT) symtab.$(OBJEXT) \
+       stringpool.$(OBJEXT) target-select.$(OBJEXT) \
+       workqueue.$(OBJEXT)
 am__objects_2 =
-am_ld_new_OBJECTS = $(am__objects_1) $(am__objects_2)
+am__objects_3 = i386.$(OBJEXT)
+am_ld_new_OBJECTS = $(am__objects_1) $(am__objects_2) $(am__objects_3)
 ld_new_OBJECTS = $(am_ld_new_OBJECTS)
 am__DEPENDENCIES_1 =
 DEFAULT_INCLUDES = -I. -I$(srcdir) -I.
@@ -225,7 +228,7 @@ INCLUDES = -D_GNU_SOURCE \
        -DLOCALEDIR="\"$(datadir)/locale\"" \
        @INCINTL@
 
-CFILES = \
+CCFILES = \
        dirsearch.cc \
        fileread.cc \
        gold.cc \
@@ -233,6 +236,10 @@ CFILES = \
        object.cc \
        options.cc \
        readsyms.cc \
+       resolve.cc \
+       symtab.cc \
+       stringpool.cc \
+       target-select.cc \
        workqueue.cc
 
 HFILES = \
@@ -243,14 +250,19 @@ HFILES = \
        object.h \
        options.h \
        readsyms.h \
+       stringpool.h \
        symtab.h \
        target.h \
        targetsize.h \
+       target-select.h \
        workqueue.h
 
+TARGETFILES = \
+       i386.cc
+
 OFILES = gold.o options.o
-POTFILES = $(CFILES) $(HFILES)
-ld_new_SOURCES = $(CFILES) $(HFILES)
+POTFILES = $(CCFILES) $(HFILES) $(TARGETFILES)
+ld_new_SOURCES = $(CCFILES) $(HFILES) $(TARGETFILES)
 ld_new_DEPENDENCIES = $(LIBINTL_DEP)
 ld_new_LDADD = $(LIBINTL)
 all: config.h
@@ -327,9 +339,14 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fileread.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gold-threads.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gold.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/i386.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/object.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/options.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/readsyms.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resolve.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@
 
 .cc.o:
index fd349ddbdce72956bc84c8ccf4eef5e86b9b126c..e419f9cb5efa6e468b480f0248f48510fe4f86ef 100644 (file)
@@ -11,6 +11,7 @@
 #include "workqueue.h"
 #include "dirsearch.h"
 #include "readsyms.h"
+#include "symtab.h"
 
 namespace gold
 {
@@ -65,7 +66,7 @@ void
 queue_initial_tasks(const General_options& options,
                    const Dirsearch& search_path,
                    const Command_line::Input_argument_list& inputs,
-                   Workqueue* workqueue)
+                   Workqueue* workqueue, Symbol_table* symtab)
 {
   if (inputs.empty())
     gold_fatal(_("no input files"), false);
@@ -81,8 +82,8 @@ queue_initial_tasks(const General_options& options,
     {
       Task_token* next_blocker = new Task_token();
       next_blocker->add_blocker();
-      workqueue->queue(new Read_symbols(options, search_path, *p, this_blocker,
-                                       next_blocker));
+      workqueue->queue(new Read_symbols(options, symtab, search_path,
+                                       *p, this_blocker, next_blocker));
       this_blocker = next_blocker;
     }
 
@@ -113,6 +114,7 @@ main(int argc, char** argv)
   gold::Workqueue workqueue(command_line.options());
 
   // The symbol table.
+  Symbol_table symtab;
 
   // Get the search path from the -L options.
   Dirsearch search_path;
@@ -120,7 +122,7 @@ main(int argc, char** argv)
 
   // Queue up the first set of tasks.
   queue_initial_tasks(command_line.options(), search_path,
-                     command_line.inputs(), &workqueue);
+                     command_line.inputs(), &workqueue, &symtab);
 
   // Run the main task processing loop.
   workqueue.process();
diff --git a/gold/i386.cc b/gold/i386.cc
new file mode 100644 (file)
index 0000000..5ecd2e3
--- /dev/null
@@ -0,0 +1,47 @@
+// i386.cc -- i386 target support for gold.
+
+#include "gold.h"
+#include "elfcpp.h"
+#include "target.h"
+#include "target-select.h"
+
+namespace
+{
+
+using namespace gold;
+
+// The i386 target class.
+
+class Target_i386 : public Sized_target<32, false>
+{
+ public:
+  Target_i386()
+    : Sized_target<32, false>(false, false)
+  { }
+};
+
+// The selector for i386 object files.
+
+class Target_selector_i386 : public Target_selector
+{
+public:
+  Target_selector_i386()
+    : Target_selector(elfcpp::EM_386, 32, false)
+  { }
+
+  Target*
+  recognize(int machine, int osabi, int abiversion) const;
+};
+
+// Recognize an i386 object file when we already know that the machine
+// number is EM_386.
+
+Target*
+Target_selector_i386::recognize(int, int, int) const
+{
+  return new Target_i386();
+}
+
+Target_selector_i386 target_selector_i386;
+
+} // End anonymous namespace.
index 8835915fdc6a4b8b5104ad06f78e98eecd9f34e1..bad7f478467ecadd9166ab89ca0eaeb3e724c70c 100644 (file)
@@ -7,6 +7,7 @@
 #include <cassert>
 
 #include "object.h"
+#include "target-select.h"
 
 namespace gold
 {
@@ -40,16 +41,16 @@ Sized_object<size, big_endian>::Sized_object(
     Input_file* input_file,
     off_t offset,
     const elfcpp::Ehdr<size, big_endian>& ehdr)
-  : Object(name, input_file, offset),
+  : Object(name, input_file, false, offset),
     osabi_(ehdr.get_e_ident()[elfcpp::EI_OSABI]),
     abiversion_(ehdr.get_e_ident()[elfcpp::EI_ABIVERSION]),
     machine_(ehdr.get_e_machine()),
     flags_(ehdr.get_e_flags()),
-    target_(NULL),
     shoff_(ehdr.get_e_shoff()),
     shnum_(0),
     shstrndx_(0),
-    symtab_shnum_(0)
+    symtab_shnum_(0),
+    symbols_(NULL)
 {
   if (ehdr.get_e_ehsize() != elfcpp::Elf_sizes<size>::ehdr_size)
     {
@@ -80,8 +81,15 @@ void
 Sized_object<size, big_endian>::setup(
     const elfcpp::Ehdr<size, big_endian>& ehdr)
 {
-  //  this->target_ = select_target(this->machine_, size, big_endian,
-  //                           this->osabi_, this->abiversion_);
+  Target* target = select_target(this->machine_, size, big_endian,
+                                this->osabi_, this->abiversion_);
+  if (target == NULL)
+    {
+      fprintf(stderr, _("%s: %s: unsupported ELF machine number %d\n"),
+             program_name, this->name().c_str(), this->machine_);
+      gold_exit(false);
+    }
+  this->set_target(target);
   unsigned int shnum = ehdr.get_e_shnum();
   unsigned int shstrndx = ehdr.get_e_shstrndx();
   if ((shnum == 0 || shstrndx == elfcpp::SHN_XINDEX)
@@ -143,9 +151,14 @@ Sized_object<size, big_endian>::do_read_symbols()
   elfcpp::Shdr<size, big_endian> symtabshdr(psymtabshdr);
   assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
 
+  // We only need the external symbols.
+  int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+  off_t locsize = symtabshdr.get_sh_info() * sym_size;
+  off_t extoff = symtabshdr.get_sh_offset() + locsize;
+  off_t extsize = symtabshdr.get_sh_size() - locsize;
+
   // Read the symbol table.
-  File_view* fvsymtab = this->get_lasting_view(symtabshdr.get_sh_offset(),
-                                              symtabshdr.get_sh_size());
+  File_view* fvsymtab = this->get_lasting_view(extoff, extsize);
 
   // Read the section header for the symbol names.
   unsigned int strtab_shnum = symtabshdr.get_sh_link();
@@ -173,7 +186,7 @@ Sized_object<size, big_endian>::do_read_symbols()
 
   Read_symbols_data ret;
   ret.symbols = fvsymtab;
-  ret.symbols_size = symtabshdr.get_sh_size();
+  ret.symbols_size = extsize;
   ret.symbol_names = fvstrtab;
   ret.symbol_names_size = strtabshdr.get_sh_size();
 
@@ -184,7 +197,8 @@ Sized_object<size, big_endian>::do_read_symbols()
 
 template<int size, bool big_endian>
 void
-Sized_object<size, big_endian>::do_add_symbols(Read_symbols_data sd)
+Sized_object<size, big_endian>::do_add_symbols(Symbol_table* symtab,
+                                              Read_symbols_data sd)
 {
   if (sd.symbols == NULL)
     {
@@ -192,25 +206,24 @@ Sized_object<size, big_endian>::do_add_symbols(Read_symbols_data sd)
       return;
     }
 
-  int sym_size = elfcpp::Elf_sizes<size>::sym_size;
-  const unsigned char* symstart = sd.symbols->data();
-  const unsigned char* symend = symstart + sd.symbols_size;
-  for (const unsigned char* p = symstart; p < symend; p += sym_size)
+  unsigned int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+  size_t symcount = sd.symbols_size / sym_size;
+  if (symcount * sym_size != sd.symbols_size)
     {
-      elfcpp::Sym<size, big_endian> sym(p);
-
-      unsigned int nameoff = sym.get_st_name();
-      if (nameoff >= sd.symbol_names_size)
-       {
-         fprintf(stderr,
-                 _("%s: %s: invalid symbol name offset %u for symbol %d\n"),
-                 program_name, this->name().c_str(), nameoff,
-                 (p - symstart) / sym_size);
-         gold_exit(false);
-       }
-      const unsigned char* name = sd.symbol_names->data() + nameoff;
-      printf("%s\n", name);
+      fprintf(stderr,
+             _("%s: %s: size of symbols is not multiple of symbol size\n"),
+             program_name, this->name().c_str());
+      gold_exit(false);
     }
+
+  this->symbols_ = new Symbol*[symcount];
+
+  const elfcpp::Sym<size, big_endian>* syms =
+    reinterpret_cast<const elfcpp::Sym<size, big_endian>*>(sd.symbols->data());
+  const char* sym_names =
+    reinterpret_cast<const char*>(sd.symbol_names->data());
+  symtab->add_from_object(this, syms, symcount, sym_names, 
+                         sd.symbol_names_size,  this->symbols_);
 }
 
 } // End namespace gold.
index 9d63b117848c1f074fd61109dbd9c39593f05797..b0ee015d754290027542e757d4fc422afd7b0f22 100644 (file)
@@ -3,10 +3,12 @@
 #ifndef GOLD_OBJECT_H
 #define GOLD_OBJECT_H
 
+#include <cassert>
+
 #include "elfcpp.h"
-#include "targetsize.h"
-#include "target.h"
 #include "fileread.h"
+#include "target.h"
+#include "symtab.h"
 
 namespace gold
 {
@@ -26,8 +28,9 @@ struct Read_symbols_data
 };
 
 // Object is an interface which represents either a 32-bit or a 64-bit
-// object file.  The actual instantiations are Sized_object<32> and
-// Sized_object<64>
+// input object.  This can be a regular object file (ET_REL) or a
+// shared object (ET_DYN).  The actual instantiations are
+// Sized_object<32> and Sized_object<64>
 
 class Object
 {
@@ -36,17 +39,25 @@ class Object
   // (e.g., libfoo.a(bar.o) if this is in an archive.  INPUT_FILE is
   // used to read the file.  OFFSET is the offset within the input
   // file--0 for a .o or .so file, something else for a .a file.
-  Object(const std::string& name, Input_file* input_file, off_t offset = 0)
-    : name_(name), input_file_(input_file), offset_(offset)
+  Object(const std::string& name, Input_file* input_file, bool is_dynamic,
+        off_t offset = 0)
+    : name_(name), input_file_(input_file), offset_(offset),
+      is_dynamic_(is_dynamic), target_(NULL)
   { }
 
   virtual ~Object()
   { }
 
+  // Return the name of the object as we would report it to the tuser.
   const std::string&
   name() const
   { return this->name_; }
 
+  // Return whether this is a dynamic object.
+  bool
+  is_dynamic() const
+  { return this->is_dynamic_; }
+
   // Read the symbol and relocation information.
   Read_symbols_data
   read_symbols()
@@ -54,8 +65,20 @@ class Object
 
   // Add symbol information to the global symbol table.
   void
-  add_symbols(Read_symbols_data rd)
-  { this->do_add_symbols(rd); }
+  add_symbols(Symbol_table* symtab, Read_symbols_data rd)
+  { this->do_add_symbols(symtab, rd); }
+
+  // Return the target structure associated with this object.
+  Target*
+  target()
+  { return this->target_; }
+
+  // Return the sized target structure associated with this object.
+  // This is like the target method but it returns a pointer of
+  // appropriate checked type.
+  template<int size, bool big_endian>
+  Sized_target<size, big_endian>*
+  sized_target();
 
  protected:
   // Read the symbols--implemented by child class.
@@ -65,7 +88,7 @@ class Object
   // Add symbol information to the global symbol table--implemented by
   // child class.
   virtual void
-  do_add_symbols(Read_symbols_data) = 0;
+  do_add_symbols(Symbol_table*, Read_symbols_data) = 0;
 
   // Get the file.
   Input_file*
@@ -81,6 +104,11 @@ class Object
   const unsigned char*
   get_view(off_t start, off_t size);
 
+  // Set the target.
+  void
+  set_target(Target* target)
+  { this->target_ = target; }
+
   // Read data from the underlying file.
   void
   read(off_t start, off_t size, void* p);
@@ -101,9 +129,25 @@ class Object
   // Offset within the file--0 for an object file, non-0 for an
   // archive.
   off_t offset_;
+  // Whether this is a dynamic object.
+  bool is_dynamic_;
+  // Target functions--may be NULL if the target is not known.
+  Target* target_;
 };
 
-// The functions of Object which are size specific.
+// Implement sized_target inline for efficiency.  This approach breaks
+// static type checking, but is made safe using asserts.
+
+template<int size, bool big_endian>
+inline Sized_target<size, big_endian>*
+Object::sized_target()
+{
+  assert(this->target_->get_size() == size);
+  assert(this->target_->is_big_endian() ? big_endian : !big_endian);
+  return static_cast<Sized_target<size, big_endian>*>(this->target_);
+}
+
+// A regular object file.  This is size and endian specific.
 
 template<int size, bool big_endian>
 class Sized_object : public Object
@@ -121,7 +165,11 @@ class Sized_object : public Object
   do_read_symbols();
 
   void
-  do_add_symbols(Read_symbols_data);
+  do_add_symbols(Symbol_table*, Read_symbols_data);
+
+  Sized_target<size, big_endian>*
+  sized_target()
+  { return this->Object::sized_target<size, big_endian>(); }
 
  private:
   // This object may not be copied.
@@ -136,8 +184,6 @@ class Sized_object : public Object
   elfcpp::Elf_Half machine_;
   // ELF file header e_flags field.
   unsigned int flags_;
-  // Target functions--may be NULL.
-  Target* target_;
   // File offset of section header table.
   off_t shoff_;
   // Number of input sections.
@@ -146,6 +192,8 @@ class Sized_object : public Object
   unsigned int shstrndx_;
   // Index of SHT_SYMTAB section.
   unsigned int symtab_shnum_;
+  // The entries in the symbol table for the external symbols.
+  Symbol** symbols_;
 };
 
 // Return an Object appropriate for the input file.  P is BYTES long,
index e0cca00e1fff3dfc4644b262b0368d086d7be4ac..35c5094a1a376fd7095b20531e05092bb62a1928 100644 (file)
@@ -6,14 +6,21 @@ gold.cc
 gold.h
 gold-threads.cc
 gold-threads.h
+i386.cc
 object.cc
 object.h
 options.cc
 options.h
 readsyms.cc
 readsyms.h
+resolve.cc
+stringpool.cc
+stringpool.h
+symtab.cc
 symtab.h
 target.h
+target-select.cc
+target-select.h
 targetsize.h
 workqueue.cc
 workqueue.h
index 604b371d8b6063cee7a01738d22369cbfc376f37..35860a5f731630c0912078bc5bce178960a38f00 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2006-08-04 14:23-0700\n"
+"POT-Creation-Date: 2006-08-18 15:26-0700\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -16,7 +16,7 @@ msgstr ""
 "Content-Type: text/plain; charset=CHARSET\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: dirsearch.cc:50
+#: dirsearch.cc:51
 #, c-format
 msgid "can not read directory %s"
 msgstr ""
@@ -51,7 +51,7 @@ msgstr ""
 msgid "%s: cannot open %s: %s"
 msgstr ""
 
-#: gold.cc:71
+#: gold.cc:72
 msgid "no input files"
 msgstr ""
 
@@ -99,68 +99,73 @@ msgstr ""
 msgid "pthread_cond_signal failed"
 msgstr ""
 
-#: object.cc:56
+#: object.cc:57
 #, c-format
 msgid "%s: %s: bad e_ehsize field (%d != %d)\n"
 msgstr ""
 
-#: object.cc:63
+#: object.cc:64
 #, c-format
 msgid "%s: %s: bad e_shentsize field (%d != %d)\n"
 msgstr ""
 
-#: object.cc:154
+#: object.cc:88
+#, c-format
+msgid "%s: %s: unsupported ELF machine number %d\n"
+msgstr ""
+
+#: object.cc:167
 #, c-format
 msgid "%s: %s: invalid symbol table name index: %u\n"
 msgstr ""
 
-#: object.cc:164
+#: object.cc:177
 #, c-format
 msgid "%s: %s: symbol table name section has wrong type: %u\n"
 msgstr ""
 
-#: object.cc:206
+#: object.cc:214
 #, c-format
-msgid "%s: %s: invalid symbol name offset %u for symbol %d\n"
+msgid "%s: %s: size of symbols is not multiple of symbol size\n"
 msgstr ""
 
 #. elfcpp::ET_DYN
-#: object.cc:249
+#: object.cc:262
 #, c-format
 msgid "%s: %s: dynamic objects are not yet supported\n"
 msgstr ""
 
-#: object.cc:273 object.cc:326 object.cc:347
+#: object.cc:286 object.cc:339 object.cc:360
 #, c-format
 msgid "%s: %s: ELF file too short\n"
 msgstr ""
 
-#: object.cc:282
+#: object.cc:295
 #, c-format
 msgid "%s: %s: invalid ELF version 0\n"
 msgstr ""
 
-#: object.cc:285
+#: object.cc:298
 #, c-format
 msgid "%s: %s: unsupported ELF version %d\n"
 msgstr ""
 
-#: object.cc:293
+#: object.cc:306
 #, c-format
 msgid "%s: %s: invalid ELF class 0\n"
 msgstr ""
 
-#: object.cc:300
+#: object.cc:313
 #, c-format
 msgid "%s: %s: unsupported ELF class %d\n"
 msgstr ""
 
-#: object.cc:308
+#: object.cc:321
 #, c-format
 msgid "%s: %s: invalid ELF data encoding\n"
 msgstr ""
 
-#: object.cc:315
+#: object.cc:328
 #, c-format
 msgid "%s: %s: unsupported ELF data encoding %d\n"
 msgstr ""
@@ -214,3 +219,23 @@ msgstr ""
 #, c-format
 msgid "%s: -%c: %s\n"
 msgstr ""
+
+#: resolve.cc:103
+#, c-format
+msgid "%s: %s: invalid STB_LOCAL symbol %s in external symbols\n"
+msgstr ""
+
+#: resolve.cc:109
+#, c-format
+msgid "%s: %s: unsupported symbol binding %d for symbol %s\n"
+msgstr ""
+
+#: symtab.cc:262
+#, c-format
+msgid "%s: %s: mixing 32-bit and 64-bit ELF objects\n"
+msgstr ""
+
+#: symtab.cc:275
+#, c-format
+msgid "%s: %s: bad symbol name offset %u at %lu\n"
+msgstr ""
index 30b341c1b6907f8da0be58cf0d9513c1437f601f..1076e6c17ef74fbf6e261a93eae980c063434b7c 100644 (file)
@@ -73,7 +73,8 @@ Read_symbols::run(Workqueue* workqueue)
                                        p, bytes);
                                        
          Read_symbols_data sd = obj->read_symbols();
-         workqueue->queue(new Add_symbols(obj, sd, this->this_blocker_,
+         workqueue->queue(new Add_symbols(this->symtab_, obj, sd,
+                                          this->this_blocker_,
                                           this->next_blocker_));
 
          // Opening the file locked it, so now we need to unlock it.
@@ -117,7 +118,7 @@ Add_symbols::locks(Workqueue* workqueue)
 void
 Add_symbols::run(Workqueue*)
 {
-  this->object_->add_symbols(this->sd_);
+  this->object_->add_symbols(this->symtab_, this->sd_);
 }
 
 } // End namespace gold.
index bad96c115650413cf7c44bf7d33dcb3c885ce85b..f01cf6108e262b0015fc0acb5fbbb552745800d9 100644 (file)
@@ -26,10 +26,10 @@ class Read_symbols : public Task
   // associated Add_symbols task from running before the previous one
   // has completed; it will be NULL for the first task.  NEXT_BLOCKER
   // is used to block the next input file from adding symbols.
-  Read_symbols(const General_options& options, const Dirsearch& dirpath,
-              const Input_argument& input, Task_token* this_blocker,
-              Task_token* next_blocker)
-    : options_(options), dirpath_(dirpath), input_(input),
+  Read_symbols(const General_options& options, Symbol_table* symtab,
+              const Dirsearch& dirpath, const Input_argument& input,
+              Task_token* this_blocker, Task_token* next_blocker)
+    : options_(options), symtab_(symtab), dirpath_(dirpath), input_(input),
       this_blocker_(this_blocker), next_blocker_(next_blocker)
   { }
 
@@ -48,6 +48,7 @@ class Read_symbols : public Task
 
  private:
   const General_options& options_;
+  Symbol_table* symtab_;
   const Dirsearch& dirpath_;
   const Input_argument& input_;
   Task_token* this_blocker_;
@@ -64,9 +65,9 @@ class Add_symbols : public Task
   // THIS_BLOCKER is used to prevent this task from running before the
   // one for the previous input file.  NEXT_BLOCKER is used to prevent
   // the next task from running.
-  Add_symbols(Object* object, Read_symbols_data sd, Task_token* this_blocker,
-             Task_token* next_blocker)
-    : object_(object), sd_(sd), this_blocker_(this_blocker),
+  Add_symbols(Symbol_table* symtab, Object* object, Read_symbols_data sd,
+             Task_token* this_blocker, Task_token* next_blocker)
+    : symtab_(symtab), object_(object), sd_(sd), this_blocker_(this_blocker),
       next_blocker_(next_blocker)
   { }
 
@@ -84,6 +85,7 @@ class Add_symbols : public Task
   run(Workqueue*);
 
 private:
+  Symbol_table* symtab_;
   Object* object_;
   Read_symbols_data sd_;
   Task_token* this_blocker_;
diff --git a/gold/resolve.cc b/gold/resolve.cc
new file mode 100644 (file)
index 0000000..8c7d828
--- /dev/null
@@ -0,0 +1,349 @@
+// resolve.cc -- symbol resolution for gold
+
+#include "gold.h"
+
+#include "elfcpp.h"
+#include "target.h"
+#include "object.h"
+#include "symtab.h"
+
+namespace gold
+{
+
+// Resolve a symbol.  This is called the second and subsequent times
+// we see a symbol.  TO is the pre-existing symbol.  SYM is the new
+// symbol, seen in OBJECT.
+
+template<int size, bool big_endian>
+void
+Symbol_table::resolve(Symbol* to,
+                     const elfcpp::Sym<size, big_endian>& sym,
+                     Object* object)
+{
+  if (object->target()->has_resolve())
+    {
+      object->sized_target<size, big_endian>()->resolve(to, sym, object);
+      return;
+    }
+
+  // Build a little code for each symbol.
+  // Bit 0: 0 for global, 1 for weak.
+  // Bit 1: 0 for regular object, 1 for shared object
+  // Bits 2-3: 0 for normal, 1 for undefined, 2 for common
+  // This gives us values from 0 to 11:
+
+  enum
+  {
+    DEF = 0,
+    WEAK_DEF = 1,
+    DYN_DEF = 2,
+    DYN_WEAK_DEF = 3,
+    UNDEF = 4,
+    WEAK_UNDEF = 5,
+    DYN_UNDEF = 6,
+    DYN_WEAK_UNDEF = 7,
+    COMMON = 8,
+    WEAK_COMMON = 9,
+    DYN_COMMON = 10,
+    DYN_WEAK_COMMON = 11
+  };
+
+  int tobits;
+  switch (to->binding())
+    {
+    case elfcpp::STB_GLOBAL:
+      tobits = 0;
+      break;
+
+    case elfcpp::STB_WEAK:
+      tobits = 1;
+      break;
+
+    case elfcpp::STB_LOCAL:
+      // We should only see externally visible symbols in the symbol
+      // table.
+      abort();
+
+    default:
+      // Any target which wants to handle STB_LOOS, etc., needs to
+      // define a resolve method.
+      abort();
+    }
+
+  if (to->object() != NULL && to->object()->is_dynamic())
+    tobits |= (1 << 1);
+
+  switch (to->shnum())
+    {
+    case elfcpp::SHN_UNDEF:
+      tobits |= (1 << 2);
+      break;
+
+    case elfcpp::SHN_COMMON:
+      tobits |= (2 << 2);
+      break;
+
+    default:
+      break;
+    }
+
+  int frombits;
+  switch (sym.get_st_bind())
+    {
+    case elfcpp::STB_GLOBAL:
+      frombits = 0;
+      break;
+
+    case elfcpp::STB_WEAK:
+      frombits = 1;
+      break;
+
+    case elfcpp::STB_LOCAL:
+      fprintf(stderr,
+             _("%s: %s: invalid STB_LOCAL symbol %s in external symbols\n"),
+             program_name, object->name().c_str(), to->name());
+      gold_exit(false);
+
+    default:
+      fprintf(stderr,
+             _("%s: %s: unsupported symbol binding %d for symbol %s\n"),
+             program_name, object->name().c_str(),
+             static_cast<int>(sym.get_st_bind()), to->name());
+      gold_exit(false);
+    }
+
+  if (object->is_dynamic())
+    frombits |= (1 << 1);
+
+  switch (sym.get_st_shndx())
+    {
+    case elfcpp::SHN_UNDEF:
+      frombits |= (1 << 2);
+      break;
+
+    case elfcpp::SHN_COMMON:
+      frombits |= (2 << 2);
+      break;
+
+    default:
+      break;
+    }
+
+  // We use a giant switch table for symbol resolution.  This code is
+  // unwieldy, but: 1) it is efficient; 2) we definitely handle all
+  // cases; 3) it is easy to change the handling of a particular case.
+  // The alternative would be a series of conditionals, but it is easy
+  // to get the ordering wrong.  This could also be done as a table,
+  // but that is no easier to understand than this large switch
+  // statement.
+
+  switch (tobits * 16 + frombits)
+    {
+    case DEF * 16 + DEF:
+      // Two definitions of the same symbol.
+      fprintf(stderr, "%s: %s: multiple definition of %s\n",
+             program_name, object->name().c_str(), to->name());
+      // FIXME: Report locations.  Record that we have seen an error.
+      return;
+
+    case WEAK_DEF * 16 + DEF:
+      // In the original SVR4 linker, a weak definition followed by a
+      // regular definition was treated as a multiple definition
+      // error.  In the Solaris linker and the GNU linker, a weak
+      // definition followed by a regular definition causes the
+      // regular definition to be ignored.  We are currently
+      // compatible with the GNU linker.  In the future we should add
+      // a target specific option to change this.  FIXME.
+      return;
+
+    case DYN_DEF * 16 + DEF:
+    case DYN_WEAK_DEF * 16 + DEF:
+    case UNDEF * 16 + DEF:
+    case WEAK_UNDEF * 16 + DEF:
+    case DYN_UNDEF * 16 + DEF:
+    case DYN_WEAK_UNDEF * 16 + DEF:
+    case COMMON * 16 + DEF:
+    case WEAK_COMMON * 16 + DEF:
+    case DYN_COMMON * 16 + DEF:
+    case DYN_WEAK_COMMON * 16 + DEF:
+
+    case DEF * 16 + WEAK_DEF:
+    case WEAK_DEF * 16 + WEAK_DEF:
+    case DYN_DEF * 16 + WEAK_DEF:
+    case DYN_WEAK_DEF * 16 + WEAK_DEF:
+    case UNDEF * 16 + WEAK_DEF:
+    case WEAK_UNDEF * 16 + WEAK_DEF:
+    case DYN_UNDEF * 16 + WEAK_DEF:
+    case DYN_WEAK_UNDEF * 16 + WEAK_DEF:
+    case COMMON * 16 + WEAK_DEF:
+    case WEAK_COMMON * 16 + WEAK_DEF:
+    case DYN_COMMON * 16 + WEAK_DEF:
+    case DYN_WEAK_COMMON * 16 + WEAK_DEF:
+
+    case DEF * 16 + DYN_DEF:
+    case WEAK_DEF * 16 + DYN_DEF:
+    case DYN_DEF * 16 + DYN_DEF:
+    case DYN_WEAK_DEF * 16 + DYN_DEF:
+    case UNDEF * 16 + DYN_DEF:
+    case WEAK_UNDEF * 16 + DYN_DEF:
+    case DYN_UNDEF * 16 + DYN_DEF:
+    case DYN_WEAK_UNDEF * 16 + DYN_DEF:
+    case COMMON * 16 + DYN_DEF:
+    case WEAK_COMMON * 16 + DYN_DEF:
+    case DYN_COMMON * 16 + DYN_DEF:
+    case DYN_WEAK_COMMON * 16 + DYN_DEF:
+
+    case DEF * 16 + DYN_WEAK_DEF:
+    case WEAK_DEF * 16 + DYN_WEAK_DEF:
+    case DYN_DEF * 16 + DYN_WEAK_DEF:
+    case DYN_WEAK_DEF * 16 + DYN_WEAK_DEF:
+    case UNDEF * 16 + DYN_WEAK_DEF:
+    case WEAK_UNDEF * 16 + DYN_WEAK_DEF:
+    case DYN_UNDEF * 16 + DYN_WEAK_DEF:
+    case DYN_WEAK_UNDEF * 16 + DYN_WEAK_DEF:
+    case COMMON * 16 + DYN_WEAK_DEF:
+    case WEAK_COMMON * 16 + DYN_WEAK_DEF:
+    case DYN_COMMON * 16 + DYN_WEAK_DEF:
+    case DYN_WEAK_COMMON * 16 + DYN_WEAK_DEF:
+
+    case DEF * 16 + UNDEF:
+    case WEAK_DEF * 16 + UNDEF:
+    case DYN_DEF * 16 + UNDEF:
+    case DYN_WEAK_DEF * 16 + UNDEF:
+    case UNDEF * 16 + UNDEF:
+    case WEAK_UNDEF * 16 + UNDEF:
+    case DYN_UNDEF * 16 + UNDEF:
+    case DYN_WEAK_UNDEF * 16 + UNDEF:
+    case COMMON * 16 + UNDEF:
+    case WEAK_COMMON * 16 + UNDEF:
+    case DYN_COMMON * 16 + UNDEF:
+    case DYN_WEAK_COMMON * 16 + UNDEF:
+
+    case DEF * 16 + WEAK_UNDEF:
+    case WEAK_DEF * 16 + WEAK_UNDEF:
+    case DYN_DEF * 16 + WEAK_UNDEF:
+    case DYN_WEAK_DEF * 16 + WEAK_UNDEF:
+    case UNDEF * 16 + WEAK_UNDEF:
+    case WEAK_UNDEF * 16 + WEAK_UNDEF:
+    case DYN_UNDEF * 16 + WEAK_UNDEF:
+    case DYN_WEAK_UNDEF * 16 + WEAK_UNDEF:
+    case COMMON * 16 + WEAK_UNDEF:
+    case WEAK_COMMON * 16 + WEAK_UNDEF:
+    case DYN_COMMON * 16 + WEAK_UNDEF:
+    case DYN_WEAK_COMMON * 16 + WEAK_UNDEF:
+
+    case DEF * 16 + DYN_UNDEF:
+    case WEAK_DEF * 16 + DYN_UNDEF:
+    case DYN_DEF * 16 + DYN_UNDEF:
+    case DYN_WEAK_DEF * 16 + DYN_UNDEF:
+    case UNDEF * 16 + DYN_UNDEF:
+    case WEAK_UNDEF * 16 + DYN_UNDEF:
+    case DYN_UNDEF * 16 + DYN_UNDEF:
+    case DYN_WEAK_UNDEF * 16 + DYN_UNDEF:
+    case COMMON * 16 + DYN_UNDEF:
+    case WEAK_COMMON * 16 + DYN_UNDEF:
+    case DYN_COMMON * 16 + DYN_UNDEF:
+    case DYN_WEAK_COMMON * 16 + DYN_UNDEF:
+
+    case DEF * 16 + DYN_WEAK_UNDEF:
+    case WEAK_DEF * 16 + DYN_WEAK_UNDEF:
+    case DYN_DEF * 16 + DYN_WEAK_UNDEF:
+    case DYN_WEAK_DEF * 16 + DYN_WEAK_UNDEF:
+    case UNDEF * 16 + DYN_WEAK_UNDEF:
+    case WEAK_UNDEF * 16 + DYN_WEAK_UNDEF:
+    case DYN_UNDEF * 16 + DYN_WEAK_UNDEF:
+    case DYN_WEAK_UNDEF * 16 + DYN_WEAK_UNDEF:
+    case COMMON * 16 + DYN_WEAK_UNDEF:
+    case WEAK_COMMON * 16 + DYN_WEAK_UNDEF:
+    case DYN_COMMON * 16 + DYN_WEAK_UNDEF:
+    case DYN_WEAK_COMMON * 16 + DYN_WEAK_UNDEF:
+
+    case DEF * 16 + COMMON:
+    case WEAK_DEF * 16 + COMMON:
+    case DYN_DEF * 16 + COMMON:
+    case DYN_WEAK_DEF * 16 + COMMON:
+    case UNDEF * 16 + COMMON:
+    case WEAK_UNDEF * 16 + COMMON:
+    case DYN_UNDEF * 16 + COMMON:
+    case DYN_WEAK_UNDEF * 16 + COMMON:
+    case COMMON * 16 + COMMON:
+    case WEAK_COMMON * 16 + COMMON:
+    case DYN_COMMON * 16 + COMMON:
+    case DYN_WEAK_COMMON * 16 + COMMON:
+
+    case DEF * 16 + WEAK_COMMON:
+    case WEAK_DEF * 16 + WEAK_COMMON:
+    case DYN_DEF * 16 + WEAK_COMMON:
+    case DYN_WEAK_DEF * 16 + WEAK_COMMON:
+    case UNDEF * 16 + WEAK_COMMON:
+    case WEAK_UNDEF * 16 + WEAK_COMMON:
+    case DYN_UNDEF * 16 + WEAK_COMMON:
+    case DYN_WEAK_UNDEF * 16 + WEAK_COMMON:
+    case COMMON * 16 + WEAK_COMMON:
+    case WEAK_COMMON * 16 + WEAK_COMMON:
+    case DYN_COMMON * 16 + WEAK_COMMON:
+    case DYN_WEAK_COMMON * 16 + WEAK_COMMON:
+
+    case DEF * 16 + DYN_COMMON:
+    case WEAK_DEF * 16 + DYN_COMMON:
+    case DYN_DEF * 16 + DYN_COMMON:
+    case DYN_WEAK_DEF * 16 + DYN_COMMON:
+    case UNDEF * 16 + DYN_COMMON:
+    case WEAK_UNDEF * 16 + DYN_COMMON:
+    case DYN_UNDEF * 16 + DYN_COMMON:
+    case DYN_WEAK_UNDEF * 16 + DYN_COMMON:
+    case COMMON * 16 + DYN_COMMON:
+    case WEAK_COMMON * 16 + DYN_COMMON:
+    case DYN_COMMON * 16 + DYN_COMMON:
+    case DYN_WEAK_COMMON * 16 + DYN_COMMON:
+
+    case DEF * 16 + DYN_WEAK_COMMON:
+    case WEAK_DEF * 16 + DYN_WEAK_COMMON:
+    case DYN_DEF * 16 + DYN_WEAK_COMMON:
+    case DYN_WEAK_DEF * 16 + DYN_WEAK_COMMON:
+    case UNDEF * 16 + DYN_WEAK_COMMON:
+    case WEAK_UNDEF * 16 + DYN_WEAK_COMMON:
+    case DYN_UNDEF * 16 + DYN_WEAK_COMMON:
+    case DYN_WEAK_UNDEF * 16 + DYN_WEAK_COMMON:
+    case COMMON * 16 + DYN_WEAK_COMMON:
+    case WEAK_COMMON * 16 + DYN_WEAK_COMMON:
+    case DYN_COMMON * 16 + DYN_WEAK_COMMON:
+    case DYN_WEAK_COMMON * 16 + DYN_WEAK_COMMON:
+
+      break;
+    }
+}
+
+// Instantiate the templates we need.  We could use the configure
+// script to restrict this to only the ones needed for implemented
+// targets.
+
+template
+void
+Symbol_table::resolve<32, true>(
+    Symbol* to,
+    const elfcpp::Sym<32, true>& sym,
+    Object* object);
+
+template
+void
+Symbol_table::resolve<32, false>(
+    Symbol* to,
+    const elfcpp::Sym<32, false>& sym,
+    Object* object);
+
+template
+void
+Symbol_table::resolve<64, true>(
+    Symbol* to,
+    const elfcpp::Sym<64, true>& sym,
+    Object* object);
+
+template
+void
+Symbol_table::resolve<64, false>(
+    Symbol* to,
+    const elfcpp::Sym<64, false>& sym,
+    Object* object);
+
+} // End namespace gold.
diff --git a/gold/stringpool.cc b/gold/stringpool.cc
new file mode 100644 (file)
index 0000000..0368014
--- /dev/null
@@ -0,0 +1,130 @@
+// stringpool.cc -- a string pool for gold
+
+#include "gold.h"
+
+#include <cassert>
+#include <cstring>
+
+#include "stringpool.h"
+
+namespace gold
+{
+
+Stringpool::Stringpool()
+  : string_set_(), strings_()
+{
+}
+
+Stringpool::~Stringpool()
+{
+  for (std::list<stringdata*>::iterator p = this->strings_.begin();
+       p != this->strings_.end();
+       ++p)
+    delete[] reinterpret_cast<char*>(*p);
+}
+
+// Hash function.
+
+size_t
+Stringpool::Stringpool_hash::operator()(const char* s) const
+{
+  // Fowler/Noll/Vo (FNV) hash (type FNV-1a).
+  if (sizeof(size_t) == 8)
+    {
+      size_t result = 14695981039346656037ULL;
+      while (*s != '\0')
+       {
+         result &= (size_t) *s++;
+         result *= 1099511628211ULL;
+       }
+      return result;
+    }
+  else
+    {
+      size_t result = 2166136261UL;
+      while (*s != '\0')
+       {
+         result ^= (size_t) *s++;
+         result *= 16777619UL;
+       }
+      return result;
+    }
+}
+
+// Add a string to the list of canonical strings.  Return a pointer to
+// the canonical string.
+
+const char*
+Stringpool::add_string(const char* s)
+{
+  const size_t buffer_size = 1000;
+  size_t len = strlen(s);
+
+  size_t alc;
+  bool front = true;
+  if (len >= buffer_size)
+    {
+      alc = sizeof(stringdata) + len;
+      front = false;
+    }
+  else if (this->strings_.empty())
+    alc = sizeof(stringdata) + buffer_size;
+  else
+    {
+      stringdata *psd = this->strings_.front();
+      if (len >= psd->alc - psd->len)
+       alc = sizeof(stringdata) + buffer_size;
+      else
+       {
+         char* ret = psd->data + psd->len;
+         memcpy(ret, s, len + 1);
+         psd->len += len + 1;
+         return ret;
+       }
+    }
+
+  stringdata *psd = reinterpret_cast<stringdata*>(new char[alc]);
+  psd->alc = alc;
+  memcpy(psd->data, s, len + 1);
+  psd->len = len + 1;
+  if (front)
+    this->strings_.push_front(psd);
+  else
+    this->strings_.push_back(psd);
+  return psd->data;
+}
+
+// Add a string to a string pool.
+
+const char*
+Stringpool::add(const char* s)
+{
+  // FIXME: This will look up the entry twice in the hash table.  The
+  // problem is that we can't insert S before we canonicalize it.  I
+  // don't think there is a way to handle this correct with
+  // unordered_set, so this should be replaced with custom code to do
+  // what we need, which is to return the empty slot.
+
+  String_set_type::const_iterator p = this->string_set_.find(s);
+  if (p != this->string_set_.end())
+    return *p;
+
+  const char* ret = this->add_string(s);
+  std::pair<String_set_type::iterator, bool> ins =
+    this->string_set_.insert(ret);
+  assert(ins.second);
+  return ret;
+}
+
+// Add a prefix of a string to a string pool.
+
+const char*
+Stringpool::add(const char* s, size_t len)
+{
+  // FIXME: This implementation should be rewritten when we rewrite
+  // the hash table to avoid copying.
+  std::string st(s, len);
+  return this->add(st);
+}
+
+} // End namespace gold.
diff --git a/gold/stringpool.h b/gold/stringpool.h
new file mode 100644 (file)
index 0000000..873c26a
--- /dev/null
@@ -0,0 +1,70 @@
+// stringpool.h -- a string pool for gold    -*- C++ -*-
+
+#include <string>
+#include <list>
+
+// Stringpool
+//   Manage a pool of unique strings.
+
+#ifndef GOLD_STRINGPOOL_H
+#define GOLD_STRINGPOOL_H
+
+namespace gold
+{
+
+class Stringpool
+{
+ public:
+  Stringpool();
+
+  ~Stringpool();
+
+  // Add a string to the pool.  This returns a canonical permanent
+  // pointer to the string.
+  const char* add(const char*);
+
+  const char* add(const std::string& s)
+  { return this->add(s.c_str()); }
+
+  // Add the prefix of a string to the pool.
+  const char* add(const char *, size_t);
+
+ private:
+  Stringpool(const Stringpool&);
+  Stringpool& operator=(const Stringpool&);
+
+  struct stringdata
+  {
+    // Length of data in buffer.
+    size_t len;
+    // Allocated size of buffer.
+    size_t alc;
+    // Buffer.
+    char data[1];
+  };
+
+  const char* add_string(const char*);
+
+  struct Stringpool_hash
+  {
+    size_t
+    operator()(const char*) const;
+  };
+
+  struct Stringpool_eq
+  {
+    bool
+    operator()(const char* p1, const char* p2) const
+    { return strcmp(p1, p2) == 0; }
+  };
+
+  typedef Unordered_set<const char*, Stringpool_hash, Stringpool_eq,
+                       std::allocator<const char*>,
+                       true> String_set_type;
+  String_set_type string_set_;
+  std::list<stringdata*> strings_;
+};
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_STRINGPOOL_H)
diff --git a/gold/strtab.h b/gold/strtab.h
new file mode 100644 (file)
index 0000000..ab22b8f
--- /dev/null
@@ -0,0 +1,73 @@
+// strtab.h -- manage an ELF string table for gold   -*- C++ -*-
+
+#ifndef GOLD_STRTAB_H
+#define GOLD_STRTAB_H
+
+#include <cstring>
+#include <string>
+
+namespace gold
+{
+
+// This class holds an ELF string table.  We keep a reference count
+// for each string, which we use to determine which strings are
+// actually required at the end.  When all operations are done, the
+// string table is finalized, which sets the offsets to use for each
+// string.
+
+class Strtab
+{
+ public:
+  Strtab();
+
+  ~Strtab();
+
+  Strtab_ref* add(const char*);
+
+  Strtab_ref* add(const std::string& s)
+  { return this->add(s.c_str()); }
+
+ private:
+  Strtab(const Strtab&);
+  Strtab& operator=(const Strtab&);
+
+  struct strtab_hash
+  {
+    std::size_t
+    operator()(const char*p);
+  };
+
+  struct strtab_eq
+  {
+    bool
+    operator()(const char* p1, const char* p2)
+    { return strcmp(p1, p2) == 0; }
+  };
+
+  Unordered_map<const char*, Strtab_ref*, strtab_hash, strtab_eq,
+               std::allocator<std::pair<const char* const, Strtab_ref*> >,
+               true> strings_;
+};
+
+// Users of Strtab work with pointers to Strtab_ref structures.  These
+// are allocated via new and should be deleted if the string is no
+// longer needed.
+
+class Strtab_ref
+{
+ public:
+  ~Strtab_ref();
+
+  const char*
+  str() const;
+
+ private:
+  Strtab_ref(const Strtab_ref&);
+  Strtab_ref& operator=(const Strtab_ref&);
+
+  int refs_;
+};
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_STRTAB_H)
diff --git a/gold/symtab.cc b/gold/symtab.cc
new file mode 100644 (file)
index 0000000..a410db3
--- /dev/null
@@ -0,0 +1,358 @@
+// symtab.cc -- the gold symbol table
+
+#include "gold.h"
+
+#include <cassert>
+#include <stdint.h>
+#include <string>
+#include <utility>
+
+#include "object.h"
+#include "symtab.h"
+
+namespace gold
+{
+
+// Class Symbol.
+
+Symbol::~Symbol()
+{
+}
+
+// Initialize the fields in the base class Symbol.
+
+template<int size, bool big_endian>
+void
+Symbol::init_base(const char* name, const char* version, Object* object,
+                 const elfcpp::Sym<size, big_endian>& sym)
+{
+  this->name_ = name;
+  this->version_ = version;
+  this->object_ = object;
+  this->shnum_ = sym.get_st_shndx(); // FIXME: Handle SHN_XINDEX.
+  this->type_ = sym.get_st_type();
+  this->binding_ = sym.get_st_bind();
+  this->visibility_ = sym.get_st_visibility();
+  this->other_ = sym.get_st_nonvis();
+  this->special_ = false;
+  this->def_ = false;
+  this->forwarder_ = false;
+}
+
+// Initialize the fields in Sized_symbol.
+
+template<int size>
+template<bool big_endian>
+void
+Sized_symbol<size>::init(const char* name, const char* version, Object* object,
+                        const elfcpp::Sym<size, big_endian>& sym)
+{
+  this->init_base(name, version, object, sym);
+  this->value_ = sym.get_st_value();
+  this->size_ = sym.get_st_size();
+}
+
+// Class Symbol_table.
+
+Symbol_table::Symbol_table()
+  : size_(0), table_(), namepool_(), forwarders_()
+{
+}
+
+Symbol_table::~Symbol_table()
+{
+}
+
+// The hash function.  The key is always canonicalized, so we use a
+// simple combination of the pointers.
+
+size_t
+Symbol_table::Symbol_table_hash::operator()(const Symbol_table_key& key) const
+{
+  return (reinterpret_cast<size_t>(key.first)
+         ^ reinterpret_cast<size_t>(key.second));
+}
+
+// The symbol table key equality function.  This is only called with
+// canonicalized name and version strings, so we can use pointer
+// comparison.
+
+bool
+Symbol_table::Symbol_table_eq::operator()(const Symbol_table_key& k1,
+                                         const Symbol_table_key& k2) const
+{
+  return k1.first == k2.first && k1.second == k2.second;
+}
+
+// Make TO a symbol which forwards to FROM.  
+
+void
+Symbol_table::make_forwarder(Symbol* from, Symbol* to)
+{
+  assert(!from->is_forwarder() && !to->is_forwarder());
+  this->forwarders_[from] = to;
+  from->set_forwarder();
+}
+
+Symbol*
+Symbol_table::resolve_forwards(Symbol* from) const
+{
+  assert(from->is_forwarder());
+  Unordered_map<Symbol*, Symbol*>::const_iterator p =
+    this->forwarders_.find(from);
+  assert(p != this->forwarders_.end());
+  return p->second;
+}
+
+// Resolve a Symbol with another Symbol.  This is only used in the
+// unusual case where there are references to both an unversioned
+// symbol and a symbol with a version, and we then discover that that
+// version is the default version.
+
+void
+Symbol_table::resolve(Symbol*, const Symbol*)
+{
+}
+
+// Add one symbol from OBJECT to the symbol table.  NAME is symbol
+// name and VERSION is the version; both are canonicalized.  DEF is
+// whether this is the default version.
+
+// If DEF is true, then this is the definition of a default version of
+// a symbol.  That means that any lookup of NAME/NULL and any lookup
+// of NAME/VERSION should always return the same symbol.  This is
+// obvious for references, but in particular we want to do this for
+// definitions: overriding NAME/NULL should also override
+// NAME/VERSION.  If we don't do that, it would be very hard to
+// override functions in a shared library which uses versioning.
+
+// We implement this by simply making both entries in the hash table
+// point to the same Symbol structure.  That is easy enough if this is
+// the first time we see NAME/NULL or NAME/VERSION, but it is possible
+// that we have seen both already, in which case they will both have
+// independent entries in the symbol table.  We can't simply change
+// the symbol table entry, because we have pointers to the entries
+// attached to the object files.  So we mark the entry attached to the
+// object file as a forwarder, and record it in the forwarders_ map.
+// Note that entries in the hash table will never be marked as
+// forwarders.
+
+template<int size, bool big_endian>
+Symbol*
+Symbol_table::add_from_object(Sized_object<size, big_endian>* object,
+                             const char *name,
+                             const char *version, bool def,
+                             const elfcpp::Sym<size, big_endian>& sym)
+{
+  Symbol* const snull = NULL;
+  std::pair<typename Symbol_table_type::iterator, bool> ins =
+    this->table_.insert(std::make_pair(std::make_pair(name, version), snull));
+
+  std::pair<typename Symbol_table_type::iterator, bool> insdef =
+    std::make_pair(this->table_.end(), false);
+  if (def)
+    {
+      const char* const vnull = NULL;
+      insdef = this->table_.insert(std::make_pair(std::make_pair(name, vnull),
+                                                 snull));
+    }
+
+  // ins.first: an iterator, which is a pointer to a pair.
+  // ins.first->first: the key (a pair of name and version).
+  // ins.first->second: the value (Symbol*).
+  // ins.second: true if new entry was inserted, false if not.
+
+  Symbol* ret;
+  if (!ins.second)
+    {
+      // We already have an entry for NAME/VERSION.
+      ret = ins.first->second;
+      assert(ret != NULL);
+      Symbol_table::resolve(ret, sym, object);
+
+      if (def)
+       {
+         if (insdef.second)
+           {
+             // This is the first time we have seen NAME/NULL.  Make
+             // NAME/NULL point to NAME/VERSION.
+             insdef.first->second = ret;
+           }
+         else
+           {
+             // This is the unfortunate case where we already have
+             // entries for both NAME/VERSION and NAME/NULL.
+             Symbol_table::resolve(ret, insdef.first->second);
+             this->make_forwarder(insdef.first->second, ret);
+             insdef.first->second = ret;
+           }
+       }
+    }
+  else
+    {
+      // This is the first time we have seen NAME/VERSION.
+      assert(ins.first->second == NULL);
+      if (def && !insdef.second)
+       {
+         // We already have an entry for NAME/NULL.  Make
+         // NAME/VERSION point to it.
+         ret = insdef.first->second;
+         Symbol_table::resolve(ret, sym, object);
+         ins.first->second = ret;
+       }
+      else
+       {
+         Sized_symbol<size>* rs;
+         Sized_target<size, big_endian>* target = object->sized_target();
+         if (target->has_make_symbol())
+           {
+             rs = target->make_symbol();
+             if (rs == NULL)
+               {
+                 // This means that we don't want a symbol table
+                 // entry after all.
+                 if (!def)
+                   this->table_.erase(ins.first);
+                 else
+                   {
+                     this->table_.erase(insdef.first);
+                     // Inserting insdef invalidated ins.
+                     this->table_.erase(std::make_pair(name, version));
+                   }
+                 return NULL;
+               }
+           }
+         else
+           rs = new Sized_symbol<size>();
+         rs->init(name, version, object, sym);
+
+         ret = rs;
+         ins.first->second = ret;
+         if (def)
+           {
+             // This is the first time we have seen NAME/NULL.  Point
+             // it at the new entry for NAME/VERSION.
+             assert(insdef.second);
+             insdef.first->second = ret;
+           }
+       }
+    }
+
+  return ret;
+}
+
+// Add all the symbols in an object to the hash table.
+
+template<int size, bool big_endian>
+void
+Symbol_table::add_from_object(
+    Sized_object<size, big_endian>* object,
+    const elfcpp::Sym<size, big_endian>* syms,
+    size_t count,
+    const char* sym_names,
+    size_t sym_name_size,
+    Symbol** sympointers)
+{
+  // We take the size from the first object we see.
+  if (this->get_size() == 0)
+    this->set_size(size);
+
+  if (size != this->get_size() || size != object->target()->get_size())
+    {
+      fprintf(stderr, _("%s: %s: mixing 32-bit and 64-bit ELF objects\n"),
+             program_name, object->name().c_str());
+      gold_exit(false);
+    }
+
+  const unsigned char* p = reinterpret_cast<const unsigned char*>(syms);
+  for (size_t i = 0; i < count; ++i)
+    {
+      elfcpp::Sym<size, big_endian> sym(p);
+
+      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, object->name().c_str(), st_name,
+                 static_cast<unsigned long>(i));
+         gold_exit(false);
+       }
+
+      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.
+      const char* ver = strchr(name, '@');
+
+      Symbol* res;
+      if (ver == NULL)
+       {
+         name = this->namepool_.add(name);
+         res = this->add_from_object(object, name, NULL, false, sym);
+       }
+      else
+       {
+         name = this->namepool_.add(name, ver - name);
+         bool def = false;
+         ++ver;
+         if (*ver == '@')
+           {
+             def = true;
+             ++ver;
+           }
+         ver = this->namepool_.add(ver);
+         res = this->add_from_object(object, name, ver, def, sym);
+       }
+
+      *sympointers++ = res;
+
+      p += elfcpp::Elf_sizes<size>::sym_size;
+    }
+}
+
+// Instantiate the templates we need.  We could use the configure
+// script to restrict this to only the ones needed for implemented
+// targets.
+
+template
+void
+Symbol_table::add_from_object<32, true>(
+    Sized_object<32, true>* object,
+    const elfcpp::Sym<32, true>* syms,
+    size_t count,
+    const char* sym_names,
+    size_t sym_name_size,
+    Symbol** sympointers);
+
+template
+void
+Symbol_table::add_from_object<32, false>(
+    Sized_object<32, false>* object,
+    const elfcpp::Sym<32, false>* syms,
+    size_t count,
+    const char* sym_names,
+    size_t sym_name_size,
+    Symbol** sympointers);
+
+template
+void
+Symbol_table::add_from_object<64, true>(
+    Sized_object<64, true>* object,
+    const elfcpp::Sym<64, true>* syms,
+    size_t count,
+    const char* sym_names,
+    size_t sym_name_size,
+    Symbol** sympointers);
+
+template
+void
+Symbol_table::add_from_object<64, false>(
+    Sized_object<64, false>* object,
+    const elfcpp::Sym<64, false>* syms,
+    size_t count,
+    const char* sym_names,
+    size_t sym_name_size,
+    Symbol** sympointers);
+
+} // End namespace gold.
index 1495fb1e6ac5bfaaaacab7a8db07937a8411a1aa..c085dd9c7dd35821f0f23a63893846b6e8e58e84 100644 (file)
@@ -3,15 +3,12 @@
 // Symbol_table
 //   The symbol table.
 
-#include "gold.h"
-
 #include <string>
 #include <utility>
 
 #include "elfcpp.h"
 #include "targetsize.h"
-#include "object.h"
-#include "workqueue.h"
+#include "stringpool.h"
 
 #ifndef GOLD_SYMTAB_H
 #define GOLD_SYMTAB_H
 namespace gold
 {
 
-// An entry in the symbol table.  The symbol table can have a lot of
-// entries, so we don't want this class to get too big.
+class Object;
+
+template<int size, bool big_endian>
+class Sized_object;
+
+template<int size, bool big_endian>
+class Sized_target;
+
+// The base class of an entry in the symbol table.  The symbol table
+// can have a lot of entries, so we don't want this class to big.
+// Size dependent fields can be found in the template class
+// Sized_symbol.  Targets may support their own derived classes.
 
-template<int size>
 class Symbol
 {
  public:
-  typedef typename elfcpp::Elf_types<size>::Elf_Addr Value;
-  typedef typename Size_types<size>::Unsigned_type Size;
+  virtual ~Symbol();
+
+  // Return the symbol name.
+  const char*
+  name() const
+  { return this->name_; }
+
+  // Return the symbol version.  This will return NULL for an
+  // unversioned symbol.
+  const char*
+  version() const
+  { return this->version_; }
+
+  // Return whether this symbol is a forwarder.  This will never be
+  // true of a symbol found in the hash table, but may be true of
+  // symbol pointers attached to object files.
+  bool
+  is_forwarder() const
+  { return this->forwarder_; }
+
+  // Mark this symbol as a forwarder.
+  void
+  set_forwarder()
+  { this->forwarder_ = true; }
+
+  // Return the object with which this symbol is associated.
+  Object*
+  object() const
+  { return this->object_; }
+
+  // Return the symbol binding.
+  elfcpp::STB
+  binding() const
+  { return this->binding_; }
+
+  // Return the section index.
+  unsigned int
+  shnum() const
+  { return this->shnum_; }
+
+ protected:
+  // Instances of this class should always be created at a specific
+  // size.
+  Symbol()
+  { }
+
+  // Initialize fields from an ELF symbol in OBJECT.
+  template<int size, bool big_endian>
+  void
+  init_base(const char *name, const char* version, Object* object,
+           const elfcpp::Sym<size, big_endian>&);
 
  private:
-  // Every symbol has a unique name, more or less, so we use
-  // std::string for the name.  There are only a few versions in a
-  // given link, so for them we point into a pool.
-  std::string name_;
+  Symbol(const Symbol&);
+  Symbol& operator=(const Symbol&);
+
+  // Symbol name (expected to point into a Stringpool).
+  const char* name_;
+  // Symbol version (expected to point into a Stringpool).  This may
+  // be NULL.
   const char* version_;
+  // Object in which symbol is defined, or in which it was first seen.
   Object* object_;
+  // Section number in object_ in which symbol is defined.
   unsigned int shnum_;
-  Value value_;
-  Size size_;
+  // Symbol type.
   elfcpp::STT type_ : 4;
+  // Symbol binding.
   elfcpp::STB binding_ : 4;
-  elfcpp:STV visibility_ : 2;
+  // Symbol visibility.
+  elfcpp::STV visibility_ : 2;
+  // Rest of symbol st_other field.
   unsigned int other_ : 6;
+  // True if this symbol always requires special target-specific
+  // handling.
+  bool special_ : 1;
+  // True if this is the default version of the symbol.
+  bool def_ : 1;
+  // True if this symbol really forwards to another symbol.  This is
+  // used when we discover after the fact that two different entries
+  // in the hash table really refer to the same symbol.  This will
+  // never be set for a symbol found in the hash table, but may be set
+  // for a symbol found in the list of symbols attached to an Object.
+  // It forwards to the symbol found in the forwarders_ map of
+  // Symbol_table.
+  bool forwarder_ : 1;
 };
 
-// The main linker symbol table.
+// The parts of a symbol which are size specific.  Using a template
+// derived class like this helps us use less space on a 32-bit system.
 
 template<int size>
+class Sized_symbol : public Symbol
+{
+ public:
+  Sized_symbol()
+  { }
+
+  // Initialize fields from an ELF symbol in OBJECT.
+  template<bool big_endian>
+  void
+  init(const char *name, const char* version, Object* object,
+       const elfcpp::Sym<size, big_endian>&);
+
+ private:
+  Sized_symbol(const Sized_symbol&);
+  Sized_symbol& operator=(const Sized_symbol&);
+
+  // Symbol value.
+  typename elfcpp::Elf_types<size>::Elf_Addr value_;
+  // Symbol size.
+  typename elfcpp::Elf_types<size>::Elf_WXword size_;
+};
+
+// The main linker symbol table.
+
 class Symbol_table
 {
  public:
   Symbol_table();
 
-  // Return a pointer to a symbol specified by name.
-  Symbol*
-  lookup(const std::string& name) const;
+  virtual ~Symbol_table();
 
-  // Return a pointer to a symbol specified by name plus version.
+  // Add COUNT external symbols from OBJECT 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(Sized_object<size, big_endian>* object,
+                 const elfcpp::Sym<size, big_endian>* syms,
+                 size_t count, const char* sym_names, size_t sym_name_size,
+                 Symbol** sympointers);
+
+  // Return the real symbol associated with the forwarder symbol FROM.
   Symbol*
-  lookup(const std::string& name, const char* version) const;
+  resolve_forwards(Symbol* from) const;
 
-  Task_token&
-  token() const
-  { return this->token_; }
+  // Return the size of the symbols in the table.
+  int
+  get_size() const
+  { return this->size_; }
 
  private:
   Symbol_table(const Symbol_table&);
   Symbol_table& operator=(const Symbol_table&);
 
-  typedef std::pair<std::string, std::string> Symbol_table_key;
+  // Set the size of the symbols in the table.
+  void
+  set_size(int size)
+  { this->size_ = size; }
+
+  // Make FROM a forwarder symbol to TO.
+  void
+  make_forwarder(Symbol* from, Symbol* to);
+
+  // Add a symbol.
+  template<int size, bool big_endian>
+  Symbol*
+  add_from_object(Sized_object<size, big_endian>*, const char *name,
+                 const char *version, bool def,
+                 const elfcpp::Sym<size, big_endian>& sym);
+
+  // Resolve symbols.
+  template<int size, bool big_endian>
+  static void
+  resolve(Symbol* to, const elfcpp::Sym<size, big_endian>& sym, Object*);
+
+  static void
+  resolve(Symbol* to, const Symbol* from);
+
+  typedef std::pair<const char*, const char*> Symbol_table_key;
+
+  struct Symbol_table_hash
+  {
+    size_t
+    operator()(const Symbol_table_key&) const;
+  };
+
+  struct Symbol_table_eq
+  {
+    bool
+    operator()(const Symbol_table_key&, const Symbol_table_key&) const;
+  };
+
+  typedef Unordered_map<Symbol_table_key, Symbol*, Symbol_table_hash,
+                       Symbol_table_eq> Symbol_table_type;
+
+  // The size of the symbols in the symbol table (32 or 64).
+  int size_;
+
+  // The symbol table itself.
+  Symbol_table_type table_;
+
+  // A pool of symbol names.
+  Stringpool namepool_;
 
-  Unordered_map<Symbol_table_key, Symbol<size>*> table_;
-  Task_token token_;
+  // Forwarding symbols.
+  Unordered_map<Symbol*, Symbol*> forwarders_;
 };
 
 } // End namespace gold.
diff --git a/gold/target-select.cc b/gold/target-select.cc
new file mode 100644 (file)
index 0000000..28b7527
--- /dev/null
@@ -0,0 +1,52 @@
+// target-select.cc -- select a target for an object file
+
+#include "gold.h"
+
+#include "elfcpp.h"
+#include "target-select.h"
+
+namespace
+{
+
+// The start of the list of target selectors.
+
+gold::Target_selector* target_selectors;
+
+} // End anonymous namespace.
+
+namespace gold
+{
+
+// Construct a Target_selector, which means adding it to the linked
+// list.  This runs at global constructor time, so we want it to be
+// fast.
+
+Target_selector::Target_selector(int machine, int size, bool big_endian)
+  : machine_(machine), size_(size), big_endian_(big_endian)
+{
+  this->next_ = target_selectors;
+  target_selectors = this;
+}
+
+// Find the target for an ELF file.
+
+extern Target*
+select_target(int machine, int size, bool big_endian, int osabi,
+             int abiversion)
+{
+  for (const Target_selector* p = target_selectors; p != NULL; p = p->next())
+    {
+      int pmach = p->machine();
+      if ((pmach == machine || pmach == elfcpp::EM_NONE)
+         && p->size() == size
+         && p->big_endian() ? big_endian : !big_endian)
+       {
+         Target* ret = p->recognize(machine, osabi, abiversion);
+         if (ret != NULL)
+           return ret;
+       }
+    }
+  return NULL;
+}
+
+} // End namespace gold.
diff --git a/gold/target-select.h b/gold/target-select.h
new file mode 100644 (file)
index 0000000..0762d58
--- /dev/null
@@ -0,0 +1,69 @@
+// target-select.h -- select a target for an object file  -*- C++ -*-
+
+#ifndef GOLD_TARGET_SELECT_H
+#define GOLD_TARGET_SELECT_H
+
+namespace gold
+{
+
+class Target;
+
+// We want to avoid a master list of targets, which implies using a
+// global constructor.  And we also want the program to start up as
+// quickly as possible, which implies avoiding global constructors.
+// We compromise on a very simple global constructor.  We use a target
+// selector, which specifies an ELF machine number and a recognition
+// function.  We use global constructors to build a linked list of
+// target selectors--a simple pointer list, not a std::list.
+
+class Target_selector
+{
+ public:
+  // Create a target selector for a specific machine number, size (32
+  // or 64), and endianness.  The machine number can be EM_NONE to
+  // test for any machine number.
+  Target_selector(int machine, int size, bool big_endian);
+
+  virtual ~Target_selector()
+  { }
+
+  // If we can handle this target, return a pointer to a target
+  // structure.  The size and endianness are known.
+  virtual Target* recognize(int machine, int osabi, int abiversion) const = 0;
+
+  // Return the next Target_selector in the linked list.
+  Target_selector*
+  next() const
+  { return this->next_; }
+
+  // Return the machine number this selector is looking for, which can
+  // be EM_NONE to match any machine number.
+  int
+  machine() const
+  { return this->machine_; }
+
+  // Return the size this is looking for (32 or 64).
+  int
+  size() const
+  { return this->size_; }
+
+  // Return the endianness this is looking for.
+  bool
+  big_endian() const
+  { return this->big_endian_; }
+
+ private:
+  int machine_;
+  int size_;
+  bool big_endian_;
+  Target_selector* next_;
+};
+
+// Select the target for an ELF file.
+
+extern Target* select_target(int machine, int size, bool big_endian,
+                            int osabi, int abiversion);
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_TARGET_SELECT_H)
index 1f1c57550b560b02fc20c44059ab6ad3f4863a82..236185bc56a7b8590a9124ce5d8bebe941b727ff 100644 (file)
@@ -1,4 +1,4 @@
-// target.h -- target support for gold
+// target.h -- target support for gold   -*- C++ -*-
 
 // The abstract class Target is the interface for target specific
 // support.  It defines abstract methods which each target must
 #ifndef GOLD_TARGET_H
 #define GOLD_TARGET_H
 
+#include "symtab.h"
+#include "elfcpp.h"
+
 namespace gold
 {
 
+class Object;
+
+// The abstract class for target specific handling.
+
 class Target
 {
  public:
+  virtual ~Target()
+  { }
+
+  // Return the bit size that this target implements.  This should
+  // return 32 or 64.
+  int
+  get_size() const
+  { return this->size_; }
+
+  // Return whether this target is big-endian.
+  bool
+  is_big_endian() const
+  { return this->is_big_endian_; }
+
+  // Whether this target has a specific make_symbol function.
+  bool
+  has_make_symbol() const
+  { return this->has_make_symbol_; }
+
+  // Whether this target has a specific resolve function.
+  bool
+  has_resolve() const
+  { return this->has_resolve_; }
+
+  // Resolve a symbol.  This is called when we see a symbol with a
+  // target specific binding (STB_LOOS through STB_HIOS or STB_LOPROC
+  // through STB_HIPROC).  TO is a pre-existing symbol.  SYM is the
+  // new symbol, seen in OBJECT.  This returns true on success, false
+  // if the symbol can not be resolved.
+  template<int size, bool big_endian>
+  bool
+  resolve(Sized_symbol<size>* to, const elfcpp::Sym<size, big_endian>& sym,
+         Object* object);
+
+ protected:
+  Target(int size, bool is_big_endian, bool has_make_symbol, bool has_resolve)
+    : size_(size),
+      is_big_endian_(is_big_endian),
+      has_make_symbol_(has_make_symbol),
+      has_resolve_(has_resolve)
+  { }
+
+ private:
+  Target(const Target&);
+  Target& operator=(const Target&);
+
+  // The target size.
+  int size_;
+  // Whether this target is big endian.
+  bool is_big_endian_;
+  // Whether this target has a special make_symbol function.
+  bool has_make_symbol_;
+  // Whether this target has a special resolve function.
+  bool has_resolve_;
 };
 
-extern Target* select_target(int machine, int size, bool big_endian,
-                            int osabi, int abiversion);
+// The abstract class for a specific size and endianness of target.
+// Each actual target implementation class should derive from an
+// instantiation of Sized_target.
+
+template<int size, bool big_endian>
+class Sized_target : public Target
+{
+ public:
+  // Make a new symbol table entry for the target.  This should be
+  // overridden by a target which needs additional information in the
+  // symbol table.  This will only be called if has_make_symbol()
+  // returns true.
+  virtual Sized_symbol<size>*
+  make_symbol()
+  { abort(); }
+
+  // Resolve a symbol for the target.  This should be overridden by a
+  // target which needs to take special action.  TO is the
+  // pre-existing symbol.  SYM is the new symbol, seen in OBJECT.
+  virtual void
+  resolve(Symbol*, const elfcpp::Sym<size, big_endian>&, Object*)
+  { abort(); }
+
+ protected:
+  Sized_target(bool has_make_symbol, bool has_resolve)
+    : Target(size, big_endian, has_make_symbol, has_resolve)
+  { }
+};
 
 } // End namespace gold.