summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@google.com>2006-12-06 00:02:36 +0000
committerIan Lance Taylor <iant@google.com>2006-12-06 00:02:36 +0000
commitc2aa2fc56cd93edf9193a29e3dfdfc1ffcc6947d (patch)
tree71dbf48e0f8ac31a259e87eecaa12eb2b0e9bc29
parent8a4e374664a48cb6ccf12c0806e6589a04226d38 (diff)
downloadbinutils-redhat-c2aa2fc56cd93edf9193a29e3dfdfc1ffcc6947d.tar.gz
Generate version information.
-rw-r--r--elfcpp/elfcpp.h128
-rw-r--r--gold/dynobj.cc841
-rw-r--r--gold/dynobj.h319
-rw-r--r--gold/i386.cc14
-rw-r--r--gold/layout.cc179
-rw-r--r--gold/layout.h22
-rw-r--r--gold/output.h8
-rw-r--r--gold/po/gold.pot59
-rw-r--r--gold/reloc.cc2
-rw-r--r--gold/resolve.cc65
-rw-r--r--gold/symtab.cc186
-rw-r--r--gold/symtab.h76
-rw-r--r--gold/target.h8
13 files changed, 1560 insertions, 347 deletions
diff --git a/elfcpp/elfcpp.h b/elfcpp/elfcpp.h
index ba85b3d5b2..305487f8bf 100644
--- a/elfcpp/elfcpp.h
+++ b/elfcpp/elfcpp.h
@@ -692,6 +692,11 @@ struct Elf_sizes
static const int rela_size = sizeof(internal::Rela_data<size>);
// Size of ELF dynamic entry.
static const int dyn_size = sizeof(internal::Dyn_data<size>);
+ // Size of ELF version structures.
+ static const int verdef_size = sizeof(internal::Verdef_data);
+ static const int verdaux_size = sizeof(internal::Verdaux_data);
+ static const int verneed_size = sizeof(internal::Verneed_data);
+ static const int vernaux_size = sizeof(internal::Vernaux_data);
};
// Accessor class for the ELF file header.
@@ -1378,6 +1383,46 @@ class Verdef
const internal::Verdef_data* p_;
};
+template<int size, bool big_endian>
+class Verdef_write
+{
+ public:
+ Verdef_write(unsigned char* p)
+ : p_(reinterpret_cast<internal::Verdef_data*>(p))
+ { }
+
+ void
+ set_vd_version(Elf_Half v)
+ { this->p_->vd_version = Convert<16, big_endian>::convert_host(v); }
+
+ void
+ set_vd_flags(Elf_Half v)
+ { this->p_->vd_flags = Convert<16, big_endian>::convert_host(v); }
+
+ void
+ set_vd_ndx(Elf_Half v)
+ { this->p_->vd_ndx = Convert<16, big_endian>::convert_host(v); }
+
+ void
+ set_vd_cnt(Elf_Half v)
+ { this->p_->vd_cnt = Convert<16, big_endian>::convert_host(v); }
+
+ void
+ set_vd_hash(Elf_Word v)
+ { this->p_->vd_hash = Convert<32, big_endian>::convert_host(v); }
+
+ void
+ set_vd_aux(Elf_Word v)
+ { this->p_->vd_aux = Convert<32, big_endian>::convert_host(v); }
+
+ void
+ set_vd_next(Elf_Word v)
+ { this->p_->vd_next = Convert<32, big_endian>::convert_host(v); }
+
+ private:
+ internal::Verdef_data* p_;
+};
+
// Accessor classes for auxiliary entries in the ELF SHT_GNU_verdef
// section.
@@ -1407,6 +1452,26 @@ class Verdaux
const internal::Verdaux_data* p_;
};
+template<int size, bool big_endian>
+class Verdaux_write
+{
+ public:
+ Verdaux_write(unsigned char* p)
+ : p_(reinterpret_cast<internal::Verdaux_data*>(p))
+ { }
+
+ void
+ set_vda_name(Elf_Word v)
+ { this->p_->vda_name = Convert<32, big_endian>::convert_host(v); }
+
+ void
+ set_vda_next(Elf_Word v)
+ { this->p_->vda_next = Convert<32, big_endian>::convert_host(v); }
+
+ private:
+ internal::Verdaux_data* p_;
+};
+
// Accessor classes for entries in the ELF SHT_GNU_verneed section.
template<int size, bool big_endian>
@@ -1447,6 +1512,38 @@ class Verneed
const internal::Verneed_data* p_;
};
+template<int size, bool big_endian>
+class Verneed_write
+{
+ public:
+ Verneed_write(unsigned char* p)
+ : p_(reinterpret_cast<internal::Verneed_data*>(p))
+ { }
+
+ void
+ set_vn_version(Elf_Half v)
+ { this->p_->vn_version = Convert<16, big_endian>::convert_host(v); }
+
+ void
+ set_vn_cnt(Elf_Half v)
+ { this->p_->vn_cnt = Convert<16, big_endian>::convert_host(v); }
+
+ void
+ set_vn_file(Elf_Word v)
+ { this->p_->vn_file = Convert<32, big_endian>::convert_host(v); }
+
+ void
+ set_vn_aux(Elf_Word v)
+ { this->p_->vn_aux = Convert<32, big_endian>::convert_host(v); }
+
+ void
+ set_vn_next(Elf_Word v)
+ { this->p_->vn_next = Convert<32, big_endian>::convert_host(v); }
+
+ private:
+ internal::Verneed_data* p_;
+};
+
// Accessor classes for auxiliary entries in the ELF SHT_GNU_verneed
// section.
@@ -1488,6 +1585,37 @@ class Vernaux
const internal::Vernaux_data* p_;
};
+template<int size, bool big_endian>
+class Vernaux_write
+{
+ public:
+ Vernaux_write(unsigned char* p)
+ : p_(reinterpret_cast<internal::Vernaux_data*>(p))
+ { }
+
+ void
+ set_vna_hash(Elf_Word v)
+ { this->p_->vna_hash = Convert<32, big_endian>::convert_host(v); }
+
+ void
+ set_vna_flags(Elf_Half v)
+ { this->p_->vna_flags = Convert<16, big_endian>::convert_host(v); }
+
+ void
+ set_vna_other(Elf_Half v)
+ { this->p_->vna_other = Convert<16, big_endian>::convert_host(v); }
+
+ void
+ set_vna_name(Elf_Word v)
+ { this->p_->vna_name = Convert<32, big_endian>::convert_host(v); }
+
+ void
+ set_vna_next(Elf_Word v)
+ { this->p_->vna_next = Convert<32, big_endian>::convert_host(v); }
+
+ private:
+ internal::Vernaux_data* p_;
+};
} // End namespace elfcpp.
diff --git a/gold/dynobj.cc b/gold/dynobj.cc
index ac5a74b1c6..9871bdeca1 100644
--- a/gold/dynobj.cc
+++ b/gold/dynobj.cc
@@ -392,7 +392,8 @@ Sized_dynobj<size, big_endian>::set_version_map(
unsigned int ndx,
const char* name) const
{
- gold_assert(ndx < version_map->size());
+ if (ndx >= version_map->size())
+ version_map->resize(ndx + 1);
if ((*version_map)[ndx] != NULL)
{
fprintf(stderr, _("%s: %s: duplicate definition for version %u\n"),
@@ -402,207 +403,191 @@ Sized_dynobj<size, big_endian>::set_version_map(
(*version_map)[ndx] = name;
}
-// Create a vector mapping version numbers to version strings.
+// Add mappings for the version definitions to VERSION_MAP.
template<int size, bool big_endian>
void
-Sized_dynobj<size, big_endian>::make_version_map(
+Sized_dynobj<size, big_endian>::make_verdef_map(
Read_symbols_data* sd,
Version_map* version_map) const
{
- if (sd->verdef == NULL && sd->verneed == NULL)
+ if (sd->verdef == NULL)
return;
- // First find the largest version index.
- unsigned int maxver = 0;
+ const char* names = reinterpret_cast<const char*>(sd->symbol_names->data());
+ off_t names_size = sd->symbol_names_size;
- if (sd->verdef != NULL)
+ const unsigned char* pverdef = sd->verdef->data();
+ off_t verdef_size = sd->verdef_size;
+ const unsigned int count = sd->verdef_info;
+
+ const unsigned char* p = pverdef;
+ for (unsigned int i = 0; i < count; ++i)
{
- const unsigned char* pverdef = sd->verdef->data();
- off_t verdef_size = sd->verdef_size;
- const unsigned int count = sd->verdef_info;
+ elfcpp::Verdef<size, big_endian> verdef(p);
- const unsigned char* p = pverdef;
- for (unsigned int i = 0; i < count; ++i)
+ if (verdef.get_vd_version() != elfcpp::VER_DEF_CURRENT)
{
- elfcpp::Verdef<size, big_endian> verdef(p);
-
- const unsigned int vd_ndx = verdef.get_vd_ndx();
+ fprintf(stderr, _("%s: %s: unexpected verdef version %u\n"),
+ program_name, this->name().c_str(), verdef.get_vd_version());
+ gold_exit(false);
+ }
- // The GNU linker clears the VERSYM_HIDDEN bit. I'm not
- // sure why.
+ const unsigned int vd_ndx = verdef.get_vd_ndx();
- if (vd_ndx > maxver)
- maxver = vd_ndx;
+ // The GNU linker clears the VERSYM_HIDDEN bit. I'm not
+ // sure why.
- const unsigned int vd_next = verdef.get_vd_next();
- if ((p - pverdef) + vd_next >= verdef_size)
- {
- fprintf(stderr,
- _("%s: %s: verdef vd_next field out of range: %u\n"),
- program_name, this->name().c_str(), vd_next);
- gold_exit(false);
- }
-
- p += vd_next;
+ // The first Verdaux holds the name of this version. Subsequent
+ // ones are versions that this one depends upon, which we don't
+ // care about here.
+ const unsigned int vd_cnt = verdef.get_vd_cnt();
+ if (vd_cnt < 1)
+ {
+ fprintf(stderr, _("%s: %s: verdef vd_cnt field too small: %u\n"),
+ program_name, this->name().c_str(), vd_cnt);
+ gold_exit(false);
}
- }
- if (sd->verneed != NULL)
- {
- const unsigned char* pverneed = sd->verneed->data();
- off_t verneed_size = sd->verneed_size;
- const unsigned int count = sd->verneed_info;
-
- const unsigned char* p = pverneed;
- for (unsigned int i = 0; i < count; ++i)
+ const unsigned int vd_aux = verdef.get_vd_aux();
+ if ((p - pverdef) + vd_aux >= verdef_size)
{
- elfcpp::Verneed<size, big_endian> verneed(p);
+ fprintf(stderr,
+ _("%s: %s: verdef vd_aux field out of range: %u\n"),
+ program_name, this->name().c_str(), vd_aux);
+ gold_exit(false);
+ }
- const unsigned int vn_aux = verneed.get_vn_aux();
- if ((p - pverneed) + vn_aux >= verneed_size)
- {
- fprintf(stderr,
- _("%s: %s: verneed vn_aux field out of range: %u\n"),
- program_name, this->name().c_str(), vn_aux);
- gold_exit(false);
- }
+ const unsigned char* pvda = p + vd_aux;
+ elfcpp::Verdaux<size, big_endian> verdaux(pvda);
- const unsigned int vn_cnt = verneed.get_vn_cnt();
- const unsigned char* pvna = p + vn_aux;
- for (unsigned int j = 0; j < vn_cnt; ++j)
- {
- elfcpp::Vernaux<size, big_endian> vernaux(pvna);
-
- const unsigned int vna_other = vernaux.get_vna_other();
- if (vna_other > maxver)
- maxver = vna_other;
-
- const unsigned int vna_next = vernaux.get_vna_next();
- if ((pvna - pverneed) + vna_next >= verneed_size)
- {
- fprintf(stderr,
- _("%s: %s: verneed vna_next field "
- "out of range: %u\n"),
- program_name, this->name().c_str(), vna_next);
- gold_exit(false);
- }
-
- pvna += vna_next;
- }
+ const unsigned int vda_name = verdaux.get_vda_name();
+ if (vda_name >= names_size)
+ {
+ fprintf(stderr,
+ _("%s: %s: verdaux vda_name field out of range: %u\n"),
+ program_name, this->name().c_str(), vda_name);
+ gold_exit(false);
+ }
- const unsigned int vn_next = verneed.get_vn_next();
- if ((p - pverneed) + vn_next >= verneed_size)
- {
- fprintf(stderr,
- _("%s: %s: verneed vn_next field out of range: %u\n"),
- program_name, this->name().c_str(), vn_next);
- gold_exit(false);
- }
+ this->set_version_map(version_map, vd_ndx, names + vda_name);
- p += vn_next;
+ const unsigned int vd_next = verdef.get_vd_next();
+ if ((p - pverdef) + vd_next >= verdef_size)
+ {
+ fprintf(stderr,
+ _("%s: %s: verdef vd_next field out of range: %u\n"),
+ program_name, this->name().c_str(), vd_next);
+ gold_exit(false);
}
+
+ p += vd_next;
}
+}
- // Now MAXVER is the largest version index we have seen.
+// Add mappings for the required versions to VERSION_MAP.
- version_map->resize(maxver + 1);
+template<int size, bool big_endian>
+void
+Sized_dynobj<size, big_endian>::make_verneed_map(
+ Read_symbols_data* sd,
+ Version_map* version_map) const
+{
+ if (sd->verneed == NULL)
+ return;
const char* names = reinterpret_cast<const char*>(sd->symbol_names->data());
off_t names_size = sd->symbol_names_size;
- if (sd->verdef != NULL)
+ const unsigned char* pverneed = sd->verneed->data();
+ const off_t verneed_size = sd->verneed_size;
+ const unsigned int count = sd->verneed_info;
+
+ const unsigned char* p = pverneed;
+ for (unsigned int i = 0; i < count; ++i)
{
- const unsigned char* pverdef = sd->verdef->data();
- off_t verdef_size = sd->verdef_size;
- const unsigned int count = sd->verdef_info;
+ elfcpp::Verneed<size, big_endian> verneed(p);
- const unsigned char* p = pverdef;
- for (unsigned int i = 0; i < count; ++i)
+ if (verneed.get_vn_version() != elfcpp::VER_NEED_CURRENT)
{
- elfcpp::Verdef<size, big_endian> verdef(p);
+ fprintf(stderr, _("%s: %s: unexpected verneed version %u\n"),
+ program_name, this->name().c_str(),
+ verneed.get_vn_version());
+ gold_exit(false);
+ }
- const unsigned int vd_cnt = verdef.get_vd_cnt();
- if (vd_cnt < 1)
- {
- fprintf(stderr, _("%s: %s: verdef vd_cnt field too small: %u\n"),
- program_name, this->name().c_str(), vd_cnt);
- gold_exit(false);
- }
+ const unsigned int vn_aux = verneed.get_vn_aux();
- const unsigned int vd_aux = verdef.get_vd_aux();
- if ((p - pverdef) + vd_aux >= verdef_size)
- {
- fprintf(stderr,
- _("%s: %s: verdef vd_aux field out of range: %u\n"),
- program_name, this->name().c_str(), vd_aux);
- gold_exit(false);
- }
+ if ((p - pverneed) + vn_aux >= verneed_size)
+ {
+ fprintf(stderr,
+ _("%s: %s: verneed vn_aux field out of range: %u\n"),
+ program_name, this->name().c_str(), vn_aux);
+ gold_exit(false);
+ }
- const unsigned char* pvda = p + vd_aux;
- elfcpp::Verdaux<size, big_endian> verdaux(pvda);
+ const unsigned int vn_cnt = verneed.get_vn_cnt();
+ const unsigned char* pvna = p + vn_aux;
+ for (unsigned int j = 0; j < vn_cnt; ++j)
+ {
+ elfcpp::Vernaux<size, big_endian> vernaux(pvna);
- const unsigned int vda_name = verdaux.get_vda_name();
- if (vda_name >= names_size)
+ const unsigned int vna_name = vernaux.get_vna_name();
+ if (vna_name >= names_size)
{
fprintf(stderr,
- _("%s: %s: verdaux vda_name field out of range: %u\n"),
- program_name, this->name().c_str(), vda_name);
+ _("%s: %s: vernaux vna_name field "
+ "out of range: %u\n"),
+ program_name, this->name().c_str(), vna_name);
gold_exit(false);
}
- this->set_version_map(version_map, verdef.get_vd_ndx(),
- names + vda_name);
+ this->set_version_map(version_map, vernaux.get_vna_other(),
+ names + vna_name);
- const unsigned int vd_next = verdef.get_vd_next();
- if ((p - pverdef) + vd_next >= verdef_size)
+ const unsigned int vna_next = vernaux.get_vna_next();
+ if ((pvna - pverneed) + vna_next >= verneed_size)
{
fprintf(stderr,
- _("%s: %s: verdef vd_next field out of range: %u\n"),
- program_name, this->name().c_str(), vd_next);
+ _("%s: %s: verneed vna_next field "
+ "out of range: %u\n"),
+ program_name, this->name().c_str(), vna_next);
gold_exit(false);
}
- p += vd_next;
+ pvna += vna_next;
+ }
+
+ const unsigned int vn_next = verneed.get_vn_next();
+ if ((p - pverneed) + vn_next >= verneed_size)
+ {
+ fprintf(stderr,
+ _("%s: %s: verneed vn_next field out of range: %u\n"),
+ program_name, this->name().c_str(), vn_next);
+ gold_exit(false);
}
+
+ p += vn_next;
}
+}
- if (sd->verneed != NULL)
- {
- const unsigned char* pverneed = sd->verneed->data();
- const unsigned int count = sd->verneed_info;
+// Create a vector mapping version numbers to version strings.
- const unsigned char* p = pverneed;
- for (unsigned int i = 0; i < count; ++i)
- {
- elfcpp::Verneed<size, big_endian> verneed(p);
+template<int size, bool big_endian>
+void
+Sized_dynobj<size, big_endian>::make_version_map(
+ Read_symbols_data* sd,
+ Version_map* version_map) const
+{
+ if (sd->verdef == NULL && sd->verneed == NULL)
+ return;
- const unsigned int vn_aux = verneed.get_vn_aux();
- const unsigned int vn_cnt = verneed.get_vn_cnt();
- const unsigned char* pvna = p + vn_aux;
- for (unsigned int j = 0; j < vn_cnt; ++j)
- {
- elfcpp::Vernaux<size, big_endian> vernaux(pvna);
-
- const unsigned int vna_name = vernaux.get_vna_name();
- if (vna_name >= names_size)
- {
- fprintf(stderr,
- _("%s: %s: vernaux vna_name field "
- "out of range: %u\n"),
- program_name, this->name().c_str(), vna_name);
- gold_exit(false);
- }
-
- this->set_version_map(version_map, vernaux.get_vna_other(),
- names + vna_name);
-
- pvna += vernaux.get_vna_next();
- }
+ // A guess at the maximum version number we will see. If this is
+ // wrong we will be less efficient but still correct.
+ version_map->reserve(sd->verdef_info + sd->verneed_info * 10);
- p += verneed.get_vn_next();
- }
- }
+ this->make_verdef_map(sd, version_map);
+ this->make_verneed_map(sd, version_map);
}
// Add the dynamic symbols to the symbol table.
@@ -1059,6 +1044,478 @@ Dynobj::sized_create_gnu_hash_table(
*pphash = phash;
}
+// Verdef methods.
+
+// Write this definition to a buffer for the output section.
+
+template<int size, bool big_endian>
+unsigned char*
+Verdef::write(const Stringpool* dynpool, bool is_last, unsigned char* pb) const
+{
+ const int verdef_size = elfcpp::Elf_sizes<size>::verdef_size;
+ const int verdaux_size = elfcpp::Elf_sizes<size>::verdaux_size;
+
+ elfcpp::Verdef_write<size, big_endian> vd(pb);
+ vd.set_vd_version(elfcpp::VER_DEF_CURRENT);
+ vd.set_vd_flags((this->is_base_ ? elfcpp::VER_FLG_BASE : 0)
+ | (this->is_weak_ ? elfcpp::VER_FLG_WEAK : 0));
+ vd.set_vd_ndx(this->index());
+ vd.set_vd_cnt(1 + this->deps_.size());
+ vd.set_vd_hash(Dynobj::elf_hash(this->name()));
+ vd.set_vd_aux(verdef_size);
+ vd.set_vd_next(is_last
+ ? 0
+ : verdef_size + (1 + this->deps_.size()) * verdaux_size);
+ pb += verdef_size;
+
+ elfcpp::Verdaux_write<size, big_endian> vda(pb);
+ vda.set_vda_name(dynpool->get_offset(this->name()));
+ vda.set_vda_next(this->deps_.empty() ? 0 : verdaux_size);
+ pb += verdaux_size;
+
+ Deps::const_iterator p;
+ unsigned int i;
+ for (p = this->deps_.begin(), i = 0;
+ p != this->deps_.end();
+ ++p, ++i)
+ {
+ elfcpp::Verdaux_write<size, big_endian> vda(pb);
+ vda.set_vda_name(dynpool->get_offset(*p));
+ vda.set_vda_next(i + 1 >= this->deps_.size() ? 0 : verdaux_size);
+ pb += verdaux_size;
+ }
+
+ return pb;
+}
+
+// Verneed methods.
+
+Verneed::~Verneed()
+{
+ for (Need_versions::iterator p = this->need_versions_.begin();
+ p != this->need_versions_.end();
+ ++p)
+ delete *p;
+}
+
+// Add a new version to this file reference.
+
+Verneed_version*
+Verneed::add_name(const char* name)
+{
+ Verneed_version* vv = new Verneed_version(name);
+ this->need_versions_.push_back(vv);
+ return vv;
+}
+
+// Set the version indexes starting at INDEX.
+
+unsigned int
+Verneed::finalize(unsigned int index)
+{
+ for (Need_versions::iterator p = this->need_versions_.begin();
+ p != this->need_versions_.end();
+ ++p)
+ {
+ (*p)->set_index(index);
+ ++index;
+ }
+ return index;
+}
+
+// Write this list of referenced versions to a buffer for the output
+// section.
+
+template<int size, bool big_endian>
+unsigned char*
+Verneed::write(const Stringpool* dynpool, bool is_last,
+ unsigned char* pb) const
+{
+ const int verneed_size = elfcpp::Elf_sizes<size>::verneed_size;
+ const int vernaux_size = elfcpp::Elf_sizes<size>::vernaux_size;
+
+ elfcpp::Verneed_write<size, big_endian> vn(pb);
+ vn.set_vn_version(elfcpp::VER_NEED_CURRENT);
+ vn.set_vn_cnt(this->need_versions_.size());
+ vn.set_vn_file(dynpool->get_offset(this->filename()));
+ vn.set_vn_aux(verneed_size);
+ vn.set_vn_next(is_last
+ ? 0
+ : verneed_size + this->need_versions_.size() * vernaux_size);
+ pb += verneed_size;
+
+ Need_versions::const_iterator p;
+ unsigned int i;
+ for (p = this->need_versions_.begin(), i = 0;
+ p != this->need_versions_.end();
+ ++p, ++i)
+ {
+ elfcpp::Vernaux_write<size, big_endian> vna(pb);
+ vna.set_vna_hash(Dynobj::elf_hash((*p)->version()));
+ // FIXME: We need to sometimes set VER_FLG_WEAK here.
+ vna.set_vna_flags(0);
+ vna.set_vna_other((*p)->index());
+ vna.set_vna_name(dynpool->get_offset((*p)->version()));
+ vna.set_vna_next(i + 1 >= this->need_versions_.size()
+ ? 0
+ : vernaux_size);
+ pb += vernaux_size;
+ }
+
+ return pb;
+}
+
+// Versions methods.
+
+Versions::~Versions()
+{
+ for (Defs::iterator p = this->defs_.begin();
+ p != this->defs_.end();
+ ++p)
+ delete *p;
+
+ for (Needs::iterator p = this->needs_.begin();
+ p != this->needs_.end();
+ ++p)
+ delete *p;
+}
+
+// Record version information for a symbol going into the dynamic
+// symbol table.
+
+void
+Versions::record_version(const General_options* options,
+ Stringpool* dynpool, const Symbol* sym)
+{
+ gold_assert(!this->is_finalized_);
+ gold_assert(sym->version() != NULL);
+
+ Stringpool::Key version_key;
+ const char* version = dynpool->add(sym->version(), &version_key);
+
+ if (!sym->is_from_dynobj())
+ this->add_def(options, sym, version, version_key);
+ else
+ {
+ // This is a version reference.
+
+ Object* object = sym->object();
+ gold_assert(object->is_dynamic());
+ Dynobj* dynobj = static_cast<Dynobj*>(object);
+
+ this->add_need(dynpool, dynobj->soname(), version, version_key);
+ }
+}
+
+// We've found a symbol SYM defined in version VERSION.
+
+void
+Versions::add_def(const General_options* options, const Symbol* sym,
+ const char* version, Stringpool::Key version_key)
+{
+ Key k(version_key, 0);
+ Version_base* const vbnull = NULL;
+ std::pair<Version_table::iterator, bool> ins =
+ this->version_table_.insert(std::make_pair(k, vbnull));
+
+ if (!ins.second)
+ {
+ // We already have an entry for this version.
+ Version_base* vb = ins.first->second;
+
+ // We have now seen a symbol in this version, so it is not
+ // weak.
+ vb->clear_weak();
+
+ // FIXME: When we support version scripts, we will need to
+ // check whether this symbol should be forced local.
+ }
+ else
+ {
+ // If we are creating a shared object, it is an error to
+ // find a definition of a symbol with a version which is not
+ // in the version script.
+ if (options->is_shared())
+ {
+ fprintf(stderr, _("%s: symbol %s has undefined version %s\n"),
+ program_name, sym->name(), version);
+ gold_exit(false);
+ }
+
+ // If this is the first version we are defining, first define
+ // the base version. FIXME: Should use soname here when
+ // creating a shared object.
+ Verdef* vdbase = new Verdef(options->output_file_name(), true, false,
+ true);
+ this->defs_.push_back(vdbase);
+
+ // When creating a regular executable, automatically define
+ // a new version.
+ Verdef* vd = new Verdef(version, false, false, false);
+ this->defs_.push_back(vd);
+ ins.first->second = vd;
+ }
+}
+
+// Add a reference to version NAME in file FILENAME.
+
+void
+Versions::add_need(Stringpool* dynpool, const char* filename, const char* name,
+ Stringpool::Key name_key)
+{
+ Stringpool::Key filename_key;
+ filename = dynpool->add(filename, &filename_key);
+
+ Key k(name_key, filename_key);
+ Version_base* const vbnull = NULL;
+ std::pair<Version_table::iterator, bool> ins =
+ this->version_table_.insert(std::make_pair(k, vbnull));
+
+ if (!ins.second)
+ {
+ // We already have an entry for this filename/version.
+ return;
+ }
+
+ // See whether we already have this filename. We don't expect many
+ // version references, so we just do a linear search. This could be
+ // replaced by a hash table.
+ Verneed* vn = NULL;
+ for (Needs::iterator p = this->needs_.begin();
+ p != this->needs_.end();
+ ++p)
+ {
+ if ((*p)->filename() == filename)
+ {
+ vn = *p;
+ break;
+ }
+ }
+
+ if (vn == NULL)
+ {
+ // We have a new filename.
+ vn = new Verneed(filename);
+ this->needs_.push_back(vn);
+ }
+
+ ins.first->second = vn->add_name(name);
+}
+
+// Set the version indexes. Create a new dynamic version symbol for
+// each new version definition.
+
+unsigned int
+Versions::finalize(const Target* target, Symbol_table* symtab,
+ unsigned int dynsym_index, std::vector<Symbol*>* syms)
+{
+ gold_assert(!this->is_finalized_);
+
+ unsigned int vi = 1;
+
+ for (Defs::iterator p = this->defs_.begin();
+ p != this->defs_.end();
+ ++p)
+ {
+ (*p)->set_index(vi);
+ ++vi;
+
+ // Create a version symbol if necessary.
+ if (!(*p)->is_symbol_created())
+ {
+ Symbol* vsym =symtab->define_as_constant(target, (*p)->name(),
+ (*p)->name(), 0, 0,
+ elfcpp::STT_OBJECT,
+ elfcpp::STB_GLOBAL,
+ elfcpp::STV_DEFAULT, 0,
+ false);
+ vsym->set_needs_dynsym_entry();
+ ++dynsym_index;
+ syms->push_back(vsym);
+ // The name is already in the dynamic pool.
+ }
+ }
+
+ // Index 1 is used for global symbols.
+ if (vi == 1)
+ {
+ gold_assert(this->defs_.empty());
+ vi = 2;
+ }
+
+ for (Needs::iterator p = this->needs_.begin();
+ p != this->needs_.end();
+ ++p)
+ vi = (*p)->finalize(vi);
+
+ this->is_finalized_ = true;
+
+ return dynsym_index;
+}
+
+// Return the version index to use for a symbol. This does two hash
+// table lookups: one in DYNPOOL and one in this->version_table_.
+// Another approach alternative would be store a pointer in SYM, which
+// would increase the size of the symbol table. Or perhaps we could
+// use a hash table from dynamic symbol pointer values to Version_base
+// pointers.
+
+unsigned int
+Versions::version_index(const Stringpool* dynpool, const Symbol* sym) const
+{
+ Stringpool::Key version_key;
+ const char* version = dynpool->find(sym->version(), &version_key);
+ gold_assert(version != NULL);
+
+ Version_table::const_iterator p;
+ if (!sym->is_from_dynobj())
+ {
+ Key k(version_key, 0);
+ p = this->version_table_.find(k);
+ }
+ else
+ {
+ Object* object = sym->object();
+ gold_assert(object->is_dynamic());
+ Dynobj* dynobj = static_cast<Dynobj*>(object);
+
+ Stringpool::Key filename_key;
+ const char* filename = dynpool->find(dynobj->soname(), &filename_key);
+ gold_assert(filename != NULL);
+
+ Key k(version_key, filename_key);
+ p = this->version_table_.find(k);
+ }
+
+ gold_assert(p != this->version_table_.end());
+
+ return p->second->index();
+}
+
+// Return an allocated buffer holding the contents of the symbol
+// version section.
+
+template<int size, bool big_endian>
+void
+Versions::symbol_section_contents(const Stringpool* dynpool,
+ unsigned int local_symcount,
+ const std::vector<Symbol*>& syms,
+ unsigned char** pp,
+ unsigned int* psize) const
+{
+ gold_assert(this->is_finalized_);
+
+ unsigned int sz = (local_symcount + syms.size()) * 2;
+ unsigned char* pbuf = new unsigned char[sz];
+
+ for (unsigned int i = 0; i < local_symcount; ++i)
+ elfcpp::Swap<16, big_endian>::writeval(pbuf + i * 2,
+ elfcpp::VER_NDX_LOCAL);
+
+ for (std::vector<Symbol*>::const_iterator p = syms.begin();
+ p != syms.end();
+ ++p)
+ {
+ unsigned int version_index;
+ const char* version = (*p)->version();
+ if (version == NULL)
+ version_index = elfcpp::VER_NDX_GLOBAL;
+ else
+ version_index = this->version_index(dynpool, *p);
+ elfcpp::Swap<16, big_endian>::writeval(pbuf + (*p)->dynsym_index() * 2,
+ version_index);
+ }
+
+ *pp = pbuf;
+ *psize = sz;
+}
+
+// Return an allocated buffer holding the contents of the version
+// definition section.
+
+template<int size, bool big_endian>
+void
+Versions::def_section_contents(const Stringpool* dynpool,
+ unsigned char** pp, unsigned int* psize,
+ unsigned int* pentries) const
+{
+ gold_assert(this->is_finalized_);
+ gold_assert(!this->defs_.empty());
+
+ const int verdef_size = elfcpp::Elf_sizes<size>::verdef_size;
+ const int verdaux_size = elfcpp::Elf_sizes<size>::verdaux_size;
+
+ unsigned int sz = 0;
+ for (Defs::const_iterator p = this->defs_.begin();
+ p != this->defs_.end();
+ ++p)
+ {
+ sz += verdef_size + verdaux_size;
+ sz += (*p)->count_dependencies() * verdaux_size;
+ }
+
+ unsigned char* pbuf = new unsigned char[sz];
+
+ unsigned char* pb = pbuf;
+ Defs::const_iterator p;
+ unsigned int i;
+ for (p = this->defs_.begin(), i = 0;
+ p != this->defs_.end();
+ ++p, ++i)
+ pb = (*p)->write<size, big_endian>(dynpool,
+ i + 1 >= this->defs_.size(),
+ pb);
+
+ gold_assert(static_cast<unsigned int>(pb - pbuf) == sz);
+
+ *pp = pbuf;
+ *psize = sz;
+ *pentries = this->defs_.size();
+}
+
+// Return an allocated buffer holding the contents of the version
+// reference section.
+
+template<int size, bool big_endian>
+void
+Versions::need_section_contents(const Stringpool* dynpool,
+ unsigned char** pp, unsigned int *psize,
+ unsigned int *pentries) const
+{
+ gold_assert(this->is_finalized_);
+ gold_assert(!this->needs_.empty());
+
+ const int verneed_size = elfcpp::Elf_sizes<size>::verneed_size;
+ const int vernaux_size = elfcpp::Elf_sizes<size>::vernaux_size;
+
+ unsigned int sz = 0;
+ for (Needs::const_iterator p = this->needs_.begin();
+ p != this->needs_.end();
+ ++p)
+ {
+ sz += verneed_size;
+ sz += (*p)->count_versions() * vernaux_size;
+ }
+
+ unsigned char* pbuf = new unsigned char[sz];
+
+ unsigned char* pb = pbuf;
+ Needs::const_iterator p;
+ unsigned int i;
+ for (p = this->needs_.begin(), i = 0;
+ p != this->needs_.end();
+ ++p, ++i)
+ pb = (*p)->write<size, big_endian>(dynpool,
+ i + 1 >= this->needs_.size(),
+ pb);
+
+ gold_assert(static_cast<unsigned int>(pb - pbuf) == sz);
+
+ *pp = pbuf;
+ *psize = sz;
+ *pentries = this->needs_.size();
+}
+
// Instantiate the templates we need. We could use the configure
// script to restrict this to only the ones for implemented targets.
@@ -1074,4 +1531,92 @@ class Sized_dynobj<64, false>;
template
class Sized_dynobj<64, true>;
+template
+void
+Versions::symbol_section_contents<32, false>(const Stringpool*,
+ unsigned int,
+ const std::vector<Symbol*>&,
+ unsigned char**,
+ unsigned int*) const;
+
+template
+void
+Versions::symbol_section_contents<32, true>(const Stringpool*,
+ unsigned int,
+ const std::vector<Symbol*>&,
+ unsigned char**,
+ unsigned int*) const;
+
+template
+void
+Versions::symbol_section_contents<64, false>(const Stringpool*,
+ unsigned int,
+ const std::vector<Symbol*>&,
+ unsigned char**,
+ unsigned int*) const;
+
+template
+void
+Versions::symbol_section_contents<64, true>(const Stringpool*,
+ unsigned int,
+ const std::vector<Symbol*>&,
+ unsigned char**,
+ unsigned int*) const;
+
+template
+void
+Versions::def_section_contents<32, false>(const Stringpool*,
+ unsigned char**,
+ unsigned int*,
+ unsigned int*) const;
+
+template
+void
+Versions::def_section_contents<32, true>(const Stringpool*,
+ unsigned char**,
+ unsigned int*,
+ unsigned int*) const;
+
+template
+void
+Versions::def_section_contents<64, false>(const Stringpool*,
+ unsigned char**,
+ unsigned int*,
+ unsigned int*) const;
+
+template
+void
+Versions::def_section_contents<64, true>(const Stringpool*,
+ unsigned char**,
+ unsigned int*,
+ unsigned int*) const;
+
+template
+void
+Versions::need_section_contents<32, false>(const Stringpool*,
+ unsigned char**,
+ unsigned int*,
+ unsigned int*) const;
+
+template
+void
+Versions::need_section_contents<32, true>(const Stringpool*,
+ unsigned char**,
+ unsigned int*,
+ unsigned int*) const;
+
+template
+void
+Versions::need_section_contents<64, false>(const Stringpool*,
+ unsigned char**,
+ unsigned int*,
+ unsigned int*) const;
+
+template
+void
+Versions::need_section_contents<64, true>(const Stringpool*,
+ unsigned char**,
+ unsigned int*,
+ unsigned int*) const;
+
} // End namespace gold.
diff --git a/gold/dynobj.h b/gold/dynobj.h
index bc877c412f..9e5dd43d70 100644
--- a/gold/dynobj.h
+++ b/gold/dynobj.h
@@ -5,11 +5,15 @@
#include <vector>
+#include "stringpool.h"
#include "object.h"
namespace gold
{
+class General_options;
+class Stringpool;
+
// A dynamic object (ET_DYN). This is an abstract base class itself.
// The implementations is the template class Sized_dynobj.
@@ -24,6 +28,10 @@ class Dynobj : public Object
const char*
soname() const;
+ // Compute the ELF hash code for a string.
+ static uint32_t
+ elf_hash(const char*);
+
// Create a standard ELF hash table, setting *PPHASH and *PHASHLEN.
// DYNSYMS is the global dynamic symbols. LOCAL_DYNSYM_COUNT is the
// number of local dynamic symbols, which is the index of the first
@@ -50,10 +58,6 @@ class Dynobj : public Object
{ this->soname_.assign(s); }
private:
- // Compute the ELF hash code for a string.
- static uint32_t
- elf_hash(const char*);
-
// Compute the GNU hash code for a string.
static uint32_t
gnu_hash(const char*);
@@ -166,6 +170,14 @@ class Sized_dynobj : public Dynobj
void
make_version_map(Read_symbols_data* sd, Version_map*) const;
+ // Add version definitions to the version map.
+ void
+ make_verdef_map(Read_symbols_data* sd, Version_map*) const;
+
+ // Add version references to the version map.
+ void
+ make_verneed_map(Read_symbols_data* sd, Version_map*) const;
+
// Add an entry to the version map.
void
set_version_map(Version_map*, unsigned int ndx, const char* name) const;
@@ -174,6 +186,305 @@ class Sized_dynobj : public Dynobj
elfcpp::Elf_file<size, big_endian, Object> elf_file_;
};
+// A base class for Verdef and Verneed_version which just handles the
+// version index which will be stored in the SHT_GNU_versym section.
+
+class Version_base
+{
+ public:
+ Version_base()
+ : index_(-1U)
+ { }
+
+ virtual
+ ~Version_base()
+ { }
+
+ // Return the version index.
+ unsigned int
+ index() const
+ {
+ gold_assert(this->index_ != -1U);
+ return this->index_;
+ }
+
+ // Set the version index.
+ void
+ set_index(unsigned int index)
+ {
+ gold_assert(this->index_ == -1U);
+ this->index_ = index;
+ }
+
+ // Clear the weak flag in a version definition.
+ virtual void
+ clear_weak() = 0;
+
+ private:
+ Version_base(const Version_base&);
+ Version_base& operator=(const Version_base&);
+
+ // The index of the version definition or reference.
+ unsigned int index_;
+};
+
+// This class handles a version being defined in the file we are
+// generating.
+
+class Verdef : public Version_base
+{
+ public:
+ Verdef(const char* name, bool is_base, bool is_weak, bool is_symbol_created)
+ : name_(name), deps_(), is_base_(is_base), is_weak_(is_weak),
+ is_symbol_created_(is_symbol_created)
+ { }
+
+ // Return the version name.
+ const char*
+ name() const
+ { return this->name_; }
+
+ // Return the number of dependencies.
+ unsigned int
+ count_dependencies() const
+ { return this->deps_.size(); }
+
+ // Add a dependency to this version. The NAME should be
+ // canonicalized in the dynamic Stringpool.
+ void
+ add_dependency(const char* name)
+ { this->deps_.push_back(name); }
+
+ // Return whether this definition is weak.
+ bool
+ is_weak() const
+ { return this->is_weak_; }
+
+ // Clear the weak flag.
+ void
+ clear_weak()
+ { this->is_weak_ = false; }
+
+ // Return whether a version symbol has been created for this
+ // definition.
+ bool
+ is_symbol_created() const
+ { return this->is_symbol_created_; }
+
+ // Write contents to buffer.
+ template<int size, bool big_endian>
+ unsigned char*
+ write(const Stringpool*, bool is_last, unsigned char*) const;
+
+ private:
+ Verdef(const Verdef&);
+ Verdef& operator=(const Verdef&);
+
+ // The type of the list of version dependencies. Each dependency
+ // should be canonicalized in the dynamic Stringpool.
+ typedef std::vector<const char*> Deps;
+
+ // The name of this version. This should be canonicalized in the
+ // dynamic Stringpool.
+ const char* name_;
+ // A list of other versions which this version depends upon.
+ Deps deps_;
+ // Whether this is the base version.
+ bool is_base_;
+ // Whether this version is weak.
+ bool is_weak_;
+ // Whether a version symbol has been created.
+ bool is_symbol_created_;
+};
+
+// A referened version. This will be associated with a filename by
+// Verneed.
+
+class Verneed_version : public Version_base
+{
+ public:
+ Verneed_version(const char* version)
+ : version_(version)
+ { }
+
+ // Return the version name.
+ const char*
+ version() const
+ { return this->version_; }
+
+ // Clear the weak flag. This is invalid for a reference.
+ void
+ clear_weak()
+ { gold_unreachable(); }
+
+ private:
+ Verneed_version(const Verneed_version&);
+ Verneed_version& operator=(const Verneed_version&);
+
+ const char* version_;
+};
+
+// Version references in a single dynamic object.
+
+class Verneed
+{
+ public:
+ Verneed(const char* filename)
+ : filename_(filename), need_versions_()
+ { }
+
+ ~Verneed();
+
+ // Return the file name.
+ const char*
+ filename() const
+ { return this->filename_; }
+
+ // Return the number of versions.
+ unsigned int
+ count_versions() const
+ { return this->need_versions_.size(); }
+
+ // Add a version name. The name should be canonicalized in the
+ // dynamic Stringpool. If the name is already present, this does
+ // nothing.
+ Verneed_version*
+ add_name(const char* name);
+
+ // Set the version indexes, starting at INDEX. Return the updated
+ // INDEX.
+ unsigned int
+ finalize(unsigned int index);
+
+ // Write contents to buffer.
+ template<int size, bool big_endian>
+ unsigned char*
+ write(const Stringpool*, bool is_last, unsigned char*) const;
+
+ private:
+ Verneed(const Verneed&);
+ Verneed& operator=(const Verneed&);
+
+ // The type of the list of version names. Each name should be
+ // canonicalized in the dynamic Stringpool.
+ typedef std::vector<Verneed_version*> Need_versions;
+
+ // The filename of the dynamic object. This should be
+ // canonicalized in the dynamic Stringpool.
+ const char* filename_;
+ // The list of version names.
+ Need_versions need_versions_;
+};
+
+// This class handles version definitions and references which go into
+// the output file.
+
+class Versions
+{
+ public:
+ Versions()
+ : defs_(), needs_(), version_table_(), is_finalized_(false)
+ { }
+
+ ~Versions();
+
+ // SYM is going into the dynamic symbol table and has a version.
+ // Record the appropriate version information.
+ void
+ record_version(const General_options*, Stringpool*, const Symbol* sym);
+
+ // Set the version indexes. DYNSYM_INDEX is the index we should use
+ // for the next dynamic symbol. We add new dynamic symbols to SYMS
+ // and return an updated DYNSYM_INDEX.
+ unsigned int
+ finalize(const Target*, Symbol_table* symtab, unsigned int dynsym_index,
+ std::vector<Symbol*>* syms);
+
+ // Return whether there are any version definitions.
+ bool
+ any_defs() const
+ { return !this->defs_.empty(); }
+
+ // Return whether there are any version references.
+ bool
+ any_needs() const
+ { return !this->needs_.empty(); }
+
+ // Build an allocated buffer holding the contents of the symbol
+ // version section (.gnu.version).
+ template<int size, bool big_endian>
+ void
+ symbol_section_contents(const Stringpool*, unsigned int local_symcount,
+ const std::vector<Symbol*>& syms,
+ unsigned char**, unsigned int*) const;
+
+ // Build an allocated buffer holding the contents of the version
+ // definition section (.gnu.version_d).
+ template<int size, bool big_endian>
+ void
+ def_section_contents(const Stringpool*, unsigned char**,
+ unsigned int* psize, unsigned int* pentries) const;
+
+ // Build an allocated buffer holding the contents of the version
+ // reference section (.gnu.version_r).
+ template<int size, bool big_endian>
+ void
+ need_section_contents(const Stringpool*, unsigned char**,
+ unsigned int* psize, unsigned int* pentries) const;
+
+ private:
+ // The type of the list of version definitions.
+ typedef std::vector<Verdef*> Defs;
+
+ // The type of the list of version references.
+ typedef std::vector<Verneed*> Needs;
+
+ // Handle a symbol SYM defined with version VERSION.
+ void
+ add_def(const General_options*, const Symbol* sym, const char* version,
+ Stringpool::Key);
+
+ // Add a reference to version NAME in file FILENAME.
+ void
+ add_need(Stringpool*, const char* filename, const char* name,
+ Stringpool::Key);
+
+ // Return the version index to use for SYM.
+ unsigned int
+ version_index(const Stringpool*, const Symbol* sym) const;
+
+ // We keep a hash table mapping canonicalized name/version pairs to
+ // a version base.
+ typedef std::pair<Stringpool::Key, Stringpool::Key> Key;
+
+ struct Version_table_hash
+ {
+ size_t
+ operator()(const Key& k) const
+ { return k.first + k.second; }
+ };
+
+ struct Version_table_eq
+ {
+ bool
+ operator()(const Key& k1, const Key& k2) const
+ { return k1.first == k2.first && k1.second == k2.second; }
+ };
+
+ typedef Unordered_map<Key, Version_base*, Version_table_hash,
+ Version_table_eq> Version_table;
+
+ // The version definitions.
+ Defs defs_;
+ // The version references.
+ Needs needs_;
+ // The mapping from a canonicalized version/filename pair to a
+ // version index. The filename may be NULL.
+ Version_table version_table_;
+ // Whether the version indexes have been set.
+ bool is_finalized_;
+};
+
} // End namespace gold.
#endif // !defined(GOLD_DYNOBJ_H)
diff --git a/gold/i386.cc b/gold/i386.cc
index ee3654c5a0..dbbd2c09b7 100644
--- a/gold/i386.cc
+++ b/gold/i386.cc
@@ -247,7 +247,7 @@ Target_i386::got_section(const General_options* options, Symbol_table* symtab,
this->got_plt_->set_space_size(3 * 4);
// Define _GLOBAL_OFFSET_TABLE_ at the start of the PLT.
- symtab->define_in_output_data(this, "_GLOBAL_OFFSET_TABLE_",
+ symtab->define_in_output_data(this, "_GLOBAL_OFFSET_TABLE_", NULL,
this->got_plt_,
0, 0, elfcpp::STT_OBJECT,
elfcpp::STB_LOCAL,
@@ -607,10 +607,10 @@ Target_i386::copy_reloc(const General_options* options,
dynbss->set_space_size(dynbss_size + symsize);
// Define the symbol in the .dynbss section.
- symtab->define_in_output_data(this, ssym->name(), dynbss, offset,
- symsize, ssym->type(), ssym->binding(),
- ssym->visibility(), ssym->nonvis(),
- false, false);
+ symtab->define_in_output_data(this, ssym->name(), ssym->version(),
+ dynbss, offset, symsize, ssym->type(),
+ ssym->binding(), ssym->visibility(),
+ ssym->nonvis(), false, false);
// Add the COPY reloc.
ssym->set_needs_dynsym_entry();
@@ -819,7 +819,7 @@ Target_i386::Scan::global(const General_options& options,
// relocation in order to avoid a COPY relocation.
gold_assert(!options.is_shared());
- if (gsym->is_defined_in_dynobj())
+ if (gsym->is_from_dynobj())
{
// This symbol is defined in a dynamic object. If it is a
// function, we make a PLT entry. Otherwise we need to
@@ -1050,7 +1050,7 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
}
// Pick the value to use for symbols defined in shared objects.
- if (gsym != NULL && gsym->is_defined_in_dynobj())
+ if (gsym != NULL && gsym->is_from_dynobj())
{
if (gsym->has_plt_offset())
value = target->plt_section()->address() + gsym->plt_offset();
diff --git a/gold/layout.cc b/gold/layout.cc
index f424bb4438..2d7a3faff0 100644
--- a/gold/layout.cc
+++ b/gold/layout.cc
@@ -42,8 +42,8 @@ Layout::Layout(const General_options& options)
: options_(options), namepool_(), sympool_(), dynpool_(), signatures_(),
section_name_map_(), segment_list_(), section_list_(),
unattached_section_list_(), special_output_list_(),
- tls_segment_(NULL), symtab_section_(NULL), dynsym_section_(NULL),
- dynamic_section_(NULL), dynamic_data_(NULL)
+ tls_segment_(NULL), symtab_section_(NULL),
+ dynsym_section_(NULL), dynamic_section_(NULL), dynamic_data_(NULL)
{
// Make space for more than enough segments for a typical file.
// This is just for efficiency--it's OK if we wind up needing more.
@@ -322,7 +322,7 @@ Layout::create_initial_dynamic_sections(const Input_objects* input_objects,
(elfcpp::SHF_ALLOC
| elfcpp::SHF_WRITE));
- symtab->define_in_output_data(input_objects->target(), "_DYNAMIC",
+ symtab->define_in_output_data(input_objects->target(), "_DYNAMIC", NULL,
this->dynamic_section_, 0, 0,
elfcpp::STT_OBJECT, elfcpp::STB_LOCAL,
elfcpp::STV_HIDDEN, 0, false, false);
@@ -405,9 +405,14 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
phdr_seg = new Output_segment(elfcpp::PT_PHDR, elfcpp::PF_R);
this->segment_list_.push_back(phdr_seg);
- // Create the dynamic symbol table, including the hash table,
- // the dynamic relocations, and the version sections.
- this->create_dynamic_symtab(target, symtab);
+ // Create the dynamic symbol table, including the hash table.
+ Output_section* dynstr;
+ std::vector<Symbol*> dynamic_symbols;
+ unsigned int local_dynamic_count;
+ Versions versions;
+ this->create_dynamic_symtab(target, symtab, &dynstr,
+ &local_dynamic_count, &dynamic_symbols,
+ &versions);
// Create the .interp section to hold the name of the
// interpreter, and put it in a PT_INTERP segment.
@@ -416,6 +421,15 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
// Finish the .dynamic section to hold the dynamic data, and put
// it in a PT_DYNAMIC segment.
this->finish_dynamic_section(input_objects, symtab);
+
+ // We should have added everything we need to the dynamic string
+ // table.
+ this->dynpool_.set_string_offsets();
+
+ // Create the version sections. We can't do this until the
+ // dynamic string table is complete.
+ this->create_version_sections(target, &versions, local_dynamic_count,
+ dynamic_symbols, dynstr);
}
// FIXME: Handle PT_GNU_STACK.
@@ -831,7 +845,11 @@ Layout::create_shdrs(int size, bool big_endian, off_t* poff)
// Create the dynamic symbol table.
void
-Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab)
+Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab,
+ Output_section **pdynstr,
+ unsigned int* plocal_dynamic_count,
+ std::vector<Symbol*>* pdynamic_symbols,
+ Versions* pversions)
{
// Count all the symbols in the dynamic symbol table, and set the
// dynamic symbol indexes.
@@ -859,13 +877,13 @@ Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab)
// this->dynpool_.
unsigned int local_symcount = index;
-
- std::vector<Symbol*> dynamic_symbols;
+ *plocal_dynamic_count = local_symcount;
// FIXME: We have to tell set_dynsym_indexes whether the
// -E/--export-dynamic option was used.
- index = symtab->set_dynsym_indexes(index, &dynamic_symbols,
- &this->dynpool_);
+ index = symtab->set_dynsym_indexes(&this->options_, target, index,
+ pdynamic_symbols, &this->dynpool_,
+ pversions);
int symsize;
unsigned int align;
@@ -883,6 +901,8 @@ Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab)
else
gold_unreachable();
+ // Create the dynamic symbol table section.
+
const char* dynsym_name = this->namepool_.add(".dynsym", NULL);
Output_section* dynsym = this->make_output_section(dynsym_name,
elfcpp::SHT_DYNSYM,
@@ -902,6 +922,8 @@ Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab)
odyn->add_section_address(elfcpp::DT_SYMTAB, dynsym);
odyn->add_constant(elfcpp::DT_SYMENT, symsize);
+ // Create the dynamic string table section.
+
const char* dynstr_name = this->namepool_.add(".dynstr", NULL);
Output_section* dynstr = this->make_output_section(dynstr_name,
elfcpp::SHT_STRTAB,
@@ -916,11 +938,15 @@ Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab)
odyn->add_section_address(elfcpp::DT_STRTAB, dynstr);
odyn->add_section_size(elfcpp::DT_STRSZ, dynstr);
+ *pdynstr = dynstr;
+
+ // Create the hash tables.
+
// FIXME: We need an option to create a GNU hash table.
unsigned char* phash;
unsigned int hashlen;
- Dynobj::create_elf_hash_table(target, dynamic_symbols, local_symcount,
+ Dynobj::create_elf_hash_table(target, *pdynamic_symbols, local_symcount,
&phash, &hashlen);
const char* hash_name = this->namepool_.add(".hash", NULL);
@@ -939,6 +965,131 @@ Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab)
odyn->add_section_address(elfcpp::DT_HASH, hashsec);
}
+// Create the version sections.
+
+void
+Layout::create_version_sections(const Target* target, const Versions* versions,
+ unsigned int local_symcount,
+ const std::vector<Symbol*>& dynamic_symbols,
+ const Output_section* dynstr)
+{
+ if (!versions->any_defs() && !versions->any_needs())
+ return;
+
+ if (target->get_size() == 32)
+ {
+ if (target->is_big_endian())
+ this->sized_create_version_sections<32, true>(versions,
+ local_symcount,
+ dynamic_symbols,
+ dynstr);
+ else
+ this->sized_create_version_sections<32, false>(versions,
+ local_symcount,
+ dynamic_symbols,
+ dynstr);
+ }
+ else if (target->get_size() == 64)
+ {
+ if (target->is_big_endian())
+ this->sized_create_version_sections<64, true>(versions,
+ local_symcount,
+ dynamic_symbols,
+ dynstr);
+ else
+ this->sized_create_version_sections<64, false>(versions,
+ local_symcount,
+ dynamic_symbols,
+ dynstr);
+ }
+ else
+ gold_unreachable();
+}
+
+// Create the version sections, sized version.
+
+template<int size, bool big_endian>
+void
+Layout::sized_create_version_sections(
+ const Versions* versions,
+ unsigned int local_symcount,
+ const std::vector<Symbol*>& dynamic_symbols,
+ const Output_section* dynstr)
+{
+ const char* vname = this->namepool_.add(".gnu.version", NULL);
+ Output_section* vsec = this->make_output_section(vname,
+ elfcpp::SHT_GNU_versym,
+ elfcpp::SHF_ALLOC);
+
+ unsigned char* vbuf;
+ unsigned int vsize;
+ versions->symbol_section_contents<size, big_endian>(&this->dynpool_,
+ local_symcount,
+ dynamic_symbols,
+ &vbuf, &vsize);
+
+ Output_section_data* vdata = new Output_data_const_buffer(vbuf, vsize, 2);
+
+ vsec->add_output_section_data(vdata);
+ vsec->set_entsize(2);
+ vsec->set_link_section(this->dynsym_section_);
+
+ Output_data_dynamic* const odyn = this->dynamic_data_;
+ odyn->add_section_address(elfcpp::DT_VERSYM, vsec);
+
+ if (versions->any_defs())
+ {
+ const char* vdname = this->namepool_.add(".gnu.version_d", NULL);
+ Output_section *vdsec;
+ vdsec = this->make_output_section(vdname, elfcpp::SHT_GNU_verdef,
+ elfcpp::SHF_ALLOC);
+
+ unsigned char* vdbuf;
+ unsigned int vdsize;
+ unsigned int vdentries;
+ versions->def_section_contents<size, big_endian>(&this->dynpool_,
+ &vdbuf, &vdsize,
+ &vdentries);
+
+ Output_section_data* vddata = new Output_data_const_buffer(vdbuf,
+ vdsize,
+ 4);
+
+ vdsec->add_output_section_data(vddata);
+ vdsec->set_link_section(dynstr);
+ vdsec->set_info(vdentries);
+
+ odyn->add_section_address(elfcpp::DT_VERDEF, vdsec);
+ odyn->add_constant(elfcpp::DT_VERDEFNUM, vdentries);
+ }
+
+ if (versions->any_needs())
+ {
+ const char* vnname = this->namepool_.add(".gnu.version_r", NULL);
+ Output_section* vnsec;
+ vnsec = this->make_output_section(vnname, elfcpp::SHT_GNU_verneed,
+ elfcpp::SHF_ALLOC);
+
+ unsigned char* vnbuf;
+ unsigned int vnsize;
+ unsigned int vnentries;
+ versions->need_section_contents<size, big_endian>(&this->dynpool_,
+ &vnbuf, &vnsize,
+ &vnentries);
+
+ Output_section_data* vndata = new Output_data_const_buffer(vnbuf,
+ vnsize,
+ 4);
+
+ vnsec->add_output_section_data(vndata);
+ vnsec->set_link_section(dynstr);
+ vnsec->set_info(vnentries);
+
+ odyn->add_section_address(elfcpp::DT_VERNEED, vnsec);
+ odyn->add_constant(elfcpp::DT_VERNEEDNUM, vnentries);
+ }
+}
+
// Create the .interp section and PT_INTERP segment.
void
@@ -990,11 +1141,11 @@ Layout::finish_dynamic_section(const Input_objects* input_objects,
// FIXME: Support --init and --fini.
Symbol* sym = symtab->lookup("_init");
- if (sym != NULL && sym->is_defined() && !sym->is_defined_in_dynobj())
+ if (sym != NULL && sym->is_defined() && !sym->is_from_dynobj())
odyn->add_symbol(elfcpp::DT_INIT, sym);
sym = symtab->lookup("_fini");
- if (sym != NULL && sym->is_defined() && !sym->is_defined_in_dynobj())
+ if (sym != NULL && sym->is_defined() && !sym->is_from_dynobj())
odyn->add_symbol(elfcpp::DT_FINI, sym);
// FIXME: Support DT_INIT_ARRAY and DT_FINI_ARRAY.
diff --git a/gold/layout.h b/gold/layout.h
index 4c54e00555..44f9f4e756 100644
--- a/gold/layout.h
+++ b/gold/layout.h
@@ -10,6 +10,7 @@
#include "workqueue.h"
#include "object.h"
+#include "dynobj.h"
#include "stringpool.h"
namespace gold
@@ -201,7 +202,10 @@ class Layout
// Create the dynamic symbol table.
void
- create_dynamic_symtab(const Target*, Symbol_table*);
+ create_dynamic_symtab(const Target*, Symbol_table*, Output_section** pdynstr,
+ unsigned int* plocal_dynamic_count,
+ std::vector<Symbol*>* pdynamic_symbols,
+ Versions* versions);
// Finish the .dynamic section and PT_DYNAMIC segment.
void
@@ -211,6 +215,20 @@ class Layout
void
create_interp(const Target* target);
+ // Create the version sections.
+ void
+ create_version_sections(const Target*, const Versions*,
+ unsigned int local_symcount,
+ const std::vector<Symbol*>& dynamic_symbols,
+ const Output_section* dynstr);
+
+ template<int size, bool big_endian>
+ void
+ sized_create_version_sections(const Versions* versions,
+ unsigned int local_symcount,
+ const std::vector<Symbol*>& dynamic_symbols,
+ const Output_section* dynstr);
+
// Return whether to include this section in the link.
template<int size, bool big_endian>
bool
@@ -242,7 +260,7 @@ class Layout
off_t
set_segment_offsets(const Target*, Output_segment*, unsigned int* pshndx);
- // Set the final file offsets and section indices of all the
+ // Set the final file offsets and section indexes of all the
// sections not associated with a segment.
off_t
set_section_offsets(off_t, unsigned int *pshndx);
diff --git a/gold/output.h b/gold/output.h
index ceea87729f..013a19f1b9 100644
--- a/gold/output.h
+++ b/gold/output.h
@@ -1165,7 +1165,7 @@ class Output_section : public Output_data
// Set the link field to the output section index of a section.
void
- set_link_section(Output_data* od)
+ set_link_section(const Output_data* od)
{
gold_assert(this->link_ == 0
&& !this->should_link_to_symtab_
@@ -1213,7 +1213,7 @@ class Output_section : public Output_data
// Set the info field to the output section index of a section.
void
- set_info_section(Output_data* od)
+ set_info_section(const Output_data* od)
{
gold_assert(this->info_ == 0);
this->info_section_ = od;
@@ -1417,11 +1417,11 @@ class Output_section : public Output_data
uint64_t entsize_;
// The file offset is in the parent class.
// Set the section link field to the index of this section.
- Output_data* link_section_;
+ const Output_data* link_section_;
// If link_section_ is NULL, this is the link field.
unsigned int link_;
// Set the section info field to the index of this section.
- Output_data* info_section_;
+ const Output_data* info_section_;
// If info_section_ is NULL, this is the section info field.
unsigned int info_;
// The section type.
diff --git a/gold/po/gold.pot b/gold/po/gold.pot
index dbfa857cf1..abce13a1d8 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-12-01 08:46-0800\n"
+"POT-Creation-Date: 2006-12-05 15:53-0800\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"
@@ -106,56 +106,71 @@ msgstr ""
msgid "%s: %s: bad section name offset for section %u: %lu\n"
msgstr ""
-#: dynobj.cc:398
+#: dynobj.cc:399
#, c-format
msgid "%s: %s: duplicate definition for version %u\n"
msgstr ""
-#: dynobj.cc:442 dynobj.cc:561
+#: dynobj.cc:431
#, c-format
-msgid "%s: %s: verdef vd_next field out of range: %u\n"
+msgid "%s: %s: unexpected verdef version %u\n"
msgstr ""
-#: dynobj.cc:466
+#: dynobj.cc:447
#, c-format
-msgid "%s: %s: verneed vn_aux field out of range: %u\n"
+msgid "%s: %s: verdef vd_cnt field too small: %u\n"
msgstr ""
-#: dynobj.cc:485
+#: dynobj.cc:456
#, c-format
-msgid "%s: %s: verneed vna_next field out of range: %u\n"
+msgid "%s: %s: verdef vd_aux field out of range: %u\n"
msgstr ""
-#: dynobj.cc:498
+#: dynobj.cc:468
#, c-format
-msgid "%s: %s: verneed vn_next field out of range: %u\n"
+msgid "%s: %s: verdaux vda_name field out of range: %u\n"
msgstr ""
-#: dynobj.cc:528
+#: dynobj.cc:479
#, c-format
-msgid "%s: %s: verdef vd_cnt field too small: %u\n"
+msgid "%s: %s: verdef vd_next field out of range: %u\n"
msgstr ""
-#: dynobj.cc:537
+#: dynobj.cc:513
#, c-format
-msgid "%s: %s: verdef vd_aux field out of range: %u\n"
+msgid "%s: %s: unexpected verneed version %u\n"
msgstr ""
-#: dynobj.cc:549
+#: dynobj.cc:524
#, c-format
-msgid "%s: %s: verdaux vda_name field out of range: %u\n"
+msgid "%s: %s: verneed vn_aux field out of range: %u\n"
msgstr ""
-#: dynobj.cc:591
+#: dynobj.cc:539
#, c-format
msgid "%s: %s: vernaux vna_name field out of range: %u\n"
msgstr ""
-#: dynobj.cc:628
+#: dynobj.cc:552
+#, c-format
+msgid "%s: %s: verneed vna_next field out of range: %u\n"
+msgstr ""
+
+#: dynobj.cc:565
+#, c-format
+msgid "%s: %s: verneed vn_next field out of range: %u\n"
+msgstr ""
+
+#: dynobj.cc:613
#, c-format
msgid "%s: %s: size of dynamic symbols is not multiple of symbol size\n"
msgstr ""
+#: dynobj.cc:1240
+#, c-format
+msgid "%s: symbol %s has undefined version %s\n"
+msgstr ""
+
#: fileread.cc:55
#, c-format
msgid "%s: warning: close(%s) failed: %s"
@@ -567,12 +582,12 @@ msgstr ""
msgid "%s: %s: reloc section %u size %lu uneven"
msgstr ""
-#: resolve.cc:142
+#: resolve.cc:147
#, c-format
msgid "%s: %s: invalid STB_LOCAL symbol %s in external symbols\n"
msgstr ""
-#: resolve.cc:148
+#: resolve.cc:153
#, c-format
msgid "%s: %s: unsupported symbol binding %d for symbol %s\n"
msgstr ""
@@ -607,12 +622,12 @@ msgstr ""
msgid "%s: %s: versym for symbol %zu has no name: %u\n"
msgstr ""
-#: symtab.cc:1063 symtab.cc:1235
+#: symtab.cc:1093 symtab.cc:1265
#, c-format
msgid "%s: %s: unsupported symbol section 0x%x\n"
msgstr ""
-#: symtab.cc:1423
+#: symtab.cc:1458
#, c-format
msgid "%s: %s: warning: %s\n"
msgstr ""
diff --git a/gold/reloc.cc b/gold/reloc.cc
index 5b4db46ccb..001fb01cc1 100644
--- a/gold/reloc.cc
+++ b/gold/reloc.cc
@@ -484,7 +484,7 @@ Copy_relocs<size, big_endian>::Copy_reloc_entry::should_emit()
{
if (this->sym_ == NULL)
return false;
- if (this->sym_->is_defined_in_dynobj())
+ if (this->sym_->is_from_dynobj())
return true;
this->sym_ = NULL;
return false;
diff --git a/gold/resolve.cc b/gold/resolve.cc
index b8e5e701cb..1272e0588a 100644
--- a/gold/resolve.cc
+++ b/gold/resolve.cc
@@ -17,10 +17,15 @@ namespace gold
template<int size, bool big_endian>
void
Symbol::override_base(const elfcpp::Sym<size, big_endian>& sym,
- Object* object)
+ Object* object, const char* version)
{
gold_assert(this->source_ == FROM_OBJECT);
this->u_.from_object.object = object;
+ if (version != NULL && this->version() != version)
+ {
+ gold_assert(this->version() == NULL);
+ this->version_ = version;
+ }
// FIXME: Handle SHN_XINDEX.
this->u_.from_object.shndx = sym.get_st_shndx();
this->type_ = sym.get_st_type();
@@ -35,22 +40,22 @@ template<int size>
template<bool big_endian>
void
Sized_symbol<size>::override(const elfcpp::Sym<size, big_endian>& sym,
- Object* object)
+ Object* object, const char* version)
{
- this->override_base(sym, object);
+ this->override_base(sym, object, version);
this->value_ = sym.get_st_value();
this->symsize_ = sym.get_st_size();
}
// 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.
+// symbol, seen in OBJECT. VERSION of the version of SYM.
template<int size, bool big_endian>
void
Symbol_table::resolve(Sized_symbol<size>* to,
const elfcpp::Sym<size, big_endian>& sym,
- Object* object)
+ Object* object, const char* version)
{
if (object->target()->has_resolve())
{
@@ -58,7 +63,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
sized_target = object->sized_target
SELECT_SIZE_ENDIAN_NAME(size, big_endian) (
SELECT_SIZE_ENDIAN_ONLY(size, big_endian));
- sized_target->resolve(to, sym, object);
+ sized_target->resolve(to, sym, object, version);
return;
}
@@ -212,7 +217,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
// are currently compatible with the GNU linker. In the future
// we should add a target specific option to change this.
// FIXME.
- to->override(sym, object);
+ to->override(sym, object, version);
return;
case DYN_DEF * 16 + DEF:
@@ -221,7 +226,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
// definition in a regular object. The definition in the
// regular object overrides the definition in the dynamic
// object.
- to->override(sym, object);
+ to->override(sym, object, version);
return;
case UNDEF * 16 + DEF:
@@ -230,7 +235,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
case DYN_WEAK_UNDEF * 16 + DEF:
// We've seen an undefined reference, and now we see a
// definition. We use the definition.
- to->override(sym, object);
+ to->override(sym, object, version);
return;
case COMMON * 16 + DEF:
@@ -238,9 +243,9 @@ Symbol_table::resolve(Sized_symbol<size>* to,
case DYN_COMMON * 16 + DEF:
case DYN_WEAK_COMMON * 16 + DEF:
// We've seen a common symbol and now we see a definition. The
- // definition overrides. FIXME: We should optionally issue a
+ // definition overrides. FIXME: We should optionally issue, version a
// warning.
- to->override(sym, object);
+ to->override(sym, object, version);
return;
case DEF * 16 + WEAK_DEF:
@@ -253,7 +258,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
case DYN_WEAK_DEF * 16 + WEAK_DEF:
// We've seen a dynamic definition and now we see a regular weak
// definition. The regular weak definition overrides.
- to->override(sym, object);
+ to->override(sym, object, version);
return;
case UNDEF * 16 + WEAK_DEF:
@@ -261,7 +266,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
case DYN_UNDEF * 16 + WEAK_DEF:
case DYN_WEAK_UNDEF * 16 + WEAK_DEF:
// A weak definition of a currently undefined symbol.
- to->override(sym, object);
+ to->override(sym, object, version);
return;
case COMMON * 16 + WEAK_DEF:
@@ -273,7 +278,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
case DYN_WEAK_COMMON * 16 + WEAK_DEF:
// A weak definition does override a definition in a dynamic
// object. FIXME: We should optionally issue a warning.
- to->override(sym, object);
+ to->override(sym, object, version);
return;
case DEF * 16 + DYN_DEF:
@@ -288,7 +293,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
case DYN_UNDEF * 16 + DYN_DEF:
case DYN_WEAK_UNDEF * 16 + DYN_DEF:
// Use a dynamic definition if we have a reference.
- to->override(sym, object);
+ to->override(sym, object, version);
return;
case COMMON * 16 + DYN_DEF:
@@ -312,7 +317,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
case DYN_UNDEF * 16 + DYN_WEAK_DEF:
case DYN_WEAK_UNDEF * 16 + DYN_WEAK_DEF:
// Use a weak dynamic definition if we have a reference.
- to->override(sym, object);
+ to->override(sym, object, version);
return;
case COMMON * 16 + DYN_WEAK_DEF:
@@ -335,7 +340,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
case DYN_UNDEF * 16 + UNDEF:
case DYN_WEAK_UNDEF * 16 + UNDEF:
// A strong undef overrides a dynamic or weak undef.
- to->override(sym, object);
+ to->override(sym, object, version);
return;
case COMMON * 16 + UNDEF:
@@ -399,7 +404,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
case DYN_WEAK_DEF * 16 + COMMON:
// A common symbol does override a weak definition or a dynamic
// definition.
- to->override(sym, object);
+ to->override(sym, object, version);
return;
case UNDEF * 16 + COMMON:
@@ -407,7 +412,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
case DYN_UNDEF * 16 + COMMON:
case DYN_WEAK_UNDEF * 16 + COMMON:
// A common symbol is a definition for a reference.
- to->override(sym, object);
+ to->override(sym, object, version);
return;
case COMMON * 16 + COMMON:
@@ -419,7 +424,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
case WEAK_COMMON * 16 + COMMON:
// I'm not sure just what a weak common symbol means, but
// presumably it can be overridden by a regular common symbol.
- to->override(sym, object);
+ to->override(sym, object, version);
return;
case DYN_COMMON * 16 + COMMON:
@@ -427,7 +432,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
{
// Use the real common symbol, but adjust the size if necessary.
typename Sized_symbol<size>::Size_type symsize = to->symsize();
- to->override(sym, object);
+ to->override(sym, object, version);
if (to->symsize() < symsize)
to->set_symsize(symsize);
}
@@ -446,7 +451,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
case DYN_UNDEF * 16 + WEAK_COMMON:
case DYN_WEAK_UNDEF * 16 + WEAK_COMMON:
// A weak common symbol is better than an undefined symbol.
- to->override(sym, object);
+ to->override(sym, object, version);
return;
case COMMON * 16 + WEAK_COMMON:
@@ -470,7 +475,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
case DYN_UNDEF * 16 + DYN_COMMON:
case DYN_WEAK_UNDEF * 16 + DYN_COMMON:
// A dynamic common symbol is a definition of sorts.
- to->override(sym, object);
+ to->override(sym, object, version);
return;
case COMMON * 16 + DYN_COMMON:
@@ -494,7 +499,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
case DYN_UNDEF * 16 + DYN_WEAK_COMMON:
case DYN_WEAK_UNDEF * 16 + DYN_WEAK_COMMON:
// I guess a weak common symbol is better than a definition.
- to->override(sym, object);
+ to->override(sym, object, version);
return;
case COMMON * 16 + DYN_WEAK_COMMON:
@@ -520,27 +525,31 @@ void
Symbol_table::resolve<32, true>(
Sized_symbol<32>* to,
const elfcpp::Sym<32, true>& sym,
- Object* object);
+ Object* object,
+ const char* version);
template
void
Symbol_table::resolve<32, false>(
Sized_symbol<32>* to,
const elfcpp::Sym<32, false>& sym,
- Object* object);
+ Object* object,
+ const char* version);
template
void
Symbol_table::resolve<64, true>(
Sized_symbol<64>* to,
const elfcpp::Sym<64, true>& sym,
- Object* object);
+ Object* object,
+ const char* version);
template
void
Symbol_table::resolve<64, false>(
Sized_symbol<64>* to,
const elfcpp::Sym<64, false>& sym,
- Object* object);
+ Object* object,
+ const char* version);
} // End namespace gold.
diff --git a/gold/symtab.cc b/gold/symtab.cc
index ededad3ed8..5b61152652 100644
--- a/gold/symtab.cc
+++ b/gold/symtab.cc
@@ -248,8 +248,8 @@ Symbol_table::lookup(const char* name, const char* version) const
template<int size, bool big_endian>
void
-Symbol_table::resolve(Sized_symbol<size>* to, const Sized_symbol<size>* from
- ACCEPT_SIZE_ENDIAN)
+Symbol_table::resolve(Sized_symbol<size>* to, const Sized_symbol<size>* from,
+ const char* version ACCEPT_SIZE_ENDIAN)
{
unsigned char buf[elfcpp::Elf_sizes<size>::sym_size];
elfcpp::Sym_write<size, big_endian> esym(buf);
@@ -259,7 +259,7 @@ Symbol_table::resolve(Sized_symbol<size>* to, const Sized_symbol<size>* from
esym.put_st_info(from->binding(), from->type());
esym.put_st_other(from->visibility(), from->nonvis());
esym.put_st_shndx(from->shndx());
- Symbol_table::resolve(to, esym.sym(), from->object());
+ Symbol_table::resolve(to, esym.sym(), from->object(), version);
}
// Add one symbol from OBJECT to the symbol table. NAME is symbol
@@ -328,7 +328,7 @@ Symbol_table::add_from_object(Object* object,
was_undefined = ret->is_undefined();
was_common = ret->is_common();
- Symbol_table::resolve(ret, sym, object);
+ Symbol_table::resolve(ret, sym, object, version);
if (def)
{
@@ -347,7 +347,7 @@ Symbol_table::add_from_object(Object* object,
insdef.first->second
SELECT_SIZE(size));
Symbol_table::resolve SELECT_SIZE_ENDIAN_NAME(size, big_endian) (
- ret, sym2 SELECT_SIZE_ENDIAN(size, big_endian));
+ ret, sym2, version SELECT_SIZE_ENDIAN(size, big_endian));
this->make_forwarder(insdef.first->second, ret);
insdef.first->second = ret;
}
@@ -363,12 +363,12 @@ Symbol_table::add_from_object(Object* object,
if (def && !insdef.second)
{
- // We already have an entry for NAME/NULL. Make
- // NAME/VERSION point to it.
+ // We already have an entry for NAME/NULL. If we override
+ // it, then change it to NAME/VERSION.
ret = this->get_sized_symbol SELECT_SIZE_NAME(size) (
insdef.first->second
SELECT_SIZE(size));
- Symbol_table::resolve(ret, sym, object);
+ Symbol_table::resolve(ret, sym, object, version);
ins.first->second = ret;
}
else
@@ -649,8 +649,8 @@ Symbol_table::add_from_dynobj(
template<int size, bool big_endian>
Sized_symbol<size>*
-Symbol_table::define_special_symbol(Target* target, const char* name,
- bool only_if_ref
+Symbol_table::define_special_symbol(const Target* target, const char* name,
+ const char* version, bool only_if_ref
ACCEPT_SIZE_ENDIAN)
{
gold_assert(this->size_ == size);
@@ -660,29 +660,34 @@ Symbol_table::define_special_symbol(Target* target, const char* name,
if (only_if_ref)
{
- oldsym = this->lookup(name, NULL);
+ oldsym = this->lookup(name, version);
if (oldsym == NULL || !oldsym->is_undefined())
return NULL;
sym = NULL;
- // Canonicalize NAME.
+ // Canonicalize NAME and VERSION.
name = oldsym->name();
+ version = oldsym->version();
}
else
{
- // Canonicalize NAME.
+ // Canonicalize NAME and VERSION.
Stringpool::Key name_key;
name = this->namepool_.add(name, &name_key);
+ Stringpool::Key version_key = 0;
+ if (version != NULL)
+ version = this->namepool_.add(version, &version_key);
+
Symbol* const snull = NULL;
- const Stringpool::Key ver_key = 0;
std::pair<typename Symbol_table_type::iterator, bool> ins =
- this->table_.insert(std::make_pair(std::make_pair(name_key, ver_key),
+ this->table_.insert(std::make_pair(std::make_pair(name_key,
+ version_key),
snull));
if (!ins.second)
{
- // We already have a symbol table entry for NAME.
+ // We already have a symbol table entry for NAME/VERSION.
oldsym = ins.first->second;
gold_assert(oldsym != NULL);
sym = NULL;
@@ -699,7 +704,8 @@ Symbol_table::define_special_symbol(Target* target, const char* name,
gold_assert(target->get_size() == size);
gold_assert(target->is_big_endian() ? big_endian : !big_endian);
typedef Sized_target<size, big_endian> My_target;
- My_target* sized_target = static_cast<My_target*>(target);
+ const My_target* sized_target =
+ static_cast<const My_target*>(target);
sym = sized_target->make_symbol();
if (sym == NULL)
return NULL;
@@ -737,9 +743,9 @@ Symbol_table::define_special_symbol(Target* target, const char* name,
// Define a symbol based on an Output_data.
-void
-Symbol_table::define_in_output_data(Target* target, const char* name,
- Output_data* od,
+Symbol*
+Symbol_table::define_in_output_data(const Target* target, const char* name,
+ const char* version, Output_data* od,
uint64_t value, uint64_t symsize,
elfcpp::STT type, elfcpp::STB binding,
elfcpp::STV visibility,
@@ -749,13 +755,15 @@ Symbol_table::define_in_output_data(Target* target, const char* name,
{
gold_assert(target->get_size() == this->size_);
if (this->size_ == 32)
- this->do_define_in_output_data<32>(target, name, od, value, symsize,
- type, binding, visibility, nonvis,
- offset_is_from_end, only_if_ref);
+ return this->do_define_in_output_data<32>(target, name, version, od, value,
+ symsize, type, binding,
+ visibility, nonvis,
+ offset_is_from_end, only_if_ref);
else if (this->size_ == 64)
- this->do_define_in_output_data<64>(target, name, od, value, symsize,
- type, binding, visibility, nonvis,
- offset_is_from_end, only_if_ref);
+ return this->do_define_in_output_data<64>(target, name, version, od, value,
+ symsize, type, binding,
+ visibility, nonvis,
+ offset_is_from_end, only_if_ref);
else
gold_unreachable();
}
@@ -763,10 +771,11 @@ Symbol_table::define_in_output_data(Target* target, const char* name,
// Define a symbol in an Output_data, sized version.
template<int size>
-void
+Sized_symbol<size>*
Symbol_table::do_define_in_output_data(
- Target* target,
+ const Target* target,
const char* name,
+ const char* version,
Output_data* od,
typename elfcpp::Elf_types<size>::Elf_Addr value,
typename elfcpp::Elf_types<size>::Elf_WXword symsize,
@@ -781,25 +790,27 @@ Symbol_table::do_define_in_output_data(
if (target->is_big_endian())
sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, true) (
- target, name, only_if_ref
+ target, name, version, only_if_ref
SELECT_SIZE_ENDIAN(size, true));
else
sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, false) (
- target, name, only_if_ref
+ target, name, version, only_if_ref
SELECT_SIZE_ENDIAN(size, false));
if (sym == NULL)
- return;
+ return NULL;
sym->init(name, od, value, symsize, type, binding, visibility, nonvis,
offset_is_from_end);
+
+ return sym;
}
// Define a symbol based on an Output_segment.
-void
-Symbol_table::define_in_output_segment(Target* target, const char* name,
- Output_segment* os,
+Symbol*
+Symbol_table::define_in_output_segment(const Target* target, const char* name,
+ const char* version, Output_segment* os,
uint64_t value, uint64_t symsize,
elfcpp::STT type, elfcpp::STB binding,
elfcpp::STV visibility,
@@ -809,13 +820,15 @@ Symbol_table::define_in_output_segment(Target* target, const char* name,
{
gold_assert(target->get_size() == this->size_);
if (this->size_ == 32)
- this->do_define_in_output_segment<32>(target, name, os, value, symsize,
- type, binding, visibility, nonvis,
- offset_base, only_if_ref);
+ return this->do_define_in_output_segment<32>(target, name, version, os,
+ value, symsize, type, binding,
+ visibility, nonvis,
+ offset_base, only_if_ref);
else if (this->size_ == 64)
- this->do_define_in_output_segment<64>(target, name, os, value, symsize,
- type, binding, visibility, nonvis,
- offset_base, only_if_ref);
+ return this->do_define_in_output_segment<64>(target, name, version, os,
+ value, symsize, type, binding,
+ visibility, nonvis,
+ offset_base, only_if_ref);
else
gold_unreachable();
}
@@ -823,10 +836,11 @@ Symbol_table::define_in_output_segment(Target* target, const char* name,
// Define a symbol in an Output_segment, sized version.
template<int size>
-void
+Sized_symbol<size>*
Symbol_table::do_define_in_output_segment(
- Target* target,
+ const Target* target,
const char* name,
+ const char* version,
Output_segment* os,
typename elfcpp::Elf_types<size>::Elf_Addr value,
typename elfcpp::Elf_types<size>::Elf_WXword symsize,
@@ -841,39 +855,41 @@ Symbol_table::do_define_in_output_segment(
if (target->is_big_endian())
sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, true) (
- target, name, only_if_ref
+ target, name, version, only_if_ref
SELECT_SIZE_ENDIAN(size, true));
else
sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, false) (
- target, name, only_if_ref
+ target, name, version, only_if_ref
SELECT_SIZE_ENDIAN(size, false));
if (sym == NULL)
- return;
+ return NULL;
sym->init(name, os, value, symsize, type, binding, visibility, nonvis,
offset_base);
+
+ return sym;
}
// Define a special symbol with a constant value. It is a multiple
// definition error if this symbol is already defined.
-void
-Symbol_table::define_as_constant(Target* target, const char* name,
- uint64_t value, uint64_t symsize,
- elfcpp::STT type, elfcpp::STB binding,
- elfcpp::STV visibility, unsigned char nonvis,
- bool only_if_ref)
+Symbol*
+Symbol_table::define_as_constant(const Target* target, const char* name,
+ const char* version, uint64_t value,
+ uint64_t symsize, elfcpp::STT type,
+ elfcpp::STB binding, elfcpp::STV visibility,
+ unsigned char nonvis, bool only_if_ref)
{
gold_assert(target->get_size() == this->size_);
if (this->size_ == 32)
- this->do_define_as_constant<32>(target, name, value, symsize,
- type, binding, visibility, nonvis,
- only_if_ref);
+ return this->do_define_as_constant<32>(target, name, version, value,
+ symsize, type, binding, visibility,
+ nonvis, only_if_ref);
else if (this->size_ == 64)
- this->do_define_as_constant<64>(target, name, value, symsize,
- type, binding, visibility, nonvis,
- only_if_ref);
+ return this->do_define_as_constant<64>(target, name, version, value,
+ symsize, type, binding, visibility,
+ nonvis, only_if_ref);
else
gold_unreachable();
}
@@ -881,10 +897,11 @@ Symbol_table::define_as_constant(Target* target, const char* name,
// Define a symbol as a constant, sized version.
template<int size>
-void
+Sized_symbol<size>*
Symbol_table::do_define_as_constant(
- Target* target,
+ const Target* target,
const char* name,
+ const char* version,
typename elfcpp::Elf_types<size>::Elf_Addr value,
typename elfcpp::Elf_types<size>::Elf_WXword symsize,
elfcpp::STT type,
@@ -897,35 +914,37 @@ Symbol_table::do_define_as_constant(
if (target->is_big_endian())
sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, true) (
- target, name, only_if_ref
+ target, name, version, only_if_ref
SELECT_SIZE_ENDIAN(size, true));
else
sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, false) (
- target, name, only_if_ref
+ target, name, version, only_if_ref
SELECT_SIZE_ENDIAN(size, false));
if (sym == NULL)
- return;
+ return NULL;
sym->init(name, value, symsize, type, binding, visibility, nonvis);
+
+ return sym;
}
// Define a set of symbols in output sections.
void
-Symbol_table::define_symbols(const Layout* layout, Target* target, int count,
- const Define_symbol_in_section* p)
+Symbol_table::define_symbols(const Layout* layout, const Target* target,
+ int count, const Define_symbol_in_section* p)
{
for (int i = 0; i < count; ++i, ++p)
{
Output_section* os = layout->find_output_section(p->output_section);
if (os != NULL)
- this->define_in_output_data(target, p->name, os, p->value, p->size,
- p->type, p->binding, p->visibility,
- p->nonvis, p->offset_is_from_end,
- p->only_if_ref);
+ this->define_in_output_data(target, p->name, NULL, os, p->value,
+ p->size, p->type, p->binding,
+ p->visibility, p->nonvis,
+ p->offset_is_from_end, p->only_if_ref);
else
- this->define_as_constant(target, p->name, 0, p->size, p->type,
+ this->define_as_constant(target, p->name, NULL, 0, p->size, p->type,
p->binding, p->visibility, p->nonvis,
p->only_if_ref);
}
@@ -934,8 +953,8 @@ Symbol_table::define_symbols(const Layout* layout, Target* target, int count,
// Define a set of symbols in output segments.
void
-Symbol_table::define_symbols(const Layout* layout, Target* target, int count,
- const Define_symbol_in_segment* p)
+Symbol_table::define_symbols(const Layout* layout, const Target* target,
+ int count, const Define_symbol_in_segment* p)
{
for (int i = 0; i < count; ++i, ++p)
{
@@ -943,12 +962,12 @@ Symbol_table::define_symbols(const Layout* layout, Target* target, int count,
p->segment_flags_set,
p->segment_flags_clear);
if (os != NULL)
- this->define_in_output_segment(target, p->name, os, p->value, p->size,
- p->type, p->binding, p->visibility,
- p->nonvis, p->offset_base,
- p->only_if_ref);
+ this->define_in_output_segment(target, p->name, NULL, os, p->value,
+ p->size, p->type, p->binding,
+ p->visibility, p->nonvis,
+ p->offset_base, p->only_if_ref);
else
- this->define_as_constant(target, p->name, 0, p->size, p->type,
+ this->define_as_constant(target, p->name, NULL, 0, p->size, p->type,
p->binding, p->visibility, p->nonvis,
p->only_if_ref);
}
@@ -960,9 +979,12 @@ Symbol_table::define_symbols(const Layout* layout, Target* target, int count,
// updated dynamic symbol index.
unsigned int
-Symbol_table::set_dynsym_indexes(unsigned int index,
+Symbol_table::set_dynsym_indexes(const General_options* options,
+ const Target* target,
+ unsigned int index,
std::vector<Symbol*>* syms,
- Stringpool* dynpool)
+ Stringpool* dynpool,
+ Versions* versions)
{
for (Symbol_table_type::iterator p = this->table_.begin();
p != this->table_.end();
@@ -982,9 +1004,17 @@ Symbol_table::set_dynsym_indexes(unsigned int index,
++index;
syms->push_back(sym);
dynpool->add(sym->name(), NULL);
+
+ // Record any version information.
+ if (sym->version() != NULL)
+ versions->record_version(options, dynpool, sym);
}
}
+ // Finish up the versions. In some cases this may add new dynamic
+ // symbols.
+ index = versions->finalize(target, this, index, syms);
+
return index;
}
diff --git a/gold/symtab.h b/gold/symtab.h
index f7a5c4c650..6e4344d4be 100644
--- a/gold/symtab.h
+++ b/gold/symtab.h
@@ -24,6 +24,7 @@ class Sized_relobj;
class Dynobj;
template<int size, bool big_endian>
class Sized_dynobj;
+class Versions;
class Output_data;
class Output_section;
class Output_segment;
@@ -303,13 +304,11 @@ class Symbol
&& this->shndx() != elfcpp::SHN_COMMON));
}
- // Return whether this symbol is defined in a dynamic object.
+ // Return true if this symbol is from a dynamic object.
bool
- is_defined_in_dynobj() const
+ is_from_dynobj() const
{
- return (this->source_ == FROM_OBJECT
- && this->object()->is_dynamic()
- && this->is_defined());
+ return this->source_ == FROM_OBJECT && this->object()->is_dynamic();
}
// Return whether this is an undefined symbol.
@@ -376,7 +375,8 @@ class Symbol
// Override existing symbol.
template<int size, bool big_endian>
void
- override_base(const elfcpp::Sym<size, big_endian>&, Object* object);
+ override_base(const elfcpp::Sym<size, big_endian>&, Object* object,
+ const char* version);
private:
Symbol(const Symbol&);
@@ -518,7 +518,8 @@ class Sized_symbol : public Symbol
// Override existing symbol.
template<bool big_endian>
void
- override(const elfcpp::Sym<size, big_endian>&, Object* object);
+ override(const elfcpp::Sym<size, big_endian>&, Object* object,
+ const char* version);
// Return the symbol's value.
Value_type
@@ -730,25 +731,20 @@ class Symbol_table
const unsigned char* versym, size_t versym_size,
const std::vector<const char*>*);
- // Define a special symbol.
- template<int size, bool big_endian>
- Sized_symbol<size>*
- define_special_symbol(Target* target, const char* name, bool only_if_ref
- ACCEPT_SIZE_ENDIAN);
-
// Define a special symbol based on an Output_data. It is a
// multiple definition error if this symbol is already defined.
- void
- define_in_output_data(Target*, const char* name, Output_data*,
- uint64_t value, uint64_t symsize,
+ Symbol*
+ define_in_output_data(const Target*, const char* name, const char* version,
+ Output_data*, uint64_t value, uint64_t symsize,
elfcpp::STT type, elfcpp::STB binding,
elfcpp::STV visibility, unsigned char nonvis,
bool offset_is_from_end, bool only_if_ref);
// Define a special symbol based on an Output_segment. It is a
// multiple definition error if this symbol is already defined.
- void
- define_in_output_segment(Target*, const char* name, Output_segment*,
+ Symbol*
+ define_in_output_segment(const Target*, const char* name,
+ const char* version, Output_segment*,
uint64_t value, uint64_t symsize,
elfcpp::STT type, elfcpp::STB binding,
elfcpp::STV visibility, unsigned char nonvis,
@@ -756,20 +752,20 @@ class Symbol_table
// Define a special symbol with a constant value. It is a multiple
// definition error if this symbol is already defined.
- void
- define_as_constant(Target*, const char* name, uint64_t value,
- uint64_t symsize, elfcpp::STT type, elfcpp::STB binding,
- elfcpp::STV visibility, unsigned char nonvis,
- bool only_if_ref);
+ Symbol*
+ define_as_constant(const Target*, const char* name, const char* version,
+ uint64_t value, uint64_t symsize, elfcpp::STT type,
+ elfcpp::STB binding, elfcpp::STV visibility,
+ unsigned char nonvis, bool only_if_ref);
// Define a set of symbols in output sections.
void
- define_symbols(const Layout*, Target*, int count,
+ define_symbols(const Layout*, const Target*, int count,
const Define_symbol_in_section*);
// Define a set of symbols in output segments.
void
- define_symbols(const Layout*, Target*, int count,
+ define_symbols(const Layout*, const Target*, int count,
const Define_symbol_in_segment*);
// Look up a symbol.
@@ -824,8 +820,8 @@ class Symbol_table
// the vector. The names are stored into the Stringpool. This
// returns an updated dynamic symbol index.
unsigned int
- set_dynsym_indexes(unsigned int index, std::vector<Symbol*>*,
- Stringpool*);
+ set_dynsym_indexes(const General_options*, const Target*, unsigned int index,
+ std::vector<Symbol*>*, Stringpool*, Versions*);
// Finalize the symbol table after we have set the final addresses
// of all the input sections. This sets the final symbol indexes,
@@ -874,17 +870,25 @@ class Symbol_table
static void
resolve(Sized_symbol<size>* to,
const elfcpp::Sym<size, big_endian>& sym,
- Object*);
+ Object*, const char* version);
template<int size, bool big_endian>
static void
- resolve(Sized_symbol<size>* to, const Sized_symbol<size>* from
- ACCEPT_SIZE_ENDIAN);
+ resolve(Sized_symbol<size>* to, const Sized_symbol<size>* from,
+ const char* version ACCEPT_SIZE_ENDIAN);
+
+ // Define a special symbol.
+ template<int size, bool big_endian>
+ Sized_symbol<size>*
+ define_special_symbol(const Target* target, const char* name,
+ const char* version, bool only_if_ref
+ ACCEPT_SIZE_ENDIAN);
// Define a symbol in an Output_data, sized version.
template<int size>
- void
- do_define_in_output_data(Target*, const char* name, Output_data*,
+ Sized_symbol<size>*
+ do_define_in_output_data(const Target*, const char* name,
+ const char* version, Output_data*,
typename elfcpp::Elf_types<size>::Elf_Addr value,
typename elfcpp::Elf_types<size>::Elf_WXword ssize,
elfcpp::STT type, elfcpp::STB binding,
@@ -893,9 +897,9 @@ class Symbol_table
// Define a symbol in an Output_segment, sized version.
template<int size>
- void
+ Sized_symbol<size>*
do_define_in_output_segment(
- Target*, const char* name, Output_segment* os,
+ const Target*, const char* name, const char* version, Output_segment* os,
typename elfcpp::Elf_types<size>::Elf_Addr value,
typename elfcpp::Elf_types<size>::Elf_WXword ssize,
elfcpp::STT type, elfcpp::STB binding,
@@ -904,9 +908,9 @@ class Symbol_table
// Define a symbol as a constant, sized version.
template<int size>
- void
+ Sized_symbol<size>*
do_define_as_constant(
- Target*, const char* name,
+ const Target*, const char* name, const char* version,
typename elfcpp::Elf_types<size>::Elf_Addr value,
typename elfcpp::Elf_types<size>::Elf_WXword ssize,
elfcpp::STT type, elfcpp::STB binding,
diff --git a/gold/target.h b/gold/target.h
index 42bed9ed37..9181a93193 100644
--- a/gold/target.h
+++ b/gold/target.h
@@ -145,15 +145,17 @@ class Sized_target : public Target
// symbol table. This will only be called if has_make_symbol()
// returns true.
virtual Sized_symbol<size>*
- make_symbol()
+ make_symbol() const
{ gold_unreachable(); }
// Resolve a symbol for the target. This should be overridden by a
// target which needs to take special action. TO is the
// pre-existing symbol. SYM is the new symbol, seen in OBJECT.
- // This will only be called if has_resolve() returns true.
+ // VERSION is the version of SYM. This will only be called if
+ // has_resolve() returns true.
virtual void
- resolve(Symbol*, const elfcpp::Sym<size, big_endian>&, Object*)
+ resolve(Symbol*, const elfcpp::Sym<size, big_endian>&, Object*,
+ const char*)
{ gold_unreachable(); }
// Scan the relocs for a section, and record any information