Generate version information.
This commit is contained in:
parent
f8f183f633
commit
14b3174058
13 changed files with 1608 additions and 395 deletions
128
elfcpp/elfcpp.h
128
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.
|
||||
|
||||
|
|
925
gold/dynobj.cc
925
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,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.
|
||||
|
|
319
gold/dynobj.h
319
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)
|
||||
|
|
14
gold/i386.cc
14
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();
|
||||
|
|
179
gold/layout.cc
179
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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 ""
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
186
gold/symtab.cc
186
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue