aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@google.com>2006-10-20 20:40:49 +0000
committerIan Lance Taylor <iant@google.com>2006-10-20 20:40:49 +0000
commit92e059d8dc78c3f65e29e48e368f6e47ea0ab671 (patch)
treef448eb3317d9cbb0f5946422cc28ef157a5f65cb
parentaf4658dc3db33004d6166b161588221ecb463a5f (diff)
downloadgdb-92e059d8dc78c3f65e29e48e368f6e47ea0ab671.zip
gdb-92e059d8dc78c3f65e29e48e368f6e47ea0ab671.tar.gz
gdb-92e059d8dc78c3f65e29e48e368f6e47ea0ab671.tar.bz2
Framework for relocation scanning. Implement simple static TLS
relocations.
-rw-r--r--elfcpp/elfcpp_internal.h2
-rw-r--r--gold/archive.cc2
-rw-r--r--gold/config.in4
-rwxr-xr-xgold/configure232
-rw-r--r--gold/configure.ac2
-rw-r--r--gold/gold.cc102
-rw-r--r--gold/gold.h21
-rw-r--r--gold/i386.cc701
-rw-r--r--gold/layout.cc85
-rw-r--r--gold/layout.h62
-rw-r--r--gold/object.cc86
-rw-r--r--gold/object.h133
-rw-r--r--gold/options.cc3
-rw-r--r--gold/options.h18
-rw-r--r--gold/output.h5
-rw-r--r--gold/po/gold.pot128
-rw-r--r--gold/readsyms.cc11
-rw-r--r--gold/reloc.cc311
-rw-r--r--gold/reloc.h506
-rw-r--r--gold/symtab.h6
-rw-r--r--gold/target-reloc.h114
-rw-r--r--gold/target.h58
-rw-r--r--gold/workqueue.cc11
-rw-r--r--gold/workqueue.h57
24 files changed, 2347 insertions, 313 deletions
diff --git a/elfcpp/elfcpp_internal.h b/elfcpp/elfcpp_internal.h
index 0d69bae..e4c8636 100644
--- a/elfcpp/elfcpp_internal.h
+++ b/elfcpp/elfcpp_internal.h
@@ -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;
diff --git a/gold/archive.cc b/gold/archive.cc
index 8639643..a64109a 100644
--- a/gold/archive.cc
+++ b/gold/archive.cc
@@ -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);
diff --git a/gold/config.in b/gold/config.in
index 3a452ff..1d40c66 100644
--- a/gold/config.in
+++ b/gold/config.in
@@ -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
diff --git a/gold/configure b/gold/configure
index c0d93b7..a64cd70 100755
--- a/gold/configure
+++ b/gold/configure
@@ -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"
diff --git a/gold/configure.ac b/gold/configure.ac
index 024ac48..42cba7f 100644
--- a/gold/configure.ac
+++ b/gold/configure.ac
@@ -16,6 +16,8 @@ AC_PROG_INSTALL
ZW_GNU_GETTEXT_SISTER_DIR
AM_PO_SUBDIRS
+AC_C_BIGENDIAN
+
AC_EXEEXT
AM_BINUTILS_WARNINGS
diff --git a/gold/gold.cc b/gold/gold.cc
index 6874e1b..c39f999 100644
--- a/gold/gold.cc
+++ b/gold/gold.cc
@@ -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)
{
diff --git a/gold/gold.h b/gold/gold.h
index 9ddf2f7..1140d66 100644
--- a/gold/gold.h
+++ b/gold/gold.h
@@ -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*,
diff --git a/gold/i386.cc b/gold/i386.cc
index 32ee881..468cb90 100644
--- a/gold/i386.cc
+++ b/gold/i386.cc
@@ -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);
diff --git a/gold/layout.cc b/gold/layout.cc
index 61b6895..a81fd43 100644
--- a/gold/layout.cc
+++ b/gold/layout.cc
@@ -14,36 +14,13 @@
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();
}
diff --git a/gold/layout.h b/gold/layout.h
index 028d714..4ec2a4a 100644
--- a/gold/layout.h
+++ b/gold/layout.h
@@ -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.
diff --git a/gold/object.cc b/gold/object.cc
index 8f1241a..5efb3cb 100644
--- a/gold/object.cc
+++ b/gold/object.cc
@@ -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.
diff --git a/gold/object.h b/gold/object.h
index ca227c5..49a1ce9 100644
--- a/gold/object.h
+++ b/gold/object.h
@@ -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.
diff --git a/gold/options.cc b/gold/options.cc
index e5a16f1..8e0465f 100644
--- a/gold/options.cc
+++ b/gold/options.cc
@@ -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)
{
}
diff --git a/gold/options.h b/gold/options.h
index ba32ef5..7e890fa 100644
--- a/gold/options.h
+++ b/gold/options.h
@@ -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
diff --git a/gold/output.h b/gold/output.h
index 368e4ba..e036b98 100644
--- a/gold/output.h
+++ b/gold/output.h
@@ -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;
diff --git a/gold/po/gold.pot b/gold/po/gold.pot
index f086e6d..66f9572 100644
--- a/gold/po/gold.pot
+++ b/gold/po/gold.pot
@@ -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 ""
diff --git a/gold/readsyms.cc b/gold/readsyms.cc
index adc8fac..3a5650a 100644
--- a/gold/readsyms.cc
+++ b/gold/readsyms.cc
@@ -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);
diff --git a/gold/reloc.cc b/gold/reloc.cc
index 905eeae..bb672e4 100644
--- a/gold/reloc.cc
+++ b/gold/reloc.cc
@@ -10,6 +10,86 @@
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);
diff --git a/gold/reloc.h b/gold/reloc.h
index 287bb79..a2e9d54 100644
--- a/gold/reloc.h
+++ b/gold/reloc.h
@@ -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)
diff --git a/gold/symtab.h b/gold/symtab.h
index 23d54e4..2c5fbc9 100644
--- a/gold/symtab.h
+++ b/gold/symtab.h
@@ -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.
diff --git a/gold/target-reloc.h b/gold/target-reloc.h
index f972b11..2d1fe30 100644
--- a/gold/target-reloc.h
+++ b/gold/target-reloc.h
@@ -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);
}
}
diff --git a/gold/target.h b/gold/target.h
index 5230bb2..75f149e 100644
--- a/gold/target.h
+++ b/gold/target.h
@@ -21,9 +21,12 @@
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)
diff --git a/gold/workqueue.cc b/gold/workqueue.cc
index 716f93db..3ef3422 100644
--- a/gold/workqueue.cc
+++ b/gold/workqueue.cc
@@ -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.
diff --git a/gold/workqueue.h b/gold/workqueue.h
index a97d86d..5cce2d5 100644
--- a/gold/workqueue.h
+++ b/gold/workqueue.h
@@ -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();