Framework for relocation scanning. Implement simple static TLS
authorIan Lance Taylor <iant@google.com>
Fri, 20 Oct 2006 20:40:49 +0000 (20:40 +0000)
committerIan Lance Taylor <iant@google.com>
Fri, 20 Oct 2006 20:40:49 +0000 (20:40 +0000)
relocations.

24 files changed:
elfcpp/elfcpp_internal.h
gold/archive.cc
gold/config.in
gold/configure
gold/configure.ac
gold/gold.cc
gold/gold.h
gold/i386.cc
gold/layout.cc
gold/layout.h
gold/object.cc
gold/object.h
gold/options.cc
gold/options.h
gold/output.h
gold/po/gold.pot
gold/readsyms.cc
gold/reloc.cc
gold/reloc.h
gold/symtab.h
gold/target-reloc.h
gold/target.h
gold/workqueue.cc
gold/workqueue.h

index 0d69bae..e4c8636 100644 (file)
@@ -16,7 +16,7 @@ namespace elfcpp
 namespace internal
 {
 
-#ifdef WORDS_BIG_ENDIAN
+#ifdef WORDS_BIGENDIAN
 const bool host_big_endian = true;
 #else
 const bool host_big_endian = false;
index 8639643..a64109a 100644 (file)
@@ -300,7 +300,7 @@ Archive::include_member(Symbol_table* symtab, Layout* layout,
       gold_exit(false);
     }
 
-  Object* obj = make_elf_object((std::string(this->input_file_->name())
+  Object* obj = make_elf_object((std::string(this->input_file_->filename())
                                 + "(" + n + ")"),
                                this->input_file_, memoff, p, bytes);
 
index 3a452ff..1d40c66 100644 (file)
@@ -69,3 +69,7 @@
 
 /* Version number of package */
 #undef VERSION
+
+/* Define to 1 if your processor stores words with the most significant byte
+   first (like Motorola and SPARC, unlike Intel and VAX). */
+#undef WORDS_BIGENDIAN
index c0d93b7..a64cd70 100755 (executable)
@@ -3869,6 +3869,238 @@ echo "${ECHO_T}found xgettext program is not GNU xgettext; ignore it" >&6
 
 
 
+echo "$as_me:$LINENO: checking whether byte ordering is bigendian" >&5
+echo $ECHO_N "checking whether byte ordering is bigendian... $ECHO_C" >&6
+if test "${ac_cv_c_bigendian+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  # See if sys/param.h defines the BYTE_ORDER macro.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/param.h>
+
+int
+main ()
+{
+#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN
+ bogus endian macros
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  # It does; now see whether it defined to BIG_ENDIAN or not.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/param.h>
+
+int
+main ()
+{
+#if BYTE_ORDER != BIG_ENDIAN
+ not big endian
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_c_bigendian=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_c_bigendian=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+# It does not; compile a test program.
+if test "$cross_compiling" = yes; then
+  # try to guess the endianness by grepping values into an object file
+  ac_cv_c_bigendian=unknown
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+short ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
+short ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
+void _ascii () { char *s = (char *) ascii_mm; s = (char *) ascii_ii; }
+short ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
+short ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
+void _ebcdic () { char *s = (char *) ebcdic_mm; s = (char *) ebcdic_ii; }
+int
+main ()
+{
+ _ascii (); _ebcdic ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  if grep BIGenDianSyS conftest.$ac_objext >/dev/null ; then
+  ac_cv_c_bigendian=yes
+fi
+if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then
+  if test "$ac_cv_c_bigendian" = unknown; then
+    ac_cv_c_bigendian=no
+  else
+    # finding both strings is unlikely to happen, but who knows?
+    ac_cv_c_bigendian=unknown
+  fi
+fi
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+int
+main ()
+{
+  /* Are we little or big endian?  From Harbison&Steele.  */
+  union
+  {
+    long l;
+    char c[sizeof (long)];
+  } u;
+  u.l = 1;
+  exit (u.c[sizeof (long) - 1] == 1);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_c_bigendian=no
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_c_bigendian=yes
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_bigendian" >&5
+echo "${ECHO_T}$ac_cv_c_bigendian" >&6
+case $ac_cv_c_bigendian in
+  yes)
+
+cat >>confdefs.h <<\_ACEOF
+#define WORDS_BIGENDIAN 1
+_ACEOF
+ ;;
+  no)
+     ;;
+  *)
+    { { echo "$as_me:$LINENO: error: unknown endianness
+presetting ac_cv_c_bigendian=no (or yes) will help" >&5
+echo "$as_me: error: unknown endianness
+presetting ac_cv_c_bigendian=no (or yes) will help" >&2;}
+   { (exit 1); exit 1; }; } ;;
+esac
+
+
+
 
 
 GCC_WARN_CFLAGS="-W -Wall -Wstrict-prototypes -Wmissing-prototypes"
index 024ac48..42cba7f 100644 (file)
@@ -16,6 +16,8 @@ AC_PROG_INSTALL
 ZW_GNU_GETTEXT_SISTER_DIR
 AM_PO_SUBDIRS
 
+AC_C_BIGENDIAN
+
 AC_EXEEXT
 
 AM_BINUTILS_WARNINGS
index 6874e1b..c39f999 100644 (file)
@@ -56,19 +56,43 @@ gold_unreachable()
   abort();
 }
 
-} // End namespace gold.
+// This class arranges to run the functions done in the middle of the
+// link.  It is just a closure.
 
-namespace
+class Middle_runner : public Task_function_runner
 {
+ public:
+  Middle_runner(const General_options& options,
+               const Input_objects* input_objects,
+               Symbol_table* symtab,
+               Layout* layout)
+    : options_(options), input_objects_(input_objects), symtab_(symtab),
+      layout_(layout)
+  { }
+
+  void
+  run(Workqueue*);
+
+ private:
+  const General_options& options_;
+  const Input_objects* input_objects_;
+  Symbol_table* symtab_;
+  Layout* layout_;
+};
 
-using namespace gold;
+void
+Middle_runner::run(Workqueue* workqueue)
+{
+  queue_middle_tasks(this->options_, this->input_objects_, this->symtab_,
+                    this->layout_, workqueue);
+}
 
 // Queue up the initial set of tasks for this link job.
 
 void
 queue_initial_tasks(const General_options& options,
                    const Dirsearch& search_path,
-                   const Command_line::Input_argument_list& inputs,
+                   const Input_argument_list& inputs,
                    Workqueue* workqueue, Input_objects* input_objects,
                    Symbol_table* symtab, Layout* layout)
 {
@@ -80,7 +104,7 @@ 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 (Command_line::Input_argument_list::const_iterator p = inputs.begin();
+  for (Input_argument_list::const_iterator p = inputs.begin();
        p != inputs.end();
        ++p)
     {
@@ -92,14 +116,65 @@ queue_initial_tasks(const General_options& options,
       this_blocker = next_blocker;
     }
 
-  workqueue->queue(new Layout_task(options, input_objects, symtab, layout,
-                                  this_blocker));
+  workqueue->queue(new Task_function(new Middle_runner(options,
+                                                      input_objects,
+                                                      symtab,
+                                                      layout),
+                                    this_blocker));
 }
 
-} // end anonymous namespace.
+// Queue up the middle set of tasks.  These are the tasks which run
+// after all the input objects have been found and all the symbols
+// have been read, but before we lay out the output file.
 
-namespace gold
+void
+queue_middle_tasks(const General_options& options,
+                  const Input_objects* input_objects,
+                  Symbol_table* symtab,
+                  Layout* layout,
+                  Workqueue* workqueue)
 {
+  // Read the relocations of the input files.  We do this to find
+  // which symbols are used by relocations which require a GOT and/or
+  // a PLT entry, or a COPY reloc.  When we implement garbage
+  // collection we will do it here by reading the relocations in a
+  // breadth first search by references.
+  //
+  // We could also read the relocations during the first pass, and
+  // mark symbols at that time.  That is how the old GNU linker works.
+  // Doing that is more complex, since we may later decide to discard
+  // some of the sections, and thus change our minds about the types
+  // of references made to the symbols.
+  Task_token* blocker = new Task_token();
+  Task_token* symtab_lock = new Task_token();
+  for (Input_objects::Object_list::const_iterator p = input_objects->begin();
+       p != input_objects->end();
+       ++p)
+    {
+      // We can read and process the relocations in any order.  But we
+      // only want one task to write to the symbol table at a time.
+      // So we queue up a task for each object to read the
+      // relocations.  That task will in turn queue a task to wait
+      // until it can write to the symbol table.
+      blocker->add_blocker();
+      workqueue->queue(new Read_relocs(options, symtab, *p, symtab_lock,
+                                      blocker));
+    }
+
+  // Allocate common symbols.  This requires write access to the
+  // symbol table, but is independent of the relocation processing.
+  // blocker->add_blocker();
+  // workqueue->queue(new Allocate_commons_task(options, symtab, layout,
+  //                                        symtab_lock, blocker));
+
+  // When all those tasks are complete, we can start laying out the
+  // output file.
+  workqueue->queue(new Task_function(new Layout_task_runner(options,
+                                                           input_objects,
+                                                           symtab,
+                                                           layout),
+                                    blocker));
+}
 
 // Queue up the final set of tasks.  This is called at the end of
 // Layout_task.
@@ -122,8 +197,8 @@ queue_final_tasks(const General_options& options,
        ++p)
     {
       final_blocker->add_blocker();
-      workqueue->queue(new Relocate_task(options, symtab, layout->sympool(),
-                                        *p, of, final_blocker));
+      workqueue->queue(new Relocate_task(options, symtab, layout, *p, of,
+                                        final_blocker));
     }
 
   // Queue a task to write out the symbol table.
@@ -138,11 +213,14 @@ queue_final_tasks(const General_options& options,
 
   // Queue a task to close the output file.  This will be blocked by
   // FINAL_BLOCKER.
-  workqueue->queue(new Close_task(of, final_blocker));
+  workqueue->queue(new Task_function(new Close_task_runner(of),
+                                    final_blocker));
 }
 
 } // End namespace gold.
 
+using namespace gold;
+
 int
 main(int argc, char** argv)
 {
index 9ddf2f7..1140d66 100644 (file)
@@ -137,6 +137,8 @@ namespace gold
 {
 
 class General_options;
+class Input_argument_list;
+class Dirsearch;
 class Input_objects;
 class Symbol_table;
 class Layout;
@@ -166,6 +168,25 @@ gold_nomem() ATTRIBUTE_NORETURN;
 extern void
 gold_unreachable() ATTRIBUTE_NORETURN;
 
+// Queue up the first set of tasks.
+extern void
+queue_initial_tasks(const General_options&,
+                   const Dirsearch&,
+                   const Input_argument_list&,
+                   Workqueue*,
+                   Input_objects*,
+                   Symbol_table*,
+                   Layout*);
+
+// Queue up the middle set of tasks.
+extern void
+queue_middle_tasks(const General_options&,
+                  const Input_objects*,
+                  Symbol_table*,
+                  Layout*,
+                  Workqueue*);
+
+// Queue up the final set of tasks.
 extern void
 queue_final_tasks(const General_options&,
                  const Input_objects*,
index 32ee881..468cb90 100644 (file)
@@ -2,8 +2,11 @@
 
 #include "gold.h"
 #include "elfcpp.h"
+#include "reloc.h"
 #include "i386.h"
 #include "object.h"
+#include "layout.h"
+#include "output.h"
 #include "target.h"
 #include "target-reloc.h"
 #include "target-select.h"
@@ -22,31 +25,92 @@ class Target_i386 : public Sized_target<32, false>
     : Sized_target<32, false>(&i386_info)
   { }
 
+  // Scan the relocations to look for symbol adjustments.
   void
-  relocate_section(const Symbol_table* symtab,
-                  Sized_object<32, false>*,
-                  unsigned int,
-                  const unsigned char*,
-                  size_t,
-                  unsigned int,
-                  const elfcpp::Elf_types<32>::Elf_Addr*,
-                  Symbol**,
-                  unsigned char*,
-                  elfcpp::Elf_types<32>::Elf_Addr,
-                  off_t);
+  scan_relocs(const General_options& options,
+             Symbol_table* symtab,
+             Sized_object<32, false>* object,
+             unsigned int sh_type,
+             const unsigned char* prelocs,
+             size_t reloc_count,
+             size_t local_symbol_count,
+             const unsigned char* plocal_symbols,
+             Symbol** global_symbols);
 
-  // The class which implements relocation.
-  struct Relocate
+  // Relocate a section.
+  void
+  relocate_section(const Relocate_info<32, false>*,
+                  unsigned int sh_type,
+                  const unsigned char* prelocs,
+                  size_t reloc_count,
+                  unsigned char* view,
+                  elfcpp::Elf_types<32>::Elf_Addr view_address,
+                  off_t view_size);
+
+ private:
+  // The class which scans relocations.
+  struct Scan
   {
     inline void
-    operator()(Sized_object<32, false>*, const elfcpp::Rel<32, false>&,
-              unsigned int r_type, Sized_symbol<32>*,
-              elfcpp::Elf_types<32>::Elf_Addr,
-              unsigned char*, elfcpp::Elf_types<32>::Elf_Addr);
+    local(const General_options& options, 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,
+          const elfcpp::Rel<32, false>& reloc, unsigned int r_type,
+          Symbol* gsym);
   };
 
- private:
+  // The class which implements relocation.
+  class Relocate
+  {
+   public:
+    // Do a relocation.
+    static inline void
+    relocate(const Relocate_info<32, false>*, size_t relnum,
+            const elfcpp::Rel<32, false>&,
+            unsigned int r_type, Sized_symbol<32>*,
+            elfcpp::Elf_types<32>::Elf_Addr,
+            unsigned char*, elfcpp::Elf_types<32>::Elf_Addr,
+            off_t);
+
+   private:
+    // Do a TLS relocation.
+    static inline void
+    relocate_tls(const Relocate_info<32, false>*, size_t relnum,
+                const elfcpp::Rel<32, false>&,
+                unsigned int r_type, Sized_symbol<32>*,
+                elfcpp::Elf_types<32>::Elf_Addr,
+                unsigned char*, elfcpp::Elf_types<32>::Elf_Addr, off_t);
+
+    // Do a TLS Initial-Exec to Local-Exec transition.
+    static inline void
+    tls_ie_to_le(const Relocate_info<32, false>*, size_t relnum,
+                Output_segment* tls_segment,
+                const elfcpp::Rel<32, false>&, unsigned int r_type,
+                elfcpp::Elf_types<32>::Elf_Addr value,
+                unsigned char* view,
+                off_t view_size);
+
+    // Check the range for a TLS relocation.
+    static inline void
+    check_range(const Relocate_info<32, false>*, size_t relnum,
+               const elfcpp::Rel<32, false>&, off_t, off_t);
+
+    // Check the validity of a TLS relocation.  This is like assert.
+    static inline void
+    check_tls(const Relocate_info<32, false>*, size_t relnum,
+             const elfcpp::Rel<32, false>&, bool);
+  };
+
+  // Adjust TLS relocation type based on the options and whether this
+  // is a local symbol.
+  static unsigned int
+  optimize_tls_reloc(const General_options*, bool is_local, int r_type);
+
+  // Information about this specific target which we pass to the
+  // general Target structure.
   static const Target::Target_info i386_info;
 };
 
@@ -62,75 +126,608 @@ const Target::Target_info Target_i386::i386_info =
   0x1000               // common_pagesize
 };
 
+// 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.
+
+unsigned int
+Target_i386::optimize_tls_reloc(const General_options* options, bool is_local,
+                               int r_type)
+{
+  // If we are generating a shared library, then we can't do anything
+  // in the linker.
+  if (options->is_shared())
+    return r_type;
+
+  switch (r_type)
+    {
+    case elfcpp::R_386_TLS_GD:
+    case elfcpp::R_386_TLS_GOTDESC:
+    case elfcpp::R_386_TLS_DESC_CALL:
+      // These are Global-Dynamic which permits fully general TLS
+      // access.  Since we know that we are generating an executable,
+      // we can convert this to Initial-Exec.  If we also know that
+      // this is a local symbol, we can further switch to Local-Exec.
+      if (is_local)
+       return elfcpp::R_386_TLS_LE_32;
+      return elfcpp::R_386_TLS_IE_32;
+
+    case elfcpp::R_386_TLS_LDM:
+      // This is Local-Dynamic, which refers to a local symbol in the
+      // dynamic TLS block.  Since we know that we generating an
+      // executable, we can switch to Local-Exec.
+      return elfcpp::R_386_TLS_LE_32;
+
+    case elfcpp::R_386_TLS_LDO_32:
+      // Another type of Local-Dynamic relocation.
+      return elfcpp::R_386_TLS_LE;
+
+    case elfcpp::R_386_TLS_IE:
+    case elfcpp::R_386_TLS_GOTIE:
+    case elfcpp::R_386_TLS_IE_32:
+      // These are Initial-Exec relocs which get the thread offset
+      // from the GOT.  If we know that we are linking against the
+      // local symbol, we can switch to Local-Exec, which links the
+      // thread offset into the instruction.
+      if (is_local)
+       return elfcpp::R_386_TLS_LE_32;
+      return r_type;
+       
+    case elfcpp::R_386_TLS_LE:
+    case elfcpp::R_386_TLS_LE_32:
+      // When we already have Local-Exec, there is nothing further we
+      // can do.
+      return r_type;
+
+    default:
+      abort();
+    }
+}
+
+// Scan a relocation for a local symbol.
+
+inline void
+Target_i386::Scan::local(const General_options& options,
+                        Sized_object<32, false>* object,
+                        const elfcpp::Rel<32, false>&, unsigned int r_type,
+                        const elfcpp::Sym<32, false>&)
+{
+  switch (r_type)
+    {
+    case elfcpp::R_386_NONE:
+    case elfcpp::R_386_GNU_VTINHERIT:
+    case elfcpp::R_386_GNU_VTENTRY:
+      break;
+
+    case elfcpp::R_386_32:
+    case elfcpp::R_386_16:
+    case elfcpp::R_386_8:
+      // FIXME: If we are generating a shared object we need to copy
+      // this relocation into the object.
+      break;
+
+    case elfcpp::R_386_PC32:
+    case elfcpp::R_386_PC16:
+    case elfcpp::R_386_PC8:
+      break;
+
+    case elfcpp::R_386_COPY:
+    case elfcpp::R_386_GLOB_DAT:
+    case elfcpp::R_386_JUMP_SLOT:
+    case elfcpp::R_386_RELATIVE:
+    case elfcpp::R_386_TLS_TPOFF:
+    case elfcpp::R_386_TLS_DTPMOD32:
+    case elfcpp::R_386_TLS_DTPOFF32:
+    case elfcpp::R_386_TLS_TPOFF32:
+    case elfcpp::R_386_TLS_DESC:
+      fprintf(stderr, _("%s: %s: unexpected reloc %u in object file\n"),
+             program_name, object->name().c_str(), r_type);
+      gold_exit(false);
+      break;
+
+    case elfcpp::R_386_TLS_IE:
+    case elfcpp::R_386_TLS_GOTIE:
+    case elfcpp::R_386_TLS_LE:
+    case elfcpp::R_386_TLS_GD:
+    case elfcpp::R_386_TLS_LDM:
+    case elfcpp::R_386_TLS_LDO_32:
+    case elfcpp::R_386_TLS_IE_32:
+    case elfcpp::R_386_TLS_LE_32:
+    case elfcpp::R_386_TLS_GOTDESC:
+    case elfcpp::R_386_TLS_DESC_CALL:
+      r_type = Target_i386::optimize_tls_reloc(&options, true, r_type);
+      switch (r_type)
+       {
+       case elfcpp::R_386_TLS_LE:
+       case elfcpp::R_386_TLS_LE_32:
+         // FIXME: If generating a shared object, we need to copy
+         // this relocation into the object.
+         break;
+
+       case elfcpp::R_386_TLS_IE:
+       case elfcpp::R_386_TLS_GOTIE:
+       case elfcpp::R_386_TLS_GD:
+       case elfcpp::R_386_TLS_LDM:
+       case elfcpp::R_386_TLS_LDO_32:
+       case elfcpp::R_386_TLS_IE_32:
+       case elfcpp::R_386_TLS_GOTDESC:
+       case elfcpp::R_386_TLS_DESC_CALL:
+         fprintf(stderr,
+                 _("%s: %s: unsupported reloc %u against local symbol\n"),
+                 program_name, object->name().c_str(), r_type);
+         break;
+       }
+      break;
+
+    case elfcpp::R_386_GOT32:
+    case elfcpp::R_386_PLT32:
+    case elfcpp::R_386_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:
+    case elfcpp::R_386_TLS_GD_CALL:
+    case elfcpp::R_386_TLS_GD_POP:
+    case elfcpp::R_386_TLS_LDM_32:
+    case elfcpp::R_386_TLS_LDM_PUSH:
+    case elfcpp::R_386_TLS_LDM_CALL:
+    case elfcpp::R_386_TLS_LDM_POP:
+    case elfcpp::R_386_USED_BY_INTEL_200:
+    default:
+      fprintf(stderr, _("%s: %s: unsupported reloc %u against local symbol\n"),
+             program_name, object->name().c_str(), r_type);
+      break;
+    }
+}
+
+// Scan a relocation for a global symbol.
+
+inline void
+Target_i386::Scan::global(const General_options& options,
+                         Sized_object<32, false>* object,
+                         const elfcpp::Rel<32, false>&, unsigned int r_type,
+                         Symbol* gsym)
+{
+  switch (r_type)
+    {
+    case elfcpp::R_386_NONE:
+    case elfcpp::R_386_GNU_VTINHERIT:
+    case elfcpp::R_386_GNU_VTENTRY: 
+      break;
+
+    case elfcpp::R_386_32:
+    case elfcpp::R_386_PC32:
+    case elfcpp::R_386_16:
+    case elfcpp::R_386_PC16:
+    case elfcpp::R_386_8:
+    case elfcpp::R_386_PC8:
+      // FIXME: If we are generating a shared object we may need to
+      // copy this relocation into the object.  If this symbol is
+      // defined in a shared object, we may need to copy this
+      // relocation in order to avoid a COPY relocation.
+      break;
+
+    case elfcpp::R_386_COPY:
+    case elfcpp::R_386_GLOB_DAT:
+    case elfcpp::R_386_JUMP_SLOT:
+    case elfcpp::R_386_RELATIVE:
+    case elfcpp::R_386_TLS_TPOFF:
+    case elfcpp::R_386_TLS_DTPMOD32:
+    case elfcpp::R_386_TLS_DTPOFF32:
+    case elfcpp::R_386_TLS_TPOFF32:
+    case elfcpp::R_386_TLS_DESC:
+      fprintf(stderr, _("%s: %s: unexpected reloc %u in object file\n"),
+             program_name, object->name().c_str(), r_type);
+      gold_exit(false);
+      break;
+
+    case elfcpp::R_386_TLS_IE:
+    case elfcpp::R_386_TLS_GOTIE:
+    case elfcpp::R_386_TLS_LE:
+    case elfcpp::R_386_TLS_GD:
+    case elfcpp::R_386_TLS_LDM:
+    case elfcpp::R_386_TLS_LDO_32:
+    case elfcpp::R_386_TLS_IE_32:
+    case elfcpp::R_386_TLS_LE_32:
+    case elfcpp::R_386_TLS_GOTDESC:
+    case elfcpp::R_386_TLS_DESC_CALL:
+      r_type = Target_i386::optimize_tls_reloc(&options,
+                                              !gsym->in_dynsym(),
+                                              r_type);
+      switch (r_type)
+       {
+       case elfcpp::R_386_TLS_LE:
+       case elfcpp::R_386_TLS_LE_32:
+         // FIXME: If generating a shared object, we need to copy
+         // this relocation into the object.
+         break;
+
+       case elfcpp::R_386_TLS_IE:
+       case elfcpp::R_386_TLS_GOTIE:
+       case elfcpp::R_386_TLS_GD:
+       case elfcpp::R_386_TLS_LDM:
+       case elfcpp::R_386_TLS_LDO_32:
+       case elfcpp::R_386_TLS_IE_32:
+       case elfcpp::R_386_TLS_GOTDESC:
+       case elfcpp::R_386_TLS_DESC_CALL:
+         fprintf(stderr,
+                 _("%s: %s: unsupported reloc %u against global symbol %s\n"),
+                 program_name, object->name().c_str(), r_type, gsym->name());
+         break;
+       }
+      break;
+
+    case elfcpp::R_386_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:
+    case elfcpp::R_386_TLS_GD_CALL:
+    case elfcpp::R_386_TLS_GD_POP:
+    case elfcpp::R_386_TLS_LDM_32:
+    case elfcpp::R_386_TLS_LDM_PUSH:
+    case elfcpp::R_386_TLS_LDM_CALL:
+    case elfcpp::R_386_TLS_LDM_POP:
+    case elfcpp::R_386_USED_BY_INTEL_200:
+    default:
+      fprintf(stderr,
+             _("%s: %s: unsupported reloc %u against global symbol %s\n"),
+             program_name, object->name().c_str(), r_type, gsym->name());
+      break;
+    }
+}
+
+// Scan relocations for a section.
+
+void
+Target_i386::scan_relocs(const General_options& options,
+                        Symbol_table* symtab,
+                        Sized_object<32, false>* object,
+                        unsigned int sh_type,
+                        const unsigned char* prelocs,
+                        size_t reloc_count,
+                        size_t local_symbol_count,
+                        const unsigned char* plocal_symbols,
+                        Symbol** global_symbols)
+{
+  if (sh_type == elfcpp::SHT_RELA)
+    {
+      fprintf(stderr, _("%s: %s: unsupported RELA reloc section\n"),
+             program_name, object->name().c_str());
+      gold_exit(false);
+    }
+
+  gold::scan_relocs<32, false, elfcpp::SHT_REL, Target_i386::Scan>(
+    options,
+    symtab,
+    object,
+    prelocs,
+    reloc_count,
+    local_symbol_count,
+    plocal_symbols,
+    global_symbols);
+}
+
 // Perform a relocation.
 
 inline void
-Target_i386::Relocate::operator()(Sized_object<32, false>* object,
-                                 const elfcpp::Rel<32, false>&,
-                                 unsigned int r_type,
-                                 Sized_symbol<32>*,
-                                 elfcpp::Elf_types<32>::Elf_Addr value,
-                                 unsigned char* view,
-                                 elfcpp::Elf_types<32>::Elf_Addr address)
+Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
+                               size_t relnum,
+                               const elfcpp::Rel<32, false>& rel,
+                               unsigned int r_type,
+                               Sized_symbol<32>* gsym,
+                               elfcpp::Elf_types<32>::Elf_Addr value,
+                               unsigned char* view,
+                               elfcpp::Elf_types<32>::Elf_Addr address,
+                               off_t view_size)
 {
   switch (r_type)
     {
     case elfcpp::R_386_NONE:
+    case elfcpp::R_386_GNU_VTINHERIT:
+    case elfcpp::R_386_GNU_VTENTRY:
       break;
 
     case elfcpp::R_386_32:
-      {
-       elfcpp::Elf_Word* wv = reinterpret_cast<elfcpp::Elf_Word*>(view);
-       unsigned int x = elfcpp::read_elf_word<false>(wv);
-       elfcpp::write_elf_word<false>(wv, x + value);
-      }
+      Relocate_functions<32, false>::rel32(view, value);
       break;
 
     case elfcpp::R_386_PC32:
-      {
-       elfcpp::Elf_Word* wv = reinterpret_cast<elfcpp::Elf_Word*>(view);
-       unsigned int x = elfcpp::read_elf_word<false>(wv);
-       elfcpp::write_elf_word<false>(wv, x + value - address);
-      }
+      Relocate_functions<32, false>::pcrel32(view, value, address);
+      break;
+
+    case elfcpp::R_386_16:
+      Relocate_functions<32, false>::rel16(view, value);
+      break;
+
+    case elfcpp::R_386_PC16:
+      Relocate_functions<32, false>::pcrel16(view, value, address);
       break;
 
+    case elfcpp::R_386_8:
+      Relocate_functions<32, false>::rel8(view, value);
+      break;
+
+    case elfcpp::R_386_PC8:
+      Relocate_functions<32, false>::pcrel8(view, value, address);
+      break;
+
+    case elfcpp::R_386_COPY:
+    case elfcpp::R_386_GLOB_DAT:
+    case elfcpp::R_386_JUMP_SLOT:
+    case elfcpp::R_386_RELATIVE:
+    case elfcpp::R_386_TLS_TPOFF:
+    case elfcpp::R_386_TLS_DTPMOD32:
+    case elfcpp::R_386_TLS_DTPOFF32:
+    case elfcpp::R_386_TLS_TPOFF32:
+    case elfcpp::R_386_TLS_DESC:
+      fprintf(stderr, _("%s: %s: unexpected reloc %u in object file\n"),
+             program_name,
+             relinfo->location(relnum, rel.get_r_offset()).c_str(),
+             r_type);
+      gold_exit(false);
+      break;
+
+    case elfcpp::R_386_TLS_IE:
+    case elfcpp::R_386_TLS_GOTIE:
+    case elfcpp::R_386_TLS_LE:
+    case elfcpp::R_386_TLS_GD:
+    case elfcpp::R_386_TLS_LDM:
+    case elfcpp::R_386_TLS_LDO_32:
+    case elfcpp::R_386_TLS_IE_32:
+    case elfcpp::R_386_TLS_LE_32:
+    case elfcpp::R_386_TLS_GOTDESC:
+    case elfcpp::R_386_TLS_DESC_CALL:
+      Target_i386::Relocate::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:
+    case elfcpp::R_386_TLS_GD_CALL:
+    case elfcpp::R_386_TLS_GD_POP:
+    case elfcpp::R_386_TLS_LDM_32:
+    case elfcpp::R_386_TLS_LDM_PUSH:
+    case elfcpp::R_386_TLS_LDM_CALL:
+    case elfcpp::R_386_TLS_LDM_POP:
+    case elfcpp::R_386_USED_BY_INTEL_200:
     default:
       fprintf(stderr, _("%s: %s: unsupported reloc %u\n"),
-             program_name, object->name().c_str(), r_type);
+             program_name,
+             relinfo->location(relnum, rel.get_r_offset()).c_str(),
+             r_type);
       // gold_exit(false);
+      break;
+    }
+}
+
+// Perform a TLS relocation.
+
+inline void
+Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
+                                   size_t relnum,
+                                   const elfcpp::Rel<32, false>& rel,
+                                   unsigned int r_type,
+                                   Sized_symbol<32>* gsym,
+                                   elfcpp::Elf_types<32>::Elf_Addr value,
+                                   unsigned char* view,
+                                   elfcpp::Elf_types<32>::Elf_Addr,
+                                   off_t view_size)
+{
+  Output_segment* tls_segment = relinfo->layout->tls_segment();
+  if (tls_segment == NULL)
+    {
+      fprintf(stderr, _("%s: %s: TLS reloc but no TLS segment\n"),
+             program_name,
+             relinfo->location(relnum, rel.get_r_offset()).c_str());
+      gold_exit(false);
+    }
+
+  const bool is_local = gsym == NULL || !gsym->in_dynsym();
+  const unsigned int opt_r_type =
+    Target_i386::optimize_tls_reloc(relinfo->options, is_local, r_type);
+  switch (r_type)
+    {
+    case elfcpp::R_386_TLS_LE_32:
+      value = tls_segment->vaddr() + tls_segment->memsz() - value;
+      Relocate_functions<32, false>::rel32(view, value);
+      break;
+
+    case elfcpp::R_386_TLS_LE:
+      value = value - (tls_segment->vaddr() + tls_segment->memsz());
+      Relocate_functions<32, false>::rel32(view, value);
+      break;
+
+    case elfcpp::R_386_TLS_IE:
+    case elfcpp::R_386_TLS_GOTIE:
+    case elfcpp::R_386_TLS_IE_32:
+      if (opt_r_type == elfcpp::R_386_TLS_LE_32)
+       {
+         Target_i386::Relocate::tls_ie_to_le(relinfo, relnum, tls_segment,
+                                             rel, r_type, value, view,
+                                             view_size);
+         break;
+       }
+      fprintf(stderr, _("%s: %s: unsupported reloc type %u\n"),
+             program_name,
+             relinfo->location(relnum, rel.get_r_offset()).c_str(),
+             r_type);
+      // gold_exit(false);
+      break;
+
+    case elfcpp::R_386_TLS_GD:
+    case elfcpp::R_386_TLS_LDM:
+    case elfcpp::R_386_TLS_LDO_32:
+    case elfcpp::R_386_TLS_GOTDESC:
+    case elfcpp::R_386_TLS_DESC_CALL:
+      fprintf(stderr, _("%s: %s: unsupported reloc %u\n"),
+             program_name,
+             relinfo->location(relnum, rel.get_r_offset()).c_str(),
+             r_type);
+      // gold_exit(false);
+      break;
+    }
+}
+
+// Do a relocation in which we convert a TLS Initial-Exec to a
+// Local-Exec.
+
+inline void
+Target_i386::Relocate::tls_ie_to_le(const Relocate_info<32, false>* relinfo,
+                                   size_t relnum,
+                                   Output_segment* tls_segment,
+                                   const elfcpp::Rel<32, false>& rel,
+                                   unsigned int r_type,
+                                   elfcpp::Elf_types<32>::Elf_Addr value,
+                                   unsigned char* view,
+                                   off_t view_size)
+{
+  // We have to actually change the instructions, which means that we
+  // need to examine the opcodes to figure out which instruction we
+  // are looking at.
+  if (r_type == elfcpp::R_386_TLS_IE)
+    {
+      // movl %gs:XX,%eax  ==>  movl $YY,%eax
+      // movl %gs:XX,%reg  ==>  movl $YY,%reg
+      // addl %gs:XX,%reg  ==>  addl $YY,%reg
+      Target_i386::Relocate::check_range(relinfo, relnum, rel, view_size, -1);
+      Target_i386::Relocate::check_range(relinfo, relnum, rel, view_size, 4);
+
+      unsigned char op1 = view[-1];
+      if (op1 == 0xa1)
+       {
+         // movl XX,%eax  ==>  movl $YY,%eax
+         view[-1] = 0xb8;
+       }
+      else
+       {
+         Target_i386::Relocate::check_range(relinfo, relnum, rel,
+                                            view_size, -2);
+
+         unsigned char op2 = view[-2];
+         if (op2 == 0x8b)
+           {
+             // movl XX,%reg  ==>  movl $YY,%reg
+             Target_i386::Relocate::check_tls(relinfo, relnum, rel,
+                                              (op1 & 0xc7) == 0x05);
+             view[-2] = 0xc7;
+             view[-1] = 0xc0 | ((op1 >> 3) & 7);
+           }
+         else if (op2 == 0x03)
+           {
+             // addl XX,%reg  ==>  addl $YY,%reg
+             Target_i386::Relocate::check_tls(relinfo, relnum, rel,
+                                              (op1 & 0xc7) == 0x05);
+             view[-2] = 0x81;
+             view[-1] = 0xc0 | ((op1 >> 3) & 7);
+           }
+         else
+           Target_i386::Relocate::check_tls(relinfo, relnum, rel, 0);
+       }
+    }
+  else
+    {
+      // subl %gs:XX(%reg1),%reg2  ==>  subl $YY,%reg2
+      // movl %gs:XX(%reg1),%reg2  ==>  movl $YY,%reg2
+      // addl %gs:XX(%reg1),%reg2  ==>  addl $YY,$reg2
+      Target_i386::Relocate::check_range(relinfo, relnum, rel, view_size, -2);
+      Target_i386::Relocate::check_range(relinfo, relnum, rel, view_size, 4);
+
+      unsigned char op1 = view[-1];
+      unsigned char op2 = view[-2];
+      Target_i386::Relocate::check_tls(relinfo, relnum, rel,
+                                      (op1 & 0xc0) == 0x80 && (op1 & 7) != 4);
+      if (op2 == 0x8b)
+       {
+         // movl %gs:XX(%reg1),%reg2  ==>  movl $YY,%reg2
+         view[-2] = 0xc7;
+         view[-1] = 0xc0 | ((op1 >> 3) & 7);
+       }
+      else if (op2 == 0x2b)
+       {
+         // subl %gs:XX(%reg1),%reg2  ==>  subl $YY,%reg2
+         view[-2] = 0x81;
+         view[-1] = 0xe8 | ((op1 >> 3) & 7);
+       }
+      else if (op2 == 0x03)
+       {
+         // addl %gs:XX(%reg1),%reg2  ==>  addl $YY,$reg2
+         view[-2] = 0x81;
+         view[-1] = 0xc0 | ((op1 >> 3) & 7);
+       }
+      else
+       Target_i386::Relocate::check_tls(relinfo, relnum, rel, 0);
+    }
+
+  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());
+
+  Relocate_functions<32, false>::rel32(view, value);
+}
+
+// Check the range for a TLS relocation.
+
+inline void
+Target_i386::Relocate::check_range(const Relocate_info<32, false>* relinfo,
+                                  size_t relnum,
+                                  const elfcpp::Rel<32, false>& rel,
+                                  off_t view_size, off_t off)
+{
+  off_t offset = rel.get_r_offset() + off;
+  if (offset < 0 || offset > view_size)
+    {
+      fprintf(stderr, _("%s: %s: TLS relocation out of range\n"),
+             program_name,
+             relinfo->location(relnum, rel.get_r_offset()).c_str());
+      gold_exit(false);
+    }
+}
+
+// Check the validity of a TLS relocation.  This is like assert.
+
+inline void
+Target_i386::Relocate::check_tls(const Relocate_info<32, false>* relinfo,
+                                size_t relnum,
+                                const elfcpp::Rel<32, false>& rel,
+                                bool valid)
+{
+  if (!valid)
+    {
+      fprintf(stderr,
+             _("%s: %s: TLS relocation against invalid instruction\n"),
+             program_name,
+             relinfo->location(relnum, rel.get_r_offset()).c_str());
+      gold_exit(false);
     }
 }
 
 // Relocate section data.
 
 void
-Target_i386::relocate_section(const Symbol_table* symtab,
-                             Sized_object<32, false>* object,
+Target_i386::relocate_section(const Relocate_info<32, false>* relinfo,
                              unsigned int sh_type,
                              const unsigned char* prelocs,
                              size_t reloc_count,
-                             unsigned int local_count,
-                             const elfcpp::Elf_types<32>::Elf_Addr* values,
-                             Symbol** global_syms,
                              unsigned char* view,
                              elfcpp::Elf_types<32>::Elf_Addr address,
                              off_t view_size)
 {
-  if (sh_type == elfcpp::SHT_RELA)
-    {
-      fprintf(stderr, _("%s: %s: unsupported RELA reloc section\n"),
-             program_name, object->name().c_str());
-      gold_exit(false);
-    }
+  assert(sh_type == elfcpp::SHT_REL);
 
   gold::relocate_section<32, false, elfcpp::SHT_REL, Target_i386::Relocate>(
-    symtab,
-    object,
+    relinfo,
     prelocs,
     reloc_count,
-    local_count,
-    values,
-    global_syms,
     view,
     address,
     view_size);
index 61b6895..a81fd43 100644 (file)
 namespace gold
 {
 
-// Layout_task methods.
-
-Layout_task::~Layout_task()
-{
-}
-
-// This task can be run when it is unblocked.
-
-Task::Is_runnable_type
-Layout_task::is_runnable(Workqueue*)
-{
-  if (this->this_blocker_->is_blocked())
-    return IS_BLOCKED;
-  return IS_RUNNABLE;
-}
-
-// We don't need to hold any locks for the duration of this task.  In
-// fact this task will be the only one running.
-
-Task_locker*
-Layout_task::locks(Workqueue*)
-{
-  return NULL;
-}
+// Layout_task_runner methods.
 
 // Lay out the sections.  This is called after all the input objects
 // have been read.
 
 void
-Layout_task::run(Workqueue* workqueue)
+Layout_task_runner::run(Workqueue* workqueue)
 {
   off_t file_size = this->layout_->finalize(this->input_objects_,
                                            this->symtab_);
@@ -63,7 +40,7 @@ Layout_task::run(Workqueue* workqueue)
 Layout::Layout(const General_options& options)
   : options_(options), last_shndx_(0), namepool_(), sympool_(), signatures_(),
     section_name_map_(), segment_list_(), section_list_(),
-    special_output_list_()
+    special_output_list_(), tls_segment_(NULL)
 {
   // Make space for more than enough segments for a typical file.
   // This is just for efficiency--it's OK if we wind up needing more.
@@ -256,30 +233,16 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
        }
 
       // If we see a loadable SHF_TLS section, we create a PT_TLS
-      // segment.
+      // segment.  There can only be one such segment.
       if ((flags & elfcpp::SHF_TLS) != 0)
        {
-         // See if we already have an equivalent PT_TLS segment.
-         for (p = this->segment_list_.begin();
-              p != segment_list_.end();
-              ++p)
+         if (this->tls_segment_ == NULL)
            {
-             if ((*p)->type() == elfcpp::PT_TLS
-                 && (((*p)->flags() & elfcpp::PF_W)
-                     == (seg_flags & elfcpp::PF_W)))
-               {
-                 (*p)->add_output_section(os, seg_flags);
-                 break;
-               }
-           }
-
-         if (p == this->segment_list_.end())
-           {
-             Output_segment* oseg = new Output_segment(elfcpp::PT_TLS,
-                                                       seg_flags);
-             this->segment_list_.push_back(oseg);
-             oseg->add_output_section(os, seg_flags);
+             this->tls_segment_ = new Output_segment(elfcpp::PT_TLS,
+                                                     seg_flags);
+             this->segment_list_.push_back(this->tls_segment_);
            }
+         this->tls_segment_->add_output_section(os, seg_flags);
        }
     }
 
@@ -440,6 +403,14 @@ Layout::segment_precedes(const Output_segment* seg1,
   if (type2 == elfcpp::PT_LOAD && type1 != elfcpp::PT_LOAD)
     return false;
 
+  // We put the PT_TLS segment last, because that is where the dynamic
+  // linker expects to find it (this is just for efficiency; other
+  // positions would also work correctly).
+  if (type1 == elfcpp::PT_TLS && type2 != elfcpp::PT_TLS)
+    return false;
+  if (type2 == elfcpp::PT_TLS && type1 != elfcpp::PT_TLS)
+    return true;
+
   const elfcpp::Elf_Word flags1 = seg1->flags();
   const elfcpp::Elf_Word flags2 = seg2->flags();
 
@@ -865,30 +836,12 @@ Write_symbols_task::run(Workqueue*)
   this->symtab_->write_globals(this->target_, this->sympool_, this->of_);
 }
 
-// Close_task methods.
-
-// We can't run until FINAL_BLOCKER is unblocked.
-
-Task::Is_runnable_type
-Close_task::is_runnable(Workqueue*)
-{
-  if (this->final_blocker_->is_blocked())
-    return IS_BLOCKED;
-  return IS_RUNNABLE;
-}
-
-// We don't lock anything.
-
-Task_locker*
-Close_task::locks(Workqueue*)
-{
-  return NULL;
-}
+// Close_task_runner methods.
 
 // Run the task--close the file.
 
 void
-Close_task::run(Workqueue*)
+Close_task_runner::run(Workqueue*)
 {
   this->of_->close();
 }
index 028d714..4ec2a4a 100644 (file)
@@ -25,46 +25,35 @@ class Output_segment;
 class Output_data;
 class Target;
 
-// This Task handles mapping the input sections to output sections and
-// laying them out in memory.
+// This task function handles mapping the input sections to output
+// sections and laying them out in memory.
 
-class Layout_task : public Task
+class Layout_task_runner : public Task_function_runner
 {
  public:
   // OPTIONS is the command line options, INPUT_OBJECTS is the list of
-  // input objects, THIS_BLOCKER is a token which blocks this task
-  // from executing until all the input symbols have been read.
-  Layout_task(const General_options& options,
-             const Input_objects* input_objects,
-             Symbol_table* symtab,
-             Layout* layout,
-             Task_token* this_blocker)
+  // input objects, SYMTAB is the symbol table, LAYOUT is the layout
+  // object.
+  Layout_task_runner(const General_options& options,
+                    const Input_objects* input_objects,
+                    Symbol_table* symtab,
+                    Layout* layout)
     : options_(options), input_objects_(input_objects), symtab_(symtab),
-      layout_(layout), this_blocker_(this_blocker)
+      layout_(layout)
   { }
 
-  ~Layout_task();
-
-  // The standard Task methods.
-
-  Is_runnable_type
-  is_runnable(Workqueue*);
-
-  Task_locker*
-  locks(Workqueue*);
-
+  // Run the operation.
   void
   run(Workqueue*);
 
  private:
-  Layout_task(const Layout_task&);
-  Layout_task& operator=(const Layout_task&);
+  Layout_task_runner(const Layout_task_runner&);
+  Layout_task_runner& operator=(const Layout_task_runner&);
 
   const General_options& options_;
   const Input_objects* input_objects_;
   Symbol_table* symtab_;
   Layout* layout_;
-  Task_token* this_blocker_;
 };
 
 // This class handles the details of laying out input sections.
@@ -105,6 +94,11 @@ class Layout
   off_t
   finalize(const Input_objects*, Symbol_table*);
 
+  // Return the TLS segment.
+  Output_segment*
+  tls_segment() const
+  { return this->tls_segment_; }
+
   // Write out data not associated with an input file or the symbol
   // table.
   void
@@ -234,6 +228,8 @@ class Layout
   // The list of sections which require special output because they
   // are not comprised of input sections.
   Data_list special_output_list_;
+  // A pointer to the PT_TLS segment if there is one.
+  Output_segment* tls_segment_;
 };
 
 // This task handles writing out data which is not part of a section
@@ -295,29 +291,21 @@ class Write_symbols_task : public Task
   Task_token* final_blocker_;
 };
 
-// This task handles closing the file.
+// This task function handles closing the file.
 
-class Close_task : public Task
+class Close_task_runner : public Task_function_runner
 {
  public:
-  Close_task(Output_file* of, Task_token* final_blocker)
-    : of_(of), final_blocker_(final_blocker)
+  Close_task_runner(Output_file* of)
+    : of_(of)
   { }
 
-  // The standard task methods.
-
-  Is_runnable_type
-  is_runnable(Workqueue*);
-
-  Task_locker*
-  locks(Workqueue*);
-
+  // Run the operation.
   void
   run(Workqueue*);
 
  private:
   Output_file* of_;
-  Task_token* final_blocker_;
 };
 
 } // End namespace gold.
index 8f1241a..5efb3cb 100644 (file)
@@ -87,6 +87,33 @@ Sized_object<size, big_endian>::section_header(unsigned int shnum)
   return this->get_view(symtabshdroff, This::shdr_size);
 }
 
+// Return the name of section SHNUM.
+
+template<int size, bool big_endian>
+std::string
+Sized_object<size, big_endian>::do_section_name(unsigned int shnum)
+{
+  Task_lock_obj<Object> tl(*this);
+
+  // Read the section names.
+  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 shdr(this->section_header(shnum));
+  if (shdr.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(), shnum,
+             static_cast<unsigned long>(shdr.get_sh_name()));
+      gold_exit(false);
+    }
+
+  return std::string(pnames + shdr.get_sh_name());
+}
+
 // Set up an object file bsaed on the file header.  This sets up the
 // target and reads the section information.
 
@@ -182,7 +209,9 @@ Sized_object<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
 
   // We only need the external symbols.
   const int sym_size = This::sym_size;
-  off_t locsize = symtabshdr.get_sh_info() * sym_size;
+  const unsigned int loccount = symtabshdr.get_sh_info();
+  this->local_symbol_count_ = loccount;
+  off_t locsize = loccount * sym_size;
   off_t extoff = symtabshdr.get_sh_offset() + locsize;
   off_t extsize = symtabshdr.get_sh_size() - locsize;
 
@@ -190,14 +219,15 @@ Sized_object<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
   File_view* fvsymtab = this->get_lasting_view(extoff, extsize);
 
   // Read the section header for the symbol names.
+  unsigned int shnum = this->shnum();
   unsigned int strtab_shnum = symtabshdr.get_sh_link();
-  if (strtab_shnum == 0 || strtab_shnum >= this->shnum())
+  if (strtab_shnum == 0 || strtab_shnum >= shnum)
     {
       fprintf(stderr, _("%s: %s: invalid symbol table name index: %u\n"),
              program_name, this->name().c_str(), strtab_shnum);
       gold_exit(false);
     }
-  typename This::Shdr strtabshdr(this->section_header(strtab_shnum));
+  typename This::Shdr strtabshdr(pshdrs + strtab_shnum * This::shdr_size);
   if (strtabshdr.get_sh_type() != elfcpp::SHT_STRTAB)
     {
       fprintf(stderr,
@@ -493,14 +523,13 @@ Sized_object<size, big_endian>::do_finalize_local_symbols(off_t off,
   assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
 
   // Read the local symbols.
-  unsigned int loccount = symtabshdr.get_sh_info();
   const int sym_size = This::sym_size;
+  const unsigned int loccount = this->local_symbol_count_;
+  assert(loccount == symtabshdr.get_sh_info());
   off_t locsize = loccount * sym_size;
   const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(),
                                              locsize);
 
-  this->local_symbol_count_ = loccount;
-
   this->values_ = new typename elfcpp::Elf_types<size>::Elf_Addr[loccount];
 
   // Read the section header for the symbol names.
@@ -587,12 +616,12 @@ Sized_object<size, big_endian>::write_local_symbols(Output_file* of,
   // Read the symbol table section header.
   typename This::Shdr symtabshdr(this->section_header(this->symtab_shnum_));
   assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
-  unsigned int local_symbol_count = this->local_symbol_count_;
-  assert(local_symbol_count == symtabshdr.get_sh_info());
+  const unsigned int loccount = this->local_symbol_count_;
+  assert(loccount == symtabshdr.get_sh_info());
 
   // Read the local symbols.
   const int sym_size = This::sym_size;
-  off_t locsize = local_symbol_count * sym_size;
+  off_t locsize = loccount * sym_size;
   const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(),
                                              locsize);
 
@@ -615,7 +644,7 @@ Sized_object<size, big_endian>::write_local_symbols(Output_file* of,
 
   psyms += sym_size;
   unsigned char* ov = oview;
-  for (unsigned int i = 1; i < local_symbol_count; ++i, psyms += sym_size)
+  for (unsigned int i = 1; i < loccount; ++i, psyms += sym_size)
     {
       elfcpp::Sym<size, big_endian> isym(psyms);
       elfcpp::Sym_write<size, big_endian> osym(ov);
@@ -665,6 +694,31 @@ Input_objects::add_object(Object* obj)
     this->any_dynamic_ = true;
 }
 
+// Relocate_info methods.
+
+// Return a string describing the location of a relocation.  This is
+// only used in error messages.
+
+template<int size, bool big_endian>
+std::string
+Relocate_info<size, big_endian>::location(size_t relnum, off_t) const
+{
+  std::string ret(this->object->name());
+  ret += ": reloc ";
+  char buf[100];
+  snprintf(buf, sizeof buf, "%zu", relnum);
+  ret += buf;
+  ret += " in reloc section ";
+  snprintf(buf, sizeof buf, "%u", this->reloc_shndx);
+  ret += buf;
+  ret += " (" + this->object->section_name(this->reloc_shndx);
+  ret += ") for section ";
+  snprintf(buf, sizeof buf, "%u", this->data_shndx);
+  ret += buf;
+  ret += " (" + this->object->section_name(this->data_shndx) + ")";
+  return ret;
+}
+
 } // End namespace gold.
 
 namespace
@@ -830,4 +884,16 @@ class Sized_object<64, false>;
 template
 class Sized_object<64, true>;
 
+template
+struct Relocate_info<32, false>;
+
+template
+struct Relocate_info<32, true>;
+
+template
+struct Relocate_info<64, false>;
+
+template
+struct Relocate_info<64, true>;
+
 } // End namespace gold.
index ca227c5..49a1ce9 100644 (file)
@@ -4,6 +4,8 @@
 #define GOLD_OBJECT_H
 
 #include <cassert>
+#include <list>
+#include <string>
 #include <vector>
 
 #include "elfcpp.h"
@@ -14,6 +16,7 @@
 namespace gold
 {
 
+class General_options;
 class Stringpool;
 class Layout;
 class Output_section;
@@ -39,6 +42,35 @@ struct Read_symbols_data
   off_t symbol_names_size;
 };
 
+// Data about a single relocation section.  This is read in
+// read_relocs and processed in scan_relocs.
+
+struct Section_relocs
+{
+  // Index of reloc section.
+  unsigned int reloc_shndx;
+  // Index of section that relocs apply to.
+  unsigned int data_shndx;
+  // Contents of reloc section.
+  File_view* contents;
+  // Reloc section type.
+  unsigned int sh_type;
+  // Number of reloc entries.
+  size_t reloc_count;
+};
+
+// Relocations in an object file.  This is read in read_relocs and
+// processed in scan_relocs.
+
+struct Read_relocs_data
+{
+  typedef std::vector<Section_relocs> Relocs_list;
+  // The relocations.
+  Relocs_list relocs;
+  // The local symbols.
+  File_view* local_symbols;
+};
+
 // Object is an interface which represents either a 32-bit or a 64-bit
 // input object.  This can be a regular object file (ET_REL) or a
 // shared object (ET_DYN).  The actual instantiations are
@@ -98,21 +130,32 @@ class Object
   Sized_target<size, big_endian>*
   sized_target(ACCEPT_SIZE_ENDIAN_ONLY);
 
-  // Read the symbol and relocation information.
+  // Read the symbol information.
   void
   read_symbols(Read_symbols_data* sd)
   { return this->do_read_symbols(sd); }
 
+  // Pass sections which should be included in the link to the Layout
+  // object, and record where the sections go in the output file.
+  void
+  layout(Layout* lay, Read_symbols_data* sd)
+  { this->do_layout(lay, sd); }
+
   // Add symbol information to the global symbol table.
   void
   add_symbols(Symbol_table* symtab, Read_symbols_data* sd)
   { this->do_add_symbols(symtab, sd); }
 
-  // Pass sections which should be included in the link to the Layout
-  // object, and record where the sections go in the output file.
+  // Read the relocs.
   void
-  layout(Layout* lay, Read_symbols_data* sd)
-  { this->do_layout(lay, sd); }
+  read_relocs(Read_relocs_data* rd)
+  { return this->do_read_relocs(rd); }
+
+  // Scan the relocs and adjust the symbol table.
+  void
+  scan_relocs(const General_options& options, Symbol_table* symtab,
+             Read_relocs_data* rd)
+  { return this->do_scan_relocs(options, symtab, rd); }
 
   // Initial local symbol processing: set the offset where local
   // symbol information will be stored; add local symbol names to
@@ -124,8 +167,8 @@ class Object
   // Relocate the input sections and write out the local symbols.
   void
   relocate(const General_options& options, const Symbol_table* symtab,
-          const Stringpool* sympool, Output_file* of)
-  { return this->do_relocate(options, symtab, sympool, of); }
+          const Layout* layout, Output_file* of)
+  { return this->do_relocate(options, symtab, layout, of); }
 
   // Return whether an input section is being included in the link.
   bool
@@ -141,6 +184,12 @@ class Object
   inline Output_section*
   output_section(unsigned int shnum, off_t* poff);
 
+  // Return the name of a section given a section index.  This is only
+  // used for error messages.
+  std::string
+  section_name(unsigned int shnum)
+  { return this->do_section_name(shnum); }
+
  protected:
   // What we need to know to map an input section to an output
   // section.  We keep an array of these, one for each input section,
@@ -163,6 +212,14 @@ class Object
   virtual void
   do_add_symbols(Symbol_table*, Read_symbols_data*) = 0;
 
+  // Read the relocs--implemented by child class.
+  virtual void
+  do_read_relocs(Read_relocs_data*) = 0;
+
+  // Scan the relocs--implemented by child class.
+  virtual void
+  do_scan_relocs(const General_options&, Symbol_table*, Read_relocs_data*) = 0;
+
   // Lay out sections--implemented by child class.
   virtual void
   do_layout(Layout*, Read_symbols_data*) = 0;
@@ -175,7 +232,11 @@ class Object
   // symbols--implemented by child class.
   virtual void
   do_relocate(const General_options& options, const Symbol_table* symtab,
-             const Stringpool*, Output_file* of) = 0;
+             const Layout*, Output_file* of) = 0;
+
+  // Get the name of a section--implemented by child class.
+  virtual std::string
+  do_section_name(unsigned int shnum) = 0;
 
   // Get the file.
   Input_file*
@@ -282,14 +343,22 @@ class Sized_object : public Object
   void
   do_read_symbols(Read_symbols_data*);
 
-  // Lay out the input sections.
-  void
-  do_layout(Layout*, Read_symbols_data*);
-
   // Add the symbols to the symbol table.
   void
   do_add_symbols(Symbol_table*, Read_symbols_data*);
 
+  // Read the relocs.
+  void
+  do_read_relocs(Read_relocs_data*);
+
+  // Scan the relocs and adjust the symbol table.
+  void
+  do_scan_relocs(const General_options&, Symbol_table*, Read_relocs_data*);
+
+  // Lay out the input sections.
+  void
+  do_layout(Layout*, Read_symbols_data*);
+
   // Finalize the local symbols.
   off_t
   do_finalize_local_symbols(off_t, Stringpool*);
@@ -297,7 +366,11 @@ class Sized_object : public Object
   // Relocate the input sections and write out the local symbols.
   void
   do_relocate(const General_options& options, const Symbol_table* symtab,
-             const Stringpool*, Output_file* of);
+             const Layout*, Output_file* of);
+
+  // Get the name of a section.
+  std::string
+  do_section_name(unsigned int shnum);
 
   // Return the appropriate Sized_target structure.
   Sized_target<size, big_endian>*
@@ -352,7 +425,8 @@ class Sized_object : public Object
 
   // Relocate the sections in the output file.
   void
-  relocate_sections(const Symbol_table*, const unsigned char* pshdrs, Views*);
+  relocate_sections(const General_options& options, const Symbol_table*,
+                   const Layout*, const unsigned char* pshdrs, Views*);
 
   // Write out the local symbols.
   void
@@ -424,6 +498,37 @@ class Input_objects
   bool any_dynamic_;
 };
 
+// Some of the information we pass to the relocation routines.  We
+// group this together to avoid passing a dozen different arguments.
+
+template<int size, bool big_endian>
+struct Relocate_info
+{
+  // Command line options.
+  const General_options* options;
+  // Symbol table.
+  const Symbol_table* symtab;
+  // Layout.
+  const Layout* layout;
+  // Object being relocated.
+  Sized_object<size, big_endian>* object;
+  // Number of local symbols.
+  unsigned int local_symbol_count;
+  // Values of local symbols.
+  typename elfcpp::Elf_types<size>::Elf_Addr *values;
+  // Global symbols.
+  Symbol** symbols;
+  // Section index of relocation section.
+  unsigned int reloc_shndx;
+  // Section index of section being relocated.
+  unsigned int data_shndx;
+
+  // Return a string showing the location of a relocation.  This is
+  // only used for error messages.
+  std::string
+  location(size_t relnum, off_t reloffset) const;
+};
+
 // Return an Object appropriate for the input file.  P is BYTES long,
 // and holds the ELF header.
 
index e5a16f1..8e0465f 100644 (file)
@@ -217,6 +217,8 @@ options::Command_line_options::options[] =
              &General_options::set_output_file_name),
   GENERAL_NOARG('r', NULL, N_("Generate relocatable output"), NULL,
                ONE_DASH, &General_options::set_relocatable),
+  GENERAL_NOARG('\0', "shared", N_("Generate shared library"),
+               NULL, ONE_DASH, &General_options::set_shared),
   GENERAL_NOARG('\0', "static", N_("Do not link against shared libraries"),
                NULL, ONE_DASH, &General_options::set_static),
   SPECIAL('\0', "help", N_("Report usage information"), NULL,
@@ -232,6 +234,7 @@ General_options::General_options()
   : search_path_(),
     output_file_name_("a.out"),
     is_relocatable_(false),
+    is_shared_(false),
     is_static_(false)
 {
 }
index ba32ef5..7e890fa 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <list>
 #include <string>
+#include <vector>
 
 namespace gold
 {
@@ -52,6 +53,11 @@ class General_options
   is_relocatable() const
   { return this->is_relocatable_; }
 
+  // --shared: Whether generating a shared object.
+  bool
+  is_shared() const
+  { return this->is_shared_; }
+
   // --static: Whether doing a static link.
   bool
   is_static() const
@@ -74,12 +80,17 @@ class General_options
   { this->is_relocatable_ = true; }
 
   void
+  set_shared()
+  { this->is_shared_ = true; }
+
+  void
   set_static()
   { this->is_static_ = true; }
 
   Dir_list search_path_;
   const char* output_file_name_;
   bool is_relocatable_;
+  bool is_shared_;
   bool is_static_;
 
   // Don't copy this structure.
@@ -143,6 +154,11 @@ class Input_argument
   Position_dependent_options options_;
 };
 
+// A list of input files.
+class Input_argument_list : public std::vector<Input_argument>
+{
+};
+
 // All the information read from the command line.
 
 class Command_line
@@ -164,8 +180,6 @@ class Command_line
   options() const
   { return this->options_; }
 
-  typedef std::list<Input_argument> Input_argument_list;
-
   // Get the list of input files.
   const Input_argument_list&
   inputs() const
index 368e4ba..e036b98 100644 (file)
@@ -443,6 +443,11 @@ class Output_segment
   flags() const
   { return this->flags_; }
 
+  // Return the memory size.
+  uint64_t
+  memsz() const
+  { return this->memsz_; }
+
   // Return the maximum alignment of the Output_data.
   uint64_t
   max_data_align() const;
index f086e6d..66f9572 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2006-10-10 11:40-0700\n"
+"POT-Creation-Date: 2006-10-20 13:39-0700\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -91,7 +91,7 @@ msgstr ""
 msgid "%s: cannot open %s: %s\n"
 msgstr ""
 
-#: gold.cc:76
+#: gold.cc:100
 msgid "no input files"
 msgstr ""
 
@@ -139,16 +139,51 @@ msgstr ""
 msgid "pthread_cond_signal failed"
 msgstr ""
 
-#: i386.cc:98
+#: i386.cc:223 i386.cc:319 i386.cc:466
 #, c-format
-msgid "%s: %s: unsupported reloc %u\n"
+msgid "%s: %s: unexpected reloc %u in object file\n"
 msgstr ""
 
-#: i386.cc:121
+#: i386.cc:256 i386.cc:277
+#, c-format
+msgid "%s: %s: unsupported reloc %u against local symbol\n"
+msgstr ""
+
+#: i386.cc:354 i386.cc:376
+#, c-format
+msgid "%s: %s: unsupported reloc %u against global symbol %s\n"
+msgstr ""
+
+#: i386.cc:397
 #, c-format
 msgid "%s: %s: unsupported RELA reloc section\n"
 msgstr ""
 
+#: i386.cc:503 i386.cc:571
+#, c-format
+msgid "%s: %s: unsupported reloc %u\n"
+msgstr ""
+
+#: i386.cc:528
+#, c-format
+msgid "%s: %s: TLS reloc but no TLS segment\n"
+msgstr ""
+
+#: i386.cc:559
+#, c-format
+msgid "%s: %s: unsupported reloc type %u\n"
+msgstr ""
+
+#: i386.cc:689
+#, c-format
+msgid "%s: %s: TLS relocation out of range\n"
+msgstr ""
+
+#: i386.cc:707
+#, c-format
+msgid "%s: %s: TLS relocation against invalid instruction\n"
+msgstr ""
+
 #: object.cc:60
 #, c-format
 msgid "%s: %s: bad e_ehsize field (%d != %d)\n"
@@ -159,103 +194,103 @@ msgstr ""
 msgid "%s: %s: bad e_shentsize field (%d != %d)\n"
 msgstr ""
 
-#: object.cc:104
+#: object.cc:108 object.cc:418
+#, c-format
+msgid "%s: %s: bad section name offset for section %u: %lu\n"
+msgstr ""
+
+#: object.cc:131
 #, c-format
 msgid "%s: %s: unsupported ELF machine number %d\n"
 msgstr ""
 
-#: object.cc:196
+#: object.cc:226
 #, c-format
 msgid "%s: %s: invalid symbol table name index: %u\n"
 msgstr ""
 
-#: object.cc:204
+#: object.cc:234
 #, c-format
 msgid "%s: %s: symbol table name section has wrong type: %u\n"
 msgstr ""
 
-#: object.cc:256
+#: object.cc:286
 #, c-format
 msgid "%s: %s: section group %u link %u out of range\n"
 msgstr ""
 
-#: object.cc:266
+#: object.cc:296
 #, c-format
 msgid "%s: %s: section group %u info %u out of range\n"
 msgstr ""
 
-#: object.cc:277
+#: object.cc:307
 #, c-format
 msgid "%s; %s: symtab section %u link %u out of range\n"
 msgstr ""
 
-#: object.cc:293
+#: object.cc:323
 #, c-format
 msgid "%s: %s: symbol %u name offset %u out of range\n"
 msgstr ""
 
-#: object.cc:315
+#: object.cc:345
 #, c-format
 msgid "%s: %s: section %u in section group %u out of range"
 msgstr ""
 
-#: object.cc:388
-#, c-format
-msgid "%s: %s: bad section name offset for section %u: %lu\n"
-msgstr ""
-
-#: object.cc:449
+#: object.cc:479
 #, c-format
 msgid "%s: %s: size of symbols is not multiple of symbol size\n"
 msgstr ""
 
-#: object.cc:537
+#: object.cc:566
 #, c-format
 msgid "%s: %s: unknown section index %u for local symbol %u\n"
 msgstr ""
 
-#: object.cc:548
+#: object.cc:577
 #, c-format
 msgid "%s: %s: local symbol %u section index %u out of range\n"
 msgstr ""
 
 #. elfcpp::ET_DYN
-#: object.cc:701
+#: object.cc:755
 #, c-format
 msgid "%s: %s: dynamic objects are not yet supported\n"
 msgstr ""
 
-#: object.cc:725 object.cc:778 object.cc:799
+#: object.cc:779 object.cc:832 object.cc:853
 #, c-format
 msgid "%s: %s: ELF file too short\n"
 msgstr ""
 
-#: object.cc:734
+#: object.cc:788
 #, c-format
 msgid "%s: %s: invalid ELF version 0\n"
 msgstr ""
 
-#: object.cc:737
+#: object.cc:791
 #, c-format
 msgid "%s: %s: unsupported ELF version %d\n"
 msgstr ""
 
-#: object.cc:745
+#: object.cc:799
 #, c-format
 msgid "%s: %s: invalid ELF class 0\n"
 msgstr ""
 
-#: object.cc:752
+#: object.cc:806
 #, c-format
 msgid "%s: %s: unsupported ELF class %d\n"
 msgstr ""
 
-#: object.cc:760
+#: object.cc:814
 #, c-format
 msgid "%s: %s: invalid ELF data encoding\n"
 msgstr ""
 
-#: object.cc:767
+#: object.cc:821
 #, c-format
 msgid "%s: %s: unsupported ELF data encoding %d\n"
 msgstr ""
@@ -296,32 +331,36 @@ msgid "Generate relocatable output"
 msgstr ""
 
 #: options.cc:220
-msgid "Do not link against shared libraries"
+msgid "Generate shared library"
 msgstr ""
 
 #: options.cc:222
+msgid "Do not link against shared libraries"
+msgstr ""
+
+#: options.cc:224
 msgid "Report usage information"
 msgstr ""
 
-#: options.cc:319 options.cc:370 options.cc:434
+#: options.cc:322 options.cc:373 options.cc:437
 msgid "missing argument"
 msgstr ""
 
-#: options.cc:332 options.cc:379
+#: options.cc:335 options.cc:382
 msgid "unknown option"
 msgstr ""
 
-#: options.cc:448
+#: options.cc:451
 #, c-format
 msgid "%s: use the --help option for usage information\n"
 msgstr ""
 
-#: options.cc:457
+#: options.cc:460
 #, c-format
 msgid "%s: %s: %s\n"
 msgstr ""
 
-#: options.cc:466
+#: options.cc:469
 #, c-format
 msgid "%s: -%c: %s\n"
 msgstr ""
@@ -361,29 +400,28 @@ msgstr ""
 msgid "%s: %s: close: %s\n"
 msgstr ""
 
-#. Here we have to handle archives and any other input file
-#. types we need.
-#: readsyms.cc:110
+#. Here we have to handle any other input file types we need.
+#: readsyms.cc:109
 #, c-format
 msgid "%s: %s: not an object or archive\n"
 msgstr ""
 
-#: reloc.cc:165
+#: reloc.cc:165 reloc.cc:392
 #, c-format
 msgid "%s: %s: relocation section %u has bad info %u\n"
 msgstr ""
 
-#: reloc.cc:182
+#: reloc.cc:176 reloc.cc:409
 #, c-format
 msgid "%s: %s: relocation section %u uses unexpected symbol table %u\n"
 msgstr ""
 
-#: reloc.cc:201
+#: reloc.cc:192 reloc.cc:428
 #, c-format
 msgid "%s: %s: unexpected entsize for reloc section %u: %lu != %u"
 msgstr ""
 
-#: reloc.cc:212
+#: reloc.cc:203 reloc.cc:439
 #, c-format
 msgid "%s: %s: reloc section %u size %lu uneven"
 msgstr ""
@@ -408,12 +446,12 @@ msgstr ""
 msgid "%s: %s: bad global symbol name offset %u at %lu\n"
 msgstr ""
 
-#: target-reloc.h:76
+#: target-reloc.h:145
 #, c-format
-msgid "%s: %s: reloc %zu has bad offset %lu\n"
+msgid "%s: %s: reloc has bad offset %zu\n"
 msgstr ""
 
-#: target-reloc.h:107
+#: target-reloc.h:176
 #, c-format
 msgid "%s: %s: undefined reference to '%s'\n"
 msgstr ""
index adc8fac..3a5650a 100644 (file)
@@ -76,10 +76,10 @@ Read_symbols::run(Workqueue* workqueue)
 
          Read_symbols_data* sd = new Read_symbols_data;
          obj->read_symbols(sd);
-         workqueue->queue(new Add_symbols(this->symtab_, this->layout_,
-                                          obj, sd,
-                                          this->this_blocker_,
-                                          this->next_blocker_));
+         workqueue->queue_front(new Add_symbols(this->symtab_, this->layout_,
+                                                obj, sd,
+                                                this->this_blocker_,
+                                                this->next_blocker_));
 
          // Opening the file locked it, so now we need to unlock it.
          input_file->file().unlock();
@@ -105,8 +105,7 @@ Read_symbols::run(Workqueue* workqueue)
        }
     }
 
-  // Here we have to handle archives and any other input file
-  // types we need.
+  // Here we have to handle any other input file types we need.
   fprintf(stderr, _("%s: %s: not an object or archive\n"),
          program_name, input_file->file().filename().c_str());
   gold_exit(false);
index 905eeae..bb672e4 100644 (file)
 namespace gold
 {
 
+// Read_relocs methods.
+
+// These tasks just read the relocation information from the file.
+// After reading it, the start another task to process the
+// information.  These tasks requires access to the file.
+
+Task::Is_runnable_type
+Read_relocs::is_runnable(Workqueue*)
+{
+  return this->object_->is_locked() ? IS_LOCKED : IS_RUNNABLE;
+}
+
+// Lock the file.
+
+Task_locker*
+Read_relocs::locks(Workqueue*)
+{
+  return new Task_locker_obj<Object>(*this->object_);
+}
+
+// Read the relocations and then start a Scan_relocs_task.
+
+void
+Read_relocs::run(Workqueue* workqueue)
+{
+  Read_relocs_data *rd = new Read_relocs_data;
+  this->object_->read_relocs(rd);
+  workqueue->queue_front(new Scan_relocs(this->options_, this->symtab_,
+                                        this->object_, rd, this->symtab_lock_,
+                                        this->blocker_));
+}
+
+// Scan_relocs methods.
+
+// These tasks scan the relocations read by Read_relocs and mark up
+// the symbol table to indicate which relocations are required.  We
+// use a lock on the symbol table to keep them from interfering with
+// each other.
+
+Task::Is_runnable_type
+Scan_relocs::is_runnable(Workqueue*)
+{
+  return this->symtab_lock_->is_writable() ? IS_RUNNABLE : IS_LOCKED;
+}
+
+// Return the locks we hold: one on the file, one on the symbol table
+// and one blocker.
+
+class Scan_relocs::Scan_relocs_locker : public Task_locker
+{
+ public:
+  Scan_relocs_locker(Object* object, Task_token& symtab_lock, Task* task,
+                    Task_token& blocker, Workqueue* workqueue)
+    : objlock_(*object), symtab_locker_(symtab_lock, task),
+      blocker_(blocker, workqueue)
+  { }
+
+ private:
+  Task_locker_obj<Object> objlock_;
+  Task_locker_write symtab_locker_;
+  Task_locker_block blocker_;
+};
+
+Task_locker*
+Scan_relocs::locks(Workqueue* workqueue)
+{
+  return new Scan_relocs_locker(this->object_, *this->symtab_lock_, this,
+                               *this->blocker_, workqueue);
+}
+
+// Scan the relocs.
+
+void
+Scan_relocs::run(Workqueue*)
+{
+  this->object_->scan_relocs(this->options_, this->symtab_, this->rd_);
+  delete this->rd_;
+  this->rd_ = NULL;
+}
+
 // Relocate_task methods.
 
 // These tasks are always runnable.
@@ -48,17 +128,154 @@ Relocate_task::locks(Workqueue* workqueue)
 void
 Relocate_task::run(Workqueue*)
 {
-  this->object_->relocate(this->options_, this->symtab_, this->sympool_,
+  this->object_->relocate(this->options_, this->symtab_, this->layout_,
                          this->of_);
 }
 
+// Read the relocs and local symbols from the object file and store
+// the information in RD.
+
+template<int size, bool big_endian>
+void
+Sized_object<size, big_endian>::do_read_relocs(Read_relocs_data* rd)
+{
+  rd->relocs.clear();
+
+  unsigned int shnum = this->shnum();
+  if (shnum == 0)
+    return;
+
+  rd->relocs.reserve(shnum / 2);
+
+  const unsigned char *pshdrs = this->get_view(this->shoff_,
+                                              shnum * This::shdr_size);
+  // Skip the first, dummy, section.
+  const unsigned char *ps = pshdrs + This::shdr_size;
+  for (unsigned int i = 1; i < shnum; ++i, ps += This::shdr_size)
+    {
+      typename This::Shdr shdr(ps);
+
+      unsigned int sh_type = shdr.get_sh_type();
+      if (sh_type != elfcpp::SHT_REL && sh_type != elfcpp::SHT_RELA)
+       continue;
+
+      unsigned int shndx = shdr.get_sh_info();
+      if (shndx >= shnum)
+       {
+         fprintf(stderr, _("%s: %s: relocation section %u has bad info %u\n"),
+                 program_name, this->name().c_str(), i, shndx);
+         gold_exit(false);
+       }
+
+      if (!this->is_section_included(shndx))
+       continue;
+
+      if (shdr.get_sh_link() != this->symtab_shnum_)
+       {
+         fprintf(stderr,
+                 _("%s: %s: relocation section %u uses unexpected "
+                   "symbol table %u\n"),
+                 program_name, this->name().c_str(), i, shdr.get_sh_link());
+         gold_exit(false);
+       }
+
+      off_t sh_size = shdr.get_sh_size();
+
+      unsigned int reloc_size;
+      if (sh_type == elfcpp::SHT_REL)
+       reloc_size = elfcpp::Elf_sizes<size>::rel_size;
+      else
+       reloc_size = elfcpp::Elf_sizes<size>::rela_size;
+      if (reloc_size != shdr.get_sh_entsize())
+       {
+         fprintf(stderr,
+                 _("%s: %s: unexpected entsize for reloc section %u: "
+                   "%lu != %u"),
+                 program_name, this->name().c_str(), i,
+                 static_cast<unsigned long>(shdr.get_sh_entsize()),
+                 reloc_size);
+         gold_exit(false);
+       }
+
+      size_t reloc_count = sh_size / reloc_size;
+      if (reloc_count * reloc_size != sh_size)
+       {
+         fprintf(stderr, _("%s: %s: reloc section %u size %lu uneven"),
+                 program_name, this->name().c_str(), i,
+                 static_cast<unsigned long>(sh_size));
+         gold_exit(false);
+       }
+
+      rd->relocs.push_back(Section_relocs());
+      Section_relocs& sr(rd->relocs.back());
+      sr.reloc_shndx = i;
+      sr.data_shndx = shndx;
+      sr.contents = this->get_lasting_view(shdr.get_sh_offset(), sh_size);
+      sr.sh_type = sh_type;
+      sr.reloc_count = reloc_count;
+    }
+
+  // Read the local symbols.
+  if (this->symtab_shnum_ == 0 || this->local_symbol_count_ == 0)
+    rd->local_symbols = NULL;
+  else
+    {
+      typename This::Shdr symtabshdr(pshdrs
+                                    + this->symtab_shnum_ * This::shdr_size);
+      assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
+      const int sym_size = This::sym_size;
+      const unsigned int loccount = this->local_symbol_count_;
+      assert(loccount == symtabshdr.get_sh_info());
+      off_t locsize = loccount * sym_size;
+      rd->local_symbols = this->get_lasting_view(symtabshdr.get_sh_offset(),
+                                                locsize);
+    }
+}
+
+// Scan the relocs and adjust the symbol table.  This looks for
+// relocations which require GOT/PLT/COPY relocations.
+
+template<int size, bool big_endian>
+void
+Sized_object<size, big_endian>::do_scan_relocs(const General_options& options,
+                                              Symbol_table* symtab,
+                                              Read_relocs_data* rd)
+{
+  Sized_target<size, big_endian>* target = this->sized_target();
+
+  const unsigned char* local_symbols;
+  if (rd->local_symbols == NULL)
+    local_symbols = NULL;
+  else
+    local_symbols = rd->local_symbols->data();
+
+  for (Read_relocs_data::Relocs_list::iterator p = rd->relocs.begin();
+       p != rd->relocs.end();
+       ++p)
+    {
+      target->scan_relocs(options, symtab, this, p->sh_type,
+                         p->contents->data(), p->reloc_count,
+                         this->local_symbol_count_,
+                         local_symbols,
+                         this->symbols_);
+      delete p->contents;
+      p->contents = NULL;
+    }
+
+  if (rd->local_symbols != NULL)
+    {
+      delete rd->local_symbols;
+      rd->local_symbols = NULL;
+    }
+}
+
 // Relocate the input sections and write out the local symbols.
 
 template<int size, bool big_endian>
 void
-Sized_object<size, big_endian>::do_relocate(const General_options&,
+Sized_object<size, big_endian>::do_relocate(const General_options& options,
                                            const Symbol_table* symtab,
-                                           const Stringpool* sympool,
+                                           const Layout* layout,
                                            Output_file* of)
 {
   unsigned int shnum = this->shnum();
@@ -78,7 +295,7 @@ Sized_object<size, big_endian>::do_relocate(const General_options&,
 
   // Apply relocations.
 
-  this->relocate_sections(symtab, pshdrs, &views);
+  this->relocate_sections(options, symtab, layout, pshdrs, &views);
 
   // Write out the accumulated views.
   for (unsigned int i = 1; i < shnum; ++i)
@@ -89,7 +306,7 @@ Sized_object<size, big_endian>::do_relocate(const General_options&,
     }
 
   // Write out the local symbols.
-  this->write_local_symbols(of, sympool);
+  this->write_local_symbols(of, layout->sympool());
 }
 
 // Write section data to the output file.  PSHDRS points to the
@@ -127,9 +344,8 @@ Sized_object<size, big_endian>::write_sections(const unsigned char* pshdrs,
       off_t sh_size = shdr.get_sh_size();
 
       unsigned char* view = of->get_output_view(start, sh_size);
-      this->input_file()->file().read(shdr.get_sh_offset(),
-                                     sh_size,
-                                     view);
+      this->read(shdr.get_sh_offset(), sh_size, view);
+
       pvs->view = view;
       pvs->address = os->address() + map_sections[i].offset;
       pvs->offset = start;
@@ -142,14 +358,25 @@ Sized_object<size, big_endian>::write_sections(const unsigned char* pshdrs,
 
 template<int size, bool big_endian>
 void
-Sized_object<size, big_endian>::relocate_sections(const Symbol_table* symtab,
-                                                 const unsigned char* pshdrs,
-                                                 Views* pviews)
+Sized_object<size, big_endian>::relocate_sections(
+    const General_options& options,
+    const Symbol_table* symtab,
+    const Layout* layout,
+    const unsigned char* pshdrs,
+    Views* pviews)
 {
   unsigned int shnum = this->shnum();
-  std::vector<Map_to_output>& map_sections(this->map_to_output());
   Sized_target<size, big_endian>* target = this->sized_target();
 
+  Relocate_info<size, big_endian> relinfo;
+  relinfo.options = &options;
+  relinfo.symtab = symtab;
+  relinfo.layout = layout;
+  relinfo.object = this;
+  relinfo.local_symbol_count = this->local_symbol_count_;
+  relinfo.values = this->values_;
+  relinfo.symbols = this->symbols_;
+
   const unsigned char* p = pshdrs + This::shdr_size;
   for (unsigned int i = 1; i < shnum; ++i, p += This::shdr_size)
     {
@@ -167,7 +394,7 @@ Sized_object<size, big_endian>::relocate_sections(const Symbol_table* symtab,
          gold_exit(false);
        }
 
-      if (map_sections[index].output_section == NULL)
+      if (!this->is_section_included(index))
        {
          // This relocation section is against a section which we
          // discarded.
@@ -215,10 +442,12 @@ Sized_object<size, big_endian>::relocate_sections(const Symbol_table* symtab,
          gold_exit(false);
        }
 
-      target->relocate_section(symtab, this, sh_type, prelocs, reloc_count,
-                              this->local_symbol_count_,
-                              this->values_,
-                              this->symbols_,
+      relinfo.reloc_shndx = i;
+      relinfo.data_shndx = index;
+      target->relocate_section(&relinfo,
+                              sh_type,
+                              prelocs,
+                              reloc_count,
                               (*pviews)[index].view,
                               (*pviews)[index].address,
                               (*pviews)[index].view_size);
@@ -230,30 +459,70 @@ Sized_object<size, big_endian>::relocate_sections(const Symbol_table* symtab,
 
 template
 void
+Sized_object<32, false>::do_read_relocs(Read_relocs_data* rd);
+
+template
+void
+Sized_object<32, true>::do_read_relocs(Read_relocs_data* rd);
+
+template
+void
+Sized_object<64, false>::do_read_relocs(Read_relocs_data* rd);
+
+template
+void
+Sized_object<64, true>::do_read_relocs(Read_relocs_data* rd);
+
+template
+void
+Sized_object<32, false>::do_scan_relocs(const General_options& options,
+                                       Symbol_table* symtab,
+                                       Read_relocs_data* rd);
+
+template
+void
+Sized_object<32, true>::do_scan_relocs(const General_options& options,
+                                      Symbol_table* symtab,
+                                      Read_relocs_data* rd);
+
+template
+void
+Sized_object<64, false>::do_scan_relocs(const General_options& options,
+                                       Symbol_table* symtab,
+                                       Read_relocs_data* rd);
+
+template
+void
+Sized_object<64, true>::do_scan_relocs(const General_options& options,
+                                      Symbol_table* symtab,
+                                      Read_relocs_data* rd);
+
+template
+void
 Sized_object<32, false>::do_relocate(const General_options& options,
                                     const Symbol_table* symtab,
-                                    const Stringpool* sympool,
+                                    const Layout* layout,
                                     Output_file* of);
 
 template
 void
 Sized_object<32, true>::do_relocate(const General_options& options,
                                    const Symbol_table* symtab,
-                                   const Stringpool* sympool,
+                                   const Layout* layout,
                                    Output_file* of);
 
 template
 void
 Sized_object<64, false>::do_relocate(const General_options& options,
                                     const Symbol_table* symtab,
-                                    const Stringpool* sympool,
+                                    const Layout* layout,
                                     Output_file* of);
 
 template
 void
 Sized_object<64, true>::do_relocate(const General_options& options,
                                    const Symbol_table* symtab,
-                                   const Stringpool* sympool,
+                                   const Layout* layout,
                                    Output_file* of);
 
 
index 287bb79..a2e9d54 100644 (file)
@@ -3,18 +3,98 @@
 #ifndef GOLD_RELOC_H
 #define GOLD_RELOC_H
 
+#include <byteswap.h>
+
 #include "workqueue.h"
 
 namespace gold
 {
 
+class Object;
+class Read_relocs_data;
+class Stringpool;
+
+// A class to read the relocations for an object file, and then queue
+// up a task to see if they require any GOT/PLT/COPY relocations in
+// the symbol table.
+
+class Read_relocs : public Task
+{
+ public:
+  // SYMTAB_LOCK is used to lock the symbol table.  BLOCKER should be
+  // unblocked when the Scan_relocs task completes.
+  Read_relocs(const General_options& options, Symbol_table* symtab,
+             Object* object, Task_token* symtab_lock,
+             Task_token* blocker)
+    : options_(options), symtab_(symtab), object_(object),
+      symtab_lock_(symtab_lock), blocker_(blocker)
+  { }
+
+  // The standard Task methods.
+
+  Is_runnable_type
+  is_runnable(Workqueue*);
+
+  Task_locker*
+  locks(Workqueue*);
+
+  void
+  run(Workqueue*);
+
+ private:
+  const General_options& options_;
+  Symbol_table* symtab_;
+  Object* object_;
+  Task_token* symtab_lock_;
+  Task_token* blocker_;
+};
+
+// Scan the relocations for an object to see if they require any
+// GOT/PLT/COPY relocations.
+
+class Scan_relocs : public Task
+{
+ public:
+  // SYMTAB_LOCK is used to lock the symbol table.  BLOCKER should be
+  // unblocked when the task completes.
+  Scan_relocs(const General_options& options, Symbol_table* symtab,
+             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)
+  { }
+
+  // The standard Task methods.
+
+  Is_runnable_type
+  is_runnable(Workqueue*);
+
+  Task_locker*
+  locks(Workqueue*);
+
+  void
+  run(Workqueue*);
+
+ private:
+  class Scan_relocs_locker;
+
+  const General_options& options_;
+  Symbol_table* symtab_;
+  Object* object_;
+  Read_relocs_data* rd_;
+  Task_token* symtab_lock_;
+  Task_token* blocker_;
+};
+
+// A class to perform all the relocations for an object file.
+
 class Relocate_task : public Task
 {
  public:
   Relocate_task(const General_options& options, const Symbol_table* symtab,
-               const Stringpool* sympool, Object* object, Output_file* of,
+               const Layout* layout, Object* object, Output_file* of,
                Task_token* final_blocker)
-    : options_(options), symtab_(symtab), sympool_(sympool), object_(object),
+    : options_(options), symtab_(symtab), layout_(layout), object_(object),
       of_(of), final_blocker_(final_blocker)
   { }
 
@@ -34,12 +114,432 @@ class Relocate_task : public Task
 
   const General_options& options_;
   const Symbol_table* symtab_;
-  const Stringpool* sympool_;
+  const Layout* layout_;
   Object* object_;
   Output_file* of_;
   Task_token* final_blocker_;
 };
 
+// Integer swapping routines used by relocation functions.  FIXME:
+// Maybe these should be more general, and/or shared with elfcpp.
+
+// Endian simply indicates whether the host is big endian or not,
+// based on the results of the configure script.
+
+struct Endian
+{
+ public:
+  // Used for template specializations.
+#ifdef WORDS_BIGENDIAN
+  static const bool host_big_endian = true;
+#else
+  static const bool host_big_endian = false;
+#endif
+};
+
+// Valtype_base is a template based on size (8, 16, 32, 64) which
+// defines a typedef Valtype for the unsigned integer of the specified
+// size.
+
+template<int size>
+struct Valtype_base;
+
+template<>
+struct Valtype_base<8>
+{
+  typedef unsigned char Valtype;
+};
+
+template<>
+struct Valtype_base<16>
+{
+  typedef uint16_t Valtype;
+};
+
+template<>
+struct Valtype_base<32>
+{
+  typedef uint32_t Valtype;
+};
+
+template<>
+struct Valtype_base<64>
+{
+  typedef uint64_t Valtype;
+};
+
+// Convert_host is a template based on size and on whether the host
+// and target have the same endianness.  It defines the type Valtype,
+// and defines a function convert_host which takes an argument of type
+// Valtype and swaps it if the host and target have different
+// endianness.
+
+template<int size, bool same_endian>
+struct Convert_host;
+
+template<int size>
+struct Convert_host<size, true>
+{
+  typedef typename Valtype_base<size>::Valtype Valtype;
+
+  static inline Valtype
+  convert_host(Valtype v)
+  { return v; }
+};
+
+template<>
+struct Convert_host<8, false>
+{
+  typedef Valtype_base<8>::Valtype Valtype;
+
+  static inline Valtype
+  convert_host(Valtype v)
+  { return v; }
+};
+
+template<>
+struct Convert_host<16, false>
+{
+  typedef Valtype_base<16>::Valtype Valtype;
+
+  static inline Valtype
+  convert_host(Valtype v)
+  { return bswap_16(v); }
+};
+
+template<>
+struct Convert_host<32, false>
+{
+  typedef Valtype_base<32>::Valtype Valtype;
+
+  static inline Valtype
+  convert_host(Valtype v)
+  { return bswap_32(v); }
+};
+
+template<>
+struct Convert_host<64, false>
+{
+  typedef Valtype_base<64>::Valtype Valtype;
+
+  static inline Valtype
+  convert_host(Valtype v)
+  { return bswap_64(v); }
+};
+
+// Convert is a template based on size and on whether we have a big
+// endian target.  It defines Valtype and convert_host like
+// Convert_host.  That is, it is just like Convert_host except in the
+// meaning of the second template parameter.
+
+template<int size, bool big_endian>
+struct Convert
+{
+  typedef typename Valtype_base<size>::Valtype Valtype;
+
+  static inline Valtype
+  convert_host(Valtype v)
+  { return Convert_host<size, big_endian == Endian::host_big_endian>
+      ::convert_host(v); }
+};
+
+// Swap is a template based on size and on whether the target is big
+// endian.  It defines the type Valtype and the functions readval and
+// writeval.  The functions read and write values of the appropriate
+// size out of buffers, swapping them if necessary.
+
+template<int size, bool big_endian>
+struct Swap
+{
+  typedef typename Valtype_base<size>::Valtype Valtype;
+
+  static inline Valtype
+  readval(const Valtype* wv)
+  { return Convert<size, big_endian>::convert_host(*wv); }
+
+  static inline void
+  writeval(Valtype* wv, Valtype v)
+  { *wv = Convert<size, big_endian>::convert_host(v); }
+};
+
+// Swap_unaligned is a template based on size and on whether the
+// target is big endian.  It defines the type Valtype and the
+// functions readval_unaligned and writeval_unaligned.  The functions
+// read and write values of the appropriate size out of buffers which
+// may be misaligned.
+
+template<int size, bool big_endian>
+class Swap_unaligned;
+
+template<bool big_endian>
+class Swap_unaligned<8, big_endian>
+{
+public:
+  typedef typename Valtype_base<8>::Valtype Valtype;
+
+  static inline Valtype
+  readval_unaligned(const unsigned char* wv)
+  { return *wv; }
+
+  static inline void
+  writeval_unaligned(unsigned char* wv, Valtype v)
+  { *wv = v; }
+};
+
+template<>
+class Swap_unaligned<16, false>
+{
+public:
+  typedef Valtype_base<16>::Valtype Valtype;
+
+  static inline Valtype
+  readval_unaligned(const unsigned char* wv)
+  {
+    return (wv[1] << 8) | wv[0];
+  }
+
+  static inline void
+  writeval_unaligned(unsigned char* wv, Valtype v)
+  {
+    wv[1] = v >> 8;
+    wv[0] = v;
+  }
+};
+
+template<>
+class Swap_unaligned<16, true>
+{
+public:
+  typedef Valtype_base<16>::Valtype Valtype;
+
+  static inline Valtype
+  readval_unaligned(const unsigned char* wv)
+  {
+    return (wv[0] << 8) | wv[1];
+  }
+
+  static inline void
+  writeval_unaligned(unsigned char* wv, Valtype v)
+  {
+    wv[0] = v >> 8;
+    wv[1] = v;
+  }
+};
+
+template<>
+class Swap_unaligned<32, false>
+{
+public:
+  typedef Valtype_base<32>::Valtype Valtype;
+
+  static inline Valtype
+  readval_unaligned(const unsigned char* wv)
+  {
+    return (wv[3] << 24) | (wv[2] << 16) | (wv[1] << 8) | wv[0];
+  }
+
+  static inline void
+  writeval_unaligned(unsigned char* wv, Valtype v)
+  {
+    wv[3] = v >> 24;
+    wv[2] = v >> 16;
+    wv[1] = v >> 8;
+    wv[0] = v;
+  }
+};
+
+template<>
+class Swap_unaligned<32, true>
+{
+public:
+  typedef Valtype_base<32>::Valtype Valtype;
+
+  static inline Valtype
+  readval_unaligned(const unsigned char* wv)
+  {
+    return (wv[0] << 24) | (wv[1] << 16) | (wv[2] << 8) | wv[3];
+  }
+
+  static inline void
+  writeval_unaligned(unsigned char* wv, Valtype v)
+  {
+    wv[0] = v >> 24;
+    wv[1] = v >> 16;
+    wv[2] = v >> 8;
+    wv[3] = v;
+  }
+};
+
+template<>
+class Swap_unaligned<64, false>
+{
+public:
+  typedef Valtype_base<64>::Valtype Valtype;
+
+  static inline Valtype
+  readval_unaligned(const unsigned char* wv)
+  {
+    return ((static_cast<Valtype>(wv[7]) << 56)
+           | (static_cast<Valtype>(wv[6]) << 48)
+           | (static_cast<Valtype>(wv[5]) << 40)
+           | (static_cast<Valtype>(wv[4]) << 32)
+           | (static_cast<Valtype>(wv[3]) << 24)
+           | (static_cast<Valtype>(wv[2]) << 16)
+           | (static_cast<Valtype>(wv[1]) << 8)
+           | static_cast<Valtype>(wv[0]));
+  }
+
+  static inline void
+  writeval_unaligned(unsigned char* wv, Valtype v)
+  {
+    wv[7] = v >> 56;
+    wv[6] = v >> 48;
+    wv[5] = v >> 40;
+    wv[4] = v >> 32;
+    wv[3] = v >> 24;
+    wv[2] = v >> 16;
+    wv[1] = v >> 8;
+    wv[0] = v;
+  }
+};
+
+template<>
+class Swap_unaligned<64, true>
+{
+public:
+  typedef Valtype_base<64>::Valtype Valtype;
+
+  static inline Valtype
+  readval_unaligned(const unsigned char* wv)
+  {
+    return ((static_cast<Valtype>(wv[0]) << 56)
+           | (static_cast<Valtype>(wv[1]) << 48)
+           | (static_cast<Valtype>(wv[2]) << 40)
+           | (static_cast<Valtype>(wv[3]) << 32)
+           | (static_cast<Valtype>(wv[4]) << 24)
+           | (static_cast<Valtype>(wv[5]) << 16)
+           | (static_cast<Valtype>(wv[6]) << 8)
+           | static_cast<Valtype>(wv[7]));
+  }
+
+  static inline void
+  writeval_unaligned(unsigned char* wv, Valtype v)
+  {
+    wv[7] = v >> 56;
+    wv[6] = v >> 48;
+    wv[5] = v >> 40;
+    wv[4] = v >> 32;
+    wv[3] = v >> 24;
+    wv[2] = v >> 16;
+    wv[1] = v >> 8;
+    wv[0] = v;
+  }
+};
+
+// Standard relocation routines which are used on many targets.  Here
+// SIZE and BIG_ENDIAN refer to the target, not the relocation type.
+
+template<int size, bool big_endian>
+class Relocate_functions
+{
+private:
+  // Do a simple relocation with the addend in the section contents.
+  // VALSIZE is the size of the value.
+  template<int valsize>
+  static inline void
+  rel(unsigned char* view, typename Swap<valsize, big_endian>::Valtype value)
+  {
+    typedef typename Swap<valsize, big_endian>::Valtype Valtype;
+    Valtype* wv = reinterpret_cast<Valtype*>(view);
+    Valtype x = Swap<valsize, big_endian>::readval(wv);
+    Swap<valsize, big_endian>::writeval(wv, x + value);
+  }
+
+  // Do a simple PC relative relocation with the addend in the section
+  // contents.  VALSIZE is the size of the value.
+  template<int valsize>
+  static inline void
+  pcrel(unsigned char* view, typename Swap<valsize, big_endian>::Valtype value,
+       typename elfcpp::Elf_types<size>::Elf_Addr address)
+  {
+    typedef typename Swap<valsize, big_endian>::Valtype Valtype;
+    Valtype* wv = reinterpret_cast<Valtype*>(view);
+    Valtype x = Swap<valsize, big_endian>::readval(wv);
+    Swap<valsize, big_endian>::writeval(wv, x + value - address);
+  }
+
+  typedef Relocate_functions<size, big_endian> This;
+
+public:
+  // Do a simple 8-bit REL relocation with the addend in the object
+  // file data.
+  static inline void
+  rel8(unsigned char* view, unsigned char value)
+  {
+    This::template rel<8>(view, value);
+  }
+
+  // Do a simple 8-bit PC relative relocation with the addend in the
+  // object file data.
+  static inline void
+  pcrel8(unsigned char* view, unsigned char value,
+        typename elfcpp::Elf_types<size>::Elf_Addr address)
+  {
+    This::template pcrel<8>(view, value, address);
+  }
+
+  // Do a simple 16-bit REL relocation with the addend in the object
+  // file data.
+  static inline void
+  rel16(unsigned char* view, elfcpp::Elf_Half value)
+  {
+    This::template rel<16>(view, value);
+  }
+
+  // Do a simple 32-bit PC relative REL relocation with the addend in
+  // the object file data.
+  static inline void
+  pcrel16(unsigned char* view, elfcpp::Elf_Word value,
+         typename elfcpp::Elf_types<size>::Elf_Addr address)
+  {
+    This::template pcrel<16>(view, value, address);
+  }
+
+  // Do a simple 32-bit REL relocation with the addend in the section
+  // contents.
+  static inline void
+  rel32(unsigned char* view, elfcpp::Elf_Word value)
+  {
+    This::template rel<32>(view, value);
+  }
+
+  // Do a simple 32-bit PC relative REL relocation with the addend in
+  // the section contents.
+  static inline void
+  pcrel32(unsigned char* view, elfcpp::Elf_Word value,
+         typename elfcpp::Elf_types<size>::Elf_Addr address)
+  {
+    This::template pcrel<32>(view, value, address);
+  }
+
+  // Do a simple 64-bit REL relocation with the addend in the section
+  // contents.
+  static inline void
+  rel64(unsigned char* view, elfcpp::Elf_Word value)
+  {
+    This::template rel<64>(view, value);
+  }
+
+  // Do a simple 64-bit PC relative REL relocation with the addend in
+  // the section contents.
+  static inline void
+  pcrel64(unsigned char* view, elfcpp::Elf_Word value,
+         typename elfcpp::Elf_types<size>::Elf_Addr address)
+  {
+    This::template pcrel<64>(view, value, address);
+  }
+};
+
 } // End namespace gold.
 
 #endif // !defined(GOLD_RELOC_H)
index 23d54e4..2c5fbc9 100644 (file)
@@ -94,6 +94,12 @@ 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.
+  bool
+  in_dynsym() const
+  { return this->in_dyn_; }
+
  protected:
   // Instances of this class should always be created at a specific
   // size.
index f972b11..2d1fe30 100644 (file)
@@ -4,6 +4,7 @@
 #define GOLD_TARGET_RELOC_H
 
 #include "elfcpp.h"
+#include "object.h"
 #include "symtab.h"
 
 namespace gold
@@ -29,7 +30,79 @@ struct Reloc_types<elfcpp::SHT_RELA, size, big_endian>
   static const int reloc_size = elfcpp::Elf_sizes<size>::rela_size;
 };
 
-// This function implements the generic part of relocation handling.
+// This function implements the generic part of reloc scanning.  This
+// is an inline function which takes a class whose operator()
+// implements the machine specific part of scanning.  We do it this
+// way to avoidmaking a function call for each relocation, and to
+// avoid repeating the generic code for each target.
+
+template<int size, bool big_endian, int sh_type, typename Scan>
+inline void
+scan_relocs(
+    const General_options& options,
+    Symbol_table* symtab,
+    Sized_object<size, big_endian>* object,
+    const unsigned char* prelocs,
+    size_t reloc_count,
+    size_t local_count,
+    const unsigned char* plocal_syms,
+    Symbol** global_syms)
+{
+  typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype;
+  const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
+  const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+  Scan scan;
+
+  for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
+    {
+      Reltype reloc(prelocs);
+
+      typename elfcpp::Elf_types<size>::Elf_WXword r_info = reloc.get_r_info();
+      unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
+      unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
+
+      if (r_sym < local_count)
+       {
+         assert(plocal_syms != NULL);
+         typename elfcpp::Sym<size, big_endian> lsym(plocal_syms
+                                                     + r_sym * sym_size);
+         const unsigned int shndx = lsym.get_st_shndx();
+         if (shndx < elfcpp::SHN_LORESERVE
+             && !object->is_section_included(lsym.get_st_shndx()))
+           {
+             // RELOC is a relocation against a local symbol in a
+             // section we are discarding.  We can ignore this
+             // relocation.  It will eventually become a reloc
+             // against the value zero.
+             //
+             // FIXME: We should issue a warning if this is an
+             // allocated section; is this the best place to do it?
+             // 
+             // FIXME: The old GNU linker would in some cases look
+             // for the linkonce section which caused this section to
+             // be discarded, and, if the other section was the same
+             // size, change the reloc to refer to the other section.
+             // That seems risky and weird to me, and I don't know of
+             // any case where it is actually required.
+
+             continue;
+           }
+
+         scan.local(options, object, reloc, r_type, lsym);
+       }
+      else
+       {
+         Symbol* gsym = global_syms[r_sym - local_count];
+         assert(gsym != NULL);
+         if (gsym->is_forwarder())
+           gsym = symtab->resolve_forwards(gsym);
+
+         scan.global(options, object, reloc, r_type, gsym);
+       }
+    }
+}
+
+// This function implements the generic part of relocation processing.
 // This is an inline function which take a class whose operator()
 // implements the machine specific part of relocation.  We do it this
 // way to avoid making a function call for each relocation, and to
@@ -37,27 +110,19 @@ struct Reloc_types<elfcpp::SHT_RELA, size, big_endian>
 // target.
 
 // SIZE is the ELF size: 32 or 64.  BIG_ENDIAN is the endianness of
-// the data.  SH_TYPE is the section type: SHT_REL or SHT_RELA.  RELOC
-// implements operator() to do a relocation.
+// the data.  SH_TYPE is the section type: SHT_REL or SHT_RELA.
+// RELOCATE implements operator() to do a relocation.
 
-// OBJECT is the object for we are processing relocs.  SH_TYPE is the
-// type of relocation: SHT_REL or SHT_RELA.  PRELOCS points to the
-// relocation data.  RELOC_COUNT is the number of relocs.  LOCAL_COUNT
-// is the number of local symbols.  LOCAL_VALUES holds the values of
-// the local symbols.  GLOBAL_SYMS points to the global symbols.  VIEW
-// is the section data, VIEW_ADDRESS is its memory address, and
-// VIEW_SIZE is the size.
+// PRELOCS points to the relocation data.  RELOC_COUNT is the number
+// of relocs.  VIEW is the section data, VIEW_ADDRESS is its memory
+// address, and VIEW_SIZE is the size.
 
 template<int size, bool big_endian, int sh_type, typename Relocate>
 inline void
 relocate_section(
-    const Symbol_table* symtab,
-    Sized_object<size, big_endian>* object,
+    const Relocate_info<size, big_endian>* relinfo,
     const unsigned char* prelocs,
     size_t reloc_count,
-    size_t local_count,
-    const typename elfcpp::Elf_types<size>::Elf_Addr* local_values,
-    Symbol** global_syms,
     unsigned char* view,
     typename elfcpp::Elf_types<size>::Elf_Addr view_address,
     off_t view_size)
@@ -66,6 +131,10 @@ relocate_section(
   const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
   Relocate relocate;
 
+  unsigned int local_count = relinfo->local_symbol_count;
+  typename elfcpp::Elf_types<size>::Elf_Addr *local_values = relinfo->values;
+  Symbol** global_syms = relinfo->symbols;
+
   for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
     {
       Reltype reloc(prelocs);
@@ -73,9 +142,9 @@ relocate_section(
       off_t offset = reloc.get_r_offset();
       if (offset < 0 || offset >= view_size)
        {
-         fprintf(stderr, _("%s: %s: reloc %zu has bad offset %lu\n"),
-                 program_name, object->name().c_str(), i,
-                 static_cast<unsigned long>(offset));
+         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);
        }
 
@@ -96,7 +165,7 @@ relocate_section(
          Symbol* gsym = global_syms[r_sym - local_count];
          assert(gsym != NULL);
          if (gsym->is_forwarder())
-           gsym = symtab->resolve_forwards(gsym);
+           gsym = relinfo->symtab->resolve_forwards(gsym);
 
          sym = static_cast<Sized_symbol<size>*>(gsym);
          value = sym->value();
@@ -105,13 +174,14 @@ relocate_section(
              && sym->binding() != elfcpp::STB_WEAK)
            {
              fprintf(stderr, _("%s: %s: undefined reference to '%s'\n"),
-                     program_name, object->name().c_str(), sym->name());
+                     program_name, relinfo->location(i, offset).c_str(),
+                     sym->name());
              // gold_exit(false);
            }
        }
 
-      relocate(object, reloc, r_type, sym, value, view + offset,
-              view_address + offset);
+      relocate.relocate(relinfo, i, reloc, r_type, sym, value, view + offset,
+                       view_address + offset, view_size);
     }
 }
 
index 5230bb2..75f149e 100644 (file)
 namespace gold
 {
 
+class General_options;
 class Object;
 template<int size, bool big_endian>
 class Sized_object;
+template<int size, bool big_endian>
+struct Relocate_info;
 
 // The abstract class for target specific handling.
 
@@ -129,32 +132,45 @@ class Sized_target : public Target
   // Resolve a symbol for the target.  This should be overridden by a
   // target which needs to take special action.  TO is the
   // pre-existing symbol.  SYM is the new symbol, seen in OBJECT.
+  // This will only be called if has_resolve() returns true.
   virtual void
   resolve(Symbol*, const elfcpp::Sym<size, big_endian>&, Object*)
   { abort(); }
 
-  // Relocate section data.  SYMTAB is the symbol table.  OBJECT is
-  // the object in which the section appears.  SH_TYPE is the type of
-  // the relocation section, SHT_REL or SHT_RELA.  PRELOCS points to
-  // the relocation information.  RELOC_COUNT is the number of relocs.
-  // LOCAL_COUNT is the number of local symbols.  The VALUES and
-  // GLOBAL_SYMS have symbol table information.  VIEW is a view into
-  // the output file holding the section contents, VIEW_ADDRESS is the
-  // virtual address of the view, and VIEW_SIZE is the size of the
-  // view.
+  // Scan the relocs for a section, and record any information
+  // required for the symbol.  OPTIONS is the command line options.
+  // SYMTAB is the symbol table.  OBJECT is the object in which the
+  // section appears.  SH_TYPE is the type of the relocation section,
+  // SHT_REL or SHT_RELA.  PRELOCS points to the relocation data.
+  // RELOC_COUNT is the number of relocs.  LOCAL_SYMBOL_COUNT is the
+  // number of local symbols.  PLOCAL_SYMBOLS points to the local
+  // symbol data from OBJECT.  GLOBAL_SYMBOLS is the array of pointers
+  // to the global symbol table from OBJECT.
   virtual void
-  relocate_section(const Symbol_table*, // symtab
-                  Sized_object<size, big_endian>*, // object
-                  unsigned int, // sh_type
-                  const unsigned char*, // prelocs
-                  size_t, // reloc_count
-                  unsigned int, // local_count
-                  const typename elfcpp::Elf_types<size>::Elf_Addr*, // values
-                  Symbol**, // global_syms
-                  unsigned char*, // view
-                  typename elfcpp::Elf_types<size>::Elf_Addr, // view_address
-                  off_t) // view_size
-  { abort(); }
+  scan_relocs(const General_options& options,
+             Symbol_table* symtab,
+             Sized_object<size, big_endian>* object,
+             unsigned int sh_type,
+             const unsigned char* prelocs,
+             size_t reloc_count,
+             size_t local_symbol_count,
+             const unsigned char* plocal_symbols,
+             Symbol** global_symbols) = 0;
+
+  // Relocate section data.  SH_TYPE is the type of the relocation
+  // section, SHT_REL or SHT_RELA.  PRELOCS points to the relocation
+  // information.  RELOC_COUNT is the number of relocs.  VIEW is a
+  // view into the output file holding the section contents,
+  // VIEW_ADDRESS is the virtual address of the view, and VIEW_SIZE is
+  // the size of the view.
+  virtual void
+  relocate_section(const Relocate_info<size, big_endian>*,
+                  unsigned int sh_type,
+                  const unsigned char* prelocs,
+                  size_t reloc_count,
+                  unsigned char* view,
+                  typename elfcpp::Elf_types<size>::Elf_Addr view_address,
+                  off_t view_size) = 0;
 
  protected:
   Sized_target(const Target::Target_info* pti)
index 716f93d..3ef3422 100644 (file)
@@ -192,6 +192,8 @@ Workqueue::~Workqueue()
   assert(this->running_ == 0);
 }
 
+// Add a task to the queue.
+
 void
 Workqueue::queue(Task* t)
 {
@@ -199,6 +201,15 @@ Workqueue::queue(Task* t)
   this->tasks_.push_back(t);
 }
 
+// Add a task to the front of the queue.
+
+void
+Workqueue::queue_front(Task* t)
+{
+  Hold_lock hl(this->tasks_lock_);
+  this->tasks_.push_front(t);
+}
+
 // Clear the list of completed tasks.  Return whether we cleared
 // anything.  The completed_lock_ must be held when this is called.
 
index a97d86d..5cce2d5 100644 (file)
@@ -288,6 +288,58 @@ class Task
   run(Workqueue*) = 0;
 };
 
+// A simple task which waits for a blocker and then runs a function.
+
+class Task_function_runner
+{
+ public:
+  virtual ~Task_function_runner()
+  { }
+
+  virtual void
+  run(Workqueue*) = 0;
+};
+
+class Task_function : public Task
+{
+ public:
+  // Both points should be allocated using new, and will be deleted
+  // after the task runs.
+  Task_function(Task_function_runner* runner, Task_token* blocker)
+    : runner_(runner), blocker_(blocker)
+  { }
+
+  ~Task_function()
+  {
+    delete this->runner_;
+    delete this->blocker_;
+  }
+
+  // The standard task methods.
+
+  // Wait until the task is unblocked.
+  Is_runnable_type
+  is_runnable(Workqueue*)
+  { return this->blocker_->is_blocked() ? IS_BLOCKED : IS_RUNNABLE; }
+
+  // This type of task does not normally hold any locks.
+  virtual Task_locker*
+  locks(Workqueue*)
+  { return NULL; }
+
+  // Run the action.
+  void
+  run(Workqueue* workqueue)
+  { this->runner_->run(workqueue); }
+
+ private:
+  Task_function(const Task_function&);
+  Task_function& operator=(const Task_function&);
+
+  Task_function_runner* runner_;
+  Task_token* blocker_;
+};
+
 // The workqueue
 
 class Workqueue_runner;
@@ -302,6 +354,11 @@ class Workqueue
   void
   queue(Task*);
 
+  // Add a new task to the front of the work queue.  It will be the
+  // next task to run if it is ready.
+  void
+  queue_front(Task*);
+
   // Process all the tasks on the work queue.
   void
   process();