Generate version information.

This commit is contained in:
Ian Lance Taylor 2006-12-06 00:02:36 +00:00
parent f8f183f633
commit 14b3174058
13 changed files with 1608 additions and 395 deletions

View File

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

View File

@ -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,6 +403,174 @@ Sized_dynobj<size, big_endian>::set_version_map(
(*version_map)[ndx] = name;
}
// Add mappings for the version definitions to VERSION_MAP.
template<int size, bool big_endian>
void
Sized_dynobj<size, big_endian>::make_verdef_map(
Read_symbols_data* sd,
Version_map* version_map) const
{
if (sd->verdef == NULL)
return;
const char* names = reinterpret_cast<const char*>(sd->symbol_names->data());
off_t names_size = sd->symbol_names_size;
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)
{
elfcpp::Verdef<size, big_endian> verdef(p);
if (verdef.get_vd_version() != elfcpp::VER_DEF_CURRENT)
{
fprintf(stderr, _("%s: %s: unexpected verdef version %u\n"),
program_name, this->name().c_str(), verdef.get_vd_version());
gold_exit(false);
}
const unsigned int vd_ndx = verdef.get_vd_ndx();
// The GNU linker clears the VERSYM_HIDDEN bit. I'm not
// sure why.
// 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);
}
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);
}
const unsigned char* pvda = p + vd_aux;
elfcpp::Verdaux<size, big_endian> verdaux(pvda);
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);
}
this->set_version_map(version_map, vd_ndx, names + vda_name);
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;
}
}
// Add mappings for the required versions to VERSION_MAP.
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;
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)
{
elfcpp::Verneed<size, big_endian> verneed(p);
if (verneed.get_vn_version() != elfcpp::VER_NEED_CURRENT)
{
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 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 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);
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 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;
}
}
// Create a vector mapping version numbers to version strings.
template<int size, bool big_endian>
@ -413,196 +582,12 @@ Sized_dynobj<size, big_endian>::make_version_map(
if (sd->verdef == NULL && sd->verneed == NULL)
return;
// First find the largest version index.
unsigned int maxver = 0;
// 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);
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)
{
elfcpp::Verdef<size, big_endian> verdef(p);
const unsigned int vd_ndx = verdef.get_vd_ndx();
// The GNU linker clears the VERSYM_HIDDEN bit. I'm not
// sure why.
if (vd_ndx > maxver)
maxver = vd_ndx;
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;
}
}
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)
{
elfcpp::Verneed<size, big_endian> verneed(p);
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 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 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;
}
}
// Now MAXVER is the largest version index we have seen.
version_map->resize(maxver + 1);
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)
{
elfcpp::Verdef<size, big_endian> verdef(p);
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 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);
}
const unsigned char* pvda = p + vd_aux;
elfcpp::Verdaux<size, big_endian> verdaux(pvda);
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);
}
this->set_version_map(version_map, verdef.get_vd_ndx(),
names + vda_name);
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;
}
}
if (sd->verneed != NULL)
{
const unsigned char* pverneed = sd->verneed->data();
const unsigned int count = sd->verneed_info;
const unsigned char* p = pverneed;
for (unsigned int i = 0; i < count; ++i)
{
elfcpp::Verneed<size, big_endian> verneed(p);
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();
}
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.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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
#, c-format
msgid "%s: %s: verneed vn_aux field out of range: %u\n"
msgstr ""
#: dynobj.cc:485
#, c-format
msgid "%s: %s: verneed vna_next field out of range: %u\n"
msgstr ""
#: dynobj.cc:498
#, c-format
msgid "%s: %s: verneed vn_next field out of range: %u\n"
msgstr ""
#: dynobj.cc:528
#: dynobj.cc:447
#, c-format
msgid "%s: %s: verdef vd_cnt field too small: %u\n"
msgstr ""
#: dynobj.cc:537
#: dynobj.cc:456
#, c-format
msgid "%s: %s: verdef vd_aux field out of range: %u\n"
msgstr ""
#: dynobj.cc:549
#: dynobj.cc:468
#, c-format
msgid "%s: %s: verdaux vda_name field out of range: %u\n"
msgstr ""
#: dynobj.cc:591
#: dynobj.cc:479
#, c-format
msgid "%s: %s: verdef vd_next field out of range: %u\n"
msgstr ""
#: dynobj.cc:513
#, c-format
msgid "%s: %s: unexpected verneed version %u\n"
msgstr ""
#: dynobj.cc:524
#, c-format
msgid "%s: %s: verneed vn_aux field out of range: %u\n"
msgstr ""
#: 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 ""

View File

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

View File

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

View File

@ -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;
}

View File

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

View File

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