Framework for relocation scanning. Implement simple static TLS
relocations.
This commit is contained in:
parent
af4658dc3d
commit
92e059d8dc
24 changed files with 2382 additions and 348 deletions
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
232
gold/configure
vendored
232
gold/configure
vendored
|
@ -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"
|
||||
|
|
|
@ -16,6 +16,8 @@ AC_PROG_INSTALL
|
|||
ZW_GNU_GETTEXT_SISTER_DIR
|
||||
AM_PO_SUBDIRS
|
||||
|
||||
AC_C_BIGENDIAN
|
||||
|
||||
AC_EXEEXT
|
||||
|
||||
AM_BINUTILS_WARNINGS
|
||||
|
|
100
gold/gold.cc
100
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)
|
||||
{ }
|
||||
|
||||
using namespace gold;
|
||||
void
|
||||
run(Workqueue*);
|
||||
|
||||
private:
|
||||
const General_options& options_;
|
||||
const Input_objects* input_objects_;
|
||||
Symbol_table* symtab_;
|
||||
Layout* layout_;
|
||||
};
|
||||
|
||||
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,
|
||||
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)
|
||||
{
|
||||
|
|
21
gold/gold.h
21
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*,
|
||||
|
|
699
gold/i386.cc
699
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
|
||||
{
|
||||
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);
|
||||
|
||||
};
|
||||
// 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
|
||||
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);
|
||||
};
|
||||
|
||||
// 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,59 +126,271 @@ const Target::Target_info Target_i386::i386_info =
|
|||
0x1000 // common_pagesize
|
||||
};
|
||||
|
||||
// Perform a relocation.
|
||||
// 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::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::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:
|
||||
{
|
||||
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);
|
||||
}
|
||||
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)
|
||||
{
|
||||
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);
|
||||
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\n"),
|
||||
fprintf(stderr, _("%s: %s: unsupported reloc %u against local symbol\n"),
|
||||
program_name, object->name().c_str(), r_type);
|
||||
// gold_exit(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Relocate section data.
|
||||
// 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::relocate_section(const Symbol_table* symtab,
|
||||
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,
|
||||
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)
|
||||
size_t local_symbol_count,
|
||||
const unsigned char* plocal_symbols,
|
||||
Symbol** global_symbols)
|
||||
{
|
||||
if (sh_type == elfcpp::SHT_RELA)
|
||||
{
|
||||
|
@ -123,14 +399,335 @@ Target_i386::relocate_section(const Symbol_table* symtab,
|
|||
gold_exit(false);
|
||||
}
|
||||
|
||||
gold::relocate_section<32, false, elfcpp::SHT_REL, Target_i386::Relocate>(
|
||||
gold::scan_relocs<32, false, elfcpp::SHT_REL, Target_i386::Scan>(
|
||||
options,
|
||||
symtab,
|
||||
object,
|
||||
prelocs,
|
||||
reloc_count,
|
||||
local_count,
|
||||
values,
|
||||
global_syms,
|
||||
local_symbol_count,
|
||||
plocal_symbols,
|
||||
global_symbols);
|
||||
}
|
||||
|
||||
// Perform a relocation.
|
||||
|
||||
inline void
|
||||
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:
|
||||
Relocate_functions<32, false>::rel32(view, value);
|
||||
break;
|
||||
|
||||
case elfcpp::R_386_PC32:
|
||||
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,
|
||||
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 Relocate_info<32, false>* relinfo,
|
||||
unsigned int sh_type,
|
||||
const unsigned char* prelocs,
|
||||
size_t reloc_count,
|
||||
unsigned char* view,
|
||||
elfcpp::Elf_types<32>::Elf_Addr address,
|
||||
off_t view_size)
|
||||
{
|
||||
assert(sh_type == elfcpp::SHT_REL);
|
||||
|
||||
gold::relocate_section<32, false, elfcpp::SHT_REL, Target_i386::Relocate>(
|
||||
relinfo,
|
||||
prelocs,
|
||||
reloc_count,
|
||||
view,
|
||||
address,
|
||||
view_size);
|
||||
|
|
|
@ -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,
|
||||
this->tls_segment_ = new Output_segment(elfcpp::PT_TLS,
|
||||
seg_flags);
|
||||
this->segment_list_.push_back(oseg);
|
||||
oseg->add_output_section(os, 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();
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
// 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,
|
||||
Task_token* this_blocker)
|
||||
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.
|
||||
|
|
|
@ -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.
|
||||
|
|
135
gold/object.h
135
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,22 +130,33 @@ 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); }
|
||||
|
||||
// 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.
|
||||
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); }
|
||||
|
||||
// Read the relocs.
|
||||
void
|
||||
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
|
||||
// *POOL; return the offset following the local symbols.
|
||||
|
@ -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.
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
@ -73,6 +79,10 @@ class General_options
|
|||
set_relocatable()
|
||||
{ this->is_relocatable_ = true; }
|
||||
|
||||
void
|
||||
set_shared()
|
||||
{ this->is_shared_ = true; }
|
||||
|
||||
void
|
||||
set_static()
|
||||
{ this->is_static_ = true; }
|
||||
|
@ -80,6 +90,7 @@ class General_options
|
|||
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
|
||||
|
|
|
@ -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;
|
||||
|
|
184
gold/po/gold.pot
184
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,14 +139,49 @@ msgstr ""
|
|||
msgid "pthread_cond_signal failed"
|
||||
msgstr ""
|
||||
|
||||
#: i386.cc:98
|
||||
#: i386.cc:223 i386.cc:319 i386.cc:466
|
||||
#, c-format
|
||||
msgid "%s: %s: unexpected reloc %u in object file\n"
|
||||
msgstr ""
|
||||
|
||||
#: 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:121
|
||||
#: i386.cc:528
|
||||
#, c-format
|
||||
msgid "%s: %s: unsupported RELA reloc section\n"
|
||||
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
|
||||
|
@ -159,103 +194,103 @@ msgstr ""
|
|||
msgid "%s: %s: bad e_shentsize field (%d != %d)\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:104
|
||||
#, c-format
|
||||
msgid "%s: %s: unsupported ELF machine number %d\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:196
|
||||
#, c-format
|
||||
msgid "%s: %s: invalid symbol table name index: %u\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:204
|
||||
#, c-format
|
||||
msgid "%s: %s: symbol table name section has wrong type: %u\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:256
|
||||
#, c-format
|
||||
msgid "%s: %s: section group %u link %u out of range\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:266
|
||||
#, c-format
|
||||
msgid "%s: %s: section group %u info %u out of range\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:277
|
||||
#, c-format
|
||||
msgid "%s; %s: symtab section %u link %u out of range\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:293
|
||||
#, c-format
|
||||
msgid "%s: %s: symbol %u name offset %u out of range\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:315
|
||||
#, c-format
|
||||
msgid "%s: %s: section %u in section group %u out of range"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:388
|
||||
#: object.cc:108 object.cc:418
|
||||
#, c-format
|
||||
msgid "%s: %s: bad section name offset for section %u: %lu\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:449
|
||||
#: object.cc:131
|
||||
#, c-format
|
||||
msgid "%s: %s: unsupported ELF machine number %d\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:226
|
||||
#, c-format
|
||||
msgid "%s: %s: invalid symbol table name index: %u\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:234
|
||||
#, c-format
|
||||
msgid "%s: %s: symbol table name section has wrong type: %u\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:286
|
||||
#, c-format
|
||||
msgid "%s: %s: section group %u link %u out of range\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:296
|
||||
#, c-format
|
||||
msgid "%s: %s: section group %u info %u out of range\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:307
|
||||
#, c-format
|
||||
msgid "%s; %s: symtab section %u link %u out of range\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:323
|
||||
#, c-format
|
||||
msgid "%s: %s: symbol %u name offset %u out of range\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:345
|
||||
#, c-format
|
||||
msgid "%s: %s: section %u in section group %u out of range"
|
||||
msgstr ""
|
||||
|
||||
#: 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 ""
|
||||
|
|
|
@ -76,7 +76,7 @@ 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_,
|
||||
workqueue->queue_front(new Add_symbols(this->symtab_, this->layout_,
|
||||
obj, sd,
|
||||
this->this_blocker_,
|
||||
this->next_blocker_));
|
||||
|
@ -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);
|
||||
|
|
307
gold/reloc.cc
307
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,
|
||||
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);
|
||||
|
@ -228,32 +457,72 @@ Sized_object<size, big_endian>::relocate_sections(const Symbol_table* symtab,
|
|||
// Instantiate the templates we need. We could use the configure
|
||||
// script to restrict this to only the ones for implemented targets.
|
||||
|
||||
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);
|
||||
|
||||
|
||||
|
|
506
gold/reloc.h
506
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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue