Can now do a full static link of hello, world in C or C++
authorIan Lance Taylor <iant@google.com>
Fri, 3 Nov 2006 18:26:11 +0000 (18:26 +0000)
committerIan Lance Taylor <iant@google.com>
Fri, 3 Nov 2006 18:26:11 +0000 (18:26 +0000)
36 files changed:
gold/Makefile.am
gold/Makefile.in
gold/aclocal.m4
gold/archive.cc
gold/archive.h
gold/common.cc [new file with mode: 0644]
gold/common.h [new file with mode: 0644]
gold/defstd.cc [new file with mode: 0644]
gold/defstd.h [new file with mode: 0644]
gold/dirsearch.h
gold/fileread.cc
gold/fileread.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/reloc.h
gold/resolve.cc
gold/symtab.cc
gold/symtab.h
gold/target-reloc.h
gold/target-select.cc
gold/target-select.h
gold/target.h
gold/workqueue.h

index 8545a77..13aae26 100644 (file)
@@ -19,6 +19,8 @@ noinst_PROGRAMS = ld-new
 
 CCFILES = \
        archive.cc \
+       common.cc \
+       defstd.cc \
        dirsearch.cc \
        fileread.cc \
        gold.cc \
@@ -37,6 +39,8 @@ CCFILES = \
 
 HFILES = \
        archive.h \
+       common.h \
+       defstd.h \
        dirsearch.h \
        fileread.h \
        gold.h \
index a9d6073..d4c0c67 100644 (file)
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.9.5 from Makefile.am.
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -16,8 +16,6 @@
 
 # Process this file with automake to generate Makefile.in
 
-SOURCES = $(ld_new_SOURCES)
-
 srcdir = @srcdir@
 top_srcdir = @top_srcdir@
 VPATH = @srcdir@
@@ -52,10 +50,9 @@ subdir = .
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/../config/depstand.m4 \
        $(top_srcdir)/../config/lead-dot.m4 \
-       $(top_srcdir)/../bfd/../config/progtest.m4 \
-       $(top_srcdir)/../bfd/../config/po.m4 \
-       $(top_srcdir)/../bfd/../config/nls.m4 \
-       $(top_srcdir)/../bfd/../config/gettext-sister.m4 \
+       $(top_srcdir)/../config/progtest.m4 \
+       $(top_srcdir)/../config/po.m4 $(top_srcdir)/../config/nls.m4 \
+       $(top_srcdir)/../config/gettext-sister.m4 \
        $(top_srcdir)/../bfd/warning.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
@@ -65,12 +62,13 @@ mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
 CONFIG_HEADER = config.h
 CONFIG_CLEAN_FILES = po/Makefile.in
 PROGRAMS = $(noinst_PROGRAMS)
-am__objects_1 = archive.$(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)
+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)
 am__objects_2 =
 am__objects_3 = i386.$(OBJEXT)
 am_ld_new_OBJECTS = $(am__objects_1) $(am__objects_2) $(am__objects_3)
@@ -233,6 +231,8 @@ INCLUDES = -D_GNU_SOURCE \
 
 CCFILES = \
        archive.cc \
+       common.cc \
+       defstd.cc \
        dirsearch.cc \
        fileread.cc \
        gold.cc \
@@ -251,6 +251,8 @@ CCFILES = \
 
 HFILES = \
        archive.h \
+       common.h \
+       defstd.h \
        dirsearch.h \
        fileread.h \
        gold.h \
@@ -347,6 +349,8 @@ distclean-compile:
        -rm -f *.tab.c
 
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/archive.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/defstd.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dirsearch.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fileread.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gold-threads.Po@am__quote@
@@ -514,7 +518,7 @@ distclean-tags:
 distdir: $(DISTFILES)
        $(am__remove_distdir)
        mkdir $(distdir)
-       $(mkdir_p) $(distdir)/.. $(distdir)/../bfd $(distdir)/../bfd/../config $(distdir)/../config $(distdir)/po
+       $(mkdir_p) $(distdir)/.. $(distdir)/../bfd $(distdir)/../config $(distdir)/po
        @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
        topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
        list='$(DISTFILES)'; for file in $$list; do \
index 1385aed..4438a34 100644 (file)
@@ -1,4 +1,4 @@
-# generated automatically by aclocal 1.9.5 -*- Autoconf -*-
+# generated automatically by aclocal 1.9.6 -*- Autoconf -*-
 
 # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
 # 2005  Free Software Foundation, Inc.
@@ -28,7 +28,7 @@ AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version="1.9"])
 # Call AM_AUTOMAKE_VERSION so it can be traced.
 # This function is AC_REQUIREd by AC_INIT_AUTOMAKE.
 AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
-        [AM_AUTOMAKE_VERSION([1.9.5])])
+        [AM_AUTOMAKE_VERSION([1.9.6])])
 
 # AM_AUX_DIR_EXPAND                                         -*- Autoconf -*-
 
@@ -870,8 +870,8 @@ AC_SUBST([am__untar])
 
 m4_include([../config/depstand.m4])
 m4_include([../config/lead-dot.m4])
-m4_include([../bfd/../config/progtest.m4])
-m4_include([../bfd/../config/po.m4])
-m4_include([../bfd/../config/nls.m4])
-m4_include([../bfd/../config/gettext-sister.m4])
+m4_include([../config/progtest.m4])
+m4_include([../config/po.m4])
+m4_include([../config/nls.m4])
+m4_include([../config/gettext-sister.m4])
 m4_include([../bfd/warning.m4])
index a64109a..031ead0 100644 (file)
@@ -9,6 +9,7 @@
 
 #include "elfcpp.h"
 #include "fileread.h"
+#include "readsyms.h"
 #include "symtab.h"
 #include "object.h"
 #include "archive.h"
@@ -47,14 +48,6 @@ const char Archive::armag[sarmag] =
 
 const char Archive::arfmag[2] = { '`', '\n' };
 
-// Get a view into the underlying file.
-
-const unsigned char*
-Archive::get_view(off_t start, off_t size)
-{
-  return this->input_file_->file().get_view(start, size);
-}
-
 // Set up the archive: read the symbol map and the extended name
 // table.
 
@@ -113,6 +106,10 @@ Archive::setup()
       this->extended_names_.assign(px, extended_size);
     }
 
+  // This array keeps track of which symbols are for archive elements
+  // which we have already included in the link.
+  this->seen_.resize(nsyms);
+
   // Opening the file locked it.  Unlock it now.
   this->input_file_->file().unlock();
 }
@@ -221,10 +218,7 @@ void
 Archive::add_symbols(Symbol_table* symtab, Layout* layout,
                     Input_objects* input_objects)
 {
-  size_t armap_size = this->armap_.size();
-  std::vector<bool> seen;
-  seen.resize(this->armap_.size());
-  seen.clear();
+  const size_t armap_size = this->armap_.size();
 
   bool added_new_object;
   do
@@ -233,20 +227,20 @@ Archive::add_symbols(Symbol_table* symtab, Layout* layout,
       off_t last = -1;
       for (size_t i = 0; i < armap_size; ++i)
        {
-         if (seen[i])
+         if (this->seen_[i])
            continue;
          if (this->armap_[i].offset == last)
            {
-             seen[i] = true;
+             this->seen_[i] = true;
              continue;
            }
 
          Symbol* sym = symtab->lookup(this->armap_[i].name);
          if (sym == NULL)
            continue;
-         else if (sym->shnum() != elfcpp::SHN_UNDEF)
+         else if (!sym->is_undefined())
            {
-             seen[i] = true;
+             this->seen_[i] = true;
              continue;
            }
          else if (sym->binding() == elfcpp::STB_WEAK)
@@ -255,6 +249,7 @@ Archive::add_symbols(Symbol_table* symtab, Layout* layout,
          // We want to include this object in the link.
          last = this->armap_[i].offset;
          this->include_member(symtab, layout, input_objects, last);
+         this->seen_[i] = true;
          added_new_object = true;
        }
     }
@@ -337,13 +332,13 @@ class Add_archive_symbols::Add_archive_symbols_locker : public Task_locker
 {
  public:
   Add_archive_symbols_locker(Task_token& token, Workqueue* workqueue,
-                            Archive* archive)
-    : blocker_(token, workqueue), archlock_(*archive)
+                            File_read& file)
+    : blocker_(token, workqueue), filelock_(file)
   { }
 
  private:
   Task_locker_block blocker_;
-  Task_locker_obj<Archive> archlock_;                       
+  Task_locker_obj<File_read> filelock_;                             
 };
 
 Task_locker*
@@ -351,7 +346,7 @@ Add_archive_symbols::locks(Workqueue* workqueue)
 {
   return new Add_archive_symbols_locker(*this->next_blocker_,
                                        workqueue,
-                                       this->archive_);
+                                       this->archive_->file());
 }
 
 void
@@ -359,6 +354,14 @@ Add_archive_symbols::run(Workqueue*)
 {
   this->archive_->add_symbols(this->symtab_, this->layout_,
                              this->input_objects_);
+
+  if (this->input_group_ != NULL)
+    this->input_group_->add_archive(this->archive_);
+  else
+    {
+      // We no longer need to know about this archive.
+      delete this->archive_;
+    }
 }
 
 } // End namespace gold.
index b2d4c46..f0edfcb 100644 (file)
@@ -13,6 +13,7 @@ namespace gold
 
 class Input_file;
 class Input_objects;
+class Input_group;
 class Layout;
 class Symbol_table;
 
@@ -44,6 +45,11 @@ class Archive
   void
   setup();
 
+  // Get a reference to the underlying file.
+  File_read&
+  file()
+  { return this->input_file_->file(); }
+
   // Lock the underlying file.
   void
   lock()
@@ -73,7 +79,8 @@ class Archive
 
   // Get a view into the underlying file.
   const unsigned char*
-  get_view(off_t start, off_t size);
+  get_view(off_t start, off_t size)
+  { return this->input_file_->file().get_view(start, size); }
 
   // Read an archive member header at OFF.  Return the size of the
   // member, and set *PNAME to the name.
@@ -101,6 +108,9 @@ class Archive
   std::vector<Armap_entry> armap_;
   // The extended name table.
   std::string extended_names_;
+  // Track which symbols in the archive map are for elements which
+  // have already been included in the link.
+  std::vector<bool> seen_;
 };
 
 // This class is used to read an archive and pick out the desired
@@ -111,11 +121,12 @@ class Add_archive_symbols : public Task
  public:
   Add_archive_symbols(Symbol_table* symtab, Layout* layout,
                      Input_objects* input_objects,
-                     Archive* archive, Task_token* this_blocker,
+                     Archive* archive, Input_group* input_group,
+                     Task_token* this_blocker,
                      Task_token* next_blocker)
     : symtab_(symtab), layout_(layout), input_objects_(input_objects),
-      archive_(archive), this_blocker_(this_blocker),
-      next_blocker_(next_blocker)
+      archive_(archive), input_group_(input_group),
+      this_blocker_(this_blocker), next_blocker_(next_blocker)
   { }
 
   ~Add_archive_symbols();
@@ -138,6 +149,7 @@ class Add_archive_symbols : public Task
   Layout* layout_;
   Input_objects* input_objects_;
   Archive* archive_;
+  Input_group* input_group_;
   Task_token* this_blocker_;
   Task_token* next_blocker_;
 };
diff --git a/gold/common.cc b/gold/common.cc
new file mode 100644 (file)
index 0000000..9738f98
--- /dev/null
@@ -0,0 +1,208 @@
+// common.cc -- handle common symbols for gold
+
+#include "gold.h"
+
+#include <algorithm>
+
+#include "workqueue.h"
+#include "layout.h"
+#include "output.h"
+#include "common.h"
+
+namespace gold
+{
+
+// Allocate_commons_task methods.
+
+// This task allocates the common symbols.  We need a lock on the
+// symbol table.
+
+Task::Is_runnable_type
+Allocate_commons_task::is_runnable(Workqueue*)
+{
+  if (!this->symtab_lock_->is_writable())
+    return IS_LOCKED;
+  return IS_RUNNABLE;
+}
+
+// Return the locks we hold: one on the symbol table, and one blocker.
+
+class Allocate_commons_task::Allocate_commons_locker : public Task_locker
+{
+ public:
+  Allocate_commons_locker(Task_token& symtab_lock, Task* task,
+                         Task_token& blocker, Workqueue* workqueue)
+    : symtab_locker_(symtab_lock, task),
+      blocker_(blocker, workqueue)
+  { }
+
+ private:
+  Task_locker_write symtab_locker_;
+  Task_locker_block blocker_;
+};
+
+Task_locker*
+Allocate_commons_task::locks(Workqueue* workqueue)
+{
+  return new Allocate_commons_locker(*this->symtab_lock_, this,
+                                    *this->blocker_, workqueue);
+}
+
+// Allocate the common symbols.
+
+void
+Allocate_commons_task::run(Workqueue*)
+{
+  this->symtab_->allocate_commons(this->options_, this->layout_);
+}
+
+// This class is used to sort the common symbol by size.  We put the
+// larger common symbols first.
+
+template<int size>
+class Sort_commons
+{
+ public:
+  Sort_commons(const Symbol_table* symtab)
+    : symtab_(symtab)
+  { }
+
+  bool operator()(const Symbol* a, const Symbol* b) const;
+
+ private:
+  const Symbol_table* symtab_;
+};
+
+template<int size>
+bool
+Sort_commons<size>::operator()(const Symbol* pa, const Symbol* pb) const
+{
+  if (pa == NULL)
+    return false;
+  if (pb == NULL)
+    return true;
+
+  const Symbol_table* symtab = this->symtab_;
+  const Sized_symbol<size>* psa;
+  psa = symtab->get_sized_symbol SELECT_SIZE_NAME (pa
+                                                  SELECT_SIZE(size));
+  const Sized_symbol<size>* psb;
+  psb = symtab->get_sized_symbol SELECT_SIZE_NAME (pb
+                                                  SELECT_SIZE(size));
+
+  typename Sized_symbol<size>::Size_type sa = psa->symsize();
+  typename Sized_symbol<size>::Size_type sb = psb->symsize();
+  if (sa < sb)
+    return false;
+  else if (sb > sa)
+    return true;
+
+  // When the symbols are the same size, we sort them by alignment.
+  typename Sized_symbol<size>::Value_type va = psa->value();
+  typename Sized_symbol<size>::Value_type vb = psb->value();
+  if (va < vb)
+    return false;
+  else if (vb > va)
+    return true;
+
+  // Otherwise we stabilize the sort by sorting by name.
+  return strcmp(psa->name(), psb->name()) < 0;
+}
+
+// Allocate the common symbols.
+
+void
+Symbol_table::allocate_commons(const General_options& options, Layout* layout)
+{
+  if (this->get_size() == 32)
+    this->do_allocate_commons<32>(options, layout);
+  else if (this->get_size() == 64)
+    this->do_allocate_commons<64>(options, layout);
+  else
+    abort();
+}
+
+// Allocated the common symbols, sized version.
+
+template<int size>
+void
+Symbol_table::do_allocate_commons(const General_options&,
+                                 Layout* layout)
+{
+  typedef typename Sized_symbol<size>::Value_type Value_type;
+  typedef typename Sized_symbol<size>::Size_type Size_type;
+
+  // We've kept a list of all the common symbols.  But the symbol may
+  // have been resolved to a defined symbol by now.  And it may be a
+  // forwarder.  First remove all non-common symbols.
+  bool any = false;
+  uint64_t addralign = 0;
+  for (Commons_type::iterator p = this->commons_.begin();
+       p != this->commons_.end();
+       ++p)
+    {
+      Symbol* sym = *p;
+      if (sym->is_forwarder())
+       {
+         sym = this->resolve_forwards(sym);
+         *p = sym;
+       }
+      if (!sym->is_common())
+       *p = NULL;
+      else
+       {
+         any = true;
+         Sized_symbol<size>* ssym;
+         ssym = this->get_sized_symbol SELECT_SIZE_NAME (sym
+                                                         SELECT_SIZE(size));
+         if (ssym->value() > addralign)
+           addralign = ssym->value();
+       }
+    }
+  if (!any)
+    return;
+
+  // Sort the common symbols by size, so that they pack better into
+  // memory.
+  std::sort(this->commons_.begin(), this->commons_.end(),
+           Sort_commons<size>(this));
+
+  // Place them in a newly allocated .bss section.
+
+  Output_section_common *poc = new Output_section_common(addralign);
+
+  layout->add_output_section_data(".bss", elfcpp::SHT_NOBITS,
+                                 elfcpp::SHF_WRITE | elfcpp::SHF_ALLOC,
+                                 poc);
+
+  // Allocate them all.
+
+  off_t off = 0;
+  for (Commons_type::iterator p = this->commons_.begin();
+       p != this->commons_.end();
+       ++p)
+    {
+      Symbol* sym = *p;
+      if (sym == NULL)
+       break;
+
+      Sized_symbol<size>* ssym;
+      ssym = this->get_sized_symbol SELECT_SIZE_NAME (sym
+                                                     SELECT_SIZE(size));
+
+      off = align_address(off, ssym->value());
+
+      Size_type symsize = ssym->symsize();
+      ssym->init(ssym->name(), poc, off, symsize, ssym->type(),
+                ssym->binding(), ssym->visibility(), ssym->nonvis(),
+                false);
+
+      off += symsize;
+    }
+
+  poc->set_common_size(off);
+
+  this->commons_.clear();
+}
+
+} // End namespace gold.
diff --git a/gold/common.h b/gold/common.h
new file mode 100644 (file)
index 0000000..75237a6
--- /dev/null
@@ -0,0 +1,49 @@
+// common.h -- handle common symbols for gold   -*- C++ -*-
+
+#ifndef GOLD_COMMON_H
+#define GOLD_COMMON_H
+
+#include "workqueue.h"
+
+namespace gold
+{
+
+class General_options;
+class Symbol_table;
+
+// This task is used to allocate the common symbols.
+
+class Allocate_commons_task : public Task
+{
+ public:
+  Allocate_commons_task(const General_options& options, Symbol_table* symtab,
+                       Layout* layout, Task_token* symtab_lock,
+                       Task_token* blocker)
+    : options_(options), symtab_(symtab), layout_(layout),
+      symtab_lock_(symtab_lock), blocker_(blocker)
+  { }
+
+  // The standard Task methods.
+
+  Is_runnable_type
+  is_runnable(Workqueue*);
+
+  Task_locker*
+  locks(Workqueue*);
+
+  void
+  run(Workqueue*);
+
+ private:
+  class Allocate_commons_locker;
+
+  const General_options& options_;
+  Symbol_table* symtab_;
+  Layout* layout_;
+  Task_token* symtab_lock_;
+  Task_token* blocker_;
+};
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_COMMON_H)
diff --git a/gold/defstd.cc b/gold/defstd.cc
new file mode 100644 (file)
index 0000000..29fd2cd
--- /dev/null
@@ -0,0 +1,127 @@
+// defstd.cc -- define standard symbols for gold.
+
+#include "gold.h"
+
+#include "symtab.h"
+#include "defstd.h"
+
+// This is a simple file which defines the standard symbols like
+// "_end".
+
+namespace
+{
+
+using namespace gold;
+
+const Define_symbol_in_section in_section[] =
+{
+  {
+    "__preinit_array_start",   // name
+    ".preinit_array",          // output_section
+    0,                         // value
+    0,                         // size
+    elfcpp::STT_NOTYPE,                // type
+    elfcpp::STB_GLOBAL,                // binding
+    elfcpp::STV_HIDDEN,                // visibility
+    0,                         // nonvis
+    false,                     // offset_is_from_end
+    true                       // only_if_ref
+  },
+  {
+    "__preinit_array_end",     // name
+    ".preinit_array",          // output_section
+    0,                         // value
+    0,                         // size
+    elfcpp::STT_NOTYPE,                // type
+    elfcpp::STB_GLOBAL,                // binding
+    elfcpp::STV_HIDDEN,                // visibility
+    0,                         // nonvis
+    true,                      // offset_is_from_end
+    true                       // only_if_ref
+  },
+  {
+    "__init_array_start",      // name
+    ".init_array",             // output_section
+    0,                         // value
+    0,                         // size
+    elfcpp::STT_NOTYPE,                // type
+    elfcpp::STB_GLOBAL,                // binding
+    elfcpp::STV_HIDDEN,                // visibility
+    0,                         // nonvis
+    false,                     // offset_is_from_end
+    true                       // only_if_ref
+  },
+  {
+    "__init_array_end",                // name
+    ".init_array",             // output_section
+    0,                         // value
+    0,                         // size
+    elfcpp::STT_NOTYPE,                // type
+    elfcpp::STB_GLOBAL,                // binding
+    elfcpp::STV_HIDDEN,                // visibility
+    0,                         // nonvis
+    true,                      // offset_is_from_end
+    true                       // only_if_ref
+  },
+  {
+    "__fini_array_start",      // name
+    ".fini_array",             // output_section
+    0,                         // value
+    0,                         // size
+    elfcpp::STT_NOTYPE,                // type
+    elfcpp::STB_GLOBAL,                // binding
+    elfcpp::STV_HIDDEN,                // visibility
+    0,                         // nonvis
+    false,                     // offset_is_from_end
+    true                       // only_if_ref
+  },
+  {
+    "__fini_array_end",                // name
+    ".fini_array",             // output_section
+    0,                         // value
+    0,                         // size
+    elfcpp::STT_NOTYPE,                // type
+    elfcpp::STB_GLOBAL,                // binding
+    elfcpp::STV_HIDDEN,                // visibility
+    0,                         // nonvis
+    true,                      // offset_is_from_end
+    true                       // only_if_ref
+  }
+};
+
+const int in_section_count = sizeof in_section / sizeof in_section[0];
+
+const Define_symbol_in_segment in_segment[] =
+{
+  {
+    "_end",                    // name
+    elfcpp::PT_LOAD,           // segment_type
+    elfcpp::PF_W,              // segment_flags_set
+    elfcpp::PF(0),             // segment_flags_clear
+    0,                         // value
+    0,                         // size
+    elfcpp::STT_NOTYPE,                // type
+    elfcpp::STB_GLOBAL,                // binding
+    elfcpp::STV_DEFAULT,       // visibility
+    0,                         // nonvis
+    Symbol::SEGMENT_START,     // offset_from_bas
+    false                      // only_if_ref
+  }
+};
+
+const int in_segment_count = sizeof in_segment / sizeof in_segment[0];
+
+} // End anonymous namespace.
+
+namespace gold
+{
+
+void
+define_standard_symbols(Symbol_table* symtab, const Layout* layout,
+                       Target* target)
+{
+  symtab->define_symbols(layout, target, in_section_count, in_section);
+  symtab->define_symbols(layout, target, in_segment_count, in_segment);
+}
+
+} // End namespace gold.
diff --git a/gold/defstd.h b/gold/defstd.h
new file mode 100644 (file)
index 0000000..f578b49
--- /dev/null
@@ -0,0 +1,16 @@
+// defstd.h -- define standard symbols for gold   -*- C++ -*-
+
+#ifndef GOLD_DEFSTD_H
+#define GOLD_DEFSTD_H
+
+#include "symtab.h"
+
+namespace gold
+{
+
+extern void
+define_standard_symbols(Symbol_table*, const Layout*, Target*);
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_DEFSTD_H)
index 3beb143..8b6ba59 100644 (file)
@@ -6,12 +6,13 @@
 #include <string>
 #include <list>
 
-#include "options.h"
 #include "workqueue.h"
 
 namespace gold
 {
 
+class General_options;
+
 // A simple interface to manage directories to be searched for
 // libraries.
 
index 987408e..00971a7 100644 (file)
@@ -102,18 +102,16 @@ File_read::is_locked()
 // See if we have a view which covers the file starting at START for
 // SIZE bytes.  Return a pointer to the View if found, NULL if not.
 
-File_read::View*
+inline File_read::View*
 File_read::find_view(off_t start, off_t size)
 {
-  for (std::list<File_read::View*>::iterator p = this->view_list_.begin();
-       p != this->view_list_.end();
-       ++p)
-    {
-      if ((*p)->start() <= start
-         && (*p)->start() + (*p)->size() >= start + size)
-       return *p;
-    }
-  return NULL;
+  off_t page = File_read::page_offset(start);
+  Views::iterator p = this->views_.find(page);
+  if (p == this->views_.end())
+    return NULL;
+  if (p->second->size() - (start - page) < size)
+    return NULL;
+  return p->second;
 }
 
 // Read data from the file.  Return the number of bytes read.  If
@@ -184,15 +182,59 @@ File_read::find_or_make_view(off_t start, off_t size, off_t* pbytes)
 {
   assert(this->lock_count_ > 0);
 
-  File_read::View* pv = this->find_view(start, size);
-  if (pv != NULL)
-    return pv;
+  off_t poff = File_read::page_offset(start);
+
+  File_read::View* const vnull = NULL;
+  std::pair<Views::iterator, bool> ins =
+    this->views_.insert(std::make_pair(poff, vnull));
+
+  if (!ins.second)
+    {
+      // There was an existing view at this offset.
+      File_read::View* v = ins.first->second;
+      if (v->size() - (start - v->start()) >= size)
+       {
+         if (pbytes != NULL)
+           *pbytes = size;
+         return v;
+       }
+
+      // This view is not large enough.
+      this->saved_views_.push_back(v);
+    }
+
+  // We need to read data from the file.
+
+  off_t psize = File_read::pages(size + (start - poff));
+  unsigned char* p = new unsigned char[psize];
 
-  unsigned char* p = new unsigned char[size];
-  off_t bytes = this->do_read(start, size, p, pbytes);
-  pv = new File_read::View(start, bytes, p);
-  this->view_list_.push_back(pv);
-  return pv;
+  off_t got_bytes;
+  off_t bytes = this->do_read(poff, psize, p, &got_bytes);
+
+  File_read::View* v = new File_read::View(poff, bytes, p);
+
+  ins.first->second = v;
+
+  if (bytes - (start - poff) >= size)
+    {
+      if (pbytes != NULL)
+       *pbytes = size;
+      return v;
+    }
+
+  if (pbytes != NULL)
+    {
+      *pbytes = bytes - (start - poff);
+      return v;
+    }
+
+  fprintf(stderr,
+         _("%s: %s: file too short: read only %lld of %lld bytes at %lld\n"),
+         program_name, this->filename().c_str(),
+         static_cast<long long>(bytes - (start - poff)),
+         static_cast<long long>(size),
+         static_cast<long long>(start));
+  gold_exit(false);
 }
 
 // This implementation of get_view just reads into a memory buffer,
@@ -221,18 +263,32 @@ File_read::get_lasting_view(off_t start, off_t size, off_t* pbytes)
 void
 File_read::clear_views(bool destroying)
 {
-  std::list<File_read::View*>::iterator p = this->view_list_.begin();
-  while (p != this->view_list_.end())
+  for (Views::iterator p = this->views_.begin();
+       p != this->views_.end();
+       ++p)
     {
-      if ((*p)->is_locked())
+      if (!p->second->is_locked())
+       delete p->second;
+      else
        {
          assert(!destroying);
-         ++p;
+         this->saved_views_.push_back(p->second);
        }
-      else
+    }
+  this->views_.clear();
+
+  Saved_views::iterator p = this->saved_views_.begin();
+  while (p != this->saved_views_.end())
+    {
+      if (!(*p)->is_locked())
        {
          delete *p;
-         p = this->view_list_.erase(p);
+         p = this->saved_views_.erase(p);
+       }
+      else
+       {
+         assert(!destroying);
+         ++p;
        }
     }
 }
index b65a86b..6e49324 100644 (file)
@@ -5,8 +5,9 @@
 #ifndef GOLD_FILEREAD_H
 #define GOLD_FILEREAD_H
 
-#include <string>
 #include <list>
+#include <map>
+#include <string>
 
 #include "options.h"
 
@@ -14,7 +15,6 @@ namespace gold
 {
 
 class Dirsearch;
-
 class File_view;
 
 // File_read manages a file descriptor for a file we are reading.  We
@@ -123,22 +123,52 @@ class File_read
 
   friend class File_view;
 
+  // Find a view into the file.
   View*
   find_view(off_t start, off_t size);
 
+  // Read data from the file into a buffer.
   off_t
   do_read(off_t start, off_t size, void* p, off_t* pbytes);
 
+  // Find or make a view into the file.
   View*
   find_or_make_view(off_t start, off_t size, off_t* pbytes);
 
+  // Clear the file views.
   void
   clear_views(bool);
 
+  // The size of a file page for buffering data.
+  static const off_t page_size = 8192;
+
+  // Given a file offset, return the page offset.
+  static off_t
+  page_offset(off_t file_offset)
+  { return file_offset & ~ (page_size - 1); }
+
+  // Given a file size, return the size to read integral pages.
+  static off_t
+  pages(off_t file_size)
+  { return (file_size + (page_size - 1)) & ~ (page_size - 1); }
+
+  // The type of a mapping from page start to views.
+  typedef std::map<off_t, View*> Views;
+
+  // A simple list of Views.
+  typedef std::list<View*> Saved_views;
+
+  // File name.
   std::string name_;
+  // File descriptor.
   int descriptor_;
+  // Number of locks on the file.
   int lock_count_;
-  std::list<View*> view_list_;
+  // Buffered views into the file.
+  Views views_;
+  // List of views which were locked but had to be removed from views_
+  // because they were not large enough.
+  Saved_views saved_views_;
 };
 
 // A view of file data that persists even when the file is unlocked.
@@ -179,7 +209,7 @@ class File_view
 class Input_file
 {
  public:
-  Input_file(const Input_argument& input_argument)
+  Input_file(const Input_file_argument& input_argument)
     : input_argument_(input_argument)
   { }
 
@@ -201,7 +231,10 @@ class Input_file
   { return this->file_; }
 
  private:
-  const Input_argument& input_argument_;
+  Input_file(const Input_file&);
+  Input_file& operator=(const Input_file&);
+
+  const Input_file_argument& input_argument_;
   File_read file_;
 };
 
index c39f999..31598dc 100644 (file)
 #include "dirsearch.h"
 #include "readsyms.h"
 #include "symtab.h"
+#include "common.h"
 #include "object.h"
 #include "layout.h"
 #include "reloc.h"
+#include "defstd.h"
 
 namespace gold
 {
@@ -92,11 +94,11 @@ Middle_runner::run(Workqueue* workqueue)
 void
 queue_initial_tasks(const General_options& options,
                    const Dirsearch& search_path,
-                   const Input_argument_list& inputs,
+                   const Command_line& cmdline,
                    Workqueue* workqueue, Input_objects* input_objects,
                    Symbol_table* symtab, Layout* layout)
 {
-  if (inputs.empty())
+  if (cmdline.begin() == cmdline.end())
     gold_fatal(_("no input files"), false);
 
   // Read the input files.  We have to add the symbols to the symbol
@@ -104,14 +106,14 @@ queue_initial_tasks(const General_options& options,
   // each input file.  We associate the blocker with the following
   // input file, to give us a convenient place to delete it.
   Task_token* this_blocker = NULL;
-  for (Input_argument_list::const_iterator p = inputs.begin();
-       p != inputs.end();
+  for (Command_line::const_iterator p = cmdline.begin();
+       p != cmdline.end();
        ++p)
     {
       Task_token* next_blocker = new Task_token();
       next_blocker->add_blocker();
       workqueue->queue(new Read_symbols(options, input_objects, symtab, layout,
-                                       search_path, *p, this_blocker,
+                                       search_path, *p, NULL, this_blocker,
                                        next_blocker));
       this_blocker = next_blocker;
     }
@@ -134,6 +136,10 @@ queue_middle_tasks(const General_options& options,
                   Layout* layout,
                   Workqueue* workqueue)
 {
+  // Predefine standard symbols.  This should be fast, so we don't
+  // bother to create a task for it.
+  define_standard_symbols(symtab, layout, input_objects->target());
+
   // Read the relocations of the input files.  We do this to find
   // which symbols are used by relocations which require a GOT and/or
   // a PLT entry, or a COPY reloc.  When we implement garbage
@@ -157,15 +163,15 @@ queue_middle_tasks(const General_options& options,
       // relocations.  That task will in turn queue a task to wait
       // until it can write to the symbol table.
       blocker->add_blocker();
-      workqueue->queue(new Read_relocs(options, symtab, *p, symtab_lock,
-                                      blocker));
+      workqueue->queue(new Read_relocs(options, symtab, layout, *p,
+                                      symtab_lock, blocker));
     }
 
   // Allocate common symbols.  This requires write access to the
   // symbol table, but is independent of the relocation processing.
-  // blocker->add_blocker();
-  // workqueue->queue(new Allocate_commons_task(options, symtab, layout,
-  //                                        symtab_lock, blocker));
+  blocker->add_blocker();
+  workqueue->queue(new Allocate_commons_task(options, symtab, layout,
+                                            symtab_lock, blocker));
 
   // When all those tasks are complete, we can start laying out the
   // output file.
@@ -257,7 +263,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, &input_objects,
+                     command_line, &workqueue, &input_objects,
                      &symtab, &layout);
 
   // Run the main task processing loop.
index 468cb90..53af5ee 100644 (file)
@@ -1,10 +1,14 @@
 // i386.cc -- i386 target support for gold.
 
 #include "gold.h"
+
+#include <cstring>
+
 #include "elfcpp.h"
 #include "reloc.h"
 #include "i386.h"
 #include "object.h"
+#include "symtab.h"
 #include "layout.h"
 #include "output.h"
 #include "target.h"
@@ -22,13 +26,15 @@ class Target_i386 : public Sized_target<32, false>
 {
  public:
   Target_i386()
-    : Sized_target<32, false>(&i386_info)
+    : Sized_target<32, false>(&i386_info),
+      got_(NULL)
   { }
 
   // Scan the relocations to look for symbol adjustments.
   void
   scan_relocs(const General_options& options,
              Symbol_table* symtab,
+             Layout* layout,
              Sized_object<32, false>* object,
              unsigned int sh_type,
              const unsigned char* prelocs,
@@ -52,12 +58,16 @@ class Target_i386 : public Sized_target<32, false>
   struct Scan
   {
     inline void
-    local(const General_options& options, Sized_object<32, false>* object,
+    local(const General_options& options, Symbol_table* symtab,
+         Layout* layout, Target_i386* target,
+         Sized_object<32, false>* object,
          const elfcpp::Rel<32, false>& reloc, unsigned int r_type,
          const elfcpp::Sym<32, false>& lsym);
 
     inline void
-    global(const General_options& options, Sized_object<32, false>* object,
+    global(const General_options& options, Symbol_table* symtab,
+          Layout* layout, Target_i386* target,
+          Sized_object<32, false>* object,
           const elfcpp::Rel<32, false>& reloc, unsigned int r_type,
           Symbol* gsym);
   };
@@ -66,9 +76,25 @@ class Target_i386 : public Sized_target<32, false>
   class Relocate
   {
    public:
-    // Do a relocation.
-    static inline void
-    relocate(const Relocate_info<32, false>*, size_t relnum,
+    Relocate()
+      : skip_call_tls_get_addr_(false)
+    { }
+
+    ~Relocate()
+    {
+      if (this->skip_call_tls_get_addr_)
+       {
+         // FIXME: This needs to specify the location somehow.
+         fprintf(stderr, _("%s: missing expected TLS relocation\n"),
+                 program_name);
+         gold_exit(false);
+       }
+    }
+
+    // Do a relocation.  Return false if the caller should not issue
+    // any warnings about this relocation.
+    inline bool
+    relocate(const Relocate_info<32, false>*, Target_i386*, size_t relnum,
             const elfcpp::Rel<32, false>&,
             unsigned int r_type, Sized_symbol<32>*,
             elfcpp::Elf_types<32>::Elf_Addr,
@@ -77,7 +103,7 @@ class Target_i386 : public Sized_target<32, false>
 
    private:
     // Do a TLS relocation.
-    static inline void
+    inline void
     relocate_tls(const Relocate_info<32, false>*, size_t relnum,
                 const elfcpp::Rel<32, false>&,
                 unsigned int r_type, Sized_symbol<32>*,
@@ -93,6 +119,15 @@ class Target_i386 : public Sized_target<32, false>
                 unsigned char* view,
                 off_t view_size);
 
+    // Do a TLS Global-Dynamic to Local-Exec transition.
+    inline void
+    tls_gd_to_le(const Relocate_info<32, false>*, size_t relnum,
+                Output_segment* tls_segment,
+                const elfcpp::Rel<32, false>&, unsigned int r_type,
+                elfcpp::Elf_types<32>::Elf_Addr value,
+                unsigned char* view,
+                off_t view_size);
+
     // Check the range for a TLS relocation.
     static inline void
     check_range(const Relocate_info<32, false>*, size_t relnum,
@@ -102,6 +137,10 @@ class Target_i386 : public Sized_target<32, false>
     static inline void
     check_tls(const Relocate_info<32, false>*, size_t relnum,
              const elfcpp::Rel<32, false>&, bool);
+
+    // This is set if we should skip the next reloc, which should be a
+    // PLT32 reloc against ___tls_get_addr.
+    bool skip_call_tls_get_addr_;
   };
 
   // Adjust TLS relocation type based on the options and whether this
@@ -109,9 +148,16 @@ class Target_i386 : public Sized_target<32, false>
   static unsigned int
   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>*
+  got_section(Symbol_table*, Layout*);
+
   // Information about this specific target which we pass to the
   // general Target structure.
   static const Target::Target_info i386_info;
+
+  // The GOT section.
+  Output_section_got<32, false>* got_;
 };
 
 const Target::Target_info Target_i386::i386_info =
@@ -126,6 +172,34 @@ const Target::Target_info Target_i386::i386_info =
   0x1000               // common_pagesize
 };
 
+// Get the GOT section, creating it if necessary.
+
+Output_section_got<32, false>*
+Target_i386::got_section(Symbol_table* symtab, Layout* layout)
+{
+  if (this->got_ == NULL)
+    {
+      this->got_ = new Output_section_got<32, false>();
+
+      assert(symtab != NULL && layout != NULL);
+      layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
+                                     elfcpp::SHF_ALLOC, this->got_);
+
+      // The first three entries are reserved.
+      this->got_->add_constant(0);
+      this->got_->add_constant(0);
+      this->got_->add_constant(0);
+
+      // Define _GLOBAL_OFFSET_TABLE_ at the start of the section.
+      symtab->define_in_output_data(this, "_GLOBAL_OFFSET_TABLE_", this->got_,
+                                   0, 0, elfcpp::STT_OBJECT,
+                                   elfcpp::STB_GLOBAL,
+                                   elfcpp::STV_HIDDEN, 0,
+                                   false, false);
+    }
+  return this->got_;
+}
+
 // Optimize the TLS relocation type based on what we know about the
 // symbol.  IS_LOCAL is true if this symbol can be resolved entirely
 // locally--i.e., does not have to be in the dynamic symbol table.
@@ -188,6 +262,9 @@ Target_i386::optimize_tls_reloc(const General_options* options, bool is_local,
 
 inline void
 Target_i386::Scan::local(const General_options& options,
+                        Symbol_table* symtab,
+                        Layout* layout,
+                        Target_i386* target,
                         Sized_object<32, false>* object,
                         const elfcpp::Rel<32, false>&, unsigned int r_type,
                         const elfcpp::Sym<32, false>&)
@@ -211,6 +288,12 @@ Target_i386::Scan::local(const General_options& options,
     case elfcpp::R_386_PC8:
       break;
 
+    case elfcpp::R_386_GOTOFF:
+    case elfcpp::R_386_GOTPC:
+      // We need a GOT section.
+      target->got_section(symtab, layout);
+      break;
+
     case elfcpp::R_386_COPY:
     case elfcpp::R_386_GLOB_DAT:
     case elfcpp::R_386_JUMP_SLOT:
@@ -261,8 +344,6 @@ Target_i386::Scan::local(const General_options& options,
 
     case elfcpp::R_386_GOT32:
     case elfcpp::R_386_PLT32:
-    case elfcpp::R_386_GOTOFF:
-    case elfcpp::R_386_GOTPC:
     case elfcpp::R_386_32PLT:
     case elfcpp::R_386_TLS_GD_32:
     case elfcpp::R_386_TLS_GD_PUSH:
@@ -284,6 +365,9 @@ Target_i386::Scan::local(const General_options& options,
 
 inline void
 Target_i386::Scan::global(const General_options& options,
+                         Symbol_table* symtab,
+                         Layout* layout,
+                         Target_i386* target,
                          Sized_object<32, false>* object,
                          const elfcpp::Rel<32, false>&, unsigned int r_type,
                          Symbol* gsym)
@@ -307,6 +391,37 @@ Target_i386::Scan::global(const General_options& options,
       // relocation in order to avoid a COPY relocation.
       break;
 
+    case elfcpp::R_386_GOT32:
+      // The symbol requires a GOT entry.
+      if (!gsym->has_got_offset())
+       {
+         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())
+           abort();
+       }
+      break;
+
+    case elfcpp::R_386_PLT32:
+      // If the symbol is resolved locally, this is just a PC32 reloc.
+      if (gsym->is_resolved_locally())
+       break;
+      fprintf(stderr,
+             _("%s: %s: unsupported reloc %u against global symbol %s\n"),
+             program_name, object->name().c_str(), r_type, gsym->name());
+      break;
+
+    case elfcpp::R_386_GOTOFF:
+    case elfcpp::R_386_GOTPC:
+      // We need a GOT section.
+      target->got_section(symtab, layout);
+      break;
+
     case elfcpp::R_386_COPY:
     case elfcpp::R_386_GLOB_DAT:
     case elfcpp::R_386_JUMP_SLOT:
@@ -332,7 +447,7 @@ Target_i386::Scan::global(const General_options& options,
     case elfcpp::R_386_TLS_GOTDESC:
     case elfcpp::R_386_TLS_DESC_CALL:
       r_type = Target_i386::optimize_tls_reloc(&options,
-                                              !gsym->in_dynsym(),
+                                              gsym->is_resolved_locally(),
                                               r_type);
       switch (r_type)
        {
@@ -357,10 +472,6 @@ Target_i386::Scan::global(const General_options& options,
        }
       break;
 
-    case elfcpp::R_386_GOT32:
-    case elfcpp::R_386_PLT32:
-    case elfcpp::R_386_GOTOFF:
-    case elfcpp::R_386_GOTPC:
     case elfcpp::R_386_32PLT:
     case elfcpp::R_386_TLS_GD_32:
     case elfcpp::R_386_TLS_GD_PUSH:
@@ -384,6 +495,7 @@ Target_i386::Scan::global(const General_options& options,
 void
 Target_i386::scan_relocs(const General_options& options,
                         Symbol_table* symtab,
+                        Layout* layout,
                         Sized_object<32, false>* object,
                         unsigned int sh_type,
                         const unsigned char* prelocs,
@@ -399,9 +511,12 @@ Target_i386::scan_relocs(const General_options& options,
       gold_exit(false);
     }
 
-  gold::scan_relocs<32, false, elfcpp::SHT_REL, Target_i386::Scan>(
+  gold::scan_relocs<32, false, Target_i386, elfcpp::SHT_REL,
+                   Target_i386::Scan>(
     options,
     symtab,
+    layout,
+    this,
     object,
     prelocs,
     reloc_count,
@@ -412,8 +527,9 @@ Target_i386::scan_relocs(const General_options& options,
 
 // Perform a relocation.
 
-inline void
+inline bool
 Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
+                               Target_i386* target,
                                size_t relnum,
                                const elfcpp::Rel<32, false>& rel,
                                unsigned int r_type,
@@ -423,6 +539,23 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
                                elfcpp::Elf_types<32>::Elf_Addr address,
                                off_t view_size)
 {
+  if (this->skip_call_tls_get_addr_)
+    {
+      if (r_type != elfcpp::R_386_PLT32
+         || gsym == NULL
+         || strcmp(gsym->name(), "___tls_get_addr") != 0)
+       {
+         fprintf(stderr, _("%s: %s: missing expected TLS relocation\n"),
+                 program_name,
+                 relinfo->location(relnum, rel.get_r_offset()).c_str());
+         gold_exit(false);
+       }
+
+      this->skip_call_tls_get_addr_ = false;
+
+      return false;
+    }
+
   switch (r_type)
     {
     case elfcpp::R_386_NONE:
@@ -454,6 +587,34 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
       Relocate_functions<32, false>::pcrel8(view, value, address);
       break;
 
+    case elfcpp::R_386_PLT32:
+      if (gsym->is_resolved_locally())
+       Relocate_functions<32, false>::pcrel32(view, value, address);
+      else
+       fprintf(stderr, _("%s: %s: unsupported reloc %u\n"),
+               program_name,
+               relinfo->location(relnum, rel.get_r_offset()).c_str(),
+               r_type);
+      break;
+
+    case elfcpp::R_386_GOT32:
+      // Local GOT offsets not yet supported.
+      assert(gsym);
+      assert(gsym->has_got_offset());
+      value = gsym->got_offset();
+      Relocate_functions<32, false>::rel32(view, value);
+      break;
+
+    case elfcpp::R_386_GOTOFF:
+      value -= target->got_section(NULL, NULL)->address();
+      Relocate_functions<32, false>::rel32(view, value);
+      break;
+
+    case elfcpp::R_386_GOTPC:
+      value = target->got_section(NULL, NULL)->address();
+      Relocate_functions<32, false>::pcrel32(view, value, address);
+      break;
+
     case elfcpp::R_386_COPY:
     case elfcpp::R_386_GLOB_DAT:
     case elfcpp::R_386_JUMP_SLOT:
@@ -480,15 +641,10 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
     case elfcpp::R_386_TLS_LE_32:
     case elfcpp::R_386_TLS_GOTDESC:
     case elfcpp::R_386_TLS_DESC_CALL:
-      Target_i386::Relocate::relocate_tls(relinfo, relnum, rel, r_type,
-                                         gsym, value, view, address,
-                                         view_size);
+      this->relocate_tls(relinfo, relnum, rel, r_type, gsym, value, view,
+                        address, view_size);
       break;
 
-    case elfcpp::R_386_GOT32:
-    case elfcpp::R_386_PLT32:
-    case elfcpp::R_386_GOTOFF:
-    case elfcpp::R_386_GOTPC:
     case elfcpp::R_386_32PLT:
     case elfcpp::R_386_TLS_GD_32:
     case elfcpp::R_386_TLS_GD_PUSH:
@@ -507,6 +663,8 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
       // gold_exit(false);
       break;
     }
+
+  return true;
 }
 
 // Perform a TLS relocation.
@@ -531,7 +689,7 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
       gold_exit(false);
     }
 
-  const bool is_local = gsym == NULL || !gsym->in_dynsym();
+  const bool is_local = gsym == NULL || gsym->is_resolved_locally();
   const unsigned int opt_r_type =
     Target_i386::optimize_tls_reloc(relinfo->options, is_local, r_type);
   switch (r_type)
@@ -564,6 +722,20 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
       break;
 
     case elfcpp::R_386_TLS_GD:
+      if (opt_r_type == elfcpp::R_386_TLS_LE_32)
+       {
+         this->tls_gd_to_le(relinfo, relnum, tls_segment,
+                            rel, r_type, value, view,
+                            view_size);
+         break;
+       }
+      fprintf(stderr, _("%s: %s: unsupported reloc %u\n"),
+             program_name,
+             relinfo->location(relnum, rel.get_r_offset()).c_str(),
+             r_type);
+      // gold_exit(false);
+      break;
+
     case elfcpp::R_386_TLS_LDM:
     case elfcpp::R_386_TLS_LDO_32:
     case elfcpp::R_386_TLS_GOTDESC:
@@ -667,14 +839,79 @@ Target_i386::Relocate::tls_ie_to_le(const Relocate_info<32, false>* relinfo,
        Target_i386::Relocate::check_tls(relinfo, relnum, rel, 0);
     }
 
-  if (r_type == elfcpp::R_386_TLS_IE_32)
-    value = tls_segment->vaddr() + tls_segment->memsz() - value;
-  else // elfcpp::R_386_TLS_IE, elfcpp::R_386_TLS_GOTIE
-    value = value - (tls_segment->vaddr() + tls_segment->memsz());
+  value = tls_segment->vaddr() + tls_segment->memsz() - value;
+  if (r_type == elfcpp::R_386_TLS_IE || r_type == elfcpp::R_386_TLS_GOTIE)
+    value = - value;
 
   Relocate_functions<32, false>::rel32(view, value);
 }
 
+// Do a relocation in which we convert a TLS Global-Dynamic to a
+// Local-Exec.
+
+inline void
+Target_i386::Relocate::tls_gd_to_le(const Relocate_info<32, false>* relinfo,
+                                   size_t relnum,
+                                   Output_segment* tls_segment,
+                                   const elfcpp::Rel<32, false>& rel,
+                                   unsigned int,
+                                   elfcpp::Elf_types<32>::Elf_Addr value,
+                                   unsigned char* view,
+                                   off_t view_size)
+{
+  // leal foo(,%reg,1),%eax; call ___tls_get_addr
+  //  ==> movl %gs,0,%eax; subl $foo@tpoff,%eax
+  // leal foo(%reg),%eax; call ___tls_get_addr
+  //  ==> movl %gs:0,%eax; subl $foo@tpoff,%eax
+
+  Target_i386::Relocate::check_range(relinfo, relnum, rel, view_size, -2);
+  Target_i386::Relocate::check_range(relinfo, relnum, rel, view_size, 9);
+
+  unsigned char op1 = view[-1];
+  unsigned char op2 = view[-2];
+
+  Target_i386::Relocate::check_tls(relinfo, relnum, rel,
+                                  op2 == 0x8d || op2 == 0x04);
+  Target_i386::Relocate::check_tls(relinfo, relnum, rel,
+                                  view[4] == 0xe8);
+
+  int roff = 5;
+
+  if (op2 == 0x04)
+    {
+      Target_i386::Relocate::check_range(relinfo, relnum, rel, view_size, -3);
+      Target_i386::Relocate::check_tls(relinfo, relnum, rel,
+                                      view[-3] == 0x8d);
+      Target_i386::Relocate::check_tls(relinfo, relnum, rel,
+                                      ((op1 & 0xc7) == 0x05
+                                       && op1 != (4 << 3)));
+      memcpy(view - 3, "\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12);
+    }
+  else
+    {
+      Target_i386::Relocate::check_tls(relinfo, relnum, rel,
+                                      (op1 & 0xf8) == 0x80 && (op1 & 7) != 4);
+      if (rel.get_r_offset() + 9 < view_size && view[9] == 0x90)
+       {
+         // There is a trailing nop.  Use the size byte subl.
+         memcpy(view - 2, "\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12);
+         roff = 6;
+       }
+      else
+       {
+         // Use the five byte subl.
+         memcpy(view - 2, "\x65\xa1\0\0\0\0\x2d\0\0\0", 11);
+       }
+    }
+
+  value = tls_segment->vaddr() + tls_segment->memsz() - value;
+  Relocate_functions<32, false>::rel32(view + roff, value);
+
+  // The next reloc should be a PLT32 reloc against __tls_get_addr.
+  // We can skip it.
+  this->skip_call_tls_get_addr_ = true;
+}
+
 // Check the range for a TLS relocation.
 
 inline void
@@ -724,8 +961,10 @@ Target_i386::relocate_section(const Relocate_info<32, false>* relinfo,
 {
   assert(sh_type == elfcpp::SHT_REL);
 
-  gold::relocate_section<32, false, elfcpp::SHT_REL, Target_i386::Relocate>(
+  gold::relocate_section<32, false, Target_i386, elfcpp::SHT_REL,
+                        Target_i386::Relocate>(
     relinfo,
+    this,
     prelocs,
     reloc_count,
     view,
@@ -733,10 +972,6 @@ Target_i386::relocate_section(const Relocate_info<32, false>* relinfo,
     view_size);
 }
 
-// The i386 target.
-
-Target_i386 target_i386;
-
 // The selector for i386 object files.
 
 class Target_selector_i386 : public Target_selector
@@ -747,16 +982,21 @@ public:
   { }
 
   Target*
-  recognize(int machine, int osabi, int abiversion) const;
+  recognize(int machine, int osabi, int abiversion);
+
+ private:
+  Target_i386* target_;
 };
 
 // Recognize an i386 object file when we already know that the machine
 // number is EM_386.
 
 Target*
-Target_selector_i386::recognize(int, int, int) const
+Target_selector_i386::recognize(int, int, int)
 {
-  return &target_i386;
+  if (this->target_ == NULL)
+    this->target_ = new Target_i386();
+  return this->target_;
 }
 
 Target_selector_i386 target_selector_i386;
index a81fd43..9e85f19 100644 (file)
@@ -38,7 +38,7 @@ Layout_task_runner::run(Workqueue* workqueue)
 // Layout methods.
 
 Layout::Layout(const General_options& options)
-  : options_(options), last_shndx_(0), namepool_(), sympool_(), signatures_(),
+  : options_(options), namepool_(), sympool_(), signatures_(),
     section_name_map_(), segment_list_(), section_list_(),
     special_output_list_(), tls_segment_(NULL)
 {
@@ -86,66 +86,114 @@ Layout::include_section(Object*, const char*,
     }
 }
 
-// Return the output section to use for input section NAME, with
-// header HEADER, from object OBJECT.  Set *OFF to the offset of this
-// input section without the output section.
+// Return an output section named NAME, or NULL if there is none.
 
-template<int size, bool big_endian>
 Output_section*
-Layout::layout(Object* object, const char* name,
-              const elfcpp::Shdr<size, big_endian>& shdr, off_t* off)
+Layout::find_output_section(const char* name) const
 {
-  // We discard empty input sections.
-  if (shdr.get_sh_size() == 0)
-    return NULL;
-
-  if (!this->include_section(object, name, shdr))
-    return NULL;
-
-  // Unless we are doing a relocateable link, .gnu.linkonce sections
-  // are laid out as though they were named for the sections are
-  // placed into.
-  if (!this->options_.is_relocatable() && Layout::is_linkonce(name))
-    name = Layout::linkonce_output_name(name);
+  for (Section_name_map::const_iterator p = this->section_name_map_.begin();
+       p != this->section_name_map_.end();
+       ++p)
+    if (strcmp(p->first.first, name) == 0)
+      return p->second;
+  return NULL;
+}
 
-  // FIXME: Handle SHF_OS_NONCONFORMING here.
+// Return an output segment of type TYPE, with segment flags SET set
+// and segment flags CLEAR clear.  Return NULL if there is none.
 
-  // Canonicalize the section name.
-  name = this->namepool_.add(name);
+Output_segment*
+Layout::find_output_segment(elfcpp::PT type, elfcpp::Elf_Word set,
+                           elfcpp::Elf_Word clear) const
+{
+  for (Segment_list::const_iterator p = this->segment_list_.begin();
+       p != this->segment_list_.end();
+       ++p)
+    if (static_cast<elfcpp::PT>((*p)->type()) == type
+       && ((*p)->flags() & set) == set
+       && ((*p)->flags() & clear) == 0)
+      return *p;
+  return NULL;
+}
 
-  // Find the output section.  The output section is selected based on
-  // the section name, type, and flags.
+// Return the output section to use for section NAME with type TYPE
+// and section flags FLAGS.
 
-  // FIXME: If we want to do relaxation, we need to modify this
-  // algorithm.  We also build a list of input sections for each
-  // output section.  Then we relax all the input sections.  Then we
-  // walk down the list and adjust all the offsets.
+Output_section*
+Layout::get_output_section(const char* name, elfcpp::Elf_Word type,
+                          elfcpp::Elf_Xword flags)
+{
+  // We should ignore some flags.
+  flags &= ~ (elfcpp::SHF_INFO_LINK
+             | elfcpp::SHF_LINK_ORDER
+             | elfcpp::SHF_GROUP);
 
-  elfcpp::Elf_Word type = shdr.get_sh_type();
-  elfcpp::Elf_Xword flags = shdr.get_sh_flags();
   const Key key(name, std::make_pair(type, flags));
   const std::pair<Key, Output_section*> v(key, NULL);
   std::pair<Section_name_map::iterator, bool> ins(
     this->section_name_map_.insert(v));
 
-  Output_section* os;
   if (!ins.second)
-    os = ins.first->second;
+    return ins.first->second;
   else
     {
       // This is the first time we've seen this name/type/flags
       // combination.
-      os = this->make_output_section(name, type, flags);
+      Output_section* os = this->make_output_section(name, type, flags);
       ins.first->second = os;
+      return os;
     }
+}
+
+// Return the output section to use for input section SHNDX, with name
+// NAME, with header HEADER, from object OBJECT.  Set *OFF to the
+// offset of this input section without the output section.
+
+template<int size, bool big_endian>
+Output_section*
+Layout::layout(Object* object, unsigned int shndx, const char* name,
+              const elfcpp::Shdr<size, big_endian>& shdr, off_t* off)
+{
+  if (!this->include_section(object, name, shdr))
+    return NULL;
+
+  // If we are not doing a relocateable link, choose the name to use
+  // for the output section.
+  size_t len = strlen(name);
+  if (!this->options_.is_relocatable())
+    name = Layout::output_section_name(name, &len);
+
+  // FIXME: Handle SHF_OS_NONCONFORMING here.
+
+  // Canonicalize the section name.
+  name = this->namepool_.add(name, len);
+
+  // Find the output section.  The output section is selected based on
+  // the section name, type, and flags.
+  Output_section* os = this->get_output_section(name, shdr.get_sh_type(),
+                                               shdr.get_sh_flags());
 
   // FIXME: Handle SHF_LINK_ORDER somewhere.
 
-  *off = os->add_input_section(object, name, shdr);
+  *off = os->add_input_section(object, shndx, name, shdr);
 
   return os;
 }
 
+// Add POSD to an output section using NAME, TYPE, and FLAGS.
+
+void
+Layout::add_output_section_data(const char* name, elfcpp::Elf_Word type,
+                               elfcpp::Elf_Xword flags,
+                               Output_section_data* posd)
+{
+  // Canonicalize the name.
+  name = this->namepool_.add(name);
+
+  Output_section* os = this->get_output_section(name, type, flags);
+  os->add_output_section_data(posd);
+}
+
 // Map section flags to segment flags.
 
 elfcpp::Elf_Word
@@ -166,9 +214,7 @@ Output_section*
 Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
                            elfcpp::Elf_Xword flags)
 {
-  ++this->last_shndx_;
-  Output_section* os = new Output_section(name, type, flags,
-                                         this->last_shndx_);
+  Output_section* os = new Output_section(name, type, flags, true);
 
   if ((flags & elfcpp::SHF_ALLOC) == 0)
     this->section_list_.push_back(os);
@@ -339,8 +385,14 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
   load_seg->add_initial_output_data(file_header);
   this->special_output_list_.push_back(file_header);
 
-  // Set the file offsets of all the segments.
-  off_t off = this->set_segment_offsets(input_objects->target(), load_seg);
+  // We set the output section indexes in set_segment_offsets and
+  // set_section_offsets.
+  unsigned int shndx = 1;
+
+  // Set the file offsets of all the segments, and all the sections
+  // they contain.
+  off_t off = this->set_segment_offsets(input_objects->target(), load_seg,
+                                       &shndx);
 
   // Create the symbol table sections.
   // FIXME: We don't need to do this if we are stripping symbols.
@@ -354,7 +406,10 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
 
   // Set the file offsets of all the sections not associated with
   // segments.
-  off = this->set_section_offsets(off);
+  off = this->set_section_offsets(off, &shndx);
+
+  // Now the section index of OSTRTAB is set.
+  osymtab->set_link(ostrtab->out_shndx());
 
   // Create the section table header.
   Output_section_headers* oshdrs = this->create_shdrs(size, big_endian, &off);
@@ -450,12 +505,13 @@ Layout::segment_precedes(const Output_segment* seg1,
   return paddr1 < paddr2;
 }
 
-// Set the file offsets of all the segments.  They have all been
-// created.  LOAD_SEG must be be laid out first.  Return the offset of
-// the data to follow.
+// Set the file offsets of all the segments, and all the sections they
+// contain.  They have all been created.  LOAD_SEG must be be laid out
+// first.  Return the offset of the data to follow.
 
 off_t
-Layout::set_segment_offsets(const Target* target, Output_segment* load_seg)
+Layout::set_segment_offsets(const Target* target, Output_segment* load_seg,
+                           unsigned int *pshndx)
 {
   // Sort them into the final order.
   std::sort(this->segment_list_.begin(), this->segment_list_.end(),
@@ -489,16 +545,17 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg)
          uint64_t abi_pagesize = target->abi_pagesize();
          if (was_readonly && ((*p)->flags() & elfcpp::PF_W) != 0)
            {
-             uint64_t align = (*p)->max_data_align();
+             uint64_t align = (*p)->addralign();
 
-             addr = (addr + align - 1) & ~ (align - 1);
+             addr = align_address(addr, align);
              aligned_addr = addr;
              if ((addr & (abi_pagesize - 1)) != 0)
                addr = addr + abi_pagesize;
            }
 
+         unsigned int shndx_hold = *pshndx;
          off = orig_off + ((addr - orig_addr) & (abi_pagesize - 1));
-         uint64_t new_addr = (*p)->set_section_addresses(addr, &off);
+         uint64_t new_addr = (*p)->set_section_addresses(addr, &off, pshndx);
 
          // Now that we know the size of this segment, we may be able
          // to save a page in memory, at the cost of wasting some
@@ -519,10 +576,10 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg)
                      != (new_addr & ~ (common_pagesize - 1)))
                  && first_off + last_off <= common_pagesize)
                {
-                 addr = ((aligned_addr + common_pagesize - 1)
-                         & ~ (common_pagesize - 1));
+                 *pshndx = shndx_hold;
+                 addr = align_address(aligned_addr, common_pagesize);
                  off = orig_off + ((addr - orig_addr) & (abi_pagesize - 1));
-                 new_addr = (*p)->set_section_addresses(addr, &off);
+                 new_addr = (*p)->set_section_addresses(addr, &off, pshndx);
                }
            }
 
@@ -550,17 +607,17 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg)
 // segment.
 
 off_t
-Layout::set_section_offsets(off_t off)
+Layout::set_section_offsets(off_t off, unsigned int* pshndx)
 {
   for (Layout::Section_list::iterator p = this->section_list_.begin();
        p != this->section_list_.end();
        ++p)
     {
+      (*p)->set_out_shndx(*pshndx);
+      ++*pshndx;
       if ((*p)->offset() != -1)
        continue;
-      uint64_t addralign = (*p)->addralign();
-      if (addralign != 0)
-       off = (off + addralign - 1) & ~ (addralign - 1);
+      off = align_address(off, (*p)->addralign());
       (*p)->set_address(0, off);
       off += (*p)->data_size();
     }
@@ -592,7 +649,7 @@ Layout::create_symtab_sections(int size, const Input_objects* input_objects,
     abort();
 
   off_t off = *poff;
-  off = (off + align - 1) & ~ (align - 1);
+  off = align_address(off, align);
   off_t startoff = off;
 
   // Save space for the dummy symbol at the start of the section.  We
@@ -614,23 +671,18 @@ Layout::create_symtab_sections(int size, const Input_objects* input_objects,
 
   this->sympool_.set_string_offsets();
 
-  ++this->last_shndx_;
   const char* symtab_name = this->namepool_.add(".symtab");
   Output_section* osymtab = new Output_section_symtab(symtab_name,
-                                                     off - startoff,
-                                                     this->last_shndx_);
+                                                     off - startoff);
   this->section_list_.push_back(osymtab);
 
-  ++this->last_shndx_;
   const char* strtab_name = this->namepool_.add(".strtab");
   Output_section *ostrtab = new Output_section_strtab(strtab_name,
-                                                     &this->sympool_,
-                                                     this->last_shndx_);
+                                                     &this->sympool_);
   this->section_list_.push_back(ostrtab);
   this->special_output_list_.push_back(ostrtab);
 
   osymtab->set_address(0, startoff);
-  osymtab->set_link(ostrtab->shndx());
   osymtab->set_info(local_symcount);
   osymtab->set_entsize(symsize);
   osymtab->set_addralign(align);
@@ -654,10 +706,7 @@ Layout::create_shstrtab()
 
   this->namepool_.set_string_offsets();
 
-  ++this->last_shndx_;
-  Output_section* os = new Output_section_strtab(name,
-                                                &this->namepool_,
-                                                this->last_shndx_);
+  Output_section* os = new Output_section_strtab(name, &this->namepool_);
 
   this->section_list_.push_back(os);
   this->special_output_list_.push_back(os);
@@ -675,8 +724,7 @@ Layout::create_shdrs(int size, bool big_endian, off_t* poff)
   oshdrs = new Output_section_headers(size, big_endian, this->segment_list_,
                                      this->section_list_,
                                      &this->namepool_);
-  uint64_t addralign = oshdrs->addralign();
-  off_t off = (*poff + addralign - 1) & ~ (addralign - 1);
+  off_t off = align_address(*poff, oshdrs->addralign());
   oshdrs->set_address(0, off);
   off += oshdrs->data_size();
   *poff = off;
@@ -686,7 +734,7 @@ Layout::create_shdrs(int size, bool big_endian, off_t* poff)
 
 // The mapping of .gnu.linkonce section names to real section names.
 
-#define MAPPING_INIT(f, t) { f, sizeof(f) - 1, t }
+#define MAPPING_INIT(f, t) { f, sizeof(f) - 1, t, sizeof(t) - 1 }
 const Layout::Linkonce_mapping Layout::linkonce_mapping[] =
 {
   MAPPING_INIT("d.rel.ro", ".data.rel.ro"),    // Must be before "d".
@@ -713,10 +761,11 @@ const int Layout::linkonce_mapping_count =
 // Return the name of the output section to use for a .gnu.linkonce
 // section.  This is based on the default ELF linker script of the old
 // GNU linker.  For example, we map a name like ".gnu.linkonce.t.foo"
-// to ".text".
+// to ".text".  Set *PLEN to the length of the name.  *PLEN is
+// initialized to the length of NAME.
 
 const char*
-Layout::linkonce_output_name(const char* name)
+Layout::linkonce_output_name(const char* name, size_t *plen)
 {
   const char* s = name + sizeof(".gnu.linkonce") - 1;
   if (*s != '.')
@@ -726,11 +775,67 @@ Layout::linkonce_output_name(const char* name)
   for (int i = 0; i < linkonce_mapping_count; ++i, ++plm)
     {
       if (strncmp(s, plm->from, plm->fromlen) == 0 && s[plm->fromlen] == '.')
-       return plm->to;
+       {
+         *plen = plm->tolen;
+         return plm->to;
+       }
     }
   return name;
 }
 
+// Choose the output section name to use given an input section name.
+// Set *PLEN to the length of the name.  *PLEN is initialized to the
+// length of NAME.
+
+const char*
+Layout::output_section_name(const char* name, size_t* plen)
+{
+  if (Layout::is_linkonce(name))
+    {
+      // .gnu.linkonce sections are laid out as though they were named
+      // for the sections are placed into.
+      return Layout::linkonce_output_name(name, plen);
+    }
+
+  // If the section name has no '.', or only an initial '.', we use
+  // the name unchanged (i.e., ".text" is unchanged).
+
+  // Otherwise, if the section name does not include ".rel", we drop
+  // the last '.'  and everything that follows (i.e., ".text.XXX"
+  // becomes ".text").
+
+  // Otherwise, if the section name has zero or one '.' after the
+  // ".rel", we use the name unchanged (i.e., ".rel.text" is
+  // unchanged).
+
+  // Otherwise, we drop the last '.' and everything that follows
+  // (i.e., ".rel.text.XXX" becomes ".rel.text").
+
+  const char* s = name;
+  if (*s == '.')
+    ++s;
+  const char* sdot = strchr(s, '.');
+  if (sdot == NULL)
+    return name;
+
+  const char* srel = strstr(s, ".rel");
+  if (srel == NULL)
+    {
+      *plen = sdot - name;
+      return name;
+    }
+
+  sdot = strchr(srel + 1, '.');
+  if (sdot == NULL)
+    return name;
+  sdot = strchr(sdot + 1, '.');
+  if (sdot == NULL)
+    return name;
+
+  *plen = sdot - name;
+  return name;
+}
+
 // Record the signature of a comdat section, and return whether to
 // include it in the link.  If GROUP is true, this is a regular
 // section group.  If GROUP is false, this is a group signature
@@ -743,7 +848,7 @@ Layout::add_comdat(const char* signature, bool group)
 {
   std::string sig(signature);
   std::pair<Signatures::iterator, bool> ins(
-    this->signatures_.insert(std::make_pair(signature, group)));
+    this->signatures_.insert(std::make_pair(sig, group)));
 
   if (ins.second)
     {
@@ -851,22 +956,22 @@ Close_task_runner::run(Workqueue*)
 
 template
 Output_section*
-Layout::layout<32, false>(Object* object, const char* name,
+Layout::layout<32, false>(Object* object, unsigned int shndx, const char* name,
                          const elfcpp::Shdr<32, false>& shdr, off_t*);
 
 template
 Output_section*
-Layout::layout<32, true>(Object* object, const char* name,
+Layout::layout<32, true>(Object* object, unsigned int shndx, const char* name,
                         const elfcpp::Shdr<32, true>& shdr, off_t*);
 
 template
 Output_section*
-Layout::layout<64, false>(Object* object, const char* name,
+Layout::layout<64, false>(Object* object, unsigned int shndx, const char* name,
                          const elfcpp::Shdr<64, false>& shdr, off_t*);
 
 template
 Output_section*
-Layout::layout<64, true>(Object* object, const char* name,
+Layout::layout<64, true>(Object* object, unsigned int shndx, const char* name,
                         const elfcpp::Shdr<64, true>& shdr, off_t*);
 
 
index 4ec2a4a..c96d47d 100644 (file)
@@ -8,7 +8,6 @@
 #include <utility>
 #include <vector>
 
-#include "options.h"
 #include "workqueue.h"
 #include "object.h"
 #include "stringpool.h"
 namespace gold
 {
 
+class General_options;
 class Input_objects;
 class Symbol_table;
+class Output_section_data;
 class Output_section;
 class Output_section_symtab;
 class Output_section_headers;
@@ -63,15 +64,22 @@ class Layout
  public:
   Layout(const General_options& options);
 
-  // Given an input section named NAME with data in SHDR from the
-  // object file OBJECT, return the output section where this input
-  // section should go.  Set *OFFSET to the offset within the output
-  // section.
+  // Given an input section SHNDX, named NAME, with data in SHDR, from
+  // the object file OBJECT, return the output section where this
+  // input section should go.  Set *OFFSET to the offset within the
+  // output section.
   template<int size, bool big_endian>
   Output_section*
-  layout(Object *object, const char* name,
+  layout(Object *object, unsigned int shndx, const char* name,
         const elfcpp::Shdr<size, big_endian>& shdr, off_t* offset);
 
+  // Add an Output_section_data to the layout.  This is used for
+  // special sections like the GOT section.
+  void
+  add_output_section_data(const char* name, elfcpp::Elf_Word type,
+                         elfcpp::Elf_Xword flags,
+                         Output_section_data*);
+
   // Return the Stringpool used for symbol names.
   const Stringpool*
   sympool() const
@@ -104,6 +112,16 @@ class Layout
   void
   write_data(Output_file*) const;
 
+  // Return an output section named NAME, or NULL if there is none.
+  Output_section*
+  find_output_section(const char* name) const;
+
+  // Return an output segment of type TYPE, with segment flags SET set
+  // and segment flags CLEAR clear.  Return NULL if there is none.
+  Output_segment*
+  find_output_segment(elfcpp::PT type, elfcpp::Elf_Word set,
+                     elfcpp::Elf_Word clear) const;
+
   // The list of segments.
 
   typedef std::vector<Output_segment*> Segment_list;
@@ -126,6 +144,7 @@ class Layout
     const char* from;
     int fromlen;
     const char* to;
+    int tolen;
   };
   static const Linkonce_mapping linkonce_mapping[];
   static const int linkonce_mapping_count;
@@ -137,12 +156,12 @@ class Layout
 
   // Set the final file offsets of all the segments.
   off_t
-  set_segment_offsets(const Target*, Output_segment*);
+  set_segment_offsets(const Target*, Output_segment*, unsigned int* pshndx);
 
-  // Set the final file offsets of all the sections not associated
-  // with a segment.
+  // Set the final file offsets and section indices of all the
+  // sections not associated with a segment.
   off_t
-  set_section_offsets(off_t);
+  set_section_offsets(off_t, unsigned int *pshndx);
 
   // Create the output sections for the symbol table.
   void
@@ -164,10 +183,21 @@ class Layout
   include_section(Object* object, const char* name,
                  const elfcpp::Shdr<size, big_endian>&);
 
+  // Return the output section name to use given an input section
+  // name.  Set *PLEN to the length of the name.  *PLEN must be
+  // initialized to the length of NAME.
+  static const char*
+  output_section_name(const char* name, size_t* plen);
+
   // Return the output section name to use for a linkonce section
-  // name.
+  // name.  PLEN is as for output_section_name.
   static const char*
-  linkonce_output_name(const char* name);
+  linkonce_output_name(const char* name, size_t* plen);
+
+  // Return the output section for NAME, TYPE and FLAGS.
+  Output_section*
+  get_output_section(const char* name, elfcpp::Elf_Word type,
+                    elfcpp::Elf_Xword flags);
 
   // Create a new Output_section.
   Output_section*
@@ -210,8 +240,6 @@ class Layout
 
   // A reference to the options on the command line.
   const General_options& options_;
-  // The index of the last output section.
-  unsigned int last_shndx_;
   // The output section names.
   Stringpool namepool_;
   // The output symbol names.
@@ -308,6 +336,16 @@ class Close_task_runner : public Task_function_runner
   Output_file* of_;
 };
 
+// A small helper function to align an address.
+
+inline uint64_t
+align_address(uint64_t address, uint64_t addralign)
+{
+  if (addralign != 0)
+    address = (address + addralign - 1) &~ (addralign - 1);
+  return address;
+}
+
 } // End namespace gold.
 
 #endif // !defined(GOLD_LAYOUT_H)
index 5efb3cb..4e7f04c 100644 (file)
@@ -16,25 +16,6 @@ namespace gold
 
 // Class Object.
 
-const unsigned char*
-Object::get_view(off_t start, off_t size)
-{
-  return this->input_file_->file().get_view(start + this->offset_, size);
-}
-
-void
-Object::read(off_t start, off_t size, void* p)
-{
-  this->input_file_->file().read(start + this->offset_, size, p);
-}
-
-File_view*
-Object::get_lasting_view(off_t start, off_t size)
-{
-  return this->input_file_->file().get_lasting_view(start + this->offset_,
-                                                   size);
-}
-
 // Class Sized_object.
 
 template<int size, bool big_endian>
@@ -79,7 +60,7 @@ Sized_object<size, big_endian>::~Sized_object()
 // Read the section header for section SHNUM.
 
 template<int size, bool big_endian>
-const unsigned char*
+inline const unsigned char*
 Sized_object<size, big_endian>::section_header(unsigned int shnum)
 {
   assert(shnum < this->shnum());
@@ -328,6 +309,32 @@ Sized_object<size, big_endian>::include_section_group(
 
   const char* signature = psymnames + sym.get_st_name();
 
+  // It seems that some versions of gas will create a section group
+  // associated with a section symbol, and then fail to give a name to
+  // the section symbol.  In such a case, use the name of the section.
+  // FIXME.
+  if (signature[0] == '\0'
+      && sym.get_st_type() == elfcpp::STT_SECTION
+      && sym.get_st_shndx() < this->shnum())
+    {
+      typename This::Shdr shdrnames(this->section_header(this->shstrndx_));
+      const unsigned char* pnamesu = this->get_view(shdrnames.get_sh_offset(),
+                                                   shdrnames.get_sh_size());
+      const char* pnames = reinterpret_cast<const char*>(pnamesu);
+      
+      typename This::Shdr sechdr(this->section_header(sym.get_st_shndx()));
+      if (sechdr.get_sh_name() >= shdrnames.get_sh_size())
+       {
+         fprintf(stderr,
+                 _("%s: %s: bad section name offset for section %u: %lu\n"),
+                 program_name, this->name().c_str(), sym.get_st_shndx(),
+                 static_cast<unsigned long>(sechdr.get_sh_name()));
+         gold_exit(false);
+       }
+
+      signature = pnames + sechdr.get_sh_name();
+    }
+
   // Record this section group, and see whether we've already seen one
   // with the same signature.
   if (layout->add_comdat(signature, true))
@@ -446,7 +453,7 @@ Sized_object<size, big_endian>::do_layout(Layout* layout,
        }
 
       off_t offset;
-      Output_section* os = layout->layout(this, name, shdr, &offset);
+      Output_section* os = layout->layout(this, i, name, shdr, &offset);
 
       map_sections[i].output_section = os;
       map_sections[i].offset = offset;
@@ -514,7 +521,7 @@ Sized_object<size, big_endian>::do_finalize_local_symbols(off_t off,
       return off;
     }
 
-  off = (off + (size >> 3) - 1) & ~ ((off_t) (size >> 3) - 1);
+  off = align_address(off, size >> 3);
 
   this->local_symbol_offset_ = off;
 
@@ -587,6 +594,7 @@ Sized_object<size, big_endian>::do_finalize_local_symbols(off_t off,
            }
 
          this->values_[i] = (mo[shndx].output_section->address()
+                             + mo[shndx].offset
                              + sym.get_st_value());
        }
 
@@ -655,7 +663,7 @@ Sized_object<size, big_endian>::write_local_symbols(Output_file* of,
          assert(st_shndx < mo.size());
          if (mo[st_shndx].output_section == NULL)
            continue;
-         st_shndx = mo[st_shndx].output_section->shndx();
+         st_shndx = mo[st_shndx].output_section->out_shndx();
        }
 
       osym.put_st_name(sympool->get_offset(pnames + isym.get_st_name()));
index 49a1ce9..5e57039 100644 (file)
@@ -154,8 +154,8 @@ class Object
   // Scan the relocs and adjust the symbol table.
   void
   scan_relocs(const General_options& options, Symbol_table* symtab,
-             Read_relocs_data* rd)
-  { return this->do_scan_relocs(options, symtab, rd); }
+             Layout* layout, Read_relocs_data* rd)
+  { return this->do_scan_relocs(options, symtab, layout, rd); }
 
   // Initial local symbol processing: set the offset where local
   // symbol information will be stored; add local symbol names to
@@ -184,6 +184,14 @@ class Object
   inline Output_section*
   output_section(unsigned int shnum, off_t* poff);
 
+  // Set the offset of an input section within its output section.
+  void
+  set_section_offset(unsigned int shndx, off_t off)
+  {
+    assert(shndx < this->map_to_output_.size());
+    this->map_to_output_[shndx].offset = off;
+  }
+
   // Return the name of a section given a section index.  This is only
   // used for error messages.
   std::string
@@ -218,7 +226,8 @@ class Object
 
   // Scan the relocs--implemented by child class.
   virtual void
-  do_scan_relocs(const General_options&, Symbol_table*, Read_relocs_data*) = 0;
+  do_scan_relocs(const General_options&, Symbol_table*, Layout*,
+                Read_relocs_data*) = 0;
 
   // Lay out sections--implemented by child class.
   virtual void
@@ -250,7 +259,8 @@ class Object
 
   // Get a view into the underlying file.
   const unsigned char*
-  get_view(off_t start, off_t size);
+  get_view(off_t start, off_t size)
+  { return this->input_file_->file().get_view(start + this->offset_, size); }
 
   // Get the number of sections.
   unsigned int
@@ -269,11 +279,16 @@ class Object
 
   // Read data from the underlying file.
   void
-  read(off_t start, off_t size, void* p);
+  read(off_t start, off_t size, void* p)
+  { this->input_file_->file().read(start + this->offset_, size, p); }
 
   // Get a lasting view into the underlying file.
   File_view*
-  get_lasting_view(off_t start, off_t size);
+  get_lasting_view(off_t start, off_t size)
+  {
+    return this->input_file_->file().get_lasting_view(start + this->offset_,
+                                                     size);
+  }
 
   // Return the vector mapping input sections to output sections.
   std::vector<Map_to_output>&
@@ -353,7 +368,8 @@ class Sized_object : public Object
 
   // Scan the relocs and adjust the symbol table.
   void
-  do_scan_relocs(const General_options&, Symbol_table*, Read_relocs_data*);
+  do_scan_relocs(const General_options&, Symbol_table*, Layout*,
+                Read_relocs_data*);
 
   // Lay out the input sections.
   void
index 8e0465f..397259e 100644 (file)
@@ -89,6 +89,24 @@ library(int argc, char** argv, char* arg, gold::Command_line* cmdline)
   return cmdline->process_l_option(argc, argv, arg);
 }
 
+// Handle the special --start-group option.
+
+int
+start_group(int, char**, char* arg, gold::Command_line* cmdline)
+{
+  cmdline->start_group(arg);
+  return 1;
+}
+
+// Handle the special --end-group option.
+
+int
+end_group(int, char**, char* arg, gold::Command_line* cmdline)
+{
+  cmdline->end_group(arg);
+  return 1;
+}
+
 // Report usage information for ld --help, and exit.
 
 int
@@ -209,6 +227,10 @@ options::Command_line_options::options[] =
   SPECIAL('l', "library", N_("Search for library LIBNAME"),
          N_("-lLIBNAME --library LIBNAME"), TWO_DASHES,
          &library),
+  SPECIAL('(', "start-group", N_("Start a library search group"), NULL,
+         TWO_DASHES, &start_group),
+  SPECIAL(')', "end-group", N_("End a library search group"), NULL,
+         TWO_DASHES, &end_group),
   GENERAL_ARG('L', "library-path", N_("Add directory to search path"),
              N_("-L DIR, --library-path DIR"), TWO_DASHES,
              &General_options::add_to_search_path),
@@ -246,9 +268,10 @@ Position_dependent_options::Position_dependent_options()
 {
 }
 
-// Construct a Command_line.
+// Command_line options.
 
 Command_line::Command_line()
+  : options_(), position_options_(), inputs_(), in_group_(false)
 {
 }
 
@@ -266,8 +289,7 @@ Command_line::process(int argc, char** argv)
     {
       if (argv[i][0] != '-' || no_more_options)
        {
-         this->inputs_.push_back(Input_argument(argv[i], false,
-                                                this->position_options_));
+         this->add_file(argv[i], false);
          ++i;
          continue;
        }
@@ -385,6 +407,12 @@ Command_line::process(int argc, char** argv)
        }
     }
 
+  if (this->in_group_)
+    {
+      fprintf(stderr, _("%s: missing group end"), program_name);
+      this->usage();
+    }
+
   // FIXME: We should only do this when configured in native mode.
   this->options_.add_to_search_path("/lib");
   this->options_.add_to_search_path("/usr/lib");
@@ -416,6 +444,22 @@ Command_line::apply_option(const options::One_option& opt,
     }
 }
 
+// Add an input file or library.
+
+void
+Command_line::add_file(const char* name, bool is_lib)
+{
+  Input_file_argument file(name, is_lib, this->position_options_);
+  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);
+    }
+}
+
 // Handle the -l option, which requires special treatment.
 
 int
@@ -436,12 +480,36 @@ Command_line::process_l_option(int argc, char** argv, char* arg)
   else
     this->usage(_("missing argument"), arg);
 
-  this->inputs_.push_back(Input_argument(libname, true,
-                                        this->position_options_));
+  this->add_file(libname, true);
 
   return ret;
 }
 
+// Handle the --start-group option.
+
+void
+Command_line::start_group(const char* arg)
+{
+  if (this->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;
+}
+
+// Handle the --end-group option.
+
+void
+Command_line::end_group(const char* arg)
+{
+  if (!this->in_group_)
+    this->usage(_("group end without group start"), arg);
+  this->in_group_ = false;
+}
+
 // Report a usage error.  */
 
 void
index 7e890fa..3b54c49 100644 (file)
 #include <list>
 #include <string>
 #include <vector>
+#include <cassert>
 
 namespace gold
 {
 
 class Command_line;
+class Input_file_group;
 
 namespace options {
 
@@ -128,11 +130,15 @@ class Position_dependent_options
 
 // A single file or library argument from the command line.
 
-class Input_argument
+class Input_file_argument
 {
  public:
-  Input_argument(const char* name, bool is_lib,
-                const Position_dependent_options& options)
+  Input_file_argument()
+    : name_(NULL), is_lib_(false), options_()
+  { }
+
+  Input_file_argument(const char* name, bool is_lib,
+                     const Position_dependent_options& options)
     : name_(name), is_lib_(is_lib), options_(options)
   { }
 
@@ -154,9 +160,90 @@ class Input_argument
   Position_dependent_options options_;
 };
 
-// A list of input files.
-class Input_argument_list : public std::vector<Input_argument>
+// A file or library, or a group, from the command line.
+
+class Input_argument
+{
+ public:
+  // Create a file or library argument.
+  explicit Input_argument(Input_file_argument file)
+    : is_file_(true), file_(file), group_(NULL)
+  { }
+
+  // Create a group argument.
+  explicit Input_argument(Input_file_group* group)
+    : is_file_(false), group_(group)
+  { }
+
+  // Return whether this is a file.
+  bool
+  is_file() const
+  { return this->is_file_; }
+
+  // Return whether this is a group.
+  bool
+  is_group() const
+  { return !this->is_file_; }
+
+  // Return the information about the file.
+  const Input_file_argument&
+  file() const
+  {
+    assert(this->is_file_);
+    return this->file_;
+  }
+
+  // Return the information about the group.
+  const Input_file_group*
+  group() const
+  {
+    assert(!this->is_file_);
+    return this->group_;
+  }
+
+  Input_file_group*
+  group()
+  {
+    assert(!this->is_file_);
+    return this->group_;
+  }
+
+ private:
+  bool is_file_;
+  Input_file_argument file_;
+  Input_file_group* group_;
+};
+
+// A group from the command line.  This is a set of arguments within
+// --start-group ... --end-group.
+
+class Input_file_group
 {
+ public:
+  typedef std::vector<Input_argument> Files;
+  typedef Files::const_iterator const_iterator;
+
+  Input_file_group()
+    : files_()
+  { }
+
+  // Add a file to the end of the group.
+  void
+  add_file(const Input_file_argument& arg)
+  { this->files_.push_back(Input_argument(arg)); }
+
+  // Iterators to iterate over the group contents.
+
+  const_iterator
+  begin() const
+  { return this->files_.begin(); }
+
+  const_iterator
+  end() const
+  { return this->files_.end(); }
+
+ private:
+  Files files_;
 };
 
 // All the information read from the command line.
@@ -164,6 +251,9 @@ class Input_argument_list : public std::vector<Input_argument>
 class Command_line
 {
  public:
+  typedef std::vector<Input_argument> Input_arguments;
+  typedef Input_arguments::const_iterator const_iterator;
+
   Command_line();
 
   // Process the command line options.  This will exit with an
@@ -175,25 +265,53 @@ class Command_line
   int
   process_l_option(int, char**, char*);
 
+  // Handle a --start-group option.
+  void
+  start_group(const char* arg);
+
+  // Handle a --end-group option.
+  void
+  end_group(const char* arg);
+
   // Get the general options.
   const General_options&
   options() const
   { return this->options_; }
 
-  // Get the list of input files.
-  const Input_argument_list&
-  inputs() const
-  { return this->inputs_; }
+  // Iterators to iterate over the list of input files.
+
+  const_iterator
+  begin() const
+  { return this->inputs_.begin(); }
+
+  const_iterator
+  end() const
+  { return this->inputs_.end(); }
 
  private:
-  void usage() ATTRIBUTE_NORETURN;
-  void usage(const char* msg, const char* opt) ATTRIBUTE_NORETURN;
-  void usage(const char* msg, char opt) ATTRIBUTE_NORETURN;
-  void apply_option(const gold::options::One_option&, const char*);
+  Command_line(const Command_line&);
+  Command_line& operator=(const Command_line&);
+
+  // Report usage error.
+  void
+  usage() ATTRIBUTE_NORETURN;
+  void
+  usage(const char* msg, const char* opt) ATTRIBUTE_NORETURN;
+  void
+  usage(const char* msg, char opt) ATTRIBUTE_NORETURN;
+
+  // Apply a command line option.
+  void
+  apply_option(const gold::options::One_option&, const char*);
+
+  // Add a file.
+  void
+  add_file(const char* name, bool is_lib);
 
   General_options options_;
   Position_dependent_options position_options_;
-  Input_argument_list inputs_;
+  Input_arguments inputs_;
+  bool in_group_;
 };
 
 } // End namespace gold.
index 82e2ca5..703a560 100644 (file)
@@ -10,6 +10,8 @@
 #include <algorithm>
 
 #include "object.h"
+#include "symtab.h"
+#include "reloc.h"
 #include "output.h"
 
 namespace gold
@@ -74,7 +76,8 @@ Output_section_headers::Output_section_headers(
   for (Layout::Segment_list::const_iterator p = segment_list.begin();
        p != segment_list.end();
        ++p)
-    count += (*p)->output_section_count();
+    if ((*p)->type() == elfcpp::PT_LOAD)
+      count += (*p)->output_section_count();
   count += section_list.size();
 
   int shdr_size;
@@ -137,18 +140,22 @@ Output_section_headers::do_sized_write(Output_file* of)
 
   v += shdr_size;
 
+  unsigned shndx = 1;
   for (Layout::Segment_list::const_iterator p = this->segment_list_.begin();
        p != this->segment_list_.end();
        ++p)
     v = (*p)->write_section_headers SELECT_SIZE_ENDIAN_NAME (
-      this->secnamepool_, v SELECT_SIZE_ENDIAN(size, big_endian));
+           this->secnamepool_, v, &shndx
+           SELECT_SIZE_ENDIAN(size, big_endian));
   for (Layout::Section_list::const_iterator p = this->section_list_.begin();
        p != this->section_list_.end();
        ++p)
     {
+      assert(shndx == (*p)->out_shndx());
       elfcpp::Shdr_write<size, big_endian> oshdr(v);
       (*p)->write_header(this->secnamepool_, &oshdr);
       v += shdr_size;
+      ++shndx;
     }
 
   of->write_output_view(this->offset(), all_shdrs_size, view);
@@ -318,6 +325,7 @@ Output_file_header::do_sized_write(Output_file* of)
   oehdr.put_e_machine(this->target_->machine_code());
   oehdr.put_e_version(elfcpp::EV_CURRENT);
 
+  // FIXME: Need to support -e, and target specific entry symbol.
   Symbol* sym = this->symtab_->lookup("_start");
   typename Sized_symbol<size>::Value_type v;
   if (sym == NULL)
@@ -344,17 +352,137 @@ Output_file_header::do_sized_write(Output_file* of)
   oehdr.put_e_shentsize(elfcpp::Elf_sizes<size>::shdr_size);
   oehdr.put_e_shnum(this->section_header_->data_size()
                     / elfcpp::Elf_sizes<size>::shdr_size);
-  oehdr.put_e_shstrndx(this->shstrtab_->shndx());
+  oehdr.put_e_shstrndx(this->shstrtab_->out_shndx());
 
   of->write_output_view(0, ehdr_size, view);
 }
 
+// Output_section_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)
+    const
+{
+  Valtype val = 0;
+
+  switch (this->local_sym_index_)
+    {
+    case GSYM_CODE:
+      {
+       Symbol* gsym = this->u_.gsym;
+
+       // If the symbol is resolved locally, we need to write out its
+       // value.  Otherwise we just write zero.  The target code is
+       // responsible for creating a relocation entry to fill in the
+       // value at runtime.
+       if (gsym->is_resolved_locally())
+         {
+           Sized_symbol<size>* sgsym;
+           // This cast is a bit ugly.  We don't want to put a
+           // virtual method in Symbol, because we want Symbol to be
+           // as small as possible.
+           sgsym = static_cast<Sized_symbol<size>*>(gsym);
+           val = sgsym->value();
+         }
+      }
+      break;
+
+    case CONSTANT_CODE:
+      val = this->u_.constant;
+      break;
+
+    default:
+      abort();
+    }
+
+  Valtype* povv = reinterpret_cast<Valtype*>(pov);
+  Swap<size, big_endian>::writeval(povv, val);
+}
+
+// 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_section_got methods.
+
+// Write out the GOT.
+
+template<int size, bool big_endian>
+void
+Output_section_got<size, big_endian>::do_write(Output_file* of)
+{
+  const int add = size / 8;
+
+  const off_t off = this->offset();
+  const off_t oview_size = this->entries_.size() * add;
+  unsigned char* const oview = of->get_output_view(off, oview_size);
+
+  unsigned char* pov = oview;
+  for (typename Got_entries::const_iterator p = this->entries_.begin();
+       p != this->entries_.end();
+       ++p)
+    {
+      p->write(pov);
+      pov += add;
+    }
+
+  of->write_output_view(off, oview_size, oview);
+
+  // We no longer need the GOT entries.
+  this->entries_.clear();
+}
+
+// Output_section::Input_section methods.
+
+// Return the data size.  For an input section we store the size here.
+// For an Output_section_data, we have to ask it for the size.
+
+off_t
+Output_section::Input_section::data_size() const
+{
+  if (this->is_input_section())
+    return this->data_size_;
+  else
+    return this->u_.posd->data_size();
+}
+
+// Set the address and file offset.
+
+void
+Output_section::Input_section::set_address(uint64_t addr, off_t off,
+                                          off_t secoff)
+{
+  if (this->is_input_section())
+    this->u_.object->set_section_offset(this->shndx_, off - secoff);
+  else
+    this->u_.posd->set_address(addr, off);
+}
+
+// Write out the data.  We don't have to do anything for an input
+// section--they are handled via Object::relocate--but this is where
+// we write out the data for an Output_section_data.
+
+void
+Output_section::Input_section::write(Output_file* of)
+{
+  if (!this->is_input_section())
+    this->u_.posd->write(of);
+}
+
 // Output_section methods.
 
 // Construct an Output_section.  NAME will point into a Stringpool.
 
 Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
-                              elfcpp::Elf_Xword flags, unsigned int shndx)
+                              elfcpp::Elf_Xword flags, bool may_add_data)
   : name_(name),
     addralign_(0),
     entsize_(0),
@@ -362,7 +490,10 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
     info_(0),
     type_(type),
     flags_(flags),
-    shndx_(shndx)
+    out_shndx_(0),
+    input_sections_(),
+    first_input_offset_(0),
+    may_add_data_(may_add_data)
 {
 }
 
@@ -370,15 +501,20 @@ Output_section::~Output_section()
 {
 }
 
-// Add an input section to an Output_section.  We don't keep track of
+// Add the input section SHNDX, with header SHDR, named SECNAME, in
+// OBJECT, to the Output_section.  Return the offset of the input
+// section within the output section.  We don't always keep track of
 // input sections for an Output_section.  Instead, each Object keeps
 // track of the Output_section for each of its input sections.
 
 template<int size, bool big_endian>
 off_t
-Output_section::add_input_section(Object* object, const char* secname,
+Output_section::add_input_section(Object* object, unsigned int shndx,
+                                 const char* secname,
                                  const elfcpp::Shdr<size, big_endian>& shdr)
 {
+  assert(this->may_add_data_);
+
   elfcpp::Elf_Xword addralign = shdr.get_sh_addralign();
   if ((addralign & (addralign - 1)) != 0)
     {
@@ -392,19 +528,56 @@ Output_section::add_input_section(Object* object, const char* secname,
     this->addralign_ = addralign;
 
   off_t ssize = this->data_size();
-  ssize = (ssize + addralign - 1) &~ (addralign - 1);
+  ssize = align_address(ssize, addralign);
+  this->set_data_size(ssize + shdr.get_sh_size());
 
-  // SHF_TLS/SHT_NOBITS sections are handled specially: they are
-  // treated as having no size and taking up no space.  We only use
-  // the real size when setting the pt_memsz field of the PT_TLS
-  // segment.
-  if ((this->flags_ & elfcpp::SHF_TLS) == 0
-      || this->type_ != elfcpp::SHT_NOBITS)
-    this->set_data_size(ssize + shdr.get_sh_size());
+  // We need to keep track of this section if we are already keeping
+  // track of sections, or if we are relaxing.  FIXME: Add test for
+  // relaxing.
+  if (! this->input_sections_.empty())
+    this->input_sections_.push_back(Input_section(object, shndx,
+                                                 shdr.get_sh_size(),
+                                                 addralign));
 
   return ssize;
 }
 
+// Add arbitrary data to an output section.
+
+void
+Output_section::add_output_section_data(Output_section_data* posd)
+{
+  if (this->input_sections_.empty())
+    this->first_input_offset_ = this->data_size();
+  this->input_sections_.push_back(Input_section(posd));
+  uint64_t addralign = posd->addralign();
+  if (addralign > this->addralign_)
+    this->addralign_ = addralign;
+  posd->set_output_section(this);
+}
+
+// Set the address of an Output_section.  This is where we handle
+// setting the addresses of any Output_section_data objects.
+
+void
+Output_section::do_set_address(uint64_t address, off_t startoff)
+{
+  if (this->input_sections_.empty())
+    return;
+
+  off_t off = startoff + this->first_input_offset_;
+  for (Input_section_list::iterator p = this->input_sections_.begin();
+       p != this->input_sections_.end();
+       ++p)
+    {
+      off = align_address(off, p->addralign());
+      p->set_address(address + (off - startoff), off, startoff);
+      off += p->data_size();
+    }
+
+  this->set_data_size(off - startoff);
+}
+
 // Write the section header to *OSHDR.
 
 template<int size, bool big_endian>
@@ -424,11 +597,23 @@ Output_section::write_header(const Stringpool* secnamepool,
   oshdr->put_sh_entsize(this->entsize_);
 }
 
+// Write out the data.  For input sections the data is written out by
+// Object::relocate, but we have to handle Output_section_data objects
+// here.
+
+void
+Output_section::do_write(Output_file* of)
+{
+  for (Input_section_list::iterator p = this->input_sections_.begin();
+       p != this->input_sections_.end();
+       ++p)
+    p->write(of);
+}
+
 // Output_section_symtab methods.
 
-Output_section_symtab::Output_section_symtab(const char* name, off_t size,
-                                            unsigned int shndx)
-  : Output_section(name, elfcpp::SHT_SYMTAB, 0, shndx)
+Output_section_symtab::Output_section_symtab(const char* name, off_t size)
+  : Output_section(name, elfcpp::SHT_SYMTAB, 0, false)
 {
   this->set_data_size(size);
 }
@@ -436,9 +621,8 @@ Output_section_symtab::Output_section_symtab(const char* name, off_t size,
 // Output_section_strtab methods.
 
 Output_section_strtab::Output_section_strtab(const char* name,
-                                            Stringpool* contents,
-                                            unsigned int shndx)
-  : Output_section(name, elfcpp::SHT_STRTAB, 0, shndx),
+                                            Stringpool* contents)
+  : Output_section(name, elfcpp::SHT_STRTAB, 0, false),
     contents_(contents)
 {
   this->set_data_size(contents->get_strtab_size());
@@ -462,7 +646,8 @@ Output_segment::Output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags)
     offset_(0),
     filesz_(0),
     type_(type),
-    flags_(flags)
+    flags_(flags),
+    is_align_known_(false)
 {
 }
 
@@ -473,12 +658,10 @@ Output_segment::add_output_section(Output_section* os,
                                   elfcpp::Elf_Word seg_flags)
 {
   assert((os->flags() & elfcpp::SHF_ALLOC) != 0);
+  assert(!this->is_align_known_);
 
-  // Update the segment flags and alignment.
+  // Update the segment flags.
   this->flags_ |= seg_flags;
-  uint64_t addralign = os->addralign();
-  if (addralign > this->align_)
-    this->align_ = addralign;
 
   Output_segment::Output_data_list* pdl;
   if (os->type() == elfcpp::SHT_NOBITS)
@@ -524,12 +707,28 @@ Output_segment::add_output_section(Output_section* os,
     {
       pdl = &this->output_data_;
       bool nobits = os->type() == elfcpp::SHT_NOBITS;
+      bool sawtls = false;
       Layout::Data_list::iterator p = pdl->end();
       do
        {
          --p;
-         if ((*p)->is_section_flag_set(elfcpp::SHF_TLS)
-             && (nobits || !(*p)->is_section_type(elfcpp::SHT_NOBITS)))
+         bool insert;
+         if ((*p)->is_section_flag_set(elfcpp::SHF_TLS))
+           {
+             sawtls = true;
+             // Put a NOBITS section after the first TLS section.
+             // But a PROGBITS section after the first TLS/PROGBITS
+             // section.
+             insert = nobits || !(*p)->is_section_type(elfcpp::SHT_NOBITS);
+           }
+         else
+           {
+             // If we've gone past the TLS sections, but we've seen a
+             // TLS section, then we need to insert this section now.
+             insert = sawtls;
+           }
+
+         if (insert)
            {
              ++p;
              pdl->insert(p, os);
@@ -537,6 +736,9 @@ 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.
     }
 
   pdl->push_back(os);
@@ -548,28 +750,59 @@ Output_segment::add_output_section(Output_section* os,
 void
 Output_segment::add_initial_output_data(Output_data* od)
 {
-  uint64_t addralign = od->addralign();
-  if (addralign > this->align_)
-    this->align_ = addralign;
-
+  assert(!this->is_align_known_);
   this->output_data_.push_front(od);
 }
 
 // Return the maximum alignment of the Output_data in Output_segment.
-// We keep this up to date as we add Output_sections and Output_data.
+// Once we compute this, we prohibit new sections from being added.
 
 uint64_t
-Output_segment::max_data_align() const
+Output_segment::addralign()
 {
+  if (!this->is_align_known_)
+    {
+      uint64_t addralign;
+
+      addralign = Output_segment::maximum_alignment(&this->output_data_);
+      if (addralign > this->align_)
+       this->align_ = addralign;
+
+      addralign = Output_segment::maximum_alignment(&this->output_bss_);
+      if (addralign > this->align_)
+       this->align_ = addralign;
+
+      this->is_align_known_ = true;
+    }
+
   return this->align_;
 }
 
+// Return the maximum alignment of a list of Output_data.
+
+uint64_t
+Output_segment::maximum_alignment(const Output_data_list* pdl)
+{
+  uint64_t ret = 0;
+  for (Output_data_list::const_iterator p = pdl->begin();
+       p != pdl->end();
+       ++p)
+    {
+      uint64_t addralign = (*p)->addralign();
+      if (addralign > ret)
+       ret = addralign;
+    }
+  return ret;
+}
+
 // Set the section addresses for an Output_segment.  ADDR is the
-// address and *POFF is the file offset.  Return the address of the
-// immediately following segment.  Update *POFF.
+// address and *POFF is the file offset.  Set the section indexes
+// starting with *PSHNDX.  Return the address of the immediately
+// following segment.  Update *POFF and *PSHNDX.
 
 uint64_t
-Output_segment::set_section_addresses(uint64_t addr, off_t* poff)
+Output_segment::set_section_addresses(uint64_t addr, off_t* poff,
+                                     unsigned int* pshndx)
 {
   assert(this->type_ == elfcpp::PT_LOAD);
 
@@ -579,13 +812,16 @@ Output_segment::set_section_addresses(uint64_t addr, off_t* poff)
   off_t orig_off = *poff;
   this->offset_ = orig_off;
 
-  addr = this->set_section_list_addresses(&this->output_data_, addr, poff);
+  *poff = align_address(*poff, this->addralign());
+
+  addr = this->set_section_list_addresses(&this->output_data_, addr, poff,
+                                         pshndx);
   this->filesz_ = *poff - orig_off;
 
   off_t off = *poff;
 
   uint64_t ret = this->set_section_list_addresses(&this->output_bss_, addr,
-                                                 poff);
+                                                 poff, pshndx);
   this->memsz_ = *poff - orig_off;
 
   // Ignore the file offset adjustments made by the BSS Output_data
@@ -599,26 +835,36 @@ Output_segment::set_section_addresses(uint64_t addr, off_t* poff)
 
 uint64_t
 Output_segment::set_section_list_addresses(Output_data_list* pdl,
-                                          uint64_t addr, off_t* poff)
+                                          uint64_t addr, off_t* poff,
+                                          unsigned int* pshndx)
 {
-  off_t off = *poff;
+  off_t startoff = *poff;
 
+  off_t off = startoff;
   for (Output_data_list::iterator p = pdl->begin();
        p != pdl->end();
        ++p)
     {
-      uint64_t addralign = (*p)->addralign();
-      addr = (addr + addralign - 1) & ~ (addralign - 1);
-      off = (off + addralign - 1) & ~ (addralign - 1);
-      (*p)->set_address(addr, off);
+      off = align_address(off, (*p)->addralign());
+      (*p)->set_address(addr + (off - startoff), off);
+
+      // Unless this is a PT_TLS segment, we want to ignore the size
+      // of a SHF_TLS/SHT_NOBITS section.  Such a section does not
+      // affect the size of a PT_LOAD segment.
+      if (this->type_ == elfcpp::PT_TLS
+         || !(*p)->is_section_flag_set(elfcpp::SHF_TLS)
+         || !(*p)->is_section_type(elfcpp::SHT_NOBITS))
+       off += (*p)->data_size();
 
-      uint64_t size = (*p)->data_size();
-      addr += size;
-      off += size;
+      if ((*p)->is_section())
+       {
+         (*p)->set_out_shndx(*pshndx);
+         ++*pshndx;
+       }
     }
 
   *poff = off;
-  return addr;
+  return addr + (off - startoff);
 }
 
 // For a non-PT_LOAD segment, set the offset from the sections, if
@@ -667,8 +913,6 @@ Output_segment::set_offset()
   this->memsz_ = (last->address()
                  + last->data_size()
                  - this->vaddr_);
-
-  // this->align_ was set as we added items.
 }
 
 // Return the number of Output_sections in an Output_segment.
@@ -700,7 +944,7 @@ Output_segment::output_section_count_list(const Output_data_list* pdl) const
 
 template<int size, bool big_endian>
 void
-Output_segment::write_header(elfcpp::Phdr_write<size, big_endian>* ophdr) const
+Output_segment::write_header(elfcpp::Phdr_write<size, big_endian>* ophdr)
 {
   ophdr->put_p_type(this->type_);
   ophdr->put_p_offset(this->offset_);
@@ -709,7 +953,7 @@ Output_segment::write_header(elfcpp::Phdr_write<size, big_endian>* ophdr) const
   ophdr->put_p_filesz(this->filesz_);
   ophdr->put_p_memsz(this->memsz_);
   ophdr->put_p_flags(this->flags_);
-  ophdr->put_p_align(this->align_);
+  ophdr->put_p_align(this->addralign());
 }
 
 // Write the section headers into V.
@@ -717,13 +961,22 @@ Output_segment::write_header(elfcpp::Phdr_write<size, big_endian>* ophdr) const
 template<int size, bool big_endian>
 unsigned char*
 Output_segment::write_section_headers(const Stringpool* secnamepool,
-                                     unsigned char* v
+                                     unsigned char* v,
+                                     unsigned int *pshndx
                                       ACCEPT_SIZE_ENDIAN) const
 {
+  // Every section that is attached to a segment must be attached to a
+  // PT_LOAD segment, so we only write out section headers for PT_LOAD
+  // segments.
+  if (this->type_ != elfcpp::PT_LOAD)
+    return v;
+
   v = this->write_section_headers_list SELECT_SIZE_ENDIAN_NAME (
-    secnamepool, &this->output_data_, v SELECT_SIZE_ENDIAN(size, big_endian));
+       secnamepool, &this->output_data_, v, pshndx
+       SELECT_SIZE_ENDIAN(size, big_endian));
   v = this->write_section_headers_list SELECT_SIZE_ENDIAN_NAME (
-    secnamepool, &this->output_bss_, v SELECT_SIZE_ENDIAN(size, big_endian));
+       secnamepool, &this->output_bss_, v, pshndx
+       SELECT_SIZE_ENDIAN(size, big_endian));
   return v;
 }
 
@@ -731,7 +984,8 @@ template<int size, bool big_endian>
 unsigned char*
 Output_segment::write_section_headers_list(const Stringpool* secnamepool,
                                           const Output_data_list* pdl,
-                                          unsigned char* v
+                                          unsigned char* v,
+                                          unsigned int* pshndx
                                            ACCEPT_SIZE_ENDIAN) const
 {
   const int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
@@ -742,9 +996,11 @@ Output_segment::write_section_headers_list(const Stringpool* secnamepool,
       if ((*p)->is_section())
        {
          const Output_section* ps = static_cast<const Output_section*>(*p);
+         assert(*pshndx == ps->out_shndx());
          elfcpp::Shdr_write<size, big_endian> oshdr(v);
          ps->write_header(secnamepool, &oshdr);
          v += shdr_size;
+         ++*pshndx;
        }
     }
   return v;
@@ -834,6 +1090,7 @@ template
 off_t
 Output_section::add_input_section<32, false>(
     Object* object,
+    unsigned int shndx,
     const char* secname,
     const elfcpp::Shdr<32, false>& shdr);
 
@@ -841,6 +1098,7 @@ template
 off_t
 Output_section::add_input_section<32, true>(
     Object* object,
+    unsigned int shndx,
     const char* secname,
     const elfcpp::Shdr<32, true>& shdr);
 
@@ -848,6 +1106,7 @@ template
 off_t
 Output_section::add_input_section<64, false>(
     Object* object,
+    unsigned int shndx,
     const char* secname,
     const elfcpp::Shdr<64, false>& shdr);
 
@@ -855,7 +1114,24 @@ template
 off_t
 Output_section::add_input_section<64, true>(
     Object* object,
+    unsigned int shndx,
     const char* secname,
     const elfcpp::Shdr<64, true>& shdr);
 
+template
+void
+Output_section_got<32, false>::do_write(Output_file* of);
+
+template
+void
+Output_section_got<32, true>::do_write(Output_file* of);
+
+template
+void
+Output_section_got<64, false>::do_write(Output_file* of);
+
+template
+void
+Output_section_got<64, true>::do_write(Output_file* of);
+
 } // End namespace gold.
index e036b98..5c72c02 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <cassert>
 #include <list>
+#include <vector>
 
 #include "elfcpp.h"
 #include "layout.h"
@@ -31,17 +32,21 @@ class Output_data
   virtual
   ~Output_data();
 
-  // Return the address.
+  // Return the address.  This is only valid after Layout::finalize is
+  // finished.
   uint64_t
   address() const
   { return this->address_; }
 
-  // Return the size of the data.
+  // Return the size of the data.  This must be valid after
+  // Layout::finalize calls set_address, but need not be valid before
+  // then.
   off_t
   data_size() const
   { return this->data_size_; }
 
-  // Return the file offset.
+  // Return the file offset.  This is only valid after
+  // Layout::finalize is finished.
   off_t
   offset() const
   { return this->offset_; }
@@ -67,11 +72,23 @@ class Output_data
   is_section_flag_set(elfcpp::Elf_Xword shf) const
   { return this->do_is_section_flag_set(shf); }
 
-  // Set the address and file offset of this data.
+  // Return the output section index, if there is an output section.
+  unsigned int
+  out_shndx() const
+  { return this->do_out_shndx(); }
+
+  // Set the output section index, if this is an output section.
+  void
+  set_out_shndx(unsigned int shndx)
+  { this->do_set_out_shndx(shndx); }
+
+  // Set the address and file offset of this data.  This is called
+  // during Layout::finalize.
   void
   set_address(uint64_t addr, off_t off);
 
-  // Write the data to the output file.
+  // Write the data to the output file.  This is called after
+  // Layout::finalize is complete.
   void
   write(Output_file* file)
   { this->do_write(file); }
@@ -104,6 +121,16 @@ class Output_data
   do_is_section_flag_set(elfcpp::Elf_Xword) const
   { return false; }
 
+  // Return the output section index, if there is an output section.
+  virtual unsigned int
+  do_out_shndx() const
+  { abort(); }
+
+  // Set the output section index, if this is an output section.
+  virtual void
+  do_set_out_shndx(unsigned int)
+  { abort(); }
+
   // Set the address and file offset of the data.  This only needs to
   // be implemented if the child needs to know.
   virtual void
@@ -270,6 +297,198 @@ class Output_file_header : public Output_data
   const Output_section* shstrtab_;
 };
 
+// Output sections are mainly comprised of input sections.  However,
+// there are cases where we have data to write out which is not in an
+// input section.  Output_section_data is used in such cases.  This is
+// an abstract base class.
+
+class Output_section_data : public Output_data
+{
+ public:
+  Output_section_data(off_t data_size, uint64_t addralign)
+    : Output_data(data_size), output_section_(NULL), addralign_(addralign)
+  { }
+
+  Output_section_data(uint64_t addralign)
+    : Output_data(0), output_section_(NULL), addralign_(addralign)
+  { }
+
+  // Record the output section.
+  void
+  set_output_section(Output_section* os)
+  {
+    assert(this->output_section_ == NULL);
+    this->output_section_ = os;
+  }
+
+ protected:
+  // The child class must implement do_write.
+
+  // Return the required alignment.
+  uint64_t
+  do_addralign() const
+  { return this->addralign_; }
+
+  // Return the section index of the output section.
+  unsigned int
+  do_out_shndx() const;
+
+ private:
+  // The output section for this section.
+  const Output_section* output_section_;
+  // The required alignment.
+  uint64_t addralign_;
+};
+
+// Output_section_common is used to handle the common symbols.  This
+// is quite simple.
+
+class Output_section_common : public Output_section_data
+{
+ public:
+  Output_section_common(uint64_t addralign)
+    : Output_section_data(addralign)
+  { }
+
+  // Set the size.
+  void
+  set_common_size(off_t common_size)
+  { this->set_data_size(common_size); }
+
+  // Write out the data--there is nothing to do, as common symbols are
+  // always zero and are stored in the BSS.
+  void
+  do_write(Output_file*)
+  { }
+};
+
+// 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
+// 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.
+
+template<int size, bool big_endian>
+class Output_section_got : public Output_section_data
+{
+ public:
+  typedef typename elfcpp::Elf_types<size>::Elf_Addr Valtype;
+
+  Output_section_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 local symbol to the GOT.  This returns the
+  // offset of the new entry from the start of the GOT.
+  unsigned int
+  add_local(Object* object, unsigned int sym_index)
+  {
+    this->entries_.push_back(Got_entry(object, sym_index));
+    this->set_got_size();
+    return this->last_got_offset();
+  }
+
+  // Add a constant to the GOT.  This returns the offset of the new
+  // entry from the start of the GOT.
+  unsigned int
+  add_constant(Valtype constant)
+  {
+    this->entries_.push_back(Got_entry(constant));
+    this->set_got_size();
+    return this->last_got_offset();
+  }
+
+  // Write out the GOT table.
+  void
+  do_write(Output_file*);
+
+ private:
+  // This POD class holds a single GOT entry.
+  class Got_entry
+  {
+   public:
+    // Create a zero entry.
+    Got_entry()
+      : local_sym_index_(CONSTANT_CODE)
+    { this->u_.constant = 0; }
+
+    // Create a global symbol entry.
+    Got_entry(Symbol* gsym)
+      : local_sym_index_(GSYM_CODE)
+    { this->u_.gsym = gsym; }
+
+    // Create a local symbol entry.
+    Got_entry(Object* object, unsigned int local_sym_index)
+      : local_sym_index_(local_sym_index)
+    {
+      assert(local_sym_index != GSYM_CODE
+            && local_sym_index != CONSTANT_CODE);
+      this->u_.object = object;
+    }
+
+    // Create a constant entry.  The constant is a host value--it will
+    // be swapped, if necessary, when it is written out.
+    Got_entry(Valtype constant)
+      : local_sym_index_(CONSTANT_CODE)
+    { this->u_.constant = constant; }
+
+    // Write the GOT entry to an output view.
+    void
+    write(unsigned char* pov) const;
+
+   private:
+    enum
+    {
+      GSYM_CODE = -1U,
+      CONSTANT_CODE = -2U
+    };
+
+    union
+    {
+      // For a local symbol, the object.
+      Object* object;
+      // For a global symbol, the symbol.
+      Symbol* gsym;
+      // For a constant, the constant.
+      Valtype constant;
+    } u_;
+    // For a local symbol, the local symbol index.  This is -1U for a
+    // global symbol, or -2U for a constant.
+    unsigned int local_sym_index_;
+  };
+
+  typedef std::vector<Got_entry> Got_entries;
+
+  // Return the offset into the GOT of GOT entry I.
+  unsigned int
+  got_offset(unsigned int i) const
+  { return i * (size / 8); }
+
+  // Return the offset into the GOT of the last entry added.
+  unsigned int
+  last_got_offset() const
+  { return this->got_offset(this->entries_.size() - 1); }
+
+  // Set the size of the section.
+  void
+  set_got_size()
+  { this->set_data_size(this->got_offset(this->entries_.size())); }
+
+  // The list of GOT entries.
+  Got_entries entries_;
+};
+
 // An output section.  We don't expect to have too many output
 // sections, so we don't bother to do a template on the size.
 
@@ -278,16 +497,20 @@ class Output_section : public Output_data
  public:
   // Create an output section, giving the name, type, and flags.
   Output_section(const char* name, elfcpp::Elf_Word, elfcpp::Elf_Xword,
-                unsigned int shndx);
+                bool may_add_data);
   virtual ~Output_section();
 
-  // Add a new input section named NAME with header SHDR from object
-  // OBJECT.  Return the offset within the output section.
+  // Add a new input section SHNDX, named NAME, with header SHDR, from
+  // object OBJECT.  Return the offset within the output section.
   template<int size, bool big_endian>
   off_t
-  add_input_section(Object* object, const char *name,
+  add_input_section(Object* object, unsigned int shndx, const char *name,
                    const elfcpp::Shdr<size, big_endian>& shdr);
 
+  // Add generated data ODATA to this output section.
+  virtual void
+  add_output_section_data(Output_section_data* posd);
+
   // Return the section name.
   const char*
   name() const
@@ -303,15 +526,15 @@ class Output_section : public Output_data
   flags() const
   { return this->flags_; }
 
-  // Return the address alignment.
-  uint64_t
-  addralign() const
-  { return this->addralign_; }
-
-  // Return the section index.
+  // Return the section index in the output file.
   unsigned int
-  shndx() const
-  { return this->shndx_; }
+  do_out_shndx() const
+  { return this->out_shndx_; }
+
+  // Set the output section index.
+  void
+  do_set_out_shndx(unsigned int shndx)
+  { this->out_shndx_ = shndx; }
 
   // Set the entsize field.
   void
@@ -333,12 +556,19 @@ class Output_section : public Output_data
   set_addralign(uint64_t v)
   { this->addralign_ = v; }
 
+  // Set the address of the Output_section.  For a typical
+  // Output_section, there is nothing to do, but if there are any
+  // Output_section_data objects we need to set the final addresses
+  // here.
+  void
+  do_set_address(uint64_t, off_t);
+
   // Write the data to the file.  For a typical Output_section, this
-  // does nothing.  We write out the data by looping over all the
-  // input sections.
+  // does nothing: the data is written out by calling Object::Relocate
+  // on each input object.  But if there are any Output_section_data
+  // objects we do need to write them out here.
   virtual void
-  do_write(Output_file*)
-  { }
+  do_write(Output_file*);
 
   // Return the address alignment--function required by parent class.
   uint64_t
@@ -366,6 +596,83 @@ class Output_section : public Output_data
   write_header(const Stringpool*, elfcpp::Shdr_write<size, big_endian>*) const;
 
  private:
+  // In some cases we need to keep a list of the input sections
+  // associated with this output section.  We only need the list if we
+  // might have to change the offsets of the input section within the
+  // output section after we add the input section.  The ordinary
+  // input sections will be written out when we process the object
+  // file, and as such we don't need to track them here.  We do need
+  // to track Output_section_data objects here.  We store instances of
+  // this structure in a std::vector, so it must be a POD.  There can
+  // be many instances of this structure, so we use a union to save
+  // some space.
+  class Input_section
+  {
+   public:
+    Input_section()
+      : shndx_(0), p2align_(0), data_size_(0)
+    { this->u_.object = NULL; }
+
+    Input_section(Object* object, unsigned int shndx, off_t data_size,
+                 uint64_t addralign)
+      : shndx_(shndx),
+       p2align_(ffsll(static_cast<long long>(addralign))),
+       data_size_(data_size)
+    {
+      assert(shndx != -1U);
+      this->u_.object = object;
+    }
+
+    Input_section(Output_section_data* posd)
+      : shndx_(-1U),
+       p2align_(ffsll(static_cast<long long>(posd->addralign()))),
+       data_size_(0)
+    { this->u_.posd = posd; }
+
+    // The required alignment.
+    uint64_t
+    addralign() const
+    { return static_cast<uint64_t>(1) << this->p2align_; }
+
+    // Return the required size.
+    off_t
+    data_size() const;
+
+    // Set the address and file offset.  This is called during
+    // Layout::finalize.  SECOFF is the file offset of the enclosing
+    // section.
+    void
+    set_address(uint64_t addr, off_t off, off_t secoff);
+
+    // Write out the data.  This does nothing for an input section.
+    void
+    write(Output_file*);
+
+   private:
+    // Whether this is an input section.
+    bool
+    is_input_section() const
+    { return this->shndx_ != -1U; }
+
+    // For an ordinary input section, this is the section index in
+    // the input file.  For an Output_section_data, this is -1U.
+    unsigned int shndx_;
+    // The required alignment, stored as a power of 2.
+    unsigned int p2align_;
+    // For an ordinary input section, the section size.
+    off_t data_size_;
+    union
+    {
+      // If shndx_ != -1U, this points to the object which holds the
+      // input section.
+      Object* object;
+      // If shndx_ == -1U, this is the data to write out.
+      Output_section_data* posd;
+    } u_;
+  };
+
+  typedef std::vector<Input_section> Input_section_list;
+
   // Most of these fields are only valid after layout.
 
   // The name of the section.  This will point into a Stringpool.
@@ -385,16 +692,35 @@ class Output_section : public Output_data
   // The section flags.
   elfcpp::Elf_Xword flags_;
   // The section index.
-  unsigned int shndx_;
+  unsigned int out_shndx_;
+  // The input sections.  This will be empty in cases where we don't
+  // need to keep track of them.
+  Input_section_list input_sections_;
+  // The offset of the first entry in input_sections_.
+  off_t first_input_offset_;
+  // Whether we permit adding data.
+  bool may_add_data_;
 };
 
 // A special Output_section which represents the symbol table
-// (SHT_SYMTAB).
+// (SHT_SYMTAB).  The actual data is written out by
+// Symbol_table::write_globals.
 
 class Output_section_symtab : public Output_section
 {
  public:
-  Output_section_symtab(const char* name, off_t size, unsigned int shndx);
+  Output_section_symtab(const char* name, off_t size);
+
+  // The data is written out by Symbol_table::write_globals.  We don't
+  // do anything here.
+  void
+  do_write(Output_file*)
+  { }
+
+  // We don't expect to see any input sections or data here.
+  void
+  add_output_section_data(Output_section_data*)
+  { abort(); }
 };
 
 // A special Output_section which holds a string table.
@@ -402,13 +728,17 @@ class Output_section_symtab : public Output_section
 class Output_section_strtab : public Output_section
 {
  public:
-  Output_section_strtab(const char* name, Stringpool* contents,
-                       unsigned int shndx);
+  Output_section_strtab(const char* name, Stringpool* contents);
 
   // Write out the data.
   void
   do_write(Output_file*);
 
+  // We don't expect to see any input sections or data here.
+  void
+  add_output_section_data(Output_section_data*)
+  { abort(); }
+
  private:
   Stringpool* contents_;
 };
@@ -448,9 +778,14 @@ class Output_segment
   memsz() const
   { return this->memsz_; }
 
+  // Return the file size.
+  off_t
+  filesz() const
+  { return this->filesz_; }
+
   // Return the maximum alignment of the Output_data.
   uint64_t
-  max_data_align() const;
+  addralign();
 
   // Add an Output_section to this segment.
   void
@@ -463,11 +798,12 @@ class Output_segment
 
   // Set the address of the segment to ADDR and the offset to *POFF
   // (aligned if necessary), and set the addresses and offsets of all
-  // contained output sections accordingly.  Return the address of the
-  // immediately following segment.  Update *POFF.  This should only
-  // be called for a PT_LOAD segment.
+  // contained output sections accordingly.  Set the section indexes
+  // of all contained output sections starting with *PSHNDX.  Return
+  // the address of the immediately following segment.  Update *POFF
+  // and *PSHNDX.  This should only be called for a PT_LOAD segment.
   uint64_t
-  set_section_addresses(uint64_t addr, off_t* poff);
+  set_section_addresses(uint64_t addr, off_t* poff, unsigned int* pshndx);
 
   // Set the offset of this segment based on the section.  This should
   // only be called for a non-PT_LOAD segment.
@@ -481,13 +817,14 @@ class Output_segment
   // Write the segment header into *OPHDR.
   template<int size, bool big_endian>
   void
-  write_header(elfcpp::Phdr_write<size, big_endian>*) const;
+  write_header(elfcpp::Phdr_write<size, big_endian>*);
 
   // Write the section headers of associated sections into V.
   template<int size, bool big_endian>
   unsigned char*
   write_section_headers(const Stringpool*,
-                        unsigned char* v ACCEPT_SIZE_ENDIAN) const;
+                        unsigned char* v,
+                       unsigned int* pshndx ACCEPT_SIZE_ENDIAN) const;
 
  private:
   Output_segment(const Output_segment&);
@@ -495,9 +832,14 @@ class Output_segment
 
   typedef std::list<Output_data*> Output_data_list;
 
+  // Find the maximum alignment in an Output_data_list.
+  static uint64_t
+  maximum_alignment(const Output_data_list*);
+
   // Set the section addresses in an Output_data_list.
   uint64_t
-  set_section_list_addresses(Output_data_list*, uint64_t addr, off_t* poff);
+  set_section_list_addresses(Output_data_list*, uint64_t addr, off_t* poff,
+                            unsigned int* pshndx);
 
   // Return the number of Output_sections in an Output_data_list.
   unsigned int
@@ -507,7 +849,8 @@ class Output_segment
   template<int size, bool big_endian>
   unsigned char*
   write_section_headers_list(const Stringpool*, const Output_data_list*,
-                            unsigned char* v ACCEPT_SIZE_ENDIAN) const;
+                            unsigned char* v,
+                            unsigned int* pshdx ACCEPT_SIZE_ENDIAN) const;
 
   // The list of output data with contents attached to this segment.
   Output_data_list output_data_;
@@ -529,6 +872,8 @@ class Output_segment
   elfcpp::Elf_Word type_;
   // The segment flags.
   elfcpp::Elf_Word flags_;
+  // Whether we have set align_.
+  bool is_align_known_;
 };
 
 // This class represents the output file.
index 76d60f9..5d4a4a0 100644 (file)
@@ -1,5 +1,9 @@
 archive.cc
 archive.h
+common.cc
+common.h
+defstd.cc
+defstd.h
 dirsearch.cc
 dirsearch.h
 fileread.cc
index 66f9572..a62d946 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2006-10-20 13:39-0700\n"
+"POT-Creation-Date: 2006-11-03 10:04-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"
@@ -16,42 +16,42 @@ msgstr ""
 "Content-Type: text/plain; charset=CHARSET\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: archive.cc:69
+#: archive.cc:62
 #, c-format
 msgid "%s: %s: no archive symbol table (run ranlib)\n"
 msgstr ""
 
-#: archive.cc:98
+#: archive.cc:91
 #, c-format
 msgid "%s: %s: bad archive symbol table names\n"
 msgstr ""
 
-#: archive.cc:132
+#: archive.cc:129
 #, c-format
 msgid "%s; %s: malformed archive header at %ld\n"
 msgstr ""
 
-#: archive.cc:153
+#: archive.cc:150
 #, c-format
 msgid "%s: %s: malformed archive header size at %ld\n"
 msgstr ""
 
-#: archive.cc:165
+#: archive.cc:162
 #, c-format
 msgid "%s: %s: malformed archive header name at %ld\n"
 msgstr ""
 
-#: archive.cc:191
+#: archive.cc:188
 #, c-format
 msgid "%s: %s: bad extended name index at %ld\n"
 msgstr ""
 
-#: archive.cc:202
+#: archive.cc:199
 #, c-format
 msgid "%s: %s: bad extended name entry at header %ld\n"
 msgstr ""
 
-#: archive.cc:284 archive.cc:297
+#: archive.cc:279 archive.cc:292
 #, c-format
 msgid "%s: %s: member at %ld is not an ELF object"
 msgstr ""
@@ -66,32 +66,32 @@ msgstr ""
 msgid "%s: warning: close(%s) failed: %s"
 msgstr ""
 
-#: fileread.cc:131
+#: fileread.cc:129
 #, c-format
 msgid "%s: %s: lseek to %lld failed: %s"
 msgstr ""
 
-#: fileread.cc:141
+#: fileread.cc:139
 #, c-format
 msgid "%s: %s: read failed: %s\n"
 msgstr ""
 
-#: fileread.cc:151
+#: fileread.cc:149 fileread.cc:232
 #, c-format
 msgid "%s: %s: file too short: read only %lld of %lld bytes at %lld\n"
 msgstr ""
 
-#: fileread.cc:267
+#: fileread.cc:323
 #, c-format
 msgid "%s: cannot find %s\n"
 msgstr ""
 
-#: fileread.cc:275
+#: fileread.cc:331
 #, c-format
 msgid "%s: cannot open %s: %s\n"
 msgstr ""
 
-#: gold.cc:100
+#: gold.cc:102
 msgid "no input files"
 msgstr ""
 
@@ -139,319 +139,361 @@ msgstr ""
 msgid "pthread_cond_signal failed"
 msgstr ""
 
-#: i386.cc:223 i386.cc:319 i386.cc:466
+#. FIXME: This needs to specify the location somehow.
+#: i386.cc:88
+#, c-format
+msgid "%s: missing expected TLS relocation\n"
+msgstr ""
+
+#: i386.cc:306 i386.cc:434 i386.cc:627
 #, c-format
 msgid "%s: %s: unexpected reloc %u in object file\n"
 msgstr ""
 
-#: i386.cc:256 i386.cc:277
+#: i386.cc:339 i386.cc:358
 #, c-format
 msgid "%s: %s: unsupported reloc %u against local symbol\n"
 msgstr ""
 
-#: i386.cc:354 i386.cc:376
+#: i386.cc:415 i386.cc:469 i386.cc:487
 #, c-format
 msgid "%s: %s: unsupported reloc %u against global symbol %s\n"
 msgstr ""
 
-#: i386.cc:397
+#: i386.cc:509
 #, c-format
 msgid "%s: %s: unsupported RELA reloc section\n"
 msgstr ""
 
-#: i386.cc:503 i386.cc:571
+#: i386.cc:548
+#, c-format
+msgid "%s: %s: missing expected TLS relocation\n"
+msgstr ""
+
+#: i386.cc:594 i386.cc:659 i386.cc:732 i386.cc:743
 #, c-format
 msgid "%s: %s: unsupported reloc %u\n"
 msgstr ""
 
-#: i386.cc:528
+#: i386.cc:686
 #, c-format
 msgid "%s: %s: TLS reloc but no TLS segment\n"
 msgstr ""
 
-#: i386.cc:559
+#: i386.cc:717
 #, c-format
 msgid "%s: %s: unsupported reloc type %u\n"
 msgstr ""
 
-#: i386.cc:689
+#: i386.cc:926
 #, c-format
 msgid "%s: %s: TLS relocation out of range\n"
 msgstr ""
 
-#: i386.cc:707
+#: i386.cc:944
 #, c-format
 msgid "%s: %s: TLS relocation against invalid instruction\n"
 msgstr ""
 
-#: object.cc:60
+#: object.cc:41
 #, c-format
 msgid "%s: %s: bad e_ehsize field (%d != %d)\n"
 msgstr ""
 
-#: object.cc:67
+#: object.cc:48
 #, c-format
 msgid "%s: %s: bad e_shentsize field (%d != %d)\n"
 msgstr ""
 
-#: object.cc:108 object.cc:418
+#: object.cc:89 object.cc:329 object.cc:425
 #, c-format
 msgid "%s: %s: bad section name offset for section %u: %lu\n"
 msgstr ""
 
-#: object.cc:131
+#: object.cc:112
 #, c-format
 msgid "%s: %s: unsupported ELF machine number %d\n"
 msgstr ""
 
-#: object.cc:226
+#: object.cc:207
 #, c-format
 msgid "%s: %s: invalid symbol table name index: %u\n"
 msgstr ""
 
-#: object.cc:234
+#: object.cc:215
 #, c-format
 msgid "%s: %s: symbol table name section has wrong type: %u\n"
 msgstr ""
 
-#: object.cc:286
+#: object.cc:267
 #, c-format
 msgid "%s: %s: section group %u link %u out of range\n"
 msgstr ""
 
-#: object.cc:296
+#: object.cc:277
 #, c-format
 msgid "%s: %s: section group %u info %u out of range\n"
 msgstr ""
 
-#: object.cc:307
+#: object.cc:288
 #, c-format
 msgid "%s; %s: symtab section %u link %u out of range\n"
 msgstr ""
 
-#: object.cc:323
+#: object.cc:304
 #, c-format
 msgid "%s: %s: symbol %u name offset %u out of range\n"
 msgstr ""
 
-#: object.cc:345
+#: object.cc:352
 #, c-format
 msgid "%s: %s: section %u in section group %u out of range"
 msgstr ""
 
-#: object.cc:479
+#: object.cc:486
 #, c-format
 msgid "%s: %s: size of symbols is not multiple of symbol size\n"
 msgstr ""
 
-#: object.cc:566
+#: object.cc:573
 #, c-format
 msgid "%s: %s: unknown section index %u for local symbol %u\n"
 msgstr ""
 
-#: object.cc:577
+#: object.cc:584
 #, c-format
 msgid "%s: %s: local symbol %u section index %u out of range\n"
 msgstr ""
 
 #. elfcpp::ET_DYN
-#: object.cc:755
+#: object.cc:763
 #, c-format
 msgid "%s: %s: dynamic objects are not yet supported\n"
 msgstr ""
 
-#: object.cc:779 object.cc:832 object.cc:853
+#: object.cc:787 object.cc:840 object.cc:861
 #, c-format
 msgid "%s: %s: ELF file too short\n"
 msgstr ""
 
-#: object.cc:788
+#: object.cc:796
 #, c-format
 msgid "%s: %s: invalid ELF version 0\n"
 msgstr ""
 
-#: object.cc:791
+#: object.cc:799
 #, c-format
 msgid "%s: %s: unsupported ELF version %d\n"
 msgstr ""
 
-#: object.cc:799
+#: object.cc:807
 #, c-format
 msgid "%s: %s: invalid ELF class 0\n"
 msgstr ""
 
-#: object.cc:806
+#: object.cc:814
 #, c-format
 msgid "%s: %s: unsupported ELF class %d\n"
 msgstr ""
 
-#: object.cc:814
+#: object.cc:822
 #, c-format
 msgid "%s: %s: invalid ELF data encoding\n"
 msgstr ""
 
-#: object.cc:821
+#: object.cc:829
 #, c-format
 msgid "%s: %s: unsupported ELF data encoding %d\n"
 msgstr ""
 
-#: options.cc:97
+#: options.cc:115
 #, c-format
 msgid ""
 "Usage: %s [options] file...\n"
 "Options:\n"
 msgstr ""
 
-#: options.cc:209
+#: options.cc:227
 msgid "Search for library LIBNAME"
 msgstr ""
 
-#: options.cc:210
+#: options.cc:228
 msgid "-lLIBNAME --library LIBNAME"
 msgstr ""
 
-#: options.cc:212
+#: options.cc:230
+msgid "Start a library search group"
+msgstr ""
+
+#: options.cc:232
+msgid "End a library search group"
+msgstr ""
+
+#: options.cc:234
 msgid "Add directory to search path"
 msgstr ""
 
-#: options.cc:213
+#: options.cc:235
 msgid "-L DIR, --library-path DIR"
 msgstr ""
 
-#: options.cc:215
+#: options.cc:237
 msgid "Set output file name"
 msgstr ""
 
-#: options.cc:216
+#: options.cc:238
 msgid "-o FILE, --output FILE"
 msgstr ""
 
-#: options.cc:218
+#: options.cc:240
 msgid "Generate relocatable output"
 msgstr ""
 
-#: options.cc:220
+#: options.cc:242
 msgid "Generate shared library"
 msgstr ""
 
-#: options.cc:222
+#: options.cc:244
 msgid "Do not link against shared libraries"
 msgstr ""
 
-#: options.cc:224
+#: options.cc:246
 msgid "Report usage information"
 msgstr ""
 
-#: options.cc:322 options.cc:373 options.cc:437
+#: options.cc:344 options.cc:395 options.cc:481
 msgid "missing argument"
 msgstr ""
 
-#: options.cc:335 options.cc:382
+#: options.cc:357 options.cc:404
 msgid "unknown option"
 msgstr ""
 
-#: options.cc:451
+#: options.cc:412
+#, c-format
+msgid "%s: missing group end"
+msgstr ""
+
+#: options.cc:494
+msgid "may not nest groups"
+msgstr ""
+
+#: options.cc:509
+msgid "group end without group start"
+msgstr ""
+
+#: options.cc:519
 #, c-format
 msgid "%s: use the --help option for usage information\n"
 msgstr ""
 
-#: options.cc:460
+#: options.cc:528
 #, c-format
 msgid "%s: %s: %s\n"
 msgstr ""
 
-#: options.cc:469
+#: options.cc:537
 #, c-format
 msgid "%s: -%c: %s\n"
 msgstr ""
 
-#: output.cc:385
+#: output.cc:521
 #, c-format
 msgid "%s: %s: invalid alignment %lu for section \"%s\"\n"
 msgstr ""
 
-#: output.cc:775
+#: output.cc:1031
 #, c-format
 msgid "%s: %s: open: %s\n"
 msgstr ""
 
-#: output.cc:784
+#: output.cc:1040
 #, c-format
 msgid "%s: %s: lseek: %s\n"
 msgstr ""
 
-#: output.cc:791
+#: output.cc:1047
 #, c-format
 msgid "%s: %s: write: %s\n"
 msgstr ""
 
-#: output.cc:801
+#: output.cc:1057
 #, c-format
 msgid "%s: %s: mmap: %s\n"
 msgstr ""
 
-#: output.cc:815
+#: output.cc:1071
 #, c-format
 msgid "%s: %s: munmap: %s\n"
 msgstr ""
 
-#: output.cc:823
+#: output.cc:1079
 #, c-format
 msgid "%s: %s: close: %s\n"
 msgstr ""
 
+#: readsyms.cc:84
+#, c-format
+msgid "%s: %s: ordinary object found in input group\n"
+msgstr ""
+
 #. Here we have to handle any other input file types we need.
-#: readsyms.cc:109
+#: readsyms.cc:126
 #, c-format
 msgid "%s: %s: not an object or archive\n"
 msgstr ""
 
-#: reloc.cc:165 reloc.cc:392
+#: reloc.cc:168 reloc.cc:408
 #, c-format
 msgid "%s: %s: relocation section %u has bad info %u\n"
 msgstr ""
 
-#: reloc.cc:176 reloc.cc:409
+#: reloc.cc:187 reloc.cc:425
 #, c-format
 msgid "%s: %s: relocation section %u uses unexpected symbol table %u\n"
 msgstr ""
 
-#: reloc.cc:192 reloc.cc:428
+#: reloc.cc:203 reloc.cc:444
 #, c-format
 msgid "%s: %s: unexpected entsize for reloc section %u: %lu != %u"
 msgstr ""
 
-#: reloc.cc:203 reloc.cc:439
+#: reloc.cc:214 reloc.cc:455
 #, c-format
 msgid "%s: %s: reloc section %u size %lu uneven"
 msgstr ""
 
-#: resolve.cc:138
+#: resolve.cc:140
 #, c-format
 msgid "%s: %s: invalid STB_LOCAL symbol %s in external symbols\n"
 msgstr ""
 
-#: resolve.cc:144
+#: resolve.cc:146
 #, c-format
 msgid "%s: %s: unsupported symbol binding %d for symbol %s\n"
 msgstr ""
 
-#: symtab.cc:303
+#: symtab.cc:428
 #, c-format
 msgid "%s: %s: mixing 32-bit and 64-bit ELF objects\n"
 msgstr ""
 
-#: symtab.cc:320
+#: symtab.cc:445
 #, c-format
 msgid "%s: %s: bad global symbol name offset %u at %lu\n"
 msgstr ""
 
-#: target-reloc.h:145
+#: symtab.cc:840 symtab.cc:975
+#, c-format
+msgid "%s: %s: unsupported symbol section 0x%x\n"
+msgstr ""
+
+#: target-reloc.h:181
 #, c-format
 msgid "%s: %s: reloc has bad offset %zu\n"
 msgstr ""
 
-#: target-reloc.h:176
+#: target-reloc.h:191
 #, c-format
 msgid "%s: %s: undefined reference to '%s'\n"
 msgstr ""
index 3a5650a..9ff7ab7 100644 (file)
@@ -22,15 +22,16 @@ Read_symbols::~Read_symbols()
   // Add_symbols task.
 }
 
-// Return whether a Read_symbols task is runnable.  We need write
-// access to the symbol table.  We can read an ordinary input file
-// immediately.  For an archive specified using -l, we have to wait
-// until the search path is complete.
+// Return whether a Read_symbols task is runnable.  We can read an
+// ordinary input file immediately.  For an archive specified using
+// -l, we have to wait until the search path is complete.
 
 Task::Is_runnable_type
 Read_symbols::is_runnable(Workqueue*)
 {
-  if (this->input_.is_lib() && this->dirpath_.token().is_blocked())
+  if (this->input_.is_file()
+      && this->input_.file().is_lib()
+      && this->dirpath_.token().is_blocked())
     return IS_BLOCKED;
 
   return IS_RUNNABLE;
@@ -51,7 +52,14 @@ Read_symbols::locks(Workqueue*)
 void
 Read_symbols::run(Workqueue* workqueue)
 {
-  Input_file* input_file = new Input_file(this->input_);
+  if (this->input_.is_group())
+    {
+      assert(this->input_group_ == NULL);
+      this->do_group(workqueue);
+      return;
+    }
+
+  Input_file* input_file = new Input_file(this->input_.file());
   input_file->open(this->options_, this->dirpath_);
 
   // Read enough of the file to pick up the entire ELF header.
@@ -69,14 +77,22 @@ Read_symbols::run(Workqueue* workqueue)
       if (memcmp(p, elfmagic, 4) == 0)
        {
          // This is an ELF object.
-         Object* obj = make_elf_object(this->input_.name(), input_file, 0,
-                                       p, bytes);
 
-         this->input_objects_->add_object(obj);
+         if (this->input_group_ != NULL)
+           {
+             fprintf(stderr,
+                     _("%s: %s: ordinary object found in input group\n"),
+                     program_name, input_file->name());
+             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->symtab_, this->layout_,
+         workqueue->queue_front(new Add_symbols(this->input_objects_,
+                                                this->symtab_, this->layout_,
                                                 obj, sd,
                                                 this->this_blocker_,
                                                 this->next_blocker_));
@@ -93,12 +109,13 @@ Read_symbols::run(Workqueue* workqueue)
       if (memcmp(p, Archive::armag, Archive::sarmag) == 0)
        {
          // This is an archive.
-         Archive* arch = new Archive(this->input_.name(), input_file);
+         Archive* arch = new Archive(this->input_.file().name(), input_file);
          arch->setup();
          workqueue->queue(new Add_archive_symbols(this->symtab_,
                                                   this->layout_,
                                                   this->input_objects_,
                                                   arch,
+                                                  this->input_group_,
                                                   this->this_blocker_,
                                                   this->next_blocker_));
          return;
@@ -111,6 +128,46 @@ Read_symbols::run(Workqueue* workqueue)
   gold_exit(false);
 }
 
+// Handle a group.  We need to walk through the arguments over and
+// over until we don't see any new undefined symbols.  We do this by
+// setting off Read_symbols Tasks as usual, but recording the archive
+// entries instead of deleting them.  We also start a Finish_group
+// Task which runs after we've read all the symbols.  In that task we
+// process the archives in a loop until we are done.
+
+void
+Read_symbols::do_group(Workqueue* workqueue)
+{
+  Input_group* input_group = new Input_group();
+
+  const Input_file_group* group = this->input_.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());
+
+      Task_token* next_blocker = new Task_token();
+      next_blocker->add_blocker();
+      workqueue->queue(new Read_symbols(this->options_, this->input_objects_,
+                                       this->symtab_, this->layout_,
+                                       this->dirpath_, arg, input_group,
+                                       this_blocker, next_blocker));
+      this_blocker = next_blocker;
+    }
+
+  const int saw_undefined = this->symtab_->saw_undefined();
+  workqueue->queue(new Finish_group(this->input_objects_,
+                                   this->symtab_,
+                                   this->layout_,
+                                   input_group,
+                                   saw_undefined,
+                                   this_blocker,
+                                   this->next_blocker_));
+}
+
 // Class Add_symbols.
 
 Add_symbols::~Add_symbols()
@@ -154,13 +211,71 @@ Add_symbols::locks(Workqueue* workqueue)
                                this->object_);
 }
 
+// Add the symbols in the object to the symbol table.
+
 void
 Add_symbols::run(Workqueue*)
 {
+  this->input_objects_->add_object(this->object_);
   this->object_->layout(this->layout_, this->sd_);
   this->object_->add_symbols(this->symtab_, this->sd_);
   delete this->sd_;
   this->sd_ = NULL;
 }
 
+// Class Finish_group.
+
+Finish_group::~Finish_group()
+{
+  if (this->this_blocker_ != NULL)
+    delete this->this_blocker_;
+  // next_blocker_ is deleted by the task associated with the next
+  // input file following the group.
+}
+
+// We need to wait for THIS_BLOCKER_ and unblock NEXT_BLOCKER_.
+
+Task::Is_runnable_type
+Finish_group::is_runnable(Workqueue*)
+{
+  if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
+    return IS_BLOCKED;
+  return IS_RUNNABLE;
+}
+
+Task_locker*
+Finish_group::locks(Workqueue* workqueue)
+{
+  return new Task_locker_block(*this->next_blocker_, workqueue);
+}
+
+// Loop over the archives until there are no new undefined symbols.
+
+void
+Finish_group::run(Workqueue*)
+{
+  int saw_undefined = this->saw_undefined_;
+  while (saw_undefined != this->symtab_->saw_undefined())
+    {
+      saw_undefined = this->symtab_->saw_undefined();
+
+      for (Input_group::const_iterator p = this->input_group_->begin();
+          p != this->input_group_->end();
+          ++p)
+       {
+         Task_lock_obj<Archive> tl(**p);
+
+         (*p)->add_symbols(this->symtab_, this->layout_,
+                           this->input_objects_);
+       }
+    }
+
+  // Delete all the archives now that we no longer need them.
+  for (Input_group::const_iterator p = this->input_group_->begin();
+       p != this->input_group_->end();
+       ++p)
+    delete *p;
+  delete this->input_group_;
+}
+
 } // End namespace gold.
index 2077d47..2348c32 100644 (file)
@@ -3,6 +3,8 @@
 #ifndef GOLD_READSYMS_H
 #define GOLD_READSYMS_H
 
+#include <vector>
+
 #include "workqueue.h"
 #include "object.h"
 
@@ -11,6 +13,8 @@ namespace gold
 
 class Input_objects;
 class Symbol_table;
+class Input_group;
+class Archive;
 
 // This Task is responsible for reading the symbols from an input
 // file.  This also includes reading the relocations so that we can
@@ -24,17 +28,20 @@ class Read_symbols : public Task
 {
  public:
   // DIRPATH is the list of directories to search for libraries.
-  // INPUT is the file to read.  THIS_BLOCKER is used to prevent the
-  // associated Add_symbols task from running before the previous one
-  // has completed; it will be NULL for the first task.  NEXT_BLOCKER
-  // is used to block the next input file from adding symbols.
+  // INPUT is the file to read.  INPUT_GROUP is not NULL if we are in
+  // the middle of an input group.  THIS_BLOCKER is used to prevent
+  // the associated Add_symbols task from running before the previous
+  // one has completed; it will be NULL for the first task.
+  // NEXT_BLOCKER is used to block the next input file from adding
+  // symbols.
   Read_symbols(const General_options& options, Input_objects* input_objects,
               Symbol_table* symtab, Layout* layout, const Dirsearch& dirpath,
-              const Input_argument& input,
+              const Input_argument& input, 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),
-      this_blocker_(this_blocker), next_blocker_(next_blocker)
+      input_group_(input_group), this_blocker_(this_blocker),
+      next_blocker_(next_blocker)
   { }
 
   ~Read_symbols();
@@ -51,12 +58,17 @@ class Read_symbols : public Task
   run(Workqueue*);
 
  private:
+  // Handle an archive group.
+  void
+  do_group(Workqueue*);
+
   const General_options& options_;
   Input_objects* input_objects_;
   Symbol_table* symtab_;
   Layout* layout_;
   const Dirsearch& dirpath_;
   const Input_argument& input_;
+  Input_group* input_group_;
   Task_token* this_blocker_;
   Task_token* next_blocker_;
 };
@@ -71,11 +83,12 @@ 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(Symbol_table* symtab, Layout* layout, Object* object,
-             Read_symbols_data* sd, Task_token* this_blocker,
-             Task_token* next_blocker)
-    : symtab_(symtab), layout_(layout), object_(object), sd_(sd),
-      this_blocker_(this_blocker), next_blocker_(next_blocker)
+  Add_symbols(Input_objects* input_objects, Symbol_table* symtab,
+             Layout* layout, Object* object, Read_symbols_data* sd,
+             Task_token* this_blocker, Task_token* next_blocker)
+    : input_objects_(input_objects), symtab_(symtab), layout_(layout),
+      object_(object), sd_(sd), this_blocker_(this_blocker),
+      next_blocker_(next_blocker)
   { }
 
   ~Add_symbols();
@@ -94,6 +107,7 @@ class Add_symbols : public Task
 private:
   class Add_symbols_locker;
 
+  Input_objects* input_objects_;
   Symbol_table* symtab_;
   Layout* layout_;
   Object* object_;
@@ -102,6 +116,75 @@ private:
   Task_token* next_blocker_;
 };
 
+// This class is used to track the archives in a group.
+
+class Input_group
+{
+ public:
+  typedef std::vector<Archive*> Archives;
+  typedef Archives::const_iterator const_iterator;
+
+  Input_group()
+    : archives_()
+  { }
+
+  // Add an archive to the group.
+  void
+  add_archive(Archive* arch)
+  { this->archives_.push_back(arch); }
+
+  // Loop over the archives in the group.
+
+  const_iterator
+  begin() const
+  { return this->archives_.begin(); }
+
+  const_iterator
+  end() const
+  { return this->archives_.end(); }
+
+ private:
+  Archives archives_;
+};
+
+// This class is used to finish up handling a group.  It is just a
+// closure.
+
+class Finish_group : public Task
+{
+ public:
+  Finish_group(Input_objects* input_objects, Symbol_table* symtab,
+              Layout* layout, Input_group* input_group,
+              int saw_undefined, Task_token* this_blocker,
+              Task_token* next_blocker)
+    : input_objects_(input_objects), symtab_(symtab), layout_(layout),
+      input_group_(input_group), saw_undefined_(saw_undefined),
+      this_blocker_(this_blocker), next_blocker_(next_blocker)
+  { }
+
+  ~Finish_group();
+
+  // The standard Task methods.
+
+  Is_runnable_type
+  is_runnable(Workqueue*);
+
+  Task_locker*
+  locks(Workqueue*);
+
+  void
+  run(Workqueue*);
+
+ private:
+  Input_objects* input_objects_;
+  Symbol_table* symtab_;
+  Layout* layout_;
+  Input_group* input_group_;
+  int saw_undefined_;
+  Task_token* this_blocker_;
+  Task_token* next_blocker_;
+};
+
 } // end namespace gold
 
 #endif // !defined(GOLD_READSYMS_H)
index bb672e4..ca5e380 100644 (file)
@@ -38,8 +38,8 @@ Read_relocs::run(Workqueue* workqueue)
   Read_relocs_data *rd = new Read_relocs_data;
   this->object_->read_relocs(rd);
   workqueue->queue_front(new Scan_relocs(this->options_, this->symtab_,
-                                        this->object_, rd, this->symtab_lock_,
-                                        this->blocker_));
+                                        this->layout_, this->object_, rd,
+                                        this->symtab_lock_, this->blocker_));
 }
 
 // Scan_relocs methods.
@@ -52,7 +52,9 @@ Read_relocs::run(Workqueue* workqueue)
 Task::Is_runnable_type
 Scan_relocs::is_runnable(Workqueue*)
 {
-  return this->symtab_lock_->is_writable() ? IS_RUNNABLE : IS_LOCKED;
+  if (!this->symtab_lock_->is_writable() || this->object_->is_locked())
+    return IS_LOCKED;
+  return IS_RUNNABLE;
 }
 
 // Return the locks we hold: one on the file, one on the symbol table
@@ -85,7 +87,8 @@ Scan_relocs::locks(Workqueue* workqueue)
 void
 Scan_relocs::run(Workqueue*)
 {
-  this->object_->scan_relocs(this->options_, this->symtab_, this->rd_);
+  this->object_->scan_relocs(this->options_, this->symtab_, this->layout_,
+                            this->rd_);
   delete this->rd_;
   this->rd_ = NULL;
 }
@@ -170,6 +173,14 @@ Sized_object<size, big_endian>::do_read_relocs(Read_relocs_data* rd)
       if (!this->is_section_included(shndx))
        continue;
 
+      // We are scanning relocations in order to fill out the GOT and
+      // PLT sections.  Relocations for sections which are not
+      // allocated (typically debugging sections) should not add new
+      // GOT and PLT entries.  So we skip them.
+      typename This::Shdr secshdr(pshdrs + shndx * This::shdr_size);
+      if ((secshdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0)
+       continue;
+
       if (shdr.get_sh_link() != this->symtab_shnum_)
        {
          fprintf(stderr,
@@ -239,6 +250,7 @@ template<int size, bool big_endian>
 void
 Sized_object<size, big_endian>::do_scan_relocs(const General_options& options,
                                               Symbol_table* symtab,
+                                              Layout* layout,
                                               Read_relocs_data* rd)
 {
   Sized_target<size, big_endian>* target = this->sized_target();
@@ -253,7 +265,7 @@ Sized_object<size, big_endian>::do_scan_relocs(const General_options& options,
        p != rd->relocs.end();
        ++p)
     {
-      target->scan_relocs(options, symtab, this, p->sh_type,
+      target->scan_relocs(options, symtab, layout, this, p->sh_type,
                          p->contents->data(), p->reloc_count,
                          this->local_symbol_count_,
                          local_symbols,
@@ -338,11 +350,15 @@ Sized_object<size, big_endian>::write_sections(const unsigned char* pshdrs,
       if (shdr.get_sh_type() == elfcpp::SHT_NOBITS)
        continue;
 
-      assert(map_sections[i].offset >= 0
-            && map_sections[i].offset < os->data_size());
       off_t start = os->offset() + map_sections[i].offset;
       off_t sh_size = shdr.get_sh_size();
 
+      if (sh_size == 0)
+       continue;
+
+      assert(map_sections[i].offset >= 0
+            && map_sections[i].offset + sh_size <= os->data_size());
+
       unsigned char* view = of->get_output_view(start, sh_size);
       this->read(shdr.get_sh_offset(), sh_size, view);
 
@@ -477,24 +493,28 @@ template
 void
 Sized_object<32, false>::do_scan_relocs(const General_options& options,
                                        Symbol_table* symtab,
+                                       Layout* layout,
                                        Read_relocs_data* rd);
 
 template
 void
 Sized_object<32, true>::do_scan_relocs(const General_options& options,
                                       Symbol_table* symtab,
+                                      Layout* layout,
                                       Read_relocs_data* rd);
 
 template
 void
 Sized_object<64, false>::do_scan_relocs(const General_options& options,
                                        Symbol_table* symtab,
+                                       Layout* layout,
                                        Read_relocs_data* rd);
 
 template
 void
 Sized_object<64, true>::do_scan_relocs(const General_options& options,
                                       Symbol_table* symtab,
+                                      Layout* layout,
                                       Read_relocs_data* rd);
 
 template
index a2e9d54..f8f07b8 100644 (file)
@@ -13,6 +13,7 @@ namespace gold
 class Object;
 class Read_relocs_data;
 class Stringpool;
+class Layout;
 
 // A class to read the relocations for an object file, and then queue
 // up a task to see if they require any GOT/PLT/COPY relocations in
@@ -24,9 +25,9 @@ class Read_relocs : public Task
   // SYMTAB_LOCK is used to lock the symbol table.  BLOCKER should be
   // unblocked when the Scan_relocs task completes.
   Read_relocs(const General_options& options, Symbol_table* symtab,
-             Object* object, Task_token* symtab_lock,
+             Layout* layout, Object* object, Task_token* symtab_lock,
              Task_token* blocker)
-    : options_(options), symtab_(symtab), object_(object),
+    : options_(options), symtab_(symtab), layout_(layout), object_(object),
       symtab_lock_(symtab_lock), blocker_(blocker)
   { }
 
@@ -44,6 +45,7 @@ class Read_relocs : public Task
  private:
   const General_options& options_;
   Symbol_table* symtab_;
+  Layout* layout_;
   Object* object_;
   Task_token* symtab_lock_;
   Task_token* blocker_;
@@ -58,10 +60,10 @@ class Scan_relocs : public Task
   // SYMTAB_LOCK is used to lock the symbol table.  BLOCKER should be
   // unblocked when the task completes.
   Scan_relocs(const General_options& options, Symbol_table* symtab,
-             Object* object, Read_relocs_data* rd, Task_token* symtab_lock,
-             Task_token* blocker)
-    : options_(options), symtab_(symtab), object_(object), rd_(rd),
-      symtab_lock_(symtab_lock), blocker_(blocker)
+             Layout* layout, Object* object, Read_relocs_data* rd,
+             Task_token* symtab_lock, Task_token* blocker)
+    : options_(options), symtab_(symtab), layout_(layout), object_(object),
+      rd_(rd), symtab_lock_(symtab_lock), blocker_(blocker)
   { }
 
   // The standard Task methods.
@@ -80,6 +82,7 @@ class Scan_relocs : public Task
 
   const General_options& options_;
   Symbol_table* symtab_;
+  Layout* layout_;
   Object* object_;
   Read_relocs_data* rd_;
   Task_token* symtab_lock_;
index 6b8199c..83e616c 100644 (file)
@@ -19,12 +19,14 @@ void
 Symbol::override_base(const elfcpp::Sym<size, big_endian>& sym,
                      Object* object)
 {
-  this->object_ = object;
-  this->shnum_ = sym.get_st_shndx(); // FIXME: Handle SHN_XINDEX.
+  assert(this->source_ == FROM_OBJECT);
+  this->u_.from_object.object = object;
+  // FIXME: Handle SHN_XINDEX.
+  this->u_.from_object.shnum = sym.get_st_shndx();
   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->nonvis_ = sym.get_st_nonvis();
 }
 
 // Override the fields in Sized_symbol.
@@ -37,7 +39,7 @@ Sized_symbol<size>::override(const elfcpp::Sym<size, big_endian>& sym,
 {
   this->override_base(sym, object);
   this->value_ = sym.get_st_value();
-  this->size_ = sym.get_st_size();
+  this->symsize_ = sym.get_st_size();
 }
 
 // Resolve a symbol.  This is called the second and subsequent times
@@ -315,9 +317,16 @@ Symbol_table::resolve(Sized_symbol<size>* to,
     case DYN_DEF * 16 + UNDEF:
     case DYN_WEAK_DEF * 16 + UNDEF:
     case UNDEF * 16 + UNDEF:
+      // A new undefined reference tells us nothing.
+      return;
+
     case WEAK_UNDEF * 16 + UNDEF:
     case DYN_UNDEF * 16 + UNDEF:
     case DYN_WEAK_UNDEF * 16 + UNDEF:
+      // A strong undef overrides a dynamic or weak undef.
+      to->override(sym, object);
+      return;
+
     case COMMON * 16 + UNDEF:
     case WEAK_COMMON * 16 + UNDEF:
     case DYN_COMMON * 16 + UNDEF:
@@ -391,50 +400,100 @@ Symbol_table::resolve(Sized_symbol<size>* to,
       return;
 
     case COMMON * 16 + COMMON:
+      // Set the size to the maximum.
+      if (sym.get_st_size() > to->symsize())
+       to->set_symsize(sym.get_st_size());
+      return;
+
     case WEAK_COMMON * 16 + COMMON:
+      // I'm not sure just what a weak common symbol means, but
+      // presumably it can be overridden by a regular common symbol.
+      to->override(sym, object);
+      return;
+
     case DYN_COMMON * 16 + COMMON:
     case DYN_WEAK_COMMON * 16 + COMMON:
+      {
+       // Use the real common symbol, but adjust the size if necessary.
+       typename Sized_symbol<size>::Size_type symsize = to->symsize();
+       to->override(sym, object);
+       if (to->symsize() < symsize)
+         to->set_symsize(symsize);
+      }
+      return;
 
     case DEF * 16 + WEAK_COMMON:
     case WEAK_DEF * 16 + WEAK_COMMON:
     case DYN_DEF * 16 + WEAK_COMMON:
     case DYN_WEAK_DEF * 16 + WEAK_COMMON:
+      // Whatever a weak common symbol is, it won't override a
+      // definition.
+      return;
+
     case UNDEF * 16 + WEAK_COMMON:
     case WEAK_UNDEF * 16 + WEAK_COMMON:
     case DYN_UNDEF * 16 + WEAK_COMMON:
     case DYN_WEAK_UNDEF * 16 + WEAK_COMMON:
+      // A weak common symbol is better than an undefined symbol.
+      to->override(sym, object);
+      return;
+
     case COMMON * 16 + WEAK_COMMON:
     case WEAK_COMMON * 16 + WEAK_COMMON:
     case DYN_COMMON * 16 + WEAK_COMMON:
     case DYN_WEAK_COMMON * 16 + WEAK_COMMON:
+      // Ignore a weak common symbol in the presence of a real common
+      // symbol.
+      return;
 
     case DEF * 16 + DYN_COMMON:
     case WEAK_DEF * 16 + DYN_COMMON:
     case DYN_DEF * 16 + DYN_COMMON:
     case DYN_WEAK_DEF * 16 + DYN_COMMON:
+      // Ignore a dynamic common symbol in the presence of a
+      // definition.
+      return;
+
     case UNDEF * 16 + DYN_COMMON:
     case WEAK_UNDEF * 16 + DYN_COMMON:
     case DYN_UNDEF * 16 + DYN_COMMON:
     case DYN_WEAK_UNDEF * 16 + DYN_COMMON:
+      // A dynamic common symbol is a definition of sorts.
+      to->override(sym, object);
+      return;
+
     case COMMON * 16 + DYN_COMMON:
     case WEAK_COMMON * 16 + DYN_COMMON:
     case DYN_COMMON * 16 + DYN_COMMON:
     case DYN_WEAK_COMMON * 16 + DYN_COMMON:
+      // Set the size to the maximum.
+      if (sym.get_st_size() > to->symsize())
+       to->set_symsize(sym.get_st_size());
+      return;
 
     case DEF * 16 + DYN_WEAK_COMMON:
     case WEAK_DEF * 16 + DYN_WEAK_COMMON:
     case DYN_DEF * 16 + DYN_WEAK_COMMON:
     case DYN_WEAK_DEF * 16 + DYN_WEAK_COMMON:
+      // A common symbol is ignored in the face of a definition.
+      return;
+
     case UNDEF * 16 + DYN_WEAK_COMMON:
     case WEAK_UNDEF * 16 + DYN_WEAK_COMMON:
     case DYN_UNDEF * 16 + DYN_WEAK_COMMON:
     case DYN_WEAK_UNDEF * 16 + DYN_WEAK_COMMON:
+      // I guess a weak common symbol is better than a definition.
+      to->override(sym, object);
+      return;
+
     case COMMON * 16 + DYN_WEAK_COMMON:
     case WEAK_COMMON * 16 + DYN_WEAK_COMMON:
     case DYN_COMMON * 16 + DYN_WEAK_COMMON:
     case DYN_WEAK_COMMON * 16 + DYN_WEAK_COMMON:
-      abort();
-      break;
+      // Set the size to the maximum.
+      if (sym.get_st_size() > to->symsize())
+       to->set_symsize(sym.get_st_size());
+      return;
 
     default:
       abort();
index 748218d..0f43faa 100644 (file)
@@ -17,28 +17,85 @@ namespace gold
 
 // Class Symbol.
 
-// Initialize the fields in the base class Symbol.
+// Initialize fields in Symbol.  This initializes everything except u_
+// and source_.
 
-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)
+Symbol::init_fields(const char* name, const char* version,
+                   elfcpp::STT type, elfcpp::STB binding,
+                   elfcpp::STV visibility, unsigned char nonvis)
 {
   this->name_ = name;
   this->version_ = version;
-  this->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->is_special_ = false;
+  this->got_offset_ = 0;
+  this->type_ = type;
+  this->binding_ = binding;
+  this->visibility_ = visibility;
+  this->nonvis_ = nonvis;
+  this->is_target_special_ = false;
   this->is_def_ = false;
   this->is_forwarder_ = false;
+  this->in_dyn_ = false;
+  this->has_got_offset_ = false;
+}
+
+// Initialize the fields in the base class Symbol for SYM in OBJECT.
+
+template<int size, bool big_endian>
+void
+Symbol::init_base(const char* name, const char* version, Object* object,
+                 const elfcpp::Sym<size, big_endian>& sym)
+{
+  this->init_fields(name, version, sym.get_st_type(), sym.get_st_bind(),
+                   sym.get_st_visibility(), sym.get_st_nonvis());
+  this->u_.from_object.object = object;
+  // FIXME: Handle SHN_XINDEX.
+  this->u_.from_object.shnum = sym.get_st_shndx();
+  this->source_ = FROM_OBJECT;
   this->in_dyn_ = object->is_dynamic();
 }
 
-// Initialize the fields in Sized_symbol.
+// Initialize the fields in the base class Symbol for a symbol defined
+// in an Output_data.
+
+void
+Symbol::init_base(const char* name, Output_data* od, elfcpp::STT type,
+                 elfcpp::STB binding, elfcpp::STV visibility,
+                 unsigned char nonvis, bool offset_is_from_end)
+{
+  this->init_fields(name, NULL, type, binding, visibility, nonvis);
+  this->u_.in_output_data.output_data = od;
+  this->u_.in_output_data.offset_is_from_end = offset_is_from_end;
+  this->source_ = IN_OUTPUT_DATA;
+}
+
+// Initialize the fields in the base class Symbol for a symbol defined
+// in an Output_segment.
+
+void
+Symbol::init_base(const char* name, Output_segment* os, elfcpp::STT type,
+                 elfcpp::STB binding, elfcpp::STV visibility,
+                 unsigned char nonvis, Segment_offset_base offset_base)
+{
+  this->init_fields(name, NULL, type, binding, visibility, nonvis);
+  this->u_.in_output_segment.output_segment = os;
+  this->u_.in_output_segment.offset_base = offset_base;
+  this->source_ = IN_OUTPUT_SEGMENT;
+}
+
+// Initialize the fields in the base class Symbol for a symbol defined
+// as a constant.
+
+void
+Symbol::init_base(const char* name, elfcpp::STT type,
+                 elfcpp::STB binding, elfcpp::STV visibility,
+                 unsigned char nonvis)
+{
+  this->init_fields(name, NULL, type, binding, visibility, nonvis);
+  this->source_ = CONSTANT;
+}
+
+// Initialize the fields in Sized_symbol for SYM in OBJECT.
 
 template<int size>
 template<bool big_endian>
@@ -48,13 +105,61 @@ Sized_symbol<size>::init(const char* name, const char* version, Object* object,
 {
   this->init_base(name, version, object, sym);
   this->value_ = sym.get_st_value();
-  this->size_ = sym.get_st_size();
+  this->symsize_ = sym.get_st_size();
+}
+
+// Initialize the fields in Sized_symbol for a symbol defined in an
+// Output_data.
+
+template<int size>
+void
+Sized_symbol<size>::init(const char* name, Output_data* od,
+                        Value_type value, Size_type symsize,
+                        elfcpp::STT type, elfcpp::STB binding,
+                        elfcpp::STV visibility, unsigned char nonvis,
+                        bool offset_is_from_end)
+{
+  this->init_base(name, od, type, binding, visibility, nonvis,
+                 offset_is_from_end);
+  this->value_ = value;
+  this->symsize_ = symsize;
+}
+
+// Initialize the fields in Sized_symbol for a symbol defined in an
+// Output_segment.
+
+template<int size>
+void
+Sized_symbol<size>::init(const char* name, Output_segment* os,
+                        Value_type value, Size_type symsize,
+                        elfcpp::STT type, elfcpp::STB binding,
+                        elfcpp::STV visibility, unsigned char nonvis,
+                        Segment_offset_base offset_base)
+{
+  this->init_base(name, os, type, binding, visibility, nonvis, offset_base);
+  this->value_ = value;
+  this->symsize_ = symsize;
+}
+
+// Initialize the fields in Sized_symbol for a symbol defined as a
+// constant.
+
+template<int size>
+void
+Sized_symbol<size>::init(const char* name, Value_type value, Size_type symsize,
+                        elfcpp::STT type, elfcpp::STB binding,
+                        elfcpp::STV visibility, unsigned char nonvis)
+{
+  this->init_base(name, type, binding, visibility, nonvis);
+  this->value_ = value;
+  this->symsize_ = symsize;
 }
 
 // Class Symbol_table.
 
 Symbol_table::Symbol_table()
-  : size_(0), offset_(0), table_(), namepool_(), forwarders_()
+  : size_(0), saw_undefined_(0), offset_(0), table_(), namepool_(),
+    forwarders_(), commons_()
 {
 }
 
@@ -144,7 +249,7 @@ Symbol_table::resolve(Sized_symbol<size>* to, const Sized_symbol<size>* from
   esym.put_st_value(from->value());
   esym.put_st_size(from->symsize());
   esym.put_st_info(from->binding(), from->type());
-  esym.put_st_other(from->visibility(), from->other());
+  esym.put_st_other(from->visibility(), from->nonvis());
   esym.put_st_shndx(from->shnum());
   Symbol_table::resolve(to, esym.sym(), from->object());
 }
@@ -198,12 +303,18 @@ Symbol_table::add_from_object(Sized_object<size, big_endian>* object,
   // ins.second: true if new entry was inserted, false if not.
 
   Sized_symbol<size>* ret;
+  bool was_undefined;
+  bool was_common;
   if (!ins.second)
     {
       // We already have an entry for NAME/VERSION.
       ret = this->get_sized_symbol SELECT_SIZE_NAME (ins.first->second
                                                      SELECT_SIZE(size));
       assert(ret != NULL);
+
+      was_undefined = ret->is_undefined();
+      was_common = ret->is_common();
+
       Symbol_table::resolve(ret, sym, object);
 
       if (def)
@@ -233,6 +344,10 @@ Symbol_table::add_from_object(Sized_object<size, big_endian>* object,
     {
       // This is the first time we have seen NAME/VERSION.
       assert(ins.first->second == NULL);
+
+      was_undefined = false;
+      was_common = false;
+
       if (def && !insdef.second)
        {
          // We already have an entry for NAME/NULL.  Make
@@ -279,6 +394,16 @@ Symbol_table::add_from_object(Sized_object<size, big_endian>* object,
        }
     }
 
+  // Record every time we see a new undefined symbol, to speed up
+  // archive groups.
+  if (!was_undefined && ret->is_undefined())
+    ++this->saw_undefined_;
+
+  // Keep track of common symbols, to speed up common symbol
+  // allocation.
+  if (!was_common && ret->is_common())
+    this->commons_.push_back(ret);
+
   return ret;
 }
 
@@ -369,6 +494,302 @@ Symbol_table::add_from_object(
     }
 }
 
+// Create and return a specially defined symbol.  If ONLY_IF_REF is
+// true, then only create the symbol if there is a reference to it.
+
+template<int size, bool big_endian>
+Sized_symbol<size>*
+Symbol_table::define_special_symbol(Target* target, const char* name,
+                                   bool only_if_ref)
+{
+  assert(this->size_ == size);
+
+  Symbol* oldsym;
+  Sized_symbol<size>* sym;
+
+  if (only_if_ref)
+    {
+      oldsym = this->lookup(name, NULL);
+      if (oldsym == NULL)
+       return NULL;
+      sym = NULL;
+
+      // Canonicalize NAME.
+      name = oldsym->name();
+    }
+  else
+    {
+      // Canonicalize NAME.
+      name = this->namepool_.add(name);
+
+      Symbol* const snull = NULL;
+      const char* const vnull = NULL;
+      std::pair<typename Symbol_table_type::iterator, bool> ins =
+       this->table_.insert(std::make_pair(std::make_pair(name, vnull),
+                                          snull));
+
+      if (!ins.second)
+       {
+         // We already have a symbol table entry for NAME.
+         oldsym = ins.first->second;
+         assert(oldsym != NULL);
+         sym = NULL;
+       }
+      else
+       {
+         // We haven't seen this symbol before.
+         assert(ins.first->second == NULL);
+
+         if (!target->has_make_symbol())
+           sym = new Sized_symbol<size>();
+         else
+           {
+             assert(target->get_size() == size);
+             assert(target->is_big_endian() ? big_endian : !big_endian);
+             typedef Sized_target<size, big_endian> My_target;
+             My_target* sized_target = static_cast<My_target*>(target);
+             sym = sized_target->make_symbol();
+             if (sym == NULL)
+               return NULL;
+           }
+
+         ins.first->second = sym;
+         oldsym = NULL;
+       }
+    }
+
+  if (oldsym != NULL)
+    {
+      assert(sym == NULL);
+
+      sym = this->get_sized_symbol SELECT_SIZE_NAME (oldsym
+                                                    SELECT_SIZE(size));
+      assert(sym->source() == Symbol::FROM_OBJECT);
+      const int old_shnum = sym->shnum();
+      if (old_shnum != elfcpp::SHN_UNDEF
+         && old_shnum != elfcpp::SHN_COMMON
+         && !sym->object()->is_dynamic())
+       {
+         fprintf(stderr, "%s: linker defined: multiple definition of %s\n",
+                 program_name, name);
+         // FIXME: Report old location.  Record that we have seen an
+         // error.
+         return NULL;
+       }
+
+      // Our new definition is going to override the old reference.
+    }
+
+  return sym;
+}
+
+// Define a symbol based on an Output_data.
+
+void
+Symbol_table::define_in_output_data(Target* target, const char* name,
+                                   Output_data* od,
+                                   uint64_t value, uint64_t symsize,
+                                   elfcpp::STT type, elfcpp::STB binding,
+                                   elfcpp::STV visibility,
+                                   unsigned char nonvis,
+                                   bool offset_is_from_end,
+                                   bool only_if_ref)
+{
+  assert(target->get_size() == this->size_);
+  if (this->size_ == 32)
+    this->do_define_in_output_data<32>(target, name, od, value, symsize,
+                                      type, binding, visibility, nonvis,
+                                      offset_is_from_end, only_if_ref);
+  else if (this->size_ == 64)
+    this->do_define_in_output_data<64>(target, name, od, value, symsize,
+                                      type, binding, visibility, nonvis,
+                                      offset_is_from_end, only_if_ref);
+  else
+    abort();
+}
+
+// Define a symbol in an Output_data, sized version.
+
+template<int size>
+void
+Symbol_table::do_define_in_output_data(
+    Target* target,
+    const char* name,
+    Output_data* od,
+    typename elfcpp::Elf_types<size>::Elf_Addr value,
+    typename elfcpp::Elf_types<size>::Elf_WXword symsize,
+    elfcpp::STT type,
+    elfcpp::STB binding,
+    elfcpp::STV visibility,
+    unsigned char nonvis,
+    bool offset_is_from_end,
+    bool only_if_ref)
+{
+  Sized_symbol<size>* sym;
+
+  if (target->is_big_endian())
+    sym = this->define_special_symbol<size, true>(target, name, only_if_ref);
+  else
+    sym = this->define_special_symbol<size, false>(target, name, only_if_ref);
+
+  if (sym == NULL)
+    return;
+
+  sym->init(name, od, value, symsize, type, binding, visibility, nonvis,
+           offset_is_from_end);
+}
+
+// Define a symbol based on an Output_segment.
+
+void
+Symbol_table::define_in_output_segment(Target* target, const char* name,
+                                      Output_segment* os,
+                                      uint64_t value, uint64_t symsize,
+                                      elfcpp::STT type, elfcpp::STB binding,
+                                      elfcpp::STV visibility,
+                                      unsigned char nonvis,
+                                      Symbol::Segment_offset_base offset_base,
+                                      bool only_if_ref)
+{
+  assert(target->get_size() == this->size_);
+  if (this->size_ == 32)
+    this->do_define_in_output_segment<32>(target, name, os, value, symsize,
+                                         type, binding, visibility, nonvis,
+                                         offset_base, only_if_ref);
+  else if (this->size_ == 64)
+    this->do_define_in_output_segment<64>(target, name, os, value, symsize,
+                                         type, binding, visibility, nonvis,
+                                         offset_base, only_if_ref);
+  else
+    abort();
+}
+
+// Define a symbol in an Output_segment, sized version.
+
+template<int size>
+void
+Symbol_table::do_define_in_output_segment(
+    Target* target,
+    const char* name,
+    Output_segment* os,
+    typename elfcpp::Elf_types<size>::Elf_Addr value,
+    typename elfcpp::Elf_types<size>::Elf_WXword symsize,
+    elfcpp::STT type,
+    elfcpp::STB binding,
+    elfcpp::STV visibility,
+    unsigned char nonvis,
+    Symbol::Segment_offset_base offset_base,
+    bool only_if_ref)
+{
+  Sized_symbol<size>* sym;
+
+  if (target->is_big_endian())
+    sym = this->define_special_symbol<size, true>(target, name, only_if_ref);
+  else
+    sym = this->define_special_symbol<size, false>(target, name, only_if_ref);
+
+  if (sym == NULL)
+    return;
+
+  sym->init(name, os, value, symsize, type, binding, visibility, nonvis,
+           offset_base);
+}
+
+// Define a special symbol with a constant value.  It is a multiple
+// definition error if this symbol is already defined.
+
+void
+Symbol_table::define_as_constant(Target* target, const char* name,
+                                uint64_t value, uint64_t symsize,
+                                elfcpp::STT type, elfcpp::STB binding,
+                                elfcpp::STV visibility, unsigned char nonvis,
+                                bool only_if_ref)
+{
+  assert(target->get_size() == this->size_);
+  if (this->size_ == 32)
+    this->do_define_as_constant<32>(target, name, value, symsize,
+                                   type, binding, visibility, nonvis,
+                                   only_if_ref);
+  else if (this->size_ == 64)
+    this->do_define_as_constant<64>(target, name, value, symsize,
+                                   type, binding, visibility, nonvis,
+                                   only_if_ref);
+  else
+    abort();
+}
+
+// Define a symbol as a constant, sized version.
+
+template<int size>
+void
+Symbol_table::do_define_as_constant(
+    Target* target,
+    const char* name,
+    typename elfcpp::Elf_types<size>::Elf_Addr value,
+    typename elfcpp::Elf_types<size>::Elf_WXword symsize,
+    elfcpp::STT type,
+    elfcpp::STB binding,
+    elfcpp::STV visibility,
+    unsigned char nonvis,
+    bool only_if_ref)
+{
+  Sized_symbol<size>* sym;
+
+  if (target->is_big_endian())
+    sym = this->define_special_symbol<size, true>(target, name, only_if_ref);
+  else
+    sym = this->define_special_symbol<size, false>(target, name, only_if_ref);
+
+  if (sym == NULL)
+    return;
+
+  sym->init(name, value, symsize, type, binding, visibility, nonvis);
+}
+
+// Define a set of symbols in output sections.
+
+void
+Symbol_table::define_symbols(const Layout* layout, Target* target, int count,
+                            const Define_symbol_in_section* p)
+{
+  for (int i = 0; i < count; ++i, ++p)
+    {
+      Output_section* os = layout->find_output_section(p->output_section);
+      if (os != NULL)
+       this->define_in_output_data(target, p->name, os, p->value, p->size,
+                                   p->type, p->binding, p->visibility,
+                                   p->nonvis, p->offset_is_from_end,
+                                   p->only_if_ref);
+      else
+       this->define_as_constant(target, p->name, 0, p->size, p->type,
+                                p->binding, p->visibility, p->nonvis,
+                                p->only_if_ref);
+    }
+}
+
+// Define a set of symbols in output segments.
+
+void
+Symbol_table::define_symbols(const Layout* layout, Target* target, int count,
+                            const Define_symbol_in_segment* p)
+{
+  for (int i = 0; i < count; ++i, ++p)
+    {
+      Output_segment* os = layout->find_output_segment(p->segment_type,
+                                                      p->segment_flags_set,
+                                                      p->segment_flags_clear);
+      if (os != NULL)
+       this->define_in_output_segment(target, p->name, os, p->value, p->size,
+                                      p->type, p->binding, p->visibility,
+                                      p->nonvis, p->offset_base,
+                                      p->only_if_ref);
+      else
+       this->define_as_constant(target, p->name, 0, p->size, p->type,
+                                p->binding, p->visibility, p->nonvis,
+                                p->only_if_ref);
+    }
+}
+
 // Set the final values for all the symbols.  Record the file offset
 // OFF.  Add their names to POOL.  Return the new file offset.
 
@@ -383,13 +804,15 @@ Symbol_table::finalize(off_t off, Stringpool* pool)
     abort();
 }
 
-// Set the final value for all the symbols.
+// Set the final value for all the symbols.  This is called after
+// Layout::finalize, so all the output sections have their final
+// address.
 
 template<int size>
 off_t
 Symbol_table::sized_finalize(off_t off, Stringpool* pool)
 {
-  off = (off + (size >> 3) - 1) & ~ ((size >> 3) - 1);
+  off = align_address(off, size >> 3);
   this->offset_ = off;
 
   const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
@@ -402,34 +825,91 @@ Symbol_table::sized_finalize(off_t off, Stringpool* pool)
       // FIXME: Here we need to decide which symbols should go into
       // the output file.
 
-      // FIXME: This is wrong.
-      if (sym->shnum() >= elfcpp::SHN_LORESERVE)
-       {
-         ++p;
-         continue;
-       }
-
-      off_t secoff;
-      Output_section* os = sym->object()->output_section(sym->shnum(),
-                                                        &secoff);
+      typename Sized_symbol<size>::Value_type value;
 
-      if (os == NULL)
-       {
-         // We should be able to erase this symbol from the symbol
-         // table, but at least with gcc 4.0.2
-         // std::unordered_map::erase doesn't appear to return the
-         // new iterator.
-         // p = this->table_.erase(p);
-         ++p;
-       }
-      else
+      switch (sym->source())
        {
-         sym->set_value(sym->value() + os->address() + secoff);
-         pool->add(sym->name());
-         ++p;
-         ++count;
-         off += sym_size;
+       case Symbol::FROM_OBJECT:
+         {
+           unsigned int shnum = sym->shnum();
+
+           // FIXME: We need some target specific support here.
+           if (shnum >= elfcpp::SHN_LORESERVE
+               && shnum != elfcpp::SHN_ABS)
+             {
+               fprintf(stderr, _("%s: %s: unsupported symbol section 0x%x\n"),
+                       program_name, sym->name(), shnum);
+               gold_exit(false);
+             }
+
+           if (shnum == elfcpp::SHN_UNDEF)
+             value = 0;
+           else if (shnum == elfcpp::SHN_ABS)
+             value = sym->value();
+           else
+             {
+               off_t secoff;
+               Output_section* os = sym->object()->output_section(shnum,
+                                                                  &secoff);
+
+               if (os == NULL)
+                 {
+                   // We should be able to erase this symbol from the
+                   // symbol table, but at least with gcc 4.0.2
+                   // std::unordered_map::erase doesn't appear to return
+                   // the new iterator.
+                   // p = this->table_.erase(p);
+                   ++p;
+                   continue;
+                 }
+
+               value = sym->value() + os->address() + secoff;
+             }
+         }
+         break;
+
+       case Symbol::IN_OUTPUT_DATA:
+         {
+           Output_data* od = sym->output_data();
+           value = sym->value() + od->address();
+           if (sym->offset_is_from_end())
+             value += od->data_size();
+         }
+         break;
+
+       case Symbol::IN_OUTPUT_SEGMENT:
+         {
+           Output_segment* os = sym->output_segment();
+           value = sym->value() + os->vaddr();
+           switch (sym->offset_base())
+             {
+             case Symbol::SEGMENT_START:
+               break;
+             case Symbol::SEGMENT_END:
+               value += os->memsz();
+               break;
+             case Symbol::SEGMENT_BSS:
+               value += os->filesz();
+               break;
+             default:
+               abort();
+             }
+         }
+         break;
+
+       case Symbol::CONSTANT:
+         value = sym->value();
+         break;
+
+       default:
+         abort();
        }
+
+      sym->set_value(value);
+      pool->add(sym->name());
+      ++count;
+      off += sym_size;
+      ++p;
     }
 
   this->output_count_ = count;
@@ -481,23 +961,61 @@ Symbol_table::sized_write_globals(const Target*,
 
       // FIXME: This repeats sized_finalize().
 
-      // FIXME: This is wrong.
-      if (sym->shnum() >= elfcpp::SHN_LORESERVE)
-       continue;
-
-      off_t secoff;
-      Output_section* os = sym->object()->output_section(sym->shnum(),
-                                                        &secoff);
-      if (os == NULL)
-       continue;
+      unsigned int shndx;
+      switch (sym->source())
+       {
+       case Symbol::FROM_OBJECT:
+         {
+           unsigned int shnum = sym->shnum();
+
+           // FIXME: We need some target specific support here.
+           if (shnum >= elfcpp::SHN_LORESERVE
+               && shnum != elfcpp::SHN_ABS)
+             {
+               fprintf(stderr, _("%s: %s: unsupported symbol section 0x%x\n"),
+                       program_name, sym->name(), sym->shnum());
+               gold_exit(false);
+             }
+
+           if (shnum == elfcpp::SHN_UNDEF || shnum == elfcpp::SHN_ABS)
+             shndx = shnum;
+           else
+             {
+               off_t secoff;
+               Output_section* os = sym->object()->output_section(shnum,
+                                                                  &secoff);
+               if (os == NULL)
+                 continue;
+
+               shndx = os->out_shndx();
+             }
+         }
+         break;
+
+       case Symbol::IN_OUTPUT_DATA:
+         shndx = sym->output_data()->out_shndx();
+         break;
+
+       case Symbol::IN_OUTPUT_SEGMENT:
+         shndx = elfcpp::SHN_ABS;
+         break;
+
+       case Symbol::CONSTANT:
+         shndx = elfcpp::SHN_ABS;
+         break;
+
+       default:
+         abort();
+       }
 
       elfcpp::Sym_write<size, big_endian> osym(ps);
       osym.put_st_name(sympool->get_offset(sym->name()));
       osym.put_st_value(sym->value());
       osym.put_st_size(sym->symsize());
       osym.put_st_info(elfcpp::elf_st_info(sym->binding(), sym->type()));
-      osym.put_st_other(elfcpp::elf_st_other(sym->visibility(), sym->other()));
-      osym.put_st_shndx(os->shndx());
+      osym.put_st_other(elfcpp::elf_st_other(sym->visibility(),
+                                            sym->nonvis()));
+      osym.put_st_shndx(shndx);
 
       ps += sym_size;
     }
index 2c5fbc9..40a9e57 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <string>
 #include <utility>
+#include <vector>
 #include <cassert>
 
 #include "elfcpp.h"
@@ -17,6 +18,8 @@ namespace gold
 {
 
 class Object;
+class Output_data;
+class Output_segment;
 class Output_file;
 class Target;
 
@@ -31,6 +34,37 @@ class Sized_object;
 class Symbol
 {
  public:
+  // Because we want the class to be small, we don't use any virtual
+  // functions.  But because symbols can be defined in different
+  // places, we need to classify them.  This enum is the different
+  // sources of symbols we support.
+  enum Source
+  {
+    // Symbol defined in an input file--this is the most common case.
+    FROM_OBJECT,
+    // Symbol defined in an Output_data, a special section created by
+    // the target.
+    IN_OUTPUT_DATA,
+    // Symbol defined in an Output_segment, with no associated
+    // section.
+    IN_OUTPUT_SEGMENT,
+    // Symbol value is constant.
+    CONSTANT
+  };
+
+  // When the source is IN_OUTPUT_SEGMENT, we need to describe what
+  // the offset means.
+  enum Segment_offset_base
+  {
+    // From the start of the segment.
+    SEGMENT_START,
+    // From the end of the segment.
+    SEGMENT_END,
+    // From the filesz of the segment--i.e., after the loaded bytes
+    // but before the bytes which are allocated but zeroed.
+    SEGMENT_BSS
+  };
+
   // Return the symbol name.
   const char*
   name() const
@@ -42,10 +76,64 @@ class Symbol
   version() const
   { return this->version_; }
 
+  // Return the symbol source.
+  Source
+  source() const
+  { return this->source_; }
+
   // Return the object with which this symbol is associated.
   Object*
   object() const
-  { return this->object_; }
+  {
+    assert(this->source_ == FROM_OBJECT);
+    return this->u_.from_object.object;
+  }
+
+  // Return the index of the section in the input object file.
+  unsigned int
+  shnum() const
+  {
+    assert(this->source_ == FROM_OBJECT);
+    return this->u_.from_object.shnum;
+  }
+
+  // Return the output data section with which this symbol is
+  // associated, if the symbol was specially defined with respect to
+  // an output data section.
+  Output_data*
+  output_data() const
+  {
+    assert(this->source_ == IN_OUTPUT_DATA);
+    return this->u_.in_output_data.output_data;
+  }
+
+  // If this symbol was defined with respect to an output data
+  // section, return whether the value is an offset from end.
+  bool
+  offset_is_from_end() const
+  {
+    assert(this->source_ == IN_OUTPUT_DATA);
+    return this->u_.in_output_data.offset_is_from_end;
+  }
+
+  // Return the output segment with which this symbol is associated,
+  // if the symbol was specially defined with respect to an output
+  // segment.
+  Output_segment*
+  output_segment() const
+  {
+    assert(this->source_ == IN_OUTPUT_SEGMENT);
+    return this->u_.in_output_segment.output_segment;
+  }
+
+  // If this symbol was defined with respect to an output segment,
+  // return the offset base.
+  Segment_offset_base
+  offset_base() const
+  {
+    assert(this->source_ == IN_OUTPUT_SEGMENT);
+    return this->u_.in_output_segment.offset_base;
+  }
 
   // Return the symbol binding.
   elfcpp::STB
@@ -64,13 +152,8 @@ class Symbol
 
   // Return the non-visibility part of the st_other field.
   unsigned char
-  other() const
-  { return this->other_; }
-
-  // Return the section index.
-  unsigned int
-  shnum() const
-  { return this->shnum_; }
+  nonvis() const
+  { return this->nonvis_; }
 
   // Return whether this symbol is a forwarder.  This will never be
   // true of a symbol found in the hash table, but may be true of
@@ -94,11 +177,49 @@ class Symbol
   set_in_dyn()
   { this->in_dyn_ = true; }
 
-  // Return whether this symbol needs an entry in the dynamic symbol
-  // table.  FIXME: Needs to be fleshed out.
+  // Return whether this symbol has an entry in the GOT section.
   bool
-  in_dynsym() const
-  { return this->in_dyn_; }
+  has_got_offset() const
+  { return this->has_got_offset_; }
+
+  // Return the offset into the GOT section of this symbol.
+  unsigned int
+  got_offset() const
+  {
+    assert(this->has_got_offset());
+    return this->got_offset_;
+  }
+
+  // Set the GOT offset of this symbol.
+  void
+  set_got_offset(unsigned int got_offset)
+  {
+    this->has_got_offset_ = true;
+    this->got_offset_ = got_offset;
+  }
+
+  // Return whether this symbol is resolved locally.  This is always
+  // true when linking statically.  It is true for a symbol defined in
+  // this object when using -Bsymbolic.  It is true for a symbol
+  // marked local in a version file.  FIXME: This needs to be
+  // completed.
+  bool
+  is_resolved_locally() const
+  { return !this->in_dyn_; }
+
+  // Return whether this is an undefined symbol.
+  bool
+  is_undefined() const
+  {
+    return this->source_ == FROM_OBJECT && this->shnum() == elfcpp::SHN_UNDEF;
+  }
+
+  // Return whether this is a common symbol.
+  bool
+  is_common() const
+  {
+    return this->source_ == FROM_OBJECT && this->shnum() == elfcpp::SHN_COMMON;
+  }
 
  protected:
   // Instances of this class should always be created at a specific
@@ -106,12 +227,34 @@ class Symbol
   Symbol()
   { }
 
+  // Initialize the general fields.
+  void
+  init_fields(const char* name, const char* version,
+             elfcpp::STT type, elfcpp::STB binding,
+             elfcpp::STV visibility, unsigned char nonvis);
+
   // Initialize fields from an ELF symbol in OBJECT.
   template<int size, bool big_endian>
   void
   init_base(const char *name, const char* version, Object* object,
            const elfcpp::Sym<size, big_endian>&);
 
+  // Initialize fields for an Output_data.
+  void
+  init_base(const char* name, Output_data*, elfcpp::STT, elfcpp::STB,
+           elfcpp::STV, unsigned char nonvis, bool offset_is_from_end);
+
+  // Initialize fields for an Output_segment.
+  void
+  init_base(const char* name, Output_segment* os, elfcpp::STT type,
+           elfcpp::STB binding, elfcpp::STV visibility,
+           unsigned char nonvis, Segment_offset_base offset_base);
+
+  // Initialize fields for a constant.
+  void
+  init_base(const char* name, elfcpp::STT type, elfcpp::STB binding,
+           elfcpp::STV visibility, unsigned char nonvis);
+
   // Override existing symbol.
   template<int size, bool big_endian>
   void
@@ -126,10 +269,45 @@ class Symbol
   // 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_;
+
+  union
+  {
+    // This struct is used if SOURCE_ == FROM_OBJECT.
+    struct
+    {
+      // Object in which symbol is defined, or in which it was first
+      // seen.
+      Object* object;
+      // Section number in object_ in which symbol is defined.
+      unsigned int shnum;
+    } from_object;
+
+    // This struct is used if SOURCE_ == IN_OUTPUT_DATA.
+    struct
+    {
+      // Output_data in which symbol is defined.  Before
+      // Layout::finalize the symbol's value is an offset within the
+      // Output_data.
+      Output_data* output_data;
+      // True if the offset is from the end, false if the offset is
+      // from the beginning.
+      bool offset_is_from_end;
+    } in_output_data;
+
+    // This struct is used if SOURCE_ == IN_OUTPUT_SEGMENT.
+    struct
+    {
+      // Output_segment in which the symbol is defined.  Before
+      // Layout::finalize the symbol's value is an offset.
+      Output_segment* output_segment;
+      // The base to use for the offset before Layout::finalize.
+      Segment_offset_base offset_base;
+    } in_output_segment;
+  } u_;
+
+  // If this symbol has an entry in the GOT section (has_got_offset_
+  // is true), this is the offset.
+  unsigned int got_offset_;
   // Symbol type.
   elfcpp::STT type_ : 4;
   // Symbol binding.
@@ -137,10 +315,12 @@ class Symbol
   // Symbol visibility.
   elfcpp::STV visibility_ : 2;
   // Rest of symbol st_other field.
-  unsigned int other_ : 6;
+  unsigned int nonvis_ : 6;
+  // The type of symbol.
+  Source source_ : 2;
   // True if this symbol always requires special target-specific
   // handling.
-  bool is_special_ : 1;
+  bool is_target_special_ : 1;
   // True if this is the default version of the symbol.
   bool is_def_ : 1;
   // True if this symbol really forwards to another symbol.  This is
@@ -153,6 +333,8 @@ class Symbol
   bool is_forwarder_ : 1;
   // True if we've seen this symbol in a dynamic object.
   bool in_dyn_ : 1;
+  // True if the symbol has an entry in the GOT section.
+  bool has_got_offset_ : 1;
 };
 
 // The parts of a symbol which are size specific.  Using a template
@@ -174,6 +356,23 @@ class Sized_symbol : public Symbol
   init(const char *name, const char* version, Object* object,
        const elfcpp::Sym<size, big_endian>&);
 
+  // Initialize fields for an Output_data.
+  void
+  init(const char* name, Output_data*, Value_type value, Size_type symsize,
+       elfcpp::STT, elfcpp::STB, elfcpp::STV, unsigned char nonvis,
+       bool offset_is_from_end);
+
+  // Initialize fields for an Output_segment.
+  void
+  init(const char* name, Output_segment*, Value_type value, Size_type symsize,
+       elfcpp::STT, elfcpp::STB, elfcpp::STV, unsigned char nonvis,
+       Segment_offset_base offset_base);
+
+  // Initialize fields for a constant.
+  void
+  init(const char* name, Value_type value, Size_type symsize,
+       elfcpp::STT, elfcpp::STB, elfcpp::STV, unsigned char nonvis);
+
   // Override existing symbol.
   template<bool big_endian>
   void
@@ -188,7 +387,12 @@ class Sized_symbol : public Symbol
   // is a template parameter).
   Size_type
   symsize() const
-  { return this->size_; }
+  { return this->symsize_; }
+
+  // Set the symbol size.  This is used when resolving common symbols.
+  void
+  set_symsize(Size_type symsize)
+  { this->symsize_ = symsize; }
 
   // Set the symbol value.  This is called when we store the final
   // values of the symbols into the symbol table.
@@ -200,10 +404,84 @@ class Sized_symbol : public Symbol
   Sized_symbol(const Sized_symbol&);
   Sized_symbol& operator=(const Sized_symbol&);
 
-  // Symbol value.
+  // Symbol value.  Before Layout::finalize this is the offset in the
+  // input section.  This is set to the final value during
+  // Layout::finalize.
   Value_type value_;
   // Symbol size.
-  Size_type size_;
+  Size_type symsize_;
+};
+
+// A struct describing a symbol defined by the linker, where the value
+// of the symbol is defined based on an output section.  This is used
+// for symbols defined by the linker, like "_init_array_start".
+
+struct Define_symbol_in_section
+{
+  // The symbol name.
+  const char* name;
+  // The name of the output section with which this symbol should be
+  // associated.  If there is no output section with that name, the
+  // symbol will be defined as zero.
+  const char* output_section;
+  // The offset of the symbol within the output section.  This is an
+  // offset from the start of the output section, unless start_at_end
+  // is true, in which case this is an offset from the end of the
+  // output section.
+  uint64_t value;
+  // The size of the symbol.
+  uint64_t size;
+  // The symbol type.
+  elfcpp::STT type;
+  // The symbol binding.
+  elfcpp::STB binding;
+  // The symbol visibility.
+  elfcpp::STV visibility;
+  // The rest of the st_other field.
+  unsigned char nonvis;
+  // If true, the value field is an offset from the end of the output
+  // section.
+  bool offset_is_from_end;
+  // If true, this symbol is defined only if we see a reference to it.
+  bool only_if_ref;
+};
+
+// A struct describing a symbol defined by the linker, where the value
+// of the symbol is defined based on a segment.  This is used for
+// symbols defined by the linker, like "_end".  We describe the
+// segment with which the symbol should be associated by its
+// characteristics.  If no segment meets these characteristics, the
+// symbol will be defined as zero.  If there is more than one segment
+// which meets these characteristics, we will use the first one.
+
+struct Define_symbol_in_segment
+{
+  // The symbol name.
+  const char* name;
+  // The segment type where the symbol should be defined, typically
+  // PT_LOAD.
+  elfcpp::PT segment_type;
+  // Bitmask of segment flags which must be set.
+  elfcpp::PF segment_flags_set;
+  // Bitmask of segment flags which must be clear.
+  elfcpp::PF segment_flags_clear;
+  // The offset of the symbol within the segment.  The offset is
+  // calculated from the position set by offset_base.
+  uint64_t value;
+  // The size of the symbol.
+  uint64_t size;
+  // The symbol type.
+  elfcpp::STT type;
+  // The symbol binding.
+  elfcpp::STB binding;
+  // The symbol visibility.
+  elfcpp::STV visibility;
+  // The rest of the st_other field.
+  unsigned char nonvis;
+  // The base from which we compute the offset.
+  Symbol::Segment_offset_base offset_base;
+  // If true, this symbol is defined only if we see a reference to it.
+  bool only_if_ref;
 };
 
 // The main linker symbol table.
@@ -226,6 +504,47 @@ class Symbol_table
                  size_t count, const char* sym_names, size_t sym_name_size,
                  Symbol** sympointers);
 
+  // Define a special symbol.
+  template<int size, bool big_endian>
+  Sized_symbol<size>*
+  define_special_symbol(Target* target, const char* name, bool only_if_ref);
+
+  // Define a special symbol based on an Output_data.  It is a
+  // multiple definition error if this symbol is already defined.
+  void
+  define_in_output_data(Target*, const char* name, Output_data*,
+                       uint64_t value, uint64_t symsize,
+                       elfcpp::STT type, elfcpp::STB binding,
+                       elfcpp::STV visibility, unsigned char nonvis,
+                       bool offset_is_from_end, bool only_if_ref);
+
+  // Define a special symbol based on an Output_segment.  It is a
+  // multiple definition error if this symbol is already defined.
+  void
+  define_in_output_segment(Target*, const char* name, Output_segment*,
+                          uint64_t value, uint64_t symsize,
+                          elfcpp::STT type, elfcpp::STB binding,
+                          elfcpp::STV visibility, unsigned char nonvis,
+                          Symbol::Segment_offset_base, bool only_if_ref);
+
+  // Define a special symbol with a constant value.  It is a multiple
+  // definition error if this symbol is already defined.
+  void
+  define_as_constant(Target*, const char* name, uint64_t value,
+                    uint64_t symsize, elfcpp::STT type, elfcpp::STB binding,
+                    elfcpp::STV visibility, unsigned char nonvis,
+                    bool only_if_ref);
+
+  // Define a set of symbols in output sections.
+  void
+  define_symbols(const Layout*, Target*, int count,
+                const Define_symbol_in_section*);
+
+  // Define a set of symbols in output segments.
+  void
+  define_symbols(const Layout*, Target*, int count,
+                const Define_symbol_in_segment*);  
+
   // Look up a symbol.
   Symbol*
   lookup(const char*, const char* version = NULL) const;
@@ -248,6 +567,15 @@ class Symbol_table
   const Sized_symbol<size>*
   get_sized_symbol(const Symbol* ACCEPT_SIZE) const;
 
+  // Return the count of undefined symbols seen.
+  int
+  saw_undefined() const
+  { return this->saw_undefined_; }
+
+  // Allocate the common symbols
+  void
+  allocate_commons(const General_options&, Layout*);
+
   // Finalize the symbol table after we have set the final addresses
   // of all the input sections.  This sets the final symbol values and
   // adds the names to *POOL.  It records the file offset OFF, and
@@ -291,6 +619,43 @@ class Symbol_table
   resolve(Sized_symbol<size>* to, const Sized_symbol<size>* from
           ACCEPT_SIZE_ENDIAN);
 
+  // Define a symbol in an Output_data, sized version.
+  template<int size>
+  void
+  do_define_in_output_data(Target*, const char* name, Output_data*,
+                          typename elfcpp::Elf_types<size>::Elf_Addr value,
+                          typename elfcpp::Elf_types<size>::Elf_WXword ssize,
+                          elfcpp::STT type, elfcpp::STB binding,
+                          elfcpp::STV visibility, unsigned char nonvis,
+                          bool offset_is_from_end, bool only_if_ref);
+
+  // Define a symbol in an Output_segment, sized version.
+  template<int size>
+  void
+  do_define_in_output_segment(
+    Target*, const char* name, Output_segment* os,
+    typename elfcpp::Elf_types<size>::Elf_Addr value,
+    typename elfcpp::Elf_types<size>::Elf_WXword ssize,
+    elfcpp::STT type, elfcpp::STB binding,
+    elfcpp::STV visibility, unsigned char nonvis,
+    Symbol::Segment_offset_base offset_base, bool only_if_ref);
+
+  // Define a symbol as a constant, sized version.
+  template<int size>
+  void
+  do_define_as_constant(
+    Target*, const char* name,
+    typename elfcpp::Elf_types<size>::Elf_Addr value,
+    typename elfcpp::Elf_types<size>::Elf_WXword ssize,
+    elfcpp::STT type, elfcpp::STB binding,
+    elfcpp::STV visibility, unsigned char nonvis,
+    bool only_if_ref);
+
+  // Allocate the common symbols, sized version.
+  template<int size>
+  void
+  do_allocate_commons(const General_options&, Layout*);
+
   // Finalize symbols specialized for size.
   template<int size>
   off_t
@@ -320,9 +685,17 @@ class Symbol_table
   typedef Unordered_map<Symbol_table_key, Symbol*, Symbol_table_hash,
                        Symbol_table_eq> Symbol_table_type;
 
+  // The type of the list of common symbols.
+
+  typedef std::vector<Symbol*> Commons_type;
+
   // The size of the symbols in the symbol table (32 or 64).
   int size_;
 
+  // We increment this every time we see a new undefined symbol, for
+  // use in archive groups.
+  int saw_undefined_;
+
   // The file offset within the output symtab section where we should
   // write the table.
   off_t offset_;
@@ -339,6 +712,13 @@ class Symbol_table
 
   // Forwarding symbols.
   Unordered_map<Symbol*, Symbol*> forwarders_;
+
+  // We don't expect there to be very many common symbols, so we keep
+  // a list of them.  When we find a common symbol we add it to this
+  // list.  It is possible that by the time we process the list the
+  // symbol is no longer a common symbol.  It may also have become a
+  // forwarder.
+  Commons_type commons_;
 };
 
 // We inline get_sized_symbol for efficiency.
index 2d1fe30..ebaa827 100644 (file)
@@ -36,11 +36,14 @@ struct Reloc_types<elfcpp::SHT_RELA, size, big_endian>
 // way to avoidmaking a function call for each relocation, and to
 // avoid repeating the generic code for each target.
 
-template<int size, bool big_endian, int sh_type, typename Scan>
+template<int size, bool big_endian, typename Target_type, int sh_type,
+        typename Scan>
 inline void
 scan_relocs(
     const General_options& options,
     Symbol_table* symtab,
+    Layout* layout,
+    Target_type* target,
     Sized_object<size, big_endian>* object,
     const unsigned char* prelocs,
     size_t reloc_count,
@@ -68,6 +71,7 @@ scan_relocs(
                                                      + r_sym * sym_size);
          const unsigned int shndx = lsym.get_st_shndx();
          if (shndx < elfcpp::SHN_LORESERVE
+             && shndx != elfcpp::SHN_UNDEF
              && !object->is_section_included(lsym.get_st_shndx()))
            {
              // RELOC is a relocation against a local symbol in a
@@ -88,7 +92,8 @@ scan_relocs(
              continue;
            }
 
-         scan.local(options, object, reloc, r_type, lsym);
+         scan.local(options, symtab, layout, target, object, reloc, r_type,
+                    lsym);
        }
       else
        {
@@ -97,7 +102,8 @@ scan_relocs(
          if (gsym->is_forwarder())
            gsym = symtab->resolve_forwards(gsym);
 
-         scan.global(options, object, reloc, r_type, gsym);
+         scan.global(options, symtab, layout, target, object, reloc, r_type,
+                     gsym);
        }
     }
 }
@@ -117,10 +123,12 @@ scan_relocs(
 // of relocs.  VIEW is the section data, VIEW_ADDRESS is its memory
 // address, and VIEW_SIZE is the size.
 
-template<int size, bool big_endian, int sh_type, typename Relocate>
+template<int size, bool big_endian, typename Target_type, int sh_type,
+        typename Relocate>
 inline void
 relocate_section(
     const Relocate_info<size, big_endian>* relinfo,
+    Target_type* target,
     const unsigned char* prelocs,
     size_t reloc_count,
     unsigned char* view,
@@ -140,13 +148,6 @@ relocate_section(
       Reltype reloc(prelocs);
 
       off_t offset = reloc.get_r_offset();
-      if (offset < 0 || offset >= view_size)
-       {
-         fprintf(stderr, _("%s: %s: reloc has bad offset %zu\n"),
-                 program_name, relinfo->location(i, offset).c_str(),
-                 static_cast<size_t>(offset));
-         gold_exit(false);
-       }
 
       typename elfcpp::Elf_types<size>::Elf_WXword r_info = reloc.get_r_info();
       unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
@@ -169,19 +170,29 @@ relocate_section(
 
          sym = static_cast<Sized_symbol<size>*>(gsym);
          value = sym->value();
+       }
 
-         if (sym->shnum() == elfcpp::SHN_UNDEF
-             && sym->binding() != elfcpp::STB_WEAK)
-           {
-             fprintf(stderr, _("%s: %s: undefined reference to '%s'\n"),
-                     program_name, relinfo->location(i, offset).c_str(),
-                     sym->name());
-             // gold_exit(false);
-           }
+      if (!relocate.relocate(relinfo, target, i, reloc, r_type, sym, value,
+                            view + offset, view_address + offset, view_size))
+       continue;
+
+      if (offset < 0 || offset >= view_size)
+       {
+         fprintf(stderr, _("%s: %s: reloc has bad offset %zu\n"),
+                 program_name, relinfo->location(i, offset).c_str(),
+                 static_cast<size_t>(offset));
+         gold_exit(false);
        }
 
-      relocate.relocate(relinfo, i, reloc, r_type, sym, value, view + offset,
-                       view_address + offset, view_size);
+      if (sym != NULL
+         && sym->is_undefined()
+         && sym->binding() != elfcpp::STB_WEAK)
+       {
+         fprintf(stderr, _("%s: %s: undefined reference to '%s'\n"),
+                 program_name, relinfo->location(i, offset).c_str(),
+                 sym->name());
+         // gold_exit(false);
+       }
     }
 }
 
index 28b7527..d15d0e3 100644 (file)
@@ -34,7 +34,7 @@ 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())
+  for (Target_selector* p = target_selectors; p != NULL; p = p->next())
     {
       int pmach = p->machine();
       if ((pmach == machine || pmach == elfcpp::EM_NONE)
index 0762d58..8ccd75f 100644 (file)
@@ -29,7 +29,7 @@ class 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;
+  virtual Target* recognize(int machine, int osabi, int abiversion) = 0;
 
   // Return the next Target_selector in the linked list.
   Target_selector*
index 75f149e..b72998d 100644 (file)
@@ -149,6 +149,7 @@ class Sized_target : public Target
   virtual void
   scan_relocs(const General_options& options,
              Symbol_table* symtab,
+             Layout* layout,
              Sized_object<size, big_endian>* object,
              unsigned int sh_type,
              const unsigned char* prelocs,
index 5cce2d5..ed7a5b0 100644 (file)
 #define GOLD_WORKQUEUE_H
 
 #include "gold-threads.h"
-#include "options.h"
 #include "fileread.h"
 
 namespace gold
 {
 
+class General_options;
 class Task;
 class Workqueue;
 
@@ -286,6 +286,10 @@ class Task
   // Run the task.
   virtual void
   run(Workqueue*) = 0;
+
+ private:
+  Task(const Task&);
+  Task& operator=(const Task&);
 };
 
 // A simple task which waits for a blocker and then runs a function.