aboutsummaryrefslogtreecommitdiff
path: root/gold
diff options
context:
space:
mode:
Diffstat (limited to 'gold')
-rw-r--r--gold/Makefile.am15
-rw-r--r--gold/Makefile.in27
-rw-r--r--gold/gold.cc10
-rw-r--r--gold/i386.cc47
-rw-r--r--gold/object.cc65
-rw-r--r--gold/object.h74
-rw-r--r--gold/po/POTFILES.in7
-rw-r--r--gold/po/gold.pot59
-rw-r--r--gold/readsyms.cc5
-rw-r--r--gold/readsyms.h16
-rw-r--r--gold/resolve.cc349
-rw-r--r--gold/stringpool.cc130
-rw-r--r--gold/stringpool.h70
-rw-r--r--gold/strtab.h73
-rw-r--r--gold/symtab.cc358
-rw-r--r--gold/symtab.h214
-rw-r--r--gold/target-select.cc52
-rw-r--r--gold/target-select.h69
-rw-r--r--gold/target.h93
19 files changed, 1625 insertions, 108 deletions
diff --git a/gold/Makefile.am b/gold/Makefile.am
index acff0a4..a01aef4 100644
--- a/gold/Makefile.am
+++ b/gold/Makefile.am
@@ -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)
diff --git a/gold/Makefile.in b/gold/Makefile.in
index 31a01c4..8881517 100644
--- a/gold/Makefile.in
+++ b/gold/Makefile.in
@@ -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:
diff --git a/gold/gold.cc b/gold/gold.cc
index fd349dd..e419f9c 100644
--- a/gold/gold.cc
+++ b/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();
diff --git a/gold/i386.cc b/gold/i386.cc
new file mode 100644
index 0000000..5ecd2e3
--- /dev/null
+++ b/gold/i386.cc
@@ -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.
diff --git a/gold/object.cc b/gold/object.cc
index 8835915..bad7f47 100644
--- a/gold/object.cc
+++ b/gold/object.cc
@@ -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.
diff --git a/gold/object.h b/gold/object.h
index 9d63b11..b0ee015 100644
--- a/gold/object.h
+++ b/gold/object.h
@@ -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,
diff --git a/gold/po/POTFILES.in b/gold/po/POTFILES.in
index e0cca00..35c5094 100644
--- a/gold/po/POTFILES.in
+++ b/gold/po/POTFILES.in
@@ -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
diff --git a/gold/po/gold.pot b/gold/po/gold.pot
index 604b371..35860a5 100644
--- a/gold/po/gold.pot
+++ b/gold/po/gold.pot
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2006-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 ""
diff --git a/gold/readsyms.cc b/gold/readsyms.cc
index 30b341c..1076e6c 100644
--- a/gold/readsyms.cc
+++ b/gold/readsyms.cc
@@ -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.
diff --git a/gold/readsyms.h b/gold/readsyms.h
index bad96c1..f01cf61 100644
--- a/gold/readsyms.h
+++ b/gold/readsyms.h
@@ -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_;
diff --git a/gold/resolve.cc b/gold/resolve.cc
new file mode 100644
index 0000000..8c7d828
--- /dev/null
+++ b/gold/resolve.cc
@@ -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.
diff --git a/gold/stringpool.cc b/gold/stringpool.cc
new file mode 100644
index 0000000..0368014
--- /dev/null
+++ b/gold/stringpool.cc
@@ -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.
diff --git a/gold/stringpool.h b/gold/stringpool.h
new file mode 100644
index 0000000..873c26a
--- /dev/null
+++ b/gold/stringpool.h
@@ -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)
diff --git a/gold/strtab.h b/gold/strtab.h
new file mode 100644
index 0000000..ab22b8f
--- /dev/null
+++ b/gold/strtab.h
@@ -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)
diff --git a/gold/symtab.cc b/gold/symtab.cc
new file mode 100644
index 0000000..a410db3
--- /dev/null
+++ b/gold/symtab.cc
@@ -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.
diff --git a/gold/symtab.h b/gold/symtab.h
index 1495fb1..c085dd9 100644
--- a/gold/symtab.h
+++ b/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 main linker symbol table.
+// 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.
+
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.
+ // 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);
+
+ // Return the real symbol associated with the forwarder symbol FROM.
Symbol*
- lookup(const std::string& name, const char* version) const;
+ resolve_forwards(Symbol* from) const;
- Task_token&
- token() const
- { return this->token_; }
+ // 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; }
+
+ // 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_;
- Unordered_map<Symbol_table_key, Symbol<size>*> table_;
- Task_token token_;
+ // Forwarding symbols.
+ Unordered_map<Symbol*, Symbol*> forwarders_;
};
} // End namespace gold.
diff --git a/gold/target-select.cc b/gold/target-select.cc
new file mode 100644
index 0000000..28b7527
--- /dev/null
+++ b/gold/target-select.cc
@@ -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.
diff --git a/gold/target-select.h b/gold/target-select.h
new file mode 100644
index 0000000..0762d58
--- /dev/null
+++ b/gold/target-select.h
@@ -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)
diff --git a/gold/target.h b/gold/target.h
index 1f1c575..236185b 100644
--- a/gold/target.h
+++ b/gold/target.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.