mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-21 01:12:32 +08:00
Another snapshot of the current state of the sources. Gets to the
point of symbol resolution and can now issue a multiple definition error. Also added target selection infrastructure.
This commit is contained in:
parent
476308bf9b
commit
14bfc3f555
@ -396,6 +396,25 @@ enum STT
|
||||
STT_HIPROC = 15
|
||||
};
|
||||
|
||||
inline STB
|
||||
elf_st_bind(unsigned char info)
|
||||
{
|
||||
return static_cast<STB>(info >> 4);
|
||||
}
|
||||
|
||||
inline STT
|
||||
elf_st_type(unsigned char info)
|
||||
{
|
||||
return static_cast<STT>(info & 0xf);
|
||||
}
|
||||
|
||||
inline unsigned char
|
||||
elf_st_info(STB bind, STT type)
|
||||
{
|
||||
return ((static_cast<unsigned char>(bind) << 4)
|
||||
+ (static_cast<unsigned char>(type) & 0xf));
|
||||
}
|
||||
|
||||
// Symbol visibility from Sym st_other field.
|
||||
|
||||
enum STV
|
||||
@ -406,6 +425,18 @@ enum STV
|
||||
STV_PROTECTED = 3
|
||||
};
|
||||
|
||||
inline STV
|
||||
elf_st_visibility(unsigned char other)
|
||||
{
|
||||
return static_cast<STV>(other & 0x3);
|
||||
}
|
||||
|
||||
inline unsigned char
|
||||
elf_st_nonvis(unsigned char other)
|
||||
{
|
||||
return static_cast<STV>(other >> 2);
|
||||
}
|
||||
|
||||
} // End namespace elfcpp.
|
||||
|
||||
// Include internal details after defining the types.
|
||||
@ -576,16 +607,32 @@ class Sym
|
||||
|
||||
typename Elf_types<size>::Elf_WXword
|
||||
get_st_size() const
|
||||
{ return internal::convert_wxword<big_endian>(this->p_->st_size); }
|
||||
{ return internal::convert_wxword<size, big_endian>(this->p_->st_size); }
|
||||
|
||||
unsigned char
|
||||
get_st_info() const
|
||||
{ return this->p_->st_info; }
|
||||
|
||||
STB
|
||||
get_st_bind() const
|
||||
{ return elf_st_bind(this->get_st_info()); }
|
||||
|
||||
STT
|
||||
get_st_type() const
|
||||
{ return elf_st_type(this->get_st_info()); }
|
||||
|
||||
unsigned char
|
||||
get_st_other() const
|
||||
{ return this->p_->st_other; }
|
||||
|
||||
STV
|
||||
get_st_visibility() const
|
||||
{ return elf_st_visibility(this->get_st_other()); }
|
||||
|
||||
unsigned char
|
||||
get_st_nonvis() const
|
||||
{ return elf_st_nonvis(this->get_st_other()); }
|
||||
|
||||
Elf_Half
|
||||
get_st_shndx() const
|
||||
{ return internal::convert_half<big_endian>(this->p_->st_shndx); }
|
||||
|
@ -17,7 +17,7 @@ INCLUDES = -D_GNU_SOURCE \
|
||||
|
||||
noinst_PROGRAMS = ld-new
|
||||
|
||||
CFILES = \
|
||||
CCFILES = \
|
||||
dirsearch.cc \
|
||||
fileread.cc \
|
||||
gold.cc \
|
||||
@ -25,6 +25,10 @@ CFILES = \
|
||||
object.cc \
|
||||
options.cc \
|
||||
readsyms.cc \
|
||||
resolve.cc \
|
||||
symtab.cc \
|
||||
stringpool.cc \
|
||||
target-select.cc \
|
||||
workqueue.cc
|
||||
|
||||
HFILES = \
|
||||
@ -35,20 +39,25 @@ HFILES = \
|
||||
object.h \
|
||||
options.h \
|
||||
readsyms.h \
|
||||
stringpool.h \
|
||||
symtab.h \
|
||||
target.h \
|
||||
targetsize.h \
|
||||
target-select.h \
|
||||
workqueue.h
|
||||
|
||||
TARGETFILES = \
|
||||
i386.cc
|
||||
|
||||
OFILES = gold.o options.o
|
||||
|
||||
POTFILES= $(CFILES) $(HFILES)
|
||||
POTFILES= $(CCFILES) $(HFILES) $(TARGETFILES)
|
||||
|
||||
po/POTFILES.in: @MAINT@ Makefile
|
||||
for f in $(POTFILES); do echo $$f; done | LC_COLLATE= sort > tmp \
|
||||
&& mv tmp $(srcdir)/po/POTFILES.in
|
||||
|
||||
ld_new_SOURCES = $(CFILES) $(HFILES)
|
||||
ld_new_SOURCES = $(CCFILES) $(HFILES) $(TARGETFILES)
|
||||
ld_new_DEPENDENCIES = $(LIBINTL_DEP)
|
||||
ld_new_LDADD = $(LIBINTL)
|
||||
|
||||
|
@ -67,9 +67,12 @@ CONFIG_CLEAN_FILES = po/Makefile.in
|
||||
PROGRAMS = $(noinst_PROGRAMS)
|
||||
am__objects_1 = dirsearch.$(OBJEXT) fileread.$(OBJEXT) gold.$(OBJEXT) \
|
||||
gold-threads.$(OBJEXT) object.$(OBJEXT) options.$(OBJEXT) \
|
||||
readsyms.$(OBJEXT) workqueue.$(OBJEXT)
|
||||
readsyms.$(OBJEXT) resolve.$(OBJEXT) symtab.$(OBJEXT) \
|
||||
stringpool.$(OBJEXT) target-select.$(OBJEXT) \
|
||||
workqueue.$(OBJEXT)
|
||||
am__objects_2 =
|
||||
am_ld_new_OBJECTS = $(am__objects_1) $(am__objects_2)
|
||||
am__objects_3 = i386.$(OBJEXT)
|
||||
am_ld_new_OBJECTS = $(am__objects_1) $(am__objects_2) $(am__objects_3)
|
||||
ld_new_OBJECTS = $(am_ld_new_OBJECTS)
|
||||
am__DEPENDENCIES_1 =
|
||||
DEFAULT_INCLUDES = -I. -I$(srcdir) -I.
|
||||
@ -225,7 +228,7 @@ INCLUDES = -D_GNU_SOURCE \
|
||||
-DLOCALEDIR="\"$(datadir)/locale\"" \
|
||||
@INCINTL@
|
||||
|
||||
CFILES = \
|
||||
CCFILES = \
|
||||
dirsearch.cc \
|
||||
fileread.cc \
|
||||
gold.cc \
|
||||
@ -233,6 +236,10 @@ CFILES = \
|
||||
object.cc \
|
||||
options.cc \
|
||||
readsyms.cc \
|
||||
resolve.cc \
|
||||
symtab.cc \
|
||||
stringpool.cc \
|
||||
target-select.cc \
|
||||
workqueue.cc
|
||||
|
||||
HFILES = \
|
||||
@ -243,14 +250,19 @@ HFILES = \
|
||||
object.h \
|
||||
options.h \
|
||||
readsyms.h \
|
||||
stringpool.h \
|
||||
symtab.h \
|
||||
target.h \
|
||||
targetsize.h \
|
||||
target-select.h \
|
||||
workqueue.h
|
||||
|
||||
TARGETFILES = \
|
||||
i386.cc
|
||||
|
||||
OFILES = gold.o options.o
|
||||
POTFILES = $(CFILES) $(HFILES)
|
||||
ld_new_SOURCES = $(CFILES) $(HFILES)
|
||||
POTFILES = $(CCFILES) $(HFILES) $(TARGETFILES)
|
||||
ld_new_SOURCES = $(CCFILES) $(HFILES) $(TARGETFILES)
|
||||
ld_new_DEPENDENCIES = $(LIBINTL_DEP)
|
||||
ld_new_LDADD = $(LIBINTL)
|
||||
all: config.h
|
||||
@ -327,9 +339,14 @@ distclean-compile:
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fileread.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gold-threads.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gold.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/i386.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/object.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/options.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/readsyms.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resolve.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stringpool.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/symtab.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/target-select.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/workqueue.Po@am__quote@
|
||||
|
||||
.cc.o:
|
||||
|
10
gold/gold.cc
10
gold/gold.cc
@ -11,6 +11,7 @@
|
||||
#include "workqueue.h"
|
||||
#include "dirsearch.h"
|
||||
#include "readsyms.h"
|
||||
#include "symtab.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
@ -65,7 +66,7 @@ void
|
||||
queue_initial_tasks(const General_options& options,
|
||||
const Dirsearch& search_path,
|
||||
const Command_line::Input_argument_list& inputs,
|
||||
Workqueue* workqueue)
|
||||
Workqueue* workqueue, Symbol_table* symtab)
|
||||
{
|
||||
if (inputs.empty())
|
||||
gold_fatal(_("no input files"), false);
|
||||
@ -81,8 +82,8 @@ queue_initial_tasks(const General_options& options,
|
||||
{
|
||||
Task_token* next_blocker = new Task_token();
|
||||
next_blocker->add_blocker();
|
||||
workqueue->queue(new Read_symbols(options, search_path, *p, this_blocker,
|
||||
next_blocker));
|
||||
workqueue->queue(new Read_symbols(options, symtab, search_path,
|
||||
*p, this_blocker, next_blocker));
|
||||
this_blocker = next_blocker;
|
||||
}
|
||||
|
||||
@ -113,6 +114,7 @@ main(int argc, char** argv)
|
||||
gold::Workqueue workqueue(command_line.options());
|
||||
|
||||
// The symbol table.
|
||||
Symbol_table symtab;
|
||||
|
||||
// Get the search path from the -L options.
|
||||
Dirsearch search_path;
|
||||
@ -120,7 +122,7 @@ main(int argc, char** argv)
|
||||
|
||||
// Queue up the first set of tasks.
|
||||
queue_initial_tasks(command_line.options(), search_path,
|
||||
command_line.inputs(), &workqueue);
|
||||
command_line.inputs(), &workqueue, &symtab);
|
||||
|
||||
// Run the main task processing loop.
|
||||
workqueue.process();
|
||||
|
47
gold/i386.cc
Normal file
47
gold/i386.cc
Normal file
@ -0,0 +1,47 @@
|
||||
// i386.cc -- i386 target support for gold.
|
||||
|
||||
#include "gold.h"
|
||||
#include "elfcpp.h"
|
||||
#include "target.h"
|
||||
#include "target-select.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
using namespace gold;
|
||||
|
||||
// The i386 target class.
|
||||
|
||||
class Target_i386 : public Sized_target<32, false>
|
||||
{
|
||||
public:
|
||||
Target_i386()
|
||||
: Sized_target<32, false>(false, false)
|
||||
{ }
|
||||
};
|
||||
|
||||
// The selector for i386 object files.
|
||||
|
||||
class Target_selector_i386 : public Target_selector
|
||||
{
|
||||
public:
|
||||
Target_selector_i386()
|
||||
: Target_selector(elfcpp::EM_386, 32, false)
|
||||
{ }
|
||||
|
||||
Target*
|
||||
recognize(int machine, int osabi, int abiversion) const;
|
||||
};
|
||||
|
||||
// Recognize an i386 object file when we already know that the machine
|
||||
// number is EM_386.
|
||||
|
||||
Target*
|
||||
Target_selector_i386::recognize(int, int, int) const
|
||||
{
|
||||
return new Target_i386();
|
||||
}
|
||||
|
||||
Target_selector_i386 target_selector_i386;
|
||||
|
||||
} // End anonymous namespace.
|
@ -7,6 +7,7 @@
|
||||
#include <cassert>
|
||||
|
||||
#include "object.h"
|
||||
#include "target-select.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
@ -40,16 +41,16 @@ Sized_object<size, big_endian>::Sized_object(
|
||||
Input_file* input_file,
|
||||
off_t offset,
|
||||
const elfcpp::Ehdr<size, big_endian>& ehdr)
|
||||
: Object(name, input_file, offset),
|
||||
: Object(name, input_file, false, offset),
|
||||
osabi_(ehdr.get_e_ident()[elfcpp::EI_OSABI]),
|
||||
abiversion_(ehdr.get_e_ident()[elfcpp::EI_ABIVERSION]),
|
||||
machine_(ehdr.get_e_machine()),
|
||||
flags_(ehdr.get_e_flags()),
|
||||
target_(NULL),
|
||||
shoff_(ehdr.get_e_shoff()),
|
||||
shnum_(0),
|
||||
shstrndx_(0),
|
||||
symtab_shnum_(0)
|
||||
symtab_shnum_(0),
|
||||
symbols_(NULL)
|
||||
{
|
||||
if (ehdr.get_e_ehsize() != elfcpp::Elf_sizes<size>::ehdr_size)
|
||||
{
|
||||
@ -80,8 +81,15 @@ void
|
||||
Sized_object<size, big_endian>::setup(
|
||||
const elfcpp::Ehdr<size, big_endian>& ehdr)
|
||||
{
|
||||
// this->target_ = select_target(this->machine_, size, big_endian,
|
||||
// this->osabi_, this->abiversion_);
|
||||
Target* target = select_target(this->machine_, size, big_endian,
|
||||
this->osabi_, this->abiversion_);
|
||||
if (target == NULL)
|
||||
{
|
||||
fprintf(stderr, _("%s: %s: unsupported ELF machine number %d\n"),
|
||||
program_name, this->name().c_str(), this->machine_);
|
||||
gold_exit(false);
|
||||
}
|
||||
this->set_target(target);
|
||||
unsigned int shnum = ehdr.get_e_shnum();
|
||||
unsigned int shstrndx = ehdr.get_e_shstrndx();
|
||||
if ((shnum == 0 || shstrndx == elfcpp::SHN_XINDEX)
|
||||
@ -143,9 +151,14 @@ Sized_object<size, big_endian>::do_read_symbols()
|
||||
elfcpp::Shdr<size, big_endian> symtabshdr(psymtabshdr);
|
||||
assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
|
||||
|
||||
// We only need the external symbols.
|
||||
int sym_size = elfcpp::Elf_sizes<size>::sym_size;
|
||||
off_t locsize = symtabshdr.get_sh_info() * sym_size;
|
||||
off_t extoff = symtabshdr.get_sh_offset() + locsize;
|
||||
off_t extsize = symtabshdr.get_sh_size() - locsize;
|
||||
|
||||
// Read the symbol table.
|
||||
File_view* fvsymtab = this->get_lasting_view(symtabshdr.get_sh_offset(),
|
||||
symtabshdr.get_sh_size());
|
||||
File_view* fvsymtab = this->get_lasting_view(extoff, extsize);
|
||||
|
||||
// Read the section header for the symbol names.
|
||||
unsigned int strtab_shnum = symtabshdr.get_sh_link();
|
||||
@ -173,7 +186,7 @@ Sized_object<size, big_endian>::do_read_symbols()
|
||||
|
||||
Read_symbols_data ret;
|
||||
ret.symbols = fvsymtab;
|
||||
ret.symbols_size = symtabshdr.get_sh_size();
|
||||
ret.symbols_size = extsize;
|
||||
ret.symbol_names = fvstrtab;
|
||||
ret.symbol_names_size = strtabshdr.get_sh_size();
|
||||
|
||||
@ -184,7 +197,8 @@ Sized_object<size, big_endian>::do_read_symbols()
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
Sized_object<size, big_endian>::do_add_symbols(Read_symbols_data sd)
|
||||
Sized_object<size, big_endian>::do_add_symbols(Symbol_table* symtab,
|
||||
Read_symbols_data sd)
|
||||
{
|
||||
if (sd.symbols == NULL)
|
||||
{
|
||||
@ -192,25 +206,24 @@ Sized_object<size, big_endian>::do_add_symbols(Read_symbols_data sd)
|
||||
return;
|
||||
}
|
||||
|
||||
int sym_size = elfcpp::Elf_sizes<size>::sym_size;
|
||||
const unsigned char* symstart = sd.symbols->data();
|
||||
const unsigned char* symend = symstart + sd.symbols_size;
|
||||
for (const unsigned char* p = symstart; p < symend; p += sym_size)
|
||||
unsigned int sym_size = elfcpp::Elf_sizes<size>::sym_size;
|
||||
size_t symcount = sd.symbols_size / sym_size;
|
||||
if (symcount * sym_size != sd.symbols_size)
|
||||
{
|
||||
elfcpp::Sym<size, big_endian> sym(p);
|
||||
|
||||
unsigned int nameoff = sym.get_st_name();
|
||||
if (nameoff >= sd.symbol_names_size)
|
||||
{
|
||||
fprintf(stderr,
|
||||
_("%s: %s: invalid symbol name offset %u for symbol %d\n"),
|
||||
program_name, this->name().c_str(), nameoff,
|
||||
(p - symstart) / sym_size);
|
||||
gold_exit(false);
|
||||
}
|
||||
const unsigned char* name = sd.symbol_names->data() + nameoff;
|
||||
printf("%s\n", name);
|
||||
fprintf(stderr,
|
||||
_("%s: %s: size of symbols is not multiple of symbol size\n"),
|
||||
program_name, this->name().c_str());
|
||||
gold_exit(false);
|
||||
}
|
||||
|
||||
this->symbols_ = new Symbol*[symcount];
|
||||
|
||||
const elfcpp::Sym<size, big_endian>* syms =
|
||||
reinterpret_cast<const elfcpp::Sym<size, big_endian>*>(sd.symbols->data());
|
||||
const char* sym_names =
|
||||
reinterpret_cast<const char*>(sd.symbol_names->data());
|
||||
symtab->add_from_object(this, syms, symcount, sym_names,
|
||||
sd.symbol_names_size, this->symbols_);
|
||||
}
|
||||
|
||||
} // End namespace gold.
|
||||
|
@ -3,10 +3,12 @@
|
||||
#ifndef GOLD_OBJECT_H
|
||||
#define GOLD_OBJECT_H
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "elfcpp.h"
|
||||
#include "targetsize.h"
|
||||
#include "target.h"
|
||||
#include "fileread.h"
|
||||
#include "target.h"
|
||||
#include "symtab.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
@ -26,8 +28,9 @@ struct Read_symbols_data
|
||||
};
|
||||
|
||||
// Object is an interface which represents either a 32-bit or a 64-bit
|
||||
// object file. The actual instantiations are Sized_object<32> and
|
||||
// Sized_object<64>
|
||||
// input object. This can be a regular object file (ET_REL) or a
|
||||
// shared object (ET_DYN). The actual instantiations are
|
||||
// Sized_object<32> and Sized_object<64>
|
||||
|
||||
class Object
|
||||
{
|
||||
@ -36,17 +39,25 @@ class Object
|
||||
// (e.g., libfoo.a(bar.o) if this is in an archive. INPUT_FILE is
|
||||
// used to read the file. OFFSET is the offset within the input
|
||||
// file--0 for a .o or .so file, something else for a .a file.
|
||||
Object(const std::string& name, Input_file* input_file, off_t offset = 0)
|
||||
: name_(name), input_file_(input_file), offset_(offset)
|
||||
Object(const std::string& name, Input_file* input_file, bool is_dynamic,
|
||||
off_t offset = 0)
|
||||
: name_(name), input_file_(input_file), offset_(offset),
|
||||
is_dynamic_(is_dynamic), target_(NULL)
|
||||
{ }
|
||||
|
||||
virtual ~Object()
|
||||
{ }
|
||||
|
||||
// Return the name of the object as we would report it to the tuser.
|
||||
const std::string&
|
||||
name() const
|
||||
{ return this->name_; }
|
||||
|
||||
// Return whether this is a dynamic object.
|
||||
bool
|
||||
is_dynamic() const
|
||||
{ return this->is_dynamic_; }
|
||||
|
||||
// Read the symbol and relocation information.
|
||||
Read_symbols_data
|
||||
read_symbols()
|
||||
@ -54,8 +65,20 @@ class Object
|
||||
|
||||
// Add symbol information to the global symbol table.
|
||||
void
|
||||
add_symbols(Read_symbols_data rd)
|
||||
{ this->do_add_symbols(rd); }
|
||||
add_symbols(Symbol_table* symtab, Read_symbols_data rd)
|
||||
{ this->do_add_symbols(symtab, rd); }
|
||||
|
||||
// Return the target structure associated with this object.
|
||||
Target*
|
||||
target()
|
||||
{ return this->target_; }
|
||||
|
||||
// Return the sized target structure associated with this object.
|
||||
// This is like the target method but it returns a pointer of
|
||||
// appropriate checked type.
|
||||
template<int size, bool big_endian>
|
||||
Sized_target<size, big_endian>*
|
||||
sized_target();
|
||||
|
||||
protected:
|
||||
// Read the symbols--implemented by child class.
|
||||
@ -65,7 +88,7 @@ class Object
|
||||
// Add symbol information to the global symbol table--implemented by
|
||||
// child class.
|
||||
virtual void
|
||||
do_add_symbols(Read_symbols_data) = 0;
|
||||
do_add_symbols(Symbol_table*, Read_symbols_data) = 0;
|
||||
|
||||
// Get the file.
|
||||
Input_file*
|
||||
@ -81,6 +104,11 @@ class Object
|
||||
const unsigned char*
|
||||
get_view(off_t start, off_t size);
|
||||
|
||||
// Set the target.
|
||||
void
|
||||
set_target(Target* target)
|
||||
{ this->target_ = target; }
|
||||
|
||||
// Read data from the underlying file.
|
||||
void
|
||||
read(off_t start, off_t size, void* p);
|
||||
@ -101,9 +129,25 @@ class Object
|
||||
// Offset within the file--0 for an object file, non-0 for an
|
||||
// archive.
|
||||
off_t offset_;
|
||||
// Whether this is a dynamic object.
|
||||
bool is_dynamic_;
|
||||
// Target functions--may be NULL if the target is not known.
|
||||
Target* target_;
|
||||
};
|
||||
|
||||
// The functions of Object which are size specific.
|
||||
// Implement sized_target inline for efficiency. This approach breaks
|
||||
// static type checking, but is made safe using asserts.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
inline Sized_target<size, big_endian>*
|
||||
Object::sized_target()
|
||||
{
|
||||
assert(this->target_->get_size() == size);
|
||||
assert(this->target_->is_big_endian() ? big_endian : !big_endian);
|
||||
return static_cast<Sized_target<size, big_endian>*>(this->target_);
|
||||
}
|
||||
|
||||
// A regular object file. This is size and endian specific.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
class Sized_object : public Object
|
||||
@ -121,7 +165,11 @@ class Sized_object : public Object
|
||||
do_read_symbols();
|
||||
|
||||
void
|
||||
do_add_symbols(Read_symbols_data);
|
||||
do_add_symbols(Symbol_table*, Read_symbols_data);
|
||||
|
||||
Sized_target<size, big_endian>*
|
||||
sized_target()
|
||||
{ return this->Object::sized_target<size, big_endian>(); }
|
||||
|
||||
private:
|
||||
// This object may not be copied.
|
||||
@ -136,8 +184,6 @@ class Sized_object : public Object
|
||||
elfcpp::Elf_Half machine_;
|
||||
// ELF file header e_flags field.
|
||||
unsigned int flags_;
|
||||
// Target functions--may be NULL.
|
||||
Target* target_;
|
||||
// File offset of section header table.
|
||||
off_t shoff_;
|
||||
// Number of input sections.
|
||||
@ -146,6 +192,8 @@ class Sized_object : public Object
|
||||
unsigned int shstrndx_;
|
||||
// Index of SHT_SYMTAB section.
|
||||
unsigned int symtab_shnum_;
|
||||
// The entries in the symbol table for the external symbols.
|
||||
Symbol** symbols_;
|
||||
};
|
||||
|
||||
// Return an Object appropriate for the input file. P is BYTES long,
|
||||
|
@ -6,14 +6,21 @@ gold.cc
|
||||
gold.h
|
||||
gold-threads.cc
|
||||
gold-threads.h
|
||||
i386.cc
|
||||
object.cc
|
||||
object.h
|
||||
options.cc
|
||||
options.h
|
||||
readsyms.cc
|
||||
readsyms.h
|
||||
resolve.cc
|
||||
stringpool.cc
|
||||
stringpool.h
|
||||
symtab.cc
|
||||
symtab.h
|
||||
target.h
|
||||
target-select.cc
|
||||
target-select.h
|
||||
targetsize.h
|
||||
workqueue.cc
|
||||
workqueue.h
|
||||
|
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2006-08-04 14:23-0700\n"
|
||||
"POT-Creation-Date: 2006-08-18 15:26-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"
|
||||
@ -16,7 +16,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=CHARSET\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: dirsearch.cc:50
|
||||
#: dirsearch.cc:51
|
||||
#, c-format
|
||||
msgid "can not read directory %s"
|
||||
msgstr ""
|
||||
@ -51,7 +51,7 @@ msgstr ""
|
||||
msgid "%s: cannot open %s: %s"
|
||||
msgstr ""
|
||||
|
||||
#: gold.cc:71
|
||||
#: gold.cc:72
|
||||
msgid "no input files"
|
||||
msgstr ""
|
||||
|
||||
@ -99,68 +99,73 @@ msgstr ""
|
||||
msgid "pthread_cond_signal failed"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:56
|
||||
#: object.cc:57
|
||||
#, c-format
|
||||
msgid "%s: %s: bad e_ehsize field (%d != %d)\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:63
|
||||
#: object.cc:64
|
||||
#, c-format
|
||||
msgid "%s: %s: bad e_shentsize field (%d != %d)\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:154
|
||||
#: object.cc:88
|
||||
#, c-format
|
||||
msgid "%s: %s: unsupported ELF machine number %d\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:167
|
||||
#, c-format
|
||||
msgid "%s: %s: invalid symbol table name index: %u\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:164
|
||||
#: object.cc:177
|
||||
#, c-format
|
||||
msgid "%s: %s: symbol table name section has wrong type: %u\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:206
|
||||
#: object.cc:214
|
||||
#, c-format
|
||||
msgid "%s: %s: invalid symbol name offset %u for symbol %d\n"
|
||||
msgid "%s: %s: size of symbols is not multiple of symbol size\n"
|
||||
msgstr ""
|
||||
|
||||
#. elfcpp::ET_DYN
|
||||
#: object.cc:249
|
||||
#: object.cc:262
|
||||
#, c-format
|
||||
msgid "%s: %s: dynamic objects are not yet supported\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:273 object.cc:326 object.cc:347
|
||||
#: object.cc:286 object.cc:339 object.cc:360
|
||||
#, c-format
|
||||
msgid "%s: %s: ELF file too short\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:282
|
||||
#: object.cc:295
|
||||
#, c-format
|
||||
msgid "%s: %s: invalid ELF version 0\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:285
|
||||
#: object.cc:298
|
||||
#, c-format
|
||||
msgid "%s: %s: unsupported ELF version %d\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:293
|
||||
#: object.cc:306
|
||||
#, c-format
|
||||
msgid "%s: %s: invalid ELF class 0\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:300
|
||||
#: object.cc:313
|
||||
#, c-format
|
||||
msgid "%s: %s: unsupported ELF class %d\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:308
|
||||
#: object.cc:321
|
||||
#, c-format
|
||||
msgid "%s: %s: invalid ELF data encoding\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:315
|
||||
#: object.cc:328
|
||||
#, c-format
|
||||
msgid "%s: %s: unsupported ELF data encoding %d\n"
|
||||
msgstr ""
|
||||
@ -214,3 +219,23 @@ msgstr ""
|
||||
#, c-format
|
||||
msgid "%s: -%c: %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: resolve.cc:103
|
||||
#, c-format
|
||||
msgid "%s: %s: invalid STB_LOCAL symbol %s in external symbols\n"
|
||||
msgstr ""
|
||||
|
||||
#: resolve.cc:109
|
||||
#, c-format
|
||||
msgid "%s: %s: unsupported symbol binding %d for symbol %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: symtab.cc:262
|
||||
#, c-format
|
||||
msgid "%s: %s: mixing 32-bit and 64-bit ELF objects\n"
|
||||
msgstr ""
|
||||
|
||||
#: symtab.cc:275
|
||||
#, c-format
|
||||
msgid "%s: %s: bad symbol name offset %u at %lu\n"
|
||||
msgstr ""
|
||||
|
@ -73,7 +73,8 @@ Read_symbols::run(Workqueue* workqueue)
|
||||
p, bytes);
|
||||
|
||||
Read_symbols_data sd = obj->read_symbols();
|
||||
workqueue->queue(new Add_symbols(obj, sd, this->this_blocker_,
|
||||
workqueue->queue(new Add_symbols(this->symtab_, obj, sd,
|
||||
this->this_blocker_,
|
||||
this->next_blocker_));
|
||||
|
||||
// Opening the file locked it, so now we need to unlock it.
|
||||
@ -117,7 +118,7 @@ Add_symbols::locks(Workqueue* workqueue)
|
||||
void
|
||||
Add_symbols::run(Workqueue*)
|
||||
{
|
||||
this->object_->add_symbols(this->sd_);
|
||||
this->object_->add_symbols(this->symtab_, this->sd_);
|
||||
}
|
||||
|
||||
} // End namespace gold.
|
||||
|
@ -26,10 +26,10 @@ class Read_symbols : public Task
|
||||
// associated Add_symbols task from running before the previous one
|
||||
// has completed; it will be NULL for the first task. NEXT_BLOCKER
|
||||
// is used to block the next input file from adding symbols.
|
||||
Read_symbols(const General_options& options, const Dirsearch& dirpath,
|
||||
const Input_argument& input, Task_token* this_blocker,
|
||||
Task_token* next_blocker)
|
||||
: options_(options), dirpath_(dirpath), input_(input),
|
||||
Read_symbols(const General_options& options, Symbol_table* symtab,
|
||||
const Dirsearch& dirpath, const Input_argument& input,
|
||||
Task_token* this_blocker, Task_token* next_blocker)
|
||||
: options_(options), symtab_(symtab), dirpath_(dirpath), input_(input),
|
||||
this_blocker_(this_blocker), next_blocker_(next_blocker)
|
||||
{ }
|
||||
|
||||
@ -48,6 +48,7 @@ class Read_symbols : public Task
|
||||
|
||||
private:
|
||||
const General_options& options_;
|
||||
Symbol_table* symtab_;
|
||||
const Dirsearch& dirpath_;
|
||||
const Input_argument& input_;
|
||||
Task_token* this_blocker_;
|
||||
@ -64,9 +65,9 @@ class Add_symbols : public Task
|
||||
// THIS_BLOCKER is used to prevent this task from running before the
|
||||
// one for the previous input file. NEXT_BLOCKER is used to prevent
|
||||
// the next task from running.
|
||||
Add_symbols(Object* object, Read_symbols_data sd, Task_token* this_blocker,
|
||||
Task_token* next_blocker)
|
||||
: object_(object), sd_(sd), this_blocker_(this_blocker),
|
||||
Add_symbols(Symbol_table* symtab, Object* object, Read_symbols_data sd,
|
||||
Task_token* this_blocker, Task_token* next_blocker)
|
||||
: symtab_(symtab), object_(object), sd_(sd), this_blocker_(this_blocker),
|
||||
next_blocker_(next_blocker)
|
||||
{ }
|
||||
|
||||
@ -84,6 +85,7 @@ class Add_symbols : public Task
|
||||
run(Workqueue*);
|
||||
|
||||
private:
|
||||
Symbol_table* symtab_;
|
||||
Object* object_;
|
||||
Read_symbols_data sd_;
|
||||
Task_token* this_blocker_;
|
||||
|
349
gold/resolve.cc
Normal file
349
gold/resolve.cc
Normal file
@ -0,0 +1,349 @@
|
||||
// resolve.cc -- symbol resolution for gold
|
||||
|
||||
#include "gold.h"
|
||||
|
||||
#include "elfcpp.h"
|
||||
#include "target.h"
|
||||
#include "object.h"
|
||||
#include "symtab.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
// Resolve a symbol. This is called the second and subsequent times
|
||||
// we see a symbol. TO is the pre-existing symbol. SYM is the new
|
||||
// symbol, seen in OBJECT.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
Symbol_table::resolve(Symbol* to,
|
||||
const elfcpp::Sym<size, big_endian>& sym,
|
||||
Object* object)
|
||||
{
|
||||
if (object->target()->has_resolve())
|
||||
{
|
||||
object->sized_target<size, big_endian>()->resolve(to, sym, object);
|
||||
return;
|
||||
}
|
||||
|
||||
// Build a little code for each symbol.
|
||||
// Bit 0: 0 for global, 1 for weak.
|
||||
// Bit 1: 0 for regular object, 1 for shared object
|
||||
// Bits 2-3: 0 for normal, 1 for undefined, 2 for common
|
||||
// This gives us values from 0 to 11:
|
||||
|
||||
enum
|
||||
{
|
||||
DEF = 0,
|
||||
WEAK_DEF = 1,
|
||||
DYN_DEF = 2,
|
||||
DYN_WEAK_DEF = 3,
|
||||
UNDEF = 4,
|
||||
WEAK_UNDEF = 5,
|
||||
DYN_UNDEF = 6,
|
||||
DYN_WEAK_UNDEF = 7,
|
||||
COMMON = 8,
|
||||
WEAK_COMMON = 9,
|
||||
DYN_COMMON = 10,
|
||||
DYN_WEAK_COMMON = 11
|
||||
};
|
||||
|
||||
int tobits;
|
||||
switch (to->binding())
|
||||
{
|
||||
case elfcpp::STB_GLOBAL:
|
||||
tobits = 0;
|
||||
break;
|
||||
|
||||
case elfcpp::STB_WEAK:
|
||||
tobits = 1;
|
||||
break;
|
||||
|
||||
case elfcpp::STB_LOCAL:
|
||||
// We should only see externally visible symbols in the symbol
|
||||
// table.
|
||||
abort();
|
||||
|
||||
default:
|
||||
// Any target which wants to handle STB_LOOS, etc., needs to
|
||||
// define a resolve method.
|
||||
abort();
|
||||
}
|
||||
|
||||
if (to->object() != NULL && to->object()->is_dynamic())
|
||||
tobits |= (1 << 1);
|
||||
|
||||
switch (to->shnum())
|
||||
{
|
||||
case elfcpp::SHN_UNDEF:
|
||||
tobits |= (1 << 2);
|
||||
break;
|
||||
|
||||
case elfcpp::SHN_COMMON:
|
||||
tobits |= (2 << 2);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
int frombits;
|
||||
switch (sym.get_st_bind())
|
||||
{
|
||||
case elfcpp::STB_GLOBAL:
|
||||
frombits = 0;
|
||||
break;
|
||||
|
||||
case elfcpp::STB_WEAK:
|
||||
frombits = 1;
|
||||
break;
|
||||
|
||||
case elfcpp::STB_LOCAL:
|
||||
fprintf(stderr,
|
||||
_("%s: %s: invalid STB_LOCAL symbol %s in external symbols\n"),
|
||||
program_name, object->name().c_str(), to->name());
|
||||
gold_exit(false);
|
||||
|
||||
default:
|
||||
fprintf(stderr,
|
||||
_("%s: %s: unsupported symbol binding %d for symbol %s\n"),
|
||||
program_name, object->name().c_str(),
|
||||
static_cast<int>(sym.get_st_bind()), to->name());
|
||||
gold_exit(false);
|
||||
}
|
||||
|
||||
if (object->is_dynamic())
|
||||
frombits |= (1 << 1);
|
||||
|
||||
switch (sym.get_st_shndx())
|
||||
{
|
||||
case elfcpp::SHN_UNDEF:
|
||||
frombits |= (1 << 2);
|
||||
break;
|
||||
|
||||
case elfcpp::SHN_COMMON:
|
||||
frombits |= (2 << 2);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// We use a giant switch table for symbol resolution. This code is
|
||||
// unwieldy, but: 1) it is efficient; 2) we definitely handle all
|
||||
// cases; 3) it is easy to change the handling of a particular case.
|
||||
// The alternative would be a series of conditionals, but it is easy
|
||||
// to get the ordering wrong. This could also be done as a table,
|
||||
// but that is no easier to understand than this large switch
|
||||
// statement.
|
||||
|
||||
switch (tobits * 16 + frombits)
|
||||
{
|
||||
case DEF * 16 + DEF:
|
||||
// Two definitions of the same symbol.
|
||||
fprintf(stderr, "%s: %s: multiple definition of %s\n",
|
||||
program_name, object->name().c_str(), to->name());
|
||||
// FIXME: Report locations. Record that we have seen an error.
|
||||
return;
|
||||
|
||||
case WEAK_DEF * 16 + DEF:
|
||||
// In the original SVR4 linker, a weak definition followed by a
|
||||
// regular definition was treated as a multiple definition
|
||||
// error. In the Solaris linker and the GNU linker, a weak
|
||||
// definition followed by a regular definition causes the
|
||||
// regular definition to be ignored. We are currently
|
||||
// compatible with the GNU linker. In the future we should add
|
||||
// a target specific option to change this. FIXME.
|
||||
return;
|
||||
|
||||
case DYN_DEF * 16 + DEF:
|
||||
case DYN_WEAK_DEF * 16 + DEF:
|
||||
case UNDEF * 16 + DEF:
|
||||
case WEAK_UNDEF * 16 + DEF:
|
||||
case DYN_UNDEF * 16 + DEF:
|
||||
case DYN_WEAK_UNDEF * 16 + DEF:
|
||||
case COMMON * 16 + DEF:
|
||||
case WEAK_COMMON * 16 + DEF:
|
||||
case DYN_COMMON * 16 + DEF:
|
||||
case DYN_WEAK_COMMON * 16 + DEF:
|
||||
|
||||
case DEF * 16 + WEAK_DEF:
|
||||
case WEAK_DEF * 16 + WEAK_DEF:
|
||||
case DYN_DEF * 16 + WEAK_DEF:
|
||||
case DYN_WEAK_DEF * 16 + WEAK_DEF:
|
||||
case UNDEF * 16 + WEAK_DEF:
|
||||
case WEAK_UNDEF * 16 + WEAK_DEF:
|
||||
case DYN_UNDEF * 16 + WEAK_DEF:
|
||||
case DYN_WEAK_UNDEF * 16 + WEAK_DEF:
|
||||
case COMMON * 16 + WEAK_DEF:
|
||||
case WEAK_COMMON * 16 + WEAK_DEF:
|
||||
case DYN_COMMON * 16 + WEAK_DEF:
|
||||
case DYN_WEAK_COMMON * 16 + WEAK_DEF:
|
||||
|
||||
case DEF * 16 + DYN_DEF:
|
||||
case WEAK_DEF * 16 + DYN_DEF:
|
||||
case DYN_DEF * 16 + DYN_DEF:
|
||||
case DYN_WEAK_DEF * 16 + DYN_DEF:
|
||||
case UNDEF * 16 + DYN_DEF:
|
||||
case WEAK_UNDEF * 16 + DYN_DEF:
|
||||
case DYN_UNDEF * 16 + DYN_DEF:
|
||||
case DYN_WEAK_UNDEF * 16 + DYN_DEF:
|
||||
case COMMON * 16 + DYN_DEF:
|
||||
case WEAK_COMMON * 16 + DYN_DEF:
|
||||
case DYN_COMMON * 16 + DYN_DEF:
|
||||
case DYN_WEAK_COMMON * 16 + DYN_DEF:
|
||||
|
||||
case DEF * 16 + DYN_WEAK_DEF:
|
||||
case WEAK_DEF * 16 + DYN_WEAK_DEF:
|
||||
case DYN_DEF * 16 + DYN_WEAK_DEF:
|
||||
case DYN_WEAK_DEF * 16 + DYN_WEAK_DEF:
|
||||
case UNDEF * 16 + DYN_WEAK_DEF:
|
||||
case WEAK_UNDEF * 16 + DYN_WEAK_DEF:
|
||||
case DYN_UNDEF * 16 + DYN_WEAK_DEF:
|
||||
case DYN_WEAK_UNDEF * 16 + DYN_WEAK_DEF:
|
||||
case COMMON * 16 + DYN_WEAK_DEF:
|
||||
case WEAK_COMMON * 16 + DYN_WEAK_DEF:
|
||||
case DYN_COMMON * 16 + DYN_WEAK_DEF:
|
||||
case DYN_WEAK_COMMON * 16 + DYN_WEAK_DEF:
|
||||
|
||||
case DEF * 16 + UNDEF:
|
||||
case WEAK_DEF * 16 + UNDEF:
|
||||
case DYN_DEF * 16 + UNDEF:
|
||||
case DYN_WEAK_DEF * 16 + UNDEF:
|
||||
case UNDEF * 16 + UNDEF:
|
||||
case WEAK_UNDEF * 16 + UNDEF:
|
||||
case DYN_UNDEF * 16 + UNDEF:
|
||||
case DYN_WEAK_UNDEF * 16 + UNDEF:
|
||||
case COMMON * 16 + UNDEF:
|
||||
case WEAK_COMMON * 16 + UNDEF:
|
||||
case DYN_COMMON * 16 + UNDEF:
|
||||
case DYN_WEAK_COMMON * 16 + UNDEF:
|
||||
|
||||
case DEF * 16 + WEAK_UNDEF:
|
||||
case WEAK_DEF * 16 + WEAK_UNDEF:
|
||||
case DYN_DEF * 16 + WEAK_UNDEF:
|
||||
case DYN_WEAK_DEF * 16 + WEAK_UNDEF:
|
||||
case UNDEF * 16 + WEAK_UNDEF:
|
||||
case WEAK_UNDEF * 16 + WEAK_UNDEF:
|
||||
case DYN_UNDEF * 16 + WEAK_UNDEF:
|
||||
case DYN_WEAK_UNDEF * 16 + WEAK_UNDEF:
|
||||
case COMMON * 16 + WEAK_UNDEF:
|
||||
case WEAK_COMMON * 16 + WEAK_UNDEF:
|
||||
case DYN_COMMON * 16 + WEAK_UNDEF:
|
||||
case DYN_WEAK_COMMON * 16 + WEAK_UNDEF:
|
||||
|
||||
case DEF * 16 + DYN_UNDEF:
|
||||
case WEAK_DEF * 16 + DYN_UNDEF:
|
||||
case DYN_DEF * 16 + DYN_UNDEF:
|
||||
case DYN_WEAK_DEF * 16 + DYN_UNDEF:
|
||||
case UNDEF * 16 + DYN_UNDEF:
|
||||
case WEAK_UNDEF * 16 + DYN_UNDEF:
|
||||
case DYN_UNDEF * 16 + DYN_UNDEF:
|
||||
case DYN_WEAK_UNDEF * 16 + DYN_UNDEF:
|
||||
case COMMON * 16 + DYN_UNDEF:
|
||||
case WEAK_COMMON * 16 + DYN_UNDEF:
|
||||
case DYN_COMMON * 16 + DYN_UNDEF:
|
||||
case DYN_WEAK_COMMON * 16 + DYN_UNDEF:
|
||||
|
||||
case DEF * 16 + DYN_WEAK_UNDEF:
|
||||
case WEAK_DEF * 16 + DYN_WEAK_UNDEF:
|
||||
case DYN_DEF * 16 + DYN_WEAK_UNDEF:
|
||||
case DYN_WEAK_DEF * 16 + DYN_WEAK_UNDEF:
|
||||
case UNDEF * 16 + DYN_WEAK_UNDEF:
|
||||
case WEAK_UNDEF * 16 + DYN_WEAK_UNDEF:
|
||||
case DYN_UNDEF * 16 + DYN_WEAK_UNDEF:
|
||||
case DYN_WEAK_UNDEF * 16 + DYN_WEAK_UNDEF:
|
||||
case COMMON * 16 + DYN_WEAK_UNDEF:
|
||||
case WEAK_COMMON * 16 + DYN_WEAK_UNDEF:
|
||||
case DYN_COMMON * 16 + DYN_WEAK_UNDEF:
|
||||
case DYN_WEAK_COMMON * 16 + DYN_WEAK_UNDEF:
|
||||
|
||||
case DEF * 16 + COMMON:
|
||||
case WEAK_DEF * 16 + COMMON:
|
||||
case DYN_DEF * 16 + COMMON:
|
||||
case DYN_WEAK_DEF * 16 + COMMON:
|
||||
case UNDEF * 16 + COMMON:
|
||||
case WEAK_UNDEF * 16 + COMMON:
|
||||
case DYN_UNDEF * 16 + COMMON:
|
||||
case DYN_WEAK_UNDEF * 16 + COMMON:
|
||||
case COMMON * 16 + COMMON:
|
||||
case WEAK_COMMON * 16 + COMMON:
|
||||
case DYN_COMMON * 16 + COMMON:
|
||||
case DYN_WEAK_COMMON * 16 + COMMON:
|
||||
|
||||
case DEF * 16 + WEAK_COMMON:
|
||||
case WEAK_DEF * 16 + WEAK_COMMON:
|
||||
case DYN_DEF * 16 + WEAK_COMMON:
|
||||
case DYN_WEAK_DEF * 16 + WEAK_COMMON:
|
||||
case UNDEF * 16 + WEAK_COMMON:
|
||||
case WEAK_UNDEF * 16 + WEAK_COMMON:
|
||||
case DYN_UNDEF * 16 + WEAK_COMMON:
|
||||
case DYN_WEAK_UNDEF * 16 + WEAK_COMMON:
|
||||
case COMMON * 16 + WEAK_COMMON:
|
||||
case WEAK_COMMON * 16 + WEAK_COMMON:
|
||||
case DYN_COMMON * 16 + WEAK_COMMON:
|
||||
case DYN_WEAK_COMMON * 16 + WEAK_COMMON:
|
||||
|
||||
case DEF * 16 + DYN_COMMON:
|
||||
case WEAK_DEF * 16 + DYN_COMMON:
|
||||
case DYN_DEF * 16 + DYN_COMMON:
|
||||
case DYN_WEAK_DEF * 16 + DYN_COMMON:
|
||||
case UNDEF * 16 + DYN_COMMON:
|
||||
case WEAK_UNDEF * 16 + DYN_COMMON:
|
||||
case DYN_UNDEF * 16 + DYN_COMMON:
|
||||
case DYN_WEAK_UNDEF * 16 + DYN_COMMON:
|
||||
case COMMON * 16 + DYN_COMMON:
|
||||
case WEAK_COMMON * 16 + DYN_COMMON:
|
||||
case DYN_COMMON * 16 + DYN_COMMON:
|
||||
case DYN_WEAK_COMMON * 16 + DYN_COMMON:
|
||||
|
||||
case DEF * 16 + DYN_WEAK_COMMON:
|
||||
case WEAK_DEF * 16 + DYN_WEAK_COMMON:
|
||||
case DYN_DEF * 16 + DYN_WEAK_COMMON:
|
||||
case DYN_WEAK_DEF * 16 + DYN_WEAK_COMMON:
|
||||
case UNDEF * 16 + DYN_WEAK_COMMON:
|
||||
case WEAK_UNDEF * 16 + DYN_WEAK_COMMON:
|
||||
case DYN_UNDEF * 16 + DYN_WEAK_COMMON:
|
||||
case DYN_WEAK_UNDEF * 16 + DYN_WEAK_COMMON:
|
||||
case COMMON * 16 + DYN_WEAK_COMMON:
|
||||
case WEAK_COMMON * 16 + DYN_WEAK_COMMON:
|
||||
case DYN_COMMON * 16 + DYN_WEAK_COMMON:
|
||||
case DYN_WEAK_COMMON * 16 + DYN_WEAK_COMMON:
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Instantiate the templates we need. We could use the configure
|
||||
// script to restrict this to only the ones needed for implemented
|
||||
// targets.
|
||||
|
||||
template
|
||||
void
|
||||
Symbol_table::resolve<32, true>(
|
||||
Symbol* to,
|
||||
const elfcpp::Sym<32, true>& sym,
|
||||
Object* object);
|
||||
|
||||
template
|
||||
void
|
||||
Symbol_table::resolve<32, false>(
|
||||
Symbol* to,
|
||||
const elfcpp::Sym<32, false>& sym,
|
||||
Object* object);
|
||||
|
||||
template
|
||||
void
|
||||
Symbol_table::resolve<64, true>(
|
||||
Symbol* to,
|
||||
const elfcpp::Sym<64, true>& sym,
|
||||
Object* object);
|
||||
|
||||
template
|
||||
void
|
||||
Symbol_table::resolve<64, false>(
|
||||
Symbol* to,
|
||||
const elfcpp::Sym<64, false>& sym,
|
||||
Object* object);
|
||||
|
||||
} // End namespace gold.
|
130
gold/stringpool.cc
Normal file
130
gold/stringpool.cc
Normal file
@ -0,0 +1,130 @@
|
||||
// stringpool.cc -- a string pool for gold
|
||||
|
||||
#include "gold.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
#include "stringpool.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
Stringpool::Stringpool()
|
||||
: string_set_(), strings_()
|
||||
{
|
||||
}
|
||||
|
||||
Stringpool::~Stringpool()
|
||||
{
|
||||
for (std::list<stringdata*>::iterator p = this->strings_.begin();
|
||||
p != this->strings_.end();
|
||||
++p)
|
||||
delete[] reinterpret_cast<char*>(*p);
|
||||
}
|
||||
|
||||
// Hash function.
|
||||
|
||||
size_t
|
||||
Stringpool::Stringpool_hash::operator()(const char* s) const
|
||||
{
|
||||
// Fowler/Noll/Vo (FNV) hash (type FNV-1a).
|
||||
if (sizeof(size_t) == 8)
|
||||
{
|
||||
size_t result = 14695981039346656037ULL;
|
||||
while (*s != '\0')
|
||||
{
|
||||
result &= (size_t) *s++;
|
||||
result *= 1099511628211ULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t result = 2166136261UL;
|
||||
while (*s != '\0')
|
||||
{
|
||||
result ^= (size_t) *s++;
|
||||
result *= 16777619UL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Add a string to the list of canonical strings. Return a pointer to
|
||||
// the canonical string.
|
||||
|
||||
const char*
|
||||
Stringpool::add_string(const char* s)
|
||||
{
|
||||
const size_t buffer_size = 1000;
|
||||
size_t len = strlen(s);
|
||||
|
||||
size_t alc;
|
||||
bool front = true;
|
||||
if (len >= buffer_size)
|
||||
{
|
||||
alc = sizeof(stringdata) + len;
|
||||
front = false;
|
||||
}
|
||||
else if (this->strings_.empty())
|
||||
alc = sizeof(stringdata) + buffer_size;
|
||||
else
|
||||
{
|
||||
stringdata *psd = this->strings_.front();
|
||||
if (len >= psd->alc - psd->len)
|
||||
alc = sizeof(stringdata) + buffer_size;
|
||||
else
|
||||
{
|
||||
char* ret = psd->data + psd->len;
|
||||
memcpy(ret, s, len + 1);
|
||||
psd->len += len + 1;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
stringdata *psd = reinterpret_cast<stringdata*>(new char[alc]);
|
||||
psd->alc = alc;
|
||||
memcpy(psd->data, s, len + 1);
|
||||
psd->len = len + 1;
|
||||
if (front)
|
||||
this->strings_.push_front(psd);
|
||||
else
|
||||
this->strings_.push_back(psd);
|
||||
return psd->data;
|
||||
}
|
||||
|
||||
// Add a string to a string pool.
|
||||
|
||||
const char*
|
||||
Stringpool::add(const char* s)
|
||||
{
|
||||
// FIXME: This will look up the entry twice in the hash table. The
|
||||
// problem is that we can't insert S before we canonicalize it. I
|
||||
// don't think there is a way to handle this correct with
|
||||
// unordered_set, so this should be replaced with custom code to do
|
||||
// what we need, which is to return the empty slot.
|
||||
|
||||
String_set_type::const_iterator p = this->string_set_.find(s);
|
||||
if (p != this->string_set_.end())
|
||||
return *p;
|
||||
|
||||
const char* ret = this->add_string(s);
|
||||
std::pair<String_set_type::iterator, bool> ins =
|
||||
this->string_set_.insert(ret);
|
||||
assert(ins.second);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Add a prefix of a string to a string pool.
|
||||
|
||||
const char*
|
||||
Stringpool::add(const char* s, size_t len)
|
||||
{
|
||||
// FIXME: This implementation should be rewritten when we rewrite
|
||||
// the hash table to avoid copying.
|
||||
std::string st(s, len);
|
||||
return this->add(st);
|
||||
}
|
||||
|
||||
} // End namespace gold.
|
70
gold/stringpool.h
Normal file
70
gold/stringpool.h
Normal file
@ -0,0 +1,70 @@
|
||||
// stringpool.h -- a string pool for gold -*- C++ -*-
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
// Stringpool
|
||||
// Manage a pool of unique strings.
|
||||
|
||||
#ifndef GOLD_STRINGPOOL_H
|
||||
#define GOLD_STRINGPOOL_H
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
class Stringpool
|
||||
{
|
||||
public:
|
||||
Stringpool();
|
||||
|
||||
~Stringpool();
|
||||
|
||||
// Add a string to the pool. This returns a canonical permanent
|
||||
// pointer to the string.
|
||||
const char* add(const char*);
|
||||
|
||||
const char* add(const std::string& s)
|
||||
{ return this->add(s.c_str()); }
|
||||
|
||||
// Add the prefix of a string to the pool.
|
||||
const char* add(const char *, size_t);
|
||||
|
||||
private:
|
||||
Stringpool(const Stringpool&);
|
||||
Stringpool& operator=(const Stringpool&);
|
||||
|
||||
struct stringdata
|
||||
{
|
||||
// Length of data in buffer.
|
||||
size_t len;
|
||||
// Allocated size of buffer.
|
||||
size_t alc;
|
||||
// Buffer.
|
||||
char data[1];
|
||||
};
|
||||
|
||||
const char* add_string(const char*);
|
||||
|
||||
struct Stringpool_hash
|
||||
{
|
||||
size_t
|
||||
operator()(const char*) const;
|
||||
};
|
||||
|
||||
struct Stringpool_eq
|
||||
{
|
||||
bool
|
||||
operator()(const char* p1, const char* p2) const
|
||||
{ return strcmp(p1, p2) == 0; }
|
||||
};
|
||||
|
||||
typedef Unordered_set<const char*, Stringpool_hash, Stringpool_eq,
|
||||
std::allocator<const char*>,
|
||||
true> String_set_type;
|
||||
String_set_type string_set_;
|
||||
std::list<stringdata*> strings_;
|
||||
};
|
||||
|
||||
} // End namespace gold.
|
||||
|
||||
#endif // !defined(GOLD_STRINGPOOL_H)
|
73
gold/strtab.h
Normal file
73
gold/strtab.h
Normal file
@ -0,0 +1,73 @@
|
||||
// strtab.h -- manage an ELF string table for gold -*- C++ -*-
|
||||
|
||||
#ifndef GOLD_STRTAB_H
|
||||
#define GOLD_STRTAB_H
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
// This class holds an ELF string table. We keep a reference count
|
||||
// for each string, which we use to determine which strings are
|
||||
// actually required at the end. When all operations are done, the
|
||||
// string table is finalized, which sets the offsets to use for each
|
||||
// string.
|
||||
|
||||
class Strtab
|
||||
{
|
||||
public:
|
||||
Strtab();
|
||||
|
||||
~Strtab();
|
||||
|
||||
Strtab_ref* add(const char*);
|
||||
|
||||
Strtab_ref* add(const std::string& s)
|
||||
{ return this->add(s.c_str()); }
|
||||
|
||||
private:
|
||||
Strtab(const Strtab&);
|
||||
Strtab& operator=(const Strtab&);
|
||||
|
||||
struct strtab_hash
|
||||
{
|
||||
std::size_t
|
||||
operator()(const char*p);
|
||||
};
|
||||
|
||||
struct strtab_eq
|
||||
{
|
||||
bool
|
||||
operator()(const char* p1, const char* p2)
|
||||
{ return strcmp(p1, p2) == 0; }
|
||||
};
|
||||
|
||||
Unordered_map<const char*, Strtab_ref*, strtab_hash, strtab_eq,
|
||||
std::allocator<std::pair<const char* const, Strtab_ref*> >,
|
||||
true> strings_;
|
||||
};
|
||||
|
||||
// Users of Strtab work with pointers to Strtab_ref structures. These
|
||||
// are allocated via new and should be deleted if the string is no
|
||||
// longer needed.
|
||||
|
||||
class Strtab_ref
|
||||
{
|
||||
public:
|
||||
~Strtab_ref();
|
||||
|
||||
const char*
|
||||
str() const;
|
||||
|
||||
private:
|
||||
Strtab_ref(const Strtab_ref&);
|
||||
Strtab_ref& operator=(const Strtab_ref&);
|
||||
|
||||
int refs_;
|
||||
};
|
||||
|
||||
} // End namespace gold.
|
||||
|
||||
#endif // !defined(GOLD_STRTAB_H)
|
358
gold/symtab.cc
Normal file
358
gold/symtab.cc
Normal file
@ -0,0 +1,358 @@
|
||||
// symtab.cc -- the gold symbol table
|
||||
|
||||
#include "gold.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "object.h"
|
||||
#include "symtab.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
// Class Symbol.
|
||||
|
||||
Symbol::~Symbol()
|
||||
{
|
||||
}
|
||||
|
||||
// Initialize the fields in the base class Symbol.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
Symbol::init_base(const char* name, const char* version, Object* object,
|
||||
const elfcpp::Sym<size, big_endian>& sym)
|
||||
{
|
||||
this->name_ = name;
|
||||
this->version_ = version;
|
||||
this->object_ = object;
|
||||
this->shnum_ = sym.get_st_shndx(); // FIXME: Handle SHN_XINDEX.
|
||||
this->type_ = sym.get_st_type();
|
||||
this->binding_ = sym.get_st_bind();
|
||||
this->visibility_ = sym.get_st_visibility();
|
||||
this->other_ = sym.get_st_nonvis();
|
||||
this->special_ = false;
|
||||
this->def_ = false;
|
||||
this->forwarder_ = false;
|
||||
}
|
||||
|
||||
// Initialize the fields in Sized_symbol.
|
||||
|
||||
template<int size>
|
||||
template<bool big_endian>
|
||||
void
|
||||
Sized_symbol<size>::init(const char* name, const char* version, Object* object,
|
||||
const elfcpp::Sym<size, big_endian>& sym)
|
||||
{
|
||||
this->init_base(name, version, object, sym);
|
||||
this->value_ = sym.get_st_value();
|
||||
this->size_ = sym.get_st_size();
|
||||
}
|
||||
|
||||
// Class Symbol_table.
|
||||
|
||||
Symbol_table::Symbol_table()
|
||||
: size_(0), table_(), namepool_(), forwarders_()
|
||||
{
|
||||
}
|
||||
|
||||
Symbol_table::~Symbol_table()
|
||||
{
|
||||
}
|
||||
|
||||
// The hash function. The key is always canonicalized, so we use a
|
||||
// simple combination of the pointers.
|
||||
|
||||
size_t
|
||||
Symbol_table::Symbol_table_hash::operator()(const Symbol_table_key& key) const
|
||||
{
|
||||
return (reinterpret_cast<size_t>(key.first)
|
||||
^ reinterpret_cast<size_t>(key.second));
|
||||
}
|
||||
|
||||
// The symbol table key equality function. This is only called with
|
||||
// canonicalized name and version strings, so we can use pointer
|
||||
// comparison.
|
||||
|
||||
bool
|
||||
Symbol_table::Symbol_table_eq::operator()(const Symbol_table_key& k1,
|
||||
const Symbol_table_key& k2) const
|
||||
{
|
||||
return k1.first == k2.first && k1.second == k2.second;
|
||||
}
|
||||
|
||||
// Make TO a symbol which forwards to FROM.
|
||||
|
||||
void
|
||||
Symbol_table::make_forwarder(Symbol* from, Symbol* to)
|
||||
{
|
||||
assert(!from->is_forwarder() && !to->is_forwarder());
|
||||
this->forwarders_[from] = to;
|
||||
from->set_forwarder();
|
||||
}
|
||||
|
||||
Symbol*
|
||||
Symbol_table::resolve_forwards(Symbol* from) const
|
||||
{
|
||||
assert(from->is_forwarder());
|
||||
Unordered_map<Symbol*, Symbol*>::const_iterator p =
|
||||
this->forwarders_.find(from);
|
||||
assert(p != this->forwarders_.end());
|
||||
return p->second;
|
||||
}
|
||||
|
||||
// Resolve a Symbol with another Symbol. This is only used in the
|
||||
// unusual case where there are references to both an unversioned
|
||||
// symbol and a symbol with a version, and we then discover that that
|
||||
// version is the default version.
|
||||
|
||||
void
|
||||
Symbol_table::resolve(Symbol*, const Symbol*)
|
||||
{
|
||||
}
|
||||
|
||||
// Add one symbol from OBJECT to the symbol table. NAME is symbol
|
||||
// name and VERSION is the version; both are canonicalized. DEF is
|
||||
// whether this is the default version.
|
||||
|
||||
// If DEF is true, then this is the definition of a default version of
|
||||
// a symbol. That means that any lookup of NAME/NULL and any lookup
|
||||
// of NAME/VERSION should always return the same symbol. This is
|
||||
// obvious for references, but in particular we want to do this for
|
||||
// definitions: overriding NAME/NULL should also override
|
||||
// NAME/VERSION. If we don't do that, it would be very hard to
|
||||
// override functions in a shared library which uses versioning.
|
||||
|
||||
// We implement this by simply making both entries in the hash table
|
||||
// point to the same Symbol structure. That is easy enough if this is
|
||||
// the first time we see NAME/NULL or NAME/VERSION, but it is possible
|
||||
// that we have seen both already, in which case they will both have
|
||||
// independent entries in the symbol table. We can't simply change
|
||||
// the symbol table entry, because we have pointers to the entries
|
||||
// attached to the object files. So we mark the entry attached to the
|
||||
// object file as a forwarder, and record it in the forwarders_ map.
|
||||
// Note that entries in the hash table will never be marked as
|
||||
// forwarders.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
Symbol*
|
||||
Symbol_table::add_from_object(Sized_object<size, big_endian>* object,
|
||||
const char *name,
|
||||
const char *version, bool def,
|
||||
const elfcpp::Sym<size, big_endian>& sym)
|
||||
{
|
||||
Symbol* const snull = NULL;
|
||||
std::pair<typename Symbol_table_type::iterator, bool> ins =
|
||||
this->table_.insert(std::make_pair(std::make_pair(name, version), snull));
|
||||
|
||||
std::pair<typename Symbol_table_type::iterator, bool> insdef =
|
||||
std::make_pair(this->table_.end(), false);
|
||||
if (def)
|
||||
{
|
||||
const char* const vnull = NULL;
|
||||
insdef = this->table_.insert(std::make_pair(std::make_pair(name, vnull),
|
||||
snull));
|
||||
}
|
||||
|
||||
// ins.first: an iterator, which is a pointer to a pair.
|
||||
// ins.first->first: the key (a pair of name and version).
|
||||
// ins.first->second: the value (Symbol*).
|
||||
// ins.second: true if new entry was inserted, false if not.
|
||||
|
||||
Symbol* ret;
|
||||
if (!ins.second)
|
||||
{
|
||||
// We already have an entry for NAME/VERSION.
|
||||
ret = ins.first->second;
|
||||
assert(ret != NULL);
|
||||
Symbol_table::resolve(ret, sym, object);
|
||||
|
||||
if (def)
|
||||
{
|
||||
if (insdef.second)
|
||||
{
|
||||
// This is the first time we have seen NAME/NULL. Make
|
||||
// NAME/NULL point to NAME/VERSION.
|
||||
insdef.first->second = ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is the unfortunate case where we already have
|
||||
// entries for both NAME/VERSION and NAME/NULL.
|
||||
Symbol_table::resolve(ret, insdef.first->second);
|
||||
this->make_forwarder(insdef.first->second, ret);
|
||||
insdef.first->second = ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is the first time we have seen NAME/VERSION.
|
||||
assert(ins.first->second == NULL);
|
||||
if (def && !insdef.second)
|
||||
{
|
||||
// We already have an entry for NAME/NULL. Make
|
||||
// NAME/VERSION point to it.
|
||||
ret = insdef.first->second;
|
||||
Symbol_table::resolve(ret, sym, object);
|
||||
ins.first->second = ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
Sized_symbol<size>* rs;
|
||||
Sized_target<size, big_endian>* target = object->sized_target();
|
||||
if (target->has_make_symbol())
|
||||
{
|
||||
rs = target->make_symbol();
|
||||
if (rs == NULL)
|
||||
{
|
||||
// This means that we don't want a symbol table
|
||||
// entry after all.
|
||||
if (!def)
|
||||
this->table_.erase(ins.first);
|
||||
else
|
||||
{
|
||||
this->table_.erase(insdef.first);
|
||||
// Inserting insdef invalidated ins.
|
||||
this->table_.erase(std::make_pair(name, version));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
rs = new Sized_symbol<size>();
|
||||
rs->init(name, version, object, sym);
|
||||
|
||||
ret = rs;
|
||||
ins.first->second = ret;
|
||||
if (def)
|
||||
{
|
||||
// This is the first time we have seen NAME/NULL. Point
|
||||
// it at the new entry for NAME/VERSION.
|
||||
assert(insdef.second);
|
||||
insdef.first->second = ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Add all the symbols in an object to the hash table.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
Symbol_table::add_from_object(
|
||||
Sized_object<size, big_endian>* object,
|
||||
const elfcpp::Sym<size, big_endian>* syms,
|
||||
size_t count,
|
||||
const char* sym_names,
|
||||
size_t sym_name_size,
|
||||
Symbol** sympointers)
|
||||
{
|
||||
// We take the size from the first object we see.
|
||||
if (this->get_size() == 0)
|
||||
this->set_size(size);
|
||||
|
||||
if (size != this->get_size() || size != object->target()->get_size())
|
||||
{
|
||||
fprintf(stderr, _("%s: %s: mixing 32-bit and 64-bit ELF objects\n"),
|
||||
program_name, object->name().c_str());
|
||||
gold_exit(false);
|
||||
}
|
||||
|
||||
const unsigned char* p = reinterpret_cast<const unsigned char*>(syms);
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
{
|
||||
elfcpp::Sym<size, big_endian> sym(p);
|
||||
|
||||
unsigned int st_name = sym.get_st_name();
|
||||
if (st_name >= sym_name_size)
|
||||
{
|
||||
fprintf(stderr, _("%s: %s: bad symbol name offset %u at %lu\n"),
|
||||
program_name, object->name().c_str(), st_name,
|
||||
static_cast<unsigned long>(i));
|
||||
gold_exit(false);
|
||||
}
|
||||
|
||||
const char* name = sym_names + st_name;
|
||||
|
||||
// In an object file, an '@' in the name separates the symbol
|
||||
// name from the version name. If there are two '@' characters,
|
||||
// this is the default version.
|
||||
const char* ver = strchr(name, '@');
|
||||
|
||||
Symbol* res;
|
||||
if (ver == NULL)
|
||||
{
|
||||
name = this->namepool_.add(name);
|
||||
res = this->add_from_object(object, name, NULL, false, sym);
|
||||
}
|
||||
else
|
||||
{
|
||||
name = this->namepool_.add(name, ver - name);
|
||||
bool def = false;
|
||||
++ver;
|
||||
if (*ver == '@')
|
||||
{
|
||||
def = true;
|
||||
++ver;
|
||||
}
|
||||
ver = this->namepool_.add(ver);
|
||||
res = this->add_from_object(object, name, ver, def, sym);
|
||||
}
|
||||
|
||||
*sympointers++ = res;
|
||||
|
||||
p += elfcpp::Elf_sizes<size>::sym_size;
|
||||
}
|
||||
}
|
||||
|
||||
// Instantiate the templates we need. We could use the configure
|
||||
// script to restrict this to only the ones needed for implemented
|
||||
// targets.
|
||||
|
||||
template
|
||||
void
|
||||
Symbol_table::add_from_object<32, true>(
|
||||
Sized_object<32, true>* object,
|
||||
const elfcpp::Sym<32, true>* syms,
|
||||
size_t count,
|
||||
const char* sym_names,
|
||||
size_t sym_name_size,
|
||||
Symbol** sympointers);
|
||||
|
||||
template
|
||||
void
|
||||
Symbol_table::add_from_object<32, false>(
|
||||
Sized_object<32, false>* object,
|
||||
const elfcpp::Sym<32, false>* syms,
|
||||
size_t count,
|
||||
const char* sym_names,
|
||||
size_t sym_name_size,
|
||||
Symbol** sympointers);
|
||||
|
||||
template
|
||||
void
|
||||
Symbol_table::add_from_object<64, true>(
|
||||
Sized_object<64, true>* object,
|
||||
const elfcpp::Sym<64, true>* syms,
|
||||
size_t count,
|
||||
const char* sym_names,
|
||||
size_t sym_name_size,
|
||||
Symbol** sympointers);
|
||||
|
||||
template
|
||||
void
|
||||
Symbol_table::add_from_object<64, false>(
|
||||
Sized_object<64, false>* object,
|
||||
const elfcpp::Sym<64, false>* syms,
|
||||
size_t count,
|
||||
const char* sym_names,
|
||||
size_t sym_name_size,
|
||||
Symbol** sympointers);
|
||||
|
||||
} // End namespace gold.
|
216
gold/symtab.h
216
gold/symtab.h
@ -3,15 +3,12 @@
|
||||
// Symbol_table
|
||||
// The symbol table.
|
||||
|
||||
#include "gold.h"
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "elfcpp.h"
|
||||
#include "targetsize.h"
|
||||
#include "object.h"
|
||||
#include "workqueue.h"
|
||||
#include "stringpool.h"
|
||||
|
||||
#ifndef GOLD_SYMTAB_H
|
||||
#define GOLD_SYMTAB_H
|
||||
@ -19,60 +16,221 @@
|
||||
namespace gold
|
||||
{
|
||||
|
||||
// An entry in the symbol table. The symbol table can have a lot of
|
||||
// entries, so we don't want this class to get too big.
|
||||
class Object;
|
||||
|
||||
template<int size, bool big_endian>
|
||||
class Sized_object;
|
||||
|
||||
template<int size, bool big_endian>
|
||||
class Sized_target;
|
||||
|
||||
// The base class of an entry in the symbol table. The symbol table
|
||||
// can have a lot of entries, so we don't want this class to big.
|
||||
// Size dependent fields can be found in the template class
|
||||
// Sized_symbol. Targets may support their own derived classes.
|
||||
|
||||
template<int size>
|
||||
class Symbol
|
||||
{
|
||||
public:
|
||||
typedef typename elfcpp::Elf_types<size>::Elf_Addr Value;
|
||||
typedef typename Size_types<size>::Unsigned_type Size;
|
||||
virtual ~Symbol();
|
||||
|
||||
// Return the symbol name.
|
||||
const char*
|
||||
name() const
|
||||
{ return this->name_; }
|
||||
|
||||
// Return the symbol version. This will return NULL for an
|
||||
// unversioned symbol.
|
||||
const char*
|
||||
version() const
|
||||
{ return this->version_; }
|
||||
|
||||
// Return whether this symbol is a forwarder. This will never be
|
||||
// true of a symbol found in the hash table, but may be true of
|
||||
// symbol pointers attached to object files.
|
||||
bool
|
||||
is_forwarder() const
|
||||
{ return this->forwarder_; }
|
||||
|
||||
// Mark this symbol as a forwarder.
|
||||
void
|
||||
set_forwarder()
|
||||
{ this->forwarder_ = true; }
|
||||
|
||||
// Return the object with which this symbol is associated.
|
||||
Object*
|
||||
object() const
|
||||
{ return this->object_; }
|
||||
|
||||
// Return the symbol binding.
|
||||
elfcpp::STB
|
||||
binding() const
|
||||
{ return this->binding_; }
|
||||
|
||||
// Return the section index.
|
||||
unsigned int
|
||||
shnum() const
|
||||
{ return this->shnum_; }
|
||||
|
||||
protected:
|
||||
// Instances of this class should always be created at a specific
|
||||
// size.
|
||||
Symbol()
|
||||
{ }
|
||||
|
||||
// Initialize fields from an ELF symbol in OBJECT.
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
init_base(const char *name, const char* version, Object* object,
|
||||
const elfcpp::Sym<size, big_endian>&);
|
||||
|
||||
private:
|
||||
// Every symbol has a unique name, more or less, so we use
|
||||
// std::string for the name. There are only a few versions in a
|
||||
// given link, so for them we point into a pool.
|
||||
std::string name_;
|
||||
Symbol(const Symbol&);
|
||||
Symbol& operator=(const Symbol&);
|
||||
|
||||
// Symbol name (expected to point into a Stringpool).
|
||||
const char* name_;
|
||||
// Symbol version (expected to point into a Stringpool). This may
|
||||
// be NULL.
|
||||
const char* version_;
|
||||
// Object in which symbol is defined, or in which it was first seen.
|
||||
Object* object_;
|
||||
// Section number in object_ in which symbol is defined.
|
||||
unsigned int shnum_;
|
||||
Value value_;
|
||||
Size size_;
|
||||
// Symbol type.
|
||||
elfcpp::STT type_ : 4;
|
||||
// Symbol binding.
|
||||
elfcpp::STB binding_ : 4;
|
||||
elfcpp:STV visibility_ : 2;
|
||||
// Symbol visibility.
|
||||
elfcpp::STV visibility_ : 2;
|
||||
// Rest of symbol st_other field.
|
||||
unsigned int other_ : 6;
|
||||
// True if this symbol always requires special target-specific
|
||||
// handling.
|
||||
bool special_ : 1;
|
||||
// True if this is the default version of the symbol.
|
||||
bool def_ : 1;
|
||||
// True if this symbol really forwards to another symbol. This is
|
||||
// used when we discover after the fact that two different entries
|
||||
// in the hash table really refer to the same symbol. This will
|
||||
// never be set for a symbol found in the hash table, but may be set
|
||||
// for a symbol found in the list of symbols attached to an Object.
|
||||
// It forwards to the symbol found in the forwarders_ map of
|
||||
// Symbol_table.
|
||||
bool forwarder_ : 1;
|
||||
};
|
||||
|
||||
// The parts of a symbol which are size specific. Using a template
|
||||
// derived class like this helps us use less space on a 32-bit system.
|
||||
|
||||
template<int size>
|
||||
class Sized_symbol : public Symbol
|
||||
{
|
||||
public:
|
||||
Sized_symbol()
|
||||
{ }
|
||||
|
||||
// Initialize fields from an ELF symbol in OBJECT.
|
||||
template<bool big_endian>
|
||||
void
|
||||
init(const char *name, const char* version, Object* object,
|
||||
const elfcpp::Sym<size, big_endian>&);
|
||||
|
||||
private:
|
||||
Sized_symbol(const Sized_symbol&);
|
||||
Sized_symbol& operator=(const Sized_symbol&);
|
||||
|
||||
// Symbol value.
|
||||
typename elfcpp::Elf_types<size>::Elf_Addr value_;
|
||||
// Symbol size.
|
||||
typename elfcpp::Elf_types<size>::Elf_WXword size_;
|
||||
};
|
||||
|
||||
// The main linker symbol table.
|
||||
|
||||
template<int size>
|
||||
class Symbol_table
|
||||
{
|
||||
public:
|
||||
Symbol_table();
|
||||
|
||||
// Return a pointer to a symbol specified by name.
|
||||
Symbol*
|
||||
lookup(const std::string& name) const;
|
||||
virtual ~Symbol_table();
|
||||
|
||||
// Return a pointer to a symbol specified by name plus version.
|
||||
Symbol*
|
||||
lookup(const std::string& name, const char* version) const;
|
||||
// Add COUNT external symbols from OBJECT to the symbol table. SYMS
|
||||
// is the symbols, SYM_NAMES is their names, SYM_NAME_SIZE is the
|
||||
// size of SYM_NAMES. This sets SYMPOINTERS to point to the symbols
|
||||
// in the symbol table.
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
add_from_object(Sized_object<size, big_endian>* object,
|
||||
const elfcpp::Sym<size, big_endian>* syms,
|
||||
size_t count, const char* sym_names, size_t sym_name_size,
|
||||
Symbol** sympointers);
|
||||
|
||||
Task_token&
|
||||
token() const
|
||||
{ return this->token_; }
|
||||
// Return the real symbol associated with the forwarder symbol FROM.
|
||||
Symbol*
|
||||
resolve_forwards(Symbol* from) const;
|
||||
|
||||
// Return the size of the symbols in the table.
|
||||
int
|
||||
get_size() const
|
||||
{ return this->size_; }
|
||||
|
||||
private:
|
||||
Symbol_table(const Symbol_table&);
|
||||
Symbol_table& operator=(const Symbol_table&);
|
||||
|
||||
typedef std::pair<std::string, std::string> Symbol_table_key;
|
||||
// Set the size of the symbols in the table.
|
||||
void
|
||||
set_size(int size)
|
||||
{ this->size_ = size; }
|
||||
|
||||
Unordered_map<Symbol_table_key, Symbol<size>*> table_;
|
||||
Task_token token_;
|
||||
// Make FROM a forwarder symbol to TO.
|
||||
void
|
||||
make_forwarder(Symbol* from, Symbol* to);
|
||||
|
||||
// Add a symbol.
|
||||
template<int size, bool big_endian>
|
||||
Symbol*
|
||||
add_from_object(Sized_object<size, big_endian>*, const char *name,
|
||||
const char *version, bool def,
|
||||
const elfcpp::Sym<size, big_endian>& sym);
|
||||
|
||||
// Resolve symbols.
|
||||
template<int size, bool big_endian>
|
||||
static void
|
||||
resolve(Symbol* to, const elfcpp::Sym<size, big_endian>& sym, Object*);
|
||||
|
||||
static void
|
||||
resolve(Symbol* to, const Symbol* from);
|
||||
|
||||
typedef std::pair<const char*, const char*> Symbol_table_key;
|
||||
|
||||
struct Symbol_table_hash
|
||||
{
|
||||
size_t
|
||||
operator()(const Symbol_table_key&) const;
|
||||
};
|
||||
|
||||
struct Symbol_table_eq
|
||||
{
|
||||
bool
|
||||
operator()(const Symbol_table_key&, const Symbol_table_key&) const;
|
||||
};
|
||||
|
||||
typedef Unordered_map<Symbol_table_key, Symbol*, Symbol_table_hash,
|
||||
Symbol_table_eq> Symbol_table_type;
|
||||
|
||||
// The size of the symbols in the symbol table (32 or 64).
|
||||
int size_;
|
||||
|
||||
// The symbol table itself.
|
||||
Symbol_table_type table_;
|
||||
|
||||
// A pool of symbol names.
|
||||
Stringpool namepool_;
|
||||
|
||||
// Forwarding symbols.
|
||||
Unordered_map<Symbol*, Symbol*> forwarders_;
|
||||
};
|
||||
|
||||
} // End namespace gold.
|
||||
|
52
gold/target-select.cc
Normal file
52
gold/target-select.cc
Normal file
@ -0,0 +1,52 @@
|
||||
// target-select.cc -- select a target for an object file
|
||||
|
||||
#include "gold.h"
|
||||
|
||||
#include "elfcpp.h"
|
||||
#include "target-select.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// The start of the list of target selectors.
|
||||
|
||||
gold::Target_selector* target_selectors;
|
||||
|
||||
} // End anonymous namespace.
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
// Construct a Target_selector, which means adding it to the linked
|
||||
// list. This runs at global constructor time, so we want it to be
|
||||
// fast.
|
||||
|
||||
Target_selector::Target_selector(int machine, int size, bool big_endian)
|
||||
: machine_(machine), size_(size), big_endian_(big_endian)
|
||||
{
|
||||
this->next_ = target_selectors;
|
||||
target_selectors = this;
|
||||
}
|
||||
|
||||
// Find the target for an ELF file.
|
||||
|
||||
extern Target*
|
||||
select_target(int machine, int size, bool big_endian, int osabi,
|
||||
int abiversion)
|
||||
{
|
||||
for (const Target_selector* p = target_selectors; p != NULL; p = p->next())
|
||||
{
|
||||
int pmach = p->machine();
|
||||
if ((pmach == machine || pmach == elfcpp::EM_NONE)
|
||||
&& p->size() == size
|
||||
&& p->big_endian() ? big_endian : !big_endian)
|
||||
{
|
||||
Target* ret = p->recognize(machine, osabi, abiversion);
|
||||
if (ret != NULL)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} // End namespace gold.
|
69
gold/target-select.h
Normal file
69
gold/target-select.h
Normal file
@ -0,0 +1,69 @@
|
||||
// target-select.h -- select a target for an object file -*- C++ -*-
|
||||
|
||||
#ifndef GOLD_TARGET_SELECT_H
|
||||
#define GOLD_TARGET_SELECT_H
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
class Target;
|
||||
|
||||
// We want to avoid a master list of targets, which implies using a
|
||||
// global constructor. And we also want the program to start up as
|
||||
// quickly as possible, which implies avoiding global constructors.
|
||||
// We compromise on a very simple global constructor. We use a target
|
||||
// selector, which specifies an ELF machine number and a recognition
|
||||
// function. We use global constructors to build a linked list of
|
||||
// target selectors--a simple pointer list, not a std::list.
|
||||
|
||||
class Target_selector
|
||||
{
|
||||
public:
|
||||
// Create a target selector for a specific machine number, size (32
|
||||
// or 64), and endianness. The machine number can be EM_NONE to
|
||||
// test for any machine number.
|
||||
Target_selector(int machine, int size, bool big_endian);
|
||||
|
||||
virtual ~Target_selector()
|
||||
{ }
|
||||
|
||||
// If we can handle this target, return a pointer to a target
|
||||
// structure. The size and endianness are known.
|
||||
virtual Target* recognize(int machine, int osabi, int abiversion) const = 0;
|
||||
|
||||
// Return the next Target_selector in the linked list.
|
||||
Target_selector*
|
||||
next() const
|
||||
{ return this->next_; }
|
||||
|
||||
// Return the machine number this selector is looking for, which can
|
||||
// be EM_NONE to match any machine number.
|
||||
int
|
||||
machine() const
|
||||
{ return this->machine_; }
|
||||
|
||||
// Return the size this is looking for (32 or 64).
|
||||
int
|
||||
size() const
|
||||
{ return this->size_; }
|
||||
|
||||
// Return the endianness this is looking for.
|
||||
bool
|
||||
big_endian() const
|
||||
{ return this->big_endian_; }
|
||||
|
||||
private:
|
||||
int machine_;
|
||||
int size_;
|
||||
bool big_endian_;
|
||||
Target_selector* next_;
|
||||
};
|
||||
|
||||
// Select the target for an ELF file.
|
||||
|
||||
extern Target* select_target(int machine, int size, bool big_endian,
|
||||
int osabi, int abiversion);
|
||||
|
||||
} // End namespace gold.
|
||||
|
||||
#endif // !defined(GOLD_TARGET_SELECT_H)
|
@ -1,4 +1,4 @@
|
||||
// target.h -- target support for gold
|
||||
// target.h -- target support for gold -*- C++ -*-
|
||||
|
||||
// The abstract class Target is the interface for target specific
|
||||
// support. It defines abstract methods which each target must
|
||||
@ -13,16 +13,103 @@
|
||||
#ifndef GOLD_TARGET_H
|
||||
#define GOLD_TARGET_H
|
||||
|
||||
#include "symtab.h"
|
||||
#include "elfcpp.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
class Object;
|
||||
|
||||
// The abstract class for target specific handling.
|
||||
|
||||
class Target
|
||||
{
|
||||
public:
|
||||
virtual ~Target()
|
||||
{ }
|
||||
|
||||
// Return the bit size that this target implements. This should
|
||||
// return 32 or 64.
|
||||
int
|
||||
get_size() const
|
||||
{ return this->size_; }
|
||||
|
||||
// Return whether this target is big-endian.
|
||||
bool
|
||||
is_big_endian() const
|
||||
{ return this->is_big_endian_; }
|
||||
|
||||
// Whether this target has a specific make_symbol function.
|
||||
bool
|
||||
has_make_symbol() const
|
||||
{ return this->has_make_symbol_; }
|
||||
|
||||
// Whether this target has a specific resolve function.
|
||||
bool
|
||||
has_resolve() const
|
||||
{ return this->has_resolve_; }
|
||||
|
||||
// Resolve a symbol. This is called when we see a symbol with a
|
||||
// target specific binding (STB_LOOS through STB_HIOS or STB_LOPROC
|
||||
// through STB_HIPROC). TO is a pre-existing symbol. SYM is the
|
||||
// new symbol, seen in OBJECT. This returns true on success, false
|
||||
// if the symbol can not be resolved.
|
||||
template<int size, bool big_endian>
|
||||
bool
|
||||
resolve(Sized_symbol<size>* to, const elfcpp::Sym<size, big_endian>& sym,
|
||||
Object* object);
|
||||
|
||||
protected:
|
||||
Target(int size, bool is_big_endian, bool has_make_symbol, bool has_resolve)
|
||||
: size_(size),
|
||||
is_big_endian_(is_big_endian),
|
||||
has_make_symbol_(has_make_symbol),
|
||||
has_resolve_(has_resolve)
|
||||
{ }
|
||||
|
||||
private:
|
||||
Target(const Target&);
|
||||
Target& operator=(const Target&);
|
||||
|
||||
// The target size.
|
||||
int size_;
|
||||
// Whether this target is big endian.
|
||||
bool is_big_endian_;
|
||||
// Whether this target has a special make_symbol function.
|
||||
bool has_make_symbol_;
|
||||
// Whether this target has a special resolve function.
|
||||
bool has_resolve_;
|
||||
};
|
||||
|
||||
extern Target* select_target(int machine, int size, bool big_endian,
|
||||
int osabi, int abiversion);
|
||||
// The abstract class for a specific size and endianness of target.
|
||||
// Each actual target implementation class should derive from an
|
||||
// instantiation of Sized_target.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
class Sized_target : public Target
|
||||
{
|
||||
public:
|
||||
// Make a new symbol table entry for the target. This should be
|
||||
// overridden by a target which needs additional information in the
|
||||
// symbol table. This will only be called if has_make_symbol()
|
||||
// returns true.
|
||||
virtual Sized_symbol<size>*
|
||||
make_symbol()
|
||||
{ abort(); }
|
||||
|
||||
// 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.
|
||||
virtual void
|
||||
resolve(Symbol*, const elfcpp::Sym<size, big_endian>&, Object*)
|
||||
{ abort(); }
|
||||
|
||||
protected:
|
||||
Sized_target(bool has_make_symbol, bool has_resolve)
|
||||
: Target(size, big_endian, has_make_symbol, has_resolve)
|
||||
{ }
|
||||
};
|
||||
|
||||
} // End namespace gold.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user