Framework for relocation scanning. Implement simple static TLS

relocations.
This commit is contained in:
Ian Lance Taylor 2006-10-20 20:40:49 +00:00
parent af4658dc3d
commit 92e059d8dc
24 changed files with 2382 additions and 348 deletions

View File

@ -16,7 +16,7 @@ namespace elfcpp
namespace internal
{
#ifdef WORDS_BIG_ENDIAN
#ifdef WORDS_BIGENDIAN
const bool host_big_endian = true;
#else
const bool host_big_endian = false;

View File

@ -300,7 +300,7 @@ Archive::include_member(Symbol_table* symtab, Layout* layout,
gold_exit(false);
}
Object* obj = make_elf_object((std::string(this->input_file_->name())
Object* obj = make_elf_object((std::string(this->input_file_->filename())
+ "(" + n + ")"),
this->input_file_, memoff, p, bytes);

View File

@ -69,3 +69,7 @@
/* Version number of package */
#undef VERSION
/* Define to 1 if your processor stores words with the most significant byte
first (like Motorola and SPARC, unlike Intel and VAX). */
#undef WORDS_BIGENDIAN

232
gold/configure vendored
View File

@ -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"

View File

@ -16,6 +16,8 @@ AC_PROG_INSTALL
ZW_GNU_GETTEXT_SISTER_DIR
AM_PO_SUBDIRS
AC_C_BIGENDIAN
AC_EXEEXT
AM_BINUTILS_WARNINGS

View File

@ -56,19 +56,43 @@ gold_unreachable()
abort();
}
} // End namespace gold.
// This class arranges to run the functions done in the middle of the
// link. It is just a closure.
namespace
class Middle_runner : public Task_function_runner
{
public:
Middle_runner(const General_options& options,
const Input_objects* input_objects,
Symbol_table* symtab,
Layout* layout)
: options_(options), input_objects_(input_objects), symtab_(symtab),
layout_(layout)
{ }
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,
this_blocker));
workqueue->queue(new Task_function(new Middle_runner(options,
input_objects,
symtab,
layout),
this_blocker));
}
} // end anonymous namespace.
// Queue up the middle set of tasks. These are the tasks which run
// after all the input objects have been found and all the symbols
// have been read, but before we lay out the output file.
namespace gold
void
queue_middle_tasks(const General_options& options,
const Input_objects* input_objects,
Symbol_table* symtab,
Layout* layout,
Workqueue* workqueue)
{
// Read the relocations of the input files. We do this to find
// which symbols are used by relocations which require a GOT and/or
// a PLT entry, or a COPY reloc. When we implement garbage
// collection we will do it here by reading the relocations in a
// breadth first search by references.
//
// We could also read the relocations during the first pass, and
// mark symbols at that time. That is how the old GNU linker works.
// Doing that is more complex, since we may later decide to discard
// some of the sections, and thus change our minds about the types
// of references made to the symbols.
Task_token* blocker = new Task_token();
Task_token* symtab_lock = new Task_token();
for (Input_objects::Object_list::const_iterator p = input_objects->begin();
p != input_objects->end();
++p)
{
// We can read and process the relocations in any order. But we
// only want one task to write to the symbol table at a time.
// So we queue up a task for each object to read the
// relocations. That task will in turn queue a task to wait
// until it can write to the symbol table.
blocker->add_blocker();
workqueue->queue(new Read_relocs(options, symtab, *p, symtab_lock,
blocker));
}
// Allocate common symbols. This requires write access to the
// symbol table, but is independent of the relocation processing.
// blocker->add_blocker();
// workqueue->queue(new Allocate_commons_task(options, symtab, layout,
// symtab_lock, blocker));
// When all those tasks are complete, we can start laying out the
// output file.
workqueue->queue(new Task_function(new Layout_task_runner(options,
input_objects,
symtab,
layout),
blocker));
}
// Queue up the final set of tasks. This is called at the end of
// Layout_task.
@ -122,8 +197,8 @@ queue_final_tasks(const General_options& options,
++p)
{
final_blocker->add_blocker();
workqueue->queue(new Relocate_task(options, symtab, layout->sympool(),
*p, of, final_blocker));
workqueue->queue(new Relocate_task(options, symtab, layout, *p, of,
final_blocker));
}
// Queue a task to write out the symbol table.
@ -138,11 +213,14 @@ queue_final_tasks(const General_options& options,
// Queue a task to close the output file. This will be blocked by
// FINAL_BLOCKER.
workqueue->queue(new Close_task(of, final_blocker));
workqueue->queue(new Task_function(new Close_task_runner(of),
final_blocker));
}
} // End namespace gold.
using namespace gold;
int
main(int argc, char** argv)
{

View File

@ -137,6 +137,8 @@ namespace gold
{
class General_options;
class Input_argument_list;
class Dirsearch;
class Input_objects;
class Symbol_table;
class Layout;
@ -166,6 +168,25 @@ gold_nomem() ATTRIBUTE_NORETURN;
extern void
gold_unreachable() ATTRIBUTE_NORETURN;
// Queue up the first set of tasks.
extern void
queue_initial_tasks(const General_options&,
const Dirsearch&,
const Input_argument_list&,
Workqueue*,
Input_objects*,
Symbol_table*,
Layout*);
// Queue up the middle set of tasks.
extern void
queue_middle_tasks(const General_options&,
const Input_objects*,
Symbol_table*,
Layout*,
Workqueue*);
// Queue up the final set of tasks.
extern void
queue_final_tasks(const General_options&,
const Input_objects*,

View File

@ -2,8 +2,11 @@
#include "gold.h"
#include "elfcpp.h"
#include "reloc.h"
#include "i386.h"
#include "object.h"
#include "layout.h"
#include "output.h"
#include "target.h"
#include "target-reloc.h"
#include "target-select.h"
@ -22,31 +25,92 @@ class Target_i386 : public Sized_target<32, false>
: Sized_target<32, false>(&i386_info)
{ }
// Scan the relocations to look for symbol adjustments.
void
relocate_section(const Symbol_table* symtab,
Sized_object<32, false>*,
unsigned int,
const unsigned char*,
size_t,
unsigned int,
const elfcpp::Elf_types<32>::Elf_Addr*,
Symbol**,
unsigned char*,
elfcpp::Elf_types<32>::Elf_Addr,
off_t);
scan_relocs(const General_options& options,
Symbol_table* symtab,
Sized_object<32, false>* object,
unsigned int sh_type,
const unsigned char* prelocs,
size_t reloc_count,
size_t local_symbol_count,
const unsigned char* plocal_symbols,
Symbol** global_symbols);
// The class which implements relocation.
struct Relocate
{
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:
{
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_PC16:
case elfcpp::R_386_PC8:
break;
default:
fprintf(stderr, _("%s: %s: unsupported reloc %u\n"),
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);
gold_exit(false);
break;
case elfcpp::R_386_TLS_IE:
case elfcpp::R_386_TLS_GOTIE:
case elfcpp::R_386_TLS_LE:
case elfcpp::R_386_TLS_GD:
case elfcpp::R_386_TLS_LDM:
case elfcpp::R_386_TLS_LDO_32:
case elfcpp::R_386_TLS_IE_32:
case elfcpp::R_386_TLS_LE_32:
case elfcpp::R_386_TLS_GOTDESC:
case elfcpp::R_386_TLS_DESC_CALL:
r_type = Target_i386::optimize_tls_reloc(&options, true, r_type);
switch (r_type)
{
case elfcpp::R_386_TLS_LE:
case elfcpp::R_386_TLS_LE_32:
// FIXME: If generating a shared object, we need to copy
// this relocation into the object.
break;
case elfcpp::R_386_TLS_IE:
case elfcpp::R_386_TLS_GOTIE:
case elfcpp::R_386_TLS_GD:
case elfcpp::R_386_TLS_LDM:
case elfcpp::R_386_TLS_LDO_32:
case elfcpp::R_386_TLS_IE_32:
case elfcpp::R_386_TLS_GOTDESC:
case elfcpp::R_386_TLS_DESC_CALL:
fprintf(stderr,
_("%s: %s: unsupported reloc %u against local symbol\n"),
program_name, object->name().c_str(), r_type);
break;
}
break;
case elfcpp::R_386_GOT32:
case elfcpp::R_386_PLT32:
case elfcpp::R_386_GOTOFF:
case elfcpp::R_386_GOTPC:
case elfcpp::R_386_32PLT:
case elfcpp::R_386_TLS_GD_32:
case elfcpp::R_386_TLS_GD_PUSH:
case elfcpp::R_386_TLS_GD_CALL:
case elfcpp::R_386_TLS_GD_POP:
case elfcpp::R_386_TLS_LDM_32:
case elfcpp::R_386_TLS_LDM_PUSH:
case elfcpp::R_386_TLS_LDM_CALL:
case elfcpp::R_386_TLS_LDM_POP:
case elfcpp::R_386_USED_BY_INTEL_200:
default:
fprintf(stderr, _("%s: %s: unsupported reloc %u against local symbol\n"),
program_name, object->name().c_str(), r_type);
break;
}
}
// 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,
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)
Target_i386::scan_relocs(const General_options& options,
Symbol_table* symtab,
Sized_object<32, false>* object,
unsigned int sh_type,
const unsigned char* prelocs,
size_t reloc_count,
size_t local_symbol_count,
const unsigned char* plocal_symbols,
Symbol** global_symbols)
{
if (sh_type == elfcpp::SHT_RELA)
{
@ -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);

View File

@ -14,36 +14,13 @@
namespace gold
{
// Layout_task methods.
Layout_task::~Layout_task()
{
}
// This task can be run when it is unblocked.
Task::Is_runnable_type
Layout_task::is_runnable(Workqueue*)
{
if (this->this_blocker_->is_blocked())
return IS_BLOCKED;
return IS_RUNNABLE;
}
// We don't need to hold any locks for the duration of this task. In
// fact this task will be the only one running.
Task_locker*
Layout_task::locks(Workqueue*)
{
return NULL;
}
// Layout_task_runner methods.
// Lay out the sections. This is called after all the input objects
// have been read.
void
Layout_task::run(Workqueue* workqueue)
Layout_task_runner::run(Workqueue* workqueue)
{
off_t file_size = this->layout_->finalize(this->input_objects_,
this->symtab_);
@ -63,7 +40,7 @@ Layout_task::run(Workqueue* workqueue)
Layout::Layout(const General_options& options)
: options_(options), last_shndx_(0), namepool_(), sympool_(), signatures_(),
section_name_map_(), segment_list_(), section_list_(),
special_output_list_()
special_output_list_(), tls_segment_(NULL)
{
// Make space for more than enough segments for a typical file.
// This is just for efficiency--it's OK if we wind up needing more.
@ -256,30 +233,16 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
}
// If we see a loadable SHF_TLS section, we create a PT_TLS
// segment.
// segment. There can only be one such segment.
if ((flags & elfcpp::SHF_TLS) != 0)
{
// See if we already have an equivalent PT_TLS segment.
for (p = this->segment_list_.begin();
p != segment_list_.end();
++p)
if (this->tls_segment_ == NULL)
{
if ((*p)->type() == elfcpp::PT_TLS
&& (((*p)->flags() & elfcpp::PF_W)
== (seg_flags & elfcpp::PF_W)))
{
(*p)->add_output_section(os, seg_flags);
break;
}
}
if (p == this->segment_list_.end())
{
Output_segment* oseg = new Output_segment(elfcpp::PT_TLS,
seg_flags);
this->segment_list_.push_back(oseg);
oseg->add_output_section(os, seg_flags);
this->tls_segment_ = new Output_segment(elfcpp::PT_TLS,
seg_flags);
this->segment_list_.push_back(this->tls_segment_);
}
this->tls_segment_->add_output_section(os, seg_flags);
}
}
@ -440,6 +403,14 @@ Layout::segment_precedes(const Output_segment* seg1,
if (type2 == elfcpp::PT_LOAD && type1 != elfcpp::PT_LOAD)
return false;
// We put the PT_TLS segment last, because that is where the dynamic
// linker expects to find it (this is just for efficiency; other
// positions would also work correctly).
if (type1 == elfcpp::PT_TLS && type2 != elfcpp::PT_TLS)
return false;
if (type2 == elfcpp::PT_TLS && type1 != elfcpp::PT_TLS)
return true;
const elfcpp::Elf_Word flags1 = seg1->flags();
const elfcpp::Elf_Word flags2 = seg2->flags();
@ -865,30 +836,12 @@ Write_symbols_task::run(Workqueue*)
this->symtab_->write_globals(this->target_, this->sympool_, this->of_);
}
// Close_task methods.
// We can't run until FINAL_BLOCKER is unblocked.
Task::Is_runnable_type
Close_task::is_runnable(Workqueue*)
{
if (this->final_blocker_->is_blocked())
return IS_BLOCKED;
return IS_RUNNABLE;
}
// We don't lock anything.
Task_locker*
Close_task::locks(Workqueue*)
{
return NULL;
}
// Close_task_runner methods.
// Run the task--close the file.
void
Close_task::run(Workqueue*)
Close_task_runner::run(Workqueue*)
{
this->of_->close();
}

View File

@ -25,46 +25,35 @@ class Output_segment;
class Output_data;
class Target;
// This Task handles mapping the input sections to output sections and
// laying them out in memory.
// This task function handles mapping the input sections to output
// sections and laying them out in memory.
class Layout_task : public Task
class Layout_task_runner : public Task_function_runner
{
public:
// OPTIONS is the command line options, INPUT_OBJECTS is the list of
// input objects, THIS_BLOCKER is a token which blocks this task
// from executing until all the input symbols have been read.
Layout_task(const General_options& options,
const Input_objects* input_objects,
Symbol_table* symtab,
Layout* layout,
Task_token* this_blocker)
// input objects, SYMTAB is the symbol table, LAYOUT is the layout
// object.
Layout_task_runner(const General_options& options,
const Input_objects* input_objects,
Symbol_table* symtab,
Layout* layout)
: options_(options), input_objects_(input_objects), symtab_(symtab),
layout_(layout), this_blocker_(this_blocker)
layout_(layout)
{ }
~Layout_task();
// The standard Task methods.
Is_runnable_type
is_runnable(Workqueue*);
Task_locker*
locks(Workqueue*);
// Run the operation.
void
run(Workqueue*);
private:
Layout_task(const Layout_task&);
Layout_task& operator=(const Layout_task&);
Layout_task_runner(const Layout_task_runner&);
Layout_task_runner& operator=(const Layout_task_runner&);
const General_options& options_;
const Input_objects* input_objects_;
Symbol_table* symtab_;
Layout* layout_;
Task_token* this_blocker_;
};
// This class handles the details of laying out input sections.
@ -105,6 +94,11 @@ class Layout
off_t
finalize(const Input_objects*, Symbol_table*);
// Return the TLS segment.
Output_segment*
tls_segment() const
{ return this->tls_segment_; }
// Write out data not associated with an input file or the symbol
// table.
void
@ -234,6 +228,8 @@ class Layout
// The list of sections which require special output because they
// are not comprised of input sections.
Data_list special_output_list_;
// A pointer to the PT_TLS segment if there is one.
Output_segment* tls_segment_;
};
// This task handles writing out data which is not part of a section
@ -295,29 +291,21 @@ class Write_symbols_task : public Task
Task_token* final_blocker_;
};
// This task handles closing the file.
// This task function handles closing the file.
class Close_task : public Task
class Close_task_runner : public Task_function_runner
{
public:
Close_task(Output_file* of, Task_token* final_blocker)
: of_(of), final_blocker_(final_blocker)
Close_task_runner(Output_file* of)
: of_(of)
{ }
// The standard task methods.
Is_runnable_type
is_runnable(Workqueue*);
Task_locker*
locks(Workqueue*);
// Run the operation.
void
run(Workqueue*);
private:
Output_file* of_;
Task_token* final_blocker_;
};
} // End namespace gold.

View File

@ -87,6 +87,33 @@ Sized_object<size, big_endian>::section_header(unsigned int shnum)
return this->get_view(symtabshdroff, This::shdr_size);
}
// Return the name of section SHNUM.
template<int size, bool big_endian>
std::string
Sized_object<size, big_endian>::do_section_name(unsigned int shnum)
{
Task_lock_obj<Object> tl(*this);
// Read the section names.
typename This::Shdr shdrnames(this->section_header(this->shstrndx_));
const unsigned char* pnamesu = this->get_view(shdrnames.get_sh_offset(),
shdrnames.get_sh_size());
const char* pnames = reinterpret_cast<const char*>(pnamesu);
typename This::Shdr shdr(this->section_header(shnum));
if (shdr.get_sh_name() >= shdrnames.get_sh_size())
{
fprintf(stderr,
_("%s: %s: bad section name offset for section %u: %lu\n"),
program_name, this->name().c_str(), shnum,
static_cast<unsigned long>(shdr.get_sh_name()));
gold_exit(false);
}
return std::string(pnames + shdr.get_sh_name());
}
// Set up an object file bsaed on the file header. This sets up the
// target and reads the section information.
@ -182,7 +209,9 @@ Sized_object<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
// We only need the external symbols.
const int sym_size = This::sym_size;
off_t locsize = symtabshdr.get_sh_info() * sym_size;
const unsigned int loccount = symtabshdr.get_sh_info();
this->local_symbol_count_ = loccount;
off_t locsize = loccount * sym_size;
off_t extoff = symtabshdr.get_sh_offset() + locsize;
off_t extsize = symtabshdr.get_sh_size() - locsize;
@ -190,14 +219,15 @@ Sized_object<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
File_view* fvsymtab = this->get_lasting_view(extoff, extsize);
// Read the section header for the symbol names.
unsigned int shnum = this->shnum();
unsigned int strtab_shnum = symtabshdr.get_sh_link();
if (strtab_shnum == 0 || strtab_shnum >= this->shnum())
if (strtab_shnum == 0 || strtab_shnum >= shnum)
{
fprintf(stderr, _("%s: %s: invalid symbol table name index: %u\n"),
program_name, this->name().c_str(), strtab_shnum);
gold_exit(false);
}
typename This::Shdr strtabshdr(this->section_header(strtab_shnum));
typename This::Shdr strtabshdr(pshdrs + strtab_shnum * This::shdr_size);
if (strtabshdr.get_sh_type() != elfcpp::SHT_STRTAB)
{
fprintf(stderr,
@ -493,14 +523,13 @@ Sized_object<size, big_endian>::do_finalize_local_symbols(off_t off,
assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
// Read the local symbols.
unsigned int loccount = symtabshdr.get_sh_info();
const int sym_size = This::sym_size;
const unsigned int loccount = this->local_symbol_count_;
assert(loccount == symtabshdr.get_sh_info());
off_t locsize = loccount * sym_size;
const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(),
locsize);
this->local_symbol_count_ = loccount;
this->values_ = new typename elfcpp::Elf_types<size>::Elf_Addr[loccount];
// Read the section header for the symbol names.
@ -587,12 +616,12 @@ Sized_object<size, big_endian>::write_local_symbols(Output_file* of,
// Read the symbol table section header.
typename This::Shdr symtabshdr(this->section_header(this->symtab_shnum_));
assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
unsigned int local_symbol_count = this->local_symbol_count_;
assert(local_symbol_count == symtabshdr.get_sh_info());
const unsigned int loccount = this->local_symbol_count_;
assert(loccount == symtabshdr.get_sh_info());
// Read the local symbols.
const int sym_size = This::sym_size;
off_t locsize = local_symbol_count * sym_size;
off_t locsize = loccount * sym_size;
const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(),
locsize);
@ -615,7 +644,7 @@ Sized_object<size, big_endian>::write_local_symbols(Output_file* of,
psyms += sym_size;
unsigned char* ov = oview;
for (unsigned int i = 1; i < local_symbol_count; ++i, psyms += sym_size)
for (unsigned int i = 1; i < loccount; ++i, psyms += sym_size)
{
elfcpp::Sym<size, big_endian> isym(psyms);
elfcpp::Sym_write<size, big_endian> osym(ov);
@ -665,6 +694,31 @@ Input_objects::add_object(Object* obj)
this->any_dynamic_ = true;
}
// Relocate_info methods.
// Return a string describing the location of a relocation. This is
// only used in error messages.
template<int size, bool big_endian>
std::string
Relocate_info<size, big_endian>::location(size_t relnum, off_t) const
{
std::string ret(this->object->name());
ret += ": reloc ";
char buf[100];
snprintf(buf, sizeof buf, "%zu", relnum);
ret += buf;
ret += " in reloc section ";
snprintf(buf, sizeof buf, "%u", this->reloc_shndx);
ret += buf;
ret += " (" + this->object->section_name(this->reloc_shndx);
ret += ") for section ";
snprintf(buf, sizeof buf, "%u", this->data_shndx);
ret += buf;
ret += " (" + this->object->section_name(this->data_shndx) + ")";
return ret;
}
} // End namespace gold.
namespace
@ -830,4 +884,16 @@ class Sized_object<64, false>;
template
class Sized_object<64, true>;
template
struct Relocate_info<32, false>;
template
struct Relocate_info<32, true>;
template
struct Relocate_info<64, false>;
template
struct Relocate_info<64, true>;
} // End namespace gold.

View File

@ -4,6 +4,8 @@
#define GOLD_OBJECT_H
#include <cassert>
#include <list>
#include <string>
#include <vector>
#include "elfcpp.h"
@ -14,6 +16,7 @@
namespace gold
{
class General_options;
class Stringpool;
class Layout;
class Output_section;
@ -39,6 +42,35 @@ struct Read_symbols_data
off_t symbol_names_size;
};
// Data about a single relocation section. This is read in
// read_relocs and processed in scan_relocs.
struct Section_relocs
{
// Index of reloc section.
unsigned int reloc_shndx;
// Index of section that relocs apply to.
unsigned int data_shndx;
// Contents of reloc section.
File_view* contents;
// Reloc section type.
unsigned int sh_type;
// Number of reloc entries.
size_t reloc_count;
};
// Relocations in an object file. This is read in read_relocs and
// processed in scan_relocs.
struct Read_relocs_data
{
typedef std::vector<Section_relocs> Relocs_list;
// The relocations.
Relocs_list relocs;
// The local symbols.
File_view* local_symbols;
};
// Object is an interface which represents either a 32-bit or a 64-bit
// input object. This can be a regular object file (ET_REL) or a
// shared object (ET_DYN). The actual instantiations are
@ -98,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.

View File

@ -217,6 +217,8 @@ options::Command_line_options::options[] =
&General_options::set_output_file_name),
GENERAL_NOARG('r', NULL, N_("Generate relocatable output"), NULL,
ONE_DASH, &General_options::set_relocatable),
GENERAL_NOARG('\0', "shared", N_("Generate shared library"),
NULL, ONE_DASH, &General_options::set_shared),
GENERAL_NOARG('\0', "static", N_("Do not link against shared libraries"),
NULL, ONE_DASH, &General_options::set_static),
SPECIAL('\0', "help", N_("Report usage information"), NULL,
@ -232,6 +234,7 @@ General_options::General_options()
: search_path_(),
output_file_name_("a.out"),
is_relocatable_(false),
is_shared_(false),
is_static_(false)
{
}

View File

@ -14,6 +14,7 @@
#include <list>
#include <string>
#include <vector>
namespace gold
{
@ -52,6 +53,11 @@ class General_options
is_relocatable() const
{ return this->is_relocatable_; }
// --shared: Whether generating a shared object.
bool
is_shared() const
{ return this->is_shared_; }
// --static: Whether doing a static link.
bool
is_static() const
@ -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

View File

@ -443,6 +443,11 @@ class Output_segment
flags() const
{ return this->flags_; }
// Return the memory size.
uint64_t
memsz() const
{ return this->memsz_; }
// Return the maximum alignment of the Output_data.
uint64_t
max_data_align() const;

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2006-10-10 11:40-0700\n"
"POT-Creation-Date: 2006-10-20 13:39-0700\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -91,7 +91,7 @@ msgstr ""
msgid "%s: cannot open %s: %s\n"
msgstr ""
#: gold.cc:76
#: gold.cc:100
msgid "no input files"
msgstr ""
@ -139,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 ""

View File

@ -76,10 +76,10 @@ Read_symbols::run(Workqueue* workqueue)
Read_symbols_data* sd = new Read_symbols_data;
obj->read_symbols(sd);
workqueue->queue(new Add_symbols(this->symtab_, this->layout_,
obj, sd,
this->this_blocker_,
this->next_blocker_));
workqueue->queue_front(new Add_symbols(this->symtab_, this->layout_,
obj, sd,
this->this_blocker_,
this->next_blocker_));
// Opening the file locked it, so now we need to unlock it.
input_file->file().unlock();
@ -105,8 +105,7 @@ Read_symbols::run(Workqueue* workqueue)
}
}
// Here we have to handle archives and any other input file
// types we need.
// Here we have to handle any other input file types we need.
fprintf(stderr, _("%s: %s: not an object or archive\n"),
program_name, input_file->file().filename().c_str());
gold_exit(false);

View File

@ -10,6 +10,86 @@
namespace gold
{
// Read_relocs methods.
// These tasks just read the relocation information from the file.
// After reading it, the start another task to process the
// information. These tasks requires access to the file.
Task::Is_runnable_type
Read_relocs::is_runnable(Workqueue*)
{
return this->object_->is_locked() ? IS_LOCKED : IS_RUNNABLE;
}
// Lock the file.
Task_locker*
Read_relocs::locks(Workqueue*)
{
return new Task_locker_obj<Object>(*this->object_);
}
// Read the relocations and then start a Scan_relocs_task.
void
Read_relocs::run(Workqueue* workqueue)
{
Read_relocs_data *rd = new Read_relocs_data;
this->object_->read_relocs(rd);
workqueue->queue_front(new Scan_relocs(this->options_, this->symtab_,
this->object_, rd, this->symtab_lock_,
this->blocker_));
}
// Scan_relocs methods.
// These tasks scan the relocations read by Read_relocs and mark up
// the symbol table to indicate which relocations are required. We
// use a lock on the symbol table to keep them from interfering with
// each other.
Task::Is_runnable_type
Scan_relocs::is_runnable(Workqueue*)
{
return this->symtab_lock_->is_writable() ? IS_RUNNABLE : IS_LOCKED;
}
// Return the locks we hold: one on the file, one on the symbol table
// and one blocker.
class Scan_relocs::Scan_relocs_locker : public Task_locker
{
public:
Scan_relocs_locker(Object* object, Task_token& symtab_lock, Task* task,
Task_token& blocker, Workqueue* workqueue)
: objlock_(*object), symtab_locker_(symtab_lock, task),
blocker_(blocker, workqueue)
{ }
private:
Task_locker_obj<Object> objlock_;
Task_locker_write symtab_locker_;
Task_locker_block blocker_;
};
Task_locker*
Scan_relocs::locks(Workqueue* workqueue)
{
return new Scan_relocs_locker(this->object_, *this->symtab_lock_, this,
*this->blocker_, workqueue);
}
// Scan the relocs.
void
Scan_relocs::run(Workqueue*)
{
this->object_->scan_relocs(this->options_, this->symtab_, this->rd_);
delete this->rd_;
this->rd_ = NULL;
}
// Relocate_task methods.
// These tasks are always runnable.
@ -48,17 +128,154 @@ Relocate_task::locks(Workqueue* workqueue)
void
Relocate_task::run(Workqueue*)
{
this->object_->relocate(this->options_, this->symtab_, this->sympool_,
this->object_->relocate(this->options_, this->symtab_, this->layout_,
this->of_);
}
// Read the relocs and local symbols from the object file and store
// the information in RD.
template<int size, bool big_endian>
void
Sized_object<size, big_endian>::do_read_relocs(Read_relocs_data* rd)
{
rd->relocs.clear();
unsigned int shnum = this->shnum();
if (shnum == 0)
return;
rd->relocs.reserve(shnum / 2);
const unsigned char *pshdrs = this->get_view(this->shoff_,
shnum * This::shdr_size);
// Skip the first, dummy, section.
const unsigned char *ps = pshdrs + This::shdr_size;
for (unsigned int i = 1; i < shnum; ++i, ps += This::shdr_size)
{
typename This::Shdr shdr(ps);
unsigned int sh_type = shdr.get_sh_type();
if (sh_type != elfcpp::SHT_REL && sh_type != elfcpp::SHT_RELA)
continue;
unsigned int shndx = shdr.get_sh_info();
if (shndx >= shnum)
{
fprintf(stderr, _("%s: %s: relocation section %u has bad info %u\n"),
program_name, this->name().c_str(), i, shndx);
gold_exit(false);
}
if (!this->is_section_included(shndx))
continue;
if (shdr.get_sh_link() != this->symtab_shnum_)
{
fprintf(stderr,
_("%s: %s: relocation section %u uses unexpected "
"symbol table %u\n"),
program_name, this->name().c_str(), i, shdr.get_sh_link());
gold_exit(false);
}
off_t sh_size = shdr.get_sh_size();
unsigned int reloc_size;
if (sh_type == elfcpp::SHT_REL)
reloc_size = elfcpp::Elf_sizes<size>::rel_size;
else
reloc_size = elfcpp::Elf_sizes<size>::rela_size;
if (reloc_size != shdr.get_sh_entsize())
{
fprintf(stderr,
_("%s: %s: unexpected entsize for reloc section %u: "
"%lu != %u"),
program_name, this->name().c_str(), i,
static_cast<unsigned long>(shdr.get_sh_entsize()),
reloc_size);
gold_exit(false);
}
size_t reloc_count = sh_size / reloc_size;
if (reloc_count * reloc_size != sh_size)
{
fprintf(stderr, _("%s: %s: reloc section %u size %lu uneven"),
program_name, this->name().c_str(), i,
static_cast<unsigned long>(sh_size));
gold_exit(false);
}
rd->relocs.push_back(Section_relocs());
Section_relocs& sr(rd->relocs.back());
sr.reloc_shndx = i;
sr.data_shndx = shndx;
sr.contents = this->get_lasting_view(shdr.get_sh_offset(), sh_size);
sr.sh_type = sh_type;
sr.reloc_count = reloc_count;
}
// Read the local symbols.
if (this->symtab_shnum_ == 0 || this->local_symbol_count_ == 0)
rd->local_symbols = NULL;
else
{
typename This::Shdr symtabshdr(pshdrs
+ this->symtab_shnum_ * This::shdr_size);
assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
const int sym_size = This::sym_size;
const unsigned int loccount = this->local_symbol_count_;
assert(loccount == symtabshdr.get_sh_info());
off_t locsize = loccount * sym_size;
rd->local_symbols = this->get_lasting_view(symtabshdr.get_sh_offset(),
locsize);
}
}
// Scan the relocs and adjust the symbol table. This looks for
// relocations which require GOT/PLT/COPY relocations.
template<int size, bool big_endian>
void
Sized_object<size, big_endian>::do_scan_relocs(const General_options& options,
Symbol_table* symtab,
Read_relocs_data* rd)
{
Sized_target<size, big_endian>* target = this->sized_target();
const unsigned char* local_symbols;
if (rd->local_symbols == NULL)
local_symbols = NULL;
else
local_symbols = rd->local_symbols->data();
for (Read_relocs_data::Relocs_list::iterator p = rd->relocs.begin();
p != rd->relocs.end();
++p)
{
target->scan_relocs(options, symtab, this, p->sh_type,
p->contents->data(), p->reloc_count,
this->local_symbol_count_,
local_symbols,
this->symbols_);
delete p->contents;
p->contents = NULL;
}
if (rd->local_symbols != NULL)
{
delete rd->local_symbols;
rd->local_symbols = NULL;
}
}
// Relocate the input sections and write out the local symbols.
template<int size, bool big_endian>
void
Sized_object<size, big_endian>::do_relocate(const General_options&,
Sized_object<size, big_endian>::do_relocate(const General_options& options,
const Symbol_table* symtab,
const Stringpool* sympool,
const Layout* layout,
Output_file* of)
{
unsigned int shnum = this->shnum();
@ -78,7 +295,7 @@ Sized_object<size, big_endian>::do_relocate(const General_options&,
// Apply relocations.
this->relocate_sections(symtab, pshdrs, &views);
this->relocate_sections(options, symtab, layout, pshdrs, &views);
// Write out the accumulated views.
for (unsigned int i = 1; i < shnum; ++i)
@ -89,7 +306,7 @@ Sized_object<size, big_endian>::do_relocate(const General_options&,
}
// Write out the local symbols.
this->write_local_symbols(of, sympool);
this->write_local_symbols(of, layout->sympool());
}
// Write section data to the output file. PSHDRS points to the
@ -127,9 +344,8 @@ Sized_object<size, big_endian>::write_sections(const unsigned char* pshdrs,
off_t sh_size = shdr.get_sh_size();
unsigned char* view = of->get_output_view(start, sh_size);
this->input_file()->file().read(shdr.get_sh_offset(),
sh_size,
view);
this->read(shdr.get_sh_offset(), sh_size, view);
pvs->view = view;
pvs->address = os->address() + map_sections[i].offset;
pvs->offset = start;
@ -142,14 +358,25 @@ Sized_object<size, big_endian>::write_sections(const unsigned char* pshdrs,
template<int size, bool big_endian>
void
Sized_object<size, big_endian>::relocate_sections(const Symbol_table* symtab,
const unsigned char* pshdrs,
Views* pviews)
Sized_object<size, big_endian>::relocate_sections(
const General_options& options,
const Symbol_table* symtab,
const Layout* layout,
const unsigned char* pshdrs,
Views* pviews)
{
unsigned int shnum = this->shnum();
std::vector<Map_to_output>& map_sections(this->map_to_output());
Sized_target<size, big_endian>* target = this->sized_target();
Relocate_info<size, big_endian> relinfo;
relinfo.options = &options;
relinfo.symtab = symtab;
relinfo.layout = layout;
relinfo.object = this;
relinfo.local_symbol_count = this->local_symbol_count_;
relinfo.values = this->values_;
relinfo.symbols = this->symbols_;
const unsigned char* p = pshdrs + This::shdr_size;
for (unsigned int i = 1; i < shnum; ++i, p += This::shdr_size)
{
@ -167,7 +394,7 @@ Sized_object<size, big_endian>::relocate_sections(const Symbol_table* symtab,
gold_exit(false);
}
if (map_sections[index].output_section == NULL)
if (!this->is_section_included(index))
{
// This relocation section is against a section which we
// discarded.
@ -215,10 +442,12 @@ Sized_object<size, big_endian>::relocate_sections(const Symbol_table* symtab,
gold_exit(false);
}
target->relocate_section(symtab, this, sh_type, prelocs, reloc_count,
this->local_symbol_count_,
this->values_,
this->symbols_,
relinfo.reloc_shndx = i;
relinfo.data_shndx = index;
target->relocate_section(&relinfo,
sh_type,
prelocs,
reloc_count,
(*pviews)[index].view,
(*pviews)[index].address,
(*pviews)[index].view_size);
@ -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);

View File

@ -3,18 +3,98 @@
#ifndef GOLD_RELOC_H
#define GOLD_RELOC_H
#include <byteswap.h>
#include "workqueue.h"
namespace gold
{
class Object;
class Read_relocs_data;
class Stringpool;
// A class to read the relocations for an object file, and then queue
// up a task to see if they require any GOT/PLT/COPY relocations in
// the symbol table.
class Read_relocs : public Task
{
public:
// SYMTAB_LOCK is used to lock the symbol table. BLOCKER should be
// unblocked when the Scan_relocs task completes.
Read_relocs(const General_options& options, Symbol_table* symtab,
Object* object, Task_token* symtab_lock,
Task_token* blocker)
: options_(options), symtab_(symtab), object_(object),
symtab_lock_(symtab_lock), blocker_(blocker)
{ }
// The standard Task methods.
Is_runnable_type
is_runnable(Workqueue*);
Task_locker*
locks(Workqueue*);
void
run(Workqueue*);
private:
const General_options& options_;
Symbol_table* symtab_;
Object* object_;
Task_token* symtab_lock_;
Task_token* blocker_;
};
// Scan the relocations for an object to see if they require any
// GOT/PLT/COPY relocations.
class Scan_relocs : public Task
{
public:
// SYMTAB_LOCK is used to lock the symbol table. BLOCKER should be
// unblocked when the task completes.
Scan_relocs(const General_options& options, Symbol_table* symtab,
Object* object, Read_relocs_data* rd, Task_token* symtab_lock,
Task_token* blocker)
: options_(options), symtab_(symtab), object_(object), rd_(rd),
symtab_lock_(symtab_lock), blocker_(blocker)
{ }
// The standard Task methods.
Is_runnable_type
is_runnable(Workqueue*);
Task_locker*
locks(Workqueue*);
void
run(Workqueue*);
private:
class Scan_relocs_locker;
const General_options& options_;
Symbol_table* symtab_;
Object* object_;
Read_relocs_data* rd_;
Task_token* symtab_lock_;
Task_token* blocker_;
};
// A class to perform all the relocations for an object file.
class Relocate_task : public Task
{
public:
Relocate_task(const General_options& options, const Symbol_table* symtab,
const Stringpool* sympool, Object* object, Output_file* of,
const Layout* layout, Object* object, Output_file* of,
Task_token* final_blocker)
: options_(options), symtab_(symtab), sympool_(sympool), object_(object),
: options_(options), symtab_(symtab), layout_(layout), object_(object),
of_(of), final_blocker_(final_blocker)
{ }
@ -34,12 +114,432 @@ class Relocate_task : public Task
const General_options& options_;
const Symbol_table* symtab_;
const Stringpool* sympool_;
const Layout* layout_;
Object* object_;
Output_file* of_;
Task_token* final_blocker_;
};
// Integer swapping routines used by relocation functions. FIXME:
// Maybe these should be more general, and/or shared with elfcpp.
// Endian simply indicates whether the host is big endian or not,
// based on the results of the configure script.
struct Endian
{
public:
// Used for template specializations.
#ifdef WORDS_BIGENDIAN
static const bool host_big_endian = true;
#else
static const bool host_big_endian = false;
#endif
};
// Valtype_base is a template based on size (8, 16, 32, 64) which
// defines a typedef Valtype for the unsigned integer of the specified
// size.
template<int size>
struct Valtype_base;
template<>
struct Valtype_base<8>
{
typedef unsigned char Valtype;
};
template<>
struct Valtype_base<16>
{
typedef uint16_t Valtype;
};
template<>
struct Valtype_base<32>
{
typedef uint32_t Valtype;
};
template<>
struct Valtype_base<64>
{
typedef uint64_t Valtype;
};
// Convert_host is a template based on size and on whether the host
// and target have the same endianness. It defines the type Valtype,
// and defines a function convert_host which takes an argument of type
// Valtype and swaps it if the host and target have different
// endianness.
template<int size, bool same_endian>
struct Convert_host;
template<int size>
struct Convert_host<size, true>
{
typedef typename Valtype_base<size>::Valtype Valtype;
static inline Valtype
convert_host(Valtype v)
{ return v; }
};
template<>
struct Convert_host<8, false>
{
typedef Valtype_base<8>::Valtype Valtype;
static inline Valtype
convert_host(Valtype v)
{ return v; }
};
template<>
struct Convert_host<16, false>
{
typedef Valtype_base<16>::Valtype Valtype;
static inline Valtype
convert_host(Valtype v)
{ return bswap_16(v); }
};
template<>
struct Convert_host<32, false>
{
typedef Valtype_base<32>::Valtype Valtype;
static inline Valtype
convert_host(Valtype v)
{ return bswap_32(v); }
};
template<>
struct Convert_host<64, false>
{
typedef Valtype_base<64>::Valtype Valtype;
static inline Valtype
convert_host(Valtype v)
{ return bswap_64(v); }
};
// Convert is a template based on size and on whether we have a big
// endian target. It defines Valtype and convert_host like
// Convert_host. That is, it is just like Convert_host except in the
// meaning of the second template parameter.
template<int size, bool big_endian>
struct Convert
{
typedef typename Valtype_base<size>::Valtype Valtype;
static inline Valtype
convert_host(Valtype v)
{ return Convert_host<size, big_endian == Endian::host_big_endian>
::convert_host(v); }
};
// Swap is a template based on size and on whether the target is big
// endian. It defines the type Valtype and the functions readval and
// writeval. The functions read and write values of the appropriate
// size out of buffers, swapping them if necessary.
template<int size, bool big_endian>
struct Swap
{
typedef typename Valtype_base<size>::Valtype Valtype;
static inline Valtype
readval(const Valtype* wv)
{ return Convert<size, big_endian>::convert_host(*wv); }
static inline void
writeval(Valtype* wv, Valtype v)
{ *wv = Convert<size, big_endian>::convert_host(v); }
};
// Swap_unaligned is a template based on size and on whether the
// target is big endian. It defines the type Valtype and the
// functions readval_unaligned and writeval_unaligned. The functions
// read and write values of the appropriate size out of buffers which
// may be misaligned.
template<int size, bool big_endian>
class Swap_unaligned;
template<bool big_endian>
class Swap_unaligned<8, big_endian>
{
public:
typedef typename Valtype_base<8>::Valtype Valtype;
static inline Valtype
readval_unaligned(const unsigned char* wv)
{ return *wv; }
static inline void
writeval_unaligned(unsigned char* wv, Valtype v)
{ *wv = v; }
};
template<>
class Swap_unaligned<16, false>
{
public:
typedef Valtype_base<16>::Valtype Valtype;
static inline Valtype
readval_unaligned(const unsigned char* wv)
{
return (wv[1] << 8) | wv[0];
}
static inline void
writeval_unaligned(unsigned char* wv, Valtype v)
{
wv[1] = v >> 8;
wv[0] = v;
}
};
template<>
class Swap_unaligned<16, true>
{
public:
typedef Valtype_base<16>::Valtype Valtype;
static inline Valtype
readval_unaligned(const unsigned char* wv)
{
return (wv[0] << 8) | wv[1];
}
static inline void
writeval_unaligned(unsigned char* wv, Valtype v)
{
wv[0] = v >> 8;
wv[1] = v;
}
};
template<>
class Swap_unaligned<32, false>
{
public:
typedef Valtype_base<32>::Valtype Valtype;
static inline Valtype
readval_unaligned(const unsigned char* wv)
{
return (wv[3] << 24) | (wv[2] << 16) | (wv[1] << 8) | wv[0];
}
static inline void
writeval_unaligned(unsigned char* wv, Valtype v)
{
wv[3] = v >> 24;
wv[2] = v >> 16;
wv[1] = v >> 8;
wv[0] = v;
}
};
template<>
class Swap_unaligned<32, true>
{
public:
typedef Valtype_base<32>::Valtype Valtype;
static inline Valtype
readval_unaligned(const unsigned char* wv)
{
return (wv[0] << 24) | (wv[1] << 16) | (wv[2] << 8) | wv[3];
}
static inline void
writeval_unaligned(unsigned char* wv, Valtype v)
{
wv[0] = v >> 24;
wv[1] = v >> 16;
wv[2] = v >> 8;
wv[3] = v;
}
};
template<>
class Swap_unaligned<64, false>
{
public:
typedef Valtype_base<64>::Valtype Valtype;
static inline Valtype
readval_unaligned(const unsigned char* wv)
{
return ((static_cast<Valtype>(wv[7]) << 56)
| (static_cast<Valtype>(wv[6]) << 48)
| (static_cast<Valtype>(wv[5]) << 40)
| (static_cast<Valtype>(wv[4]) << 32)
| (static_cast<Valtype>(wv[3]) << 24)
| (static_cast<Valtype>(wv[2]) << 16)
| (static_cast<Valtype>(wv[1]) << 8)
| static_cast<Valtype>(wv[0]));
}
static inline void
writeval_unaligned(unsigned char* wv, Valtype v)
{
wv[7] = v >> 56;
wv[6] = v >> 48;
wv[5] = v >> 40;
wv[4] = v >> 32;
wv[3] = v >> 24;
wv[2] = v >> 16;
wv[1] = v >> 8;
wv[0] = v;
}
};
template<>
class Swap_unaligned<64, true>
{
public:
typedef Valtype_base<64>::Valtype Valtype;
static inline Valtype
readval_unaligned(const unsigned char* wv)
{
return ((static_cast<Valtype>(wv[0]) << 56)
| (static_cast<Valtype>(wv[1]) << 48)
| (static_cast<Valtype>(wv[2]) << 40)
| (static_cast<Valtype>(wv[3]) << 32)
| (static_cast<Valtype>(wv[4]) << 24)
| (static_cast<Valtype>(wv[5]) << 16)
| (static_cast<Valtype>(wv[6]) << 8)
| static_cast<Valtype>(wv[7]));
}
static inline void
writeval_unaligned(unsigned char* wv, Valtype v)
{
wv[7] = v >> 56;
wv[6] = v >> 48;
wv[5] = v >> 40;
wv[4] = v >> 32;
wv[3] = v >> 24;
wv[2] = v >> 16;
wv[1] = v >> 8;
wv[0] = v;
}
};
// Standard relocation routines which are used on many targets. Here
// SIZE and BIG_ENDIAN refer to the target, not the relocation type.
template<int size, bool big_endian>
class Relocate_functions
{
private:
// Do a simple relocation with the addend in the section contents.
// VALSIZE is the size of the value.
template<int valsize>
static inline void
rel(unsigned char* view, typename Swap<valsize, big_endian>::Valtype value)
{
typedef typename Swap<valsize, big_endian>::Valtype Valtype;
Valtype* wv = reinterpret_cast<Valtype*>(view);
Valtype x = Swap<valsize, big_endian>::readval(wv);
Swap<valsize, big_endian>::writeval(wv, x + value);
}
// Do a simple PC relative relocation with the addend in the section
// contents. VALSIZE is the size of the value.
template<int valsize>
static inline void
pcrel(unsigned char* view, typename Swap<valsize, big_endian>::Valtype value,
typename elfcpp::Elf_types<size>::Elf_Addr address)
{
typedef typename Swap<valsize, big_endian>::Valtype Valtype;
Valtype* wv = reinterpret_cast<Valtype*>(view);
Valtype x = Swap<valsize, big_endian>::readval(wv);
Swap<valsize, big_endian>::writeval(wv, x + value - address);
}
typedef Relocate_functions<size, big_endian> This;
public:
// Do a simple 8-bit REL relocation with the addend in the object
// file data.
static inline void
rel8(unsigned char* view, unsigned char value)
{
This::template rel<8>(view, value);
}
// Do a simple 8-bit PC relative relocation with the addend in the
// object file data.
static inline void
pcrel8(unsigned char* view, unsigned char value,
typename elfcpp::Elf_types<size>::Elf_Addr address)
{
This::template pcrel<8>(view, value, address);
}
// Do a simple 16-bit REL relocation with the addend in the object
// file data.
static inline void
rel16(unsigned char* view, elfcpp::Elf_Half value)
{
This::template rel<16>(view, value);
}
// Do a simple 32-bit PC relative REL relocation with the addend in
// the object file data.
static inline void
pcrel16(unsigned char* view, elfcpp::Elf_Word value,
typename elfcpp::Elf_types<size>::Elf_Addr address)
{
This::template pcrel<16>(view, value, address);
}
// Do a simple 32-bit REL relocation with the addend in the section
// contents.
static inline void
rel32(unsigned char* view, elfcpp::Elf_Word value)
{
This::template rel<32>(view, value);
}
// Do a simple 32-bit PC relative REL relocation with the addend in
// the section contents.
static inline void
pcrel32(unsigned char* view, elfcpp::Elf_Word value,
typename elfcpp::Elf_types<size>::Elf_Addr address)
{
This::template pcrel<32>(view, value, address);
}
// Do a simple 64-bit REL relocation with the addend in the section
// contents.
static inline void
rel64(unsigned char* view, elfcpp::Elf_Word value)
{
This::template rel<64>(view, value);
}
// Do a simple 64-bit PC relative REL relocation with the addend in
// the section contents.
static inline void
pcrel64(unsigned char* view, elfcpp::Elf_Word value,
typename elfcpp::Elf_types<size>::Elf_Addr address)
{
This::template pcrel<64>(view, value, address);
}
};
} // End namespace gold.
#endif // !defined(GOLD_RELOC_H)

View File

@ -94,6 +94,12 @@ class Symbol
set_in_dyn()
{ this->in_dyn_ = true; }
// Return whether this symbol needs an entry in the dynamic symbol
// table. FIXME: Needs to be fleshed out.
bool
in_dynsym() const
{ return this->in_dyn_; }
protected:
// Instances of this class should always be created at a specific
// size.

View File

@ -4,6 +4,7 @@
#define GOLD_TARGET_RELOC_H
#include "elfcpp.h"
#include "object.h"
#include "symtab.h"
namespace gold
@ -29,7 +30,79 @@ struct Reloc_types<elfcpp::SHT_RELA, size, big_endian>
static const int reloc_size = elfcpp::Elf_sizes<size>::rela_size;
};
// This function implements the generic part of relocation handling.
// This function implements the generic part of reloc scanning. This
// is an inline function which takes a class whose operator()
// implements the machine specific part of scanning. We do it this
// way to avoidmaking a function call for each relocation, and to
// avoid repeating the generic code for each target.
template<int size, bool big_endian, int sh_type, typename Scan>
inline void
scan_relocs(
const General_options& options,
Symbol_table* symtab,
Sized_object<size, big_endian>* object,
const unsigned char* prelocs,
size_t reloc_count,
size_t local_count,
const unsigned char* plocal_syms,
Symbol** global_syms)
{
typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype;
const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
Scan scan;
for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
{
Reltype reloc(prelocs);
typename elfcpp::Elf_types<size>::Elf_WXword r_info = reloc.get_r_info();
unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
if (r_sym < local_count)
{
assert(plocal_syms != NULL);
typename elfcpp::Sym<size, big_endian> lsym(plocal_syms
+ r_sym * sym_size);
const unsigned int shndx = lsym.get_st_shndx();
if (shndx < elfcpp::SHN_LORESERVE
&& !object->is_section_included(lsym.get_st_shndx()))
{
// RELOC is a relocation against a local symbol in a
// section we are discarding. We can ignore this
// relocation. It will eventually become a reloc
// against the value zero.
//
// FIXME: We should issue a warning if this is an
// allocated section; is this the best place to do it?
//
// FIXME: The old GNU linker would in some cases look
// for the linkonce section which caused this section to
// be discarded, and, if the other section was the same
// size, change the reloc to refer to the other section.
// That seems risky and weird to me, and I don't know of
// any case where it is actually required.
continue;
}
scan.local(options, object, reloc, r_type, lsym);
}
else
{
Symbol* gsym = global_syms[r_sym - local_count];
assert(gsym != NULL);
if (gsym->is_forwarder())
gsym = symtab->resolve_forwards(gsym);
scan.global(options, object, reloc, r_type, gsym);
}
}
}
// This function implements the generic part of relocation processing.
// This is an inline function which take a class whose operator()
// implements the machine specific part of relocation. We do it this
// way to avoid making a function call for each relocation, and to
@ -37,27 +110,19 @@ struct Reloc_types<elfcpp::SHT_RELA, size, big_endian>
// target.
// SIZE is the ELF size: 32 or 64. BIG_ENDIAN is the endianness of
// the data. SH_TYPE is the section type: SHT_REL or SHT_RELA. RELOC
// implements operator() to do a relocation.
// the data. SH_TYPE is the section type: SHT_REL or SHT_RELA.
// RELOCATE implements operator() to do a relocation.
// OBJECT is the object for we are processing relocs. SH_TYPE is the
// type of relocation: SHT_REL or SHT_RELA. PRELOCS points to the
// relocation data. RELOC_COUNT is the number of relocs. LOCAL_COUNT
// is the number of local symbols. LOCAL_VALUES holds the values of
// the local symbols. GLOBAL_SYMS points to the global symbols. VIEW
// is the section data, VIEW_ADDRESS is its memory address, and
// VIEW_SIZE is the size.
// PRELOCS points to the relocation data. RELOC_COUNT is the number
// of relocs. VIEW is the section data, VIEW_ADDRESS is its memory
// address, and VIEW_SIZE is the size.
template<int size, bool big_endian, int sh_type, typename Relocate>
inline void
relocate_section(
const Symbol_table* symtab,
Sized_object<size, big_endian>* object,
const Relocate_info<size, big_endian>* relinfo,
const unsigned char* prelocs,
size_t reloc_count,
size_t local_count,
const typename elfcpp::Elf_types<size>::Elf_Addr* local_values,
Symbol** global_syms,
unsigned char* view,
typename elfcpp::Elf_types<size>::Elf_Addr view_address,
off_t view_size)
@ -66,6 +131,10 @@ relocate_section(
const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
Relocate relocate;
unsigned int local_count = relinfo->local_symbol_count;
typename elfcpp::Elf_types<size>::Elf_Addr *local_values = relinfo->values;
Symbol** global_syms = relinfo->symbols;
for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
{
Reltype reloc(prelocs);
@ -73,9 +142,9 @@ relocate_section(
off_t offset = reloc.get_r_offset();
if (offset < 0 || offset >= view_size)
{
fprintf(stderr, _("%s: %s: reloc %zu has bad offset %lu\n"),
program_name, object->name().c_str(), i,
static_cast<unsigned long>(offset));
fprintf(stderr, _("%s: %s: reloc has bad offset %zu\n"),
program_name, relinfo->location(i, offset).c_str(),
static_cast<size_t>(offset));
gold_exit(false);
}
@ -96,7 +165,7 @@ relocate_section(
Symbol* gsym = global_syms[r_sym - local_count];
assert(gsym != NULL);
if (gsym->is_forwarder())
gsym = symtab->resolve_forwards(gsym);
gsym = relinfo->symtab->resolve_forwards(gsym);
sym = static_cast<Sized_symbol<size>*>(gsym);
value = sym->value();
@ -105,13 +174,14 @@ relocate_section(
&& sym->binding() != elfcpp::STB_WEAK)
{
fprintf(stderr, _("%s: %s: undefined reference to '%s'\n"),
program_name, object->name().c_str(), sym->name());
program_name, relinfo->location(i, offset).c_str(),
sym->name());
// gold_exit(false);
}
}
relocate(object, reloc, r_type, sym, value, view + offset,
view_address + offset);
relocate.relocate(relinfo, i, reloc, r_type, sym, value, view + offset,
view_address + offset, view_size);
}
}

View File

@ -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)

View File

@ -192,6 +192,8 @@ Workqueue::~Workqueue()
assert(this->running_ == 0);
}
// Add a task to the queue.
void
Workqueue::queue(Task* t)
{
@ -199,6 +201,15 @@ Workqueue::queue(Task* t)
this->tasks_.push_back(t);
}
// Add a task to the front of the queue.
void
Workqueue::queue_front(Task* t)
{
Hold_lock hl(this->tasks_lock_);
this->tasks_.push_front(t);
}
// Clear the list of completed tasks. Return whether we cleared
// anything. The completed_lock_ must be held when this is called.

View File

@ -288,6 +288,58 @@ class Task
run(Workqueue*) = 0;
};
// A simple task which waits for a blocker and then runs a function.
class Task_function_runner
{
public:
virtual ~Task_function_runner()
{ }
virtual void
run(Workqueue*) = 0;
};
class Task_function : public Task
{
public:
// Both points should be allocated using new, and will be deleted
// after the task runs.
Task_function(Task_function_runner* runner, Task_token* blocker)
: runner_(runner), blocker_(blocker)
{ }
~Task_function()
{
delete this->runner_;
delete this->blocker_;
}
// The standard task methods.
// Wait until the task is unblocked.
Is_runnable_type
is_runnable(Workqueue*)
{ return this->blocker_->is_blocked() ? IS_BLOCKED : IS_RUNNABLE; }
// This type of task does not normally hold any locks.
virtual Task_locker*
locks(Workqueue*)
{ return NULL; }
// Run the action.
void
run(Workqueue* workqueue)
{ this->runner_->run(workqueue); }
private:
Task_function(const Task_function&);
Task_function& operator=(const Task_function&);
Task_function_runner* runner_;
Task_token* blocker_;
};
// The workqueue
class Workqueue_runner;
@ -302,6 +354,11 @@ class Workqueue
void
queue(Task*);
// Add a new task to the front of the work queue. It will be the
// next task to run if it is ready.
void
queue_front(Task*);
// Process all the tasks on the work queue.
void
process();